From 0eaa1f93f3511b31e1213ffedada055c77dc1f12 Mon Sep 17 00:00:00 2001 From: ghost2023 Date: Thu, 28 May 2026 15:41:47 +0300 Subject: [PATCH] feat(onboarding): Implement customer onboarding guard in App.tsx, redirecting unprofiled users to OnboardingPage, centralizing user and customer data management in useAuth with cookie-based auth. --- apps/edr-freight-web/portal/src/App.tsx | 15 +- .../portal/src/hooks/useAuth.ts | 18 ++- .../portal/src/pages/portal/MyPortalPage.tsx | 139 +++--------------- .../portal/src/services/api.ts | 8 +- 4 files changed, 46 insertions(+), 134 deletions(-) diff --git a/apps/edr-freight-web/portal/src/App.tsx b/apps/edr-freight-web/portal/src/App.tsx index a546a43d8..ed1c458d1 100644 --- a/apps/edr-freight-web/portal/src/App.tsx +++ b/apps/edr-freight-web/portal/src/App.tsx @@ -42,10 +42,12 @@ import FileUploadSettingsPage from "./pages/admin/FileUploadSettingsPage"; import MyPortalPage from "./pages/portal/MyPortalPage"; import EDRFreightLandingPage from "./pages/EDRFreightLandingPage"; import SignupPage from "./pages/accounts/SignupPage"; +import OnboardingPage from "./pages/accounts/OnboardingPage"; import VerificationOtpPage from "./pages/accounts/VerificationOtpPage"; import SetPasswordPage from "./pages/accounts/SetPasswordPage"; import LoginPage from "./pages/accounts/LoginPage"; import Station from "./components/stations/Station"; +import { useEffect } from "react"; const sidebarItems: SidebarItem[] = [ { label: "My Portal", href: "/", icon: }, @@ -69,9 +71,14 @@ const sidebarItems: SidebarItem[] = [ const App = () => { const navigate = useNavigate(); const location = useLocation(); - const { user, isPending, logout } = useAuth(); + const { user, isPending, logout, customer, customerQuery } = useAuth(); + + console.log({ customer, isPending, user }); + useEffect(() => { + if (!user) return; + // if (!user.hasSetPassword) navigate("/set-password"); + }, [user]); - console.log({ user, isPending }); if (isPending) { return (
@@ -93,6 +100,10 @@ const App = () => { ); } + if (user && !customer && !customerQuery.isPending) { + return ; + } + const displayName = user?.name?.en || user?.username || user?.email || "User"; const userEmail = user?.email; diff --git a/apps/edr-freight-web/portal/src/hooks/useAuth.ts b/apps/edr-freight-web/portal/src/hooks/useAuth.ts index 5b626721c..dd9a1c5b6 100644 --- a/apps/edr-freight-web/portal/src/hooks/useAuth.ts +++ b/apps/edr-freight-web/portal/src/hooks/useAuth.ts @@ -30,6 +30,7 @@ const useAuth = () => { api.auth.getMyInfo.queryOptions({ enabled: !!getCookie("auth-token"), retry: false, + staleTime: 10 * 60 * 1000, }), ); @@ -38,6 +39,8 @@ const useAuth = () => { input: { id: authQuery.data?.id ?? "" }, enabled: !!authQuery.data?.id, retry: false, + staleTime: 10 * 60 * 1000, + refetchOnWindowFocus: false, }), ); @@ -63,8 +66,9 @@ const useAuth = () => { ): Promise> => { try { const res = await api.auth.createUser.call(payload); - localStorage.setItem("auth-token", `auth-token=${res.token}; path=/`); - localStorage.setItem("userId", res.userId); + setCookie("auth-token", res.token, 7); + setCookie("refresh-token", res.refreshToken, 7); + await authQuery.refetch(); const otpCode = res.otp?.split(" ")?.[6] ?? ""; localStorage.setItem("otp", otpCode); localStorage.setItem("otp-phone", payload.phoneNumber); @@ -83,7 +87,7 @@ const useAuth = () => { confirmPassword: string; }): Promise> => { try { - const userId = localStorage.getItem("userId") ?? ""; + const userId = authQuery.data?.id ?? ""; const email = localStorage.getItem("otp-email") ?? ""; const verificationCode = localStorage.getItem("otp") ?? ""; await api.auth.setPassword.call({ @@ -96,6 +100,9 @@ const useAuth = () => { ["userId", "otp", "otp-phone", "otp-email"].forEach((k) => localStorage.removeItem(k), ); + await queryClient.invalidateQueries({ + queryKey: api.auth.getMyInfo.queryKey(), + }); return { success: true, data: undefined }; } catch (err) { return { success: false, error: extractApiError(err) }; @@ -159,10 +166,6 @@ const useAuth = () => { window.location.href = "/login"; }; - const invalidate = async () => { - await Promise.all([authQuery.refetch(), customerQuery.refetch()]); - }; - return { isPending, user: authQuery.data ?? null, @@ -174,7 +177,6 @@ const useAuth = () => { sendOTP, generateVerificationCode, logout, - invalidate, authQuery, customerQuery, }; diff --git a/apps/edr-freight-web/portal/src/pages/portal/MyPortalPage.tsx b/apps/edr-freight-web/portal/src/pages/portal/MyPortalPage.tsx index 231ff068d..d8cced8ba 100644 --- a/apps/edr-freight-web/portal/src/pages/portal/MyPortalPage.tsx +++ b/apps/edr-freight-web/portal/src/pages/portal/MyPortalPage.tsx @@ -1,13 +1,6 @@ -import { - useEffect, - useMemo, - useState, -} from "react"; +import { useEffect, useMemo, useState } from "react"; -import { - Link, - useNavigate, -} from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import { Building2, @@ -31,19 +24,10 @@ import { formatCurrency } from "@/pages/billing/invoices.mock"; import { customersService } from "@/services/customers.service"; -import { getMyInfo } from "@/services/account"; +import { authService } from "@/services/auth.service"; import NewCustomerPage from "../customers/NewCustomerPage"; import { Button } from "@edr/ui-common"; -type Customer = { - id: string; - companyName: string; - firstName: string; - lastName: string; - email: string; - phone: string; -}; - export default function MyPortalPage() { const navigate = useNavigate(); @@ -58,58 +42,10 @@ export default function MyPortalPage() { // MOCK DATA // ------------------------------------------------------------ - const me = useMemo(() => getCurrentCustomer(), []); const myBookings = useMemo(() => getMyBookings(), []); const myShipments = useMemo(() => getMyShipments(), []); const myInvoices = useMemo(() => getMyInvoices(), []); - // ------------------------------------------------------------ - // FETCH CUSTOMER - // ------------------------------------------------------------ - - useEffect(() => { - const initialize = async () => { - try { - setLoading(true); - - const userRes = await getMyInfo(); - const userId = userRes?.data?.id; - localStorage.setItem("currentUser", JSON.stringify(userRes.data)); - // if (!userId) { - // navigate("/login"); - // return; - // } - - const res = await customersService.getByUserId(userId); - if (res) { - setCustomer(res); - return; - } - - // customer not found → onboarding - // navigate("/customers/register"); - } catch (error: any) { - console.error("Customer fetch failed:", error); - - const status = error?.response?.status; - - if (status === 404) { - // navigate("/customers/register"); - return; - } - - if (status === 401) { - // navigate("/login"); - return; - } - } finally { - setLoading(false); - } - }; - - initialize(); - }, [navigate]); - // ------------------------------------------------------------ // LOADING // ------------------------------------------------------------ @@ -118,9 +54,7 @@ export default function MyPortalPage() { return (
-

- Loading portal... -

+

Loading portal...

); @@ -134,9 +68,7 @@ export default function MyPortalPage() { return (
-

- No customer profile found -

+

No customer profile found

{/* */} -
@@ -164,31 +93,24 @@ export default function MyPortalPage() { // ------------------------------------------------------------ const activeBookings = myBookings.filter( - (b) => - b.status === "Confirmed" || - b.status === "In Transit" + (b) => b.status === "Confirmed" || b.status === "In Transit", ); - const activeShipments = myShipments.filter( - (s) => s.status === "In Transit" - ); + const activeShipments = myShipments.filter((s) => s.status === "In Transit"); const outstandingInvoices = myInvoices.filter( - (i) => i.status === "Sent" || i.status === "Overdue" + (i) => i.status === "Sent" || i.status === "Overdue", ); const totalOutstanding = outstandingInvoices.reduce( - (sum, i) => - i.currency === "USD" ? sum + i.amount : sum, - 0 + (sum, i) => (i.currency === "USD" ? sum + i.amount : sum), + 0, ); const totalSpent = myInvoices.reduce( (sum, i) => - i.status === "Paid" && i.currency === "USD" - ? sum + i.amount - : sum, - 0 + i.status === "Paid" && i.currency === "USD" ? sum + i.amount : sum, + 0, ); // ------------------------------------------------------------ @@ -198,13 +120,11 @@ export default function MyPortalPage() { return (
- {/* HERO */}
-
{customer.companyName?.charAt(0)} @@ -244,7 +164,6 @@ export default function MyPortalPage() { {/* KPI */}
-
-

- {label} -

+

{label}

-

- {value} -

+

{value}

-

- {sub} -

+

{sub}

+ {content} ); } - return ( -
- {content} -
- ); -} \ No newline at end of file + return
{content}
; +} diff --git a/apps/edr-freight-web/portal/src/services/api.ts b/apps/edr-freight-web/portal/src/services/api.ts index d05807090..ac1a708da 100644 --- a/apps/edr-freight-web/portal/src/services/api.ts +++ b/apps/edr-freight-web/portal/src/services/api.ts @@ -81,11 +81,7 @@ export const api = { "verifyOTP", authService.verifyOTP, ), - logout: endpoint( - "auth", - "logout", - authService.logout, - ), + logout: endpoint("auth", "logout", authService.logout), }, customers: { @@ -115,7 +111,7 @@ export const api = { customersService.remove(id), ), - getByUserId: endpoint<{ id: string }, Customer>( + getByUserId: endpoint<{ id: string }, Customer | null>( "customers", "getByUserId", ({ id }) => customersService.getByUserId(id),