**chore(storefront): apply consistent code formatting and improve readability**
Refactored multiple files for code styling consistency, using proper indentation and spacing to align with team standards. Improved readability and maintainability across composables, Apollo plugin, and localization files. Enhancements: - Standardized import and function indentation across all composables. - Updated `biome.json` schema to the latest version (v2.4.4) for tool compatibility. - Organized code blocks in Apollo plugin for better understandability. No functional changes introduced—this is a non-breaking, code refinement commit.
This commit is contained in:
parent
c36135d78d
commit
e65e7b7d73
18 changed files with 600 additions and 576 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<string | null>(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
return {
|
||||
syncOrder,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IPostResponse>(GET_POSTS);
|
||||
const { data, error } = useAsyncQuery<IPostResponse>(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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,4 +17,4 @@ export async function usePromocodes() {
|
|||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,45 +4,53 @@ import type { Ref } from 'vue';
|
|||
export function useFilters(filterableAttributes: Ref<IStoreFilters[]>) {
|
||||
const selectedMap = reactive<Record<string, Record<string, boolean>>>({});
|
||||
const selectedAllMap = reactive<Record<string, boolean>>({});
|
||||
const priceRange = ref<[number, number]>([0, 50000]);
|
||||
const priceRange = ref<
|
||||
[
|
||||
number,
|
||||
number,
|
||||
]
|
||||
>([
|
||||
0,
|
||||
50000,
|
||||
]);
|
||||
const collapse = ref<string[]>([]);
|
||||
|
||||
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<IStoreFilters[]>) {
|
|||
|
||||
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<IStoreFilters[]>) {
|
|||
|
||||
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<IStoreFilters[]>) {
|
|||
|
||||
function buildAttributesString(filters: Record<string, string[]>): 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<string, string[]> {
|
||||
|
|
@ -100,7 +108,10 @@ export function useFilters(filterableAttributes: Ref<IStoreFilters[]>) {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@ export function useAvatarUpload() {
|
|||
if (!file) return;
|
||||
|
||||
await mutate(
|
||||
{
|
||||
{
|
||||
file,
|
||||
},
|
||||
{
|
||||
context: {
|
||||
hasUpload: true,
|
||||
{
|
||||
context: {
|
||||
hasUpload: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
onDone(({ data }) => {
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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', {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
return {
|
||||
syncWishlist,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export const CURRENCY = '$';
|
||||
export const CURRENCY = '$';
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, string>);
|
||||
const clientCookies = document.cookie.split(';').reduce(
|
||||
(acc, cookie) => {
|
||||
const [key, value] = cookie.trim().split('=');
|
||||
acc[key] = decodeURIComponent(value);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
);
|
||||
|
||||
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<string, string>);
|
||||
const serverCookies = cookieHeader.split(';').reduce(
|
||||
(acc, cookie) => {
|
||||
const [key, value] = cookie.trim().split('=');
|
||||
if (key && value) {
|
||||
acc[key] = decodeURIComponent(value);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
);
|
||||
|
||||
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<string, string> = {
|
||||
...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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -341,4 +341,4 @@
|
|||
"title": "Shop",
|
||||
"text": "Discover our curated collection of luxury fashion and accessories that define sophisticated style"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{}
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -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": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль"
|
||||
}
|
||||
}
|
||||
"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": "Откройте для себя нашу кураторскую коллекцию люксовой моды и аксессуаров, определяющих утонченный стиль"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue