feat(notification): integrate global notification plugin using ElNotification
Added a global `notify` method via Nuxt plugin to replace `useNotification`. Improved messaging structure by embedding progress bars and handled dynamic durations. Updated usage across composables and components for consistency. - Replaced `useNotification` with `$notify` in all applicable files. - Updated `app.config.ts` to support customizable notification positions. - Refactored affected composables for simplified notification calls. - Enhanced progress indicator display within notifications. Breaking Changes: `useNotification` is removed, requiring migration to the new `$notify` API.
This commit is contained in:
parent
2ea18eb8a6
commit
8d7685ef67
31 changed files with 257 additions and 199 deletions
3
storefront/app.config.d.ts
vendored
3
storefront/app.config.d.ts
vendored
|
|
@ -6,14 +6,13 @@ declare module 'nuxt/schema' {
|
|||
file: string;
|
||||
default: boolean;
|
||||
}>;
|
||||
defaultLocale: string;
|
||||
};
|
||||
ui: {
|
||||
showBreadcrumbs: boolean;
|
||||
showSearchBar: boolean;
|
||||
isHeaderFixed: boolean;
|
||||
isAuthModals: boolean;
|
||||
toastPosition: string;
|
||||
notificationPosition: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ export default defineAppConfig({
|
|||
showSearchBar: true,
|
||||
isHeaderFixed: true,
|
||||
isAuthModals: false,
|
||||
toastPosition: 'top-right',
|
||||
notificationPosition: 'top-right',
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ const appStore = useAppStore();
|
|||
const { $appHelpers } = useNuxtApp();
|
||||
|
||||
const { isDemoMode, uiConfig } = useProjectConfig();
|
||||
const toaster = { position: uiConfig.value.toastPosition };
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
|
||||
const showBreadcrumbs = computed(() => {
|
||||
|
|
|
|||
|
|
@ -99,10 +99,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header__search" :class="[{ active: isSearchVisible }]">
|
||||
<div class="header__search" :class="[{ active: isSearchVisible && uiConfig.showSearchBar }]">
|
||||
<ui-search
|
||||
ref="searchRef"
|
||||
v-if="uiConfig.showSearchBar"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -134,7 +133,6 @@ const cookieCart = useCookie($appHelpers.COOKIES_CART_KEY, {
|
|||
default: () => [],
|
||||
path: '/',
|
||||
});
|
||||
console.log(cookieCart.value)
|
||||
|
||||
const productsInCartQuantity = computed(() => {
|
||||
if (isAuthenticated.value) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useLocaleRedirect } from '@composables/languages';
|
||||
import { useNotification } from '@composables/notification';
|
||||
import { useUserBaseData } from '@composables/user';
|
||||
import { LOGIN } from '@graphql/mutations/auth';
|
||||
import type { ILoginResponse } from '@types';
|
||||
|
|
@ -8,9 +7,10 @@ export function useLogin() {
|
|||
const { t } = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const localePath = useLocalePath();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const { checkAndRedirect } = useLocaleRedirect();
|
||||
const { loadUserBaseData } = useUserBaseData();
|
||||
|
||||
const cookieRefresh = useCookie($appHelpers.COOKIES_REFRESH_TOKEN_KEY, {
|
||||
default: () => '',
|
||||
|
|
@ -25,53 +25,53 @@ export function useLogin() {
|
|||
path: '/',
|
||||
});
|
||||
|
||||
const { mutate, loading, error } = useMutation<ILoginResponse>(LOGIN);
|
||||
const { mutate, loading } = useMutation<ILoginResponse>(LOGIN);
|
||||
|
||||
|
||||
async function login(email: string, password: string, isStayLogin: boolean) {
|
||||
const result = await mutate({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
const authData = result?.data?.obtainJwtToken;
|
||||
if (!authData) return;
|
||||
try {
|
||||
const result = await mutate({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
const authData = result?.data?.obtainJwtToken;
|
||||
if (!authData) return;
|
||||
|
||||
if (isStayLogin && authData.refreshToken) {
|
||||
cookieRefresh.value = authData.refreshToken;
|
||||
if (isStayLogin && authData.refreshToken) {
|
||||
cookieRefresh.value = authData.refreshToken;
|
||||
}
|
||||
|
||||
userStore.setUser(authData.user);
|
||||
cookieAccess.value = authData.accessToken;
|
||||
|
||||
navigateTo(localePath('/'));
|
||||
|
||||
$notify({
|
||||
message: t('popup.success.login'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
if (authData.user.language !== cookieLocale.value) {
|
||||
await checkAndRedirect(authData.user.language);
|
||||
}
|
||||
|
||||
await loadUserBaseData(authData.user.email);
|
||||
} catch (err: unknown) {
|
||||
console.error('useLogin error:', err);
|
||||
let message = t('popup.errors.defaultError');
|
||||
if (isGraphQLError(err)) {
|
||||
message = err.graphQLErrors?.[0]?.message || message;
|
||||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
});
|
||||
}
|
||||
|
||||
userStore.setUser(authData.user);
|
||||
cookieAccess.value = authData.accessToken;
|
||||
|
||||
navigateTo(localePath('/'));
|
||||
|
||||
useNotification({
|
||||
message: t('popup.success.login'),
|
||||
type: 'success',
|
||||
});
|
||||
|
||||
if (authData.user.language !== cookieLocale.value) {
|
||||
await checkAndRedirect(authData.user.language);
|
||||
}
|
||||
|
||||
await useUserBaseData(authData.user.email);
|
||||
}
|
||||
|
||||
watch(error, (err) => {
|
||||
if (!err) return;
|
||||
console.error('useLogin error:', err);
|
||||
let message = t('popup.errors.defaultError');
|
||||
if (isGraphQLError(err)) {
|
||||
message = err.graphQLErrors?.[0]?.message || message;
|
||||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
login,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { NEW_PASSWORD } from '@graphql/mutations/auth.js';
|
||||
import type { INewPasswordResponse } from '@types';
|
||||
|
||||
export function useNewPassword() {
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const { $notify } = useNuxtApp();
|
||||
const localePath = useLocalePath();
|
||||
|
||||
const token = useRouteQuery('token', '');
|
||||
|
|
@ -21,7 +21,7 @@ export function useNewPassword() {
|
|||
});
|
||||
|
||||
if (result?.data?.confirmResetPassword.success) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.newPassword'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -43,7 +43,7 @@ export function useNewPassword() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { RESET_PASSWORD } from '@graphql/mutations/auth.js';
|
||||
import type { IPasswordResetResponse } from '@types';
|
||||
|
||||
export function usePasswordReset() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { mutate, loading, error } = useMutation<IPasswordResetResponse>(RESET_PASSWORD);
|
||||
|
|
@ -14,7 +14,7 @@ export function usePasswordReset() {
|
|||
});
|
||||
|
||||
if (result?.data?.resetPassword.success) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.reset'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -32,7 +32,7 @@ export function usePasswordReset() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useLogout } from '@composables/auth';
|
||||
import { useLocaleRedirect } from '@composables/languages';
|
||||
import { useNotification } from '@composables/notification';
|
||||
import { useUserBaseData } from '@composables/user';
|
||||
import { REFRESH } from '@graphql/mutations/auth';
|
||||
|
||||
|
|
@ -9,9 +8,10 @@ export function useRefresh() {
|
|||
const router = useRouter();
|
||||
const localePath = useLocalePath();
|
||||
const userStore = useUserStore();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const { checkAndRedirect } = useLocaleRedirect();
|
||||
const { loadUserBaseData } = useUserBaseData();
|
||||
const { logout } = useLogout();
|
||||
|
||||
const { mutate, loading, error } = useMutation(REFRESH);
|
||||
|
|
@ -65,7 +65,7 @@ export function useRefresh() {
|
|||
await checkAndRedirect(data.user.language);
|
||||
}
|
||||
|
||||
await useUserBaseData(data.user.email);
|
||||
await loadUserBaseData(data.user.email);
|
||||
} catch (err) {
|
||||
if (isTokenInvalidError(err)) {
|
||||
await logout();
|
||||
|
|
@ -83,7 +83,7 @@ export function useRefresh() {
|
|||
message = err;
|
||||
}
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
@ -107,7 +107,7 @@ export function useRefresh() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { useMailClient } from '@composables/utils';
|
||||
import { REGISTER } from '@graphql/mutations/auth.js';
|
||||
import type { IRegisterResponse } from '@types';
|
||||
|
|
@ -16,6 +15,7 @@ interface IRegisterArguments {
|
|||
|
||||
export function useRegister() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { mailClientUrl, detectMailClient, openMailClient } = useMailClient();
|
||||
|
|
@ -37,7 +37,7 @@ export function useRegister() {
|
|||
if (result?.data?.createUser?.success) {
|
||||
detectMailClient(payload.email);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: h('div', [
|
||||
h('p', t('popup.success.register')),
|
||||
mailClientUrl.value
|
||||
|
|
@ -69,7 +69,7 @@ export function useRegister() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import type { AppConfig } from 'nuxt/schema';
|
||||
|
||||
export type DemoConfigKey = keyof AppConfig['ui'];
|
||||
|
||||
export const useProjectConfig = () => {
|
||||
const appConfig = useAppConfig();
|
||||
const { $notify } = useNuxtApp();
|
||||
const { t } = useI18n();
|
||||
|
||||
const demoOverridesCookie = useCookie<Partial<AppConfig['ui']>>('nuxt-demo-overrides', {
|
||||
|
|
@ -114,7 +114,7 @@ ${entries}
|
|||
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.configCopy'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { CONTACT_US } from '@graphql/mutations/contact';
|
||||
import type { IContactUsResponse } from '@types';
|
||||
|
||||
|
|
@ -12,6 +11,7 @@ interface IContactUsArguments {
|
|||
|
||||
export function useContactUs() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
|
||||
const { mutate, loading, error } = useMutation<IContactUsResponse>(CONTACT_US);
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ export function useContactUs() {
|
|||
const result = await mutate(variables);
|
||||
|
||||
if (result?.data?.contactUs.received) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.contactUs'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -49,7 +49,7 @@ export function useContactUs() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { MANAGE_FEEDBACK } from '@graphql/mutations/feedbacks';
|
||||
import type { IFeedbackActionResponse } from '@types';
|
||||
|
||||
|
|
@ -11,6 +10,7 @@ interface IFeedbackActionArguments {
|
|||
|
||||
export function useFeedbackAction() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const isAuthenticated = computed(() => userStore.isAuthenticated);
|
||||
|
|
@ -35,13 +35,13 @@ export function useFeedbackAction() {
|
|||
const result = await mutate(variables);
|
||||
|
||||
if (result?.data?.feedback) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.addFeedback'),
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.errors.loginFirst'),
|
||||
type: 'error',
|
||||
});
|
||||
|
|
@ -57,7 +57,7 @@ export function useFeedbackAction() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,36 +1,50 @@
|
|||
import type { VNodeChild } from 'vue';
|
||||
import type { VNodeChild } from 'vue'
|
||||
import type { NotificationOptions } from 'element-plus'
|
||||
|
||||
interface INotificationArguments {
|
||||
message: string | VNodeChild;
|
||||
type: string;
|
||||
title?: string;
|
||||
export interface INotificationArguments {
|
||||
message: string | VNodeChild
|
||||
type: 'success' | 'error' | 'warning' | 'info'
|
||||
title?: string
|
||||
}
|
||||
|
||||
export function useNotification(args: INotificationArguments) {
|
||||
const duration = 5000;
|
||||
export default defineNuxtPlugin(() => {
|
||||
const duration = 5000
|
||||
const config = useAppConfig()
|
||||
|
||||
const progressBar = h('div', {
|
||||
class: 'el-notification__progress',
|
||||
style: {
|
||||
animationDuration: `${duration}ms`,
|
||||
function notify(args: INotificationArguments) {
|
||||
const progressBar = h('div', {
|
||||
class: 'el-notification__progress',
|
||||
style: {
|
||||
animationDuration: `${duration}ms`,
|
||||
},
|
||||
})
|
||||
|
||||
const bodyContent =
|
||||
typeof args.message === 'string'
|
||||
? h('p', args.message)
|
||||
: args.message
|
||||
|
||||
const messageVNode = h('div', [
|
||||
bodyContent,
|
||||
progressBar,
|
||||
])
|
||||
|
||||
const notification = ElNotification({
|
||||
title: args.title,
|
||||
duration: 0,
|
||||
message: messageVNode,
|
||||
type: args.type,
|
||||
position: config.ui.notificationPosition,
|
||||
} as NotificationOptions)
|
||||
|
||||
setTimeout(() => {
|
||||
notification.close()
|
||||
}, duration)
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
notify,
|
||||
},
|
||||
});
|
||||
|
||||
const bodyContent: VNodeChild = typeof args.message === 'string' ? h('p', args.message) : args.message;
|
||||
|
||||
const messageVNode = h('div', [
|
||||
bodyContent,
|
||||
progressBar,
|
||||
]);
|
||||
|
||||
const notification = ElNotification({
|
||||
title: args.title,
|
||||
duration: 0,
|
||||
message: messageVNode,
|
||||
type: args.type,
|
||||
} as NotificationOptions);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.close();
|
||||
}, duration);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { BUY_CART } from '@graphql/mutations/cart';
|
||||
import type { IBuyOrderResponse } from '@types';
|
||||
|
||||
export function useOrderBuy() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const cartStore = useCartStore();
|
||||
|
||||
const orderUuid = computed(() => cartStore.currentOrder?.uuid);
|
||||
|
|
@ -32,7 +32,7 @@ export function useOrderBuy() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import {
|
||||
ADD_TO_CART,
|
||||
BULK_CART,
|
||||
|
|
@ -29,7 +28,7 @@ export function useOrderOverwrite() {
|
|||
const { t } = useI18n();
|
||||
const cartStore = useCartStore();
|
||||
const userStore = useUserStore();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const isAuthenticated = computed(() => userStore.isAuthenticated);
|
||||
const orderUuid = computed(() => cartStore.currentOrder?.uuid);
|
||||
|
|
@ -78,7 +77,7 @@ export function useOrderOverwrite() {
|
|||
if (addResult?.data?.addOrderProduct?.order) {
|
||||
cartStore.setCurrentOrders(addResult.data.addOrderProduct.order);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.addToCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -98,7 +97,7 @@ export function useOrderOverwrite() {
|
|||
if (removeResult?.data?.removeOrderProduct?.order) {
|
||||
cartStore.setCurrentOrders(removeResult.data.removeOrderProduct.order);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -118,7 +117,7 @@ export function useOrderOverwrite() {
|
|||
if (removeKindResult?.data?.removeOrderProductsOfAKind?.order) {
|
||||
cartStore.setCurrentOrders(removeKindResult.data.removeOrderProductsOfAKind.order);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -137,7 +136,7 @@ export function useOrderOverwrite() {
|
|||
if (removeAllResult?.data?.removeAllOrderProducts?.order) {
|
||||
cartStore.setCurrentOrders(removeAllResult.data.removeAllOrderProducts.order);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeAllFromCart'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -155,7 +154,7 @@ export function useOrderOverwrite() {
|
|||
|
||||
if (bulkResult?.data?.bulkOrderAction?.order) {
|
||||
cartStore.setCurrentOrders(bulkResult.data.bulkOrderAction.order);
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.bulkRemoveOrder'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -190,7 +189,7 @@ export function useOrderOverwrite() {
|
|||
|
||||
cookieCart.value = current;
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.addToCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -221,7 +220,7 @@ export function useOrderOverwrite() {
|
|||
|
||||
cookieCart.value = current;
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -237,7 +236,7 @@ export function useOrderOverwrite() {
|
|||
(item) => item.product.uuid !== args.productUuid
|
||||
);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromCart', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -250,7 +249,7 @@ export function useOrderOverwrite() {
|
|||
case 'removeAll': {
|
||||
cookieCart.value = [];
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeAllFromCart'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -267,7 +266,7 @@ export function useOrderOverwrite() {
|
|||
|
||||
if (bulkResult?.data?.bulkOrderAction?.order) {
|
||||
cartStore.setCurrentOrders(bulkResult.data.bulkOrderAction.order);
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.bulkRemoveOrder'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -287,18 +286,14 @@ export function useOrderOverwrite() {
|
|||
(errors) => {
|
||||
const err = errors.find(Boolean);
|
||||
if (!err) return;
|
||||
|
||||
console.error('useOrderOverwrite error:', err);
|
||||
|
||||
let message = t('popup.errors.defaultError');
|
||||
|
||||
if (isGraphQLError(err)) {
|
||||
message = err.graphQLErrors?.[0]?.message || message;
|
||||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { BUY_PRODUCT } from '@graphql/mutations/products';
|
||||
import type { IBuyProductResponse } from '@types';
|
||||
|
||||
|
|
@ -23,7 +22,7 @@ export function useProductBuy() {
|
|||
console.log(result?.data);
|
||||
}
|
||||
} else {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.errors.loginFirst'),
|
||||
type: 'error',
|
||||
});
|
||||
|
|
@ -39,7 +38,7 @@ export function useProductBuy() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ export function useValidators() {
|
|||
const { t } = useI18n();
|
||||
|
||||
const required = (text: string) => {
|
||||
if (text) return true;
|
||||
if (text?.trim()) return true;
|
||||
return t('errors.required');
|
||||
};
|
||||
|
||||
const isEmail = (email: string) => {
|
||||
if (!email) return required(email);
|
||||
if (/.+@.+\..+/.test(email)) return true;
|
||||
const value = email?.trim();
|
||||
|
||||
if (!value) return required(value);
|
||||
if (/.+@.+\..+/.test(value)) return true;
|
||||
return t('errors.mail');
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { SEARCH } from '@graphql/mutations/search';
|
||||
import type { ISearchResponse, ISearchResults } from '@types';
|
||||
|
||||
export function useSearch() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
|
||||
const searchResults = ref<ISearchResults | null>(null);
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ export function useSearch() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { UPLOAD_AVATAR } from '@graphql/mutations/user';
|
||||
import type { IAvatarUploadResponse } from '@types';
|
||||
|
||||
export function useAvatarUpload() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const userStore = useUserStore();
|
||||
const { mutate, onDone, error } = useMutation<IAvatarUploadResponse>(UPLOAD_AVATAR);
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ export function useAvatarUpload() {
|
|||
const user = data?.uploadAvatar.user;
|
||||
if (user) {
|
||||
userStore.setUser(user);
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.avatarUpload'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -43,7 +43,7 @@ export function useAvatarUpload() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { DEPOSIT } from '@graphql/mutations/deposit';
|
||||
|
||||
export function useDeposit() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
|
||||
const { mutate, loading, error } = useMutation(DEPOSIT);
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export function useDeposit() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useNotification } from '@composables/notification';
|
||||
import { ACTIVATE_USER } from '@graphql/mutations/user.js';
|
||||
import type { IUserActivationResponse } from '@types';
|
||||
|
||||
export function useUserActivation() {
|
||||
const { t } = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
|
||||
const { mutate, loading, error } = useMutation<IUserActivationResponse>(ACTIVATE_USER);
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ export function useUserActivation() {
|
|||
});
|
||||
|
||||
if (result?.data?.activateUser) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.activationSuccess'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -30,7 +30,7 @@ export function useUserActivation() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useWishlistSync } from '@composables/wishlist';
|
|||
import { getUserBaseData } from '@graphql/queries/combined/userBaseData';
|
||||
import type { IUserBaseDataResponse } from '@types';
|
||||
|
||||
export async function useUserBaseData(userEmail: string) {
|
||||
export function useUserBaseData() {
|
||||
const wishlistStore = useWishlistStore();
|
||||
const cartStore = useCartStore();
|
||||
const promocodeStore = usePromocodeStore();
|
||||
|
|
@ -12,35 +12,37 @@ export async function useUserBaseData(userEmail: string) {
|
|||
const { syncWishlist } = useWishlistSync();
|
||||
const { syncOrder } = useOrderSync();
|
||||
|
||||
const { document, variables } = getUserBaseData({
|
||||
userEmail,
|
||||
status: orderStatuses.PENDING,
|
||||
});
|
||||
async function loadUserBaseData(userEmail: string) {
|
||||
const { document, variables } = getUserBaseData({
|
||||
userEmail,
|
||||
status: orderStatuses.PENDING,
|
||||
});
|
||||
|
||||
const { mutate, error } = useMutation<IUserBaseDataResponse>(document);
|
||||
const { mutate, error } = useMutation<IUserBaseDataResponse>(document);
|
||||
const result = await mutate(variables);
|
||||
|
||||
const result = await mutate(variables);
|
||||
const data = result?.data;
|
||||
|
||||
if (data?.wishlists.edges) {
|
||||
wishlistStore.setWishlist(data.wishlists.edges[0].node);
|
||||
|
||||
await syncWishlist();
|
||||
}
|
||||
if (data?.orders.edges) {
|
||||
cartStore.setCurrentOrders(data.orders.edges[0].node);
|
||||
|
||||
await syncOrder();
|
||||
}
|
||||
if (data?.promocodes.edges) {
|
||||
promocodeStore.setPromocodes(data.promocodes.edges);
|
||||
}
|
||||
|
||||
watch(error, (err) => {
|
||||
if (err) {
|
||||
console.error('useUserBaseData error:', err);
|
||||
if (error.value) {
|
||||
console.error('useUserBaseData error:', error.value);
|
||||
}
|
||||
});
|
||||
|
||||
return {};
|
||||
const data = result?.data;
|
||||
|
||||
if (data?.wishlists.edges) {
|
||||
wishlistStore.setWishlist(data.wishlists.edges[0].node);
|
||||
|
||||
await syncWishlist();
|
||||
}
|
||||
if (data?.orders.edges) {
|
||||
cartStore.setCurrentOrders(data.orders.edges[0].node);
|
||||
|
||||
await syncOrder();
|
||||
}
|
||||
if (data?.promocodes.edges) {
|
||||
promocodeStore.setPromocodes(data.promocodes.edges);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loadUserBaseData
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import { useLogout } from '@composables/auth';
|
||||
import { useLocaleRedirect } from '@composables/languages';
|
||||
import { useNotification } from '@composables/notification';
|
||||
import { UPDATE_USER } from '@graphql/mutations/user';
|
||||
import type { IUserUpdatingResponse } from '@types';
|
||||
|
||||
export function useUserUpdating() {
|
||||
const userStore = useUserStore();
|
||||
const { t } = useI18n();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const { mutate, loading, error } = useMutation<IUserUpdatingResponse>(UPDATE_USER);
|
||||
|
||||
|
|
@ -53,7 +52,7 @@ export function useUserUpdating() {
|
|||
// }
|
||||
|
||||
if (Object.keys(params).length === 0) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.errors.noDataToUpdate'),
|
||||
type: 'error',
|
||||
});
|
||||
|
|
@ -66,14 +65,14 @@ export function useUserUpdating() {
|
|||
if (userEmail.value !== email) {
|
||||
await logout();
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.emailUpdate'),
|
||||
type: 'info',
|
||||
});
|
||||
} else {
|
||||
userStore.setUser(data.user);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.userUpdate'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -94,7 +93,7 @@ export function useUserUpdating() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import {useNotification} from '@composables/notification';
|
||||
import {
|
||||
ADD_TO_WISHLIST,
|
||||
BULK_WISHLIST,
|
||||
|
|
@ -27,7 +26,7 @@ export function useWishlistOverwrite() {
|
|||
const { t } = useI18n();
|
||||
const wishlistStore = useWishlistStore();
|
||||
const userStore = useUserStore();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const isAuthenticated = computed(() => userStore.isAuthenticated);
|
||||
const wishlistUuid = computed(() => wishlistStore.wishlist?.uuid);
|
||||
|
|
@ -71,7 +70,7 @@ export function useWishlistOverwrite() {
|
|||
if (addResult?.data?.addWishlistProduct?.wishlist) {
|
||||
wishlistStore.setWishlist(addResult.data.addWishlistProduct.wishlist);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.addToWishlist', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -91,7 +90,7 @@ export function useWishlistOverwrite() {
|
|||
if (removeResult?.data?.removeWishlistProduct?.wishlist) {
|
||||
wishlistStore.setWishlist(removeResult.data.removeWishlistProduct.wishlist);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromWishlist', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -111,7 +110,7 @@ export function useWishlistOverwrite() {
|
|||
if (removeAllResult?.data?.removeAllWishlistProducts?.wishlist) {
|
||||
wishlistStore.setWishlist(removeAllResult.data.removeAllWishlistProducts.wishlist);
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeAllFromWishlist'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -133,7 +132,7 @@ export function useWishlistOverwrite() {
|
|||
if (args.isBulkSync) {
|
||||
cookieWishlist.value = [];
|
||||
} else {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.bulkRemoveWishlist'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -154,7 +153,7 @@ export function useWishlistOverwrite() {
|
|||
: [];
|
||||
|
||||
if (current.includes(args.productUuid)) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.errors.alreadyInWishlist', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -166,7 +165,7 @@ export function useWishlistOverwrite() {
|
|||
current.push(args.productUuid);
|
||||
cookieWishlist.value = current;
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.addToWishlist', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -183,7 +182,7 @@ export function useWishlistOverwrite() {
|
|||
)
|
||||
: [];
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeFromWishlist', {
|
||||
product: args.productName,
|
||||
}),
|
||||
|
|
@ -196,7 +195,7 @@ export function useWishlistOverwrite() {
|
|||
case 'removeAll': {
|
||||
cookieWishlist.value = [];
|
||||
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.removeAllFromWishlist'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -217,7 +216,7 @@ export function useWishlistOverwrite() {
|
|||
if (args.isBulkSync) {
|
||||
cookieWishlist.value = [];
|
||||
} else {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.bulkRemoveWishlist'),
|
||||
type: 'success',
|
||||
});
|
||||
|
|
@ -245,7 +244,7 @@ export function useWishlistOverwrite() {
|
|||
} else {
|
||||
message = err.message;
|
||||
}
|
||||
useNotification({
|
||||
$notify({
|
||||
message,
|
||||
type: 'error',
|
||||
title: t('popup.errors.main'),
|
||||
|
|
|
|||
|
|
@ -51,15 +51,10 @@ export function useWishlistSync() {
|
|||
cookieWishlist.value = [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to sync wishlist:', err);
|
||||
console.error('useWishlistSync error:', err);
|
||||
}
|
||||
}
|
||||
|
||||
watch(syncError, (err) => {
|
||||
if (!err) return;
|
||||
console.error('useWishlistSync error:', err);
|
||||
});
|
||||
|
||||
return {
|
||||
syncWishlist,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ import { useRouteQuery } from '@vueuse/router';
|
|||
import { useBrands } from '@composables/brands';
|
||||
import { usePosts } from '@composables/posts';
|
||||
import { useProducts, useProductTags } from '@composables/products';
|
||||
import { useNotification } from '@composables/notification';
|
||||
|
||||
const {t} = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const appStore = useAppStore();
|
||||
const route = useRoute();
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ onMounted( async () => {
|
|||
}
|
||||
|
||||
if (route.path.includes('payment')) {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.payment'),
|
||||
type: 'info'
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import {usePageTitle} from '@composables/utils';
|
||||
import {useNotification} from '@composables/notification';
|
||||
import {useDate} from '@composables/date';
|
||||
|
||||
const {t, locale} = useI18n();
|
||||
const { $notify } = useNuxtApp();
|
||||
const promocodeStore = usePromocodeStore();
|
||||
|
||||
const promocodes = computed(() => promocodeStore.promocodes);
|
||||
|
|
@ -51,7 +51,7 @@ const promocodes = computed(() => promocodeStore.promocodes);
|
|||
const copyCode = (code: string) => {
|
||||
navigator.clipboard.writeText(code)
|
||||
.then(() => {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.promocodeCopy'),
|
||||
type: 'success'
|
||||
});
|
||||
|
|
|
|||
|
|
@ -50,11 +50,10 @@
|
|||
import {usePageTitle} from '@composables/utils';
|
||||
import { useDate } from '@composables/date';
|
||||
import {useAvatarUpload} from '@composables/user';
|
||||
import {useNotification} from '@composables/notification';
|
||||
|
||||
const {t} = useI18n();
|
||||
const userStore = useUserStore();
|
||||
const { $appHelpers } = useNuxtApp();
|
||||
const { $appHelpers, $notify } = useNuxtApp();
|
||||
|
||||
const { uploadAvatar } = useAvatarUpload();
|
||||
|
||||
|
|
@ -86,7 +85,7 @@ const copyReferral = () => {
|
|||
if (finishedOrdersQuantity.value > 0) {
|
||||
navigator.clipboard.writeText(referralLink.value)
|
||||
.then(() => {
|
||||
useNotification({
|
||||
$notify({
|
||||
message: t('popup.success.referralCopy'),
|
||||
type: 'success'
|
||||
});
|
||||
|
|
|
|||
52
storefront/app/plugins/03.notification.ts
Normal file
52
storefront/app/plugins/03.notification.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import type { NotificationOptions } from 'element-plus';
|
||||
import type { VNodeChild } from 'vue';
|
||||
|
||||
export interface INotificationArguments {
|
||||
message: string | VNodeChild;
|
||||
type: 'success' | 'error' | 'warning' | 'info';
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useAppConfig();
|
||||
|
||||
function notify(args: INotificationArguments) {
|
||||
if (process.server) return;
|
||||
|
||||
const duration = 5000;
|
||||
const progressBar = h('div', {
|
||||
class: 'el-notification__progress',
|
||||
style: {
|
||||
animationDuration: `${duration}ms`,
|
||||
},
|
||||
});
|
||||
|
||||
const bodyContent =
|
||||
typeof args.message === 'string'
|
||||
? h('p', args.message)
|
||||
: args.message;
|
||||
|
||||
const messageVNode = h('div', [
|
||||
bodyContent,
|
||||
progressBar,
|
||||
]);
|
||||
|
||||
const notification = ElNotification({
|
||||
title: args.title,
|
||||
duration: 0,
|
||||
message: messageVNode,
|
||||
type: args.type,
|
||||
position: config.ui.notificationPosition,
|
||||
} as NotificationOptions);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.close();
|
||||
}, duration);
|
||||
}
|
||||
|
||||
return {
|
||||
provide: {
|
||||
notify,
|
||||
},
|
||||
}
|
||||
});
|
||||
2
storefront/nuxt-app.d.ts
vendored
2
storefront/nuxt-app.d.ts
vendored
|
|
@ -1,5 +1,6 @@
|
|||
import type { ApolloClient, NormalizedCacheObject } from '@apollo/client/core';
|
||||
import type { ApolloError } from '@apollo/client/errors';
|
||||
import type { INotificationArguments } from '~/plugins/03.notification'
|
||||
|
||||
declare module '#app' {
|
||||
interface NuxtApp {
|
||||
|
|
@ -17,6 +18,7 @@ declare module '#app' {
|
|||
$apollo: {
|
||||
defaultClient: ApolloClient<NormalizedCacheObject>;
|
||||
};
|
||||
$notify: (args: INotificationArguments) => void
|
||||
}
|
||||
|
||||
interface NuxtConfig {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,13 @@
|
|||
"path": "./.nuxt/tsconfig.node.json"
|
||||
}
|
||||
],
|
||||
"compilerOptions": {
|
||||
"types": ["@types/node"]
|
||||
},
|
||||
"include": [
|
||||
"./**/*.d.ts",
|
||||
"./**/*.ts",
|
||||
"./**/*.vue"
|
||||
"./**/*.vue",
|
||||
"types/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue