fix build

This commit is contained in:
hamid zarghami
2025-11-17 09:16:08 +03:30
parent 6a7eac4d0c
commit 683c9ff8ad
16 changed files with 28 additions and 572 deletions
+19
View File
@@ -38,6 +38,7 @@
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.33.0", "@eslint/js": "^9.33.0",
"@types/moment-jalaali": "^0.7.9", "@types/moment-jalaali": "^0.7.9",
"@types/node": "^24.10.1",
"@types/react": "^19.1.10", "@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7", "@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.0", "@vitejs/plugin-react": "^5.0.0",
@@ -2156,6 +2157,17 @@
"moment": ">=2.14.0" "moment": ">=2.14.0"
} }
}, },
"node_modules/@types/node": {
"version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.1.11", "version": "19.1.11",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz",
@@ -5159,6 +5171,13 @@
"typescript": ">=4.8.4 <6.0.0" "typescript": ">=4.8.4 <6.0.0"
} }
}, },
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+1
View File
@@ -40,6 +40,7 @@
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.33.0", "@eslint/js": "^9.33.0",
"@types/moment-jalaali": "^0.7.9", "@types/moment-jalaali": "^0.7.9",
"@types/node": "^24.10.1",
"@types/react": "^19.1.10", "@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7", "@types/react-dom": "^19.1.7",
"@vitejs/plugin-react": "^5.0.0", "@vitejs/plugin-react": "^5.0.0",
+1 -1
View File
@@ -90,7 +90,7 @@ const Filters: FC<FiltersProps> = ({
}, [fields, initialValues, onChange]); }, [fields, initialValues, onChange]);
useEffect(() => { useEffect(() => {
const timeouts: Record<string, number> = {}; const timeouts: Record<string, ReturnType<typeof setTimeout>> = {};
Object.keys(inputValues).forEach(fieldName => { Object.keys(inputValues).forEach(fieldName => {
timeouts[fieldName] = setTimeout(() => { timeouts[fieldName] = setTimeout(() => {
-60
View File
@@ -1,60 +0,0 @@
import { type FC } from 'react'
import LogoImage from '../../assets/images/logo.svg'
import LogoSmallImage from '../../assets/images/logo-small.svg'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import RegisterStep1 from './components/RegisterStep1'
import { useAuthStore } from './store/AuthStore'
import RegisterStep2 from './components/RegisterStep2'
const Register: FC = () => {
const { stepLogin } = useAuthStore()
const { t } = useTranslation('global')
return (
<div className='w-full h-full flex justify-center lg:py-[75px] py-4 lg:items-center lg:px-10 px-4'>
<div className='flex w-full max-h-[812px] max-w-[1200px] bg-secondary h-full rounded-3xl overflow-hidden'>
<div className='flex-1 flex flex-col justify-center min-w-[50%] overflow-y-auto bg-white lg:px-9 px-4 py-7'>
<div className=''>
<img src={LogoSmallImage} className='w-8' />
<div className='mt-5'>
<h2 className='text-2xl font-bold'>
{t('auth.welcome')}
</h2>
<p className='text-description text-sm mt-2'>
{t('auth.enter_information')}
</p>
</div>
{
stepLogin === 1 ?
<RegisterStep1 />
:
<RegisterStep2 />
}
<div className='mt-6 flex justify-center gap-2 items-center text-sm'>
<p className='text-description'>
{t('auth.before_registered')}
</p>
<Link to={Pages.auth.login}>
<div>{t('auth.login')}</div>
</Link>
</div>
</div>
</div>
<div className='flex-1 min-w-[50%] lg:flex hidden justify-center items-center'>
<img src={LogoImage} className='h-20' />
</div>
</div>
</div>
)
}
export default Register
-136
View File
@@ -1,136 +0,0 @@
import { FC, Fragment } from 'react'
import { useFormik } from 'formik'
import { RegisterType } from '../types/AuthTypes'
import * as Yup from 'yup'
import { useAuthStore } from '../store/AuthStore'
import { useTranslation } from 'react-i18next'
import Input from '../../../components/Input'
import DatePickerComponent from '../../../components/DatePicker'
import Button from '../../../components/Button'
import { useRegister } from '../hooks/useAuthData'
import { ErrorType } from '../../../helpers/types'
import { toast } from 'react-toastify'
import { Pages } from '../../../config/Pages'
const RegisterStep2: FC = () => {
const { t } = useTranslation('global')
const { phone } = useAuthStore()
const register = useRegister()
const formik = useFormik<RegisterType>({
initialValues: {
firstName: '',
lastName: '',
birthDate: '',
code: 0,
nationalCode: '',
password: '',
phone: phone,
},
validationSchema: Yup.object({
firstName: Yup.string()
.required(t('errors.required')),
lastName: Yup.string()
.required(t('errors.required')),
birthDate: Yup.string()
.required(t('errors.required')),
code: Yup.number()
.required(t('errors.required')),
nationalCode: Yup.string()
.required(t('errors.required')),
password: Yup.string()
.required(t('errors.required')),
phone: Yup.string()
.required(t('errors.required')),
}),
onSubmit(values) {
register.mutate(values, {
onSuccess(data) {
localStorage.setItem(import.meta.env.VITE_TOKEN_NAME, data?.data?.accessToken?.token)
localStorage.setItem(import.meta.env.VITE_REFRESH_TOKEN_NAME, data?.data?.refreshToken?.token)
window.location.href = Pages.dashboard
},
onError(error: ErrorType) {
toast.error(error?.response?.data?.error?.message[0])
},
})
},
})
return (
<Fragment>
<div className='mt-5 rowTwoInput'>
<Input
label={t('auth.name')}
placeholder={t('auth.enter_name')}
name='firstName'
onChange={formik.handleChange}
error_text={formik.touched.firstName && formik.errors.firstName ? formik.errors.firstName : ''}
/>
<Input
label={t('auth.family')}
placeholder={t('auth.enter_family')}
name='lastName'
onChange={formik.handleChange}
error_text={formik.touched.lastName && formik.errors.lastName ? formik.errors.lastName : ''}
/>
</div>
<div className='mt-4 min-w-full rowTwoInput'>
<DatePickerComponent
label={t('auth.dateofbirth')}
onChange={(date: string) => formik.setFieldValue('birthDate', date)}
placeholder={t('auth.select_date')}
error_text={formik.touched.birthDate && formik.errors.birthDate ? formik.errors.birthDate : ''}
/>
<Input
label={t('auth.national_code')}
placeholder={t('auth.national_code_enter')}
name='nationalCode'
onChange={formik.handleChange}
error_text={formik.touched.nationalCode && formik.errors.nationalCode ? formik.errors.nationalCode : ''}
/>
</div>
<div className='mt-4 rowTwoInput'>
<Input
label={t('auth.password')}
placeholder={t('auth.enter_password')}
type='password'
name='password'
onChange={formik.handleChange}
error_text={formik.touched.password && formik.errors.password ? formik.errors.password : ''}
/>
<Input
label={t('auth.phonen_number')}
placeholder={t('auth.enter_phone_number')}
readOnly
value={phone}
/>
</div>
<div className='mt-4 rowTwoInput'>
<Input
label={t('auth.verify_code')}
placeholder={t('auth.enter_verify_code')}
type='tel'
name='code'
onChange={formik.handleChange}
error_text={formik.touched.code && formik.errors.code ? formik.errors.code : ''}
/>
</div>
<Button
label={t('auth.next')}
className='mt-8'
onClick={() => formik.handleSubmit()}
isLoading={register.isPending}
/>
</Fragment>
)
}
export default RegisterStep2
+3 -5
View File
@@ -3,10 +3,8 @@ import Input from '../components/Input'
// import { ArrowDown2, CloseCircle, HambergerMenu, Logout, Wallet } from 'iconsax-react' // import { ArrowDown2, CloseCircle, HambergerMenu, Logout, Wallet } from 'iconsax-react'
// import AvatarImage from '../assets/images/avatar_image.png' // import AvatarImage from '../assets/images/avatar_image.png'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { Pages } from '../config/Pages'
import { useSharedStore } from './store/sharedStore' import { useSharedStore } from './store/sharedStore'
import { HambergerMenu, Wallet } from 'iconsax-react' import { HambergerMenu } from 'iconsax-react'
import { clx } from '@/helpers/utils' import { clx } from '@/helpers/utils'
const Header: FC = () => { const Header: FC = () => {
@@ -44,9 +42,9 @@ const Header: FC = () => {
</div> </div>
{/* <img src={LogoImage} className='h-6 xl:hidden block absolute right-0 left-0 mx-auto' /> */} {/* <img src={LogoImage} className='h-6 xl:hidden block absolute right-0 left-0 mx-auto' /> */}
<div className='flex xl:gap-6 gap-4 items-center'> <div className='flex xl:gap-6 gap-4 items-center'>
<Link className='xl:hidden' to={Pages.wallet}> {/* <Link className='xl:hidden' to={Pages.wallet}>
<Wallet className='xl:size-[18px] size-[17px]' color='black' /> <Wallet className='xl:size-[18px] size-[17px]' color='black' />
</Link> </Link> */}
{/* <Notifications /> */} {/* <Notifications /> */}
{/* { {/* {
data && ( data && (
-50
View File
@@ -1,50 +0,0 @@
import { DocumentText } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { Pages } from '../../config/Pages'
const BlogSubMenu: FC = () => {
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<DocumentText
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.blog')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={'لیست'}
isActive={isActive('list')}
link={Pages.blog.list}
/>
<SubMenuItem
title={'دسته بندی'}
isActive={isActive('create')}
link={Pages.blog.category}
/>
<SubMenuItem
title={'نظرات'}
isActive={isActive('comments')}
link={Pages.blog.comments}
/>
</div>
</div>
)
}
export default BlogSubMenu
+2 -2
View File
@@ -29,12 +29,12 @@ const CustomerSubMenu: FC = () => {
<SubMenuItem <SubMenuItem
title={t('submenu.customer_list')} title={t('submenu.customer_list')}
isActive={isActive('list')} isActive={isActive('list')}
link={Pages.customer.list} link={Pages.orders.list}
/> />
<SubMenuItem <SubMenuItem
title={t('submenu.create_customer')} title={t('submenu.create_customer')}
isActive={isActive('create')} isActive={isActive('create')}
link={Pages.customer.create} link={Pages.orders.add}
/> />
</div> </div>
-52
View File
@@ -1,52 +0,0 @@
import { Teacher } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const LearningSubMenu: FC = () => {
const { t } = useTranslation('global')
const location = useLocation()
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Teacher
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.learning')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('learning.learnings')}
isActive={isActive('list')}
link={Pages.learning.list}
/>
<SubMenuItem
title={t('learning.new_learning')}
isActive={isActive('create')}
link={Pages.learning.create}
/>
<SubMenuItem
title={t('learning.category_learning')}
isActive={isActive('category')}
link={Pages.learning.category}
/>
</div>
</div>
)
}
export default LearningSubMenu
-46
View File
@@ -1,46 +0,0 @@
import { Receipt21 } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const ReceiptSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Receipt21
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('receip.receips')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('receip.receip_list')}
isActive={isActive('list')}
link={Pages.receipts.index}
/>
<SubMenuItem
title={t('receip.add_receip')}
isActive={isActive('create')}
link={Pages.receipts.create}
/>
</div>
</div>
)
}
export default ReceiptSubMenu
-57
View File
@@ -1,57 +0,0 @@
import { Element3 } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const ServicesSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Element3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.services')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.services_list')}
isActive={isActive('list')}
link={Pages.services.list}
/>
<SubMenuItem
title={t('submenu.add_service')}
isActive={isActive('add')}
link={Pages.services.add}
/>
<SubMenuItem
title={t('submenu.service_category')}
isActive={isActive('category')}
link={Pages.services.category}
/>
<SubMenuItem
title={t('submenu.reviews')}
isActive={isActive('reviews')}
link={Pages.services.review}
/>
</div>
</div>
)
}
export default ServicesSubMenu
-47
View File
@@ -1,47 +0,0 @@
import { Headphone } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
import SubMenuItem from './SubMenuItem'
const SupportSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return <div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Headphone
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.support')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.plan_list')}
isActive={isActive('list')}
link={Pages.support.list}
/>
<SubMenuItem
title={t('submenu.create_plan')}
isActive={isActive('create')}
link={Pages.support.create}
/>
</div>
</div>
}
export default SupportSubMenu
-52
View File
@@ -1,52 +0,0 @@
import { Messages3 } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { useLocation } from 'react-router-dom'
import { Pages } from '../../config/Pages'
const TicketSubMenu: FC = () => {
const location = useLocation()
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Messages3
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.ticket')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.ticket_list')}
isActive={isActive('list')}
link={Pages.ticket.list}
/>
<SubMenuItem
title={t('submenu.send_ticket')}
isActive={isActive('create')}
link={Pages.ticket.create}
/>
<SubMenuItem
title={t('submenu.category')}
isActive={isActive('category')}
link={Pages.ticket.category}
/>
</div>
</div>
)
}
export default TicketSubMenu
-64
View File
@@ -1,64 +0,0 @@
import { Profile } from 'iconsax-react'
import { type FC } from 'react'
import { useTranslation } from 'react-i18next'
import SubMenuItem from './SubMenuItem'
import { Pages } from '../../config/Pages'
const UsersSubMenu: FC = () => {
const { t } = useTranslation('global')
const isActive = (name: string) => {
return location.pathname.includes(name)
}
return (
<div className='py-12'>
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
<Profile
size={24}
color='#000'
variant='Bold'
/>
<div className='text-xs'>
{t('sidebar.users')}
</div>
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
title={t('submenu.user_list')}
isActive={isActive('list')}
link={Pages.users.list}
/>
<SubMenuItem
title={t('submenu.add_user')}
isActive={isActive('create')}
link={Pages.users.create}
/>
<SubMenuItem
title={t('submenu.role_list')}
isActive={isActive('all')}
link={Pages.users.roleList}
/>
<SubMenuItem
title={t('submenu.role_create')}
isActive={isActive('roles-add')}
link={Pages.users.roleCreate}
/>
<SubMenuItem
title={t('user.add_user_group')}
isActive={isActive('group-add')}
link={Pages.users.groupAdd}
/>
<SubMenuItem
title={t('user.list_user_group')}
isActive={isActive('groups')}
link={Pages.users.groupList}
/>
</div>
</div>
)
}
export default UsersSubMenu
+1
View File
@@ -1,6 +1,7 @@
export interface IBaseResponse { export interface IBaseResponse {
statusCode: number; statusCode: number;
success: boolean; success: boolean;
status: number;
} }
export interface IResponse<T> extends IBaseResponse { export interface IResponse<T> extends IBaseResponse {
data: T; data: T;
+1
View File
@@ -5,6 +5,7 @@
"lib": ["ES2023"], "lib": ["ES2023"],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"types": ["node"],
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",