change financial and pixel perfect

This commit is contained in:
hamid zarghami
2025-03-02 18:27:57 +03:30
parent 7317fb26cf
commit 632c8f4c4e
21 changed files with 8234 additions and 154 deletions
+66 -30
View File
@@ -7,45 +7,51 @@ import Button from '../../../components/Button'
import { InfoCircle, TickCircle } from 'iconsax-react'
import { CreateLegalUserType, ProvinesItemType } from '../types/FinancialTypes'
import * as Yup from 'yup'
import { useCreateLegalUser, useGetCities, useGetFinancialInfo, useGetProvines } from '../hooks/useFinancialData'
import { useCreateLegalUser, useGetCities, useGetLegalInfo, useGetProvines } from '../hooks/useFinancialData'
import Select from '../../../components/Select'
import PageLoading from '../../../components/PageLoading'
import { toast } from 'react-toastify'
import { ErrorType } from '../../../helpers/types'
import { useGetProfile } from '../../profile/hooks/useProfileData'
const Legal: FC = () => {
const { t } = useTranslation('global')
const [isReadOnly, setIsReadOnly] = useState<boolean>(false)
const [provinesId, setProvinesId] = useState<string>('')
const getFinancialInfo = useGetFinancialInfo()
const getProvines = useGetProvines()
const getLegalInfo = useGetLegalInfo()
const getCities = useGetCities(provinesId)
const createLegalUser = useCreateLegalUser()
const getProfile = useGetProfile()
const formik = useFormik<CreateLegalUserType>({
initialValues: {
address: '',
cityId: '',
companyRegisteredName: '',
registrationName: '',
economicCode: '',
nationalId: '',
number: '',
nationalIdentity: '',
phone: '',
postalCode: '',
registrationId: ''
registrationCode: ''
},
validationSchema: Yup.object({
address: Yup.string().required(t('errors.required')),
cityId: Yup.string().required(t('errors.required')),
companyRegisteredName: Yup.string().required(t('errors.required')),
registrationName: Yup.string().required(t('errors.required')),
economicCode: Yup.string().required(t('errors.required')),
nationalId: Yup.string().required(t('errors.required')),
number: Yup.string().required(t('errors.required')),
nationalIdentity: Yup.string().required(t('errors.required')),
phone: Yup.string().required(t('errors.required')),
postalCode: Yup.string().required(t('errors.required')),
registrationId: Yup.string().required(t('errors.required'))
registrationCode: Yup.string().required(t('errors.required'))
}),
onSubmit: values => {
createLegalUser.mutate(values, {
const params = {
...values,
cityId: +values.cityId
}
createLegalUser.mutate(params, {
onSuccess: () => {
toast.success(t('success'))
window.location.reload()
@@ -57,33 +63,63 @@ const Legal: FC = () => {
}
})
// useEffect(() => {
// if (getFinancialInfo.data?.data?.user?.legalUser || getFinancialInfo.data?.data?.user?.realUser) {
// setIsReadOnly(true)
// }
// if (getFinancialInfo.data?.data?.user?.legalUser) {
// const data = getFinancialInfo.data.data?.user
// formik.setValues({
// address: data?.address.address,
// cityId: data?.address?.city?.id,
// companyRegisteredName: data?.legalUser.companyRegisteredName,
// economicCode: data?.legalUser.economicCode,
// nationalId: data?.legalUser.nationalId,
// number: data?.legalUser.number,
// postalCode: data?.address.postalCode,
// registrationId: data?.legalUser.registrationId
// })
// setProvinesId(data?.address?.city?.province?.id)
// }
// }, [getFinancialInfo.data])
useEffect(() => {
if (getFinancialInfo.data?.data?.user?.legalUser || getFinancialInfo.data?.data?.user?.realUser) {
if (getLegalInfo.data?.data?.legalUser) {
setIsReadOnly(true)
}
if (getFinancialInfo.data?.data?.user?.legalUser) {
const data = getFinancialInfo.data.data?.user
if (getLegalInfo.data?.data?.legalUser) {
const data = getLegalInfo.data?.data?.legalUser
formik.setValues({
address: data?.address.address,
address: data?.address.fullAddress,
cityId: data?.address?.city?.id,
companyRegisteredName: data?.legalUser.companyRegisteredName,
economicCode: data?.legalUser.economicCode,
nationalId: data?.legalUser.nationalId,
number: data?.legalUser.number,
registrationName: data.registrationName,
economicCode: data.economicCode,
nationalIdentity: data.nationalIdentity,
phone: data.phone,
postalCode: data?.address.postalCode,
registrationId: data?.legalUser.registrationId
registrationCode: data.registrationCode
})
setProvinesId(data?.address?.city?.province?.id)
}
}, [getFinancialInfo.data])
}, [getLegalInfo.data])
useEffect(() => {
if (getProfile.data && getProfile.data?.data?.user?.financialType) {
setIsReadOnly(true)
}
}, [getProfile.data])
return (
<div className='bg-white rounded-3xl xl:p-6 p-4 mt-8 text-sm'>
{
getProvines.isPending || getFinancialInfo.isPending ?
getProvines.isPending || getLegalInfo.isPending ?
<PageLoading />
:
<Fragment>
@@ -100,8 +136,8 @@ const Legal: FC = () => {
<div className='flex items-end xl:gap-6 gap-3'>
<Input
label={t('financial.company_name')}
{...formik.getFieldProps('companyRegisteredName')}
error_text={formik.touched.companyRegisteredName && formik.errors.companyRegisteredName ? formik.errors.companyRegisteredName : ''}
{...formik.getFieldProps('registrationName')}
error_text={formik.touched.registrationName && formik.errors.registrationName ? formik.errors.registrationName : ''}
readOnly={isReadOnly}
/>
</div>
@@ -109,8 +145,8 @@ const Legal: FC = () => {
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
<Input
label={t('financial.company_code')}
{...formik.getFieldProps('registrationId')}
error_text={formik.touched.registrationId && formik.errors.registrationId ? formik.errors.registrationId : ''}
{...formik.getFieldProps('registrationCode')}
error_text={formik.touched.registrationCode && formik.errors.registrationCode ? formik.errors.registrationCode : ''}
readOnly={isReadOnly}
/>
</div>
@@ -118,8 +154,8 @@ const Legal: FC = () => {
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
<Input
label={t('financial.national_id')}
{...formik.getFieldProps('nationalId')}
error_text={formik.touched.nationalId && formik.errors.nationalId ? formik.errors.nationalId : ''}
{...formik.getFieldProps('nationalIdentity')}
error_text={formik.touched.nationalIdentity && formik.errors.nationalIdentity ? formik.errors.nationalIdentity : ''}
readOnly={isReadOnly}
/>
@@ -166,8 +202,8 @@ const Legal: FC = () => {
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
<Input
label={t('financial.company_phone')}
{...formik.getFieldProps('number')}
error_text={formik.touched.number && formik.errors.number ? formik.errors.number : ''}
{...formik.getFieldProps('phone')}
error_text={formik.touched.phone && formik.errors.phone ? formik.errors.phone : ''}
readOnly={isReadOnly}
/>
+93 -50
View File
@@ -8,9 +8,11 @@ import Button from '../../../components/Button'
import { InfoCircle, TickCircle } from 'iconsax-react'
import { CreateRealUserType, ProvinesItemType } from '../types/FinancialTypes'
import * as Yup from 'yup'
import { useCreateRealUser, useGetCities, useGetFinancialInfo, useGetProvines } from '../hooks/useFinancialData'
import { useCreateRealUser, useGetCities, useGetProvines, useGetRealInfo } from '../hooks/useFinancialData'
import { toast } from 'react-toastify'
import { ErrorType } from '../../../helpers/types'
import DatePickerComponent from '../../../components/DatePicker'
import { useGetProfile } from '../../profile/hooks/useProfileData'
const Personal: FC = () => {
@@ -18,30 +20,45 @@ const Personal: FC = () => {
const [isReadOnly, setIsReadOnly] = useState<boolean>(false)
const [provinesId, setProvinesId] = useState<string>('')
const getFinancialInfo = useGetFinancialInfo()
const createRealUser = useCreateRealUser()
const getProvines = useGetProvines()
const getRealInfo = useGetRealInfo()
const getCities = useGetCities(provinesId)
const getProfile = useGetProfile()
const formik = useFormik<CreateRealUserType>({
initialValues: {
address: '',
cityId: '',
fatherName: '',
birthDate: '',
firstName: '',
gender: '',
lastName: '',
nationalCode: '',
nationality: '',
phone: '',
postalCode: ''
},
validationSchema: Yup.object({
address: Yup.string().required(t('errors.required')),
cityId: Yup.string().required(t('errors.required')),
fatherName: Yup.string().required(t('errors.required')),
fatherName: Yup.string().required(t('rerrors.equired')),
gender: Yup.string().required(t('errors.required')),
firstName: Yup.string().required(t('errors.required')),
lastName: Yup.string().required(t('rerrors.equired')),
nationalCode: Yup.string().required(t('errors.required')),
nationality: Yup.string().required(t('errors.required')),
postalCode: Yup.string().required(t('errors.required'))
phone: Yup.string().required(t('errors.required')),
postalCode: Yup.string().required(t('errors.required')),
birthDate: Yup.string().required(t('errors.required'))
}),
onSubmit: values => {
createRealUser.mutate(values, {
const params = {
...values,
cityId: +values.cityId
}
createRealUser.mutate(params, {
onSuccess: () => {
toast.success(t('success'))
window.location.reload()
@@ -55,25 +72,35 @@ const Personal: FC = () => {
useEffect(() => {
if (getFinancialInfo.data?.data?.user?.legalUser || getFinancialInfo.data?.data?.user?.realUser) {
setIsReadOnly(true)
}
if (getFinancialInfo.data?.data?.user?.realUser) {
const data = getFinancialInfo.data?.data?.user
if (getRealInfo.data?.data?.realUser) {
const data = getRealInfo.data?.data?.realUser
setIsReadOnly(true)
formik.setValues({
address: data.address.address,
cityId: data.address?.city?.cityId,
fatherName: data?.realUser?.fatherName,
gender: data?.realUser?.gender,
nationality: data?.realUser?.nationality,
postalCode: data?.address?.postalCode
address: data.address.fullAddress,
cityId: data.address?.city?.id,
fatherName: data?.fatherName,
gender: data?.gender,
nationality: data?.nationality,
postalCode: data?.address?.postalCode,
birthDate: data?.birthDate,
firstName: data?.firstName,
lastName: data?.lastName,
nationalCode: data?.nationalCode,
phone: data?.phone
})
setProvinesId(data?.address?.city?.province?.id)
}
}, [getFinancialInfo.data])
}, [getRealInfo.data])
useEffect(() => {
if (getProfile.data && getProfile.data?.data?.user?.financialType) {
setIsReadOnly(true)
}
}, [getProfile.data])
return (
@@ -88,31 +115,33 @@ const Personal: FC = () => {
</div>
</div>
<div className='flex-1'>
{/* <div className='flex items-end xl:gap-6 gap-3'>
<div className='flex xl:gap-6 gap-3'>
<Input
label={t('financial.name')}
{...formik.getFieldProps('company_name')}
error_text={formik.touched.company_name && formik.errors.company_name ? formik.errors.company_name : ''}
{...formik.getFieldProps('firstName')}
error_text={formik.touched.firstName && formik.errors.firstName ? formik.errors.firstName : ''}
readOnly={isReadOnly}
/>
<Input
label={t('financial.family')}
{...formik.getFieldProps('company_name')}
error_text={formik.touched.company_name && formik.errors.company_name ? formik.errors.company_name : ''}
{...formik.getFieldProps('lastName')}
error_text={formik.touched.lastName && formik.errors.lastName ? formik.errors.lastName : ''}
readOnly={isReadOnly}
/>
</div> */}
<div className='flex items-end xl:gap-6 gap-3'>
</div>
<div className='flex xl:gap-6 gap-3 mt-8'>
<Select
label={t('financial.sex')}
placeholder={t('select')}
items={[
{
label: t('man'),
value: 'male'
value: 'MALE'
},
{
label: t('woman'),
value: 'female'
value: 'FEMALE'
},
]}
{...formik.getFieldProps('gender')}
@@ -128,37 +157,51 @@ const Personal: FC = () => {
/>
</div>
{/* <div className='flex items-end xl:gap-6 gap-3 mt-8'>
<div className='flex xl:gap-6 gap-3 mt-8'>
<Input
label={t('financial.phone_number')}
{...formik.getFieldProps('company_name')}
error_text={formik.touched. && formik.errors.company_name ? formik.errors.company_name : ''}
{...formik.getFieldProps('phone')}
error_text={formik.touched.phone && formik.errors.phone ? formik.errors.phone : ''}
readOnly={isReadOnly}
/>
<Input
label={t('financial.national_code')}
{...formik.getFieldProps('company_name')}
error_text={formik.touched.na && formik.errors.company_name ? formik.errors.company_name : ''}
/>
</div> */}
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
{/* <DatePickerComponent
label={t('financial.date_of_birth')}
onChange={(value) => formik.setFieldValue('dateOfBirth', value)}
placeholder={t('financial.date_of_birth')}
error_text={formik.touched. && formik.errors.dateOfBirth ? formik.errors.dateOfBirth : ''}
/> */}
<Input
label={t('financial.nationality')}
{...formik.getFieldProps('nationality')}
error_text={formik.touched.nationality && formik.errors.nationality ? formik.errors.nationality : ''}
{...formik.getFieldProps('nationalCode')}
error_text={formik.touched.nationalCode && formik.errors.nationalCode ? formik.errors.nationalCode : ''}
readOnly={isReadOnly}
/>
</div>
{/* <div className='flex items-end xl:gap-6 gap-3 mt-8'>
<div className='flex xl:gap-6 gap-3 mt-8'>
<DatePickerComponent
label={t('financial.date_of_birth')}
onChange={(value) => formik.setFieldValue('birthDate', value)}
placeholder={t('financial.date_of_birth')}
error_text={formik.touched.birthDate && formik.errors.birthDate ? formik.errors.birthDate : ''}
readOnly={isReadOnly}
defaulValue={formik.values.birthDate}
/>
<Select
items={[
{
label: t('financial.iranian'),
value: 'IRANIAN'
},
{
label: t('financial.foreign'),
value: 'FOREIGN'
},
]}
{...formik.getFieldProps('nationality')}
error_text={formik.touched.nationality && formik.errors.nationality ? formik.errors.nationality : ''}
readOnly={isReadOnly}
label={t('financial.nationality')}
/>
</div>
{/* <div className='flex xl:gap-6 gap-3 mt-8'>
<Input
label={t('financial.company_phone')}
{...formik.getFieldProps('number')}
@@ -187,7 +230,7 @@ const Personal: FC = () => {
</div>
</div>
<div className='flex-1'>
<div className='flex items-end xl:gap-6 gap-3'>
<div className='flex xl:gap-6 gap-3'>
<Select
value={provinesId}
label={t('financial.state')}
@@ -215,7 +258,7 @@ const Personal: FC = () => {
/>
</div>
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
<div className='flex xl:gap-6 gap-3 mt-8'>
<Textarea
{...formik.getFieldProps('address')}
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''}
@@ -40,3 +40,17 @@ export const useGetFinancialInfo = () => {
queryFn: () => api.getFinancialInfo(),
});
};
export const useGetLegalInfo = () => {
return useQuery({
queryKey: ["legal-info"],
queryFn: () => api.getLegalInfo(),
});
};
export const useGetRealInfo = () => {
return useQuery({
queryKey: ["real-info"],
queryFn: () => api.getRealInfo(),
});
};
@@ -5,12 +5,12 @@ import {
} from "../types/FinancialTypes";
export const createLegalUser = async (params: CreateLegalUserType) => {
const { data } = await axios.post(`/users/legal-user`, params);
const { data } = await axios.post(`/users/legal`, params);
return data;
};
export const createRealUser = async (params: CreateRealUserType) => {
const { data } = await axios.post(`/users/real-user`, params);
const { data } = await axios.post(`/users/real`, params);
return data;
};
@@ -28,3 +28,13 @@ export const getFinancialInfo = async () => {
const { data } = await axios.get(`/users/me/financial-info`);
return data;
};
export const getLegalInfo = async () => {
const { data } = await axios.get(`/users/legal`);
return data;
};
export const getRealInfo = async () => {
const { data } = await axios.get(`/users/real`);
return data;
};
+12 -7
View File
@@ -1,21 +1,26 @@
export type CreateRealUserType = {
phone: string;
firstName: string;
lastName: string;
birthDate: string;
nationalCode: string;
gender: string;
fatherName: string;
nationality: string;
address: string;
postalCode: string;
cityId: string;
cityId: string | number;
};
export type CreateLegalUserType = {
economicCode: string;
companyRegisteredName: string;
registrationId: string;
nationalId: string;
number: string;
postalCode: string;
registrationCode: string;
registrationName: string;
nationalIdentity: string;
address: string;
cityId: string;
postalCode: string;
cityId: string | number;
phone: string;
};
export type ProvinesItemType = {
+47 -2
View File
@@ -6,15 +6,18 @@ import { clx } from '../../helpers/utils';
import StatusCircle from '../../components/StatusCircle';
import { useOutsideClick } from '../../hooks/useOutSideClick';
import { useGetNotification, useReadAll } from './hooks/useNotificationData';
import { NotificationItemType } from './types/NotificationTypes';
import { NotificationItemType, NotificationTypeEnum } from './types/NotificationTypes';
import { timeAgo } from '../../config/func';
import InfiniteScroll from 'react-infinite-scroll-component';
import MoonLoader from "react-spinners/MoonLoader"
import Button from '../../components/Button';
import { toast } from 'react-toastify';
import { useGetDashboardSummary } from '../home/hooks/useHomeData';
import { useNavigate } from 'react-router-dom';
import { Pages } from '../../config/Pages';
const Notifications: FC = () => {
const navigate = useNavigate()
const { t } = useTranslation('global');
const ref = useOutsideClick(() => setShowModal(false));
const [activeTab, setActiveTab] = useState<'all' | 'read' | 'unread'>('all');
@@ -34,6 +37,48 @@ const Notifications: FC = () => {
})
}
const handleRedirect = (type: NotificationTypeEnum) => {
switch (type) {
case NotificationTypeEnum.USER_LOGIN:
break;
case NotificationTypeEnum.ANNOUNCEMENT:
navigate(Pages.announcement.list)
break;
case NotificationTypeEnum.WALLET_CHARGE:
navigate(Pages.transactions)
break;
case NotificationTypeEnum.WALLET_DEDUCTION:
navigate(Pages.transactions)
break;
case NotificationTypeEnum.BILL_INVOICE_REMINDER:
navigate(Pages.receipts.index)
break;
case NotificationTypeEnum.BILL_INVOICE:
navigate(Pages.receipts.index)
break;
case NotificationTypeEnum.CREATE_INVOICE:
navigate(Pages.receipts.index)
break;
case NotificationTypeEnum.CREATE_SERVICE:
navigate(Pages.services.other)
break;
case NotificationTypeEnum.UNBLOCK_SERVICE:
navigate(Pages.services.other)
break;
case NotificationTypeEnum.BLOCK_SERVICE:
navigate(Pages.services.other)
break;
case NotificationTypeEnum.ANSWER_TICKET:
navigate(Pages.ticket.list)
break;
case NotificationTypeEnum.CREATE_TICKET:
navigate(Pages.ticket.list)
break;
default:
break
}
}
return (
<div ref={ref}>
<div onClick={() => setShowModal(!showModal)} className='relative cursor-pointer'>
@@ -106,7 +151,7 @@ const Notifications: FC = () => {
>
{
posts.map((item: NotificationItemType) => (
<div className="bg-white h-fit gap-4 items-start rounded-xl bg-opacity-60 p-3 mb-4 flex" key={item.id}>
<div onClick={() => handleRedirect(item.type)} className="bg-white h-fit gap-4 items-start rounded-xl bg-opacity-60 p-3 mb-4 flex" key={item.id}>
<div className="mt-1">
<StatusCircle color="#00BA4B" />
</div>
@@ -4,4 +4,28 @@ export type NotificationItemType = {
message: string;
createdAt: string;
isRead: boolean;
type: NotificationTypeEnum;
};
export enum NotificationTypeEnum {
USER_LOGIN = "USER_LOGIN",
ANNOUNCEMENT = "ANNOUNCEMENT",
// Finance category
WALLET_CHARGE = "WALLET_CHARGE",
WALLET_DEDUCTION = "WALLET_DEDUCTION",
//Invoice
BILL_INVOICE_REMINDER = "BILL_INVOICE_REMINDER",
BILL_INVOICE = "BILL_INVOICE",
CREATE_INVOICE = "CREATE_INVOICE",
// Service category
CREATE_SERVICE = "CREATE_SERVICE",
UNBLOCK_SERVICE = "UNBLOCK_SERVICE",
BLOCK_SERVICE = "BLOCK_SERVICE",
// Support category
ANSWER_TICKET = "ANSWER_TICKET",
CREATE_TICKET = "CREATE_TICKET",
}
+4 -10
View File
@@ -2,11 +2,9 @@ import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AvatarImage from '../../assets/images/avatar_image.png'
import Button from '../../components/Button'
import { DocumentUpload, TickCircle } from 'iconsax-react'
import { DocumentUpload } from 'iconsax-react'
import Input from '../../components/Input'
import DatePickerComponent from '../../components/DatePicker'
import Select from '../../components/Select'
import Textarea from '../../components/Textarea'
import { useGetProfile, useUpdateProfile } from './hooks/useProfileData'
import Username from './components/Username'
import { useDropzone } from 'react-dropzone'
@@ -15,8 +13,7 @@ import { useSingleUpload } from '../ticket/hooks/useTicketData'
import { ErrorType } from '../../helpers/types'
import { UpdateProfileType } from './types/ProfileTypes'
import PageLoading from '../../components/PageLoading'
import { useGetCities, useGetProvines } from '../financial/hooks/useFinancialData'
import { ProvinesItemType } from '../financial/types/FinancialTypes'
import { useGetProvines } from '../financial/hooks/useFinancialData'
import { useFormik } from 'formik'
import * as Yup from 'yup'
import Email from './components/Email'
@@ -27,9 +24,7 @@ const Profile: FC = () => {
const { t } = useTranslation('global')
const singleUpload = useSingleUpload()
const [file, setFile] = useState<File>()
const [provinesId, setProvinesId] = useState<string>('')
const getProvines = useGetProvines()
const getCities = useGetCities(provinesId)
const getProfile = useGetProfile()
const updateProfile = useUpdateProfile()
@@ -65,7 +60,6 @@ const Profile: FC = () => {
postalCode: getProfile.data.data.user.postalCode || '',
})
if (getProfile.data.data.user.city) {
setProvinesId(getProfile.data.data.user.city.province?.id)
}
}
@@ -197,7 +191,7 @@ const Profile: FC = () => {
</div>
</div>
<div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7'>
{/* <div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7'>
<div className='flex-1'>
<div>
{t('profile.address')}
@@ -260,7 +254,7 @@ const Profile: FC = () => {
</div>
</div>
</div> */}
<div className='h-20 xl:hidden'></div>
</div>
+2 -2
View File
@@ -72,7 +72,7 @@ const CardtoCard: FC = () => {
label={t('wallet.select_sheba')}
placeholder={t('select')}
items={getBankAccount.data?.data?.bankAccounts?.map((item: any) => ({
label: item.IBan,
label: 'IR' + item.IBan,
value: item.id
}))}
name='bankAccountId'
@@ -84,7 +84,7 @@ const CardtoCard: FC = () => {
<div className='mt-8'>
<Input
label={t('wallet.amount')}
placeholder={t('wallet.enter_amount_card')}
placeholder={t('wallet.enter_amount_sheba')}
name='amount'
onChange={formik.handleChange}
error_text={formik.touched.amount && formik.errors.amount ? formik.errors.amount : ''}