bank crud

This commit is contained in:
hamid zarghami
2025-02-06 11:22:25 +03:30
parent e0048cb0a1
commit 1e8b542960
11 changed files with 539 additions and 2 deletions
+159
View File
@@ -0,0 +1,159 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '../../components/Button'
import { TickCircle, TickSquare } from 'iconsax-react'
import SwitchComponent from '../../components/Switch'
import Input from '../../components/Input'
import { useFormik } from 'formik'
import { CreateBankType } from './types/CardBankTypes'
import * as Yup from 'yup'
import { useCreateBank } from './hooks/useCardBankData'
import { useNavigate } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import { ErrorType } from '../../helpers/types'
import { toast } from 'react-toastify'
const CreateBankCard: FC = () => {
const navigate = useNavigate()
const { t } = useTranslation('global')
const createBank = useCreateBank()
const formik = useFormik<CreateBankType>({
initialValues: {
accountOwnerName: '',
bankName: '',
cardNumber: '',
IBan: '',
isActive: true,
},
validationSchema: Yup.object({
accountOwnerName: Yup.string().required(t('errors.required')),
bankName: Yup.string().required(t('errors.required')),
cardNumber: Yup.string().required(t('errors.required')),
IBan: Yup.string().required(t('errors.required')),
}),
onSubmit: (values) => {
createBank.mutate(values, {
onSuccess: () => {
formik.resetForm()
navigate(Pages.cardBank.list)
},
onError: (error: ErrorType) => {
toast.error(error.response?.data?.error?.message[0])
}
})
}
})
return (
<div className='mt-4'>
<div className='flex justify-between items-center'>
<div>
{t('cardBank.new_account')}
</div>
<div>
<Button
className='px-4'
onClick={() => formik.handleSubmit()}
isLoading={createBank.isPending}
>
<div className='flex gap-2 items-center'>
<TickCircle
size={15}
color='#fff'
/>
<div>{t('cardBank.submit_account')}</div>
</div>
</Button>
</div>
</div>
<div className='flex gap-6 xl:mt-8 mt-4'>
<div className='flex-1 text-sm bg-white py-8 xl:px-10 px-4 rounded-3xl'>
<div>
{t('cardBank.account_information')}
</div>
<div className='mt-10 flex items-center gap-5'>
<div>
{t('cardBank.status_account')}
</div>
<SwitchComponent
active={formik.values.isActive}
onChange={(value) => formik.setFieldValue('isActive', value)}
/>
</div>
<div className='mt-8 rowTwoInput'>
<Input
label={t('cardBank.account_owner_name')}
name='accountOwnerName'
value={formik.values.accountOwnerName}
onChange={formik.handleChange}
error_text={formik.touched.accountOwnerName && formik.errors.accountOwnerName ? formik.errors.accountOwnerName : ''}
/>
<Input
label={t('cardBank.bank_name')}
name='bankName'
value={formik.values.bankName}
onChange={formik.handleChange}
error_text={formik.touched.bankName && formik.errors.bankName ? formik.errors.bankName : ''}
/>
</div>
<div className='mt-8 rowTwoInput'>
<Input
label={t('cardBank.card_number')}
name='cardNumber'
value={formik.values.cardNumber}
onChange={formik.handleChange}
error_text={formik.touched.cardNumber && formik.errors.cardNumber ? formik.errors.cardNumber : ''}
/>
<Input
label={t('cardBank.sheba')}
name='IBan'
value={formik.values.IBan}
onChange={formik.handleChange}
error_text={formik.touched.IBan && formik.errors.IBan ? formik.errors.IBan : ''}
/>
</div>
</div>
<div className='bg-white w-sidebar xl:block hidden py-10 px-5 h-fit rounded-3xl'>
<div className='text-sm'>
{t('ticket.title_hint')}
</div>
<div className='mt-6'>
<div className='flex items-start gap-2 border-b pb-5'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید.
</div>
</div>
<div className='flex items-start gap-2 mt-6 border-b pb-5'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است.
</div>
</div>
<div className='flex items-start gap-2 mt-6'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است.
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default CreateBankCard
+179
View File
@@ -0,0 +1,179 @@
import { FC, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '../../components/Button'
import { TickCircle, TickSquare } from 'iconsax-react'
import SwitchComponent from '../../components/Switch'
import Input from '../../components/Input'
import { useFormik } from 'formik'
import { CreateBankType } from './types/CardBankTypes'
import * as Yup from 'yup'
import { useGetCardBankDetail, useUpdateBank } from './hooks/useCardBankData'
import { useNavigate, useParams } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import { ErrorType } from '../../helpers/types'
import { toast } from 'react-toastify'
const EditBankCard: FC = () => {
const { id } = useParams()
const navigate = useNavigate()
const { t } = useTranslation('global')
const updateBank = useUpdateBank(id ? id : '')
const getCard = useGetCardBankDetail(id ? id : '')
const formik = useFormik<CreateBankType>({
initialValues: {
accountOwnerName: '',
bankName: '',
cardNumber: '',
IBan: '',
isActive: true,
},
validationSchema: Yup.object({
accountOwnerName: Yup.string().required(t('errors.required')),
bankName: Yup.string().required(t('errors.required')),
cardNumber: Yup.string().required(t('errors.required')),
IBan: Yup.string().required(t('errors.required')),
}),
onSubmit: (values) => {
updateBank.mutate(values, {
onSuccess: () => {
formik.resetForm()
navigate(Pages.cardBank.list)
},
onError: (error: ErrorType) => {
toast.error(error.response?.data?.error?.message[0])
}
})
}
})
useEffect(() => {
if (getCard.data?.data?.bankAccount) {
const data = getCard.data?.data?.bankAccount
formik.setValues({
accountOwnerName: data.accountOwnerName,
bankName: data.bankName,
cardNumber: data.cardNumber,
IBan: data.IBan,
isActive: data.isActive,
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [getCard.data])
return (
<div className='mt-4'>
<div className='flex justify-between items-center'>
<div>
{t('cardBank.new_account')}
</div>
<div>
<Button
className='px-4'
onClick={() => formik.handleSubmit()}
isLoading={updateBank.isPending}
>
<div className='flex gap-2 items-center'>
<TickCircle
size={15}
color='#fff'
/>
<div>{t('edit')}</div>
</div>
</Button>
</div>
</div>
<div className='flex gap-6 xl:mt-8 mt-4'>
<div className='flex-1 text-sm bg-white py-8 xl:px-10 px-4 rounded-3xl'>
<div>
{t('cardBank.account_information')}
</div>
<div className='mt-10 flex items-center gap-5'>
<div>
{t('cardBank.status_account')}
</div>
<SwitchComponent
active={formik.values.isActive}
onChange={(value) => formik.setFieldValue('isActive', value)}
/>
</div>
<div className='mt-8 rowTwoInput'>
<Input
label={t('cardBank.account_owner_name')}
name='accountOwnerName'
value={formik.values.accountOwnerName}
onChange={formik.handleChange}
error_text={formik.touched.accountOwnerName && formik.errors.accountOwnerName ? formik.errors.accountOwnerName : ''}
/>
<Input
label={t('cardBank.bank_name')}
name='bankName'
value={formik.values.bankName}
onChange={formik.handleChange}
error_text={formik.touched.bankName && formik.errors.bankName ? formik.errors.bankName : ''}
/>
</div>
<div className='mt-8 rowTwoInput'>
<Input
label={t('cardBank.card_number')}
name='cardNumber'
value={formik.values.cardNumber}
onChange={formik.handleChange}
error_text={formik.touched.cardNumber && formik.errors.cardNumber ? formik.errors.cardNumber : ''}
/>
<Input
label={t('cardBank.sheba')}
name='IBan'
value={formik.values.IBan}
onChange={formik.handleChange}
error_text={formik.touched.IBan && formik.errors.IBan ? formik.errors.IBan : ''}
/>
</div>
</div>
<div className='bg-white w-sidebar xl:block hidden py-10 px-5 h-fit rounded-3xl'>
<div className='text-sm'>
{t('ticket.title_hint')}
</div>
<div className='mt-6'>
<div className='flex items-start gap-2 border-b pb-5'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید.
</div>
</div>
<div className='flex items-start gap-2 mt-6 border-b pb-5'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است.
</div>
</div>
<div className='flex items-start gap-2 mt-6'>
<div>
<TickSquare size={20} color='black' variant='Bold' />
</div>
<div className='text-description text-xs leading-5'>
پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است.
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default EditBankCard
+84
View File
@@ -0,0 +1,84 @@
import { FC } from 'react'
import { useGetCardBanks } from './hooks/useCardBankData'
import PageLoading from '../../components/PageLoading'
import Td from '../../components/Td'
import { useTranslation } from 'react-i18next'
import { CreateBankItemType } from './types/CardBankTypes'
import { Link } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import Button from '../../components/Button'
import { Add, Eye } from 'iconsax-react'
const CardBankList: FC = () => {
const { t } = useTranslation('global')
const getCardBanks = useGetCardBanks()
return (
<div className='mt-4'>
<div className='flex w-full justify-between items-center'>
<div>
{t('cardBank.manage_banks')}
</div>
<div>
<Link to={Pages.cardBank.create}>
<Button
className='px-5'
>
<div className='flex gap-2'>
<Add
className='size-5'
color='#fff'
/>
<div>{t('cardBank.add_account')}</div>
</div>
</Button>
</Link>
</div>
</div>
{
getCardBanks.isPending ?
<PageLoading />
:
<div className='relative overflow-x-auto rounded-3xl mt-9 w-full'>
<table className='w-full text-sm '>
<thead className='thead'>
<tr>
<Td text={t('cardBank.account_owner_name')} />
<Td text={t('cardBank.bank_name')} />
<Td text={t('cardBank.card_number')} />
<Td text={t('cardBank.sheba')} />
<Td text={t('ticket.detail')} />
</tr>
</thead>
<tbody>
{
getCardBanks.data?.data?.bankAccounts?.map((item: CreateBankItemType) => {
return (
<tr key={item.id} className='tr'>
<Td text={item.accountOwnerName} />
<Td text={item.bankName} />
<Td text={item.cardNumber} />
<Td text={item.IBan} />
<Td text={''}>
<Link to={Pages.cardBank.detail + item.id}>
<Eye size={20} color='#8C90A3' />
</Link>
</Td>
</tr>
)
})
}
</tbody>
</table>
</div>
}
</div>
)
}
export default CardBankList
@@ -0,0 +1,46 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { CreateBankType } from "../types/CardBankTypes";
import * as api from "../service/CardBankService";
export const useCreateBank = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (variables: CreateBankType) => api.createCardBank(variables),
onSuccess: () => {
queryClient.refetchQueries({
queryKey: ["cardBanks"],
});
},
});
};
export const useGetCardBanks = () => {
return useQuery({
queryKey: ["cardBanks"],
queryFn: api.getCardBanks,
});
};
export const useGetCardBankDetail = (id: string) => {
return useQuery({
queryKey: ["cardBank", id],
queryFn: () => api.getCardBankDetail(id),
enabled: !!id,
});
};
export const useUpdateBank = (id: string) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (variables: CreateBankType) =>
api.updateCardBank(id, variables),
onSuccess: () => {
queryClient.refetchQueries({
queryKey: ["cardBanks"],
});
queryClient.refetchQueries({
queryKey: ["cardBank", id],
});
},
});
};
@@ -0,0 +1,22 @@
import axios from "../../../config/axios";
import { CreateBankType } from "../types/CardBankTypes";
export const createCardBank = async (params: CreateBankType) => {
const { data } = await axios.post(`/payments/bank-account`, params);
return data;
};
export const getCardBanks = async () => {
const { data } = await axios.get(`/payments/bank-account`);
return data;
};
export const getCardBankDetail = async (id: string) => {
const { data } = await axios.get(`/payments/bank-account/${id}`);
return data;
};
export const updateCardBank = async (id: string, params: CreateBankType) => {
const { data } = await axios.patch(`/payments/bank-account/${id}`, params);
return data;
};
+15
View File
@@ -0,0 +1,15 @@
export type CreateBankType = {
cardNumber: string;
IBan: string;
bankName: string;
accountOwnerName: string;
isActive: boolean;
};
export type CreateBankItemType = {
id: string;
cardNumber: string;
IBan: string;
bankName: string;
accountOwnerName: string;
isActive: boolean;
};