324 lines
12 KiB
Vue
324 lines
12 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";
|
|
import useVuelidate from "@vuelidate/core";
|
|
import { helpers, required, minLength } from "@vuelidate/validators";
|
|
|
|
// 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,
|
|
});
|
|
|
|
// computed
|
|
|
|
const formRules = computed(() => {
|
|
return {
|
|
province: {
|
|
required: helpers.withMessage("فیلد استان سکونت الزامی می باشد", required),
|
|
minLength: helpers.withMessage("فیلد استان سکونت حداقل 2 کرکتر می باشد", minLength(2)),
|
|
},
|
|
city: {
|
|
required: helpers.withMessage("فیلد شهر سکونت الزامی می باشد", required),
|
|
minLength: helpers.withMessage("فیلد شهر سکونت حداقل 2 کرکتر می باشد", minLength(2)),
|
|
},
|
|
postal_code: {
|
|
required: helpers.withMessage("فیلد کد پستی الزامی می باشد", required),
|
|
minLength: helpers.withMessage("فیلد کد پستی حداقل 10 کرکتر می باشد", minLength(10)),
|
|
},
|
|
address: {
|
|
required: helpers.withMessage("فیلد آدرس کامل الزامی می باشد", required),
|
|
minLength: helpers.withMessage("فیلد آدرس کامل حداقل 2 کرکتر می باشد", minLength(2)),
|
|
},
|
|
phone: {
|
|
required: helpers.withMessage("فیلد تلفن همراه الزامی می باشد", required),
|
|
minLength: helpers.withMessage("فیلد تلفن همراه حداقل 10 کرکتر می باشد", minLength(10)),
|
|
},
|
|
};
|
|
});
|
|
|
|
const formValidator$ = useVuelidate(formRules, addressData);
|
|
|
|
// 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,
|
|
};
|
|
}
|
|
formValidator$.value.$reset();
|
|
isShow.value = false;
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
await formValidator$.value.$validate();
|
|
if (!formValidator$.value.$errors.length) {
|
|
createOrUpdateAddress(
|
|
{ ...addressData.value },
|
|
{
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.addresses],
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.cart],
|
|
});
|
|
closeModal();
|
|
addToast({
|
|
message: isEditing.value ? "آدرس با موفقیت ویرایش شد" : "آدرس با موفقیت اضافه شد",
|
|
options: {
|
|
status: "success",
|
|
},
|
|
});
|
|
},
|
|
onError: () => {
|
|
addToast({
|
|
message: isEditing.value ? "آدرس با موفقیت ویرایش شد" : "مشکلی در افزودن آدرس رخ داد",
|
|
options: {
|
|
status: "error",
|
|
},
|
|
});
|
|
},
|
|
},
|
|
);
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => [addressData.value.for_me, isShow.value],
|
|
([newValue, newValue2]) => {
|
|
if (!isEditing.value) {
|
|
addressData.value.phone = newValue == "بله" && newValue2 ? (account.value?.phone ?? "") : "";
|
|
}
|
|
},
|
|
{
|
|
immediate: 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 transition-all"
|
|
:variant="!!address ? 'ghost' : 'solid'"
|
|
:class="!!address ? '!bg-transparent !underline underline-offset-4' : ''"
|
|
>
|
|
<span class="whitespace-pre max-lg:text-xs">
|
|
{{ !!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">
|
|
<DataField
|
|
id="name"
|
|
label="نام پیش فرض آدرس"
|
|
>
|
|
<Input
|
|
id="name"
|
|
type="text"
|
|
placeholder="اینجا وارد کنید ..."
|
|
v-model="addressData.name!"
|
|
/>
|
|
</DataField>
|
|
|
|
<DataField
|
|
id="for_me"
|
|
label="آدرس شما؟"
|
|
:required="true"
|
|
>
|
|
<Select
|
|
id="for_me"
|
|
:options="['بله', 'خیر']"
|
|
placeholder="انتخاب کنید"
|
|
v-model="addressData.for_me as string"
|
|
/>
|
|
</DataField>
|
|
|
|
<DataField
|
|
id="phone"
|
|
label="تلفن همراه"
|
|
:required="true"
|
|
:error="formValidator$.phone"
|
|
>
|
|
<Input
|
|
id="phone"
|
|
type="text"
|
|
placeholder="اینجا وارد کنید ..."
|
|
:error="formValidator$.phone.$error"
|
|
v-model="addressData.phone!"
|
|
/>
|
|
</DataField>
|
|
|
|
<DataField
|
|
id="province"
|
|
label="استان"
|
|
:required="true"
|
|
:error="formValidator$.province"
|
|
>
|
|
<Input
|
|
id="province"
|
|
type="text"
|
|
placeholder="اینجا وارد کنید ..."
|
|
:error="formValidator$.province.$error"
|
|
v-model="addressData.province!"
|
|
/>
|
|
</DataField>
|
|
|
|
<DataField
|
|
id="city"
|
|
label="شهر"
|
|
:required="true"
|
|
:error="formValidator$.city"
|
|
>
|
|
<Input
|
|
id="city"
|
|
type="text"
|
|
placeholder="اینجا وارد کنید ..."
|
|
:error="formValidator$.city.$error"
|
|
v-model="addressData.city!"
|
|
/>
|
|
</DataField>
|
|
|
|
<DataField
|
|
id="postal_code"
|
|
label="کد پستی"
|
|
:required="true"
|
|
:error="formValidator$.postal_code"
|
|
>
|
|
<Input
|
|
id="postal_code"
|
|
type="text"
|
|
placeholder="اینجا وارد کنید ..."
|
|
:error="formValidator$.postal_code.$error"
|
|
v-model="addressData.postal_code!"
|
|
/>
|
|
</DataField>
|
|
</div>
|
|
|
|
<DataField
|
|
id="address"
|
|
label="آدرس کامل"
|
|
:required="true"
|
|
:error="formValidator$.address"
|
|
>
|
|
<Textarea
|
|
id="address"
|
|
placeholder="آدرس خود را بنویسید"
|
|
v-model="addressData.address"
|
|
:error="formValidator$.address.$error"
|
|
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-2.5 lg:py-3 leading-[175%] selection:bg-slate-100 rounded-md lg:rounded-100 outline-none max-lg:h-[5rem] lg:flex-1 text-xs lg:!text-sm placeholder-slate-400 placeholder:text-xs lg:placeholder:text-sm placeholder:font-normal"
|
|
></Textarea>
|
|
</DataField>
|
|
|
|
<div class="flex items-center justify-between w-full gap-2">
|
|
<label
|
|
for="is_main"
|
|
class="text-xs font-medium lg:text-sm text-gray-900"
|
|
>
|
|
به عنوان آدرس پیش فرض ثبت شود؟
|
|
</label>
|
|
|
|
<!-- {{ address?.is_main }} -->
|
|
|
|
<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="handleSubmit"
|
|
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>
|