Merge branch 'main' of https://github.com/Byeto-Company/hossein_por_shop
This commit is contained in:
@@ -23,10 +23,10 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative rounded-150 overflow-hidden w-full h-[500px]">
|
||||
<div class="relative rounded-150 overflow-hidden w-full h-[500px] bg-white">
|
||||
<img
|
||||
:id="`category-image-${id}`"
|
||||
class="absolute object-cover size-full"
|
||||
class="absolute object-contain size-full"
|
||||
:src="picture"
|
||||
alt=""
|
||||
/>
|
||||
@@ -49,7 +49,7 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`);
|
||||
<div class="typo-s-h-md">
|
||||
{{ category }}
|
||||
<span class="typo-p-xs -translate-y-1 inline-block mr-1">
|
||||
24
|
||||
{{ count }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="typo-p-md">محصولات ما را مشاهده کنید</span>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import useGetAccount from "~/composables/api/account/useGetAccount";
|
||||
import { useAuth } from "~/composables/api/auth/useAuth";
|
||||
import useBaseUrl from "~/composables/global/useBaseUrl";
|
||||
|
||||
// types
|
||||
|
||||
@@ -15,6 +16,7 @@ type NavLink = {
|
||||
|
||||
const { data: account } = useGetAccount();
|
||||
const { logout } = useAuth();
|
||||
const baseUrl = useBaseUrl();
|
||||
|
||||
const nav_links = ref<NavLink[]>([
|
||||
{
|
||||
@@ -45,45 +47,44 @@ const nav_links = ref<NavLink[]>([
|
||||
<div
|
||||
class="size-full flex items-center justify-between container py-[2.25rem]"
|
||||
>
|
||||
<div
|
||||
v-if="!!account"
|
||||
class="w-2/12 flex items-center justify-start"
|
||||
>
|
||||
<span class="size-[2rem] bg-black rounded-full"></span>
|
||||
<button @click="() => logout(true)">خروج از وبسایت</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-16">
|
||||
<div class="flex items-center justify-end gap-[1.5rem]">
|
||||
<button
|
||||
v-if="!!account"
|
||||
:title="account.first_name + ' ' + account.last_name"
|
||||
@click="() => logout(true)"
|
||||
class="size-[1.5rem] relative overflow-hidden rounded-full bg-slate-300"
|
||||
>
|
||||
<img :src="baseUrl + account.profile_photo" alt="" />
|
||||
</button>
|
||||
<NuxtLink to="/signin" v-else class="flex-center">
|
||||
<Icon name="ci:profile" size="20px" class="**:stroke-black" />
|
||||
</NuxtLink>
|
||||
<button class="flex-center">
|
||||
<Icon name="ci:search" size="18px" class="**:stroke-black" />
|
||||
</button>
|
||||
<button class="flex-center">
|
||||
<Icon name="ci:cart" size="20px" class="**:stroke-black" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@click="navigateTo('/signin')"
|
||||
class="cursor-pointer"
|
||||
v-else
|
||||
>
|
||||
وارد شوید
|
||||
</button>
|
||||
|
||||
<nav
|
||||
class="flex-center gap-[2.5rem] w-8/12 typo-label-sm text-slate-500"
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="(link, index) in nav_links"
|
||||
:key="index"
|
||||
:to="link.path"
|
||||
<nav
|
||||
class="flex-center gap-[2.5rem] typo-label-sm text-slate-600"
|
||||
>
|
||||
{{ link.title }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
|
||||
<div class="w-2/12 flex items-center justify-end gap-[1.5rem]">
|
||||
<button class="size-[1.5rem] flex-center">
|
||||
<Icon name="ci:search" class="**:stroke-black" />
|
||||
</button>
|
||||
<button class="size-[1.5rem] flex-center">
|
||||
<Icon name="ci:profile" class="**:stroke-black" />
|
||||
</button>
|
||||
<button class="size-[1.5rem] flex-center">
|
||||
<Icon name="ci:cart" class="**:stroke-black" />
|
||||
</button>
|
||||
<NuxtLink
|
||||
v-for="(link, index) in nav_links"
|
||||
:key="index"
|
||||
:to="link.path"
|
||||
>
|
||||
{{ link.title }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
LOGO
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@ type Props = {
|
||||
picture: string;
|
||||
title: string;
|
||||
color: string;
|
||||
price: number;
|
||||
price: string;
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
@@ -99,14 +99,14 @@ watch(
|
||||
<template>
|
||||
<div class="size-full flex flex-col gap-14 justify-between">
|
||||
<div class="w-full flex flex-col gap-10">
|
||||
<div class="flex items-center justify-between w-full gap-5">
|
||||
<div class="flex flex-col items-center w-full gap-5">
|
||||
<div
|
||||
class="flex items-center justify-start gap-2 text-lg w-full"
|
||||
>
|
||||
<Icon name="ci:filter-list" size="24" />
|
||||
ترتیب بر اساس
|
||||
</div>
|
||||
<div class="w-full flex items-start justify-end gap-2">
|
||||
<div class="w-full flex items-center gap-2">
|
||||
<button
|
||||
v-for="(sort, index) in sort_filter"
|
||||
:key="index"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type { SwiperClass } from "swiper/react";
|
||||
import useHomeData from "~/composables/api/home/useHomeData";
|
||||
|
||||
type Props = {}
|
||||
|
||||
@@ -14,30 +15,10 @@ const {} = toRefs(props);
|
||||
|
||||
// state
|
||||
|
||||
const { data: homeData } = useHomeData();
|
||||
|
||||
const swiper_instance = ref<SwiperClass | null>(null);
|
||||
|
||||
const slides = [
|
||||
{
|
||||
id: 0,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "TEST"
|
||||
}
|
||||
];
|
||||
|
||||
// methods
|
||||
|
||||
@@ -48,50 +29,58 @@ const onSwiper = (swiper: SwiperClass) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full my-20 relative">
|
||||
<Swiper
|
||||
:slides-per-view="3.65"
|
||||
:space-between="20"
|
||||
:slides-offset-after="125"
|
||||
:slides-offset-before="125"
|
||||
@swiper="onSwiper"
|
||||
>
|
||||
<SwiperSlide
|
||||
v-for="slide in slides"
|
||||
:key="slide.id"
|
||||
<section class="flex flex-col gap-4 bg-black h-[110svh] mt-40 py-32">
|
||||
<div class="w-full flex justify-center items-center">
|
||||
<span class="text-white typo-h-4">
|
||||
دسته بندی ها
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-full my-20 relative">
|
||||
<Swiper
|
||||
:loop="true"
|
||||
:centered-slides="true"
|
||||
:slides-per-view="3.65"
|
||||
:space-between="20"
|
||||
@swiper="onSwiper"
|
||||
>
|
||||
<CategoryCard
|
||||
:id="slide.id"
|
||||
category="یک دسته بندی تست"
|
||||
picture="/img/product-1.jpg"
|
||||
:count="20"
|
||||
description="یک دسته بندی تستasdasd"
|
||||
<SwiperSlide
|
||||
v-for="slide in homeData!.sub_categories"
|
||||
:key="slide.id"
|
||||
>
|
||||
<CategoryCard
|
||||
dark-layer
|
||||
:id="slide.id"
|
||||
:category="slide.name"
|
||||
:picture="slide.icon"
|
||||
:count="slide.product_count"
|
||||
description="توضیحات دسته بندی"
|
||||
/>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
|
||||
<div
|
||||
v-if="!swiper_instance?.isBeginning"
|
||||
@click="swiper_instance?.slidePrev()"
|
||||
class="absolute z-20 right-20 shadow-lg cursor-pointer shadow-black/25 bottom-[50%] bg-white rounded-full size-11.5 flex justify-center items-center"
|
||||
>
|
||||
<Icon
|
||||
name="ci:arrow-right"
|
||||
class="**:stroke-black"
|
||||
size="24"
|
||||
/>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!swiper_instance?.isBeginning"
|
||||
@click="swiper_instance?.slidePrev()"
|
||||
class="absolute z-20 right-20 shadow-lg cursor-pointer shadow-black/25 bottom-[50%] bg-white rounded-full size-11.5 flex justify-center items-center"
|
||||
>
|
||||
<Icon
|
||||
name="ci:arrow-right"
|
||||
class="**:stroke-black"
|
||||
size="24"
|
||||
/>
|
||||
<div
|
||||
v-if="!swiper_instance?.isEnd"
|
||||
@click="swiper_instance?.slideNext()"
|
||||
class="absolute z-20 left-20 shadow-lg cursor-pointer shadow-black/25 bottom-[50%] bg-white rounded-full size-11.5 flex justify-center items-center"
|
||||
>
|
||||
<Icon
|
||||
name="ci:arrow-left"
|
||||
class="**:stroke-black"
|
||||
size="24"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!swiper_instance?.isEnd"
|
||||
@click="swiper_instance?.slideNext()"
|
||||
class="absolute z-20 left-20 shadow-lg cursor-pointer shadow-black/25 bottom-[50%] bg-white rounded-full size-11.5 flex justify-center items-center"
|
||||
>
|
||||
<Icon
|
||||
name="ci:arrow-left"
|
||||
class="**:stroke-black"
|
||||
size="24"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -4,34 +4,13 @@
|
||||
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
import type { SwiperClass } from "swiper/react";
|
||||
import useHomeData from "~/composables/api/home/useHomeData";
|
||||
|
||||
// state
|
||||
|
||||
const { data: homeData } = useHomeData();
|
||||
const swiper_instance = ref<SwiperClass | null>(null);
|
||||
|
||||
const slides = [
|
||||
{
|
||||
id: 0,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "TEST"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "TEST"
|
||||
}
|
||||
];
|
||||
|
||||
// methods
|
||||
|
||||
const onSwiper = (swiper: SwiperClass) => {
|
||||
@@ -58,27 +37,36 @@ const onChange = (swiper: SwiperClass) => {
|
||||
@slide-change="onChange"
|
||||
>
|
||||
<SwiperSlide
|
||||
v-for="slide in slides"
|
||||
v-for="slide in homeData!.sliders"
|
||||
:key="slide.id"
|
||||
>
|
||||
<div class="relative w-full rounded-200 h-[80svh] overflow-hidden">
|
||||
<img
|
||||
<video
|
||||
v-if="!!slide.video"
|
||||
muted
|
||||
autoplay
|
||||
loop
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
src="/img/hero-bg.jpg"
|
||||
alt=""
|
||||
:src="slide.video"
|
||||
/>
|
||||
<div class="size-full absolute z-10 bg-linear-to-t from-black to-transparent" />
|
||||
<img
|
||||
v-else
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
:src="slide.image!"
|
||||
:alt="slide.title"
|
||||
/>
|
||||
<div class="size-full absolute z-10 bg-linear-to-t from-black/50 to-transparent" />
|
||||
<div class="px-20 absolute z-10 w-full bottom-36">
|
||||
<div class="border-b border-white/10 pb-6">
|
||||
<h3 class="typo-hero-1 text-white">
|
||||
Samsung {{ slide.id }}
|
||||
<div class="border-b border-white/10 pb-6 flex flex-col gap-4">
|
||||
<h3 class="typo-h-1 tracking-[-2px] text-white">
|
||||
{{ slide.title }}
|
||||
</h3>
|
||||
<div class="flex justify-between items-end">
|
||||
<span class="typo-p-lg text-white">
|
||||
توضیحات درمورد این محصول خاص
|
||||
</span>
|
||||
<span class="typo-p-lg text-white">
|
||||
{{ slide.description }}
|
||||
</span>
|
||||
<Button class="invert rounded-full hover:bg-transparent">
|
||||
خرید Samsung
|
||||
مشاهده
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,7 +86,7 @@ const onChange = (swiper: SwiperClass) => {
|
||||
</button>
|
||||
<div class="flex items-center justify-center gap-3 text-white">
|
||||
<div
|
||||
v-for="(slide, index) in slides"
|
||||
v-for="(_slide, index) in homeData!.sliders"
|
||||
:class="swiper_instance?.realIndex === index ? 'bg-white' : 'bg-transparent'"
|
||||
class="border border-white size-3 rounded-full transition-all duration-200"
|
||||
@click="swiper_instance?.slideTo(index)"
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
// import
|
||||
|
||||
import useHomeData from "~/composables/api/home/useHomeData";
|
||||
|
||||
// state
|
||||
|
||||
const { data: homeData } = useHomeData();
|
||||
|
||||
const clipPathPercent = ref(49);
|
||||
|
||||
const draggableEl = ref<HTMLElement | null>(null);
|
||||
@@ -29,56 +36,64 @@ watch(
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="flex flex-col items-center gap-3 mb-16">
|
||||
<span class="typo-p-md text-slate-500">یک متن تست لورم</span>
|
||||
<span class="typo-h-3 text-black"
|
||||
>تفاوت محصول را ببینید در اینجا</span
|
||||
>
|
||||
<span class="typo-p-md text-slate-500">مقایسه محصولات</span>
|
||||
<span class="typo-h-3 text-black">
|
||||
تفاوت محصلات ما را ببینید
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
ref="previewContainerEl"
|
||||
class="rounded-200 overflow-hidden h-[90svh] relative"
|
||||
>
|
||||
<img
|
||||
src="/img/hero-bg.jpg"
|
||||
class="select-none absolute size-full object-cover"
|
||||
alt=""
|
||||
:src="homeData!.difreance_section.image1"
|
||||
class="select-none absolute size-full object-cover brightness-[95%]"
|
||||
:alt="homeData!.difreance_section.title1"
|
||||
/>
|
||||
|
||||
<div class="absolute size-full right-0 w-full">
|
||||
<img
|
||||
src="/img/hero-bg.jpg"
|
||||
class="overlay-image select-none absolute object-cover size-full hue-rotate-200 brightness-35"
|
||||
alt=""
|
||||
:src="homeData!.difreance_section.image2"
|
||||
class="overlay-image select-none absolute object-cover size-full brightness-[95%]"
|
||||
:alt="homeData!.difreance_section.title2"
|
||||
/>
|
||||
<div
|
||||
:style="{
|
||||
left: `${clipPathPercent}%`,
|
||||
}"
|
||||
ref="draggableEl"
|
||||
class="select-none w-2 h-full bg-white absolute left-0 flex items-center justify-center"
|
||||
class="select-none w-2 h-full bg-black absolute left-0 flex items-center justify-center"
|
||||
>
|
||||
<div
|
||||
class="cursor-grab hover:scale-115 transition-transform rounded-full absolute bg-white size-11 flex items-center justify-center"
|
||||
class="cursor-grab hover:scale-115 transition-transform rounded-full absolute bg-black size-11 flex items-center justify-center"
|
||||
>
|
||||
<Icon
|
||||
name="ci:arrows"
|
||||
size="24"
|
||||
class="**:stroke-black"
|
||||
class="**:stroke-white"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="absolute bottom-0 p-10 w-full flex justify-between items-end bg-linear-to-t from-black/55 to-transparent"
|
||||
class="absolute bottom-0 p-10 w-full flex justify-between items-end"
|
||||
>
|
||||
<div class="flex flex-col gap-2 text-white">
|
||||
<span class="typo-p-md">رنگ محصول</span>
|
||||
<span class="typo-h-3">نارنجی</span>
|
||||
<div class="flex flex-col gap-2 text-black">
|
||||
<span class="typo-p-md">
|
||||
{{ homeData!.difreance_section.description1 }}
|
||||
</span>
|
||||
<span class="typo-h-3">
|
||||
{{ homeData!.difreance_section.title1 }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col justify-start gap-2 text-white">
|
||||
<span class="typo-p-md">رنگ محصول</span>
|
||||
<span class="typo-h-3">سفید</span>
|
||||
<div class="flex flex-col gap-2 text-black">
|
||||
<span class="typo-p-md text-end">
|
||||
{{ homeData!.difreance_section.description2 }}
|
||||
</span>
|
||||
<span class="typo-h-3 text-end">
|
||||
{{ homeData!.difreance_section.title2 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
// types
|
||||
|
||||
type Props = {}
|
||||
|
||||
// props
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const {} = toRefs(props);
|
||||
|
||||
// state
|
||||
|
||||
const isOpen = ref(false);
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
|
||||
// import
|
||||
|
||||
import useGetProduct from "~/composables/api/product/useGetProduct";
|
||||
|
||||
// state
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.params.id as string | undefined;
|
||||
|
||||
const { data: product } = useGetProduct(id);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="h-[95svh] w-full relative bg-black mt-[5rem]">
|
||||
<img src="/img/product-3.jpg" class="object-cover absolute size-full" />
|
||||
<div class="size-full absolute inset-0 bg-black/60" />
|
||||
<section class="h-[110svh] w-full relative bg-black mt-[5rem]">
|
||||
<video
|
||||
src="/video/product-video.mp4"
|
||||
class="object-cover absolute size-full"
|
||||
muted
|
||||
autoplay
|
||||
loop
|
||||
/>
|
||||
<div class="size-full absolute inset-0 bg-black/20" />
|
||||
<StickyCard
|
||||
color="سبز"
|
||||
:price="240000"
|
||||
picture="/img/product-1.jpg"
|
||||
title="نام محصول"
|
||||
class="absolute right-6 bottom-6"
|
||||
color="آبی"
|
||||
:price="product!.price"
|
||||
picture="/img/product-6.webp"
|
||||
:title="product!.name"
|
||||
class="absolute right-10 bottom-10"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// imports
|
||||
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
|
||||
|
||||
// types
|
||||
|
||||
export type GetHomeDataResponse = {
|
||||
"sliders": {
|
||||
"id": number,
|
||||
"link": string,
|
||||
"title": string,
|
||||
"description": string,
|
||||
"image": string | null,
|
||||
"video": string | null
|
||||
}[],
|
||||
"sub_categories": {
|
||||
"id": number,
|
||||
"name": string,
|
||||
"icon": string,
|
||||
"product_count": number,
|
||||
}[],
|
||||
"products": Product[],
|
||||
"difreance_section": {
|
||||
"image1": string,
|
||||
"image2": string,
|
||||
"title1": string,
|
||||
"title2": string,
|
||||
"description1": string,
|
||||
"description2": string,
|
||||
"link1": string,
|
||||
"link2": string
|
||||
}
|
||||
};
|
||||
|
||||
const useHomeData = () => {
|
||||
|
||||
// state
|
||||
|
||||
const { $axios: axios } = useNuxtApp();
|
||||
|
||||
// methods
|
||||
|
||||
const handleHomeData = async () => {
|
||||
const { data } = await axios.get<GetHomeDataResponse>(`${API_ENDPOINTS.home}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
return useQuery({
|
||||
queryKey: [QUERY_KEYS.home],
|
||||
queryFn: () => handleHomeData()
|
||||
});
|
||||
};
|
||||
|
||||
export default useHomeData;
|
||||
@@ -1,40 +1,42 @@
|
||||
export const API_ENDPOINTS = {
|
||||
home : "/home",
|
||||
account: {
|
||||
profile: "/accounts/profile",
|
||||
send_otp: "/accounts/send_otp",
|
||||
send_otp: "/accounts/send_otp"
|
||||
},
|
||||
product: {
|
||||
get: "/products",
|
||||
get: "/products"
|
||||
},
|
||||
auth: {
|
||||
refresh: "/token/refresh",
|
||||
verify: "/accounts/verify",
|
||||
signin: "/token",
|
||||
logout: "/accounts/logout",
|
||||
logout: "/accounts/logout"
|
||||
},
|
||||
chat: {
|
||||
messages: "/chat/product",
|
||||
new_message: "/chat/product",
|
||||
new_message: "/chat/product"
|
||||
},
|
||||
products: {
|
||||
get_all: "/products",
|
||||
categories: "/products/categories",
|
||||
},
|
||||
categories: "/products/categories"
|
||||
}
|
||||
};
|
||||
|
||||
export const QUERY_KEYS = {
|
||||
home: "home",
|
||||
chat: "chat",
|
||||
product: "product",
|
||||
products: "products",
|
||||
account: "account",
|
||||
categories: "categories",
|
||||
categories: "categories"
|
||||
};
|
||||
|
||||
export const MUTATION_KEYS = {
|
||||
create_chat: "create_chat",
|
||||
create_chat: "create_chat"
|
||||
};
|
||||
|
||||
export const PRODUCT_RANGE = {
|
||||
min: 0,
|
||||
max: 100_000_000,
|
||||
max: 100_000_000
|
||||
};
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// import
|
||||
|
||||
import useGetCategories from "~/composables/api/product/useGetCategories";
|
||||
|
||||
// state
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
<script lang="ts" setup>
|
||||
|
||||
import Categories from "~/components/home/Categories.vue";
|
||||
// import
|
||||
|
||||
import useHomeData from "~/composables/api/home/useHomeData";
|
||||
|
||||
// state
|
||||
|
||||
const { suspense } = useHomeData();
|
||||
|
||||
// lifecycle
|
||||
|
||||
onServerPrefetch(async () => {
|
||||
const response = await suspense();
|
||||
|
||||
if (response.isError) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: `Landing error : ${response.error.message}`,
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -9,9 +28,8 @@ import Categories from "~/components/home/Categories.vue";
|
||||
<Hero />
|
||||
<Preview />
|
||||
<Categories />
|
||||
<ProductsSlider title="یک عنوان تستی" />
|
||||
<ProductsSlider title="محصولات پرفروش" />
|
||||
<Brands />
|
||||
<!-- <ProductHero />-->
|
||||
<MostRecentComments />
|
||||
<LatestStories />
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import axiosOriginal from "axios";
|
||||
import { useAuth } from "~/composables/api/auth/useAuth";
|
||||
import { API_ENDPOINTS } from "~/constants";
|
||||
import Logger from "~/tools/logger";
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useRuntimeConfig();
|
||||
@@ -23,7 +24,9 @@ export default defineNuxtPlugin(() => {
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
return response;
|
||||
}, function(error) {
|
||||
}, async function(error) {
|
||||
|
||||
await Logger.axiosErrorLog(error);
|
||||
|
||||
// if (error.status === 401) {
|
||||
// logout();
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Vendored
+5
-2
@@ -24,11 +24,14 @@ declare global {
|
||||
|
||||
type Product = {
|
||||
id: number;
|
||||
price: number;
|
||||
price: string;
|
||||
name: string;
|
||||
description: string;
|
||||
currency: string;
|
||||
image: string;
|
||||
"video": string | null,
|
||||
"image1": string,
|
||||
"image2": string,
|
||||
"image3": string,
|
||||
rating: number;
|
||||
view: number;
|
||||
sell: number;
|
||||
|
||||
Reference in New Issue
Block a user