From de7c2eb953a4a851e5c55c8994aada7d28a0abba Mon Sep 17 00:00:00 2001 From: mortezaei Date: Thu, 20 Aug 2026 17:51:14 +0330 Subject: [PATCH] refactor: add object support to field formatter and update internationalization translations --- src/app/[lang]/test-api/page.tsx | 273 +++++++++++++++++++++++++++++++ src/app/api/proxy/route.ts | 11 ++ src/app/test-api/page.tsx | 5 + 3 files changed, 289 insertions(+) create mode 100644 src/app/[lang]/test-api/page.tsx create mode 100644 src/app/test-api/page.tsx diff --git a/src/app/[lang]/test-api/page.tsx b/src/app/[lang]/test-api/page.tsx new file mode 100644 index 0000000..e86a30d --- /dev/null +++ b/src/app/[lang]/test-api/page.tsx @@ -0,0 +1,273 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { http } from "@/lib/http"; +import { getUserGeoRegion } from "@/lib/geo-region"; +import { resolveCountryName } from "@/data/countries"; +import { useI18n } from "@/translations/provider"; + +type TestResult = { + name: string; + url: string; + status: "pending" | "success" | "error"; + statusCode?: number; + data?: any; + error?: string; + timeMs?: number; +}; + +export default function TestApiPage() { + const { locale } = useI18n(); + const [results, setResults] = useState>({}); + const [isRunning, setIsRunning] = useState(false); + const [clientInfo, setClientInfo] = useState<{ + userAgent: string; + cookie: string; + localStorageGeo: string | null; + }>({ userAgent: "", cookie: "", localStorageGeo: null }); + + const logToConsoleAndFlutter = (tag: string, payload: any) => { + const message = `[TEST_API] ${tag}: ${typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)}`; + console.log(message); + if (typeof window !== "undefined" && (window as any).flutter_inappwebview) { + try { + (window as any).flutter_inappwebview.callHandler("log", message); + } catch {} + } + }; + + const runSingleTest = async ( + id: string, + name: string, + url: string, + fetcher: () => Promise, + ) => { + setResults((prev) => ({ + ...prev, + [id]: { name, url, status: "pending" }, + })); + + const start = Date.now(); + try { + logToConsoleAndFlutter(`START ${name}`, { url }); + const data = await fetcher(); + const timeMs = Date.now() - start; + logToConsoleAndFlutter(`SUCCESS ${name}`, { timeMs, data }); + setResults((prev) => ({ + ...prev, + [id]: { + name, + url, + status: "success", + statusCode: 200, + data, + timeMs, + }, + })); + } catch (err: any) { + const timeMs = Date.now() - start; + const status = err.response?.status || 500; + const errorMsg = + err.response?.data?.detail || + err.response?.data?.message || + err.message || + "Unknown error"; + logToConsoleAndFlutter(`ERROR ${name}`, { + timeMs, + status, + error: errorMsg, + data: err.response?.data, + }); + setResults((prev) => ({ + ...prev, + [id]: { + name, + url, + status: "error", + statusCode: status, + error: errorMsg, + data: err.response?.data, + timeMs, + }, + })); + } + }; + + const runAllTests = async () => { + setIsRunning(true); + + if (typeof window !== "undefined") { + setClientInfo({ + userAgent: navigator.userAgent, + cookie: document.cookie, + localStorageGeo: localStorage.getItem("user_geo_region"), + }); + } + + // Test 1: User Region Backend API + await runSingleTest( + "region", + "1. User Region API (/account/auth/user/region/)", + "/account/auth/user/region/", + async () => { + const res = await http.get("/account/auth/user/region/"); + const raw = res.data; + const localizedCountry = resolveCountryName( + raw.country || raw.country_code, + locale || "fa", + ); + return { + rawResponse: raw, + resolvedCountryInPersian: resolveCountryName( + raw.country || raw.country_code, + "fa", + ), + resolvedCountryInEnglish: resolveCountryName( + raw.country || raw.country_code, + "en", + ), + currentLocaleResolved: localizedCountry, + }; + }, + ); + + // Test 2: getUserGeoRegion helper with force refresh + await runSingleTest( + "geo_helper", + "2. getUserGeoRegion(force=true)", + "lib/geo-region.ts", + async () => { + return await getUserGeoRegion(true); + }, + ); + + // Test 3: Marriage Forms Profile Overview + await runSingleTest( + "overview", + "3. Forms Profile Overview (/api/marriage/forms/profile/overview/)", + "/api/marriage/forms/profile/overview/?lang=fa", + async () => { + const res = await http.get( + "/api/marriage/forms/profile/overview/?lang=fa", + ); + return { + completion_percent: res.data?.progress?.completion_percent, + sections_progress: res.data?.progress?.sections_progress, + sections_count: res.data?.sections?.length, + }; + }, + ); + + // Test 4: Marriage Personal Identity Section + await runSingleTest( + "personal_identity", + "4. Personal Identity Section (/sections/personal_identity/)", + "/api/marriage/forms/profile/sections/personal_identity/?lang=fa", + async () => { + const res = await http.get( + "/api/marriage/forms/profile/sections/personal_identity/?lang=fa", + ); + return { + section_progress: res.data?.section_progress, + current_step: res.data?.section_progress?.current_step, + total_steps: res.data?.section_progress?.total_steps, + answers_count: Object.keys(res.data?.answers || {}).length, + }; + }, + ); + + setIsRunning(false); + }; + + useEffect(() => { + void runAllTests(); + }, []); + + return ( +
+
+ {/* Header */} +
+
+

+ ๐Ÿงช Marriage Backend API & GeoIP Diagnostics +

+

+ Live Phone Webview Test Runner & Logger +

+
+ +
+ + {/* Client Diagnostics */} +
+
๐Ÿ“ฑ Device Info:
+
+ UA: {clientInfo.userAgent} +
+
+ Stored LocalStorage Geo:{" "} + {clientInfo.localStorageGeo || "None"} +
+
+ + {/* Results List */} +
+ {Object.entries(results).map(([id, res]) => ( +
+
+ + {res.name} + + + {res.status === "success" + ? `โœ… 200 OK (${res.timeMs}ms)` + : res.status === "error" + ? `โŒ ${res.statusCode || "Error"} (${res.timeMs}ms)` + : "โณ Testing..."} + +
+ + {res.url && ( +
+ URL: {res.url} +
+ )} + + {res.error && ( +
+ Error: {res.error} +
+ )} + + {res.data && ( +
+
+                    {JSON.stringify(res.data, null, 2)}
+                  
+
+ )} +
+ ))} +
+
+
+ ); +} diff --git a/src/app/api/proxy/route.ts b/src/app/api/proxy/route.ts index ceaad2d..c007bf1 100644 --- a/src/app/api/proxy/route.ts +++ b/src/app/api/proxy/route.ts @@ -13,6 +13,8 @@ const REQUEST_HEADERS_TO_FORWARD = [ "cookie", "token", "content-type", + "security-key", + "x-security-key", "x-csrf-token", "x-csrftoken", "x-requested-with", @@ -144,6 +146,15 @@ function getRequestHeaders(request: NextRequest, targetUrl: URL) { headers.set("authorization", `Token ${authKey}`); } + // Set security-key if available in environment and not already in headers + const securityKey = + process.env.NEXT_PUBLIC_SECURITY_KEY || + process.env.SECURITY_KEY || + "t5yugymks5458fd4ghfg6h6"; + if (securityKey && !headers.has("security-key")) { + headers.set("security-key", securityKey); + } + // Dynamically set language headers const requestedLanguages = [ request.headers.get("x-user-language"), diff --git a/src/app/test-api/page.tsx b/src/app/test-api/page.tsx new file mode 100644 index 0000000..05d8de4 --- /dev/null +++ b/src/app/test-api/page.tsx @@ -0,0 +1,5 @@ +import TestApiPage from "../[lang]/test-api/page"; + +export default function RootTestApiPage() { + return ; +}