Flow:
After the user successfully logs in, the app should load users Vendor and navigate to VendorID
Example: myUrl.com/vendor/ID
Different cases I'm trying to support:
1. A user puts it URL with Vendor ID:
App will reload Vendor
2. After login
App will load the Vendor and Navigate to URL
3. On refresh
App will re-load Vendor, and only navigate if URL does not exist already of VendorID (So the user will stay on the same page he is already at)
My issue:
When a user refreshes the app, he will be re-navigated to root Vendor (Not good, I want him to stay on his page, navigate only on login)
Code I have tried so far:
@Effect()
loadVendor(): Observable<VendorDataInitAction | AuthAction | VendorDataAction> {
return this._actions$
.pipe(
ofType<AuthLoginSuccessAction | AuthRefreshSuccessAction>(AuthActions.LoginSuccess, AuthActions.RefreshSuccess),
withLatestFrom(this._store.select(selectAuthActor)),
filter(([_, actor]) => isUserLoggedIn(actor)),
switchMap(([_, actor]) => {
const errorActions = [
new AuthSetAuthMessageAction({
message: 'You need to be granted access in order to login to Portal.\n' +
'Please contact your Platterz representative.',
type: AuthMessageType.Error
}),
new AuthLogoutAction()
];
return this._apollo
.query<AssociatedRestaurants>({
query: AssociatedRestaurantsQuery
})
.pipe(
switchMap((result): ObservableInput<AuthAction | VendorDataAction> => {
const errors = result.errors && result.errors.length > 0;
const noRestaurants = !(result.data && result.data.associatedLocations &&
result.data.associatedLocations.locations.length);
if (errors || noRestaurants) {
return errorActions;
}
return [
new VendorDataInitAction(result.data.associatedLocations.locations)
];
}),
catchError(() => errorActions)
);
}));
}
@Effect()
navigateToVendorOnDataLoad(): Observable<VendorDidSetIDURLAction> {
return this._actions$
.pipe(
ofType<VendorDidSetIDURLAction>(VendorDataActions.Init),
withLatestFrom(this._route.params.pipe(map((params) => params.vendorID))),
filter(([, vendorId]) => vendorId == null),
switchMap(() => this._store.select(selectCurrentVendor)),
filter((vendor) => !!vendor),
take(1),
map((vendor) => {
// When trying to get Route params, and navigate only if VendorID is null, Its always null...
this._router.navigate(['/vendors', vendor.id, 'dashboard']);
return new VendorDidSetIDURLAction();
})
);
}
I tried accessing Route params on @Effect with no success, it does not contain VendorID while refreshing...
How is it possible to get Route params from @Effect? Or is there a better way of archiving this logic?
Posting my solution for anyone else bumping to a similar issue.
Seems as URL params are not accessible at times from @Effects (Specifically on refresh) So I used local storage instead.
Flow goes as the following:
By default, the app will always navigate you to sign-in page in case you do not have any URL params (Enter base app URL)
Any auth component has a CanActive guard, that checks for logged in state, if logged in, navigates to current Vendor, if not, sign-in will be displayed.
First route:
{ path: '', redirectTo: 'auth', pathMatch: 'full' },
{
path: 'auth',
component: AuthPageComponent,
canActivate: [AppLoggedOutGuard],
children: [
{ path: '', redirectTo: 'sign-in', pathMatch: 'full' },
{
path: 'sign-in',
component: LoginPageComponent
},
{
path: 'sign-up',
data: { signUpBenefits },
component: VendorSignUpComponent
}
]
},
LoggedOut guard
@Injectable()
export class AppLoggedOutGuard extends AppRoleGuard implements CanActivate {
constructor(
store: Store<IAppState>,
router: Router,
private _appAuthService: AppAuthService
) {
super(router, store);
}
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
return this._user$
.pipe(
take(1),
switchMap(() => this._appAuthService.getLoggedInState()),
map((isLoggedIn) => {
if (isLoggedIn) {
this._navigateToVendor();
return false;
}
return true;
})
);
}
private _navigateToVendor(): void {
this._store.select(selectCurrentVendor)
.pipe(
filter((vendor) => !!vendor),
take(1)
).subscribe((vendor) => {
this._router.navigate(['/vendors', vendor.id, 'dashboard']);
});
}
}
For fetching extra data, you can use a resolver on the Vendor(Or you entity) base component