diff --git a/src/App.tsx b/src/App.tsx
index 07cc833..b89c080 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -4,15 +4,17 @@ import 'swiper/swiper-bundle.css';
import 'react-loading-skeleton/dist/skeleton.css'
import { BrowserRouter } from 'react-router-dom'
import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'
-// import { getToken } from './config/func'
import MainRouter from './router/MainRouter'
-// import AuthRouter from './router/AuthRouter'
import ToastContainer from './components/Toast'
import { getRefreshToken, getToken, removeRefreshToken, removeToken, setRefreshToken, setToken } from './config/func';
import AuthRouter from './router/AuthRouter';
+import CompleteProfileRouter from './router/CompleteProfileRouter';
import type { IApiErrorRepsonse } from './shared/types/Types';
import { Paths } from './config/Paths';
import { refreshToken } from './pages/auth/service/AuthService';
+import { useGetMe } from './pages/user/hooks/useUserData';
+import { needsProfileCompletion } from './pages/user/utils/profileUtils';
+import MoonLoader from 'react-spinners/MoonLoader';
declare global {
interface Window {
@@ -123,17 +125,37 @@ const queryClient = new QueryClient({
}
});
-const App: FC = () => {
-
- const isLoggedIn = getToken()
+const AppRoutes: FC = () => {
+ const isLoggedIn = !!getToken()
+ const { data: user, isLoading } = useGetMe({ enabled: isLoggedIn })
+ const profileIncomplete = isLoggedIn && needsProfileCompletion(user)
+ if (isLoggedIn && isLoading) {
+ return (
+
+
+
+ )
+ }
+ return (
+
+ {!isLoggedIn ? (
+
+ ) : profileIncomplete ? (
+
+ ) : (
+
+ )}
+
+
+ )
+}
+
+const App: FC = () => {
return (
-
- {isLoggedIn ? : }
-
-
+
)
}
diff --git a/src/config/Paths.tsx b/src/config/Paths.tsx
index 2a0aba5..78f7037 100644
--- a/src/config/Paths.tsx
+++ b/src/config/Paths.tsx
@@ -29,6 +29,7 @@ export const Paths = {
},
auth: {
login: '/login',
+ completeProfile: '/complete-profile',
},
payment: {
payInvoice: '/payments/invoice/',
diff --git a/src/config/statusRegistry.ts b/src/config/statusRegistry.ts
index 1d864ea..ff5e0a9 100644
--- a/src/config/statusRegistry.ts
+++ b/src/config/statusRegistry.ts
@@ -22,10 +22,8 @@ export const statusRegistry: Record = {
[ProformaInvoiceStatusEnum.PARTIALLY_CONFIRMED]: { label: 'تایید جزئی', variant: 'info' },
[ProformaInvoiceStatusEnum.CONFIRMED]: { label: 'تایید شده', variant: 'success' },
- // --- Invoice confirm status (from API) ---
+ // --- Invoice confirm status (from API; partially_confirmed/confirmed covered by enum above) ---
pending: { label: 'تایید نشده', variant: 'warning' },
- partially_confirmed: { label: 'تایید جزئی', variant: 'info' },
- confirmed: { label: 'تایید شده', variant: 'success' },
// --- OrderStatusEnum ---
[OrderStatusEnum.CREATED]: { label: 'ایجاد شده', variant: 'info' },
diff --git a/src/pages/auth/CompleteProfile.tsx b/src/pages/auth/CompleteProfile.tsx
new file mode 100644
index 0000000..9ebc1a0
--- /dev/null
+++ b/src/pages/auth/CompleteProfile.tsx
@@ -0,0 +1,28 @@
+import { type FC } from 'react'
+import LogoImage from '../../assets/images/logo.svg'
+import LogoSmallImage from '../../assets/images/logo-small.svg'
+import CompleteProfileForm from './components/CompleteProfileForm'
+
+const CompleteProfile: FC = () => {
+ return (
+
+
+
+
+
+

+

+
+
+
+
+
+
+

+
+
+
+ )
+}
+
+export default CompleteProfile
diff --git a/src/pages/auth/components/CompleteProfileForm.tsx b/src/pages/auth/components/CompleteProfileForm.tsx
new file mode 100644
index 0000000..0b8a72f
--- /dev/null
+++ b/src/pages/auth/components/CompleteProfileForm.tsx
@@ -0,0 +1,101 @@
+import { type FC } from 'react'
+import Input from '@/components/Input'
+import { useFormik } from 'formik'
+import * as Yup from 'yup'
+import Button from '@/components/Button'
+import Error from '@/components/Error'
+import { useGetMe, useUpdateProfile } from '@/pages/user/hooks/useUserData'
+import { toast } from '@/shared/toast'
+import { extractErrorMessage } from '@/config/func'
+import { Paths } from '@/config/Paths'
+import type { UpdateProfileType } from '@/pages/user/types/Types'
+
+const CompleteProfileForm: FC = () => {
+ const { data: user } = useGetMe()
+ const updateProfile = useUpdateProfile()
+
+ const formik = useFormik({
+ enableReinitialize: true,
+ initialValues: {
+ firstName: user?.firstName ?? '',
+ lastName: user?.lastName ?? '',
+ },
+ validationSchema: Yup.object({
+ firstName: Yup.string()
+ .trim()
+ .required('نام اجباری است.'),
+ lastName: Yup.string()
+ .trim()
+ .required('نام خانوادگی اجباری است.'),
+ }),
+ onSubmit(values) {
+ updateProfile.mutate(
+ {
+ firstName: values.firstName.trim(),
+ lastName: values.lastName.trim(),
+ },
+ {
+ onSuccess() {
+ toast('اطلاعات شما با موفقیت ثبت شد', 'success')
+ window.location.href = Paths.home
+ },
+ onError(error) {
+ toast(extractErrorMessage(error), 'error')
+ },
+ },
+ )
+ },
+ })
+
+ return (
+
+
+
+ تکمیل اطلاعات
+
+
+ لطفاً نام و نام خانوادگی خود را وارد کنید .
+
+
+
+
+
+
+ )
+}
+
+export default CompleteProfileForm
diff --git a/src/pages/auth/components/LoginStep2.tsx b/src/pages/auth/components/LoginStep2.tsx
index 5d4d7fa..57f3005 100644
--- a/src/pages/auth/components/LoginStep2.tsx
+++ b/src/pages/auth/components/LoginStep2.tsx
@@ -12,6 +12,7 @@ import { extractErrorMessage, setRefreshToken } from '../../../config/func'
import { setToken } from '../../../config/func'
import { toast } from '@/shared/toast'
import { Paths } from '@/config/Paths'
+import { needsProfileCompletion } from '@/pages/user/utils/profileUtils'
const LoginStep2: FC = () => {
@@ -38,8 +39,10 @@ const LoginStep2: FC = () => {
onSuccess(data) {
setToken(data?.data?.tokens?.accessToken?.token)
setRefreshToken(data?.data?.tokens?.refreshToken?.token)
- // Check if there's a redirect parameter in the URL
- window.location.href = Paths.profile
+ const user = data?.data?.user
+ window.location.href = needsProfileCompletion(user)
+ ? Paths.auth.completeProfile
+ : Paths.home
},
onError(error) {
toast(extractErrorMessage(error), 'error')
diff --git a/src/pages/user/hooks/useUserData.ts b/src/pages/user/hooks/useUserData.ts
index c1292db..ebad736 100644
--- a/src/pages/user/hooks/useUserData.ts
+++ b/src/pages/user/hooks/useUserData.ts
@@ -1,9 +1,22 @@
-import { useQuery } from "@tanstack/react-query";
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import * as api from "../service/UserService";
+import type { UpdateProfileType } from "../types/Types";
-export const useGetMe = () => {
+export const useGetMe = (options?: { enabled?: boolean }) => {
return useQuery({
queryKey: ["me"],
queryFn: api.getMe,
+ enabled: options?.enabled ?? true,
+ });
+};
+
+export const useUpdateProfile = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (variables: UpdateProfileType) => api.updateProfile(variables),
+ onSuccess: (data) => {
+ queryClient.setQueryData(["me"], data);
+ },
});
};
diff --git a/src/pages/user/service/UserService.ts b/src/pages/user/service/UserService.ts
index e539ac9..d9b5903 100644
--- a/src/pages/user/service/UserService.ts
+++ b/src/pages/user/service/UserService.ts
@@ -1,7 +1,17 @@
import axios from "@/config/axios";
-import type { GetMeResponseType } from "@/pages/user/types/Types";
+import type { GetMeResponseType, UpdateProfileType } from "@/pages/user/types/Types";
export const getMe = async (): Promise => {
const { data } = await axios.get("/public/users/me");
return data.data;
};
+
+export const updateProfile = async (
+ params: UpdateProfileType,
+): Promise => {
+ const { data } = await axios.patch(
+ "/public/users/update",
+ params,
+ );
+ return data.data;
+};
diff --git a/src/pages/user/types/Types.ts b/src/pages/user/types/Types.ts
index e916604..ec58df0 100644
--- a/src/pages/user/types/Types.ts
+++ b/src/pages/user/types/Types.ts
@@ -14,3 +14,8 @@ export interface UserMeType {
}
export type GetMeResponseType = BaseResponse;
+
+export type UpdateProfileType = {
+ firstName: string;
+ lastName: string;
+};
diff --git a/src/pages/user/utils/profileUtils.ts b/src/pages/user/utils/profileUtils.ts
new file mode 100644
index 0000000..d098aa5
--- /dev/null
+++ b/src/pages/user/utils/profileUtils.ts
@@ -0,0 +1,9 @@
+type ProfileNameFields = {
+ firstName?: string | null;
+ lastName?: string | null;
+};
+
+export const needsProfileCompletion = (user?: ProfileNameFields | null): boolean => {
+ if (!user) return false;
+ return !user.firstName?.trim() || !user.lastName?.trim();
+};
diff --git a/src/router/CompleteProfileRouter.tsx b/src/router/CompleteProfileRouter.tsx
new file mode 100644
index 0000000..08bf13d
--- /dev/null
+++ b/src/router/CompleteProfileRouter.tsx
@@ -0,0 +1,13 @@
+import CompleteProfile from '@/pages/auth/CompleteProfile'
+import { type FC } from 'react'
+import { Route, Routes } from 'react-router-dom'
+
+const CompleteProfileRouter: FC = () => {
+ return (
+
+ } />
+
+ )
+}
+
+export default CompleteProfileRouter