import { Injectable } from '@angular/core' ; import { BehaviorSubject , interval , Observable } from 'rxjs' ; import { distinctUntilChanged , map , tap } from 'rxjs/operators' ; import { EmailConfirmationService } from '../components/email-confirmation/email-confirmation.service' ; import { FormToastService } from './form-toast.service' ; /**
 * Allows a member to attempt to resend a confirmation email.
 * Stores timestamp of when user is next allowed in local storage
 * so that the thread being blocked doesn't impact the countdown.
 */ @ Injectable ( { providedIn : 'root' } ) export class EmailResendService { public readonly inProgress$ : BehaviorSubject < boolean > = new BehaviorSubject < boolean > ( false ) ; public readonly retryTimer$ : Observable < number > = interval ( 1000 ) . pipe ( map ( i => ( this . retryInSeconds > 0 ? this . retryInSeconds : 0 ) ) , distinctUntilChanged ( ) , tap ( i => { this . inProgress$ . next ( false ) ; } ) ) ; constructor ( protected service , protected toast ) { } param { number } seconds returns { Promise < void > } async send ( seconds = 60 ) { if ( this . inProgress$ . getValue ( ) ) { this . toast . warn ( 'Email send already in progress.' ) ; return ; } if ( ! ( this . retryInSeconds > 0 ) ) { this . inProgress$ . next ( true ) ; try { let sent = await this . service . send ( ) ; if ( ! sent ) { throw new Error ( 'Failed to send email.' ) ; } } catch ( e ) { console . error ( e ) ; this . toast . error ( e . message ?? 'An error has occurred sending your email.' ) ; this . inProgress$ . next ( false ) ; return ; } let time = new Date ( ) ; time . setSeconds ( time . getSeconds ( ) + seconds ) ; localStorage . setItem ( 'email_resend' , time . getTime ( ) . toString ( ) ) ; this . toast . success ( 'Email sent, check your inbox for a verification email.' ) ; return ; } this . toast . inform ( 'Please wait ' + this . retryInSeconds + ' seconds before sending another email.' ) ; } returns { number } get canResendTimestamp ( ) : number { return parseInt ( localStorage . getItem ( 'email_resend' ) ) ?? 0 ; } returns { number } get retryInSeconds ( ) : number { return ( Math . floor ( ( this . canResendTimestamp - new Date ( ) . getTime ( ) ) / 1000 ) ?? 0 ) ; } }