added create or update logic
This commit is contained in:
@@ -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">
|
||||||
انصراف
|
انصراف
|
||||||
|
|||||||
Reference in New Issue
Block a user