feat: add withdraw request functionality and UI components
This commit is contained in:
@@ -1,18 +1,24 @@
|
||||
<script setup>
|
||||
import { Link } from '@inertiajs/inertia-vue3'
|
||||
import ActivityCard from './ActivityCard.vue'
|
||||
import { formatPrice } from '../../utils/numberUtils'
|
||||
|
||||
const props = defineProps({
|
||||
stats: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="grid grid-cols-4 max-lg:grid-cols-2 max-sm:grid-cols-1 gap-4">
|
||||
<ActivityCard title="کیس در انتظار بررسی"
|
||||
:count="5" link="/dashboard/doctor/cases" label-link="مشاهده و بررسی" />
|
||||
:count="stats.pending_cases" link="/dashboard/cases" label-link="مشاهده و بررسی" />
|
||||
<ActivityCard title="کیس بررسی شده در ماه"
|
||||
:count="999" link="/dashboard/doctor/cases" label-link="مشاهده گزارشات کیسها" />
|
||||
<ActivityCard title="تومان درآمد"
|
||||
:count="formatPrice(50000000)" link="/dashboard/doctor/cases" label-link="مشاهده گزارشات مالی " />
|
||||
<ActivityCard title="ساعت تا شیت بعدی"
|
||||
:count="4" link="/dashboard/doctor/cases" label-link="مشاهده شیفتها" />
|
||||
:count="stats.monthly_reviewed" link="/dashboard/reports" label-link="مشاهده گزارشات کیسها" />
|
||||
<ActivityCard :title="stats.is_doctor ? 'تومان درآمد' : 'تومان هزینه در ماه'"
|
||||
:count="formatPrice(stats.monthly_amount)" :link="stats.is_doctor ? '/dashboard/wallet' : '/dashboard/invoices'" label-link="مشاهده گزارشات مالی" />
|
||||
<ActivityCard v-if="stats.next_shift_hours !== null" title="ساعت تا شیفت بعدی"
|
||||
:count="stats.next_shift_hours" link="/dashboard/shifts" label-link="مشاهده شیفتها" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -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>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import UiButton from '../../components/ui/UiButton.vue';
|
||||
import { computed, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import ProgressBar from 'primevue/progressbar';
|
||||
import { toast } from 'vue3-toastify';
|
||||
@@ -9,11 +9,15 @@ import RequestCase from './fastRequest/RequestCase.vue';
|
||||
import RequestDetails from './fastRequest/RequestDetails.vue';
|
||||
import RequestDoctor from './fastRequest/RequestDoctor.vue';
|
||||
import RequestReview from './fastRequest/RequestReview.vue';
|
||||
import InvoiceModal from './fastRequest/InvoiceModal.vue';
|
||||
import { useFastRequestStore } from '../../store/FastRequest';
|
||||
|
||||
const visible = defineModel('visible');
|
||||
const fastRequestStore = useFastRequestStore();
|
||||
|
||||
const invoiceVisible = ref(false);
|
||||
const invoiceDocument = ref(null);
|
||||
|
||||
const steps = [
|
||||
{ label: 'نوع درخواست', component: RequestType },
|
||||
{ label: 'انتخاب کیس', component: RequestCase },
|
||||
@@ -49,8 +53,9 @@ const handleNext = async () => {
|
||||
|
||||
try {
|
||||
const document = await fastRequestStore.submit();
|
||||
toast.success(`درخواست شما با شماره پرونده ${document.code} با موفقیت ثبت شد.`);
|
||||
invoiceDocument.value = document;
|
||||
visible.value = false;
|
||||
invoiceVisible.value = true;
|
||||
} catch (error) {
|
||||
toast.error(error.response?.data?.message || 'خطا در ثبت درخواست. لطفا دوباره تلاش کنید.');
|
||||
}
|
||||
@@ -93,4 +98,5 @@ const handleNext = async () => {
|
||||
/>
|
||||
</div>
|
||||
</Dialog>
|
||||
<invoice-modal v-model:visible="invoiceVisible" :document="invoiceDocument"></invoice-modal>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import UiButton from '../ui/UiButton.vue';
|
||||
import PaymentSuccessSvg from '../svg/paymentSuccess.svg';
|
||||
import PaymentFailedSvg from '../svg/paymentFailed.svg';
|
||||
|
||||
const visible = defineModel('visible');
|
||||
|
||||
const props = defineProps({
|
||||
result: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const isPaid = computed(() => props.result?.status === 'paid');
|
||||
|
||||
const isWalletTopUp = computed(() => props.result?.purpose === 'WalletTopUp');
|
||||
|
||||
const closeModal = () => {
|
||||
visible.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">
|
||||
<div v-if="result" class="w-full flex flex-col items-center justify-center gap-2 py-6">
|
||||
<component :is="isPaid ? PaymentSuccessSvg : PaymentFailedSvg" class="w-[180px] h-[150px]" />
|
||||
<h2 class="text-[15px] font-[700] text-[#3E4C63] mt-2">
|
||||
<template v-if="isPaid">{{ isWalletTopUp ? 'کیف پول شما با موفقیت شارژ شد.' : 'پرداخت شما با موفقیت انجام شد.' }}</template>
|
||||
<template v-else>متاسفانه پرداخت شما با خطا روبهرو شده است.</template>
|
||||
</h2>
|
||||
<p class="max-w-[480px] text-center text-[13px] font-[400] text-[#576989] leading-7">
|
||||
<template v-if="isPaid && isWalletTopUp">مبلغ پرداختی به موجودی کیف پول شما اضافه شد و میتوانید از آن برای پرداخت فاکتورها استفاده کنید.</template>
|
||||
<template v-else-if="isPaid">کارشناسان پرداخت و درخواست شما را به زودی بررسی خواهند کرد.</template>
|
||||
<template v-else>لطفا دوباره نسبت به پرداخت اقدام نمایید. در صورتیکه مبلغ از حساب شما کسر شده و یا فکر میکنید اشتباهی رخ داده است، با کارشناسان ما در تماس باشید.</template>
|
||||
</p>
|
||||
<p class="text-[13px] font-[700] text-[#3E4C63] mt-2">شماره پیگیری: {{ result.track_id }}</p>
|
||||
<div class="flex items-center justify-center gap-2 mt-4">
|
||||
<ui-button label="بازگشت به داشبورد" severity="success" size="small" @click="closeModal" />
|
||||
<ui-button v-if="!isPaid" label="تماس با پشتیبانی" severity="secondary" size="small" @click="closeModal" />
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
rows: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="bg-white border border-complement-50 rounded-2xl p-4">
|
||||
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
|
||||
{{ title }}
|
||||
</h2>
|
||||
<ul class="mt-3 flex flex-col gap-2">
|
||||
<li v-for="row in rows" :key="row.label" class="flex items-start gap-2 text-[11px]">
|
||||
<span class="font-normal text-[#576989]">{{ row.label }}:</span>
|
||||
<span class="font-semibold text-[#3E4C63]">{{ row.value ?? '-' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup>
|
||||
const value = defineModel({ type: String, default: '' })
|
||||
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
editable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
error: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
|
||||
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
|
||||
{{ title }}
|
||||
</h2>
|
||||
<textarea
|
||||
v-if="editable"
|
||||
v-model="value"
|
||||
rows="6"
|
||||
:placeholder="placeholder"
|
||||
class="w-full bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#3E4C63] leading-6 outline-none focus:border-[#C1D0E8] resize-y"
|
||||
></textarea>
|
||||
<div v-else class="w-full min-h-[7rem] bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#3E4C63] leading-6 whitespace-pre-line">
|
||||
{{ value || 'موردی ثبت نشده است.' }}
|
||||
</div>
|
||||
<p v-if="error" class="text-[11px] text-[#7A1419]">{{ error }}</p>
|
||||
</section>
|
||||
</template>
|
||||
@@ -1,8 +1,12 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import { usePage } from '@inertiajs/inertia-vue3';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import UiButton from '../../ui/UiButton.vue';
|
||||
import { toast } from 'vue3-toastify';
|
||||
import { modalityTitle } from '../../../data/fastRequestOptions';
|
||||
import { formatPrice } from '../../../utils/numberUtils';
|
||||
|
||||
const visible = defineModel('visible');
|
||||
|
||||
@@ -10,31 +14,69 @@ const props = defineProps({
|
||||
document: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
invoice: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const formattedAmount = computed(() => {
|
||||
return Number(props.document?.invoice?.amount || 0).toLocaleString('fa-IR');
|
||||
});
|
||||
const { props: pageProps } = usePage();
|
||||
|
||||
const handlePay = () => {
|
||||
visible.value = false;
|
||||
const paying = ref(false);
|
||||
const payingWithWallet = ref(false);
|
||||
|
||||
const currentInvoice = computed(() => props.invoice ?? props.document?.invoice ?? null);
|
||||
|
||||
const formattedAmount = computed(() => formatPrice(currentInvoice.value?.amount || 0));
|
||||
|
||||
const walletBalance = computed(() => Number(pageProps.value.auth?.wallet_balance || 0));
|
||||
|
||||
const formattedWalletBalance = computed(() => formatPrice(walletBalance.value));
|
||||
|
||||
const hasEnoughBalance = computed(() => walletBalance.value >= Number(currentInvoice.value?.amount || 0));
|
||||
|
||||
const handlePay = async () => {
|
||||
paying.value = true;
|
||||
try {
|
||||
const { data } = await window.axios.post('/dashboard/payments', { invoice_id: currentInvoice.value.id });
|
||||
window.location.href = data.url;
|
||||
} catch (error) {
|
||||
paying.value = false;
|
||||
toast.error(error.response?.data?.message || 'خطا در اتصال به درگاه پرداخت. لطفا دوباره تلاش کنید.');
|
||||
}
|
||||
}
|
||||
|
||||
const handleWalletPay = async () => {
|
||||
payingWithWallet.value = true;
|
||||
try {
|
||||
await window.axios.post(`/dashboard/invoices/${currentInvoice.value.id}/pay-wallet`);
|
||||
toast.success('فاکتور با موفقیت از کیف پول پرداخت شد.');
|
||||
visible.value = false;
|
||||
Inertia.reload();
|
||||
} catch (error) {
|
||||
toast.error(error.response?.data?.message || 'خطا در پرداخت از کیف پول. لطفا دوباره تلاش کنید.');
|
||||
} finally {
|
||||
payingWithWallet.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:visible="visible" :modal="true" :closable="true" :dismissableMask="false" :maximizable="false" :style="{ width: '1032px' }">
|
||||
<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>
|
||||
<h2 class="text-[14px] font-[700] text-[#576989]">فاکتور پرداخت «{{ document?.invoice?.number }}»</h2>
|
||||
<div class="w-full flex items-center justify-start">
|
||||
<h2 class="text-[14px] font-[700] text-[#576989]">فاکتور پرداخت «{{ currentInvoice?.number }}»</h2>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="document" class="w-full flex flex-col gap-4 border-t border-[#EBEBEB] pt-4">
|
||||
<div class="w-full flex items-center gap-3 bg-[#EEF2F8] border border-[#DEE3EB] rounded-[12px] px-4 py-4">
|
||||
<i class="fi-rr-info text-[20px] text-[#576989]"></i>
|
||||
<p class="text-[13px] font-[400] text-[#3E4C63]">
|
||||
<div v-if="currentInvoice" class="w-full flex flex-col gap-4 border-t border-[#EBEBEB] pt-4">
|
||||
<div class="w-full flex items-center gap-3 bg-[#EEF2F8] border border-[#DEE3EB] rounded-[12px] px-4 py-3">
|
||||
<i class="fi-rr-info text-[18px] text-[#576989]"></i>
|
||||
<p class="text-[12px] font-[400] text-[#3E4C63] leading-6">
|
||||
یک فاکتور به مبلغ « <span class="font-[700]">{{ formattedAmount }} تومان</span> » برای شما ایجاد شد. لطفا جهت ادامه مراحل درخواست نسبت به پرداخت اقدام نمایید.
|
||||
</p>
|
||||
</div>
|
||||
<p class="text-[13px] font-[400] text-[#3E4C63] leading-7">
|
||||
<p v-if="document" class="text-[13px] font-[400] text-[#3E4C63] leading-7">
|
||||
این فاکتور جهت پردازش درخواست
|
||||
<span class="font-[600] text-[#7A1419]">(({{ modalityTitle(document.modality) }}))</span>
|
||||
به شناسه
|
||||
@@ -48,9 +90,14 @@ const handlePay = () => {
|
||||
<br>
|
||||
بدیهیست که در صورت عدم تایید کارشناسان مبلغ مربوطه به کیف پول شما بازگردانده خواهد شد.
|
||||
</p>
|
||||
<p class="text-[12px] font-[400] text-[#576989]">
|
||||
موجودی کیف پول شما: <span class="font-[700] text-[#3E4C63]">{{ formattedWalletBalance }} تومان</span>
|
||||
<span v-if="!hasEnoughBalance" class="text-[#7A1419]"> (موجودی کیف پول کافی نیست)</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-full pt-3 flex items-center justify-start border-t border-[#EBEBEB]">
|
||||
<ui-button label="تایید و پرداخت" severity="success" size="small" @click="handlePay" />
|
||||
<div class="w-full pt-3 flex items-center justify-start gap-2 border-t border-[#EBEBEB]">
|
||||
<ui-button label="پرداخت با کیف پول" severity="primary" size="small" :loading="payingWithWallet" :disabled="payingWithWallet || paying || !hasEnoughBalance" @click="handleWalletPay" />
|
||||
<ui-button label="پرداخت از طریق درگاه" severity="success" size="small" :loading="paying" :disabled="paying || payingWithWallet" @click="handlePay" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useForm, usePage } from '@inertiajs/inertia-vue3';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import { toast } from 'vue3-toastify';
|
||||
import UiCard from '../../ui/UiCard.vue';
|
||||
import UiInput from '../../ui/UiInput.vue';
|
||||
import UiButton from '../../ui/UiButton.vue';
|
||||
import { convertEnglishToPersian, convertPersianToEnglish, formatPrice } from '../../../utils/numberUtils';
|
||||
|
||||
const props = defineProps({
|
||||
bankCards: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const { props: pageProps } = usePage();
|
||||
|
||||
const walletBalance = computed(() => Number(pageProps.value.auth?.wallet_balance || 0));
|
||||
|
||||
const amount = ref('');
|
||||
const selectedCardId = ref(props.bankCards[0]?.id ?? null);
|
||||
|
||||
const numericAmount = computed(() => Number(convertPersianToEnglish(amount.value).replace(/\D/g, '')) || 0);
|
||||
|
||||
const formatCardNumber = (cardNumber) => convertEnglishToPersian(cardNumber.replace(/(\d{4})(?=\d)/g, '$1 - '));
|
||||
|
||||
const selectFullBalance = () => {
|
||||
amount.value = String(walletBalance.value);
|
||||
};
|
||||
|
||||
const withdrawForm = useForm({
|
||||
amount: null,
|
||||
bank_card_id: null,
|
||||
});
|
||||
|
||||
const submitWithdraw = () => {
|
||||
if (numericAmount.value < 10000) {
|
||||
toast.error('حداقل مبلغ برداشت ۱۰٬۰۰۰ تومان است.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedCardId.value) {
|
||||
toast.error('لطفا کارت بانکی مقصد را انتخاب کنید.');
|
||||
return;
|
||||
}
|
||||
|
||||
withdrawForm.amount = numericAmount.value;
|
||||
withdrawForm.bank_card_id = selectedCardId.value;
|
||||
|
||||
withdrawForm.post('/dashboard/wallet/withdraw-requests', {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
amount.value = '';
|
||||
toast.success('درخواست برداشت شما ثبت شد و در انتظار بررسی است.');
|
||||
},
|
||||
onError: (errors) => toast.error(Object.values(errors)[0] || 'خطا در ثبت درخواست برداشت.'),
|
||||
});
|
||||
};
|
||||
|
||||
const cardModalVisible = ref(false);
|
||||
|
||||
const cardForm = useForm({
|
||||
card_number: '',
|
||||
holder_name: '',
|
||||
});
|
||||
|
||||
const submitCard = () => {
|
||||
cardForm.card_number = convertPersianToEnglish(cardForm.card_number).replace(/\D/g, '');
|
||||
|
||||
cardForm.post('/dashboard/wallet/bank-cards', {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
cardForm.reset();
|
||||
cardModalVisible.value = false;
|
||||
toast.success('کارت بانکی با موفقیت ثبت شد.');
|
||||
},
|
||||
onError: (errors) => toast.error(Object.values(errors)[0] || 'خطا در ثبت کارت بانکی.'),
|
||||
});
|
||||
};
|
||||
|
||||
const deleteCard = (card) => {
|
||||
Inertia.delete(`/dashboard/wallet/bank-cards/${card.id}`, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
if (selectedCardId.value === card.id) {
|
||||
selectedCardId.value = null;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiCard title="درخواست برداشت" variant="default">
|
||||
<div class="grid grid-cols-2 max-lg:grid-cols-1 gap-6 items-start">
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-[11px] font-normal text-[#576989] leading-6">
|
||||
مبلغ مورد نظر پس از بررسی و تایید توسط کارشناسان، از کیف پول شما کسر و به کارت انتخابی واریز میشود.
|
||||
</p>
|
||||
<div class="flex items-end gap-3 max-sm:flex-col max-sm:items-stretch">
|
||||
<UiInput
|
||||
v-model="amount"
|
||||
label="مبلغ برداشت"
|
||||
placeholder="مبلغ مورد نظر را به تومان وارد کنید"
|
||||
prefixEnd="تومان"
|
||||
prefixClasses="!border-dominant-50"
|
||||
class="!w-full"
|
||||
customClass="!border-dominant-50 !font-normal !text-[12px]"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<button
|
||||
type="button"
|
||||
class="text-[11px] font-normal text-[#576989] bg-[#F5F7FA] border border-[#DEE3EB] rounded-lg px-3 py-1.5 hover:bg-[#EEF2F8]"
|
||||
@click="selectFullBalance"
|
||||
>
|
||||
کل موجودی ({{ formatPrice(walletBalance) }} تومان)
|
||||
</button>
|
||||
</div>
|
||||
<UiButton
|
||||
label="ثبت درخواست برداشت"
|
||||
severity="success"
|
||||
size="small"
|
||||
class="self-start"
|
||||
:loading="withdrawForm.processing"
|
||||
:disabled="withdrawForm.processing"
|
||||
@click="submitWithdraw"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-[11px] font-semibold text-[#3E4C63]">کارت بانکی مقصد</span>
|
||||
<button type="button" class="text-[11px] font-semibold text-[#365891]" @click="cardModalVisible = true">
|
||||
+ افزودن کارت
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="!bankCards.length" class="bg-[#F8FAFC] border border-dashed border-[#C1D0E8] rounded-xl p-4 text-[11px] font-normal text-[#576989] text-center leading-6">
|
||||
هنوز کارتی ثبت نکردهاید. برای ثبت درخواست برداشت ابتدا یک کارت بانکی اضافه کنید.
|
||||
</p>
|
||||
<label
|
||||
v-for="card in bankCards"
|
||||
:key="card.id"
|
||||
class="flex items-center gap-3 border rounded-xl px-4 py-3 cursor-pointer transition-colors"
|
||||
:class="selectedCardId === card.id ? 'border-[#365891] bg-[#EEF2F8]' : 'border-[#DEE3EB] bg-white hover:bg-[#F8FAFC]'"
|
||||
>
|
||||
<input
|
||||
v-model="selectedCardId"
|
||||
type="radio"
|
||||
name="bank_card"
|
||||
:value="card.id"
|
||||
class="accent-[#365891]"
|
||||
/>
|
||||
<span class="flex flex-col gap-1 flex-1">
|
||||
<span class="text-[12px] font-semibold text-[#3E4C63]" dir="ltr">{{ formatCardNumber(card.card_number) }}</span>
|
||||
<span class="text-[11px] font-normal text-[#576989]">{{ card.holder_name }}</span>
|
||||
</span>
|
||||
<button type="button" class="text-[11px] font-semibold text-[#7A1419]" @click.prevent="deleteCard(card)">حذف</button>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog v-model:visible="cardModalVisible" :modal="true" :closable="true" :dismissableMask="false" :style="{ width: '420px' }" 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>
|
||||
<div class="w-full flex flex-col gap-4 border-t border-[#EBEBEB] pt-4">
|
||||
<UiInput
|
||||
v-model="cardForm.card_number"
|
||||
label="شماره کارت"
|
||||
placeholder="شماره کارت ۱۶ رقمی"
|
||||
maxlength="16"
|
||||
customClass="!border-dominant-50 !font-normal !text-[12px]"
|
||||
/>
|
||||
<UiInput
|
||||
v-model="cardForm.holder_name"
|
||||
label="نام صاحب حساب"
|
||||
placeholder="نام و نام خانوادگی صاحب کارت"
|
||||
customClass="!border-dominant-50 !font-normal !text-[12px]"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-full pt-4 flex items-center justify-start gap-2 border-t border-[#EBEBEB] mt-4">
|
||||
<UiButton label="ثبت کارت" severity="success" size="small" :loading="cardForm.processing" :disabled="cardForm.processing" @click="submitCard" />
|
||||
<UiButton label="انصراف" severity="secondary" size="small" :disabled="cardForm.processing" @click="cardModalVisible = false" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</UiCard>
|
||||
</template>
|
||||
@@ -1,14 +1,47 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { Link, usePage } from '@inertiajs/inertia-vue3';
|
||||
import { useGlobalStore } from '../../store/Global';
|
||||
import UiInput from '../ui/UiInput.vue';
|
||||
import ArrowDownSvg from '../svg/arrowDown.svg';
|
||||
import GlobalSvg from '../svg/global.svg';
|
||||
import EditProfileModal from '../dashboard/EditProfileModal.vue';
|
||||
import { formatPrice } from '../../utils/numberUtils';
|
||||
const globalStore = useGlobalStore();
|
||||
const { props } = usePage();
|
||||
|
||||
const walletBalance = computed(() => formatPrice(props.value.auth?.wallet_balance || 0));
|
||||
|
||||
const toggleSidebar = () => {
|
||||
globalStore.sidebarOpen = !globalStore.sidebarOpen;
|
||||
};
|
||||
|
||||
const userMenuOpen = ref(false);
|
||||
const userMenuRef = ref(null);
|
||||
const editProfileVisible = ref(false);
|
||||
|
||||
const toggleUserMenu = () => {
|
||||
userMenuOpen.value = !userMenuOpen.value;
|
||||
};
|
||||
|
||||
const openEditProfile = () => {
|
||||
userMenuOpen.value = false;
|
||||
editProfileVisible.value = true;
|
||||
};
|
||||
|
||||
const closeOnClickOutside = (event) => {
|
||||
if (userMenuRef.value && !userMenuRef.value.contains(event.target)) {
|
||||
userMenuOpen.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => document.addEventListener('click', closeOnClickOutside));
|
||||
onBeforeUnmount(() => document.removeEventListener('click', closeOnClickOutside));
|
||||
|
||||
const menuItems = [
|
||||
{ label: 'کیف پول', icon: 'fi-rr-wallet', href: '/dashboard/wallet' },
|
||||
{ label: 'فاکتورها', icon: 'fi-rr-receipt', href: '/dashboard/invoices' },
|
||||
{ label: 'برنامه شیفتها', icon: 'fi-rr-calendar-clock', href: '/dashboard/shifts' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -39,17 +72,63 @@ const toggleSidebar = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<Link href="/dashboard/wallet" class="flex items-center gap-2.5 rounded-lg bg-dominant-light border border-dominant-50 ps-1.5 pe-3 py-1.5 transition-colors hover:border-dominant-100">
|
||||
<span class="flex items-center justify-center w-8 h-8 rounded-lg bg-white border border-dominant-50 text-dominant-400">
|
||||
<i class="fi fi-rr-wallet flex text-[15px]"></i>
|
||||
</span>
|
||||
<span class="flex flex-col max-sm:hidden">
|
||||
<span class="text-[10px] font-normal text-dominant-200">موجودی کیف پول</span>
|
||||
<span class="text-[12px] font-bold text-dominant-500">{{ walletBalance }} <span class="text-[10px] font-normal text-dominant-300">تومان</span></span>
|
||||
</span>
|
||||
</Link>
|
||||
<div class="flex items-center justify-center border-l-[1px] !border-dominant-50 pl-4">
|
||||
<GlobalSvg />
|
||||
</div>
|
||||
<div class="grid grid-cols-2a justify-start items-center gap-2">
|
||||
<span class="text-dominant-300 text-[12px] font-normal">
|
||||
{{ globalStore.current_user.fullname }}
|
||||
</span>
|
||||
<ArrowDownSvg class="!w-4 !h-4 flex -mt-0.5"/>
|
||||
<div ref="userMenuRef" class="relative">
|
||||
<button type="button" class="flex items-center gap-2 cursor-pointer" @click="toggleUserMenu">
|
||||
<span class="flex items-center justify-center w-9 h-9 rounded-full bg-dominant-light border border-dominant-50 overflow-hidden">
|
||||
<img v-if="globalStore.current_user.profile_url" :src="globalStore.current_user.profile_url" alt="تصویر پروفایل" class="w-full h-full object-cover" />
|
||||
<i v-else class="fi fi-rr-user flex text-sm text-dominant-300"></i>
|
||||
</span>
|
||||
<span class="text-dominant-300 text-[12px] font-normal max-sm:hidden">
|
||||
{{ globalStore.current_user.fullname }}
|
||||
</span>
|
||||
<i class="fi fi-rr-angle-small-down flex text-sm text-dominant-300 transition-transform duration-200" :class="{ 'rotate-180': userMenuOpen }"></i>
|
||||
</button>
|
||||
<Transition
|
||||
enter-active-class="transition duration-150 ease-out"
|
||||
enter-from-class="opacity-0 -translate-y-1"
|
||||
enter-to-class="opacity-100 translate-y-0"
|
||||
leave-active-class="transition duration-100 ease-in"
|
||||
leave-from-class="opacity-100 translate-y-0"
|
||||
leave-to-class="opacity-0 -translate-y-1"
|
||||
>
|
||||
<nav v-if="userMenuOpen" class="absolute left-0 top-full mt-2 w-52 rounded-xl bg-white border border-complement-100 shadow-all py-2 z-30">
|
||||
<ul class="flex flex-col">
|
||||
<li>
|
||||
<button type="button" class="w-full flex items-center gap-2.5 px-4 py-2.5 text-[12px] font-normal text-complement-900 cursor-pointer transition-colors hover:bg-complement-50" @click="openEditProfile">
|
||||
<i class="fi fi-rr-user-pen flex text-[14px] text-complement-700"></i>
|
||||
ویرایش حساب کاربری
|
||||
</button>
|
||||
</li>
|
||||
<li v-for="item in menuItems" :key="item.href">
|
||||
<Link :href="item.href" class="flex items-center gap-2.5 px-4 py-2.5 text-[12px] font-normal text-complement-900 transition-colors hover:bg-complement-50" @click="userMenuOpen = false">
|
||||
<i class="fi flex text-[14px] text-complement-700" :class="item.icon"></i>
|
||||
{{ item.label }}
|
||||
</Link>
|
||||
</li>
|
||||
<li class="border-t border-complement-100 mt-1 pt-1">
|
||||
<Link href="/dashboard/logout" class="flex items-center gap-2.5 px-4 py-2.5 text-[12px] font-normal text-dominant-400 transition-colors hover:bg-dominant-light">
|
||||
<i class="fi fi-rr-sign-out-alt flex text-[14px]"></i>
|
||||
خروج از حساب
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
<EditProfileModal v-model:visible="editProfileVisible" />
|
||||
</header>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import LogoutSvg from "../svg/logout.svg"
|
||||
import CalendarSvg from "../svg/calendar.svg"
|
||||
import StatusUpSvg from "../svg/statusUp.svg"
|
||||
import PetSvg from "../svg/pet.svg"
|
||||
import WalletSvg from "../svg/wallet.svg"
|
||||
import InvoiceSvg from "../svg/invoice.svg"
|
||||
|
||||
interface SidebarItem extends MenuItem {
|
||||
label: string;
|
||||
@@ -87,6 +89,20 @@ const items: Ref<SidebarItem[]> = ref([
|
||||
key: 'reports',
|
||||
permission: null,
|
||||
},
|
||||
{
|
||||
label: "کیف پول",
|
||||
icon: WalletSvg,
|
||||
to: "/dashboard/wallet",
|
||||
key: 'wallet',
|
||||
permission: null,
|
||||
},
|
||||
{
|
||||
label: "فاکتورها",
|
||||
icon: InvoiceSvg,
|
||||
to: "/dashboard/invoices",
|
||||
key: 'invoices',
|
||||
permission: null,
|
||||
},
|
||||
{
|
||||
label: "شیفت ها",
|
||||
icon: CalendarSvg,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.5 5.25V12.75C16.5 15 15.375 16.5 12.75 16.5H5.25C2.625 16.5 1.5 15 1.5 12.75V5.25C1.5 3 2.625 1.5 5.25 1.5H12.75C15.375 1.5 16.5 3 16.5 5.25Z" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.4375 5.8125H12.5625" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.4375 9H12.5625" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.4375 12.1875H9.75" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 691 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="220" height="180" viewBox="0 0 220 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="46" cy="34" r="4" fill="#F5A9AB"/>
|
||||
<circle cx="178" cy="28" r="3" fill="#F5A9AB"/>
|
||||
<circle cx="188" cy="120" r="4" fill="#F5A9AB"/>
|
||||
<circle cx="34" cy="128" r="3" fill="#F5A9AB"/>
|
||||
<circle cx="110" cy="164" r="3" fill="#F5A9AB"/>
|
||||
<circle cx="110" cy="90" r="52" fill="#E5484D"/>
|
||||
<path d="M92 72L128 108M128 72L92 108" stroke="white" stroke-width="9" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 493 B |
@@ -0,0 +1,19 @@
|
||||
<svg width="220" height="180" viewBox="0 0 220 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="38" y="24" width="4" height="14" rx="2" transform="rotate(-24 38 24)" fill="#3E6D9C"/>
|
||||
<rect x="176" y="18" width="4" height="12" rx="2" transform="rotate(32 176 18)" fill="#E5484D"/>
|
||||
<rect x="24" y="96" width="4" height="12" rx="2" transform="rotate(58 24 96)" fill="#E5484D"/>
|
||||
<rect x="188" y="92" width="4" height="14" rx="2" transform="rotate(-40 188 92)" fill="#3E6D9C"/>
|
||||
<rect x="66" y="150" width="4" height="12" rx="2" transform="rotate(20 66 150)" fill="#8BC34A"/>
|
||||
<rect x="150" y="152" width="4" height="12" rx="2" transform="rotate(-28 150 152)" fill="#E5484D"/>
|
||||
<circle cx="30" cy="58" r="3" fill="#8BC34A"/>
|
||||
<circle cx="58" cy="12" r="3" fill="#E5484D"/>
|
||||
<circle cx="118" cy="8" r="3" fill="#64B5F6"/>
|
||||
<circle cx="196" cy="52" r="3" fill="#8BC34A"/>
|
||||
<circle cx="200" cy="136" r="3" fill="#64B5F6"/>
|
||||
<circle cx="96" cy="168" r="3" fill="#E5484D"/>
|
||||
<circle cx="20" cy="140" r="3" fill="#64B5F6"/>
|
||||
<circle cx="164" cy="120" r="2.5" fill="#E5484D"/>
|
||||
<circle cx="52" cy="118" r="2.5" fill="#8BC34A"/>
|
||||
<circle cx="110" cy="90" r="52" fill="#5384AD"/>
|
||||
<path d="M88 91L103 106L133 76" stroke="white" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.75 9.9075H10.995C10.29 9.9075 9.7125 9.33 9.7125 8.625C9.7125 7.92 10.29 7.3425 10.995 7.3425H12.75" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.235 8.61H11.145" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.1875 2.25H10.6875C12.5325 2.25 12.9375 2.7 12.9375 4.005V7.3425" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.65 11.055C4.65 11.4675 4.3125 11.805 3.9 11.805C3.4875 11.805 3.15 11.4675 3.15 11.055C3.15 10.6425 3.4875 10.305 3.9 10.305C4.3125 10.305 4.65 10.6425 4.65 11.055Z" fill="#965457"/>
|
||||
<path d="M1.5 8.8125V12.375C1.5 14.445 3.18 16.125 5.25 16.125H12.75C14.82 16.125 16.5 14.445 16.5 12.375V6.375C16.5 4.305 14.82 2.625 12.75 2.625" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M1.5 8.8125V5.25C1.5 4.0575 2.235 2.9925 3.3525 2.5725" stroke="#965457" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -7,50 +7,39 @@ const props = defineProps([
|
||||
'perPage',
|
||||
'links',
|
||||
])
|
||||
|
||||
const pageItemClass = 'flex items-center justify-center w-8 h-8 rounded-lg border text-[11px] font-semibold transition-colors';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="pagination" v-if="lastPage > 1">
|
||||
<nav class="flex items-center gap-1.5 p-4" v-if="lastPage > 1">
|
||||
<template v-for="(link , index) in links" :key="index">
|
||||
<div class="paginate" v-if="link.label == 'قبلی'">
|
||||
<Link v-if="link.url" :href="link.url">
|
||||
<i class="fi fi-rr-angle-small-right flex text-xl"></i>
|
||||
<template v-if="link.label == 'قبلی'">
|
||||
<Link v-if="link.url" :href="link.url" :class="pageItemClass" class="border-complement-100 text-complement-700 hover:bg-complement-50">
|
||||
<i class="fi fi-rr-angle-small-right flex text-base"></i>
|
||||
</Link>
|
||||
</div>
|
||||
<div class="paginate" v-else-if="link.label == 'بعدی'">
|
||||
<Link v-if="link.url" :href="link.url">
|
||||
<i class="fi fi-rr-angle-small-left flex text-xl"></i>
|
||||
<span v-else :class="pageItemClass" class="border-complement-100 text-complement-200">
|
||||
<i class="fi fi-rr-angle-small-right flex text-base"></i>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="link.label == 'بعدی'">
|
||||
<Link v-if="link.url" :href="link.url" :class="pageItemClass" class="border-complement-100 text-complement-700 hover:bg-complement-50">
|
||||
<i class="fi fi-rr-angle-small-left flex text-base"></i>
|
||||
</Link>
|
||||
</div>
|
||||
<div class="paginate flex items-center" :class="{'!text-white !bg-client-primary' : currentPage == link.label }" v-else>
|
||||
<Link v-if="link.url" :href="link.url" class="flex pt-1">{{link.label}}</Link>
|
||||
<Link v-else href="" class="flex">{{link.label}}</Link>
|
||||
</div>
|
||||
<span v-else :class="pageItemClass" class="border-complement-100 text-complement-200">
|
||||
<i class="fi fi-rr-angle-small-left flex text-base"></i>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Link
|
||||
v-if="link.url"
|
||||
:href="link.url"
|
||||
:class="[pageItemClass, currentPage == link.label ? 'bg-dominant border-dominant text-white' : 'border-complement-100 text-complement-900 hover:bg-complement-50']"
|
||||
>
|
||||
{{ link.label }}
|
||||
</Link>
|
||||
<span v-else :class="pageItemClass" class="border-transparent text-complement-700">{{ link.label }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</section>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style lang="postcss">
|
||||
section.pagination{
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
section.pagination div.paginate:first-child a{
|
||||
border-top-right-radius: .4rem;
|
||||
border-bottom-right-radius: .4rem;
|
||||
}
|
||||
section.pagination div.paginate:last-child a{
|
||||
border-top-left-radius: .4rem;
|
||||
border-bottom-left-radius: .4rem;
|
||||
}
|
||||
section.pagination div.paginate a{
|
||||
display: flex;
|
||||
height: 2.2rem;
|
||||
width: 2.2rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #e6e6e6;
|
||||
@apply text-client-Fontcolor
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -133,6 +133,12 @@ const buttonClasses = computed(() => {
|
||||
if (props.severity === 'secondary') {
|
||||
classes.push('!font-[600] !text-[11px] !rounded-[6px]')
|
||||
}
|
||||
if (props.severity === 'success') {
|
||||
classes.push('ui-button--success !font-[600] !text-[11px] !rounded-[6px]')
|
||||
}
|
||||
if (props.severity === 'danger') {
|
||||
classes.push('!font-[600] !text-[11px] !rounded-[6px]')
|
||||
}
|
||||
|
||||
return classes.join(' ')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user