financial
This commit is contained in:
@@ -12,6 +12,7 @@ type Props = {
|
|||||||
error_text?: string,
|
error_text?: string,
|
||||||
placeholder?: string,
|
placeholder?: string,
|
||||||
label?: string,
|
label?: string,
|
||||||
|
readOnly?: boolean,
|
||||||
} & SelectHTMLAttributes<HTMLSelectElement>
|
} & SelectHTMLAttributes<HTMLSelectElement>
|
||||||
|
|
||||||
const Select: FC<Props> = (props: Props) => {
|
const Select: FC<Props> = (props: Props) => {
|
||||||
@@ -25,6 +26,7 @@ const Select: FC<Props> = (props: Props) => {
|
|||||||
}
|
}
|
||||||
<select {...props} className={clx(
|
<select {...props} className={clx(
|
||||||
'w-full text-black relative block border appearance-none border-border px-2.5 h-10 text-sm rounded-2.5 bg-gray',
|
'w-full text-black relative block border appearance-none border-border px-2.5 h-10 text-sm rounded-2.5 bg-gray',
|
||||||
|
props.readOnly && 'bg-gray-100 border-0 text-description',
|
||||||
props.className,
|
props.className,
|
||||||
props.label && 'mt-1'
|
props.label && 'mt-1'
|
||||||
)}>
|
)}>
|
||||||
@@ -45,7 +47,7 @@ const Select: FC<Props> = (props: Props) => {
|
|||||||
</select>
|
</select>
|
||||||
<ArrowDown2 size={16} color='black' className={clx(
|
<ArrowDown2 size={16} color='black' className={clx(
|
||||||
'absolute z-0 top-3 left-2',
|
'absolute z-0 top-3 left-2',
|
||||||
props.label && 'top-10'
|
props.label && 'top-9'
|
||||||
)} />
|
)} />
|
||||||
{
|
{
|
||||||
props.error_text && props.error_text !== '' ?
|
props.error_text && props.error_text !== '' ?
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const Tabs: FC<Props> = (props: Props) => {
|
|||||||
<SwiperSlide style={SWIPER_SLIDE_STYLE} onClick={() => props.onChange(item.value)} key={item.value} className={clx(
|
<SwiperSlide style={SWIPER_SLIDE_STYLE} onClick={() => props.onChange(item.value)} key={item.value} className={clx(
|
||||||
'flex flex-col max-w-fit mt-[15px] items-center gap-2 cursor-pointer',
|
'flex flex-col max-w-fit mt-[15px] items-center gap-2 cursor-pointer',
|
||||||
index === 0 && 'pr-[30px]',
|
index === 0 && 'pr-[30px]',
|
||||||
index === props.items.length - 1 && 'pl-[30px]',
|
index === props.items.length - 1 && props.items.length > 3 && 'pl-[30px]',
|
||||||
props.active === item.value && 'text-black'
|
props.active === item.value && 'text-black'
|
||||||
)}>
|
)}>
|
||||||
{item.icon}
|
{item.icon}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { FC, InputHTMLAttributes } from 'react'
|
import { FC, InputHTMLAttributes } from 'react'
|
||||||
import Error from './Error'
|
import Error from './Error'
|
||||||
|
import { clx } from '../helpers/utils'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label: string,
|
label: string,
|
||||||
@@ -14,7 +15,11 @@ const Textarea: FC<Props> = (props: Props) => {
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
className='border border-border leading-7 w-full rounded-xl px-4 py-3 min-h-[100px] mt-1 text-xs'
|
className={clx(
|
||||||
|
'border border-border leading-7 w-full rounded-xl px-4 py-3 min-h-[100px] mt-1 text-xs',
|
||||||
|
props.readOnly && 'bg-gray-100 border-0 text-description'
|
||||||
|
)}
|
||||||
|
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|||||||
+34
-1
@@ -320,5 +320,38 @@
|
|||||||
},
|
},
|
||||||
"email": "ایمیل",
|
"email": "ایمیل",
|
||||||
"save": "ذخیره",
|
"save": "ذخیره",
|
||||||
"select": "انتخاب"
|
"select": "انتخاب",
|
||||||
|
"financial": {
|
||||||
|
"financial": "مشخصات مالی",
|
||||||
|
"legal": "حقوقی",
|
||||||
|
"personal": "حقیقی",
|
||||||
|
"info_company": "اطلاعات ثبتی شرکت",
|
||||||
|
"enter_info_your_company": "اطلاعت شرکت خود را با دقت وارد کنید.",
|
||||||
|
"company_name": "نام ثبتی شرکت",
|
||||||
|
"company_code": "کد ثبتی شرکت",
|
||||||
|
"national_id": "شناسه ملی",
|
||||||
|
"economic_code": "کد اقتصادی",
|
||||||
|
"company_contact_info": "اطلاعات تماس شرکت",
|
||||||
|
"company_contact_address": "اطلاعت تماس و آدرس شرکت خود را با دقت وارد کنید.",
|
||||||
|
"company_phone": "شماره تماس",
|
||||||
|
"company_postal_code": "کد پستی",
|
||||||
|
"address": "آدرس",
|
||||||
|
"personal_information": "مشخصات فردی",
|
||||||
|
"enter_your_personal_information": "مشخصات فردی خود را با دقت وارد کنید.",
|
||||||
|
"name": "نام",
|
||||||
|
"family": "نام خانوادگی",
|
||||||
|
"sex": "جنسیت",
|
||||||
|
"father_name": "نام پدر",
|
||||||
|
"phone_number": "شماره تماس",
|
||||||
|
"national_code": "کد ملی",
|
||||||
|
"date_of_birth": "تاریخ تولد",
|
||||||
|
"nationality": "ملیت",
|
||||||
|
"enter_address": " آدرس خود را با دقت وارد کنید.",
|
||||||
|
"state": "استان",
|
||||||
|
"city": "شهر",
|
||||||
|
"notice_cannot_edit": "ویرایش مشخصات فردی بعد از تکمیل اطلاعات امکان پذیر نیست"
|
||||||
|
},
|
||||||
|
"man": "مرد",
|
||||||
|
"woman": "زن",
|
||||||
|
"success": "عملیات با موفقیت انجام شد"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import * as api from "../service/AdsService";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
export const useGetAds = (location: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["ads", location],
|
||||||
|
queryFn: () => api.getAds(location),
|
||||||
|
enabled: !!location,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import axios from "../../../config/axios";
|
||||||
|
|
||||||
|
export const getAds = async (location: string) => {
|
||||||
|
const { data } = await axios.get(
|
||||||
|
`/advertise/by-location?location=${location}`
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export enum AdsDisplayLocation {
|
||||||
|
HOMEPAGE_TOP = "HOMEPAGE_TOP",
|
||||||
|
SINGLE_SERVICE_PAGE = "SINGLE_SERVICE_PAGE",
|
||||||
|
MY_SERVICES_PAGE = "MY_SERVICES_PAGE",
|
||||||
|
OTHER_SERVICES_TOP = "OTHER_SERVICES_TOP",
|
||||||
|
OTHER_SERVICES_LEFT = "OTHER_SERVICES_LEFT",
|
||||||
|
SERVICE = "SERVICE",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AdsItemType = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
imageUrl: string;
|
||||||
|
link: string;
|
||||||
|
isActive: boolean;
|
||||||
|
createdAt: string;
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
displayLocation: AdsDisplayLocation;
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { FC, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Tabs from '../../components/Tabs'
|
||||||
|
import { ProfileCircle, UserTag } from 'iconsax-react'
|
||||||
|
import Legal from './components/Legal'
|
||||||
|
import Personal from './components/Personal'
|
||||||
|
|
||||||
|
const Financial: FC = () => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
const [activeTab, setActiveTab] = useState('legal')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-4'>
|
||||||
|
<div>
|
||||||
|
{t('financial.financial')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8'>
|
||||||
|
<Tabs
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
icon: <UserTag color={activeTab === 'legal' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
|
label: t('financial.legal'),
|
||||||
|
value: 'legal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <ProfileCircle color={activeTab === 'personal' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
|
label: t('financial.legal'),
|
||||||
|
value: 'personal'
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
active={activeTab}
|
||||||
|
onChange={setActiveTab}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
activeTab === 'legal' ?
|
||||||
|
<Legal />
|
||||||
|
:
|
||||||
|
<Personal />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Financial
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
import { FC, Fragment, useEffect, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Input from '../../../components/Input'
|
||||||
|
import { useFormik } from 'formik'
|
||||||
|
import Textarea from '../../../components/Textarea'
|
||||||
|
import Button from '../../../components/Button'
|
||||||
|
import { TickCircle } from 'iconsax-react'
|
||||||
|
import { CreateLegalUserType, ProvinesItemType } from '../types/FinancialTypes'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
import { useCreateLegalUser, useGetCities, useGetFinancialInfo, useGetProvines } from '../hooks/useFinancialData'
|
||||||
|
import Select from '../../../components/Select'
|
||||||
|
import PageLoading from '../../../components/PageLoading'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
|
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 getCities = useGetCities(provinesId)
|
||||||
|
const createLegalUser = useCreateLegalUser()
|
||||||
|
|
||||||
|
const formik = useFormik<CreateLegalUserType>({
|
||||||
|
initialValues: {
|
||||||
|
address: '',
|
||||||
|
cityId: '',
|
||||||
|
companyRegisteredName: '',
|
||||||
|
economicCode: '',
|
||||||
|
nationalId: '',
|
||||||
|
number: '',
|
||||||
|
postalCode: '',
|
||||||
|
registrationId: ''
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object({
|
||||||
|
address: Yup.string().required(t('errors.required')),
|
||||||
|
cityId: Yup.string().required(t('errors.required')),
|
||||||
|
companyRegisteredName: 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')),
|
||||||
|
postalCode: Yup.string().required(t('errors.required')),
|
||||||
|
registrationId: Yup.string().required(t('errors.required'))
|
||||||
|
}),
|
||||||
|
onSubmit: values => {
|
||||||
|
createLegalUser.mutate(values, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success(t('success'))
|
||||||
|
window.location.reload()
|
||||||
|
},
|
||||||
|
onError(error: ErrorType) {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if (getFinancialInfo.data?.data?.user?.legalUser) {
|
||||||
|
setIsReadOnly(true)
|
||||||
|
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])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='bg-white rounded-3xl xl:p-6 p-4 mt-8 text-sm'>
|
||||||
|
{
|
||||||
|
getProvines.isPending || getFinancialInfo.isPending ?
|
||||||
|
<PageLoading />
|
||||||
|
:
|
||||||
|
<Fragment>
|
||||||
|
<div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7 border-b pb-7'>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<div>
|
||||||
|
{t('financial.info_company')}
|
||||||
|
</div>
|
||||||
|
<div className='text-description text-xs mt-2'>
|
||||||
|
{t('financial.enter_info_your_company')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<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 : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={t('financial.economic_code')}
|
||||||
|
{...formik.getFieldProps('economicCode')}
|
||||||
|
error_text={formik.touched.economicCode && formik.errors.economicCode ? formik.errors.economicCode : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7 pb-7'>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<div>
|
||||||
|
{t('financial.company_contact_info')}
|
||||||
|
</div>
|
||||||
|
<div className='text-description text-xs mt-2'>
|
||||||
|
{t('financial.company_contact_address')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex-1'>
|
||||||
|
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3'>
|
||||||
|
<Select
|
||||||
|
value={provinesId}
|
||||||
|
label={t('financial.state')}
|
||||||
|
placeholder={t('select')}
|
||||||
|
items={getProvines.data?.data?.provinces.map((item: ProvinesItemType) => ({ label: item.name, value: item.id }))}
|
||||||
|
onChange={(e) => setProvinesId(e.target.value)}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label={t('financial.city')}
|
||||||
|
placeholder={t('select')}
|
||||||
|
items={getCities.data?.data?.cities ? getCities.data?.data?.cities.map((item: ProvinesItemType) => ({ label: item.name, value: item.id })) : []}
|
||||||
|
{...formik.getFieldProps('cityId')}
|
||||||
|
error_text={formik.touched.cityId && formik.errors.cityId ? formik.errors.cityId : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={t('financial.company_postal_code')}
|
||||||
|
{...formik.getFieldProps('postalCode')}
|
||||||
|
error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
|
||||||
|
<Textarea
|
||||||
|
{...formik.getFieldProps('address')}
|
||||||
|
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''}
|
||||||
|
label={t('financial.address')}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
!isReadOnly &&
|
||||||
|
<div className='mt-8 flex justify-end'>
|
||||||
|
<Button
|
||||||
|
className='w-fit px-7'
|
||||||
|
onClick={() => formik.handleSubmit()}
|
||||||
|
isLoading={createLegalUser.isPending}
|
||||||
|
>
|
||||||
|
<div className='flex gap-2 items-center'>
|
||||||
|
<TickCircle
|
||||||
|
size={24}
|
||||||
|
color='white'
|
||||||
|
/>
|
||||||
|
<div>{t('save')}</div>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Legal
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
import { useFormik } from 'formik'
|
||||||
|
import { FC, useEffect, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Input from '../../../components/Input'
|
||||||
|
import Select from '../../../components/Select'
|
||||||
|
import Textarea from '../../../components/Textarea'
|
||||||
|
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 { toast } from 'react-toastify'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
|
||||||
|
const Personal: FC = () => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
|
||||||
|
const [isReadOnly, setIsReadOnly] = useState<boolean>(false)
|
||||||
|
const [provinesId, setProvinesId] = useState<string>('')
|
||||||
|
const getFinancialInfo = useGetFinancialInfo()
|
||||||
|
const createRealUser = useCreateRealUser()
|
||||||
|
const getProvines = useGetProvines()
|
||||||
|
const getCities = useGetCities(provinesId)
|
||||||
|
|
||||||
|
const formik = useFormik<CreateRealUserType>({
|
||||||
|
initialValues: {
|
||||||
|
address: '',
|
||||||
|
cityId: '',
|
||||||
|
fatherName: '',
|
||||||
|
gender: '',
|
||||||
|
nationality: '',
|
||||||
|
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')),
|
||||||
|
gender: Yup.string().required(t('errors.required')),
|
||||||
|
nationality: Yup.string().required(t('errors.required')),
|
||||||
|
postalCode: Yup.string().required(t('errors.required'))
|
||||||
|
}),
|
||||||
|
onSubmit: values => {
|
||||||
|
createRealUser.mutate(values, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success(t('success'))
|
||||||
|
window.location.reload()
|
||||||
|
},
|
||||||
|
onError(error: ErrorType) {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if (getFinancialInfo.data?.data?.user?.realUser) {
|
||||||
|
const data = getFinancialInfo.data?.data?.user
|
||||||
|
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
|
||||||
|
})
|
||||||
|
setProvinesId(data?.address?.city?.province?.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [getFinancialInfo.data])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='bg-white rounded-3xl xl:p-6 p-4 mt-8 text-sm'>
|
||||||
|
<div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7 border-b pb-7'>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<div>
|
||||||
|
{t('financial.personal_information')}
|
||||||
|
</div>
|
||||||
|
<div className='text-description text-xs mt-2'>
|
||||||
|
{t('financial.enter_your_personal_information')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex-1'>
|
||||||
|
{/* <div className='flex items-end 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 : ''}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={t('financial.family')}
|
||||||
|
{...formik.getFieldProps('company_name')}
|
||||||
|
error_text={formik.touched.company_name && formik.errors.company_name ? formik.errors.company_name : ''}
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3'>
|
||||||
|
<Select
|
||||||
|
label={t('financial.sex')}
|
||||||
|
placeholder={t('select')}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: t('man'),
|
||||||
|
value: 'male'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('woman'),
|
||||||
|
value: 'female'
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
{...formik.getFieldProps('gender')}
|
||||||
|
error_text={formik.touched.gender && formik.errors.gender ? formik.errors.gender : ''}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={t('financial.father_name')}
|
||||||
|
{...formik.getFieldProps('fatherName')}
|
||||||
|
error_text={formik.touched.fatherName && formik.errors.fatherName ? formik.errors.fatherName : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <div className='flex items-end 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 : ''}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<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 : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <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 : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label={t('financial.company_postal_code')}
|
||||||
|
{...formik.getFieldProps('postalCode')}
|
||||||
|
error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8 flex xl:flex-row flex-col xl:gap-0 gap-7 pb-7'>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<div>
|
||||||
|
{t('financial.address')}
|
||||||
|
</div>
|
||||||
|
<div className='text-description text-xs mt-2'>
|
||||||
|
{t('financial.enter_address')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex-1'>
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3'>
|
||||||
|
<Select
|
||||||
|
value={provinesId}
|
||||||
|
label={t('financial.state')}
|
||||||
|
placeholder={t('select')}
|
||||||
|
items={getProvines.data?.data?.provinces.map((item: ProvinesItemType) => ({ label: item.name, value: item.id }))}
|
||||||
|
onChange={(e) => setProvinesId(e.target.value)}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label={t('financial.city')}
|
||||||
|
placeholder={t('select')}
|
||||||
|
items={getCities.data?.data?.cities ? getCities.data?.data?.cities.map((item: ProvinesItemType) => ({ label: item.name, value: item.id })) : []}
|
||||||
|
{...formik.getFieldProps('cityId')}
|
||||||
|
error_text={formik.touched.cityId && formik.errors.cityId ? formik.errors.cityId : ''}
|
||||||
|
readOnly={isReadOnly}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8'>
|
||||||
|
<Input
|
||||||
|
label={t('financial.company_postal_code')}
|
||||||
|
{...formik.getFieldProps('postalCode')}
|
||||||
|
error_text={formik.touched.postalCode && formik.errors.postalCode ? formik.errors.postalCode : ''}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex items-end xl:gap-6 gap-3 mt-8'>
|
||||||
|
<Textarea
|
||||||
|
{...formik.getFieldProps('address')}
|
||||||
|
error_text={formik.touched.address && formik.errors.address ? formik.errors.address : ''}
|
||||||
|
label={t('financial.address')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8 h-10 text-xs bg-[#FFF2F2] text-[#DB0105] rounded-xl px-4 flex gap-2 items-center'>
|
||||||
|
<InfoCircle
|
||||||
|
size={18}
|
||||||
|
color='#DB0105'
|
||||||
|
/>
|
||||||
|
<div>{t('financial.notice_cannot_edit')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-8 flex justify-end'>
|
||||||
|
<Button
|
||||||
|
className='w-fit px-7'
|
||||||
|
onClick={() => formik.handleSubmit()}
|
||||||
|
isLoading={createRealUser.isPending}
|
||||||
|
>
|
||||||
|
<div className='flex gap-2 items-center'>
|
||||||
|
<TickCircle
|
||||||
|
size={24}
|
||||||
|
color='white'
|
||||||
|
/>
|
||||||
|
<div>{t('save')}</div>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Personal
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
|
import * as api from "../service/FinancialService";
|
||||||
|
import {
|
||||||
|
CreateLegalUserType,
|
||||||
|
CreateRealUserType,
|
||||||
|
} from "../types/FinancialTypes";
|
||||||
|
|
||||||
|
export const useCreateLegalUser = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (variables: CreateLegalUserType) =>
|
||||||
|
api.createLegalUser(variables),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetProvines = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["provines"],
|
||||||
|
queryFn: () => api.getProvines(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCreateRealUser = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (variables: CreateRealUserType) =>
|
||||||
|
api.createRealUser(variables),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetCities = (provincesId: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["cities", provincesId],
|
||||||
|
queryFn: () => api.getCities(provincesId),
|
||||||
|
enabled: !!provincesId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetFinancialInfo = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["financial-info"],
|
||||||
|
queryFn: () => api.getFinancialInfo(),
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import axios from "../../../config/axios";
|
||||||
|
import {
|
||||||
|
CreateLegalUserType,
|
||||||
|
CreateRealUserType,
|
||||||
|
} from "../types/FinancialTypes";
|
||||||
|
|
||||||
|
export const createLegalUser = async (params: CreateLegalUserType) => {
|
||||||
|
const { data } = await axios.post(`/users/legal-user`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createRealUser = async (params: CreateRealUserType) => {
|
||||||
|
const { data } = await axios.post(`/users/real-user`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getProvines = async () => {
|
||||||
|
const { data } = await axios.get(`/address/provinces/list?limit=50`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCities = async (id: string) => {
|
||||||
|
const { data } = await axios.get(`/address/provinces/${id}/cities`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getFinancialInfo = async () => {
|
||||||
|
const { data } = await axios.get(`/users/me/financial-info`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export type CreateRealUserType = {
|
||||||
|
gender: string;
|
||||||
|
fatherName: string;
|
||||||
|
nationality: string;
|
||||||
|
address: string;
|
||||||
|
postalCode: string;
|
||||||
|
cityId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateLegalUserType = {
|
||||||
|
economicCode: string;
|
||||||
|
companyRegisteredName: string;
|
||||||
|
registrationId: string;
|
||||||
|
nationalId: string;
|
||||||
|
number: string;
|
||||||
|
postalCode: string;
|
||||||
|
address: string;
|
||||||
|
cityId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProvinesItemType = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
+22
-36
@@ -1,5 +1,4 @@
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import BannerImage from '../../assets/images/banner.png'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ArrowLeft, Element3, Messages3, NotificationStatus, Teacher } from 'iconsax-react'
|
import { ArrowLeft, Element3, Messages3, NotificationStatus, Teacher } from 'iconsax-react'
|
||||||
import ItemDashboard from './components/ItemDashboard'
|
import ItemDashboard from './components/ItemDashboard'
|
||||||
@@ -8,66 +7,53 @@ import AccessbilityImage from '../../assets/images/accessbility.jpg'
|
|||||||
import BoxNewAccessbility from './components/BoxNewAccessbility'
|
import BoxNewAccessbility from './components/BoxNewAccessbility'
|
||||||
import DanakLearning from './components/DanakLearning'
|
import DanakLearning from './components/DanakLearning'
|
||||||
import { Carousel } from "@material-tailwind/react";
|
import { Carousel } from "@material-tailwind/react";
|
||||||
|
import { useGetAds } from '../ads/hooks/useAdsData'
|
||||||
|
import { AdsDisplayLocation, AdsItemType } from '../ads/types/AdsTypes'
|
||||||
|
|
||||||
|
|
||||||
const Home: FC = () => {
|
const Home: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
|
const getAds = useGetAds(AdsDisplayLocation.HOMEPAGE_TOP)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex gap-6'>
|
<div className='w-full flex gap-6'>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
<Carousel prevArrow={() => null} nextArrow={() => null} autoplay={false} className="rounded-xl h-fit dltr" placeholder="" onPointerEnterCapture={() => { }} onPointerLeaveCapture={() => { }} >
|
<Carousel autoplay className="rounded-xl h-fit dltr" placeholder="" onPointerEnterCapture={() => { }} onPointerLeaveCapture={() => { }} >
|
||||||
<div className='relative drtl'>
|
{
|
||||||
<img src={BannerImage} className='w-full rounded-3xl' />
|
getAds.data?.data?.ads?.map((item: AdsItemType) => {
|
||||||
<div className='absolute size-full top-0 right-0 xl:py-6 py-4 xl:px-8 px-4 flex flex-col xl:justify-between'>
|
return (
|
||||||
<div className='sm:flex hidden justify-end w-full'>
|
<div key={item.id} className='relative drtl'>
|
||||||
<button className="xl:px-8 px-4 w-fit xl:py-1.5 py-1 bg-white bg-opacity-10 text-white xl:text-sm text-xs rounded-full shadow-md ">
|
<img src={item.imageUrl} className='w-full max-h-[300px] h-full object-cover rounded-3xl' />
|
||||||
|
<div className='absolute bg-black bg-opacity-20 size-full top-0 right-0 py-6 px-8 flex flex-col justify-between'>
|
||||||
|
<button className="px-8 w-fit py-1.5 bg-white bg-opacity-10 text-white text-sm rounded-full shadow-md ">
|
||||||
{t('home.new')}
|
{t('home.new')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
||||||
<div className='xl:tetx-base leading-7 text-xs truncate xl:overflow-auto'>
|
<div>
|
||||||
سفارش نرمافزار اختصاصی: سرمایهای برای آینده یا فقط هزینهای برای امروز؟
|
{item.title}
|
||||||
</div>
|
</div>
|
||||||
<div className='xl:mt-3 mt-2 text-border text-xs'>
|
<div className='mt-3 text-border text-xs'>
|
||||||
۸ دقیقه مطالعه
|
۸ دقیقه مطالعه
|
||||||
</div>
|
</div>
|
||||||
<button className='xl:mt-3 mt-2 xl:px-4 px-2 xl:h-9 h-6 flex gap-2 items-center xl:text-xs text-[10px] xl:rounded-2.5 rounded-lg bg-black text-white'>
|
{
|
||||||
|
<a href={item.link}>
|
||||||
|
<button className='mt-3 px-4 h-9 flex gap-2 items-center text-xs rounded-2.5 bg-black text-white'>
|
||||||
<div>
|
<div>
|
||||||
{t('home.study')}
|
{t('home.study')}
|
||||||
</div>
|
</div>
|
||||||
<ArrowLeft size={14} color='white' />
|
<ArrowLeft size={14} color='white' />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
}
|
||||||
</div>
|
|
||||||
<div className='relative drtl'>
|
|
||||||
<img src={BannerImage} className='w-full rounded-3xl' />
|
|
||||||
<div className='absolute size-full top-0 right-0 xl:py-6 py-4 xl:px-8 px-4 flex flex-col xl:justify-between'>
|
|
||||||
<div className='sm:flex hidden justify-end w-full'>
|
|
||||||
<button className="xl:px-8 px-4 w-fit xl:py-1.5 py-1 bg-white bg-opacity-10 text-white xl:text-sm text-xs rounded-full shadow-md ">
|
|
||||||
{t('home.new')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
|
||||||
<div className='xl:tetx-base leading-7 text-xs truncate xl:overflow-auto'>
|
|
||||||
سفارش نرمافزار اختصاصی: سرمایهای برای آینده یا فقط هزینهای برای امروز؟
|
|
||||||
</div>
|
|
||||||
<div className='xl:mt-3 mt-2 text-border text-xs'>
|
|
||||||
۸ دقیقه مطالعه
|
|
||||||
</div>
|
|
||||||
<button className='xl:mt-3 mt-2 xl:px-4 px-2 xl:h-9 h-6 flex gap-2 items-center xl:text-xs text-[10px] xl:rounded-2.5 rounded-lg bg-black text-white'>
|
|
||||||
<div>
|
|
||||||
{t('home.study')}
|
|
||||||
</div>
|
|
||||||
<ArrowLeft size={14} color='white' />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
</Carousel>
|
</Carousel>
|
||||||
|
|
||||||
<div className='mt-8 flex-wrap text-sm flex gap-6 items-center'>
|
<div className='mt-8 flex-wrap text-sm flex gap-6 items-center'>
|
||||||
|
|||||||
@@ -105,13 +105,13 @@ const Profile: FC = () => {
|
|||||||
label={t('profile.date_of_birth')}
|
label={t('profile.date_of_birth')}
|
||||||
onChange={() => { }}
|
onChange={() => { }}
|
||||||
placeholder=''
|
placeholder=''
|
||||||
defaulValue='1400-01-01'
|
defaulValue={getProfile.data?.data?.user?.birthDate}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='xl:mt-7 mt-4'>
|
<div className='xl:mt-7 mt-4'>
|
||||||
<Input
|
<Input
|
||||||
label={t('profile.national_code')}
|
label={t('profile.national_code')}
|
||||||
value={'۰۰۱۲۳۴۵۳۴۴'}
|
value={getProfile.data?.data?.user?.nationalCode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { Carousel } from '@material-tailwind/react'
|
import { Carousel } from '@material-tailwind/react'
|
||||||
import { FC, Fragment } from 'react'
|
import { FC, Fragment } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import BannerImage from '../../assets/images/banner2.jpeg'
|
|
||||||
import RobotImage from '../../assets/images/robot.jpeg'
|
|
||||||
import { ArrowLeft } from 'iconsax-react'
|
import { ArrowLeft } from 'iconsax-react'
|
||||||
import TitleLine from '../../components/TitleLine'
|
import TitleLine from '../../components/TitleLine'
|
||||||
import { useGetSuggestedServices } from './hooks/useServiceData'
|
import { useGetSuggestedServices } from './hooks/useServiceData'
|
||||||
@@ -10,6 +8,8 @@ import PageLoading from '../../components/PageLoading'
|
|||||||
import { ItemServiceType } from './types/ServiecTypes'
|
import { ItemServiceType } from './types/ServiecTypes'
|
||||||
import ServiceItem from '../../components/ServiceItem'
|
import ServiceItem from '../../components/ServiceItem'
|
||||||
import OtherServicesComponent from './components/OtherServices'
|
import OtherServicesComponent from './components/OtherServices'
|
||||||
|
import { useGetAds } from '../ads/hooks/useAdsData'
|
||||||
|
import { AdsDisplayLocation, AdsItemType } from '../ads/types/AdsTypes'
|
||||||
|
|
||||||
|
|
||||||
const OtherServices: FC = () => {
|
const OtherServices: FC = () => {
|
||||||
@@ -17,22 +17,23 @@ const OtherServices: FC = () => {
|
|||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
|
|
||||||
const getSuggestedServices = useGetSuggestedServices()
|
const getSuggestedServices = useGetSuggestedServices()
|
||||||
|
const getAds = useGetAds(AdsDisplayLocation.OTHER_SERVICES_TOP)
|
||||||
|
const getAdsLeft = useGetAds(AdsDisplayLocation.OTHER_SERVICES_LEFT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full flex gap-6'>
|
<div className='w-full flex gap-6'>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
{
|
{
|
||||||
getSuggestedServices.isPending ?
|
getSuggestedServices.isPending || getAdsLeft.isPending ?
|
||||||
<PageLoading />
|
<PageLoading />
|
||||||
:
|
:
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Carousel autoplay className="rounded-xl h-fit dltr" placeholder="" onPointerEnterCapture={() => { }} onPointerLeaveCapture={() => { }} >
|
<Carousel autoplay className="rounded-xl h-fit dltr" placeholder="" onPointerEnterCapture={() => { }} onPointerLeaveCapture={() => { }} >
|
||||||
<div className='relative drtl'>
|
{
|
||||||
<img src={BannerImage} className='w-full max-h-[300px] h-full object-cover rounded-3xl' />
|
getAds.data?.data?.ads?.map((item: AdsItemType) => {
|
||||||
|
return (
|
||||||
|
<div key={item.id} className='relative drtl'>
|
||||||
|
<img src={item.imageUrl} className='w-full max-h-[300px] h-full object-cover rounded-3xl' />
|
||||||
<div className='absolute bg-black bg-opacity-20 size-full top-0 right-0 py-6 px-8 flex flex-col justify-between'>
|
<div className='absolute bg-black bg-opacity-20 size-full top-0 right-0 py-6 px-8 flex flex-col justify-between'>
|
||||||
<button className="px-8 w-fit py-1.5 bg-white bg-opacity-10 text-white text-sm rounded-full shadow-md ">
|
<button className="px-8 w-fit py-1.5 bg-white bg-opacity-10 text-white text-sm rounded-full shadow-md ">
|
||||||
{t('home.new')}
|
{t('home.new')}
|
||||||
@@ -40,43 +41,28 @@ const OtherServices: FC = () => {
|
|||||||
|
|
||||||
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
||||||
<div>
|
<div>
|
||||||
سفارش نرمافزار اختصاصی: سرمایهای برای آینده یا فقط هزینهای برای امروز؟
|
{item.title}
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-3 text-border text-xs'>
|
<div className='mt-3 text-border text-xs'>
|
||||||
۸ دقیقه مطالعه
|
۸ دقیقه مطالعه
|
||||||
</div>
|
</div>
|
||||||
|
{
|
||||||
|
<a href={item.link}>
|
||||||
<button className='mt-3 px-4 h-9 flex gap-2 items-center text-xs rounded-2.5 bg-black text-white'>
|
<button className='mt-3 px-4 h-9 flex gap-2 items-center text-xs rounded-2.5 bg-black text-white'>
|
||||||
<div>
|
<div>
|
||||||
{t('home.study')}
|
{t('home.study')}
|
||||||
</div>
|
</div>
|
||||||
<ArrowLeft size={14} color='white' />
|
<ArrowLeft size={14} color='white' />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
}
|
||||||
</div>
|
|
||||||
<div className='relative drtl'>
|
|
||||||
<img src={BannerImage} className='w-full max-h-[300px] object-cover rounded-3xl' />
|
|
||||||
<div className='absolute bg-black bg-opacity-20 size-full top-0 right-0 py-6 px-8 flex flex-col justify-between'>
|
|
||||||
<button className="px-8 w-fit py-1.5 bg-white bg-opacity-10 text-white text-sm rounded-full shadow-md ">
|
|
||||||
{t('home.new')}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div className='max-w-[340px] font-medium text-white text-lg leading-10'>
|
|
||||||
<div>
|
|
||||||
سفارش نرمافزار اختصاصی: سرمایهای برای آینده یا فقط هزینهای برای امروز؟
|
|
||||||
</div>
|
|
||||||
<div className='mt-3 text-border text-xs'>
|
|
||||||
۸ دقیقه مطالعه
|
|
||||||
</div>
|
|
||||||
<button className='mt-3 px-4 h-9 flex gap-2 items-center text-xs rounded-2.5 bg-black text-white'>
|
|
||||||
<div>
|
|
||||||
{t('home.study')}
|
|
||||||
</div>
|
|
||||||
<ArrowLeft size={14} color='white' />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
</Carousel>
|
</Carousel>
|
||||||
|
|
||||||
|
|
||||||
@@ -108,18 +94,21 @@ const OtherServices: FC = () => {
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{
|
||||||
|
getAdsLeft.isSuccess && getAdsLeft.data.data.ads[0] &&
|
||||||
<div className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
|
<div className='bg-white w-sidebar h-fit hidden xl:block rounded-3xl overflow-hidden relative'>
|
||||||
<img
|
<img
|
||||||
src={RobotImage}
|
src={getAdsLeft.data.data.ads[0].imageUrl}
|
||||||
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
className='w-full backdrop-blur-[100px] h-[550px] object-cover'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='absolute flex items-center px-4 w-full bottom-0 h-[86px] bg-black bg-opacity-5 backdrop-blur-[14px]'>
|
<div className='absolute flex items-center px-4 w-full bottom-0 h-[86px] bg-black bg-opacity-5 backdrop-blur-[14px]'>
|
||||||
<div className='max-w-[80%] text-sm leading-6 text-white'>
|
<div className='max-w-[80%] text-sm leading-6 text-white'>
|
||||||
سفارش نرمافزار اختصاصی: سرمایهای برای آینده یا فقط هزینهای برای امروز؟
|
{getAdsLeft.data.data.ads[0].title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import DetailService from '../pages/service/DetailService'
|
|||||||
import TicketList from '../pages/ticket/TicketList'
|
import TicketList from '../pages/ticket/TicketList'
|
||||||
import CreateTicket from '../pages/ticket/CreateTicket'
|
import CreateTicket from '../pages/ticket/CreateTicket'
|
||||||
import TicketDetail from '../pages/ticket/Detail'
|
import TicketDetail from '../pages/ticket/Detail'
|
||||||
|
import Financial from '../pages/financial/Financial'
|
||||||
|
|
||||||
const MainRouter: FC = () => {
|
const MainRouter: FC = () => {
|
||||||
return (
|
return (
|
||||||
@@ -51,6 +52,7 @@ const MainRouter: FC = () => {
|
|||||||
<Route path={Pages.setting} element={<Setting />} />
|
<Route path={Pages.setting} element={<Setting />} />
|
||||||
<Route path={Pages.wallet} element={<Wallet />} />
|
<Route path={Pages.wallet} element={<Wallet />} />
|
||||||
<Route path={Pages.profile} element={<Profile />} />
|
<Route path={Pages.profile} element={<Profile />} />
|
||||||
|
<Route path={Pages.financial} element={<Financial />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user