133 lines
6.1 KiB
Vue
133 lines
6.1 KiB
Vue
<script setup>
|
||
import { computed, ref, watch } from 'vue';
|
||
import { Inertia } from '@inertiajs/inertia';
|
||
import { usePage } from '@inertiajs/inertia-vue3';
|
||
import Dialog from 'primevue/dialog';
|
||
import UiButton from '../ui/UiButton.vue';
|
||
import UiInput from '../ui/UiInput.vue';
|
||
import { useGlobalStore } from '../../store/Global';
|
||
|
||
const visible = defineModel('visible');
|
||
|
||
const globalStore = useGlobalStore();
|
||
const { props } = usePage();
|
||
|
||
const form = ref({
|
||
fullname: '',
|
||
birthdate: '',
|
||
national_code: '',
|
||
email: '',
|
||
province: '',
|
||
city: '',
|
||
address: '',
|
||
});
|
||
|
||
const avatarFile = ref(null);
|
||
const avatarPreview = ref('');
|
||
const avatarInput = ref(null);
|
||
const errors = ref({});
|
||
const submitting = ref(false);
|
||
|
||
const avatarUrl = computed(() => avatarPreview.value || globalStore.current_user.profile_url || '');
|
||
|
||
watch(visible, (isOpen) => {
|
||
if (!isOpen) return;
|
||
const user = props.value.auth?.User || {};
|
||
form.value = {
|
||
fullname: user.fullname || '',
|
||
birthdate: user.birthdate || '',
|
||
national_code: user.national_code || '',
|
||
email: user.email || '',
|
||
province: user.province || '',
|
||
city: user.city || '',
|
||
address: user.address || '',
|
||
};
|
||
avatarFile.value = null;
|
||
avatarPreview.value = '';
|
||
errors.value = {};
|
||
});
|
||
|
||
const errorFor = (field) => {
|
||
const error = errors.value[field];
|
||
return Array.isArray(error) ? error[0] : (error || '');
|
||
};
|
||
|
||
const openAvatarPicker = () => {
|
||
avatarInput.value?.click();
|
||
};
|
||
|
||
const handleAvatarChange = (event) => {
|
||
const file = event.target.files?.[0];
|
||
if (!file) return;
|
||
avatarFile.value = file;
|
||
avatarPreview.value = URL.createObjectURL(file);
|
||
};
|
||
|
||
const submit = () => {
|
||
submitting.value = true;
|
||
Inertia.post('/dashboard/profile', {
|
||
...form.value,
|
||
avatar: avatarFile.value,
|
||
}, {
|
||
forceFormData: true,
|
||
preserveScroll: true,
|
||
onSuccess: () => {
|
||
globalStore.current_user = props.value.auth.User;
|
||
visible.value = false;
|
||
},
|
||
onError: (formErrors) => {
|
||
errors.value = formErrors;
|
||
},
|
||
onFinish: () => {
|
||
submitting.value = false;
|
||
},
|
||
});
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<Dialog v-model:visible="visible" :modal="true" :closable="true" :dismissableMask="false" :maximizable="false" :style="{ width: '688px' , minHeight: '376px' }" class="fast-request-dialog" :pt="{header : '!bg-client-primaryBlue'}">
|
||
<template #header>
|
||
<div class="w-full flex items-center justify-start">
|
||
<h2 class="text-[14px] font-[700] text-[#576989]">ویرایش حساب کاربری</h2>
|
||
</div>
|
||
</template>
|
||
<form class="w-full flex flex-col gap-5 border-t border-[#EBEBEB] pt-5" @submit.prevent="submit">
|
||
<div class="flex items-center gap-4">
|
||
<div class="relative">
|
||
<span class="flex items-center justify-center w-20 h-20 rounded-full bg-[#F6F7F9] border border-[#DEE3EB] overflow-hidden">
|
||
<img v-if="avatarUrl" :src="avatarUrl" alt="تصویر پروفایل" class="w-full h-full object-cover" />
|
||
<i v-else class="fi fi-rr-user flex text-2xl text-[#576989]"></i>
|
||
</span>
|
||
<button type="button" class="absolute -bottom-1 -left-1 flex items-center justify-center w-7 h-7 rounded-full bg-dominant text-white border-2 border-white cursor-pointer" @click="openAvatarPicker">
|
||
<i class="fi fi-rr-camera flex text-[11px]"></i>
|
||
</button>
|
||
<input ref="avatarInput" type="file" accept="image/png,image/jpeg" class="hidden" @change="handleAvatarChange" />
|
||
</div>
|
||
<div class="flex flex-col gap-1">
|
||
<span class="text-[13px] font-[700] text-[#3E4C63]">تصویر پروفایل</span>
|
||
<span class="text-[11px] font-[400] text-[#576989]">فرمتهای مجاز: png ،jpg — حداکثر ۱۰ مگابایت</span>
|
||
<span v-if="errorFor('avatar')" class="text-[11px] text-[#7A1419]">{{ errorFor('avatar') }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-2 max-sm:grid-cols-1 gap-4">
|
||
<UiInput v-model="form.fullname" label="نام و نام خانوادگی" placeholder="نام و نام خانوادگی خود را وارد کنید" :error="errorFor('fullname')" />
|
||
<div class="flex flex-col gap-1">
|
||
<label class="ui-input-label">تاریخ تولد</label>
|
||
<CustomDatePicker v-model="form.birthdate" type="date" format="YYYY-MM-DD" display-format="jYYYY/jMM/jDD" class="w-full" />
|
||
<span v-if="errorFor('birthdate')" class="text-[11px] text-[#7A1419]">{{ errorFor('birthdate') }}</span>
|
||
</div>
|
||
<UiInput v-model="form.national_code" label="کد ملی" placeholder="کد ملی خود را وارد کنید" convertPersianNumbers :error="errorFor('national_code')" />
|
||
<UiInput v-model="form.email" label="ایمیل" type="email" placeholder="ایمیل خود را وارد کنید" direction="ltr" :error="errorFor('email')" />
|
||
<UiInput v-model="form.province" label="استان" placeholder="استان محل سکونت" :error="errorFor('province')" />
|
||
<UiInput v-model="form.city" label="شهر" placeholder="شهر محل سکونت" :error="errorFor('city')" />
|
||
</div>
|
||
<UiInput v-model="form.address" label="آدرس" placeholder="آدرس خود را وارد کنید" :error="errorFor('address')" />
|
||
<div class="w-full pt-3 flex items-center justify-start gap-2 border-t border-[#EBEBEB]">
|
||
<UiButton label="ذخیره تغییرات" severity="success" size="small" :loading="submitting" :disabled="submitting" @click="submit" />
|
||
<UiButton label="انصراف" severity="secondary" size="small" :disabled="submitting" @click="visible = false" />
|
||
</div>
|
||
</form>
|
||
</Dialog>
|
||
</template>
|