login v1
This commit is contained in:
Generated
+74
-2
@@ -13,6 +13,8 @@
|
|||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-i18next": "^15.2.0",
|
"react-i18next": "^15.2.0",
|
||||||
|
"react-loading": "^2.0.3",
|
||||||
|
"react-multi-date-picker": "^4.5.2",
|
||||||
"react-router-dom": "^7.1.0",
|
"react-router-dom": "^7.1.0",
|
||||||
"react-toastify": "^11.0.2",
|
"react-toastify": "^11.0.2",
|
||||||
"tailwind-merge": "^2.5.5"
|
"tailwind-merge": "^2.5.5"
|
||||||
@@ -2905,7 +2907,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
@@ -3035,6 +3036,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -3168,7 +3182,6 @@
|
|||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -3505,6 +3518,18 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
@@ -3545,6 +3570,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-date-object": {
|
||||||
|
"version": "2.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-date-object/-/react-date-object-2.1.9.tgz",
|
||||||
|
"integrity": "sha512-BHxD/quWOTo9fLKV/cfL/M31ePoj4a1JaJ/CnOf8Ndg3mrkh4x9wEMMkCfTrzduxDOgU8ZgR8uarhqI5G71sTg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.0.0",
|
"version": "19.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
||||||
@@ -3557,6 +3588,16 @@
|
|||||||
"react": "^19.0.0"
|
"react": "^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-element-popper": {
|
||||||
|
"version": "2.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-element-popper/-/react-element-popper-2.1.7.tgz",
|
||||||
|
"integrity": "sha512-tuM2OxKlW32h+6uFSK6EENHPeZ2OGgOipHfOAl+VLWEv9/j3QkSGbD+ADX3A9uJlmq24i37n28RjJmAbGTfpEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-i18next": {
|
"node_modules/react-i18next": {
|
||||||
"version": "15.2.0",
|
"version": "15.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.2.0.tgz",
|
||||||
@@ -3579,6 +3620,37 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/react-loading": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-loading/-/react-loading-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-Vdqy79zq+bpeWJqC+xjltUjuGApyoItPgL0vgVfcJHhqwU7bAMKzysfGW/ADu6i0z0JiOCRJjo+IkFNkRNbA3A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react": ">=0.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-multi-date-picker": {
|
||||||
|
"version": "4.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-multi-date-picker/-/react-multi-date-picker-4.5.2.tgz",
|
||||||
|
"integrity": "sha512-FgWjZB3Z6IA6XpcWiLPk85PwcRUhOiYhKK42o5k672gD/n2I6rzPfQ8bUrldOIiF/Z7FfOCdH7a6FeubzqteLg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-date-object": "^2.1.8",
|
||||||
|
"react-element-popper": "^2.1.6"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.2",
|
"version": "0.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-i18next": "^15.2.0",
|
"react-i18next": "^15.2.0",
|
||||||
|
"react-loading": "^2.0.3",
|
||||||
|
"react-multi-date-picker": "^4.5.2",
|
||||||
"react-router-dom": "^7.1.0",
|
"react-router-dom": "^7.1.0",
|
||||||
"react-toastify": "^11.0.2",
|
"react-toastify": "^11.0.2",
|
||||||
"tailwind-merge": "^2.5.5"
|
"tailwind-merge": "^2.5.5"
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.16675 1.66675V4.16675" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M13.8333 1.66675V4.16675" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.41675 7.57495H17.5834" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M18 7.08341V14.1667C18 16.6667 16.75 18.3334 13.8333 18.3334H7.16667C4.25 18.3334 3 16.6667 3 14.1667V7.08341C3 4.58341 4.25 2.91675 7.16667 2.91675H13.8333C16.75 2.91675 18 4.58341 18 7.08341Z" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M13.5788 11.4167H13.5863" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M13.5788 13.9167H13.5863" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.4963 11.4167H10.5038" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.4963 13.9167H10.5038" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.41185 11.4167H7.41933" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.41185 13.9167H7.41933" stroke="#292D32" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
import { ButtonHTMLAttributes, FC, memo, ReactNode } from 'react'
|
||||||
|
import ReactLoading from 'react-loading'
|
||||||
|
import { XOR } from '../helpers/types'
|
||||||
|
import { clx } from '../helpers/utils'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
isLoading?: boolean,
|
||||||
|
} & ButtonHTMLAttributes<HTMLButtonElement> &
|
||||||
|
XOR<{ children: ReactNode }, { label: string, isLoading?: boolean }>;
|
||||||
|
|
||||||
|
const Button: FC<Props> = memo((props: Props) => {
|
||||||
|
|
||||||
|
const buttonClass = clx(
|
||||||
|
'flex rounded-xl items-center justify-center text-center h-12 text-sm bg-primary text-white w-full',
|
||||||
|
props.disabled && 'cursor-not-allowed opacity-60',
|
||||||
|
props.className
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button {...props} className={`${buttonClass} ${props.className}`} >
|
||||||
|
{
|
||||||
|
props.isLoading ?
|
||||||
|
<ReactLoading type='spin' color={'white'} width={20} height={20} />
|
||||||
|
:
|
||||||
|
props.label || props.children
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Button
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { useState, useEffect, FC } from 'react';
|
||||||
|
import DatePicker from 'react-multi-date-picker';
|
||||||
|
import persian from 'react-date-object/calendars/persian';
|
||||||
|
import persian_fa from 'react-date-object/locales/persian_fa';
|
||||||
|
import DateObject from 'react-date-object';
|
||||||
|
import CalenderIcon from '../assets/images/calendar.svg'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onChange: (date: string) => void;
|
||||||
|
defaulValue?: string;
|
||||||
|
error_text?: string;
|
||||||
|
placeholder: string;
|
||||||
|
reset?: boolean;
|
||||||
|
isDateTime?: boolean;
|
||||||
|
className?: string;
|
||||||
|
label: string
|
||||||
|
};
|
||||||
|
|
||||||
|
const DatePickerComponent: FC<Props> = (props: Props) => {
|
||||||
|
const [value, setValue] = useState<DateObject | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.reset) {
|
||||||
|
setValue(null);
|
||||||
|
}
|
||||||
|
}, [props.reset]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (value) {
|
||||||
|
const formattedDate = `${value.year}/${value.month.number}/${value.day}`;
|
||||||
|
props.onChange(formattedDate);
|
||||||
|
}
|
||||||
|
}, [props, value]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.defaulValue && !value) {
|
||||||
|
const defaultDate = new DateObject({
|
||||||
|
date: props.defaulValue,
|
||||||
|
calendar: persian,
|
||||||
|
locale: persian_fa,
|
||||||
|
});
|
||||||
|
setValue(defaultDate);
|
||||||
|
}
|
||||||
|
}, [props.defaulValue, value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full">
|
||||||
|
<div className='text-sm'>
|
||||||
|
{props.label}
|
||||||
|
</div>
|
||||||
|
<div className='relative mt-1.5'>
|
||||||
|
<DatePicker
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
value={value}
|
||||||
|
onChange={(date) => setValue(date as DateObject)}
|
||||||
|
calendar={persian}
|
||||||
|
locale={persian_fa}
|
||||||
|
calendarPosition="bottom-right"
|
||||||
|
className={props.className}
|
||||||
|
/>
|
||||||
|
{props.error_text && props.error_text !== '' && (
|
||||||
|
<div className="text-xs text-right text-red-600 mt-2 mr-2 font-medium">
|
||||||
|
{props.error_text}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<img src={CalenderIcon} className='absolute top-0 bottom-0 my-auto left-2' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DatePickerComponent;
|
||||||
@@ -17,7 +17,7 @@ type Props = {
|
|||||||
const Input: FC<Props> = (props: Props) => {
|
const Input: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
const inputClass = clx(
|
const inputClass = clx(
|
||||||
'w-full h-12 text-black block px-4 rounded-xl mt-2 border border-border',
|
'w-full h-12 text-black block px-4 text-sm rounded-xl mt-1 border border-border',
|
||||||
props.readOnly && 'bg-gray-100',
|
props.readOnly && 'bg-gray-100',
|
||||||
props.className
|
props.className
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -35,3 +35,15 @@ textarea::placeholder {
|
|||||||
@apply flex flex-col sm:flex-row sm:gap-5 gap-5;
|
@apply flex flex-col sm:flex-row sm:gap-5 gap-5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.rmdp-input {
|
||||||
|
min-height: 48px;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
border: 1px solid #d0d0d0 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
margin: 0px;
|
||||||
|
padding-right: 16px !important;
|
||||||
|
}
|
||||||
|
.rmdp-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
+11
-1
@@ -6,6 +6,16 @@
|
|||||||
"name": "نام",
|
"name": "نام",
|
||||||
"enter_name": "نام خود را وارد کنید",
|
"enter_name": "نام خود را وارد کنید",
|
||||||
"family": "نام خانوادگی",
|
"family": "نام خانوادگی",
|
||||||
"enter_family": "نام خانوادگی خود را وارد کنید"
|
"enter_family": "نام خانوادگی خود را وارد کنید",
|
||||||
|
"select_date": "انتخاب تاریخ",
|
||||||
|
"dateofbirth": "تاریخ تولد",
|
||||||
|
"national_code": "کد ملی",
|
||||||
|
"email": "ایمیل",
|
||||||
|
"enter_email": "ایمیل خود را وارد کنید",
|
||||||
|
"phonen_number": "شماره تماس",
|
||||||
|
"enter_phone_number": "شماره تماس خود را وارد کنید",
|
||||||
|
"password": "رمز عبور",
|
||||||
|
"enter_password": "رمز عبور انتخابی خود را وارد کنید",
|
||||||
|
"next": "ادامه"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ import LogoImage from '../../assets/images/logo.svg'
|
|||||||
import LogoSmallImage from '../../assets/images/logo-small.svg'
|
import LogoSmallImage from '../../assets/images/logo-small.svg'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Input from '../../components/Input'
|
import Input from '../../components/Input'
|
||||||
|
import DatePickerComponent from '../../components/DatePicker'
|
||||||
|
import Button from '../../components/Button'
|
||||||
|
|
||||||
const Login: FC = () => {
|
const Login: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full h-full flex justify-center py-[100px] items-center'>
|
<div className='w-full h-full flex justify-center py-[100px] items-center px-10'>
|
||||||
<div className='flex w-full max-w-[1200px] bg-secondary h-full rounded-3xl overflow-hidden'>
|
<div className='flex w-full max-w-[1200px] bg-secondary h-full rounded-3xl overflow-hidden'>
|
||||||
<div className='flex-1 min-w-[50%] bg-white p-9'>
|
<div className='flex-1 min-w-[50%] overflow-y-auto bg-white p-9'>
|
||||||
<div className=''>
|
<div className=''>
|
||||||
<img src={LogoSmallImage} className='w-8' />
|
<img src={LogoSmallImage} className='w-8' />
|
||||||
<div className='mt-5'>
|
<div className='mt-5'>
|
||||||
@@ -37,6 +39,38 @@ const Login: FC = () => {
|
|||||||
placeholder={t('auth.enter_family')}
|
placeholder={t('auth.enter_family')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='mt-6 min-w-full rowTwoInput'>
|
||||||
|
<DatePickerComponent label={t('auth.dateofbirth')} onChange={(date: string) => console.log(date)} placeholder={t('auth.select_date')} />
|
||||||
|
<Input
|
||||||
|
label={t('auth.family')}
|
||||||
|
placeholder={t('auth.enter_family')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-6 rowTwoInput'>
|
||||||
|
<Input
|
||||||
|
label={t('auth.email')}
|
||||||
|
placeholder={t('auth.enter_email')}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label={t('auth.phonen_number')}
|
||||||
|
placeholder={t('auth.enter_phone_number')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-6 rowTwoInput'>
|
||||||
|
<Input
|
||||||
|
label={t('auth.password')}
|
||||||
|
placeholder={t('auth.enter_password')}
|
||||||
|
type='password'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
label={t('auth.next')}
|
||||||
|
className='mt-6'
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user