added create or update logic

This commit is contained in:
Mamalizz
2025-02-02 23:06:13 +03:30
parent b3e09152e4
commit fc22ca0d99
+169 -50
View File
@@ -1,4 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
// imports
import useCreateOrUpdateAddress, {
type CreateOrUpdateAddressRequest,
} from "~/composables/api/account/useCreateOrUpdateAddress";
import useGetAccount from "~/composables/api/account/useGetAccount";
import { QUERY_KEYS } from "~/constants";
import { useToast } from "~/composables/global/useToast";
// types // types
type Props = { type Props = {
@@ -11,45 +20,105 @@ const props = defineProps<Props>();
const { address } = toRefs(props); const { address } = toRefs(props);
// emit
const emit = defineEmits(["add"]);
// state
const isShow = ref(false);
const addressData = ref<
Pick<Address, "province" | "city" | "postal_code" | "full_address">
>({
province: address.value?.province ?? "",
city: address.value?.city ?? "",
postal_code: address.value?.postal_code ?? "",
full_address: address.value?.full_address ?? "",
});
// computed // computed
const isEditing = computed(() => !!address.value); const isEditing = computed(() => !!address.value);
// state
const { $queryClient: queryClient } = useNuxtApp();
const { addToast } = useToast();
const isShow = ref(false);
const addressData = ref<CreateOrUpdateAddressRequest>({
id: address.value?.id ?? undefined,
province: address.value?.province ?? "",
city: address.value?.city ?? "",
postal_code: address.value?.postal_code ?? "",
address: address.value?.address ?? "",
name: address.value?.name ?? "",
phone: address.value?.phone ?? "",
for_me: !isEditing.value
? address.value?.for_me ?? "بله"
: address.value?.for_me == true
? "بله"
: "خیر",
});
// queries
const { data: account } = useGetAccount();
const {
mutateAsync: createOrUpdateAddress,
isPending: createAddressIsPending,
} = useCreateOrUpdateAddress(isEditing);
// methods // methods
const closeModal = () => { const closeModal = () => {
if (!isEditing.value) { if (!isEditing.value) {
addressData.value = { addressData.value = {
id: undefined,
province: "", province: "",
city: "", city: "",
address: "",
postal_code: "", postal_code: "",
full_address: "", name: "",
phone: "",
for_me: "بله",
}; };
} }
isShow.value = false; isShow.value = false;
}; };
const addNew = () => { const addNew = () => {
emit("add", { ...addressData.value, id: Date.now() }); createOrUpdateAddress(
closeModal(); { ...addressData.value },
{
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [QUERY_KEYS.addresses],
});
closeModal();
addToast({
message: isEditing.value
? "آدرس با موفقیت ویرایش شد"
: "آدرس با موفقیت اضافه شد",
options: {
status: "success",
},
});
},
onError: () => {
addToast({
message: isEditing.value
? "آدرس با موفقیت ویرایش شد"
: "مشکلی در افزودن آدرس رخ داد",
options: {
status: "error",
},
});
},
}
);
}; };
watch(
() => addressData.value.for_me,
(newValue) => {
if (!isEditing.value) {
addressData.value.phone =
newValue == "بله" ? account.value?.phone : "";
}
},
{
immediate: true,
deep: true,
}
);
</script> </script>
<template> <template>
@@ -74,7 +143,7 @@ const addNew = () => {
</DialogTrigger> </DialogTrigger>
<DialogPortal> <DialogPortal>
<DialogOverlay <DialogOverlay
class="bg-black/20 data-[state=open]:animate-overlay-show fixed inset-0 z-30" class="bg-black/50 backdrop-blur-sm data-[state=open]:animate-overlay-show fixed inset-0 z-30"
/> />
<DialogContent <DialogContent
class="data-[state=open]:animate-content-show text-black font-iran-yekan-x fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[50rem] translate-x-[-50%] translate-y-[-50%] rounded-3xl bg-white shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none z-[100]" class="data-[state=open]:animate-content-show text-black font-iran-yekan-x fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[50rem] translate-x-[-50%] translate-y-[-50%] rounded-3xl bg-white shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none z-[100]"
@@ -86,10 +155,16 @@ const addNew = () => {
class="inline-flex size-8 items-center justify-center transition-all rounded-full bg-gray-50 border border-slate-200 hover:border-black focus:outline-none" class="inline-flex size-8 items-center justify-center transition-all rounded-full bg-gray-50 border border-slate-200 hover:border-black focus:outline-none"
aria-label="Close" aria-label="Close"
> >
<Icon name="bi:x-lg" class="**:fill-red-600" /> <Icon name="bi:x-lg" class="**:fill-black" />
</DialogClose> </DialogClose>
<DialogTitle class="typo-sub-h-xl font-semibold"> <DialogTitle
class="typo-sub-h-xl font-semibold flex items-center gap-3"
>
{{ !!address ? "ویرایش آدرس" : "افزودن آدرس" }} {{ !!address ? "ویرایش آدرس" : "افزودن آدرس" }}
<Icon
:name="!!address ? 'bi:pen' : 'bi:plus'"
:size="!!address ? '20' : '32'"
/>
</DialogTitle> </DialogTitle>
</div> </div>
@@ -97,6 +172,59 @@ const addNew = () => {
<div <div
class="grid w-full grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3" class="grid w-full grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3"
> >
<div class="flex flex-col gap-2">
<label
for="name"
class="text-xs font-semibold lg:text-sm text-gray-900"
>نام پیش فرض
<span class="text-sm text-red-500"
>*</span
></label
>
<Input
id="name"
type="text"
placeholder="اینجا وارد کنید ..."
v-model="addressData.name"
/>
</div>
<div class="flex flex-col gap-2">
<label
for="province"
class="text-xs font-semibold lg:text-sm text-gray-900"
>آدرس شما؟
<span class="text-sm text-red-500"
>*</span
></label
>
<Select
:options="['بله', 'خیر']"
placeholder="انتخاب کنید"
v-model="addressData.for_me"
/>
</div>
<div class="flex flex-col gap-2">
<label
for="phone"
class="text-xs font-semibold lg:text-sm text-gray-900"
>شماره تلفن
<span class="text-sm text-red-500"
>*</span
></label
>
<Input
id="phone"
type="text"
placeholder="اینجا وارد کنید ..."
v-model="addressData.phone"
/>
</div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<label <label
for="province" for="province"
@@ -107,18 +235,10 @@ const addNew = () => {
></label ></label
> >
<ComboBox <Input
id="province" id="province"
:options="[ type="text"
{ placeholder="اینجا وارد کنید ..."
name: 'استان ها',
children: [
{ name: 'مشهد' },
{ name: 'مشهد' },
{ name: 'مشهد' },
],
},
]"
v-model="addressData.province" v-model="addressData.province"
/> />
</div> </div>
@@ -132,18 +252,10 @@ const addNew = () => {
>*</span >*</span
></label ></label
> >
<ComboBox <Input
id="city" id="city"
:options="[ type="text"
{ placeholder="اینجا وارد کنید ..."
name: 'استان ها',
children: [
{ name: 'مشهد' },
{ name: 'مشهد' },
{ name: 'مشهد' },
],
},
]"
v-model="addressData.city" v-model="addressData.city"
/> />
</div> </div>
@@ -160,8 +272,7 @@ const addNew = () => {
<Input <Input
id="post" id="post"
type="text" type="text"
placeholder="جست و جو" placeholder="اینجا وارد کنید ..."
class="rounded-xl"
v-model="addressData.postal_code" v-model="addressData.postal_code"
/> />
</div> </div>
@@ -177,16 +288,24 @@ const addNew = () => {
<textarea <textarea
id="address" id="address"
placeholder="آدرس خود را بنویسید" placeholder="آدرس خود را بنویسید"
v-model="addressData.full_address" v-model="addressData.address"
class="flex items-center field-sizing-content resize-none bg-slate-50 border-slate-200 hover:border-black focus:border-black max-h-[10rem] text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100 outline-none flex-1 !text-sm placeholder-slate-400" class="flex items-center field-sizing-content resize-none bg-slate-50 border-slate-200 hover:border-black focus:border-black max-h-[10rem] text-black justify-between cursor-text transition-all border-[1.5px] gap-3 typo-label-md px-4 py-3.5 selection:bg-slate-100 rounded-100 outline-none flex-1 !text-sm placeholder-slate-400"
></textarea> ></textarea>
</div> </div>
</div> </div>
<div class="p-6 border-t border-slate-200 flex gap-3"> <div class="p-6 border-t border-slate-200 flex gap-3">
<Button @click="addNew" class="rounded-full px-10" <Button
>ثبت</Button :disabled="createAddressIsPending"
@click="addNew"
class="rounded-full px-10"
> >
<Icon
v-if="createAddressIsPending"
name="svg-spinners:3-dots-bounce"
/>
<span v-else>ثبت</span>
</Button>
<DialogClose aria-label="Close"> <DialogClose aria-label="Close">
<Button variant="outlined" class="rounded-full px-10"> <Button variant="outlined" class="rounded-full px-10">
انصراف انصراف