Skip to content

Commit

Permalink
fix: implement requested changes
Browse files Browse the repository at this point in the history
- floating buttons changed to normal icon buttons and tooltip with text added
- added a label in the wishlist list to indicate that the wishlist is shared
- fixed the problems when the wishlist is no longer shared -> redirect to error page
- fixed the problem with duplicate requests
- added a separate state for the shared wishlist so that logged in users can use the link to the shared wishlist
  • Loading branch information
fgiesske-intershop committed Oct 16, 2024
1 parent 38f69b4 commit c02dfbc
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 40 deletions.
6 changes: 6 additions & 0 deletions src/app/extensions/wishlists/facades/wishlists.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import {
getAllWishlistsItemsSkus,
getPreferredWishlist,
getSelectedWishlistDetails,
getSharedWishlist,
getSharedWishlistError,
getSharedWishlistLoading,
getWishlistsError,
getWishlistsLoading,
moveItemToWishlist,
Expand All @@ -35,6 +38,9 @@ export class WishlistsFacade {
allWishlistsItemsSkus$: Observable<string[]> = this.store.pipe(select(getAllWishlistsItemsSkus));
wishlistLoading$: Observable<boolean> = this.store.pipe(select(getWishlistsLoading));
wishlistError$: Observable<HttpError> = this.store.pipe(select(getWishlistsError));
sharedWishlist$: Observable<Wishlist> = this.store.pipe(select(getSharedWishlist));
sharedWishlistLoading$: Observable<boolean> = this.store.pipe(select(getSharedWishlistLoading));
sharedWishlistError$: Observable<HttpError> = this.store.pipe(select(getSharedWishlistError));

wishlistSelectOptions$(filterCurrent = true) {
return this.wishlists$.pipe(
Expand Down
41 changes: 28 additions & 13 deletions src/app/extensions/wishlists/guards/fetch-shared-wishlist.guard.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
import { inject } from '@angular/core';
import { ActivatedRouteSnapshot } from '@angular/router';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { Store, select } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';

import { wishlistActions } from '../store/wishlist';
import { isSharedWishlistLoaded, isSharedWishlistLoading, wishlistActions } from '../store/wishlist';

/**
* Fetch the shared wishlist
*/
export function fetchSharedWishlistGuard(route: ActivatedRouteSnapshot): boolean | Observable<boolean> {
const store = inject(Store);
const wishlistId = route.params.wishlistId;
const owner = route.queryParams.owner;
const secureCode = route.queryParams.secureCode;

return store.pipe(
tap(() => {
store.dispatch(
wishlistActions.loadSharedWishlist({
wishlistId: route.params.wishlistId,
owner: route.queryParams.owner,
secureCode: route.queryParams.secureCode,
})
select(isSharedWishlistLoaded(wishlistId)),
switchMap(loaded => {
if (loaded) {
return of(true);
}

return store.pipe(
select(isSharedWishlistLoading(wishlistId)),
tap(loading => {
if (!loading) {
store.dispatch(
wishlistActions.loadSharedWishlist({
wishlistId,
owner,
secureCode,
})
);
}
}),
map(() => true)
);
}),
map(() => true)
})
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,41 @@
/></a>
</div>

<ul class="share-tools">
<li>
<ul class="row list-unstyled justify-content-end">
<li class="p-2">
<button
type="button"
*ngIf="wishlist.shared"
(click)="unshareWishlist(wishlist.id)"
class="btn-tool btn-link float-right"
class="btn-tool btn-link"
data-testing-id="wishlist-stop-sharing"
title="{{ 'account.wishlist.header.stop_wishlist_sharing.label' | translate }}"
>
<fa-icon icon="pause" />
<span class="share-label">{{ 'account.wishlist.header.stop_wishlist_sharing.label' | translate }}</span>
<fa-icon [icon]="['fas', 'pause']" />
</button>
</li>

<li>
<li class="p-2">
<button
type="button"
(click)="shareWishlistDialog.show()"
class="btn-tool btn-link float-right"
class="btn-tool btn-link"
data-testing-id="wishlist-sharing"
title="{{ 'account.wishlist.header.send_wishlist.label' | translate }}"
>
<fa-icon icon="paper-plane" />
<span class="share-label">{{ 'account.wishlist.header.send_wishlist.label' | translate }}</span>
<fa-icon [icon]="['fas', 'paper-plane']" />
</button>
</li>

<li>
<li class="p-2 pr-4">
<button
type="button"
(click)="editWishlistDialog.show()"
class="btn-tool btn-link float-right"
class="btn-tool btn-link"
data-testing-id="wishlist-details-edit"
title="{{ 'account.wishlist.header.edit_wishlist.label' | translate }}"
>
<fa-icon icon="pencil-alt" />
<span class="share-label">{{ 'account.wishlist.header.edit_wishlist.label' | translate }}</span>
<fa-icon [icon]="['fas', 'pencil-alt']" />
</button>
</li>
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
><span *ngIf="wishlist.preferred" class="input-help pl-3">{{
'account.wishlists.table.preferred' | translate
}}</span>
<span *ngIf="wishlist.preferred && wishlist.shared" class="input-help p-1">|</span>
<span *ngIf="wishlist.shared" class="input-help">{{ 'account.wishlists.table.shared' | translate }}</span>
</div>
<div class="col-2 list-item">
{{ 'account.wishlists.items' | translate : { '0': wishlist.itemsCount } }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
<!-- Error message -->
<ish-error-message [error]="wishlistError$ | async" />

<div *ngIf="wishlist$ | async as wishlist" class="col-9" data-testing-id="shared-wishlist">
<h1>{{ wishlist.title }}</h1>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

import { HttpError } from 'ish-core/models/http-error/http-error.model';

import { WishlistsFacade } from '../../facades/wishlists.facade';
import { WishlistItem } from '../../models/wishlist/wishlist.model';
import { Wishlist, WishlistItem } from '../../models/wishlist/wishlist.model';

@Component({
selector: 'ish-wishlist-page',
templateUrl: './shared-wishlist-page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SharedWishlistPageComponent {
private readonly wishlistsFacade = inject(WishlistsFacade);
export class SharedWishlistPageComponent implements OnInit {
wishlist$: Observable<Wishlist>;
wishlistError$: Observable<HttpError>;
wishlistLoading$: Observable<boolean>;

constructor(private wishlistsFacade: WishlistsFacade) {}

wishlist$ = this.wishlistsFacade.currentWishlist$;
wishlistError$ = this.wishlistsFacade.wishlistError$;
wishlistLoading$ = this.wishlistsFacade.wishlistLoading$;
ngOnInit() {
this.wishlist$ = this.wishlistsFacade.sharedWishlist$;
this.wishlistError$ = this.wishlistsFacade.sharedWishlistError$;
this.wishlistLoading$ = this.wishlistsFacade.sharedWishlistLoading$;
}

trackByFn(_: number, item: WishlistItem) {
return item.id;
Expand Down
24 changes: 22 additions & 2 deletions src/app/extensions/wishlists/store/wishlist/wishlist.effects.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
import { routerNavigatedAction } from '@ngrx/router-store';
import { Store, select } from '@ngrx/store';
import { debounceTime, filter, map, mergeMap, switchMap } from 'rxjs/operators';
import { from } from 'rxjs';
import { concatMap, debounceTime, filter, map, mergeMap, switchMap, take } from 'rxjs/operators';

import { displaySuccessMessage } from 'ish-core/store/core/messages';
import { ofUrl, selectRouteParam } from 'ish-core/store/core/router';
Expand Down Expand Up @@ -49,7 +51,12 @@ import { getSelectedWishlistDetails, getSelectedWishlistId, getWishlistDetails }

@Injectable()
export class WishlistEffects {
constructor(private actions$: Actions, private wishlistService: WishlistService, private store: Store) {}
constructor(
private actions$: Actions,
private wishlistService: WishlistService,
private store: Store,
private router: Router
) {}

loadWishlists$ = createEffect(() =>
this.actions$.pipe(
Expand Down Expand Up @@ -281,10 +288,23 @@ export class WishlistEffects {
mapToPayload(),
mergeMap(payload =>
this.wishlistService.getSharedWishlist(payload.wishlistId, payload.owner, payload.secureCode).pipe(
take(1),
map(wishlist => wishlistApiActions.loadSharedWishlistSuccess({ wishlist })),
mapErrorToAction(wishlistApiActions.loadSharedWishlistFail)
)
)
)
);

loadSharedWishlistFailed$ = createEffect(() =>
this.actions$.pipe(
ofType(wishlistApiActions.loadSharedWishlistFail),
mapToPayloadProperty('error'),
concatMap(() =>
from(this.router.navigate(['/error'])).pipe(
map(() => ({ type: '[Wishlist API] Navigation Success' })) // No-op action
)
)
)
);
}
24 changes: 23 additions & 1 deletion src/app/extensions/wishlists/store/wishlist/wishlist.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export interface WishlistState extends EntityState<Wishlist> {
loading: boolean;
selected: string;
error: HttpError;
sharedWishlist: Wishlist;
sharedWishlistLoading: boolean;
sharedWishlistError: HttpError;
}

export const wishlistsAdapter = createEntityAdapter<Wishlist>({
Expand All @@ -42,6 +45,9 @@ export const initialState: WishlistState = wishlistsAdapter.getInitialState({
loading: false,
selected: undefined,
error: undefined,
sharedWishlist: undefined,
sharedWishlistLoading: false,
sharedWishlistError: undefined,
});

export const wishlistReducer = createReducer(
Expand Down Expand Up @@ -133,5 +139,21 @@ export const wishlistReducer = createReducer(
};

return wishlistsAdapter.upsertOne(updatedWishlist, state);
})
}),
on(
wishlistApiActions.loadSharedWishlistSuccess,
(state, action): WishlistState => ({
...state,
sharedWishlist: action.payload.wishlist,
sharedWishlistLoading: false,
})
),
on(
wishlistApiActions.loadSharedWishlistFail,
(state, action): WishlistState => ({
...state,
sharedWishlistLoading: false,
sharedWishlistError: action.payload.error,
})
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isArrayEqual } from 'ish-core/utils/functions';
import { Wishlist } from '../../models/wishlist/wishlist.model';
import { getWishlistsState } from '../wishlists-store';

import { initialState, wishlistsAdapter } from './wishlist.reducer';
import { WishlistState, initialState, wishlistsAdapter } from './wishlist.reducer';

const getWishlistState = createSelector(getWishlistsState, state => (state ? state.wishlists : initialState));

Expand Down Expand Up @@ -39,3 +39,21 @@ export const getAllWishlistsItemsSkus = createSelectorFactory<object, string[]>(
)(getAllWishlists, (wishlists: Wishlist[]): string[] =>
uniq(wishlists.map(wishlist => wishlist.items.map(items => items.sku)).flat())
);

export const getSharedWishlist = createSelector(getWishlistState, (state: WishlistState) => state.sharedWishlist);

export const getSharedWishlistLoading = createSelector(
getWishlistState,
(state: WishlistState) => state.sharedWishlistLoading
);

export const getSharedWishlistError = createSelector(
getWishlistState,
(state: WishlistState) => state.sharedWishlistError
);

export const isSharedWishlistLoading = (wishlistId: string) =>
createSelector(getWishlistState, (state: WishlistState) => state.loading && state.selected === wishlistId);

export const isSharedWishlistLoaded = (wishlistId: string) =>
createSelector(selectEntities, entities => !!entities[wishlistId]);
1 change: 1 addition & 0 deletions src/assets/i18n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@
"account.wishlists.no_items": "You have not added any available items to your wish list.",
"account.wishlists.no_wishlists": "Currently you don’t have any wish lists.",
"account.wishlists.table.preferred": "Preferred",
"account.wishlists.table.shared": "Shared",
"account.wishlists.widget.heading": "Your wish list items",
"account.wishlists.wishlist_form.cancel_button.text": "Cancel",
"account.wishlists.wishlist_form.name.error.maxlength": "The wish list name must not exceed 35 characters. ",
Expand Down

0 comments on commit c02dfbc

Please sign in to comment.