feat: add withdraw request functionality and UI components
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user