complete asan service gps
This commit is contained in:
Generated
+12
-8
@@ -24,7 +24,6 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^11.3.28",
|
"framer-motion": "^11.3.28",
|
||||||
"iconsax-react": "^0.0.8",
|
"iconsax-react": "^0.0.8",
|
||||||
"iranianbanklogos": "^3.1.2",
|
|
||||||
"moment-jalaali": "^0.10.1",
|
"moment-jalaali": "^0.10.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@@ -37,7 +36,8 @@
|
|||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
"yup": "^1.4.0",
|
"yup": "^1.4.0",
|
||||||
"zustand": "^4.5.5"
|
"zustand": "^4.5.5",
|
||||||
|
"zustand-persist": "^0.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tanstack/eslint-plugin-query": "^5.51.15",
|
"@tanstack/eslint-plugin-query": "^5.51.15",
|
||||||
@@ -10587,12 +10587,6 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iranianbanklogos": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/iranianbanklogos/-/iranianbanklogos-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-F6GnrhrC9UO1c4CW8uJloXAkg7pgx/Y8ok6qixb6L0knwIanG6Idudi8/Ebuu3c9PVd59wDTtTZQvtszr+Yyvw==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@@ -20313,6 +20307,16 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zustand-persist": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/zustand-persist/-/zustand-persist-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-u6bBIc4yZRpSKBKuTNhoqvoIb09gGHk2NkiPg4K7MPIWTYZg70PlpBn48QEDnKZwfNurnf58TaW5BuMGIMf5hw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"zustand": ">=3.6.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -19,7 +19,6 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^11.3.28",
|
"framer-motion": "^11.3.28",
|
||||||
"iconsax-react": "^0.0.8",
|
"iconsax-react": "^0.0.8",
|
||||||
"iranianbanklogos": "^3.1.2",
|
|
||||||
"moment-jalaali": "^0.10.1",
|
"moment-jalaali": "^0.10.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@@ -32,7 +31,8 @@
|
|||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
"yup": "^1.4.0",
|
"yup": "^1.4.0",
|
||||||
"zustand": "^4.5.5"
|
"zustand": "^4.5.5",
|
||||||
|
"zustand-persist": "^0.4.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|||||||
+13
-37
@@ -1,43 +1,19 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
<head>
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
<meta charset="utf-8" />
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
-->
|
<meta name="theme-color" content="#000000" />
|
||||||
<title>React App</title>
|
<meta name="description" content="Web site created using create-react-app" />
|
||||||
</head>
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<body>
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<link rel="icon" type="image/svg+xml" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcBAMAAACAI8KnAAAAMFBMVEVHcEwHUJAHUpIGUpMGUpMNR4MHUpMGVJUIUZEIUZEIUZELTIoMTYwKT44GU5QHUpLtfyqAAAAAEHRSTlMAUJPA2BKu/4BebyM0QO6fto/c2wAAARNJREFUeAFF0QFEQ1EUh/FvtbdVe2uTCKDCCmSIBYgUgYYYUAFDMNvaf7MwYBoYEINSqIAHAhAwgAeMQFEglMiA5Lg9+4Cfc91zuWAtbO6sEOWVGxeDcqOIq3sK8Fh1irfx73shRy9Yb6QkKUsZG27jG/skbNyl5/jMAXjnsZbjKCwFJPLJVtqxksmTfOr+c1j1KiyhiOKVXGrC8Jut2Qk7t+zPyN2cHWp5EaNnDEdGO8xYqjGywzlfdWLSNQWFq7ZIH0zvEpctSgZrUgfmJHtG4iQp1YsUJHuk145Jat7ZqlIAG1zKUpM9YD6fduxnKgA1pkxfjIvY+B3/Zj3k8Ays8Q/AcQNXqvD5MPitBURdRZ/yB8Qed1faOTlWAAAAAElFTkSuQmCC" />
|
||||||
<div id="root"></div>
|
<title>آسان سرویس</title>
|
||||||
<!--
|
</head>
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
<body>
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
+21
@@ -1,8 +1,29 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { Imei } from "./components/home/imei";
|
import { Imei } from "./components/home/imei";
|
||||||
import { StatusBox } from "./components/home/status-box";
|
import { StatusBox } from "./components/home/status-box";
|
||||||
|
import { getUsersInformation } from "./services/api/user";
|
||||||
import { TransitionPages } from "./transition";
|
import { TransitionPages } from "./transition";
|
||||||
|
import { useUserStore } from "./store/user";
|
||||||
|
import { handleError } from "./utility/error-handle";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const { updateUser } = useUserStore()
|
||||||
|
const { mutate: userMutate } = useMutation({
|
||||||
|
mutationFn: getUsersInformation,
|
||||||
|
mutationKey: ["user"]
|
||||||
|
})
|
||||||
|
const handleGetUsersInformation = async () => {
|
||||||
|
await userMutate({}, {
|
||||||
|
onSuccess: (res: any) => {
|
||||||
|
updateUser(res?.data)
|
||||||
|
},
|
||||||
|
onError: (err: any) => handleError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
handleGetUsersInformation()
|
||||||
|
}, [])
|
||||||
return (
|
return (
|
||||||
<TransitionPages>
|
<TransitionPages>
|
||||||
<div className="flex flex-col gap-y-[30px] w-full">
|
<div className="flex flex-col gap-y-[30px] w-full">
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ export const AwardNotComplete: FC<Props> = ({ award }) => {
|
|||||||
<div className="flex flex-col items-start gap-3">
|
<div className="flex flex-col items-start gap-3">
|
||||||
<p className="font-normal text-base text-primary-text-color" style={{ fontFamily: "vazirmatn" }}>{award?.desc?.length >= 70 ? `${award?.desc?.slice(0, 70)} ...` : award?.desc}</p>
|
<p className="font-normal text-base text-primary-text-color" style={{ fontFamily: "vazirmatn" }}>{award?.desc?.length >= 70 ? `${award?.desc?.slice(0, 70)} ...` : award?.desc}</p>
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
<p className="font-normal text-sm text-secondary-text-color">{formatDateToPersian(award?.expireDate, "jYYYY/jMM/jD")}</p>
|
|
||||||
<Calendar2 color="#777577" className="size-5" />
|
<Calendar2 color="#777577" className="size-5" />
|
||||||
|
<p className="font-normal text-sm text-secondary-text-color">{formatDateToPersian(award?.expireDate, "jYYYY/jMM/jD")}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { Cup, Transmit } from "iconsax-react"
|
import { Cup, Transmit } from "iconsax-react"
|
||||||
|
import { AwardsResponse } from "../../types"
|
||||||
|
import { FC } from "react"
|
||||||
|
import { formatDateToPersian } from "../../utility/getDate"
|
||||||
|
|
||||||
|
type Props = {
|
||||||
export const AwardComplete = () => {
|
award: AwardsResponse
|
||||||
|
}
|
||||||
|
export const AwardComplete: FC<Props> = ({ award }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-10 bg-auth-form p-[18px] rounded-[40px]">
|
<div className="flex flex-col w-full h-full justify-between gap-10 bg-auth-form p-[18px] rounded-[40px]">
|
||||||
<div className="flex flex-col gap-3">
|
<div className="flex flex-col gap-3">
|
||||||
<p className="font-normal text-lg text-secondary-text-color">۲۵۰ هزار تومان تخفیف برای اقامت در تمام ویلاها و کلبه های جاجیگا با حداقل رزرو ۲ میلیون تومان.</p>
|
<p className="font-normal text-lg text-secondary-text-color">{award?.req?.desc}</p>
|
||||||
<p className="font-normal text-base text-secondary-text-color">1403/06/12</p>
|
<p className="font-normal text-base text-secondary-text-color">{formatDateToPersian(award?.expireDate, "jYYYY/jMM/jD")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
<div className="flex flex-row gap-x-[6px] items-center">
|
<div className="flex flex-row gap-x-[6px] items-center">
|
||||||
<p className="font-normal text-lg text-secondary-text-color">75</p>
|
<p className="font-normal text-lg text-secondary-text-color">{award?.score}</p>
|
||||||
<Cup className="size-4" color="#777577" />
|
<Cup className="size-4" color="#777577" />
|
||||||
</div>
|
</div>
|
||||||
<div className="size-10 flex items-center justify-center bg-white rounded-full cursor-pointer">
|
<div className="size-10 flex items-center justify-center bg-white rounded-full cursor-pointer">
|
||||||
|
|||||||
@@ -1,31 +1,48 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { AwardNotComplete } from "./award-not-complete"
|
import { AwardNotComplete } from "./award-not-complete";
|
||||||
import { getAwardsList } from "../../services/api/awards"
|
import { getAwardsList } from "../../services/api/awards";
|
||||||
import { AwardsResponse } from "../../types"
|
import { AwardsResponse, AwardStatus } from "../../types";
|
||||||
import { AwardSkeleton } from "./award-skeleton"
|
import { AwardSkeleton } from "./award-skeleton";
|
||||||
import { handleError } from "../../utility/error-handle"
|
import { handleError } from "../../utility/error-handle";
|
||||||
import { useEffect } from "react"
|
import { useEffect, useState } from "react";
|
||||||
|
import { AwardComplete } from "./awards-complete";
|
||||||
|
import { useUserStore } from "../../store/user";
|
||||||
|
|
||||||
export const Awards = () => {
|
export const Awards = () => {
|
||||||
|
const { user } = useUserStore()
|
||||||
|
const [status, setStatus] = useState<AwardStatus>({
|
||||||
|
awards: 0,
|
||||||
|
my_score: 0
|
||||||
|
});
|
||||||
const { data, isLoading, error } = useQuery({
|
const { data, isLoading, error } = useQuery({
|
||||||
queryKey: ["awards"],
|
queryKey: ["awards"],
|
||||||
queryFn: getAwardsList
|
queryFn: getAwardsList
|
||||||
})
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleError(error)
|
handleError(error);
|
||||||
}, [error])
|
}, [error]);
|
||||||
|
|
||||||
if (isLoading) return <AwardSkeleton />
|
useEffect(() => {
|
||||||
|
const awardsTemp: number = data?.data?.length;
|
||||||
|
const tempScores: any = data?.data?.filter((award: AwardsResponse) => award?.status === 1);
|
||||||
|
const myScore = tempScores?.reduce((totalScore: number, award: AwardsResponse) => totalScore + award?.score, 0);
|
||||||
|
setStatus({
|
||||||
|
awards: awardsTemp,
|
||||||
|
my_score: myScore
|
||||||
|
});
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
if (isLoading) return <AwardSkeleton />;
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
<p className="font-medium text-xl text-primary-text-color">جوایز (5)</p>
|
<p className="font-medium text-xl text-primary-text-color">جوایز ({status?.awards})</p>
|
||||||
<p className="font-normal text-base text-primary-text-color">امتیازهای من: 65</p>
|
<p className="font-normal text-base text-primary-text-color">امتیازهای من: {status?.my_score}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-6">
|
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-6">
|
||||||
{data?.data?.map((award: AwardsResponse) => <AwardNotComplete key={award.id} award={award} />)}
|
{data?.data?.map((award: AwardsResponse, index: number) => award?.status === 0 ? <AwardNotComplete key={index} award={award} /> : <AwardComplete key={index} award={award} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export const ComboBox: FC<Props> = ({ field, placeholder, className, data = [],
|
|||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className={`input-style min-w-full ${className}`}
|
className={`input-style min-w-full ${className} ${placeholder && "placeholder:text-primary-text-color"}`}
|
||||||
displayValue={(person: any) => person?.name}
|
displayValue={(person: any) => person?.name}
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -45,9 +45,9 @@ export const ComboBox: FC<Props> = ({ field, placeholder, className, data = [],
|
|||||||
transition
|
transition
|
||||||
className="bg-white shadow min-w-[220px] !max-h-[300px] mt-2 rounded-xl p-2"
|
className="bg-white shadow min-w-[220px] !max-h-[300px] mt-2 rounded-xl p-2"
|
||||||
>
|
>
|
||||||
{filteredValue.map((value) => (
|
{filteredValue.map((value, index: number) => (
|
||||||
<ComboboxOption
|
<ComboboxOption
|
||||||
key={value?.id}
|
key={index}
|
||||||
value={value}
|
value={value}
|
||||||
className="group flex cursor-default items-center gap-2 rounded-lg py-1.5 px-3 select-none data-[focus]:bg-secondary-text-color/10"
|
className="group flex cursor-default items-center gap-2 rounded-lg py-1.5 px-3 select-none data-[focus]:bg-secondary-text-color/10"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import persian_fa from "react-date-object/locales/persian_fa"
|
|||||||
import { getJalaaliDate } from '../../utility/getDate';
|
import { getJalaaliDate } from '../../utility/getDate';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
field: any
|
field: any,
|
||||||
|
placeholder?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DatepickerComponent: FC<Props> = ({ field }) => {
|
export const DatepickerComponent: FC<Props> = ({ field, placeholder }) => {
|
||||||
return (
|
return (
|
||||||
<div className='relative w-full min-w-max cursor-pointer mb-10 xl:mb-0'>
|
<div className='relative w-full min-w-max cursor-pointer mb-10 xl:mb-0'>
|
||||||
<div className="absolute top-[18.5px] left-5 grid h-5 w-5 place-items-center !z-50">
|
<div className="absolute top-[18.5px] left-5 grid h-5 w-5 place-items-center">
|
||||||
<Calendar2 color='#777577' />
|
<Calendar2 color='#777577' />
|
||||||
</div>
|
</div>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
@@ -20,11 +21,12 @@ export const DatepickerComponent: FC<Props> = ({ field }) => {
|
|||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
showOtherDays
|
showOtherDays
|
||||||
placeholder={getJalaaliDate()}
|
placeholder={placeholder ? placeholder : getJalaaliDate()}
|
||||||
calendar={persian}
|
calendar={persian}
|
||||||
locale={persian_fa}
|
locale={persian_fa}
|
||||||
calendarPosition="bottom-right"
|
calendarPosition="bottom-right"
|
||||||
inputClass='w-full !min-w-full absolute input-style top-0 z-10 cursor-pointer'
|
arrow={false}
|
||||||
|
inputClass={`w-full !min-w-full absolute input-style top-0 cursor-pointer`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ type Props = {
|
|||||||
field?: any,
|
field?: any,
|
||||||
className?: string,
|
className?: string,
|
||||||
value?: string,
|
value?: string,
|
||||||
onChange?: (value: string) => void
|
onChange?: (value: string) => void,
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Input: FC<Props> = ({ placeholder, type = "text", icon, field, className, value, onChange }) => {
|
export const Input: FC<Props> = ({ placeholder, type = "text", icon, field, className, value, onChange, disabled = false }) => {
|
||||||
const [hidden, setHidden] = useState<boolean>(false)
|
const [hidden, setHidden] = useState<boolean>(false)
|
||||||
const handleHidden = () => setHidden(prev => !prev)
|
const handleHidden = () => setHidden(prev => !prev)
|
||||||
return (
|
return (
|
||||||
@@ -27,7 +28,7 @@ export const Input: FC<Props> = ({ placeholder, type = "text", icon, field, clas
|
|||||||
: icon}
|
: icon}
|
||||||
{placeholder === "شماره کارت" && field.value && findBankByPAN(field.value).icon}
|
{placeholder === "شماره کارت" && field.value && findBankByPAN(field.value).icon}
|
||||||
</div>
|
</div>
|
||||||
<InputComponent ref={field?.ref} {...field} value={value} onChange={onChange || field?.onChange} type={type === "password" && hidden ? "text" : type} placeholder={placeholder} className={`input-style min-w-full ${className}`} />
|
<InputComponent ref={field?.ref} {...field} value={value} onChange={onChange || field?.onChange} type={type === "password" && hidden ? "text" : type} placeholder={placeholder} className={`input-style min-w-full ${className}`} disabled={disabled} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { flexRender, getCoreRowModel, getPaginationRowModel, useReactTable } from "@tanstack/react-table"
|
import { flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"
|
||||||
import { ArrowDown2, ArrowLeft2, ArrowRight2, ArrowUp2, SearchNormal1 } from "iconsax-react"
|
import { ArrowDown2, ArrowLeft2, ArrowRight2, ArrowUp2, SearchNormal1 } from "iconsax-react"
|
||||||
import { FC, useEffect, useState } from "react"
|
import { FC, useEffect, useState } from "react"
|
||||||
import { Input } from "./input"
|
import { Input } from "./input"
|
||||||
@@ -24,20 +24,17 @@ type ADSortType = {
|
|||||||
export const Table: FC<Props> = ({ columns, data, tableStatus = false, tableScore = 0, isLoading = false, totalData = 0 }) => {
|
export const Table: FC<Props> = ({ columns, data, tableStatus = false, tableScore = 0, isLoading = false, totalData = 0 }) => {
|
||||||
const [aDSort, setADSort] = useState<ADSortType>({
|
const [aDSort, setADSort] = useState<ADSortType>({
|
||||||
key: "",
|
key: "",
|
||||||
value: 1
|
value: -1
|
||||||
})
|
})
|
||||||
const { updateParams, params, clearParams } = useParamsStore()
|
const { updateParams, params, clearParams } = useParamsStore()
|
||||||
const totalPages = Math.ceil(totalData / params?.rows)
|
const totalPages = Math.ceil(totalData / params?.rows)
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: data ? data : [],
|
data: data ? data : [],
|
||||||
columns: columns ? columns : [],
|
columns: columns ? columns : [],
|
||||||
debugTable: true,
|
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
enableColumnResizing: true,
|
enableColumnResizing: true,
|
||||||
columnResizeMode: 'onChange',
|
columnResizeMode: 'onChange',
|
||||||
debugHeaders: true,
|
pageCount: params?.rows,
|
||||||
debugColumns: true,
|
|
||||||
getPaginationRowModel: getPaginationRowModel()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleInputValue = (value: string) => {
|
const handleInputValue = (value: string) => {
|
||||||
@@ -71,14 +68,16 @@ export const Table: FC<Props> = ({ columns, data, tableStatus = false, tableScor
|
|||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
<div className="flex flex-col sm:flex-row justify-between items-center gap-2.5 md:gap-10">
|
<div className="flex flex-col sm:flex-row justify-between items-center gap-2.5 md:gap-10">
|
||||||
<div className="sm:max-w-[300px] xl:max-w-[450px] w-full">
|
<div className="sm:max-w-[300px] xl:max-w-[450px] w-full">
|
||||||
<Input placeholder="جستجو" value={params?.search} onChange={(e: any) => handleInputValue(e?.target?.value)} className="bg-auth-form placeholder:text-[#777577]" icon={<SearchNormal1 color="#777577" />} />
|
<Input placeholder="جستجو" value={params?.search} onChange={(e: any) => {
|
||||||
|
handleInputValue(e?.target?.value)
|
||||||
|
}} className="bg-auth-form placeholder:text-[#777577]" icon={<SearchNormal1 color="#777577" />} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full sm:max-w-[100px]">
|
<div className="w-full sm:max-w-[100px]">
|
||||||
<ComboBox placeholder={params?.rows.toString()} className="bg-auth-form" data={tableRows} mode="table" />
|
<ComboBox placeholder={params?.rows.toString()} className="bg-auth-form" data={tableRows} mode="table" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex justify-start items-end text-sm lg:text-lg text-primary-text-color font-normal -mb-7 pl-2">{tableStatus && `امتیاز من : ${tableScore}`}</div>
|
<div className="w-full flex justify-start items-end text-sm lg:text-lg text-primary-text-color font-normal -mb-7 pl-2">{tableStatus && `امتیاز من : ${tableScore}`}</div>
|
||||||
<div className="block max-w-full overflow-x-auto overflow-y-hidden bg-auth-form rounded-[40px] shadow-sm p-4 pb-0 xl:p-9 xl:pb-0 relative">
|
<div className="block max-w-full min-h-max overflow-x-auto overflow-y-hidden bg-auth-form rounded-[40px] shadow-sm p-4 pb-0 xl:p-9 xl:pb-0 relative">
|
||||||
<table>
|
<table>
|
||||||
<thead className="border-b border-b-secondary-color">
|
<thead className="border-b border-b-secondary-color">
|
||||||
{table.getHeaderGroups().map((headerGroup: any, index: number) => (
|
{table.getHeaderGroups().map((headerGroup: any, index: number) => (
|
||||||
@@ -92,7 +91,7 @@ export const Table: FC<Props> = ({ columns, data, tableStatus = false, tableScor
|
|||||||
}}>
|
}}>
|
||||||
<div {...{ className: header.column.getCanSort() ? "text-secondary-text-color text-base font-normal flex flex-row items-center justify-center gap-1 px-4 py-2" : "", onClick: header.column.getToggleSortingHandler() }}>
|
<div {...{ className: header.column.getCanSort() ? "text-secondary-text-color text-base font-normal flex flex-row items-center justify-center gap-1 px-4 py-2" : "", onClick: header.column.getToggleSortingHandler() }}>
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
{{ asc: <ArrowDown2 color="#777577" className="size-4" />, desc: <ArrowUp2 color="#777577" className="size-4" /> }[header.column.getIsSorted() as string] ?? null}
|
{aDSort?.value === 1 && aDSort?.key === header.getContext()?.column?.id ? <ArrowDown2 color="#777577" className="size-4" /> : <ArrowUp2 color="#777577" className="size-4" />}
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { Trash } from 'iconsax-react';
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setSelectedImage: (file: any) => any,
|
||||||
|
selectedImage: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ImageUpload: FC<Props> = ({ selectedImage, setSelectedImage }) => {
|
||||||
|
const handleImageChange = (event: any) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
setSelectedImage(file);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleImageDelete = () => {
|
||||||
|
setSelectedImage(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-left">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
onChange={handleImageChange}
|
||||||
|
className="hidden"
|
||||||
|
id="imageUpload"
|
||||||
|
/>
|
||||||
|
<label htmlFor="imageUpload" className="cursor-pointer">
|
||||||
|
{selectedImage ? (
|
||||||
|
<div className="relative">
|
||||||
|
<img src={URL.createObjectURL(selectedImage)} alt="Selected image" className="w-full min-w-max max-h-60 object-fill rounded-[40px]" />
|
||||||
|
<Trash color='#fff' size={25} onClick={handleImageDelete} className='absolute bottom-2 right-4' />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="bg-white w-full min-w-max h-fit min-h-60 flex items-center justify-center text-secondary-text-color rounded-[40px]">
|
||||||
|
عکس خود را انتخاب کنید
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -15,8 +15,10 @@ export const LoginForm = () => {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const { mutate, isPending } = useMutation({
|
const { mutate, isPending } = useMutation({
|
||||||
mutationFn: loginMutation
|
mutationFn: loginMutation,
|
||||||
|
mutationKey: ["login"]
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
@@ -24,12 +26,13 @@ export const LoginForm = () => {
|
|||||||
} = useForm<LoginFormInterface>({
|
} = useForm<LoginFormInterface>({
|
||||||
resolver: yupResolver(loginSchema)
|
resolver: yupResolver(loginSchema)
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleLoginSubmit: SubmitHandler<LoginFormInterface> = async (data) => {
|
const handleLoginSubmit: SubmitHandler<LoginFormInterface> = async (data) => {
|
||||||
mutate({
|
await mutate({
|
||||||
...data,
|
...data,
|
||||||
remember_me: true
|
remember_me: true
|
||||||
}, {
|
}, {
|
||||||
onSuccess: (data: any) => {
|
onSuccess: async (data: any) => {
|
||||||
window.localStorage.setItem("token", data?.data?.token)
|
window.localStorage.setItem("token", data?.data?.token)
|
||||||
toast.success("با موفقیت وارد شدین")
|
toast.success("با موفقیت وارد شدین")
|
||||||
navigate("/")
|
navigate("/")
|
||||||
|
|||||||
@@ -1,21 +1,55 @@
|
|||||||
import { Button } from "@headlessui/react"
|
import { Button } from "@headlessui/react"
|
||||||
import { Input } from "../common/input"
|
import { Input } from "../common/input"
|
||||||
|
import { useMutation } from "@tanstack/react-query"
|
||||||
|
import { checkIMEI } from "../../services/api/imei"
|
||||||
|
import { ButtonComponent } from "../common/button"
|
||||||
|
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
||||||
|
import { CheckIMEI } from "../../types"
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup"
|
||||||
|
import { checkIMEISchema } from "../../schema"
|
||||||
|
import { ErrorComponent } from "../common/error"
|
||||||
|
import toast from "react-hot-toast"
|
||||||
|
import { handleError } from "../../utility/error-handle"
|
||||||
|
|
||||||
export const Imei = () => {
|
export const Imei = () => {
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
control
|
||||||
|
} = useForm<CheckIMEI>({
|
||||||
|
resolver: yupResolver(checkIMEISchema)
|
||||||
|
})
|
||||||
|
const { mutate, isPending } = useMutation({
|
||||||
|
mutationFn: checkIMEI,
|
||||||
|
mutationKey: ["IMEI"]
|
||||||
|
})
|
||||||
|
const handleCheckIMEI: SubmitHandler<CheckIMEI> = async (data) => {
|
||||||
|
await mutate(data, {
|
||||||
|
onSuccess: (res: any) => {
|
||||||
|
toast.success("کد IMEI معتبر است")
|
||||||
|
},
|
||||||
|
onError: (err: any) => handleError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col lg:flex-row bg-auth-form p-[30px] rounded-[40px] gap-8">
|
<form onSubmit={handleSubmit(handleCheckIMEI)} className="w-full flex flex-col lg:flex-row bg-auth-form p-[30px] rounded-[40px] gap-8">
|
||||||
<div className="w-full h-full flex items-center justify-center">
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
<img src="/svgs/dashboard/binary.svg" alt="binary" className="size-full max-w-[500px] max-h-[500px]" />
|
<img src="/svgs/dashboard/binary.svg" alt="binary" className="size-full max-w-[500px] max-h-[500px]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col w-full gap-10 justify-center lg:justify-between">
|
<div className="flex flex-col w-full gap-10 justify-center lg:justify-between">
|
||||||
<Input placeholder="کد IMEI" />
|
<Controller control={control} name="IMEI" render={({ field }) => (
|
||||||
|
<div className="flex flex-col !gap-0">
|
||||||
|
<Input placeholder="کد IMEI" type="text" field={field} />
|
||||||
|
<ErrorComponent show={errors?.IMEI} message={errors?.IMEI?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
<p className="font-normal text-base text-primary-text-color text-justify lg:text-wrap">
|
<p className="font-normal text-base text-primary-text-color text-justify lg:text-wrap">
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز
|
||||||
</p>
|
</p>
|
||||||
<div className="w-full flex justify-end">
|
<div className="w-full flex justify-end">
|
||||||
<Button className="w-full min-w-full xl:min-w-min xl:max-w-60">ثبت کد</Button>
|
<ButtonComponent title="ثبت کد" className="w-full min-w-full xl:min-w-min xl:max-w-60" pending={isPending} type="submit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+174
-122
@@ -1,142 +1,194 @@
|
|||||||
import { Button } from "@headlessui/react"
|
|
||||||
import { Input } from "../common/input"
|
import { Input } from "../common/input"
|
||||||
import { DatepickerComponent } from "../common/datepicker"
|
import { DatepickerComponent } from "../common/datepicker"
|
||||||
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
||||||
import { MyAccountInterface } from "../../types"
|
import { CitiesType, ComboBoxItems, ProvinceType, UpdateUserInterface } from "../../types"
|
||||||
import { yupResolver } from "@hookform/resolvers/yup"
|
import { yupResolver } from "@hookform/resolvers/yup"
|
||||||
import { MyAccountSchema } from "../../schema"
|
import { UpdateUserSchema } from "../../schema"
|
||||||
import { ErrorComponent } from "../common/error"
|
import { ErrorComponent } from "../common/error"
|
||||||
import { ComboBox } from "../common/combo-box"
|
import { ComboBox } from "../common/combo-box"
|
||||||
|
import { ResetPasswordBox } from "./reset-password-box"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { getProvincesList } from "../../services/api/province"
|
||||||
|
import { useMutation, useQuery } from "@tanstack/react-query"
|
||||||
|
import { getCitiesList } from "../../services/api/cities"
|
||||||
|
import { useUserStore } from "../../store/user"
|
||||||
|
import { ButtonComponent } from "../common/button"
|
||||||
|
import { updateUSerInformations } from "../../services/api/user"
|
||||||
|
import toast from "react-hot-toast"
|
||||||
|
import { handleError } from "../../utility/error-handle"
|
||||||
|
import { ImageUpload } from "../common/upload"
|
||||||
|
|
||||||
export const MyAccountPage = () => {
|
export const MyAccountPage = () => {
|
||||||
const { handleSubmit, formState: { errors }, control } = useForm<MyAccountInterface>({
|
const [selectedImage, setSelectedImage] = useState<any>(null);
|
||||||
resolver: yupResolver(MyAccountSchema)
|
const { user, updateUser } = useUserStore()
|
||||||
|
const { mutate, isPending } = useMutation({
|
||||||
|
mutationFn: updateUSerInformations,
|
||||||
|
mutationKey: ["update-user"]
|
||||||
|
})
|
||||||
|
const { handleSubmit, formState: { errors }, control, watch, reset } = useForm<UpdateUserInterface>({
|
||||||
|
resolver: yupResolver(UpdateUserSchema),
|
||||||
|
})
|
||||||
|
const provinceName: any = watch("province_name");
|
||||||
|
const [provinceData, setProvinceData] = useState<ComboBoxItems[] | []>([])
|
||||||
|
const [citiesData, setCitiesData] = useState<ComboBoxItems[] | []>([])
|
||||||
|
const { data: provinces } = useQuery({
|
||||||
|
queryFn: getProvincesList,
|
||||||
|
queryKey: ["province"]
|
||||||
|
})
|
||||||
|
const { data: cities } = useQuery({
|
||||||
|
queryFn: getCitiesList,
|
||||||
|
queryKey: ["cities"]
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleMyAccountForm: SubmitHandler<MyAccountInterface> = async (data) => {
|
const handleUpdateUser: SubmitHandler<UpdateUserInterface> = async (data) => {
|
||||||
console.log("data =>", data)
|
let formData = new FormData()
|
||||||
|
formData.append("first_name", data?.first_name)
|
||||||
|
formData.append("last_name", data?.last_name)
|
||||||
|
formData.append("province_name", data?.province_name?.name)
|
||||||
|
formData.append("city_name", data?.city_name?.name)
|
||||||
|
formData.append("shopName", data?.shopName)
|
||||||
|
formData.append("birthDate", data?.birthDate)
|
||||||
|
formData.append("address", data?.address)
|
||||||
|
formData.append("cell_number", data?.cell_number)
|
||||||
|
formData.append("image", selectedImage)
|
||||||
|
await mutate({ formData, id: user?.id }, {
|
||||||
|
onSuccess: (res: any) => {
|
||||||
|
toast?.success("اطلاعات کاربر با موفقیت بروز رسانی شد")
|
||||||
|
updateUser(res?.data?.user)
|
||||||
|
},
|
||||||
|
onError: (err: any) => handleError(err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const tempArray: ComboBoxItems[] = [...provinceData]
|
||||||
|
provinces?.data?.data?.map((province: ProvinceType) => tempArray.push({
|
||||||
|
id: province?.ProvinceID,
|
||||||
|
name: province?.ProvinceName
|
||||||
|
}))
|
||||||
|
setProvinceData(tempArray)
|
||||||
|
}, [provinces])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const tempCities: any = []
|
||||||
|
const newCities = cities?.data?.data?.filter((city: CitiesType) => city?.ProvinceName?.toLocaleLowerCase()?.includes(provinceName?.name?.toLowerCase()))
|
||||||
|
newCities?.map((city: CitiesType) => tempCities?.push({
|
||||||
|
id: city?.CityID,
|
||||||
|
name: city?.CityName
|
||||||
|
}))
|
||||||
|
setCitiesData(tempCities)
|
||||||
|
}, [provinceName]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reset({
|
||||||
|
address: user?.address,
|
||||||
|
birthDate: user?.birthDate,
|
||||||
|
city_name: { id: 1, name: user?.city_name },
|
||||||
|
province_name: { id: 1, name: user?.province_name },
|
||||||
|
mobile_number: user?.mobile_number,
|
||||||
|
first_name: user?.first_name,
|
||||||
|
last_name: user?.last_name,
|
||||||
|
national_code: user?.national_code,
|
||||||
|
shopName: user?.shopName,
|
||||||
|
cell_number: user?.cell_number,
|
||||||
|
})
|
||||||
|
}, [reset])
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(handleMyAccountForm)} className="w-full h-full flex flex-col gap-10 bg-auth-form rounded-[40px] p-[30px]">
|
<div className="w-full h-full flex flex-col gap-10 bg-auth-form rounded-[40px] p-[30px]">
|
||||||
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
<form onSubmit={handleSubmit(handleUpdateUser)} className="w-full h-full flex flex-col gap-10 bg-auth-form rounded-[40px]">
|
||||||
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
||||||
<p className="font-medium text-xl text-primary-text-color">اطلاعات اولیه</p>
|
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
||||||
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
<p className="font-medium text-xl text-primary-text-color">اطلاعات اولیه</p>
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
||||||
</p>
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
||||||
</div>
|
</p>
|
||||||
<div className="flex flex-col gap-10 w-full">
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px]">
|
|
||||||
<Controller name="phoneNumber" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="شماره تماس" type="number" field={field} />
|
|
||||||
<ErrorComponent show={errors.phoneNumber} message={errors.phoneNumber?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="marketName" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="نام شرکت" field={field} />
|
|
||||||
<ErrorComponent show={errors.marketName} message={errors.marketName?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="name" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="نام" field={field} />
|
|
||||||
<ErrorComponent show={errors.name} message={errors.name?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="family" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="نام خانوادگی" field={field} />
|
|
||||||
<ErrorComponent show={errors.family} message={errors.family?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="capCity" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<ComboBox field={field} />
|
|
||||||
<ErrorComponent show={errors.capCity} message={errors.capCity?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="city" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<ComboBox field={field} />
|
|
||||||
<ErrorComponent show={errors.city} message={errors.city?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y-2 border" />
|
<div className="flex flex-col gap-10 w-full">
|
||||||
</div>
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px]">
|
||||||
</div>
|
<Controller name="mobile_number" control={control} render={({ field }) => (
|
||||||
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
<div>
|
||||||
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
<Input placeholder={user?.mobile_number ? user?.mobile_number : "شماره تماس"} type="number" disabled field={field} />
|
||||||
<p className="font-medium text-xl text-primary-text-color">اطلاعات تکمیلی</p>
|
<ErrorComponent show={errors.mobile_number} message={errors.mobile_number?.message} />
|
||||||
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
</div>
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
)} />
|
||||||
</p>
|
<Controller name="shopName" control={control} render={({ field }) => (
|
||||||
</div>
|
<div>
|
||||||
<div className="flex flex-col gap-10 w-full">
|
<Input placeholder={user?.shopName ? user?.shopName : "نام شرکت"} field={field} />
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px]">
|
<ErrorComponent show={errors.shopName} message={errors.shopName?.message} />
|
||||||
<Controller name="address" control={control} render={({ field }) => (
|
</div>
|
||||||
<div>
|
)} />
|
||||||
<Input placeholder="آدرس" field={field} />
|
<Controller name="first_name" control={control} render={({ field }) => (
|
||||||
<ErrorComponent show={errors.address} message={errors.address?.message} />
|
<div>
|
||||||
</div>
|
<Input placeholder={user?.first_name ? user?.first_name : "نام"} field={field} />
|
||||||
)} />
|
<ErrorComponent show={errors.first_name} message={errors.first_name?.message} />
|
||||||
<Controller name="phoneNumber1" control={control} render={({ field }) => (
|
</div>
|
||||||
<div>
|
)} />
|
||||||
<Input placeholder="شماره تماس" type="number" field={field} />
|
<Controller name="last_name" control={control} render={({ field }) => (
|
||||||
<ErrorComponent show={errors.phoneNumber1} message={errors.phoneNumber1?.message} />
|
<div>
|
||||||
</div>
|
<Input placeholder={user?.last_name ? user?.last_name : "نام خانوادگی"} field={field} />
|
||||||
)} />
|
<ErrorComponent show={errors.last_name} message={errors.last_name?.message} />
|
||||||
<Controller name="staticNumber" control={control} render={({ field }) => (
|
</div>
|
||||||
<div>
|
)} />
|
||||||
<Input placeholder="شماره ثابت" type="number" field={field} />
|
<Controller name="province_name" control={control} render={({ field }) => (
|
||||||
<ErrorComponent show={errors.staticNumber} message={errors.staticNumber?.message} />
|
<div>
|
||||||
</div>
|
<ComboBox field={field} data={provinceData} placeholder={user?.province_name} />
|
||||||
)} />
|
<ErrorComponent show={errors.province_name} message={errors.province_name?.message} />
|
||||||
<Controller name="date" control={control} render={({ field }) => (
|
</div>
|
||||||
<div className="flex flex-col gap-y-9">
|
)} />
|
||||||
<DatepickerComponent field={field} />
|
<Controller name="city_name" control={control} render={({ field }) => (
|
||||||
<ErrorComponent show={errors.date} message={errors.date?.message} />
|
<div>
|
||||||
</div>
|
<ComboBox field={field} data={citiesData} placeholder={user?.city_name} />
|
||||||
)} />
|
<ErrorComponent show={errors.city_name} message={errors.city_name?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<ImageUpload setSelectedImage={setSelectedImage} selectedImage={selectedImage} />
|
||||||
|
</div>
|
||||||
|
<div className="divide-y-2 border" />
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y-2 border" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
||||||
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
||||||
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
<p className="font-medium text-xl text-primary-text-color">اطلاعات تکمیلی</p>
|
||||||
<p className="font-medium text-xl text-primary-text-color">تغییر رمز عبور</p>
|
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
||||||
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
</p>
|
||||||
</p>
|
</div>
|
||||||
|
<div className="flex flex-col gap-10 w-full">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px]">
|
||||||
|
<Controller name="address" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder={user?.address ? user?.address : "آدرس"} field={field} />
|
||||||
|
<ErrorComponent show={errors.address} message={errors.address?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<Controller name="national_code" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder={user?.national_code} type="number" field={field} disabled />
|
||||||
|
<ErrorComponent show={errors.national_code} message={errors.national_code?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<Controller name="cell_number" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder={user?.cell_number} type="number" field={field} />
|
||||||
|
<ErrorComponent show={errors.cell_number} message={errors.cell_number?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<Controller name="birthDate" control={control} render={({ field }) => (
|
||||||
|
<div className="flex flex-col gap-y-9">
|
||||||
|
<DatepickerComponent field={field} placeholder={user?.birthDate} />
|
||||||
|
<ErrorComponent show={errors.birthDate} message={errors.birthDate?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
</div>
|
||||||
|
<div className="divide-y-2 border" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px] w-full">
|
<div className="flex w-full min-w-max lg:justify-end mt-10">
|
||||||
<Controller name="currentPassword" control={control} render={({ field }) => (
|
<ButtonComponent type="submit" title="ذخیره" pending={isPending} className="w-full lg:max-w-fit lg:min-w-72" />
|
||||||
<div>
|
|
||||||
<Input placeholder="رمز عبور فعلی" type="password" field={field} />
|
|
||||||
<ErrorComponent show={errors.currentPassword} message={errors.currentPassword?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<div />
|
|
||||||
<Controller name="newPassword" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="رمز عبور جدید" type="password" field={field} />
|
|
||||||
<ErrorComponent show={errors.newPassword} message={errors.newPassword?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
<Controller name="repeatPassword" control={control} render={({ field }) => (
|
|
||||||
<div>
|
|
||||||
<Input placeholder="تکرار رمز عبور" type="password" field={field} />
|
|
||||||
<ErrorComponent show={errors.repeatPassword} message={errors.repeatPassword?.message} />
|
|
||||||
</div>
|
|
||||||
)} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
<div className="flex w-full xl:justify-end mt-10">
|
<ResetPasswordBox />
|
||||||
<Button type="submit" className="w-full xl:max-w-fit xl:min-w-72">ذخیره</Button>
|
</div >
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
||||||
|
import { ResetPasswordUserSchema } from "../../schema"
|
||||||
|
import { ResetPasswordUser } from "../../types"
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup"
|
||||||
|
import { ErrorComponent } from "../common/error"
|
||||||
|
import { Input } from "../common/input"
|
||||||
|
import { ButtonComponent } from "../common/button"
|
||||||
|
import { useMutation } from "@tanstack/react-query"
|
||||||
|
import { changeUserPassword } from "../../services/api/user"
|
||||||
|
import toast from "react-hot-toast"
|
||||||
|
import { handleError } from "../../utility/error-handle"
|
||||||
|
|
||||||
|
export const ResetPasswordBox = () => {
|
||||||
|
const { mutate, isPending } = useMutation({
|
||||||
|
mutationFn: changeUserPassword,
|
||||||
|
mutationKey: ["user-password"]
|
||||||
|
})
|
||||||
|
const { handleSubmit, formState: { errors }, control } = useForm<ResetPasswordUser>({
|
||||||
|
resolver: yupResolver(ResetPasswordUserSchema)
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleResetUserPassword: SubmitHandler<ResetPasswordUser> = async (data) => {
|
||||||
|
await mutate({
|
||||||
|
...data
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success("تغییر رمز عبور با موفقیت انجام شد")
|
||||||
|
},
|
||||||
|
onError: (err: any) => {
|
||||||
|
handleError(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<form className="w-full h-full flex flex-col gap-10" onSubmit={handleSubmit(handleResetUserPassword)}>
|
||||||
|
<div className="flex flex-col gap-5 xl:gap-0 xl:flex-row xl:gap-x-10 xl:justify-between items-start">
|
||||||
|
<div className="flex flex-col gap-y-5 w-full xl:max-w-fit">
|
||||||
|
<p className="font-medium text-xl text-primary-text-color">تغییر رمز عبور</p>
|
||||||
|
<p className="font-normal text-base text-secondary-text-color text-wrap xl:max-w-xs">
|
||||||
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[18px] w-full">
|
||||||
|
<Controller name="password" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder="رمز عبور فعلی" type="password" field={field} />
|
||||||
|
<ErrorComponent show={errors.password} message={errors.password?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<div />
|
||||||
|
<Controller name="newPassword" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder="رمز عبور جدید" type="password" field={field} />
|
||||||
|
<ErrorComponent show={errors.newPassword} message={errors.newPassword?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
<Controller name="password_confirmation" control={control} render={({ field }) => (
|
||||||
|
<div>
|
||||||
|
<Input placeholder="تکرار رمز عبور" type="password" field={field} />
|
||||||
|
<ErrorComponent show={errors.password_confirmation} message={errors.password_confirmation?.message} />
|
||||||
|
</div>
|
||||||
|
)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full lg:justify-end mt-10">
|
||||||
|
<ButtonComponent type="submit" title="تغییر رمز عبور" pending={isPending} className="w-full lg:max-w-fit lg:min-w-72" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
import { Call } from "iconsax-react"
|
import { Call, Profile } from "iconsax-react"
|
||||||
import React, { FC } from "react"
|
import { FC } from "react"
|
||||||
|
import { useUserStore } from "../../../store/user"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setShow: () => void
|
setShow: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header: FC<Props> = ({ setShow }) => {
|
export const Header: FC<Props> = ({ setShow }) => {
|
||||||
|
const { user } = useUserStore()
|
||||||
return (
|
return (
|
||||||
<header className="flex flex-row w-full justify-between items-center mb-10 lg:mb-[60px]">
|
<header className="flex flex-row w-full justify-between items-center mb-10 lg:mb-[60px]">
|
||||||
<div className="flex flex-row gap-x-5 lg:gap-x-3 items-center">
|
<div className="flex flex-row gap-x-5 lg:gap-x-3 items-center">
|
||||||
<img src="/svgs/header/burger-menu.svg" alt="burger menu" className="lg:hidden size-[27px]" onClick={setShow} />
|
<img src="/svgs/header/burger-menu.svg" alt="burger menu" className="lg:hidden size-[27px]" onClick={setShow} />
|
||||||
<img src="/svgs/header/person.svg" alt="person" className="size-[60px]" />
|
{user?.profilePic !== "noPic" ? <img src={`https://asan-service.com/${user?.profilePic}`} alt="person" className="size-[60px] rounded-full" /> : <div className="size-[60px] flex flex-row justify-center items-center bg-secondary-color rounded-full">
|
||||||
<p className="hidden font-normal text-sm lg:block lg:text-xl">علی مصلحی</p>
|
<Profile
|
||||||
|
size="30"
|
||||||
|
color="#777577"
|
||||||
|
/></div>}
|
||||||
|
<p className="hidden font-normal text-sm lg:block lg:text-xl">{user?.first_name} {user?.last_name}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-x-3 items-center">
|
<div className="flex flex-row gap-x-3 items-center">
|
||||||
<p className="font-normal text-sm lg:text-xl">021-45597000</p>
|
<p className="font-normal text-sm lg:text-xl"><a href={`tel:${user?.mobile_number}`}>{user?.mobile_number}</a></p>
|
||||||
<Call color="#11212D" variant="Bold" className="size-[27px]" />
|
<Call color="#11212D" variant="Bold" className="size-[27px]" />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { sidebarItems } from "../../../utility/sidebar";
|
|||||||
import { SidebarItem } from "./sidebar-item";
|
import { SidebarItem } from "./sidebar-item";
|
||||||
import { CloseCircle, LogoutCurve } from "iconsax-react";
|
import { CloseCircle, LogoutCurve } from "iconsax-react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useUserStore } from "../../../store/user";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setShow: (value: boolean) => void,
|
setShow: (value: boolean) => void,
|
||||||
@@ -11,11 +12,13 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SidebarMobile: FC<Props> = ({ setShow, show }) => {
|
export const SidebarMobile: FC<Props> = ({ setShow, show }) => {
|
||||||
|
const { clearUser } = useUserStore()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const handleCloseSidebar = () => setShow(false);
|
const handleCloseSidebar = () => setShow(false);
|
||||||
const handleExit = () => {
|
const handleExit = () => {
|
||||||
window.localStorage.clear()
|
window.localStorage.clear()
|
||||||
navigate("/auth/login")
|
navigate("/auth/login")
|
||||||
|
clearUser()
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,21 +1,72 @@
|
|||||||
import { Button } from "@headlessui/react"
|
|
||||||
import { ComboBox } from "../common/combo-box"
|
import { ComboBox } from "../common/combo-box"
|
||||||
import { FC } from "react"
|
import { FC, useEffect, useState } from "react"
|
||||||
|
import { useUserStore } from "../../store/user"
|
||||||
|
import { ButtonComponent } from "../common/button"
|
||||||
|
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
||||||
|
import { CardBank, SendWithdraw } from "../../types"
|
||||||
|
import { ErrorComponent } from "../common/error"
|
||||||
|
import { useMutation } from "@tanstack/react-query"
|
||||||
|
import { sendwithdraw } from "../../services/api/wallet"
|
||||||
|
import toast from "react-hot-toast"
|
||||||
|
import { handleError } from "../../utility/error-handle"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pending: boolean
|
pending: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WalletAddress: FC<Props> = ({ pending }) => {
|
export const WalletAddress: FC<Props> = ({ pending }) => {
|
||||||
|
const [selectedCard, setSelectedCard] = useState<CardBank | null>(null)
|
||||||
|
const { mutate, isPending } = useMutation({
|
||||||
|
mutationFn: sendwithdraw,
|
||||||
|
mutationKey: ["withdraw"]
|
||||||
|
})
|
||||||
|
const { handleSubmit, formState: { errors }, control, watch } = useForm<any>({
|
||||||
|
})
|
||||||
|
const cardDetail: any = watch("card")
|
||||||
|
const [userBanks, setUserBanks] = useState<any>([])
|
||||||
|
const { user } = useUserStore()
|
||||||
|
useEffect(() => {
|
||||||
|
const tempUserBanks: any = [...userBanks]
|
||||||
|
user?.cardBank?.map((cards: any) => tempUserBanks.push({
|
||||||
|
id: cards?.IBAN,
|
||||||
|
name: cards?.PAN,
|
||||||
|
}))
|
||||||
|
setUserBanks(tempUserBanks)
|
||||||
|
|
||||||
|
}, [user])
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedCard: CardBank | CardBank[] | [] = user?.cardBank?.filter((cardBanks: any) => cardBanks?.IBAN === cardDetail?.id && cardBanks?.PAN === cardDetail?.name)
|
||||||
|
setSelectedCard(selectedCard?.[0])
|
||||||
|
}, [cardDetail])
|
||||||
|
const handleSendWithdraw: SubmitHandler<SendWithdraw> = async () => {
|
||||||
|
await mutate({
|
||||||
|
card: {
|
||||||
|
holderName: selectedCard?.holderName,
|
||||||
|
PAN: selectedCard?.PAN,
|
||||||
|
IBAN: selectedCard?.IBAN
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
onSuccess: (res: any) => {
|
||||||
|
toast.success("درخواست شما با موفقیت ثبت شد")
|
||||||
|
},
|
||||||
|
onError: (err: any) => handleError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col lg:flex-row bg-auth-form p-[30px] rounded-[40px] gap-8">
|
<form onSubmit={handleSubmit(handleSendWithdraw)} className="w-full flex flex-col lg:flex-row bg-auth-form p-[30px] rounded-[40px] gap-8">
|
||||||
<div className="w-full h-full flex items-center justify-center">
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
<img src="/svgs/dashboard/wallet.svg" alt="wallet" className="size-full max-w-[500px] max-h-[500px]" />
|
<img src="/svgs/dashboard/wallet.svg" alt="wallet" className="size-full max-w-[500px] max-h-[500px]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col w-full gap-10 justify-center lg:justify-between">
|
<div className="flex flex-col w-full gap-10 justify-center lg:justify-between">
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-10">
|
||||||
<p className="text-2xl font-medium text-primary-text-color">ثبت درخواست برداشت از حساب</p>
|
<p className="text-2xl font-medium text-primary-text-color">ثبت درخواست برداشت از حساب</p>
|
||||||
{!pending && <ComboBox placeholder="حساب بانکی مورد نظر خود را انتخاب کنید" />}
|
|
||||||
|
{!pending && <Controller control={control} name="card" render={({ field }) => (
|
||||||
|
<>
|
||||||
|
<ComboBox placeholder="حساب بانکی مورد نظر خود را انتخاب کنید" data={userBanks} field={field} />
|
||||||
|
<ErrorComponent show={errors?.card} message={errors?.card?.message} />
|
||||||
|
</>
|
||||||
|
)} />}
|
||||||
</div>
|
</div>
|
||||||
{!pending && <p className="font-normal text-base text-primary-text-color text-justify lg:text-wrap">
|
{!pending && <p className="font-normal text-base text-primary-text-color text-justify lg:text-wrap">
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز
|
||||||
@@ -24,9 +75,9 @@ export const WalletAddress: FC<Props> = ({ pending }) => {
|
|||||||
{`همکار گرامی
|
{`همکار گرامی
|
||||||
طبق درخواست قبلی، عملیات واریز مبلغ 765,975 تومان به حساب شما در حال اجراست. متاسفانه پیش از تکمیل درخواست، امکان شروع عملیات جدید برای شما وجود ندارد.`}</p>}
|
طبق درخواست قبلی، عملیات واریز مبلغ 765,975 تومان به حساب شما در حال اجراست. متاسفانه پیش از تکمیل درخواست، امکان شروع عملیات جدید برای شما وجود ندارد.`}</p>}
|
||||||
<div className="w-full flex justify-end">
|
<div className="w-full flex justify-end">
|
||||||
<Button className="w-full min-w-full xl:min-w-min xl:max-w-60">{pending ? "لغو درخواست" : "ثبت درخواست"}</Button>
|
<ButtonComponent className="w-full min-w-full xl:min-w-min xl:max-w-60" pending={isPending} title={pending ? "لغو درخواست" : "ثبت درخواست"} type="submit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -36,7 +36,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@apply text-base font-medium flex w-full justify-center bg-primary-color max-w-[442px] max-h-[55px] rounded-[20px] p-[18px] text-white
|
@apply text-base font-medium flex w-full justify-center bg-primary-color max-h-[55px] rounded-[20px] p-[18px] text-white
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import ReactDOM from 'react-dom/client';
|
|||||||
import { RouterProvider } from 'react-router-dom';
|
import { RouterProvider } from 'react-router-dom';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import "iranianbanklogos/dist/ibl.css";
|
|
||||||
import { Toaster } from 'react-hot-toast';
|
import { Toaster } from 'react-hot-toast';
|
||||||
import { RQProvider } from './rq-provider';
|
import { RQProvider } from './rq-provider';
|
||||||
|
|
||||||
|
|||||||
+33
-25
@@ -76,34 +76,23 @@ export const RegisterSchema = yup.object({
|
|||||||
.required("تکرار رمز عبور الزامی میباشد"),
|
.required("تکرار رمز عبور الزامی میباشد"),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const MyAccountSchema = yup.object({
|
export const UpdateUserSchema = yup.object({
|
||||||
phoneNumber: yup.string()
|
first_name: yup.string().required("وارد کردن نام الزامی میباشد").min(3, "نام نمیتواند کمتر از 3 کاراکتر باشد").max(20, "نام نمیتواند بیشتر از 20 کاراکتر باشد"),
|
||||||
.required("وارد کردن شماره تماس الزامی میباشد")
|
last_name: yup.string().required("وارد کردن نام خانوادگی الزامی میباشد").min(3, "نام خانوادگی نمیتواند کمتر از 3 کاراکتر باشد").max(25, "نام خانوادگی نمیتواند بیشتر از 25 کاراکتر باشد"),
|
||||||
|
city_name: yup.object().required("وارد کردن شهر الزامی مباشد"),
|
||||||
|
province_name: yup.object().required("وارد کردن استان الزامی مباشد"),
|
||||||
|
shopName: yup.string().required("وارد کردن نام فروشگاه الزامی میباشد").min(2, "نام فروشگاه نمیتواند کمتر از 3 کاراکتر باشد").max(30, "نام فروشگاه نمیتواند بیشتر از 30 کاراکتر باشد"),
|
||||||
|
birthDate: yup.string().required("وارد کردن تاریخ تولد الزامی میباشد"),
|
||||||
|
address: yup.string().required("وارد کردن آدرس الزامی میباشد").min(5, "آدرس نمیتواند کمتر از 5 کاراکتر باشد").max(50, "آدرس نمیتواند بیشتر از از 50 کاراکتر باشد"),
|
||||||
|
cell_number: yup.string()
|
||||||
|
.min(11, "شماره تلفن ثابت نمیتوند کمتر از 11 رقم باشد")
|
||||||
|
.max(11, "شماره ثابت نمیتواند بیشتر از 11 رقم باشد")
|
||||||
|
.matches(/^[0-9]{11}$/, "شماره تماس نامعتبر").required("وارد کردن شماره تلفن ثابت الزامی میباشد"),
|
||||||
|
national_code: yup.string().min(10, "کد ملی نمیتواند کمتر از 10 کاراکتر باشد").max(10, "کد ملی نمیتونه بیشتر از 10 کاراکتر باشه").matches(/^[0-9]{10}$/, "کد نامعتبر"),
|
||||||
|
mobile_number: yup.string()
|
||||||
.min(11, "شماره تماس نمیتوند کمتر از 11 رقم باشد")
|
.min(11, "شماره تماس نمیتوند کمتر از 11 رقم باشد")
|
||||||
.max(11, "شماره تماس نمیتواند بیشتر از 11 رقم باشد")
|
.max(11, "شماره تماس نمیتواند بیشتر از 11 رقم باشد")
|
||||||
.matches(/^[0-9]{11}$/, "شماره تماس نامعتبر"),
|
.matches(/^[0-9]{11}$/, "شماره تماس نامعتبر"),
|
||||||
marketName: yup.string().required("وارد کردن نام فروشگاه الزامی میباشد").min(2, "نام فروشگاه نمیتواند کمتر از 3 کاراکتر باشد").max(30, "نام فروشگاه نمیتواند بیشتر از 30 کاراکتر باشد"),
|
|
||||||
name: yup.string().required("وارد کردن نام الزامی میباشد").min(3, "نام نمیتواند کمتر از 3 کاراکتر باشد").max(20, "نام نمیتواند بیشتر از 20 کاراکتر باشد"),
|
|
||||||
family: yup.string().required("وارد کردن نام خانوادگی الزامی میباشد").min(3, "نام خانوادگی نمیتواند کمتر از 3 کاراکتر باشد").max(25, "نام خانوادگی نمیتواند بیشتر از 25 کاراکتر باشد"),
|
|
||||||
city: yup.object().required("وارد کردن شهر الزامی مباشد"),
|
|
||||||
capCity: yup.object().required("وارد کردن استان الزامی مباشد"),
|
|
||||||
address: yup.string().required("وارد کردن آدرس الزامی میباشد"),
|
|
||||||
phoneNumber1: yup.string()
|
|
||||||
.required("وارد کردن شماره تماس الزامی میباشد")
|
|
||||||
.min(11, "شماره تماس نمیتوند کمتر از 11 رقم باشد")
|
|
||||||
.max(11, "شماره تماس نمیتواند بیشتر از 11 رقم باشد")
|
|
||||||
.matches(/^[0-9]{11}$/, "شماره تماس نامعتبر"),
|
|
||||||
staticNumber: yup.string()
|
|
||||||
.required("وارد کردن شماره تماس الزامی میباشد")
|
|
||||||
.min(8, "شماره تماس نمیتوند کمتر از 8 رقم باشد")
|
|
||||||
.max(8, "شماره تماس نمیتواند بیشتر از 8 رقم باشد")
|
|
||||||
.matches(/^[0-9]{8}$/, "شماره تماس نامعتبر"),
|
|
||||||
date: yup.string().required("وارد کردن تاریخ الزامی میباشد"),
|
|
||||||
currentPassword: yup.string().required("وارد کردن رمز عبور فعلی الزامی میباشد"),
|
|
||||||
newPassword: yup.string().min(8, "رمز عبور نمیتواند کمتر از 8 کاراکتر باشد").required("رمز عبور الزامی میباشد"),
|
|
||||||
repeatPassword: yup.string()
|
|
||||||
.oneOf([yup.ref('newPassword')], "رمز عبور و تکرار آن باید یکسان باشند")
|
|
||||||
.required("تکرار رمز عبور الزامی میاشد"),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const AddNewCardSchema = yup.object({
|
export const AddNewCardSchema = yup.object({
|
||||||
@@ -120,3 +109,22 @@ export const AddNewCardSchema = yup.object({
|
|||||||
.max(26, " شماره شبا نمیتواند بیشتر از 26 رقم باشد")
|
.max(26, " شماره شبا نمیتواند بیشتر از 26 رقم باشد")
|
||||||
.matches(/^IR[0-9]{24}$/, "شماره شبا نامعتبر"),
|
.matches(/^IR[0-9]{24}$/, "شماره شبا نامعتبر"),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const ResetPasswordUserSchema = yup.object({
|
||||||
|
password: yup.string().min(8, "رمز عبور نمیتواند کمتر از 8 کاراکتر باشد").required("رمز عبور الزامی میباشد"),
|
||||||
|
newPassword: yup.string().min(8, "رمز عبور جدید نمیتواند کمتر از 8 کاراکتر باشد")
|
||||||
|
.notOneOf([yup.ref('password')], "رمز عبور جدید نباید با رمز عبور فعلی یکسان باشد")
|
||||||
|
.required("رمز عبور جدید الزامی میباشد"),
|
||||||
|
password_confirmation: yup.string()
|
||||||
|
.oneOf([yup.ref('newPassword')], "رمز عبور جدید و تکرار آن باید یکسان باشند")
|
||||||
|
.required("تکرار رمز عبور الزامی میباشد"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SendWithdrawSchema = yup.object({
|
||||||
|
holderName: yup.string().required("وارد کردن اطلاعات صاحب کارت الزامی میباشد"),
|
||||||
|
card: yup.object(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const checkIMEISchema = yup.object({
|
||||||
|
IMEI: yup.string().required("وارد کردن اطلاعات IMEI الزامی میباشد").min(15,"شناسه IMEI نمیتواند کمتر از 15 کاراکتر باشد").max(15,"شناسه IMEI نمیتواند بیشتر از 15 کاراکتر باشد"),
|
||||||
|
})
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { CheckIMEI } from "../../types";
|
||||||
|
import axiosInstance from "../axios";
|
||||||
|
|
||||||
|
|
||||||
|
export const checkIMEI = (payload: CheckIMEI) => axiosInstance.post<any>("gps/register-device", payload)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { ResetPasswordUser } from "../../types";
|
||||||
|
import axiosInstance from "../axios";
|
||||||
|
|
||||||
|
export const getUsersInformation = ({ }: any) => axiosInstance.get("/gps/user/me")
|
||||||
|
export const changeUserPassword = (payload: ResetPasswordUser) => axiosInstance.post<any>("/gps/user/reset-pass", payload)
|
||||||
|
export const updateUSerInformations = (payload: any) => axiosInstance.put<any>(`/gps/user/me/${payload?.id}`, payload?.formData)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import axiosInstance from "../axios";
|
import axiosInstance from "../axios";
|
||||||
import { OverviewResponse } from "./overview";
|
import { OverviewResponse } from "./overview";
|
||||||
|
|
||||||
export const getWalletDetails = () => axiosInstance.get<OverviewResponse[] | OverviewResponse | [], any>("/gps/overview/wallet")
|
export const getWalletDetails = () => axiosInstance.get<OverviewResponse[] | OverviewResponse | [], any>("/gps/overview/wallet")
|
||||||
|
export const sendwithdraw = (payload: any) => axiosInstance.post("/gps/withdraw", payload)
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { UserInterface } from '../types';
|
||||||
|
import { persist } from "zustand/middleware";
|
||||||
|
|
||||||
|
type ZustandState = {
|
||||||
|
user: UserInterface;
|
||||||
|
updateUser: (userData: Partial<UserInterface>) => void;
|
||||||
|
clearUser: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultParams: UserInterface = {
|
||||||
|
cardBank: [],
|
||||||
|
city_name: "",
|
||||||
|
created_at: "",
|
||||||
|
dollarBalance: "",
|
||||||
|
first_name: "",
|
||||||
|
id: "",
|
||||||
|
last_name: "",
|
||||||
|
mobile_number: "",
|
||||||
|
national_code: "",
|
||||||
|
profilePic: "",
|
||||||
|
province_name: "",
|
||||||
|
score: 0,
|
||||||
|
shopName: "",
|
||||||
|
updated_at: "",
|
||||||
|
walletBalance: 0,
|
||||||
|
active: true,
|
||||||
|
_id: "",
|
||||||
|
address: "",
|
||||||
|
birthDate: "",
|
||||||
|
cell_number: "",
|
||||||
|
}
|
||||||
|
export const useUserStore = create<ZustandState>()(
|
||||||
|
persist(
|
||||||
|
(set) => ({
|
||||||
|
user: defaultParams,
|
||||||
|
updateUser: (userData: Partial<UserInterface>) =>
|
||||||
|
set((state) => ({
|
||||||
|
...state,
|
||||||
|
user: {
|
||||||
|
...state.user,
|
||||||
|
...userData,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
clearUser: () =>
|
||||||
|
set((state) => ({
|
||||||
|
...state,
|
||||||
|
user: defaultParams,
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: 'user-store',
|
||||||
|
getStorage: () => localStorage
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
+65
-24
@@ -67,25 +67,21 @@ export interface StatusBoxItemInterface {
|
|||||||
detail?: boolean
|
detail?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MyAccountInterface {
|
export interface UpdateUserInterface {
|
||||||
phoneNumber: string,
|
id?: any,
|
||||||
marketName: string,
|
first_name: string
|
||||||
name: string,
|
last_name: string
|
||||||
family: string,
|
city_name: object | any
|
||||||
city: object,
|
province_name: object | any
|
||||||
capCity: object,
|
shopName: string
|
||||||
address: string,
|
birthDate: string
|
||||||
phoneNumber1: string,
|
address: string
|
||||||
staticNumber: string,
|
cell_number: string,
|
||||||
date: string,
|
national_code?: string,
|
||||||
currentPassword: string,
|
mobile_number?: string,
|
||||||
newPassword: string,
|
image?: any
|
||||||
repeatPassword: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BankName = "saderat" | "mehr" | "pasargad"
|
|
||||||
type PersianBankName = "مهر" | "صادرات" | "پاسارگاد"
|
|
||||||
|
|
||||||
export interface CardBank {
|
export interface CardBank {
|
||||||
_id: string,
|
_id: string,
|
||||||
holderName: string,
|
holderName: string,
|
||||||
@@ -207,15 +203,17 @@ export interface RegisterDeviceId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AwardsResponse {
|
export interface AwardsResponse {
|
||||||
_id: string,
|
|
||||||
score: number,
|
score: number,
|
||||||
title: string,
|
title: string,
|
||||||
desc: string,
|
desc: string
|
||||||
expireDate: string,
|
req: {
|
||||||
created_at: string,
|
userId: string,
|
||||||
updated_at: string,
|
desc: string,
|
||||||
__v: number,
|
metaData: null | any,
|
||||||
id: string
|
status: number
|
||||||
|
},
|
||||||
|
status: number,
|
||||||
|
expireDate: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TransactionsData {
|
interface TransactionsData {
|
||||||
@@ -313,3 +311,46 @@ export interface CitiesResponse {
|
|||||||
data: CitiesType[] | [],
|
data: CitiesType[] | [],
|
||||||
error: string | null | any
|
error: string | null | any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserInterface {
|
||||||
|
cardBank: CardBank[] | [],
|
||||||
|
city_name: string,
|
||||||
|
created_at: string,
|
||||||
|
dollarBalance: string,
|
||||||
|
first_name: string,
|
||||||
|
id: string,
|
||||||
|
last_name: string,
|
||||||
|
mobile_number: string,
|
||||||
|
national_code: string,
|
||||||
|
profilePic: string,
|
||||||
|
province_name: string
|
||||||
|
score: number
|
||||||
|
shopName: string
|
||||||
|
updated_at: string
|
||||||
|
walletBalance: number
|
||||||
|
active: boolean,
|
||||||
|
_id: string,
|
||||||
|
address: string,
|
||||||
|
birthDate: string,
|
||||||
|
cell_number: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResetPasswordUser {
|
||||||
|
password: string,
|
||||||
|
newPassword: string,
|
||||||
|
password_confirmation: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AwardStatus {
|
||||||
|
awards: number,
|
||||||
|
my_score: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendWithdraw {
|
||||||
|
holderName: string,
|
||||||
|
card: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CheckIMEI {
|
||||||
|
IMEI: string
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ const columnConfigs: colConfig[] | [] = [
|
|||||||
</div>
|
</div>
|
||||||
},
|
},
|
||||||
{ accessor: "created_at", header: "تاریخ درخواست", cellRenderer: (info) => info.getValue() && <p style={{ direction: "ltr" }}>{formatDateToPersian(info.getValue())}</p> },
|
{ accessor: "created_at", header: "تاریخ درخواست", cellRenderer: (info) => info.getValue() && <p style={{ direction: "ltr" }}>{formatDateToPersian(info.getValue())}</p> },
|
||||||
{ accessor: "id", header: "شماره پیگیری" },
|
{ accessor: "trackingNumber", header: "شماره پیگیری" },
|
||||||
{ accessor: "updated_at", header: "تاریخ واریز", cellRenderer: (info) => info.getValue() && <p style={{ direction: "ltr" }}>{formatDateToPersian(info.getValue())}</p> },
|
{ accessor: "updated_at", header: "تاریخ واریز", cellRenderer: (info) => info.getValue() && <p style={{ direction: "ltr" }}>{formatDateToPersian(info.getValue())}</p> },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user