diff --git a/storefront/app/composables/auth/useRegister.ts b/storefront/app/composables/auth/useRegister.ts index 22ccc62b..fa57b058 100644 --- a/storefront/app/composables/auth/useRegister.ts +++ b/storefront/app/composables/auth/useRegister.ts @@ -31,7 +31,7 @@ export function useRegister() { password: payload.password, confirmPassword: payload.confirmPassword, referrer: payload.referrer, - isSubscribed: payload.isSubscribed + isSubscribed: payload.isSubscribed, }); if (result?.data?.createUser?.success) { diff --git a/storefront/app/composables/brands/useBrands.ts b/storefront/app/composables/brands/useBrands.ts index 3eda77a6..063b7d34 100644 --- a/storefront/app/composables/brands/useBrands.ts +++ b/storefront/app/composables/brands/useBrands.ts @@ -1,5 +1,5 @@ import { GET_BRANDS } from '@graphql/queries/standalone/brands'; -import type { IBrand, IBrandsResponse } from '@types'; +import type { IBrand, IBrandsResponse } from '@types'; interface IBrandArgs { brandAfter?: string; @@ -32,7 +32,7 @@ export function useBrands(args: IBrandArgs = {}) { endCursor: string; }>({ hasNextPage: false, - endCursor: '' + endCursor: '', }); const error = ref(null); diff --git a/storefront/app/composables/orders/useOrderOverwrite.ts b/storefront/app/composables/orders/useOrderOverwrite.ts index 2be8f5fd..893778bf 100644 --- a/storefront/app/composables/orders/useOrderOverwrite.ts +++ b/storefront/app/composables/orders/useOrderOverwrite.ts @@ -8,7 +8,8 @@ import { } from '@graphql/mutations/cart'; import type { IAddToOrderResponse, - IBulkOrderResponse, IProduct, + IBulkOrderResponse, + IProduct, IRemoveAllFromOrderResponse, IRemoveFromOrderResponse, IRemoveKindFromOrderResponse, @@ -168,17 +169,20 @@ export function useOrderOverwrite() { switch (args.type) { case 'add': { const currentCart = cookieCart.value || []; - const existingItem = currentCart.find( - (item) => item.product.uuid === args.product.uuid - ); + const existingItem = currentCart.find((item) => item.product.uuid === args.product.uuid); if (existingItem) { existingItem.quantity += 1; - cookieCart.value = [...currentCart]; + cookieCart.value = [ + ...currentCart, + ]; } else { cookieCart.value = [ ...currentCart, - { product: args.product, quantity: 1 } + { + product: args.product, + quantity: 1, + }, ]; } @@ -194,18 +198,16 @@ export function useOrderOverwrite() { case 'remove': { const currentCart = cookieCart.value || []; - const existingItem = currentCart.find( - (item) => item.product.uuid === args.product.uuid - ); + const existingItem = currentCart.find((item) => item.product.uuid === args.product.uuid); if (existingItem) { if (existingItem.quantity > 1) { existingItem.quantity -= 1; - cookieCart.value = [...currentCart]; + cookieCart.value = [ + ...currentCart, + ]; } else { - cookieCart.value = currentCart.filter( - (item) => item.product.uuid !== args.product.uuid - ); + cookieCart.value = currentCart.filter((item) => item.product.uuid !== args.product.uuid); } useNotification({ @@ -220,9 +222,7 @@ export function useOrderOverwrite() { } case 'removeKind': { - cookieCart.value = cookieCart.value.filter( - (item) => item.product.uuid !== args.product.uuid - ); + cookieCart.value = cookieCart.value.filter((item) => item.product.uuid !== args.product.uuid); useNotification({ message: t('popup.success.removeFromCart', { @@ -247,10 +247,8 @@ export function useOrderOverwrite() { case 'bulk': { if (args.bulkAction === 'remove' && args.products) { - const uuidsToRemove = args.products.map(p => p.uuid); - cookieCart.value = cookieCart.value.filter( - (item) => !uuidsToRemove.includes(item.product.uuid) - ); + const uuidsToRemove = args.products.map((p) => p.uuid); + cookieCart.value = cookieCart.value.filter((item) => !uuidsToRemove.includes(item.product.uuid)); useNotification({ message: t('popup.success.bulkRemoveOrder'), @@ -260,16 +258,16 @@ export function useOrderOverwrite() { const currentCart = cookieCart.value || []; for (const productRef of args.products) { - const existingItem = currentCart.find( - (item) => item.product.uuid === productRef.uuid - ); + const existingItem = currentCart.find((item) => item.product.uuid === productRef.uuid); if (existingItem) { existingItem.quantity += 1; } } - cookieCart.value = [...currentCart]; + cookieCart.value = [ + ...currentCart, + ]; } break; diff --git a/storefront/app/composables/orders/useOrderSync.ts b/storefront/app/composables/orders/useOrderSync.ts index 202450a6..6f9c1fc2 100644 --- a/storefront/app/composables/orders/useOrderSync.ts +++ b/storefront/app/composables/orders/useOrderSync.ts @@ -1,68 +1,73 @@ import { useOrderOverwrite } from '@composables/orders/useOrderOverwrite'; export function useOrderSync() { - const cartStore = useCartStore(); - const userStore = useUserStore(); - const { $appHelpers } = useNuxtApp(); + const cartStore = useCartStore(); + const userStore = useUserStore(); + const { $appHelpers } = useNuxtApp(); - const { overwriteOrder } = useOrderOverwrite(); + const { overwriteOrder } = useOrderOverwrite(); - const isAuthenticated = computed(() => userStore.isAuthenticated); - const orderUuid = computed(() => cartStore.currentOrder?.uuid); + const isAuthenticated = computed(() => userStore.isAuthenticated); + const orderUuid = computed(() => cartStore.currentOrder?.uuid); - const cookieCart = useCookie($appHelpers.COOKIES_CART_KEY, { - default: () => [], - path: '/', - }); + const cookieCart = useCookie($appHelpers.COOKIES_CART_KEY, { + default: () => [], + path: '/', + }); - async function syncOrder() { - if (!isAuthenticated.value || !orderUuid.value) { - return; - } + async function syncOrder() { + if (!isAuthenticated.value || !orderUuid.value) { + return; + } - const cookieCartItems = cookieCart.value || []; + const cookieCartItems = cookieCart.value || []; - if (cookieCartItems.length === 0) { - return; - } + if (cookieCartItems.length === 0) { + return; + } - const apiCartProducts = cartStore.currentOrder?.orderProducts?.edges || []; + const apiCartProducts = cartStore.currentOrder?.orderProducts?.edges || []; - const apiProductMap = new Map( - apiCartProducts.map(e => [e.node.product.uuid, e.node.quantity]) - ); + const apiProductMap = new Map( + apiCartProducts.map((e) => [ + e.node.product.uuid, + e.node.quantity, + ]), + ); - const productsToSync = []; + const productsToSync = []; - for (const cartItem of cookieCartItems) { - const apiQuantity = apiProductMap.get(cartItem.product.uuid) || 0; - const quantityDifference = cartItem.quantity - apiQuantity; + for (const cartItem of cookieCartItems) { + const apiQuantity = apiProductMap.get(cartItem.product.uuid) || 0; + const quantityDifference = cartItem.quantity - apiQuantity; - if (quantityDifference > 0) { - for (let i = 0; i < quantityDifference; i++) { - productsToSync.push({ uuid: cartItem.product.uuid }); - } - } - } + if (quantityDifference > 0) { + for (let i = 0; i < quantityDifference; i++) { + productsToSync.push({ + uuid: cartItem.product.uuid, + }); + } + } + } - if (productsToSync.length === 0) { - cookieCart.value = []; - return; - } + if (productsToSync.length === 0) { + cookieCart.value = []; + return; + } - try { - await overwriteOrder({ - type: 'bulk', - bulkAction: 'add', - isBulkSync: true, - products: productsToSync - }); - } catch (err) { - console.error('Failed to sync cart:', err); - } - } + try { + await overwriteOrder({ + type: 'bulk', + bulkAction: 'add', + isBulkSync: true, + products: productsToSync, + }); + } catch (err) { + console.error('Failed to sync cart:', err); + } + } - return { - syncOrder, - }; -} \ No newline at end of file + return { + syncOrder, + }; +} diff --git a/storefront/app/composables/posts/usePosts.ts b/storefront/app/composables/posts/usePosts.ts index 5f1289b5..e888cc50 100644 --- a/storefront/app/composables/posts/usePosts.ts +++ b/storefront/app/composables/posts/usePosts.ts @@ -1,18 +1,18 @@ -import {GET_POSTS} from "@graphql/queries/standalone/blog"; -import type {IPostResponse} from '@types'; +import { GET_POSTS } from '@graphql/queries/standalone/blog'; +import type { IPostResponse } from '@types'; export function usePosts() { - const { data, error } = useAsyncQuery(GET_POSTS); + const { data, error } = useAsyncQuery(GET_POSTS); - const posts = computed(() => data.value?.posts.edges ?? []); + const posts = computed(() => data.value?.posts.edges ?? []); - watch(error, (err) => { - if (err) { - console.error('usePosts error:', err); - } - }); + watch(error, (err) => { + if (err) { + console.error('usePosts error:', err); + } + }); - return { - posts, - }; + return { + posts, + }; } diff --git a/storefront/app/composables/promocodes/usePromocodes.ts b/storefront/app/composables/promocodes/usePromocodes.ts index 6935565c..cb10d9ae 100644 --- a/storefront/app/composables/promocodes/usePromocodes.ts +++ b/storefront/app/composables/promocodes/usePromocodes.ts @@ -17,4 +17,4 @@ export async function usePromocodes() { }); return {}; -} \ No newline at end of file +} diff --git a/storefront/app/composables/store/useFilters.ts b/storefront/app/composables/store/useFilters.ts index 97b75d77..6a64f3da 100644 --- a/storefront/app/composables/store/useFilters.ts +++ b/storefront/app/composables/store/useFilters.ts @@ -4,45 +4,53 @@ import type { Ref } from 'vue'; export function useFilters(filterableAttributes: Ref) { const selectedMap = reactive>>({}); const selectedAllMap = reactive>({}); - const priceRange = ref<[number, number]>([0, 50000]); + const priceRange = ref< + [ + number, + number, + ] + >([ + 0, + 50000, + ]); const collapse = ref([]); watch( - filterableAttributes, - (attrs) => { - attrs?.forEach((attr) => { - const key = attr.attributeName; + filterableAttributes, + (attrs) => { + attrs?.forEach((attr) => { + const key = attr.attributeName; - if (!selectedMap[key]) { - selectedMap[key] = {}; + if (!selectedMap[key]) { + selectedMap[key] = {}; + } + if (selectedAllMap[key] === undefined) { + selectedAllMap[key] = false; + } + attr.possibleValues.forEach((v) => { + if (selectedMap[key][v] === undefined) { + selectedMap[key][v] = false; } - if (selectedAllMap[key] === undefined) { - selectedAllMap[key] = false; - } - attr.possibleValues.forEach((v) => { - if (selectedMap[key][v] === undefined) { - selectedMap[key][v] = false; - } - }); }); - }, - { - immediate: true, - }, + }); + }, + { + immediate: true, + }, ); watch( - () => filterableAttributes.value?.map((a) => selectedMap[a.attributeName]), - (maps) => { - maps?.forEach((values, idx) => { - const key = filterableAttributes.value[idx]?.attributeName; - selectedAllMap[key] = Object.values(values).every((v) => v); - }); - }, - { - immediate: true, - deep: true, - }, + () => filterableAttributes.value?.map((a) => selectedMap[a.attributeName]), + (maps) => { + maps?.forEach((values, idx) => { + const key = filterableAttributes.value[idx]?.attributeName; + selectedAllMap[key] = Object.values(values).every((v) => v); + }); + }, + { + immediate: true, + deep: true, + }, ); function toggleAll(attrName: string) { @@ -56,10 +64,10 @@ export function useFilters(filterableAttributes: Ref) { function resetFilters() { filterableAttributes.value?.forEach((attr) => { - selectedAllMap[attr.attributeName] = false; - attr.possibleValues.forEach((v) => { - selectedMap[attr.attributeName][v] = false; - }); + selectedAllMap[attr.attributeName] = false; + attr.possibleValues.forEach((v) => { + selectedMap[attr.attributeName][v] = false; + }); }); } @@ -68,8 +76,8 @@ export function useFilters(filterableAttributes: Ref) { Object.entries(selectedMap).forEach(([attr, values]) => { const checked = Object.entries(values) - .filter(([, ok]) => ok) - .map(([val]) => val); + .filter(([, ok]) => ok) + .map(([val]) => val); if (checked.length) { picked[attr] = checked; } @@ -80,13 +88,13 @@ export function useFilters(filterableAttributes: Ref) { function buildAttributesString(filters: Record): string { return Object.entries(filters) - .map(([name, vals]) => { - if (name === 'float' && vals.length === 2) { - return `${name}=gte-${vals[0]};${name}=lte-${vals[1]}`; - } - return vals.length === 1 ? `${name}=icontains-${vals[0]}` : `${name}=in-${JSON.stringify(vals)}`; - }) - .join(';'); + .map(([name, vals]) => { + if (name === 'float' && vals.length === 2) { + return `${name}=gte-${vals[0]};${name}=lte-${vals[1]}`; + } + return vals.length === 1 ? `${name}=icontains-${vals[0]}` : `${name}=in-${JSON.stringify(vals)}`; + }) + .join(';'); } function parseAttributesString(str: string): Record { @@ -100,7 +108,10 @@ export function useFilters(filterableAttributes: Ref) { if (expr.startsWith('range-')) { const parts = expr.slice(6).split('-'); if (parts.length >= 2) { - result[name] = [parts.slice(0, parts.length - 1).join('-'), parts[parts.length - 1]]; + result[name] = [ + parts.slice(0, parts.length - 1).join('-'), + parts[parts.length - 1], + ]; } } else if (expr.startsWith('in-')) { try { diff --git a/storefront/app/composables/user/useAvatarUpload.ts b/storefront/app/composables/user/useAvatarUpload.ts index 6cd4dc50..57615cff 100644 --- a/storefront/app/composables/user/useAvatarUpload.ts +++ b/storefront/app/composables/user/useAvatarUpload.ts @@ -12,14 +12,15 @@ export function useAvatarUpload() { if (!file) return; await mutate( - { + { file, }, - { - context: { - hasUpload: true, + { + context: { + hasUpload: true, + }, }, - }); + ); } onDone(({ data }) => { diff --git a/storefront/app/composables/user/useUserBaseData.ts b/storefront/app/composables/user/useUserBaseData.ts index d23d866d..67f985c7 100644 --- a/storefront/app/composables/user/useUserBaseData.ts +++ b/storefront/app/composables/user/useUserBaseData.ts @@ -1,6 +1,6 @@ import { orderStatuses } from '@appConstants'; import { useOrderSync } from '@composables/orders'; -import {useWishlistSync} from "@composables/wishlist"; +import { useWishlistSync } from '@composables/wishlist'; import { getUserBaseData } from '@graphql/queries/combined/userBaseData'; import type { IUserBaseDataResponse } from '@types'; diff --git a/storefront/app/composables/wishlist/useWishlistOverwrite.ts b/storefront/app/composables/wishlist/useWishlistOverwrite.ts index 5c2c7bad..69f9526f 100644 --- a/storefront/app/composables/wishlist/useWishlistOverwrite.ts +++ b/storefront/app/composables/wishlist/useWishlistOverwrite.ts @@ -7,7 +7,8 @@ import { } from '@graphql/mutations/wishlist'; import type { IAddToWishlistResponse, - IBulkWishlistResponse, IProduct, + IBulkWishlistResponse, + IProduct, IRemoveAllFromWishlistResponse, IRemoveFromWishlistResponse, } from '@types'; @@ -147,9 +148,7 @@ export function useWishlistOverwrite() { } else { switch (args.type) { case 'add': { - const isAlreadyInWishlist = cookieWishlist.value.some( - (item) => item.uuid === args.product.uuid - ); + const isAlreadyInWishlist = cookieWishlist.value.some((item) => item.uuid === args.product.uuid); if (isAlreadyInWishlist) { useNotification({ @@ -159,7 +158,10 @@ export function useWishlistOverwrite() { type: 'warning', }); } else { - cookieWishlist.value = [...cookieWishlist.value, args.product]; + cookieWishlist.value = [ + ...cookieWishlist.value, + args.product, + ]; useNotification({ message: t('popup.success.addToWishlist', { @@ -173,9 +175,7 @@ export function useWishlistOverwrite() { } case 'remove': { - cookieWishlist.value = cookieWishlist.value.filter( - (item) => item.uuid !== args.product.uuid - ); + cookieWishlist.value = cookieWishlist.value.filter((item) => item.uuid !== args.product.uuid); useNotification({ message: t('popup.success.removeFromWishlist', { diff --git a/storefront/app/composables/wishlist/useWishlistSync.ts b/storefront/app/composables/wishlist/useWishlistSync.ts index d149a9a1..0307cc65 100644 --- a/storefront/app/composables/wishlist/useWishlistSync.ts +++ b/storefront/app/composables/wishlist/useWishlistSync.ts @@ -1,66 +1,66 @@ -import {useWishlistOverwrite} from "@composables/wishlist/useWishlistOverwrite"; +import { useWishlistOverwrite } from '@composables/wishlist/useWishlistOverwrite'; export function useWishlistSync() { - const wishlistStore = useWishlistStore(); - const userStore = useUserStore(); - const { $appHelpers } = useNuxtApp(); + const wishlistStore = useWishlistStore(); + const userStore = useUserStore(); + const { $appHelpers } = useNuxtApp(); - const { overwriteWishlist } = useWishlistOverwrite(); + const { overwriteWishlist } = useWishlistOverwrite(); - const isAuthenticated = computed(() => userStore.isAuthenticated); - const wishlistUuid = computed(() => wishlistStore.wishlist?.uuid); + const isAuthenticated = computed(() => userStore.isAuthenticated); + const wishlistUuid = computed(() => wishlistStore.wishlist?.uuid); - const cookieWishlist = useCookie($appHelpers.COOKIES_WISHLIST_KEY, { - default: () => [], - path: '/', - }); + const cookieWishlist = useCookie($appHelpers.COOKIES_WISHLIST_KEY, { + default: () => [], + path: '/', + }); - async function syncWishlist() { - if (!isAuthenticated.value || !wishlistUuid.value) { - return; - } + async function syncWishlist() { + if (!isAuthenticated.value || !wishlistUuid.value) { + return; + } - const cookieProducts = cookieWishlist.value || []; + const cookieProducts = cookieWishlist.value || []; - if (cookieProducts.length === 0) { - return; - } + if (cookieProducts.length === 0) { + return; + } - const apiProductUuids = wishlistStore.wishlist?.products?.edges.map(e => e.node.uuid) || []; + const apiProductUuids = wishlistStore.wishlist?.products?.edges.map((e) => e.node.uuid) || []; - const productsToAdd = cookieProducts.filter( - (product) => !apiProductUuids.includes(product.uuid) - ); + const productsToAdd = cookieProducts.filter((product) => !apiProductUuids.includes(product.uuid)); - if (productsToAdd.length === 0) { - cookieWishlist.value = []; - return; - } + if (productsToAdd.length === 0) { + cookieWishlist.value = []; + return; + } - try { - await overwriteWishlist({ - type: 'bulk', - bulkAction: 'add', - isBulkSync: true, - products: productsToAdd.map(p => ({ uuid: p.uuid })) - }) + try { + await overwriteWishlist({ + type: 'bulk', + bulkAction: 'add', + isBulkSync: true, + products: productsToAdd.map((p) => ({ + uuid: p.uuid, + })), + }); - if (bulkResult?.data?.bulkWishlistAction?.wishlist) { - wishlistStore.setWishlist(bulkResult.data.bulkWishlistAction.wishlist); + if (bulkResult?.data?.bulkWishlistAction?.wishlist) { + wishlistStore.setWishlist(bulkResult.data.bulkWishlistAction.wishlist); - cookieWishlist.value = []; - } - } catch (err) { - console.error('Failed to sync wishlist:', err); - } - } + cookieWishlist.value = []; + } + } catch (err) { + console.error('Failed to sync wishlist:', err); + } + } - watch(syncError, (err) => { - if (!err) return; - console.error('useWishlistSync error:', err); - }); + watch(syncError, (err) => { + if (!err) return; + console.error('useWishlistSync error:', err); + }); - return { - syncWishlist, - }; -} \ No newline at end of file + return { + syncWishlist, + }; +} diff --git a/storefront/app/constants/currency.ts b/storefront/app/constants/currency.ts index 71d28e38..c479e19c 100644 --- a/storefront/app/constants/currency.ts +++ b/storefront/app/constants/currency.ts @@ -1 +1 @@ -export const CURRENCY = '$'; \ No newline at end of file +export const CURRENCY = '$'; diff --git a/storefront/app/constants/docs.ts b/storefront/app/constants/docs.ts index 44da4641..e0f867c9 100644 --- a/storefront/app/constants/docs.ts +++ b/storefront/app/constants/docs.ts @@ -1,8 +1,8 @@ export enum docsSlugs { - TERMS = 'terms-conditions', - POLICY = 'privacy-policy', - FAQ = 'faq', - SHIPPING = 'shipping-information', - RETURN = 'return-policy', - ABOUT = 'about-us' + TERMS = 'terms-conditions', + POLICY = 'privacy-policy', + FAQ = 'faq', + SHIPPING = 'shipping-information', + RETURN = 'return-policy', + ABOUT = 'about-us', } diff --git a/storefront/app/plugins/01.apollo.ts b/storefront/app/plugins/01.apollo.ts index 7cb08c80..81c0958a 100644 --- a/storefront/app/plugins/01.apollo.ts +++ b/storefront/app/plugins/01.apollo.ts @@ -1,9 +1,8 @@ - import { ApolloLink, from } from '@apollo/client/core'; import { setContext } from '@apollo/client/link/context'; import { onError } from '@apollo/client/link/error'; import { provideApolloClient } from '@vue/apollo-composable'; -import createUploadLink from "apollo-upload-client/createUploadLink.mjs"; +import createUploadLink from 'apollo-upload-client/createUploadLink.mjs'; export default defineNuxtPlugin((nuxtApp) => { const runtime = useRuntimeConfig(); @@ -22,23 +21,29 @@ export default defineNuxtPlugin((nuxtApp) => { let locale = 'en-gb'; if (import.meta.client) { - const clientCookies = document.cookie.split(';').reduce((acc, cookie) => { - const [key, value] = cookie.trim().split('='); - acc[key] = decodeURIComponent(value); - return acc; - }, {} as Record); + const clientCookies = document.cookie.split(';').reduce( + (acc, cookie) => { + const [key, value] = cookie.trim().split('='); + acc[key] = decodeURIComponent(value); + return acc; + }, + {} as Record, + ); accessToken = clientCookies[$appHelpers.COOKIES_ACCESS_TOKEN_KEY] || ''; locale = clientCookies[$appHelpers.COOKIES_LOCALE_KEY] || 'en-gb'; } else { const cookieHeader = nuxtApp.ssrContext?.event?.node?.req?.headers?.cookie || ''; - const serverCookies = cookieHeader.split(';').reduce((acc, cookie) => { - const [key, value] = cookie.trim().split('='); - if (key && value) { - acc[key] = decodeURIComponent(value); - } - return acc; - }, {} as Record); + const serverCookies = cookieHeader.split(';').reduce( + (acc, cookie) => { + const [key, value] = cookie.trim().split('='); + if (key && value) { + acc[key] = decodeURIComponent(value); + } + return acc; + }, + {} as Record, + ); accessToken = serverCookies[$appHelpers.COOKIES_ACCESS_TOKEN_KEY] || ''; locale = serverCookies[$appHelpers.COOKIES_LOCALE_KEY] || 'en-gb'; @@ -46,14 +51,16 @@ export default defineNuxtPlugin((nuxtApp) => { const hdrs: Record = { ...headers, - 'Accept-Language': locale + 'Accept-Language': locale, }; if (accessToken) { hdrs['X-SCHON-AUTH'] = `Bearer ${accessToken}`; } - return { headers: hdrs }; + return { + headers: hdrs, + }; }); const customLink = new ApolloLink((operation, forward) => { @@ -63,15 +70,17 @@ export default defineNuxtPlugin((nuxtApp) => { }); const httpLink = createUploadLink({ - uri: `https://api.${runtime.public.schonBaseDomain}/graphql/` + uri: `https://api.${runtime.public.schonBaseDomain}/graphql/`, }); - $apollo.defaultClient.setLink(from([ - errorLink, - authLink, - customLink, - httpLink, - ])); + $apollo.defaultClient.setLink( + from([ + errorLink, + authLink, + customLink, + httpLink, + ]), + ); provideApolloClient($apollo.defaultClient); -}); \ No newline at end of file +}); diff --git a/storefront/biome.json b/storefront/biome.json index 62e8637e..97cdf60c 100644 --- a/storefront/biome.json +++ b/storefront/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.4/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/storefront/i18n/locales/en-gb.json b/storefront/i18n/locales/en-gb.json index b08081ab..e1051fe2 100644 --- a/storefront/i18n/locales/en-gb.json +++ b/storefront/i18n/locales/en-gb.json @@ -341,4 +341,4 @@ "title": "Shop", "text": "Discover our curated collection of luxury fashion and accessories that define sophisticated style" } -} \ No newline at end of file +} diff --git a/storefront/i18n/locales/ro-ro.json b/storefront/i18n/locales/ro-ro.json index 9e26dfee..0967ef42 100644 --- a/storefront/i18n/locales/ro-ro.json +++ b/storefront/i18n/locales/ro-ro.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/storefront/i18n/locales/ru-ru.json b/storefront/i18n/locales/ru-ru.json index ea2f0416..17e65c21 100644 --- a/storefront/i18n/locales/ru-ru.json +++ b/storefront/i18n/locales/ru-ru.json @@ -1,344 +1,344 @@ { - "buttons": { - "login": "Войти", - "register": "Регистрация", - "createAccount": "Создать аккаунт", - "addToCart": "В корзину", - "removeFromCart": "Удалить из корзины", - "addAllToCart": "Добавить все в корзину", - "addToWishlist": "В избранное", - "removeFromWishlist": "Удалить из избранного", - "send": "Отправить", - "goEmail": "Перейти к почте", - "logout": "Выйти", - "checkout": "Оформить заказ", - "save": "Сохранить", - "sendLink": "Отправить ссылку для сброса", - "topUp": "Пополнить", - "shopNow": "КУПИТЬ СЕЙЧАС", - "shopTheSale": "Купить по акции", - "readMore": "Читать далее", - "sendMessage": "Отправить сообщение", - "saveChanges": "Сохранить изменения", - "clearAll": "Очистить всё" - }, - "errors": { - "required": "Это поле обязательно!", - "mail": "Введите корректный email!", - "compare": "Пароли не совпадают!", - "needLower": "Добавьте строчную букву.", - "needUpper": "Добавьте заглавную букву.", - "needNumber": "Добавьте цифру.", - "needMin": "Мин. 8 символов", - "needSpecial": "Добавьте спецсимвол: #.?!$%^&*'()_+=:;\"'/>.<,|\\-", - "pageNotFound": "Страница не найдена" - }, - "fields": { - "search": "Поиск", - "searchOrder": "Поиск заказа", - "name": "Имя", - "firstName": "Имя", - "lastName": "Фамилия", - "phoneNumber": "Номер телефона", - "email": "Email", - "subject": "Тема", - "message": "Ваше сообщение", - "password": "Пароль", - "newPassword": "Новый пароль", - "confirmPassword": "Подтвердите пароль", - "confirmNewPassword": "Подтвердите новый пароль", - "brandsSearch": "Поиск брендов по названию..." - }, - "checkboxes": { - "remember": "Запомнить меня", - "chooseAll": "Выбрать все", - "agree": "Я согласен с {terms} и {policy}", - "subscribe": "Подписаться на рассылку новостей об эксклюзивных предложениях и обновлениях" - }, - "popup": { - "errors": { - "main": "Ошибка!", - "defaultError": "Что-то пошло не так...", - "noDataToUpdate": "Нет данных для обновления.", - "loginFirst": "Войдите, чтобы выполнить это действие!", - "alreadyInWishlist": "{product} уже есть в избранном!" - }, - "success": { - "login": "Вход выполнен", - "register": "Аккаунт успешно создан. Пожалуйста, подтвердите ваш Email перед входом!", - "confirmEmail": "Ссылка для подтверждения E-mail успешно отправлена!", - "reset": "Если указанный email существует в нашей системе, мы отправим на него письмо для восстановления пароля!", - "newPassword": "Вы успешно изменили пароль!", - "contactUs": "Ваше сообщение успешно отправлено!", - "addToCart": "{product} добавлен в корзину!", - "removeFromCart": "{product} удален из корзины!", - "removeAllFromCart": "Корзина успешно очищена!", - "addToWishlist": "{product} добавлен в избранное!", - "removeFromWishlist": "{product} удален из избранного!", - "removeAllFromWishlist": "Список избранного успешно очищен!", - "bulkRemoveWishlist": "Выбранные товары удалены из избранного!", - "bulkRemoveOrder": "Выбранные товары удалены из корзины!", - "avatarUpload": "Аватар успешно загружен!", - "userUpdate": "Профиль успешно обновлен!", - "emailUpdate": "Проверьте вашу почту для перехода по ссылке подтверждения и завершения обновления email.", - "referralCopy": "Реферальная ссылка скопирована!", - "promocodeCopy": "Промокод скопирован!", - "configCopy": "Новая ui конфигурация скопирована!", - "addFeedback": "Ваш отзыв сохранен!" - }, - "addToCartLimit": "Лимит общего количества составляет {quantity}!", - "failAdd": "Пожалуйста, войдите, чтобы совершить покупку", - "activationSuccess": "E-mail успешно подтвержден. Пожалуйста, войдите!", - "successUpdate": "Профиль успешно обновлен!", - "payment": "Ваш платеж обрабатывается! Пожалуйста, подождите", - "successCheckout": "Заказ успешно оплачен!" - }, - "header": { - "nav": { - "shop": "Магазин", - "catalog": "Каталог", - "brands": "Бренды", - "blog": "Блог", - "contact": "Контакты" - }, - "actions": { - "wishlist": "Избранное", - "cart": "Корзина", - "login": "Войти", - "profile": "Профиль" - }, - "search": { - "empty": "Ничего не найдено" - }, - "catalog": { - "title": "Каталог" - } - }, - "footer": { - "address": "Адрес: ", - "email": "Email: ", - "phone": "Телефон: ", - "text": "Курируем вневременную роскошную моду для взыскательных личностей", - "shop": "Магазин", - "allProducts": "Все товары", - "catalog": "Каталог", - "brands": "Бренды", - "help": "Помощь", - "rights": "Все права защищены." - }, - "home": { - "hero": { - "title": "Вневременная элегантность", - "text": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль" - }, - "categories": { - "title": "Покупки по категориям" - }, - "ad": { - "title": "Весенняя коллекция", - "text1": "Скидки до 40%", - "text2": "Откройте для себя последние тренды в мире люксовой моды" - }, - "blog": { - "title": "Из журнала" - } - }, - "forms": { - "login": { - "title": "С возвращением", - "subtitle": "Войдите в свой аккаунт, чтобы продолжить", - "forgot": "Забыли пароль?", - "or": "или" - }, - "register": { - "title": "Создать аккаунт", - "subtitle": "Зарегистрируйтесь, чтобы начать ваше стильное путешествие", - "login": "Уже есть аккаунт?" - }, - "reset": { - "title": "Сброс пароля", - "subtitle": "Введите ваш email, и мы отправим ссылку для сброса пароля.", - "backToLogin": "Назад к входу" - }, - "newPassword": { - "title": "Новый пароль" - } - }, - "cards": { - "product": { - "stock": "В наличии: " - } - }, - "breadcrumbs": { - "home": "Главная", - "catalog": "Каталог", - "contact": "Контакты", - "orders": "Заказы", - "wishlist": "Избранное", - "cart": "Корзина", - "settings": "Настройки", - "balance": "Баланс", - "promocodes": "Промокоды", - "login": "Вход", - "register": "Регистрация", - "resetPassword": "Сброс пароля", - "newPassword": "Новый пароль", - "brands": "Бренды", - "blog": "Блог", - "search": "Поиск", - "categories": "Категории", - "shop": "Магазин", - "policy": "Политика конфиденциальности", - "terms": "Условия использования", - "return": "Политика возврата", - "faq": "Часто задаваемые вопросы", - "shipping": "Информация о доставке", - "about": "О нас" - }, - "contact": { - "title": "Свяжитесь с нами", - "text": "Мы будем рады услышать вас. Отправьте нам сообщение, и мы ответим как можно скорее.", - "block": { - "title": "Давайте общаться", - "text": "Есть ли у вас вопросы о наших товарах, нужен совет по стилю или вы хотите сотрудничать с нами — мы здесь, чтобы помочь. Наша команда стремится предоставлять исключительный сервис и поддержку.", - "email": "Написать нам", - "call": "Позвонить нам", - "hours": "Часы работы" - }, - "form": { - "title": "Отправить сообщение" - } - }, - "store": { - "sorting": "Сортировать по:", - "filters": { - "title": "Фильтры", - "apply": "Применить", - "reset": "Сбросить", - "all": "Все" - } - }, - "search": { - "title": "Результаты поиска", - "products": "Товары", - "categories": "Категории", - "brands": "Бренды", - "byRequest": "по запросу" - }, - "product": { - "characteristics": "Все характеристики", - "similar": "Вам также может понравиться" - }, - "profile": { - "settings": { - "title": "Настройки", - "joinData": "Дата регистрации", - "accountInfo": "Информация об аккаунте", - "copyReferral": "Скопировать реферальную ссылку", - "referralTooltip": "Вы получите реферальную ссылку после успешной покупки" - }, - "orders": { - "title": "Заказы", - "chooseStatus": "Выберите статус", - "id": "№", - "price": "Цена", - "total": "Итого", - "empty": "Нет заказов по данным параметрам.", - "statuses": { - "all": "Все", - "failed": "Ошибка", - "payment": "Ожидает оплаты", - "created": "Создан", - "delivering": "Доставляется", - "finished": "Завершен", - "momental": "Моментальный" - }, - "searchTooltip": "Введите номер заказа или название товара" - }, - "wishlist": { - "title": "Избранное", - "total": "{quantity} товаров на сумму {amount}", - "deleteTooltip": "Удалить всё из избранного", - "empty": "Ваш список избранного пуст." - }, - "cart": { - "title": "Корзина", - "quantity": "Количество: ", - "total": "Итого", - "empty": "Ваша корзина пуста." - }, - "balance": { - "title": "Баланс" - }, - "promocodes": { - "title": "Промокоды", - "until": "До", - "empty": "У вас нет промокодов." - }, - "logout": "Выйти" - }, - "demo": { - "settings": { - "title": "Демо-настройки", - "ui": "Настройки интерфейса" - }, - "buttons": { - "reset": "Сбросить на умолчания", - "save": "Сохранить изменения", - "generateCode": "Сгенерировать код для 'app.config.ts'" - }, - "preview": { - "text": "Замените объект UI в 'app.config.ts' на этот код" - }, - "descriptions": { - "showBreadcrumbs": "Показывать цепочку навигации на страницах.", - "showSearchBar": "Показывать строку поиска в шапке сайта." - } - }, - "docs": { - "faq": { - "title": "Часто задаваемые вопросы" - }, - "shipping": { - "title": "Информация о доставке" - }, - "return": { - "title": "Политика возврата" - }, - "policy": { - "title": "Политика конфиденциальности" - }, - "terms": { - "title": "Условия использования" - }, - "about": { - "title": "О нас" - } - }, - "brands": { - "title": "Люксовые бренды", - "text": "Откройте для себя самые престижные мировые модные дома и люксовые бренды, подобранные для взыскательного вкуса." - }, - "catalog": { - "title": "Разнообразные категории", - "text": "Откройте для себя самые престижные мировые модные дома и люксовые категории, подобранные для взыскательного вкуса." - }, - "blog": { - "title": "Модный журнал", - "text": "Узнавайте о последних трендах, источниках вдохновения для стиля и модных инсайтах от нашей редакции." - }, - "cart": { - "title": "Моя корзина", - "items": "нет товаров | {count} товар | {count} товара | {count} товаров", - "empty": "Ваша корзина пуста" - }, - "wishlist": { - "title": "Мои Избранные", - "items": "нет товаров | {count} товар | {count} товара | {count} товаров", - "empty": "Список выших избранных пуст" - }, - "shop": { - "title": "Магазин", - "text": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль" - } -} \ No newline at end of file + "buttons": { + "login": "Войти", + "register": "Регистрация", + "createAccount": "Создать аккаунт", + "addToCart": "В корзину", + "removeFromCart": "Удалить из корзины", + "addAllToCart": "Добавить все в корзину", + "addToWishlist": "В избранное", + "removeFromWishlist": "Удалить из избранного", + "send": "Отправить", + "goEmail": "Перейти к почте", + "logout": "Выйти", + "checkout": "Оформить заказ", + "save": "Сохранить", + "sendLink": "Отправить ссылку для сброса", + "topUp": "Пополнить", + "shopNow": "КУПИТЬ СЕЙЧАС", + "shopTheSale": "Купить по акции", + "readMore": "Читать далее", + "sendMessage": "Отправить сообщение", + "saveChanges": "Сохранить изменения", + "clearAll": "Очистить всё" + }, + "errors": { + "required": "Это поле обязательно!", + "mail": "Введите корректный email!", + "compare": "Пароли не совпадают!", + "needLower": "Добавьте строчную букву.", + "needUpper": "Добавьте заглавную букву.", + "needNumber": "Добавьте цифру.", + "needMin": "Мин. 8 символов", + "needSpecial": "Добавьте спецсимвол: #.?!$%^&*'()_+=:;\"'/>.<,|\\-", + "pageNotFound": "Страница не найдена" + }, + "fields": { + "search": "Поиск", + "searchOrder": "Поиск заказа", + "name": "Имя", + "firstName": "Имя", + "lastName": "Фамилия", + "phoneNumber": "Номер телефона", + "email": "Email", + "subject": "Тема", + "message": "Ваше сообщение", + "password": "Пароль", + "newPassword": "Новый пароль", + "confirmPassword": "Подтвердите пароль", + "confirmNewPassword": "Подтвердите новый пароль", + "brandsSearch": "Поиск брендов по названию..." + }, + "checkboxes": { + "remember": "Запомнить меня", + "chooseAll": "Выбрать все", + "agree": "Я согласен с {terms} и {policy}", + "subscribe": "Подписаться на рассылку новостей об эксклюзивных предложениях и обновлениях" + }, + "popup": { + "errors": { + "main": "Ошибка!", + "defaultError": "Что-то пошло не так...", + "noDataToUpdate": "Нет данных для обновления.", + "loginFirst": "Войдите, чтобы выполнить это действие!", + "alreadyInWishlist": "{product} уже есть в избранном!" + }, + "success": { + "login": "Вход выполнен", + "register": "Аккаунт успешно создан. Пожалуйста, подтвердите ваш Email перед входом!", + "confirmEmail": "Ссылка для подтверждения E-mail успешно отправлена!", + "reset": "Если указанный email существует в нашей системе, мы отправим на него письмо для восстановления пароля!", + "newPassword": "Вы успешно изменили пароль!", + "contactUs": "Ваше сообщение успешно отправлено!", + "addToCart": "{product} добавлен в корзину!", + "removeFromCart": "{product} удален из корзины!", + "removeAllFromCart": "Корзина успешно очищена!", + "addToWishlist": "{product} добавлен в избранное!", + "removeFromWishlist": "{product} удален из избранного!", + "removeAllFromWishlist": "Список избранного успешно очищен!", + "bulkRemoveWishlist": "Выбранные товары удалены из избранного!", + "bulkRemoveOrder": "Выбранные товары удалены из корзины!", + "avatarUpload": "Аватар успешно загружен!", + "userUpdate": "Профиль успешно обновлен!", + "emailUpdate": "Проверьте вашу почту для перехода по ссылке подтверждения и завершения обновления email.", + "referralCopy": "Реферальная ссылка скопирована!", + "promocodeCopy": "Промокод скопирован!", + "configCopy": "Новая ui конфигурация скопирована!", + "addFeedback": "Ваш отзыв сохранен!" + }, + "addToCartLimit": "Лимит общего количества составляет {quantity}!", + "failAdd": "Пожалуйста, войдите, чтобы совершить покупку", + "activationSuccess": "E-mail успешно подтвержден. Пожалуйста, войдите!", + "successUpdate": "Профиль успешно обновлен!", + "payment": "Ваш платеж обрабатывается! Пожалуйста, подождите", + "successCheckout": "Заказ успешно оплачен!" + }, + "header": { + "nav": { + "shop": "Магазин", + "catalog": "Каталог", + "brands": "Бренды", + "blog": "Блог", + "contact": "Контакты" + }, + "actions": { + "wishlist": "Избранное", + "cart": "Корзина", + "login": "Войти", + "profile": "Профиль" + }, + "search": { + "empty": "Ничего не найдено" + }, + "catalog": { + "title": "Каталог" + } + }, + "footer": { + "address": "Адрес: ", + "email": "Email: ", + "phone": "Телефон: ", + "text": "Курируем вневременную роскошную моду для взыскательных личностей", + "shop": "Магазин", + "allProducts": "Все товары", + "catalog": "Каталог", + "brands": "Бренды", + "help": "Помощь", + "rights": "Все права защищены." + }, + "home": { + "hero": { + "title": "Вневременная элегантность", + "text": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль" + }, + "categories": { + "title": "Покупки по категориям" + }, + "ad": { + "title": "Весенняя коллекция", + "text1": "Скидки до 40%", + "text2": "Откройте для себя последние тренды в мире люксовой моды" + }, + "blog": { + "title": "Из журнала" + } + }, + "forms": { + "login": { + "title": "С возвращением", + "subtitle": "Войдите в свой аккаунт, чтобы продолжить", + "forgot": "Забыли пароль?", + "or": "или" + }, + "register": { + "title": "Создать аккаунт", + "subtitle": "Зарегистрируйтесь, чтобы начать ваше стильное путешествие", + "login": "Уже есть аккаунт?" + }, + "reset": { + "title": "Сброс пароля", + "subtitle": "Введите ваш email, и мы отправим ссылку для сброса пароля.", + "backToLogin": "Назад к входу" + }, + "newPassword": { + "title": "Новый пароль" + } + }, + "cards": { + "product": { + "stock": "В наличии: " + } + }, + "breadcrumbs": { + "home": "Главная", + "catalog": "Каталог", + "contact": "Контакты", + "orders": "Заказы", + "wishlist": "Избранное", + "cart": "Корзина", + "settings": "Настройки", + "balance": "Баланс", + "promocodes": "Промокоды", + "login": "Вход", + "register": "Регистрация", + "resetPassword": "Сброс пароля", + "newPassword": "Новый пароль", + "brands": "Бренды", + "blog": "Блог", + "search": "Поиск", + "categories": "Категории", + "shop": "Магазин", + "policy": "Политика конфиденциальности", + "terms": "Условия использования", + "return": "Политика возврата", + "faq": "Часто задаваемые вопросы", + "shipping": "Информация о доставке", + "about": "О нас" + }, + "contact": { + "title": "Свяжитесь с нами", + "text": "Мы будем рады услышать вас. Отправьте нам сообщение, и мы ответим как можно скорее.", + "block": { + "title": "Давайте общаться", + "text": "Есть ли у вас вопросы о наших товарах, нужен совет по стилю или вы хотите сотрудничать с нами — мы здесь, чтобы помочь. Наша команда стремится предоставлять исключительный сервис и поддержку.", + "email": "Написать нам", + "call": "Позвонить нам", + "hours": "Часы работы" + }, + "form": { + "title": "Отправить сообщение" + } + }, + "store": { + "sorting": "Сортировать по:", + "filters": { + "title": "Фильтры", + "apply": "Применить", + "reset": "Сбросить", + "all": "Все" + } + }, + "search": { + "title": "Результаты поиска", + "products": "Товары", + "categories": "Категории", + "brands": "Бренды", + "byRequest": "по запросу" + }, + "product": { + "characteristics": "Все характеристики", + "similar": "Вам также может понравиться" + }, + "profile": { + "settings": { + "title": "Настройки", + "joinData": "Дата регистрации", + "accountInfo": "Информация об аккаунте", + "copyReferral": "Скопировать реферальную ссылку", + "referralTooltip": "Вы получите реферальную ссылку после успешной покупки" + }, + "orders": { + "title": "Заказы", + "chooseStatus": "Выберите статус", + "id": "№", + "price": "Цена", + "total": "Итого", + "empty": "Нет заказов по данным параметрам.", + "statuses": { + "all": "Все", + "failed": "Ошибка", + "payment": "Ожидает оплаты", + "created": "Создан", + "delivering": "Доставляется", + "finished": "Завершен", + "momental": "Моментальный" + }, + "searchTooltip": "Введите номер заказа или название товара" + }, + "wishlist": { + "title": "Избранное", + "total": "{quantity} товаров на сумму {amount}", + "deleteTooltip": "Удалить всё из избранного", + "empty": "Ваш список избранного пуст." + }, + "cart": { + "title": "Корзина", + "quantity": "Количество: ", + "total": "Итого", + "empty": "Ваша корзина пуста." + }, + "balance": { + "title": "Баланс" + }, + "promocodes": { + "title": "Промокоды", + "until": "До", + "empty": "У вас нет промокодов." + }, + "logout": "Выйти" + }, + "demo": { + "settings": { + "title": "Демо-настройки", + "ui": "Настройки интерфейса" + }, + "buttons": { + "reset": "Сбросить на умолчания", + "save": "Сохранить изменения", + "generateCode": "Сгенерировать код для 'app.config.ts'" + }, + "preview": { + "text": "Замените объект UI в 'app.config.ts' на этот код" + }, + "descriptions": { + "showBreadcrumbs": "Показывать цепочку навигации на страницах.", + "showSearchBar": "Показывать строку поиска в шапке сайта." + } + }, + "docs": { + "faq": { + "title": "Часто задаваемые вопросы" + }, + "shipping": { + "title": "Информация о доставке" + }, + "return": { + "title": "Политика возврата" + }, + "policy": { + "title": "Политика конфиденциальности" + }, + "terms": { + "title": "Условия использования" + }, + "about": { + "title": "О нас" + } + }, + "brands": { + "title": "Люксовые бренды", + "text": "Откройте для себя самые престижные мировые модные дома и люксовые бренды, подобранные для взыскательного вкуса." + }, + "catalog": { + "title": "Разнообразные категории", + "text": "Откройте для себя самые престижные мировые модные дома и люксовые категории, подобранные для взыскательного вкуса." + }, + "blog": { + "title": "Модный журнал", + "text": "Узнавайте о последних трендах, источниках вдохновения для стиля и модных инсайтах от нашей редакции." + }, + "cart": { + "title": "Моя корзина", + "items": "нет товаров | {count} товар | {count} товара | {count} товаров", + "empty": "Ваша корзина пуста" + }, + "wishlist": { + "title": "Мои Избранные", + "items": "нет товаров | {count} товар | {count} товара | {count} товаров", + "empty": "Список выших избранных пуст" + }, + "shop": { + "title": "Магазин", + "text": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль" + } +}