| @@ -2,8 +2,9 @@ | ||
| 2 | 2 | import { useQuery } from "@tanstack/react-query"; |
| 3 | 3 | import { apiClient } from "../lib/api-client"; |
| 4 | 4 | import { API_ENDPOINTS } from "../lib/api-endpoints"; |
| 5 | 5 | import { __ } from "../lib/i18n"; |
| 6 | +import { toDateValue } from "../lib/dateFormat"; | |
| 6 | 7 | import { |
| 7 | 8 | LayoutDashboard, |
| 8 | 9 | Calendar, |
| 9 | 10 | CreditCard, |
| @@ -33,8 +34,9 @@ | ||
| 33 | 34 | import Payments from "./account/Payments"; |
| 34 | 35 | import Documents from "./account/Documents"; |
| 35 | 36 | import Profile from "./account/Profile"; |
| 36 | 37 | import SavedTrips from "./account/SavedTrips"; |
| 38 | +import { useToast } from "../components/ui/toast"; | |
| 37 | 39 | |
| 38 | 40 | const navigation: Array<{ |
| 39 | 41 | id: Section; |
| 40 | 42 | label: string; |
| @@ -49,8 +51,9 @@ | ||
| 49 | 51 | ]; |
| 50 | 52 | |
| 51 | 53 | const AccountPage: React.FC = () => { |
| 52 | 54 | const accountShell = useMemo(() => getYatraAccountPageGlobals(), []); |
| 55 | + const { showToast } = useToast(); | |
| 53 | 56 | |
| 54 | 57 | const accountNavigation = React.useMemo(() => { |
| 55 | 58 | const wl = |
| 56 | 59 | typeof window !== "undefined" && |
| @@ -155,8 +158,42 @@ | ||
| 155 | 158 | const newSection = getSectionFromUrl(); |
| 156 | 159 | setSection(newSection); |
| 157 | 160 | }, [urlKey]); |
| 158 | 161 | |
| 162 | + // Surface the result of an email-change confirmation. The confirmation link | |
| 163 | + // (from WordPress-style verification email) redirects here with | |
| 164 | + // ?email_change=success|error; show feedback, open the Profile tab, then | |
| 165 | + // strip the param so a refresh doesn't repeat the toast. | |
| 166 | + React.useEffect(() => { | |
| 167 | + if (typeof window === "undefined") { | |
| 168 | + return; | |
| 169 | + } | |
| 170 | + const params = new URLSearchParams(window.location.search); | |
| 171 | + const outcome = params.get("email_change"); | |
| 172 | + if (outcome !== "success" && outcome !== "error") { | |
| 173 | + return; | |
| 174 | + } | |
| 175 | + if (outcome === "success") { | |
| 176 | + showToast(__("Your email address has been updated.", "yatra"), "success"); | |
| 177 | + setSection("profile"); | |
| 178 | + } else { | |
| 179 | + showToast( | |
| 180 | + __( | |
| 181 | + "This email confirmation link is invalid or has expired.", | |
| 182 | + "yatra", | |
| 183 | + ), | |
| 184 | + "error", | |
| 185 | + ); | |
| 186 | + } | |
| 187 | + params.delete("email_change"); | |
| 188 | + const query = params.toString(); | |
| 189 | + const cleanUrl = `${window.location.pathname}${query ? `?${query}` : ""}`; | |
| 190 | + window.history.replaceState({}, "", cleanUrl); | |
| 191 | + (window as any).__lastAccountSearch = window.location.search; | |
| 192 | + // Run once on mount. | |
| 193 | + // eslint-disable-next-line react-hooks/exhaustive-deps | |
| 194 | + }, []); | |
| 195 | + | |
| 159 | 196 | // Update URL and localStorage when section changes |
| 160 | 197 | const handleSectionChange = (newSection: Section) => { |
| 161 | 198 | setSection(newSection); |
| 162 | 199 | |
| @@ -403,9 +440,9 @@ | ||
| 403 | 440 | const outstanding = payments |
| 404 | 441 | .filter((p: Payment) => p.status === "pending") |
| 405 | 442 | .reduce((sum: number, payment: Payment) => sum + payment.amount, 0); |
| 406 | 443 | const upcoming = bookings.filter( |
| 407 | - (b: Booking) => new Date(b.travel_date) > new Date(), | |
| 444 | + (b: Booking) => toDateValue(b.travel_date) > new Date(), | |
| 408 | 445 | ).length; |
| 409 | 446 | |
| 410 | 447 | // Calculate from real data |
| 411 | 448 | const totalSpent = displayProfile?.total_spent ?? 0; |