Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
feat: allow disconnect of existing interceptors (#1249)
Browse files Browse the repository at this point in the history
* feat: notifications from interceptors can now be disconnected

* feat: added translation for addToCart notification

* feat: move of notification-functions to default-theme
  • Loading branch information
niklaswolf authored Nov 30, 2020
1 parent 237b489 commit 19bc146
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 52 deletions.
10 changes: 8 additions & 2 deletions api/composables.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ export function getDefaultApiParams(): {
[composableName: string]: ShopwareSearchParams;
};

// @beta
export interface IInterceptorCallbackFunction {
// (undocumented)
(payload: any, rootContext?: ApplicationVueContext_2): void;
}

// @beta
export const INTERCEPTOR_KEYS: {
ADD_TO_CART: string;
Expand Down Expand Up @@ -230,8 +236,8 @@ export interface IUseCheckout {
// @beta
export interface IUseIntercept {
broadcast: (broadcastKey: string, value?: any) => void;
disconnect: (broadcastKey: string, method: Function) => void;
intercept: (broadcastKey: string, method: Function) => void;
disconnect: (broadcastKey: string, method: IInterceptorCallbackFunction) => void;
intercept: (broadcastKey: string, method: IInterceptorCallbackFunction) => void;
}

// @beta
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@shopware-pwa/composables](./composables.md) &gt; [IInterceptorCallbackFunction](./composables.iinterceptorcallbackfunction.md)

## IInterceptorCallbackFunction interface

> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
>
interface for the callback function of interceptors

<b>Signature:</b>

```typescript
export interface IInterceptorCallbackFunction
```
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ Stop listening on event
<b>Signature:</b>

```typescript
disconnect: (broadcastKey: string, method: Function) => void;
disconnect: (broadcastKey: string, method: IInterceptorCallbackFunction) => void;
```
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ Intercept broadcasted event
<b>Signature:</b>

```typescript
intercept: (broadcastKey: string, method: Function) => void;
intercept: (broadcastKey: string, method: IInterceptorCallbackFunction) => void;
```
4 changes: 2 additions & 2 deletions docs/landing/resources/api/composables.iuseintercept.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export interface IUseIntercept
| Property | Type | Description |
| --- | --- | --- |
| [broadcast](./composables.iuseintercept.broadcast.md) | (broadcastKey: string, value?: any) =&gt; void | <b><i>(BETA)</i></b> Broadcast new event |
| [disconnect](./composables.iuseintercept.disconnect.md) | (broadcastKey: string, method: Function) =&gt; void | <b><i>(BETA)</i></b> Stop listening on event |
| [intercept](./composables.iuseintercept.intercept.md) | (broadcastKey: string, method: Function) =&gt; void | <b><i>(BETA)</i></b> Intercept broadcasted event |
| [disconnect](./composables.iuseintercept.disconnect.md) | (broadcastKey: string, method: [IInterceptorCallbackFunction](./composables.iinterceptorcallbackfunction.md)<!-- -->) =&gt; void | <b><i>(BETA)</i></b> Stop listening on event |
| [intercept](./composables.iuseintercept.intercept.md) | (broadcastKey: string, method: [IInterceptorCallbackFunction](./composables.iinterceptorcallbackfunction.md)<!-- -->) =&gt; void | <b><i>(BETA)</i></b> Intercept broadcasted event |

1 change: 1 addition & 0 deletions docs/landing/resources/api/composables.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
| --- | --- |
| [ApplicationVueContext](./composables.applicationvuecontext.md) | <b><i>(BETA)</i></b> Applicatoin Context for Shopware PWA. It's an extended Vue instance. |
| [CurrentPagination](./composables.currentpagination.md) | <b><i>(BETA)</i></b> |
| [IInterceptorCallbackFunction](./composables.iinterceptorcallbackfunction.md) | <b><i>(BETA)</i></b> interface for the callback function of interceptors |
| [IUseAddToCart](./composables.iuseaddtocart.md) | <b><i>(BETA)</i></b> interface for [useAddToCart](./composables.useaddtocart.md) composable |
| [IUseCart](./composables.iusecart.md) | <b><i>(BETA)</i></b> interface for [useCart](./composables.usecart.md) composable |
| [IUseCheckout](./composables.iusecheckout.md) | <b><i>(BETA)</i></b> interface for [useCheckout](./composables.usecheckout.md) composable |
Expand Down
15 changes: 12 additions & 3 deletions packages/composables/__tests__/useIntercept.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ describe("Composables - useIntercept", () => {
const interceptedMethod = jest.fn();
intercept("my-event", interceptedMethod);
broadcast("my-event", { someParam: 123 });
expect(interceptedMethod).toHaveBeenCalledWith({ someParam: 123 });
expect(interceptedMethod).toHaveBeenCalledWith(
{ someParam: 123 },
rootContextMock
);
});

it("should not intercept disconnected event interceptor", () => {
Expand All @@ -58,8 +61,14 @@ describe("Composables - useIntercept", () => {
intercept("my-event", interceptedMethod);
intercept("my-event", secondInterceptedMethod);
broadcast("my-event", { someParam: 123 });
expect(interceptedMethod).toHaveBeenCalledWith({ someParam: 123 });
expect(secondInterceptedMethod).toHaveBeenCalledWith({ someParam: 123 });
expect(interceptedMethod).toHaveBeenCalledWith(
{ someParam: 123 },
rootContextMock
);
expect(secondInterceptedMethod).toHaveBeenCalledWith(
{ someParam: 123 },
rootContextMock
);
});

it("should not invoke any interceptor if there are no registered methods", () => {
Expand Down
8 changes: 6 additions & 2 deletions packages/composables/src/hooks/useUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ import { CustomerRegistrationParams } from "@shopware-pwa/commons/interfaces/req
import { ClientApiError } from "@shopware-pwa/commons/interfaces/errors/ApiError";
import { Country } from "@shopware-pwa/commons/interfaces/models/system/country/Country";
import { Salutation } from "@shopware-pwa/commons/interfaces/models/system/salutation/Salutation";
import { INTERCEPTOR_KEYS, useIntercept } from "@shopware-pwa/composables";
import {
IInterceptorCallbackFunction,
INTERCEPTOR_KEYS,
useIntercept,
} from "@shopware-pwa/composables";
import { ApplicationVueContext, getApplicationContext } from "../appContext";

/**
Expand Down Expand Up @@ -162,7 +166,7 @@ export const useUser = (rootContext: ApplicationVueContext): IUseUser => {
await refreshUser();
}
};
const onLogout = (fn: Function) =>
const onLogout = (fn: IInterceptorCallbackFunction) =>
intercept(INTERCEPTOR_KEYS.USER_LOGOUT, fn);

const refreshUser = async (): Promise<void> => {
Expand Down
3 changes: 2 additions & 1 deletion packages/composables/src/logic/useAddToCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
useCart,
INTERCEPTOR_KEYS,
useIntercept,
IInterceptorCallbackFunction,
} from "@shopware-pwa/composables";
import { ClientApiError } from "@shopware-pwa/commons/interfaces/errors/ApiError";
import { ApplicationVueContext, getApplicationContext } from "../appContext";
Expand Down Expand Up @@ -103,7 +104,7 @@ export const useAddToCart = (
}
};

const onAddToCart = (fn: Function) =>
const onAddToCart = (fn: IInterceptorCallbackFunction) =>
intercept(INTERCEPTOR_KEYS.ADD_TO_CART, fn);

const getStock = computed(() => product && product.stock);
Expand Down
43 changes: 33 additions & 10 deletions packages/composables/src/logic/useIntercept.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ export const INTERCEPTOR_KEYS = {
USER_LOGOUT: "onUserLogout",
};

/**
* interface for the callback function of interceptors
* @beta
*/
export interface IInterceptorCallbackFunction {
(payload: any, rootContext?: ApplicationVueContext): void;
}

/**
* interface for {@link useIntercept} composable
* @beta
Expand All @@ -48,11 +56,17 @@ export interface IUseIntercept {
/**
* Intercept broadcasted event
*/
intercept: (broadcastKey: string, method: Function) => void;
intercept: (
broadcastKey: string,
method: IInterceptorCallbackFunction
) => void;
/**
* Stop listening on event
*/
disconnect: (broadcastKey: string, method: Function) => void;
disconnect: (
broadcastKey: string,
method: IInterceptorCallbackFunction
) => void;
}

/**
Expand All @@ -65,34 +79,43 @@ export const useIntercept = (
): IUseIntercept => {
const { interceptors } = getApplicationContext(rootContext, "useIntercept");

const localSunscribers: any[] = [];
const localSubscribers: any[] = [];
const isVueInstance: boolean = !!getCurrentInstance();

const broadcast = (broadcastKey: string, value?: any) => {
if (interceptors[broadcastKey]?.length) {
interceptors[broadcastKey].forEach((broadcastMethod: Function) =>
broadcastMethod(value)
interceptors[
broadcastKey
].forEach((broadcastMethod: IInterceptorCallbackFunction) =>
broadcastMethod(value, rootContext)
);
}
};

const intercept = (broadcastKey: string, method: Function) => {
const intercept = (
broadcastKey: string,
method: IInterceptorCallbackFunction
) => {
if (!interceptors[broadcastKey]) interceptors[broadcastKey] = [];
interceptors[broadcastKey].push(method);
isVueInstance && localSunscribers.push({ broadcastKey, method });
isVueInstance && localSubscribers.push({ broadcastKey, method });
};

const disconnect = (broadcastKey: string, method: Function) => {
const disconnect = (
broadcastKey: string,
method: IInterceptorCallbackFunction
) => {
interceptors[broadcastKey] =
interceptors[broadcastKey]?.filter(
(subscribedMethod: Function) => subscribedMethod !== method
(subscribedMethod: IInterceptorCallbackFunction) =>
subscribedMethod !== method
) || [];
};

// Automatically clean listener if it was used in Vue component
isVueInstance &&
onUnmounted(() => {
localSunscribers.forEach(({ broadcastKey, method }) => {
localSubscribers.forEach(({ broadcastKey, method }) => {
disconnect(broadcastKey, method);
});
});
Expand Down
3 changes: 2 additions & 1 deletion packages/default-theme/src/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,6 @@
"Enter promo code": "Rabattcode eingeben",
"Applied promo codes:": "Angewandte Rabattcodes:",
"Promotion code added successfully": "Rabattcode wurde erfolgreich angewendet",
"Promotion code does not exist": "Rabattcode existiert nicht"
"Promotion code does not exist": "Rabattcode existiert nicht",
"{productName} has been added to cart.": "{productName} wurde dem Warenkorb hinzugefügt."
}
3 changes: 2 additions & 1 deletion packages/default-theme/src/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,6 @@
"Tap any heart next to a product to favorite.": "Tap any heart next to a product to favorite.",
"We’ll save them for you here!": "We’ll save them for you here!",
"No favourites yet": "No favourites yet",
"Wishlist": "Wishlist"
"Wishlist": "Wishlist",
"{productName} has been added to cart.": "{productName} has been added to cart."
}
1 change: 1 addition & 0 deletions packages/default-theme/src/logic/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "@theme/logic/useLocales"
export * from "@/logic/notifications"
28 changes: 28 additions & 0 deletions packages/default-theme/src/logic/notifications/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useNotifications } from "@shopware-pwa/composables"

export const addToCartNotification = (product, rootContext) => {
const { pushSuccess } = useNotifications(rootContext)
pushSuccess(
rootContext.i18n.t("{productName} has been added to cart.", {
productName: product?.translated?.name || product?.name,
})
)
}

export const addPromotionCodeNotification = (result, rootContext) => {
const { pushSuccess, pushError } = useNotifications(rootContext)
// It's strange that success also ends up as an error in the API response
const err = Object.values(result.errors)[0]
if (err) {
switch (err.messageKey) {
case "promotion-discount-added":
pushSuccess(rootContext.i18n.t("Promotion code added successfully"))
break
case "promotion-not-found":
pushError(rootContext.i18n.t("Promotion code does not exist"))
break
default:
pushError(err.message.toString())
}
}
}
35 changes: 7 additions & 28 deletions packages/default-theme/src/plugins/notifications.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
import { useIntercept, INTERCEPTOR_KEYS } from "@shopware-pwa/composables"
import {
useIntercept,
INTERCEPTOR_KEYS,
useNotifications,
} from "@shopware-pwa/composables"
addPromotionCodeNotification,
addToCartNotification,
} from "@/logic/notifications"

export default async ({ app }) => {
export default ({ app }) => {
const { intercept } = useIntercept(app)
const { pushSuccess, pushError } = useNotifications(app)
intercept(INTERCEPTOR_KEYS.ADD_TO_CART, function ({ product }) {
pushSuccess(
`${product?.translated?.name || product?.name} has been added to cart.`
)
})

intercept(INTERCEPTOR_KEYS.ADD_PROMOTION_CODE, function ({ result }) {
// It's strange that success also ends up as an error in the API response
const err = Object.values(result.errors)[0]
if (err) {
switch (err.messageKey) {
case "promotion-discount-added":
pushSuccess(app.i18n.t("Promotion code added successfully"))
break
case "promotion-not-found":
pushError(app.i18n.t("Promotion code does not exist"))
break
default:
pushError(err.message.toString())
}
}
})
intercept(INTERCEPTOR_KEYS.ADD_TO_CART, addToCartNotification)
intercept(INTERCEPTOR_KEYS.ADD_PROMOTION_CODE, addPromotionCodeNotification)
}

1 comment on commit 19bc146

@vercel
Copy link

@vercel vercel bot commented on 19bc146 Nov 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.