Files
hossein-por-shop/frontend/components/cart/delivery/AddressModal.vue
T
2025-04-11 21:39:26 +03:30

300 lines
10 KiB
Vue

<script setup lang="ts">
// imports
import useCreateOrUpdateAddress from "~/composables/api/account/useCreateOrUpdateAddress";
import useGetAccount from "~/composables/api/account/useGetAccount";
import { QUERY_KEYS } from "~/constants";
import { useToast } from "~/composables/global/useToast";
// types
type Props = {
address?: Address;
};
// props
const props = defineProps<Props>();
const { address } = toRefs(props);
// computed
const isEditing = computed(() => !!address.value);
// state
const { $queryClient: queryClient } = useNuxtApp();
const { addToast } = useToast();
const isShow = ref(false);
const addressData = ref({
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
? "بله"
: "خیر",
is_main: address.value?.is_main ?? false,
});
// queries
const { data: account } = useGetAccount();
const {
mutateAsync: createOrUpdateAddress,
isPending: createAddressIsPending,
} = useCreateOrUpdateAddress(isEditing);
// methods
const closeModal = () => {
if (!isEditing.value) {
addressData.value = {
id: undefined,
province: "",
city: "",
address: "",
postal_code: "",
name: "",
phone: "",
for_me: "بله",
is_main: false,
};
}
isShow.value = false;
};
const addNew = () => {
createOrUpdateAddress(
{ ...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>
<template>
<Modal
v-model="isShow"
:title="!!address ? 'ویرایش آدرس' : 'افزودن آدرس'"
:icon="!!address ? 'bi:pen' : 'ci:plus'"
:iconSize="!!address ? '20' : '32'"
contectClass="w-full max-lg:container lg:!w-[70vw]"
@close="closeModal"
>
<template #trigger>
<Button
:end-icon="!!address ? 'bi:pen' : 'ci:plus'"
size="md"
class="rounded-full"
:variant="!!address ? 'ghost' : 'solid'"
:class="!!address ? '!bg-transparent !underline' : ''"
>
<span class="whitespace-pre">
{{ !!address ? "ویرایش" : "افزودن آدرس" }}
</span>
</Button>
</template>
<template #content>
<div class="flex-col-center gap-6 py-10" dir="rtl">
<div
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 as string"
/>
</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">
<label
for="province"
class="text-xs font-semibold lg:text-sm text-gray-900"
>استان
<span class="text-sm text-red-500">*</span>
</label>
<Input
id="province"
type="text"
placeholder="اینجا وارد کنید ..."
v-model="addressData.province!"
/>
</div>
<div class="flex flex-col gap-2">
<label
for="city"
class="text-xs font-semibold lg:text-sm text-gray-900"
>شهر
<span class="text-sm text-red-500">*</span></label
>
<Input
id="city"
type="text"
placeholder="اینجا وارد کنید ..."
v-model="addressData.city!"
/>
</div>
<div class="flex flex-col gap-2">
<label
for="post"
class="text-xs font-semibold lg:text-sm text-gray-900"
>کد پستی
<span class="text-sm text-red-500">*</span></label
>
<Input
id="post"
type="text"
placeholder="اینجا وارد کنید ..."
v-model="addressData.postal_code!"
/>
</div>
</div>
<div class="flex flex-col w-full gap-2">
<label
for="address"
class="text-xs font-semibold lg:text-sm text-gray-900"
>آدرس کامل
<span class="text-sm text-red-500">*</span></label
>
<textarea
id="address"
placeholder="آدرس خود را بنویسید"
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-1.5 lg:py-3.5 selection:bg-slate-100 rounded-md lg:rounded-100 outline-none flex-1 text-xs lg:!text-sm placeholder-slate-400"
></textarea>
</div>
<div class="flex items-center justify-between w-full gap-2">
<label
for="is_main"
class="text-xs font-semibold lg:text-sm text-gray-900"
>
به عنوان آدرس پیش فرض ثبت شود؟
</label>
<Switch id="is_main" v-model="addressData.is_main" />
</div>
</div>
<div class="py-6 border-t border-slate-200 flex gap-3">
<Button
:disabled="createAddressIsPending"
@click="addNew"
class="rounded-full px-10"
size="md"
>
<Icon
v-if="createAddressIsPending"
name="svg-spinners:3-dots-bounce"
/>
<span v-else>ثبت</span>
</Button>
<DialogClose aria-label="Close">
<Button
variant="outlined"
class="rounded-full px-10"
size="md"
>
انصراف
</Button>
</DialogClose>
</div>
</template>
</Modal>
</template>
<style scoped></style>