agmission/Development/client/src/app/domain/guards/subscription.guard.ts

117 lines
5.0 KiB
TypeScript

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { SubscriptionService } from '../services/subscription.service';
import { catchError, map } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { StripeSubscription } from '../models/subscription.model';
import { SUB, SubStripe } from '@app/profile/common';
import { AppMessageService } from '@app/shared/app-message.service';
import { AC, globals } from '@app/shared/global';
import { RouterUtilsService } from '@app/shared/router-utils.service';
/**
This guards against unresolved subscriptions when the user is subscribing to a new subscription in the
main flow (services <->billing-detail<->checkout<->checkout-review<->checkout-confirm). When the user has an unresolved subscription, the guard forces user to enter the resolving subscription flow.
*/
@Injectable({ providedIn: 'root' })
export class SubscriptionGuard implements CanActivate {
constructor(
private readonly authSvc: AuthService,
private readonly subSvc: SubscriptionService,
private readonly router: Router,
private readonly msgSvc: AppMessageService,
private readonly routerUtils: RouterUtilsService
) { }
canActivate(activatedRoute: ActivatedRouteSnapshot): Observable<boolean> {
return this.subSvc.fetchSubscriptions(this.authSvc.user?.membership?.custId).pipe(
map((subs) => {
const fromPath = this.routerUtils.getCurrentUrl().split('/').pop();
const toPath = activatedRoute.url[0]?.path;
const hasLatestSubs = subs?.length > 0;
const hasUnresolvedSubs = this.hasUnresolvedSubs(subs);
const hasAllActiveSubs = hasLatestSubs && !hasUnresolvedSubs;
const isSubscribing = (!hasLatestSubs || hasAllActiveSubs)
&& (this.isInMainFlow(fromPath, toPath)
|| this.isPageReload(fromPath, toPath));
const isResolvingSubs = hasUnresolvedSubs
&& (this.isInResolvingFlow(fromPath, toPath)
|| this.isPageReload(fromPath, toPath));
const viewPayment = this.isPaymentPage(toPath);
const viewPaymentMethod = this.isPaymentMethodPage(toPath);
const viewAC = this.isACPage(toPath) && !hasUnresolvedSubs;
const canNavigate = isSubscribing || viewPayment || viewPaymentMethod || viewAC || true;
const shouldNavigateToMyServices = hasUnresolvedSubs && !isResolvingSubs;
if (canNavigate) {
return true;
} else if (shouldNavigateToMyServices) {
this.router.navigate([SUB.PROFILE, SUB.MY_SERVICES]);
} else if (isResolvingSubs) {
return true;
} else {
this.router.navigate(['/', SUB.HOME]);
}
}),
catchError(err => {
this.msgSvc.addFailedMsg(globals.doThingsFailed.replace('#do#', globals.load).replace('#thing#', globals.subscription));
return of(false);
})
);
}
private isInMainFlow(fromPath: string, toPath: string): boolean {
return (fromPath === SUB.SERVICES && toPath === SUB.BILL_ADR) ||
(fromPath === SUB.BILL_ADR && toPath === SUB.CHKOUT) ||
(fromPath === SUB.CHKOUT && toPath === SUB.BILL_ADR) ||
(fromPath === SUB.CHKOUT && toPath === SUB.CHKOUT_REV) ||
(fromPath === SUB.CHKOUT_REV && toPath === SUB.CHKOUT_CONF) ||
(fromPath === SUB.CHKOUT_REV && toPath === SUB.CHKOUT) ||
this.isTrialFLow(fromPath, toPath);
}
private isInResolvingFlow(fromPath: string, toPath: string): boolean {
return (fromPath === SUB.UNPAID_SUB && toPath === SUB.BILL_ADR) ||
(fromPath === SUB.BILL_ADR && toPath === SUB.CHKOUT) ||
(fromPath === SUB.BILL_ADR && toPath === SUB.UNPAID_SUB) ||
(fromPath === SUB.CHKOUT && toPath === SUB.BILL_ADR) ||
(fromPath === SUB.CHKOUT && toPath === SUB.CHKOUT_REV) ||
(fromPath === SUB.CHKOUT_REV && toPath === SUB.CHKOUT) ||
(fromPath === SUB.CHKOUT_REV && toPath === SUB.CHKOUT_CONF) ||
(fromPath === SUB.MY_SERVICES && toPath === SUB.CHKOUT_REV) ||
(fromPath === SUB.MY_SERVICES && toPath === SUB.UNPAID_SUB);
}
private isTrialFLow(fromPath: string, toPath: string): boolean {
return (fromPath === SUB.CHKOUT && toPath === SUB.CHKOUT_CONF) ||
(fromPath === SUB.MY_SERVICES && toPath === SUB.BILL_ADR);
}
private isPageReload(fromPath: string, toPath: string): boolean {
return (!fromPath && (toPath === SUB.BILL_ADR || toPath === SUB.CHKOUT || toPath === SUB.CHKOUT_REV || toPath === SUB.CHKOUT_CONF));
}
private hasUnresolvedSubs(subs: StripeSubscription[]): boolean {
return subs?.some(sub => sub.status === SubStripe.PAST_DUE || sub.status === SubStripe.OVERDUE || sub.status === SubStripe.UNPAID || sub.status === SubStripe.INCOMPLETE);
}
private isPaymentPage(path: string): boolean {
return path === SUB.PM_HISTORY || path === SUB.PM_DETAIL;
}
private isPaymentMethodPage(path: string): boolean {
return path === SUB.PM_LIST;
}
private isACPage(path: string): boolean {
return path === AC;
}
}