diff --git a/src/hooks/useQueryParams.ts b/src/hooks/useQueryParams.ts new file mode 100644 index 0000000..069cb8f --- /dev/null +++ b/src/hooks/useQueryParams.ts @@ -0,0 +1,5 @@ +import { useLocation } from "react-router-dom"; + +export const useQueryParams = () => { + return new URLSearchParams(useLocation().search); +}; diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index 7dd534a..e8a87df 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -1,12 +1,94 @@ import ProfileDetails from "./section/ProfileDetails"; import ProductConfigList from "./section/ProductConfigList"; +import { useQueryParams } from "../../hooks/useQueryParams"; +import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import useAxios from "../../hooks/useAxios"; +import { AxiosError, AxiosResponse } from "axios"; +import ModalPayment from "./section/components/ModalPayment"; +import { useNavigate } from "react-router-dom"; const Profile = () => { + const query = useQueryParams(); + const axios = useAxios(); + const [isOpen, setIsOpen] = useState(false); + const [isPayment, setIsPayment] = useState(false); + const [message, setMessage] = useState(""); + const navigate = useNavigate(); + const mutation = useMutation({ + mutationKey: ["statusPayment"], + mutationFn: (values: { trackId: string }) => { + return axios.post("/home/config/confirm", values); + }, + onSuccess: (data) => { + setIsOpen(true); + setIsPayment(true); + setMessage(data?.data?.result?.alert); + navigate("/profile", { replace: true }); + }, + onError: (err: AxiosError) => { + let errorMessage = "یک خطای غیرمنتظره رخ داد"; + if ( + err.response?.data && + typeof err.response.data === "object" && + "alert" in err.response.data + ) { + errorMessage = (err.response.data as { alert: string }).alert; + } + setIsOpen(true); + setIsPayment(false); + setMessage(errorMessage); + navigate("/profile", { replace: true }); + }, + }); + useEffect(() => { + const trackId = query.get("trackId"); + + if (trackId) { + toast.promise(mutation.mutateAsync({ trackId }), { + loading: "درحال تایید درگاه پرداخت...", + success: (res: AxiosResponse) => { + return `${res.data.alert}`; + }, + error: (err: AxiosError) => { + let errorMessage = "یک خطای غیرمنتظره رخ داد"; + if ( + err.response?.data && + typeof err.response.data === "object" && + "alert" in err.response.data + ) { + errorMessage = (err.response.data as { alert: string }).alert; + } + return errorMessage; + }, + }); + } else { + console.error("Track ID is missing or invalid."); + } + }, []); + + const {data,isLoading,isFetching,error} = useQuery({ + queryKey:["profile",mutation], + queryFn:()=>{ + return axios.get('/profile'); + } + }) return ( -
- - -
+ <> + {!mutation.isPending && ( + + )} +
+ + +
+ ); }; diff --git a/src/pages/profile/section/ProductConfigList.tsx b/src/pages/profile/section/ProductConfigList.tsx index 755707a..51215d2 100644 --- a/src/pages/profile/section/ProductConfigList.tsx +++ b/src/pages/profile/section/ProductConfigList.tsx @@ -1,10 +1,34 @@ +import { LoaderIcon } from "react-hot-toast"; +import Alert from "../../../components/alert/Alert"; +import Button from "../../../components/button"; +import { ProfileDetailsProps } from "../../../types/props"; import ConfigItem from "./components/ConfigItem"; +import ConfigItemLoading from "./components/ConfigItemLoading"; import ProfileImage from "./components/ProfileImage"; +import { Fragment } from "react/jsx-runtime"; -const ProductConfigList = () => { +const ProductConfigList = ({ + data, + isLoading, + isFetching, + error, + userTitle, +}: ProfileDetailsProps) => { return (
+
+ +
+

لیست کانفیگ ها

@@ -12,21 +36,33 @@ const ProductConfigList = () => { className="w-full h-full p-3 flex flex-col gap-3 justify-center items-center" > - - - + {isLoading || isFetching ? ( + Array(3) + .fill(null) + .map((_, i) => ( + + + + )) + ) : error ? ( + + {error.message} + + ) : ( + data?.result?.configs?.map((item) => { + return ( + + + + ); + }) + )}
); diff --git a/src/pages/profile/section/ProfileDetails.tsx b/src/pages/profile/section/ProfileDetails.tsx index 6f049a2..22dc1cc 100644 --- a/src/pages/profile/section/ProfileDetails.tsx +++ b/src/pages/profile/section/ProfileDetails.tsx @@ -1,13 +1,27 @@ -import { MdEdit } from "react-icons/md"; +import { MdLogout } from "react-icons/md"; import Button from "../../../components/button"; -import ModalEditProfile from "./components/ModalEditProfile"; -import { useState } from "react"; +import { useDispatch } from "react-redux"; +import { setToken } from "../../../redux/slices/token"; +import { AxiosError } from "axios"; +import { LoaderIcon } from "react-hot-toast"; +import { ProfileDetailsProps } from "../../../types/props"; -const ProfileDetails = () => { +const ProfileDetails = ({ + data, + isLoading, + isFetching, + error, +}: ProfileDetailsProps) => { return (
- +
); }; @@ -15,32 +29,67 @@ const ProfileDetails = () => { export default ProfileDetails; const EditProfile = () => { - const [isOpen, setIsOpen] = useState(false); + // const [isOpen, setIsOpen] = useState(false); + const dispatch = useDispatch(); return ( -
- - */} +
); }; -const ProductDetails = () => { +const ProductDetails = ({ + enable_config, + disable_config, + isLoading, + isFetching, + error, +}: { + enable_config: number; + disable_config: number; + isLoading: boolean; + isFetching: boolean; + error: Error | AxiosError | null; +}) => { return (
-

+

کانفیگ های فعال :{" "} - 2 -

-

+ + {isLoading || isFetching ? ( + + ) : error ? ( + "error" + ) : ( + enable_config + )} + +

+
کانفیگ های غیر فعال :{" "} - 10 -

+ + {isLoading || isFetching ? ( + + ) : error ? ( + "error" + ) : ( + disable_config + )} + +
); diff --git a/src/pages/profile/section/components/ConfigItem.tsx b/src/pages/profile/section/components/ConfigItem.tsx index c832abe..863c638 100644 --- a/src/pages/profile/section/components/ConfigItem.tsx +++ b/src/pages/profile/section/components/ConfigItem.tsx @@ -5,13 +5,30 @@ import ModalConfigDetails from "./ModalConfigDetails"; import { useState } from "react"; import Dropdown, { DropdownItem } from "../../../../components/dropdown"; import ProgressSpace from "../../../../components/progressSpace"; +import toast from "react-hot-toast"; +import { useNavigate } from "react-router-dom"; -const ConfigItem = ({ dateBuy, configName, isDisabled }: ConfigItemProps) => { +const ConfigItem = ({ + dateBuy, + configName, + isDisabled, + isShowTraffic, + textCopy, +}: ConfigItemProps) => { const [isOpen, setIsOpen] = useState(false); const [isOpenDropDown, setIsOpenDropDown] = useState(false); + const navigate = useNavigate(); const handleToggle = () => { setIsOpenDropDown(!isOpen); }; + const copyToClipboard = async (textToCopy: string) => { + try { + await navigator.clipboard.writeText(textToCopy); + toast.success("متن با موفقیت کپی شد!"); + } catch (err) { + toast.error(`Failed to copy: , ${err}`); + } + }; return ( <> @@ -21,11 +38,13 @@ const ConfigItem = ({ dateBuy, configName, isDisabled }: ConfigItemProps) => { dateBuy={dateBuy} isDisabled={isDisabled} nameConfig={configName} + isShowTraffic={isShowTraffic} + textCopy={textCopy} />
{isDisabled && (
-
+
کانفیگ {configName} غیر فعال است .{" "} - - - - - - - + {isShowTraffic && ( + + + + + + + )}
- )}
- {!isDisabled && ( + {!isDisabled || isShowTraffic && (
diff --git a/src/pages/profile/section/components/ModalPayment.tsx b/src/pages/profile/section/components/ModalPayment.tsx new file mode 100644 index 0000000..d54339f --- /dev/null +++ b/src/pages/profile/section/components/ModalPayment.tsx @@ -0,0 +1,50 @@ +import { Dispatch, SetStateAction } from "react"; +import MuiModal from "../../../../common/modal"; +import { MdError, MdVerified } from "react-icons/md"; + +const ModalPayment = ({ + isOpen, + setIsOpen, + isPayment, + message, +}: { + isOpen: boolean; + setIsOpen: Dispatch>; + isPayment: boolean; + message: string; +}) => { + console.log(isPayment); + + return ( + +
+
+ {isPayment ? ( + <> + {" "} + +

+ پرداخت موفقیت امیز بود {message} +

+

از اعتماد شما سپاسگذاریم

+ + ) : ( + <> + {" "} + +

+ پرداخت موفقیت امیز نبود {message} +

+

+ در صورت کسر وجه اگر تا 48 ساعت برگشت داده نشد با پشتیبانی تماس + بگیرید +

+ + )} +
+
+
+ ); +}; + +export default ModalPayment;