Untitled
unknown
plain_text
11 days ago
7.9 kB
3
Indexable
import RestClient from '@/util/api'; import '@/core/api'; import { RestClientError } from '@/core/RestClientError'; import ScId from '@/onCommerce/sc-common/ScId'; import { Trans, useTranslation } from 'react-i18next'; import useGlobalNotification from '@/core/GlobalNotification/useGlobalNotification'; import { QueryKey, useQueryClient } from 'react-query'; import { TFunction } from 'i18next'; import { Client, Message, Subscription } from 'webstomp-client'; import { useClient } from '@/portal/views/ClientProvider'; import { useEffect } from 'react'; import TextLink from '@/core/components/TextLink/TextLink'; import { GlobalNotificationContextState } from '@/core/GlobalNotification/GlobalNotificationContext'; /** * Convenience wrapper around the RestClient in order to simplify read and write operations in screen components. */ export default class ScBackend { /** * Wrapper so send a read operation in screen components. The base part for the URL is already set here 'api/uib/onCommerce/' * @param url The url of the operation without slash at the beginning e.g. 'basket/data' * @param params Any request params to append to the URL (optional; disallows url-embedding; converts via Object.entries() with basic support for non-nested arrays). * @param scId The screen component ID. */ public static read(url: string, scId: ScId, params?: object): any { if (params != null) { url += `?${this.buildQueryParams(params)}`; } return RestClient.get(`./api/uib/onCommerce/${url}`, null, { headers: { 'Component-Id': scId.toRequestHeaderValue(), }, }).catch(err => { throw new RestClientError(err, err.status); }); } private static buildQueryParams(parameterObject: object): URLSearchParams { const params = new URLSearchParams(); Object.entries(parameterObject).forEach(([key, value]) => { if (Array.isArray(value)) { value.forEach(v => params.append(key, this.encodeQueryParam(v))); } else if (value != null) { params.append(key, this.encodeQueryParam(value)); } }); return params; } private static encodeQueryParam(param: unknown): string { if ( typeof param === 'string' || typeof param === 'number' || typeof param === 'boolean' ) { return encodeURIComponent(param); } else { return encodeURIComponent(String(param)); } } /** * Wrapper so send a write operation in screen components. The base part for the URL is already set here 'api/uib/onCommerce/' * @param url The url of the operation without slash at the beginning e.g. 'basket/data' * @param data The data of the operation. * @param scId The screen component ID. */ public static write(url: string, data: any, scId: ScId): any { return RestClient.post(`./api/uib/onCommerce/${url}`, data, { headers: { 'Component-Id': scId.toRequestHeaderValue(), }, }).catch((error: any) => { throw new RestClientError(error); }); } } /** * Error handler displaying a given error or default fallback message * @param eShopErrorPrefix Error message to be attached to displayed when no specific backend message */ export const handleErrorWithFallback = ( t: TFunction, notification: GlobalNotificationContextState, eShopErrorPrefix?: string ) => { return (error: RestClientError) => { let message; const translationKey = error?.responseJSON?.translationKey; const translationData = error?.responseJSON?.translationData; if ( (translationKey && !translationData) || (translationKey && translationData && !Object.keys(translationData).length) ) { message = t(translationKey); } else if ( translationKey && translationData && Object.keys(translationData).length ) { message = t(translationKey, { ...translationData, }); } else if (eShopErrorPrefix) { message = ( <> {`${eShopErrorPrefix} `} <Trans i18nKey="errorHandling:contactEshopSupport" t={t}> {' '} <TextLink text={'support-omnipluseshop-hq@daimlertruck.com'} url={`mailto:support-omnipluseshop-hq@daimlertruck.com`} />{' '} </Trans> </> ); } else { message = t('errorHandling:system.failure', { systemName: 'Backend', }); } notification.showNotification({ message, severity: 'error', }); }; }; /** * Error handler displaying a global notification for a given error * @param eShopErrorPrefix Error message to be attached to displayed when no specific backend message */ export const useHandleErrorWithFallback = (eShopErrorPrefix?: string) => { const { t } = useTranslation(['common', 'errorHandling', 'htmlMail']); const notification = useGlobalNotification(); return handleErrorWithFallback(t, notification, eShopErrorPrefix); }; /** * Default mutation handler overwriting the query data for the given QueryKey * with the new data received on success and displaying a success notification. */ export const useDefaultMutationOptions = <T,>(queryKey: QueryKey) => { const { t } = useTranslation(['common', 'errorHandling']); const notification = useGlobalNotification(); const queryClient = useQueryClient(); return { onError: handleErrorWithFallback(t, notification), onSuccess: (result: T) => { queryClient.setQueryData(queryKey, result); const message = t('common:editSuccess'); notification.showNotification({ message, severity: 'success', }); }, }; }; /** * Mutation handler displaying a notification only in case of an error. */ export const useSilentActionMutationOptions = () => { const { t } = useTranslation(['errorHandling']); const notification = useGlobalNotification(); return { onError: handleErrorWithFallback(t, notification), }; }; /** * Mutation handler displaying a notification on error and success but not * overwriting the query cache. */ export const useActionMutationOptions = <T,>() => { const { t } = useTranslation(['common', 'errorHandling']); const notification = useGlobalNotification(); return { onError: handleErrorWithFallback(t, notification), onSuccess: () => { const message = t('common:editSuccess'); notification.showNotification({ message, severity: 'success', }); }, }; }; interface WebsocketSignal { signal: string; } /** * Hook for subscribing to the standard refetch signal for an SC topic. */ export const useRefetchSubscription = ( topic: SubscriptionTopic, action: () => void ) => { return useSubscription(topic, (message?: WebsocketSignal) => { if (message?.signal === 'refetchData') { action(); } }); }; /** * Hook for creating a subscription on a given topic using the default websocket client. */ export const useSubscription = ( topic: SubscriptionTopic, messageHandler: (message: any) => void ) => { const client = useClient(); useEffect(() => { const subscription = client && createSubscription(client, topic, messageHandler); return () => { if (subscription) { subscription.unsubscribe(); } }; }, [client]); }; /** * Helper method creating a subscription on a given client and topic */ function createSubscription( client: Client, topic: string, callback: (messageBody: any) => void ): Subscription { const fullTopic = `/user/queue/oncommerce/sc/${topic}`; return client.subscribe(fullTopic, (message: Message) => { callback(JSON.parse(message.body)); }); } export enum SubscriptionTopic { Basket = 'basket', CrossSellingProducts = 'crossSellingProducts', EShopHeader = 'eShopHeader', OrderHistoryDetails = 'orderHistoryDetails', TrackRemoteEvent = 'trackRemoteEvent', }
Editor is loading...
Leave a Comment