complete Complete User Request Submission section RAD-1
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
const props = defineProps({
|
||||
phone: String,
|
||||
availableLevels: Array
|
||||
})
|
||||
|
||||
const getLevelLabel = (level) => {
|
||||
return level === 'supervisor' ? 'پورتال کاربران' : level === 'doctor' ? 'پورتال پزشکان' : 'پورتال کاربران'
|
||||
}
|
||||
|
||||
const getLevelRoute = (level) => {
|
||||
return `/auth/login/choose-portal/${level}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.ChoosePortal.title') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.ChoosePortal.subtitle').replace('%phone%', phone) }}
|
||||
</p>
|
||||
<Link href="/auth/login/phone" class="!text-dominant-600 text-[11px] font-normal">
|
||||
(تغییر شماره)
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 mt-6">
|
||||
<Link
|
||||
v-for="level in availableLevels"
|
||||
:key="level"
|
||||
:href="getLevelRoute(level)"
|
||||
class="no-underline"
|
||||
>
|
||||
<UiButton
|
||||
severity="secondary"
|
||||
:label="getLevelLabel(level)"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</main>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,59 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue';
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
import { inject } from 'vue';
|
||||
|
||||
const route = inject('route');
|
||||
|
||||
const props = defineProps({
|
||||
phone: String
|
||||
})
|
||||
|
||||
const handleRegisterSupervisor = () => {
|
||||
Inertia.visit(route('register.supervisor'))
|
||||
}
|
||||
|
||||
const handleRegisterVet = () => {
|
||||
Inertia.visit(route('register.veterinarian'))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.ChooseRegisterType.title') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 text-[11px] font-normal">
|
||||
{{ $t('auth.ChooseRegisterType.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 mt-6">
|
||||
<UiButton
|
||||
severity="secondary"
|
||||
label="ثبتنام به عنوان سرپرست"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
@click="handleRegisterSupervisor"
|
||||
/>
|
||||
<UiButton
|
||||
severity="secondary"
|
||||
label="ثبتنام به عنوان دامپزشک"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
@click="handleRegisterVet"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<div class="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||
<h1 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
{{ $t('auth.forgot_password.title') }}
|
||||
</h1>
|
||||
</div>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,78 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import UiInput from '../../components/ui/UiInput.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
import { ref } from 'vue';
|
||||
import { inject } from 'vue';
|
||||
import { toast } from 'vue3-toastify';
|
||||
|
||||
const route = inject('route');
|
||||
|
||||
const code = ref('');
|
||||
const isLoading = ref(false);
|
||||
|
||||
const handleVerifyOtp = () => {
|
||||
isLoading.value = true
|
||||
Inertia.post(route('verifyOtp'), {
|
||||
otp_code: code.value
|
||||
}, {
|
||||
onError: (errors) => {
|
||||
toast.error(errors.otp_code || 'خطا در تایید کد تایید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
},
|
||||
onFinish: () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.OtpVerification.title').replace('%userType%', 'پزشکان') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.OtpVerification.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 mt-6">
|
||||
<UiInput
|
||||
prefix-end="کد تایید موقت"
|
||||
type="text"
|
||||
custom-class="!pl-3"
|
||||
direction="ltr"
|
||||
v-model="code"
|
||||
/>
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
class="!mt-4"
|
||||
:label="isLoading ? 'در حال تایید...' : 'تایید و بازیابی گذرواژه'"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
:loading="isLoading"
|
||||
@click="handleVerifyOtp"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
<template #footer>
|
||||
<Link class="text-center text-[13px] font-normal text-dominant-700 mt-6" :href="route('login')">
|
||||
تغییر شماره موبایل
|
||||
</Link>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,89 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import UiInput from '../../components/ui/UiInput.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import { ref } from 'vue'
|
||||
import { toast } from 'vue3-toastify';
|
||||
|
||||
const props = defineProps({
|
||||
phone: String,
|
||||
level: String
|
||||
})
|
||||
|
||||
|
||||
const password = ref('');
|
||||
const isLoading = ref(false)
|
||||
|
||||
const handleLogin = () => {
|
||||
if (!password.value) {
|
||||
toast.error('لطفاً گذرواژه را وارد کنید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
Inertia.post('/auth/login/authenticate', {
|
||||
password: password.value
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
isLoading.value = false
|
||||
},
|
||||
onError: (errors) => {
|
||||
isLoading.value = false
|
||||
toast.error(errors.password || 'خطا در ورود')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.Password.title').replace('%userType%', level === 'supervisor' ? 'سرپرست' : level === 'doctor' ? 'پزشک' : 'دانپزشک') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.Password.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 mt-6">
|
||||
<UiInput
|
||||
v-model="password"
|
||||
prefix-end="گذرواژه"
|
||||
type="password"
|
||||
password-display-type="asterisks"
|
||||
direction="ltr"
|
||||
/>
|
||||
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
class="!mt-4"
|
||||
:label="isLoading ? 'در حال ورود...' : 'تایید و ورود به حساب'"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
:loading="isLoading"
|
||||
@click="handleLogin"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
<template #footer>
|
||||
<Link method="post" class="text-center text-[13px] font-normal text-dominant-700 mt-6" :href="route('sendOtp')">
|
||||
رمز خود را فراموش کردهاید؟
|
||||
</Link>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,124 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue';
|
||||
import UiInputWithDropdown from '../../components/ui/UiInputWithDropdown.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import { countries } from '../../data/countries.js'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
import { inject } from 'vue';
|
||||
import { convertPersianToEnglish } from '../../utils/numberUtils.js'
|
||||
import { toast } from 'vue3-toastify'
|
||||
|
||||
const route = inject('route');
|
||||
|
||||
const selectedCountry = ref(countries[0])
|
||||
const phoneNumber = ref('')
|
||||
const isLoading = ref(false)
|
||||
|
||||
const handlePrefixChange = (country) => {
|
||||
selectedCountry.value = country
|
||||
}
|
||||
|
||||
const validatePhone = (phone) => {
|
||||
const phoneRegex = /^[0-9۰-۹]{10,15}$/
|
||||
return phoneRegex.test(phone.replace(/\s/g, ''))
|
||||
}
|
||||
|
||||
const handleLogin = async () => {
|
||||
if (!phoneNumber.value) {
|
||||
toast.error('لطفاً شماره موبایل را وارد کنید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!validatePhone(phoneNumber.value)) {
|
||||
toast.error('لطفاً شماره موبایل معتبر وارد کنید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
try {
|
||||
let processedPhone = convertPersianToEnglish(phoneNumber.value)
|
||||
if (processedPhone.startsWith('0')) {
|
||||
processedPhone = processedPhone.substring(1)
|
||||
}
|
||||
|
||||
Inertia.post(route('checkPhone'), {
|
||||
prefix: selectedCountry.value.prefix,
|
||||
phone: processedPhone
|
||||
}, {
|
||||
onSuccess: (page) => {
|
||||
|
||||
},
|
||||
onError: (errors) => {
|
||||
},
|
||||
onFinish: () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.phone.title') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 text-[11px] font-normal">
|
||||
{{ $t('auth.phone.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="my-6">
|
||||
<UiInputWithDropdown
|
||||
search-placeholder="Search Country Name or Phone Code ..."
|
||||
dropdown-search-input-class="!text-dominant-200 !bg-dominant-50 !border-0 !pt-3 !font-normal !text-sm"
|
||||
type="tel"
|
||||
v-model="phoneNumber"
|
||||
prefix-end="شماره موبایل"
|
||||
dropdown-direction="ltr"
|
||||
:prefix-options="countries"
|
||||
:default-prefix-value="selectedCountry.value"
|
||||
direction="ltr"
|
||||
@prefix-change="handlePrefixChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
:label="isLoading ? 'در حال بررسی...' : 'ورود و ثبتنام'"
|
||||
size="large"
|
||||
class="!mt-4"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm mt-1"
|
||||
:loading="isLoading"
|
||||
@click="handleLogin"
|
||||
/>
|
||||
</main>
|
||||
<template #footer>
|
||||
<p class="text-center text-[13px] font-normal text-dominant-500 mt-6">
|
||||
Change Language to English
|
||||
</p>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,208 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import UiInput from '../../components/ui/UiInput.vue'
|
||||
import UiInputWithDropdown from '../../components/ui/UiInputWithDropdown.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { inject } from 'vue';
|
||||
import { countries } from '../../data/countries.js'
|
||||
import { ref, onMounted } from 'vue';
|
||||
import UiSelect from '../../components/ui/UiSelect.vue';
|
||||
import provinces from '../../data/provinces.json'
|
||||
import cities from '../../data/cities.json'
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import { toast } from 'vue3-toastify';
|
||||
|
||||
const props = defineProps({
|
||||
phone: String
|
||||
})
|
||||
|
||||
const errors = ref([])
|
||||
const isLoading = ref(false)
|
||||
const route = inject('route');
|
||||
|
||||
const selectedCountry = ref(countries[0])
|
||||
|
||||
const handlePrefixChange = (country) => {
|
||||
selectedCountry.value = country
|
||||
}
|
||||
|
||||
const selectedCity = ref(null)
|
||||
const selectedProvince = ref(null)
|
||||
const citiesList = ref([])
|
||||
const provincesList = ref(provinces);
|
||||
|
||||
const formData = ref({
|
||||
fullName: '',
|
||||
nationalCode: '',
|
||||
phone: props.phone || '',
|
||||
address: '',
|
||||
province: '',
|
||||
city: '',
|
||||
address: '',
|
||||
level: 'سرپرست',
|
||||
})
|
||||
|
||||
const handleProvinceChange = (province) => {
|
||||
if (province) {
|
||||
const provinceId = province.id
|
||||
const filteredCities = cities.filter(city => city.province_id === provinceId)
|
||||
citiesList.value = filteredCities
|
||||
} else {
|
||||
citiesList.value = []
|
||||
}
|
||||
selectedCity.value = null
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
if (props.phone) {
|
||||
if (props.phone.startsWith('+')) {
|
||||
const match = countries.find(c => props.phone.startsWith(c.prefix))
|
||||
if (match) {
|
||||
selectedCountry.value = match
|
||||
formData.value.phone = props.phone.replace(match.prefix, '')
|
||||
} else {
|
||||
formData.value.phone = props.phone
|
||||
}
|
||||
} else {
|
||||
formData.value.phone = props.phone
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!selectedProvince.value) {
|
||||
toast.error('لطفاً استان را انتخاب کنید')
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedCity.value) {
|
||||
toast.error('لطفاً شهر را انتخاب کنید')
|
||||
return
|
||||
}
|
||||
if (!formData.value.nationalCode) {
|
||||
toast.error('لطفاً کد ملی را وارد کنید')
|
||||
return
|
||||
}
|
||||
isLoading.value = true
|
||||
const fullPhone = selectedCountry.value.prefix + formData.value.phone
|
||||
|
||||
const submitData = {
|
||||
fullName: formData.value.fullName,
|
||||
national_code: formData.value.nationalCode,
|
||||
phone: fullPhone,
|
||||
province: selectedProvince.value.name,
|
||||
city: selectedCity.value.name,
|
||||
address: formData.value.address,
|
||||
level: formData.value.level,
|
||||
}
|
||||
|
||||
Inertia.post(route('register.store'), submitData, {
|
||||
onSuccess: () => {
|
||||
},
|
||||
onError: (errors) => {
|
||||
errors.value = errors
|
||||
isLoading.value = false
|
||||
},
|
||||
onFinish: () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[700px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.RegisterSupervisor.title').replace('%userType%', 'سرپرستان') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.RegisterSupervisor.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 content-start items-start mt-6">
|
||||
<UiInput
|
||||
prefix-start="نام و نام خانوادگی"
|
||||
type="text"
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
v-model="formData.fullName"
|
||||
/>
|
||||
<UiInput
|
||||
prefix-end="کد ملی"
|
||||
type="text"
|
||||
convert-persian-numbers
|
||||
direction="ltr"
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
custom-class="!font-yekanBakh !text-sm"
|
||||
v-model="formData.nationalCode"
|
||||
:error="errors.national_code"
|
||||
/>
|
||||
<UiInputWithDropdown
|
||||
search-placeholder="Search Country Name or Phone Code ..."
|
||||
dropdown-search-input-class="!text-dominant-200 !bg-dominant-50 !border-0 !pt-3 !font-normal !text-sm"
|
||||
type="tel"
|
||||
class="!my-0 !col-span-2"
|
||||
prefix-end="شماره موبایل"
|
||||
dropdown-direction="ltr"
|
||||
:prefix-options="countries"
|
||||
:default-prefix-value="selectedCountry.value"
|
||||
direction="ltr"
|
||||
v-model="formData.phone"
|
||||
@prefix-change="handlePrefixChange"
|
||||
/>
|
||||
<UiSelect
|
||||
v-model="selectedProvince"
|
||||
:options="provincesList"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
prefix-start="استان"
|
||||
:filter="true"
|
||||
filter-placeholder="جستجو در استانها..."
|
||||
:show-clear="false"
|
||||
class="!my-0 max-sm:col-span-2"
|
||||
@change="handleProvinceChange"
|
||||
/>
|
||||
<UiSelect
|
||||
v-model="selectedCity"
|
||||
:options="citiesList"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
prefix-start="شهر"
|
||||
:filter="true"
|
||||
class="!my-0 max-sm:col-span-2"
|
||||
filter-placeholder="جستجو در شهرها..."
|
||||
:show-clear="false"
|
||||
/>
|
||||
|
||||
<UiInput
|
||||
prefix-start="آدرس"
|
||||
type="text"
|
||||
class="!my-0 col-span-2"
|
||||
v-model="formData.address"
|
||||
/>
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
:label="isLoading ? 'در حال ثبت...' : 'تایید اطلاعات و ثبتنام'"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
class="col-span-2 mt-4 max-sm:!mt-0"
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm"
|
||||
:loading="isLoading"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
<template #footer>
|
||||
<Link class="text-center text-[13px] font-normal text-dominant-700 mt-6" :href="route('register.chooseType')">
|
||||
بازگشت
|
||||
</Link>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,253 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import UiInput from '../../components/ui/UiInput.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import provinces from '../../data/provinces.json'
|
||||
import cities from '../../data/cities.json'
|
||||
import UiInputWithDropdown from '../../components/ui/UiInputWithDropdown.vue';
|
||||
import UiSelect from '../../components/ui/UiSelect.vue';
|
||||
import { inject } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { countries } from '../../data/countries.js'
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import { toast } from 'vue3-toastify';
|
||||
|
||||
const props = defineProps({
|
||||
phone: String
|
||||
})
|
||||
|
||||
const route = inject('route');
|
||||
|
||||
const selectedCountry = ref(countries[0])
|
||||
const handlePrefixChange = (country) => {
|
||||
selectedCountry.value = country
|
||||
}
|
||||
|
||||
const selectedSpecialty = ref(null)
|
||||
const selectedCity = ref(null)
|
||||
const selectedProvince = ref(null)
|
||||
const citiesList = ref([])
|
||||
const provincesList = ref(provinces)
|
||||
const specialtiesList = ref([
|
||||
{ id: 1, name: 'جراح عمومی' },
|
||||
{ id: 2, name: 'جراح حیوانات' },
|
||||
{ id: 3, name: 'جراح حیوانات و طبیعت' }
|
||||
])
|
||||
|
||||
const formData = ref({
|
||||
fullName: '',
|
||||
nationalCode: '',
|
||||
phone: props.phone || '',
|
||||
clinicName: '',
|
||||
clinicPhone: '',
|
||||
address: '',
|
||||
specialty: '',
|
||||
province: '',
|
||||
city: '',
|
||||
address: '',
|
||||
level: 'دانپزشک',
|
||||
})
|
||||
|
||||
const errors = ref({})
|
||||
const isLoading = ref(false)
|
||||
|
||||
const handleProvinceChange = (province) => {
|
||||
if (province) {
|
||||
const provinceId = province.id
|
||||
const filteredCities = cities.filter(city => city.province_id === provinceId)
|
||||
citiesList.value = filteredCities
|
||||
} else {
|
||||
citiesList.value = []
|
||||
}
|
||||
selectedCity.value = null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.phone) {
|
||||
if (props.phone.startsWith('+')) {
|
||||
const match = countries.find(c => props.phone.startsWith(c.prefix))
|
||||
if (match) {
|
||||
selectedCountry.value = match
|
||||
formData.value.phone = props.phone.replace(match.prefix, '')
|
||||
} else {
|
||||
formData.value.phone = props.phone
|
||||
}
|
||||
} else {
|
||||
formData.value.phone = props.phone
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!selectedSpecialty.value) {
|
||||
toast.error('لطفاً تخصص را انتخاب کنید')
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedProvince.value) {
|
||||
toast.error('لطفاً استان را انتخاب کنید')
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedCity.value) {
|
||||
toast.error('لطفاً شهر را انتخاب کنید')
|
||||
return
|
||||
}
|
||||
if (!formData.value.nationalCode) {
|
||||
toast.error('لطفاً کد ملی را وارد کنید')
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
const fullPhone = selectedCountry.value.prefix + formData.value.phone
|
||||
|
||||
const submitData = {
|
||||
fullName: formData.value.fullName,
|
||||
national_code: formData.value.nationalCode,
|
||||
specialty: selectedSpecialty.value.name,
|
||||
phone: fullPhone,
|
||||
clinic_name: formData.value.clinicName,
|
||||
clinic_phone: formData.value.clinicPhone,
|
||||
province: selectedProvince.value.name,
|
||||
city: selectedCity.value.name,
|
||||
address: formData.value.address,
|
||||
level: 'دانپزشک'
|
||||
}
|
||||
|
||||
Inertia.post(route('register.store'), submitData, {
|
||||
onSuccess: () => {
|
||||
},
|
||||
onError: (errors) => {
|
||||
errors.value = errors
|
||||
isLoading.value = false
|
||||
},
|
||||
onFinish: () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[700px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.RegisterVet.title').replace('%userType%', 'پزشکان') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.RegisterVet.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-2 content-start items-start mt-6">
|
||||
<UiInput
|
||||
prefix-start="نام و نام خانوادگی"
|
||||
type="text"
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
v-model="formData.fullName"
|
||||
:error="errors.first_name"
|
||||
/>
|
||||
<UiInput
|
||||
prefix-end="کد ملی"
|
||||
type="text"
|
||||
convert-persian-numbers
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
direction="ltr"
|
||||
custom-class="!font-yekanBakh !text-sm"
|
||||
v-model="formData.nationalCode"
|
||||
:error="errors.national_code"
|
||||
/>
|
||||
<UiSelect
|
||||
v-model="selectedSpecialty"
|
||||
:options="specialtiesList"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
prefix-start="تخصص"
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
:filter="true"
|
||||
filter-placeholder="جستجو در تخصصها..."
|
||||
:show-clear="false"
|
||||
/>
|
||||
<UiInputWithDropdown
|
||||
search-placeholder="Search Country Name or Phone Code ..."
|
||||
dropdown-search-input-class="!text-dominant-200 !bg-dominant-50 !border-0 !pt-3 !font-normal !text-sm"
|
||||
type="tel"
|
||||
class="!my-0 max-sm:!col-span-2"
|
||||
prefix-end="شماره موبایل"
|
||||
dropdown-direction="ltr"
|
||||
v-model="formData.phone"
|
||||
:prefix-options="countries"
|
||||
:default-prefix-value="selectedCountry.value"
|
||||
direction="ltr"
|
||||
@prefix-change="handlePrefixChange"
|
||||
/>
|
||||
<UiInput
|
||||
prefix-start="نام کلینیک"
|
||||
class="!mb-0 max-sm:!col-span-2"
|
||||
type="text"
|
||||
custom-class="!font-yekanBakh !text-sm"
|
||||
v-model="formData.clinicName"
|
||||
/>
|
||||
<UiInput
|
||||
prefix-end="تلفن کلینیک"
|
||||
type="text"
|
||||
direction="ltr"
|
||||
class="!mb-0 max-sm:!col-span-2"
|
||||
convert-persian-numbers
|
||||
v-model="formData.clinicPhone"
|
||||
/>
|
||||
<UiSelect
|
||||
v-model="selectedProvince"
|
||||
:options="provincesList"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
prefix-start="استان"
|
||||
:filter="true"
|
||||
filter-placeholder="جستجو در استانها..."
|
||||
:show-clear="false"
|
||||
class="!my-0"
|
||||
@change="handleProvinceChange"
|
||||
/>
|
||||
<UiSelect
|
||||
v-model="selectedCity"
|
||||
:options="citiesList"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
prefix-start="شهر"
|
||||
class="!my-0 "
|
||||
:filter="true"
|
||||
filter-placeholder="جستجو در شهرها..."
|
||||
:show-clear="false"
|
||||
/>
|
||||
|
||||
<UiInput
|
||||
prefix-start="آدرس"
|
||||
type="text"
|
||||
class="col-span-2 !mb-0"
|
||||
v-model="formData.address"
|
||||
/>
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
:label="isLoading ? 'در حال ثبت...' : 'تایید اطلاعات و ثبتنام'"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
class="col-span-2 mt-4 max-sm:!mt-0"
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm"
|
||||
:loading="isLoading"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
<template #footer>
|
||||
<Link class="text-center text-[13px] font-normal text-dominant-700 mt-6" :href="route('register.chooseType')">
|
||||
بازگشت
|
||||
</Link>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup>
|
||||
import AuthLayout from '../../layouts/AuthLayout.vue'
|
||||
import UiButton from '../../components/ui/UiButton.vue'
|
||||
import UiInput from '../../components/ui/UiInput.vue'
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import { ref } from 'vue';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import { inject } from 'vue';
|
||||
import { toast } from 'vue3-toastify';
|
||||
const route = inject('route');
|
||||
const isLoading = ref(false);
|
||||
const password = ref('');
|
||||
const confirmPassword = ref('');
|
||||
|
||||
const updatePassword = () => {
|
||||
if (!password.value) {
|
||||
toast.error('لطفاً گذرواژه را وارد کنید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!confirmPassword.value) {
|
||||
toast.error('لطفاً تکرار گذرواژه را وارد کنید', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (password.value !== confirmPassword.value) {
|
||||
toast.error('گذرواژه و تکرار گذرواژه مطابقت ندارند', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
return
|
||||
}
|
||||
isLoading.value = true
|
||||
Inertia.post(route('updatePassword'), { password: password.value, password_confirmation: confirmPassword.value }, {
|
||||
onError: (errors) => {
|
||||
toast.error(errors.password || 'خطا در تغییر گذرواژه', {
|
||||
position: 'top-right',
|
||||
rtl: true,
|
||||
theme: 'colored',
|
||||
autoClose: 3000,
|
||||
})
|
||||
},
|
||||
onFinish: () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AuthLayout>
|
||||
<main class="p-9 h-auto w-[450px] max-sm:w-[90%] m-auto bg-white rounded-xl">
|
||||
<div class="grid grid-cols-a justify-start">
|
||||
<h1 class="text-[16px] font-semibold !text-dominant-800">
|
||||
{{ $t('auth.ResetPassword.title').replace('%userType%', 'پزشکان') }}
|
||||
</h1>
|
||||
<p class="!text-dominant-800 mt-1 text-[11px] font-normal">
|
||||
{{ $t('auth.ResetPassword.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex content-start flex-col mt-6">
|
||||
<UiInput
|
||||
prefix-end="گذرواژه"
|
||||
type="password"
|
||||
password-display-type="asterisks"
|
||||
direction="ltr"
|
||||
class="!mb-2"
|
||||
v-model="password"
|
||||
/>
|
||||
<UiInput
|
||||
prefix-end="تکرار گذرواژه"
|
||||
type="password"
|
||||
password-display-type="asterisks"
|
||||
direction="ltr"
|
||||
v-model="confirmPassword"
|
||||
/>
|
||||
<UiButton
|
||||
severity="dominant"
|
||||
class="!mt-4"
|
||||
label="تایید و بازیابی گذرواژه"
|
||||
size="large"
|
||||
full-width
|
||||
outlined
|
||||
height="40px"
|
||||
icon-position="start"
|
||||
icon-class="!text-sm"
|
||||
:loading="isLoading"
|
||||
@click="updatePassword"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
<template #footer>
|
||||
<Link :href="route('login')" class="text-center text-[13px] font-normal text-dominant-700 mt-6">
|
||||
بازگشت به صفحه ورود
|
||||
</Link>
|
||||
</template>
|
||||
</AuthLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user