feat: add withdraw request functionality and UI components

This commit is contained in:
2026-08-27 02:39:57 +03:30
parent aeef95339d
commit 4ce663c669
115 changed files with 4064 additions and 315 deletions
@@ -0,0 +1,189 @@
<script setup>
import { computed, ref } from 'vue';
import { usePage } from '@inertiajs/inertia-vue3';
import { toast } from 'vue3-toastify';
import ClientLayout from '../../../layouts/ClientLayout.vue';
import TableGeneric from '../../../components/ui/TableGeneric.vue';
import UiCard from '../../../components/ui/UiCard.vue';
import UiInput from '../../../components/ui/UiInput.vue';
import UiButton from '../../../components/ui/UiButton.vue';
import WalletSvg from '../../../components/svg/wallet.svg';
import WithdrawRequestCard from '../../../components/dashboard/wallet/WithdrawRequestCard.vue';
import { walletTransactionColumns } from '../../../data/walletTransactionsTableColumns';
import { withdrawRequestColumns } from '../../../data/withdrawRequestsTableColumns';
import { convertEnglishToPersian, convertPersianToEnglish, formatPrice } from '../../../utils/numberUtils';
const props = defineProps({
transactions: {
type: Object,
required: true
},
withdrawRequests: {
type: Array,
required: true
},
bankCards: {
type: Array,
required: true
}
});
const { props: pageProps } = usePage();
const quickAmounts = [100000, 200000, 500000];
const amount = ref('');
const depositing = ref(false);
const numericAmount = computed(() => Number(convertPersianToEnglish(amount.value).replace(/\D/g, '')) || 0);
const formattedBalance = computed(() => formatPrice(pageProps.value.auth?.wallet_balance || 0));
const pendingWithdrawAmount = computed(() => props.withdrawRequests
.filter((request) => request.status === 'در انتظار بررسی')
.reduce((sum, request) => sum + request.amount, 0));
const withdrawStatusClasses = (status) => {
if (status === 'تایید شده') {
return 'text-[#1F7A4D] bg-[#E6F4EC]';
}
if (status === 'رد شده') {
return 'text-[#7A1419] bg-[#F8E9EA]';
}
return 'text-[#576989] bg-[#EEF2F8]';
};
const formatCardNumber = (cardNumber) => convertEnglishToPersian(cardNumber.replace(/(\d{4})(?=\d)/g, '$1 - '));
const selectQuickAmount = (value) => {
amount.value = String(value);
};
const handleDeposit = async () => {
if (numericAmount.value < 10000) {
toast.error('حداقل مبلغ شارژ ۱۰٬۰۰۰ تومان است.');
return;
}
depositing.value = true;
try {
const { data } = await window.axios.post('/dashboard/wallet/deposit', { amount: numericAmount.value });
window.location.href = data.url;
} catch (error) {
depositing.value = false;
toast.error(error.response?.data?.message || 'خطا در اتصال به درگاه پرداخت. لطفا دوباره تلاش کنید.');
}
};
</script>
<template>
<ClientLayout>
<div class="flex flex-col gap-4">
<UiCard title="کیف پول" variant="default">
<div class="grid grid-cols-2 max-sm:grid-cols-1 gap-4">
<div class="flex items-center gap-3 bg-[#EEF2F8] border border-[#DEE3EB] rounded-[12px] px-5 py-4">
<WalletSvg class="w-6 h-6" />
<div class="flex flex-col gap-1">
<span class="text-[11px] font-normal text-[#576989]">موجودی کیف پول</span>
<strong class="text-[16px] font-bold text-[#3E4C63]">{{ formattedBalance }} تومان</strong>
</div>
</div>
<div class="flex items-center gap-3 bg-[#F8FAFC] border border-[#DEE3EB] rounded-[12px] px-5 py-4">
<div class="flex flex-col gap-1">
<span class="text-[11px] font-normal text-[#576989]">مبلغ در انتظار برداشت</span>
<strong class="text-[16px] font-bold text-[#3E4C63]">{{ formatPrice(pendingWithdrawAmount) }} تومان</strong>
</div>
</div>
</div>
</UiCard>
<UiCard title="شارژ کیف پول" variant="default">
<form class="flex flex-col gap-4" @submit.prevent="handleDeposit">
<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-[22rem] max-sm:!w-full"
customClass="!border-dominant-50 !font-normal !text-[12px]"
/>
<UiButton
label="افزایش موجودی"
severity="success"
size="small"
:loading="depositing"
:disabled="depositing"
@click="handleDeposit"
/>
</div>
<div class="flex items-center gap-2 flex-wrap">
<button
v-for="value in quickAmounts"
:key="value"
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="selectQuickAmount(value)"
>
{{ formatPrice(value) }} تومان
</button>
</div>
</form>
</UiCard>
<WithdrawRequestCard :bank-cards="bankCards" />
<UiCard title="درخواست‌های برداشت" variant="default">
<TableGeneric
class="bg-white !rounded-2xl"
:data="withdrawRequests"
customStyle="!text-[11px] !font-normal"
:searchable="false"
:columns="withdrawRequestColumns"
:selectable="false"
:pagination="null"
:model-value="[]"
>
<template #column-bank_card="{ data }">
<span v-if="data.bank_card" dir="ltr">{{ formatCardNumber(data.bank_card.card_number) }}</span>
<span v-else>-</span>
</template>
<template #column-status="{ data }">
<span class="text-[11px] font-normal rounded-md px-2 py-1" :class="withdrawStatusClasses(data.status)">
{{ data.status }}
</span>
</template>
</TableGeneric>
</UiCard>
<UiCard title="تراکنش‌ها" variant="default">
<TableGeneric
class="bg-white !rounded-2xl"
:data="transactions.data"
customStyle="!text-[11px] !font-normal"
:searchable="false"
:columns="walletTransactionColumns"
:selectable="false"
:pagination="transactions.meta"
:model-value="[]"
>
<template #column-type="{ data }">
<span
class="text-[11px] font-normal rounded-md px-2 py-1"
:class="data.type === 'واریز' ? 'text-[#1F7A4D] bg-[#E6F4EC]' : 'text-[#7A1419] bg-[#F8E9EA]'"
>
{{ data.type }}
</span>
</template>
</TableGeneric>
</UiCard>
</div>
</ClientLayout>
</template>