Extract save button logic

This commit is contained in:
marzban-dev
2026-05-26 11:14:52 +03:30
parent 886a3ee541
commit 048f5435ff
2 changed files with 49 additions and 42 deletions
@@ -0,0 +1,46 @@
<script lang="ts" setup>
// imports
import { useAuth } from "~/composables/api/auth/useAuth";
import useGetProduct from "~/composables/api/product/useGetProduct";
import useSaveProduct from "~/composables/api/product/useSaveProduct";
import { QUERY_KEYS } from "~/constants";
// states
const route = useRoute();
const id = route.params.id as string | undefined;
const { $queryClient: queryClient } = useNuxtApp();
const { token } = useAuth();
const { mutateAsync: saveProduct, isPending: isSaveProductPending } = useSaveProduct();
const { data: product, refetch: refetchProduct, isFetching: isFetchingPending } = useGetProduct(id);
// methods
const saveProductHandler = async () => {
await saveProduct({ product_slug: product.value!.slug });
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.product] });
};
</script>
<template>
<button
@click="saveProductHandler"
:disabled="isSaveProductPending || isFetchingPending || !token"
class="size-10 bg-slate-50 border-slate-200 border rounded-lg flex-center"
>
<Icon
v-if="isSaveProductPending || isFetchingPending"
name="ci:svg-spinners-180-ring-with-bg"
/>
<Icon
v-else
:class="product?.added_to_favorites ? '**:fill-blue-400' : ''"
:name="product?.added_to_favorites ? 'bi-bookmark-fill' : 'ci:bi-bookmark'"
/>
</button>
</template>
@@ -5,8 +5,6 @@ import useGetProduct from "~/composables/api/product/useGetProduct";
import type { ProductVariantProvideType } from "~/pages/product/[id].vue"; import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
import useAddCartItem from "~/composables/api/orders/useAddCartItem"; import useAddCartItem from "~/composables/api/orders/useAddCartItem";
import { useAuth } from "~/composables/api/auth/useAuth"; import { useAuth } from "~/composables/api/auth/useAuth";
import useSaveProduct from "~/composables/api/product/useSaveProduct";
import { QUERY_KEYS } from "~/constants";
// state // state
@@ -14,11 +12,9 @@ const route = useRoute();
const id = route.params.id as string | undefined; const id = route.params.id as string | undefined;
const { token } = useAuth(); const { token } = useAuth();
const { $queryClient: queryClient } = useNuxtApp();
const { data: product, refetch: refetchProduct, isFetching: isFetchingPending } = useGetProduct(id); const { data: product, refetch: refetchProduct, isFetching: isFetchingPending } = useGetProduct(id);
const { mutateAsync: addCartItem, isPending: isAddCartItemPending } = useAddCartItem(); const { mutateAsync: addCartItem, isPending: isAddCartItemPending } = useAddCartItem();
const { mutateAsync: saveProduct, isPending: isSaveProductPending } = useSaveProduct();
const selectedVariantId = ref(product.value!.variants[0].id); const selectedVariantId = ref(product.value!.variants[0].id);
const selectedQuantity = ref(1); const selectedQuantity = ref(1);
@@ -40,11 +36,6 @@ const addItemToCart = async () => {
await refetchProduct(); await refetchProduct();
}; };
const saveProductHandler = async () => {
await saveProduct({ product_slug: product.value!.slug });
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.product] });
};
// watch // watch
watch([selectedVariantId, product], ([selectedVariantId, product]) => { watch([selectedVariantId, product], ([selectedVariantId, product]) => {
@@ -99,22 +90,7 @@ watch(
</NuxtLink> </NuxtLink>
</div> </div>
<button <SaveButton />
@click="saveProductHandler"
:disabled="isSaveProductPending || isFetchingPending || !token"
class="size-10 bg-slate-50 border-slate-200 border rounded-lg flex-center"
>
<Icon
v-if="isSaveProductPending || isFetchingPending"
name="ci:svg-spinners-180-ring-with-bg"
/>
<Icon
v-else
:class="product?.added_to_favorites ? '**:fill-blue-400' : ''"
:name="product?.added_to_favorites ? 'bi-bookmark-fill' : 'ci:bi-bookmark'"
/>
</button>
</div> </div>
<h1 class="typo-h-6 xs:typo-h-5 sm:typo-h-4 lg:typo-h-2"> <h1 class="typo-h-6 xs:typo-h-5 sm:typo-h-4 lg:typo-h-2">
{{ product!.name }} {{ product!.name }}
@@ -178,22 +154,7 @@ watch(
</NuxtLink> </NuxtLink>
</div> </div>
<button <SaveButton />
@click="saveProductHandler"
:disabled="isSaveProductPending || isFetchingPending || !token"
class="size-10 bg-slate-50 border-slate-200 border rounded-lg flex-center"
>
<Icon
v-if="isSaveProductPending || isFetchingPending"
name="ci:svg-spinners-180-ring-with-bg"
/>
<Icon
v-else
:class="product?.added_to_favorites ? '**:fill-blue-400' : ''"
:name="product?.added_to_favorites ? 'bi-bookmark-fill' : 'ci:bi-bookmark'"
/>
</button>
</div> </div>
<h1 class="typo-h-4 xl:typo-h-3 max-lg:hidden"> <h1 class="typo-h-4 xl:typo-h-3 max-lg:hidden">
{{ product!.name }} {{ product!.name }}
@@ -365,7 +326,7 @@ watch(
<InfoCard /> <InfoCard />
<Share /> <Share :product="product!" />
</div> </div>
<ProductDescription <ProductDescription