|
|
@ -79,99 +79,6 @@ function resolvePhoneCodeFromCountryCode(isoCode?: string): string | undefined { |
|
|
return undefined; |
|
|
return undefined; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function requestLocationFromFlutterBridge(): Promise<UserGeoRegion | null> { |
|
|
|
|
|
if (typeof window === "undefined") return Promise.resolve(null); |
|
|
|
|
|
|
|
|
|
|
|
const hasFlutterBridge = |
|
|
|
|
|
typeof (window as any).HabibApp?.postMessage === "function" || |
|
|
|
|
|
typeof (window as any).flutter_inappwebview?.callHandler === "function"; |
|
|
|
|
|
|
|
|
|
|
|
if (!hasFlutterBridge) { |
|
|
|
|
|
return Promise.resolve(null); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve) => { |
|
|
|
|
|
let settled = false; |
|
|
|
|
|
let timer: NodeJS.Timeout | null = null; |
|
|
|
|
|
let unsubscribe: (() => void) | undefined; |
|
|
|
|
|
|
|
|
|
|
|
const cleanup = () => { |
|
|
|
|
|
settled = true; |
|
|
|
|
|
if (timer) clearTimeout(timer); |
|
|
|
|
|
if (unsubscribe) unsubscribe(); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
timer = setTimeout(() => { |
|
|
|
|
|
if (!settled) { |
|
|
|
|
|
cleanup(); |
|
|
|
|
|
console.warn("[GEO_BRIDGE] Timeout waiting for Flutter get_location response"); |
|
|
|
|
|
resolve(null); |
|
|
|
|
|
} |
|
|
|
|
|
}, 4000); |
|
|
|
|
|
|
|
|
|
|
|
const handleFlutterResponse: NonNullable<Window["onFlutterResponse"]> = ( |
|
|
|
|
|
event, |
|
|
|
|
|
) => { |
|
|
|
|
|
if (event.action === "get_location") { |
|
|
|
|
|
cleanup(); |
|
|
|
|
|
if (event.success && event.data) { |
|
|
|
|
|
const data = event.data as any; |
|
|
|
|
|
console.log( |
|
|
|
|
|
"[GEO_BRIDGE] 📥 Received from Flutter get_location:", |
|
|
|
|
|
JSON.stringify(data), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const rawCountry = data.country || data.country_code || ""; |
|
|
|
|
|
const isoCode = |
|
|
|
|
|
data.country_code || |
|
|
|
|
|
(rawCountry && rawCountry.trim().length === 2 |
|
|
|
|
|
? rawCountry.trim().toUpperCase() |
|
|
|
|
|
: undefined); |
|
|
|
|
|
const phoneCode = resolvePhoneCodeFromCountryCode(isoCode); |
|
|
|
|
|
const countryName = |
|
|
|
|
|
resolveCountryName(rawCountry || isoCode, "en") || rawCountry; |
|
|
|
|
|
const countryFa = |
|
|
|
|
|
resolveCountryName(rawCountry || isoCode, "fa") || countryName; |
|
|
|
|
|
|
|
|
|
|
|
console.log( |
|
|
|
|
|
`[GEO_BRIDGE] 🌍 Resolved Country: FA=${countryFa} | EN=${countryName} | Code=${isoCode} | City=${data.city || "None"} | IP=${data.ip || "None"}`, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const region: UserGeoRegion = { |
|
|
|
|
|
ip: data.ip, |
|
|
|
|
|
city: data.city, |
|
|
|
|
|
country: countryName, |
|
|
|
|
|
countryCode: isoCode, |
|
|
|
|
|
phoneCode: phoneCode || "+44", |
|
|
|
|
|
}; |
|
|
|
|
|
resolve(region); |
|
|
|
|
|
} else { |
|
|
|
|
|
resolve(null); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (typeof window.addFlutterResponseListener === "function") { |
|
|
|
|
|
unsubscribe = window.addFlutterResponseListener(handleFlutterResponse); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
console.log("[GEO_BRIDGE] 🚀 Sending { action: 'get_location' } to Flutter..."); |
|
|
|
|
|
if ((window as any).HabibApp?.postMessage) { |
|
|
|
|
|
(window as any).HabibApp.postMessage( |
|
|
|
|
|
JSON.stringify({ action: "get_location" }), |
|
|
|
|
|
); |
|
|
|
|
|
} else if ((window as any).flutter_inappwebview?.callHandler) { |
|
|
|
|
|
(window as any).flutter_inappwebview.callHandler("get_location"); |
|
|
|
|
|
} |
|
|
|
|
|
} catch (err) { |
|
|
|
|
|
console.error("[GEO_BRIDGE] Failed to postMessage to Flutter:", err); |
|
|
|
|
|
cleanup(); |
|
|
|
|
|
resolve(null); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function getUserGeoRegion(force = false): Promise<UserGeoRegion> { |
|
|
export function getUserGeoRegion(force = false): Promise<UserGeoRegion> { |
|
|
if (!force) { |
|
|
if (!force) { |
|
|
const existing = getStoredUserGeoRegion(); |
|
|
const existing = getStoredUserGeoRegion(); |
|
|
@ -189,18 +96,9 @@ export function getUserGeoRegion(force = false): Promise<UserGeoRegion> { |
|
|
|
|
|
|
|
|
geoRegionPromise = (async () => { |
|
|
geoRegionPromise = (async () => { |
|
|
try { |
|
|
try { |
|
|
// 1. Primary: Flutter Native Bridge (uses phone's direct native IP)
|
|
|
|
|
|
const bridgeRegion = await requestLocationFromFlutterBridge(); |
|
|
|
|
|
if (bridgeRegion && (bridgeRegion.country || bridgeRegion.city)) { |
|
|
|
|
|
setStoredUserGeoRegion(bridgeRegion); |
|
|
|
|
|
return bridgeRegion; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 2. Secondary: Direct HTTP Client fallback (if in browser or bridge fails)
|
|
|
|
|
|
|
|
|
// 1. Primary: Habib Backend User Region API (/account/auth/user/region/)
|
|
|
try { |
|
|
try { |
|
|
console.log( |
|
|
|
|
|
"[GEO_AUTO_LOG] 🚀 Requesting /account/auth/user/region/ from backend...", |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
console.log("[GEO_AUTO_LOG] 🚀 Requesting /account/auth/user/region/ from backend..."); |
|
|
const response = await http.get<{ |
|
|
const response = await http.get<{ |
|
|
ip?: string; |
|
|
ip?: string; |
|
|
country?: string; |
|
|
country?: string; |
|
|
@ -211,22 +109,18 @@ export function getUserGeoRegion(force = false): Promise<UserGeoRegion> { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const data = response.data; |
|
|
const data = response.data; |
|
|
console.log( |
|
|
|
|
|
"[GEO_AUTO_LOG] 📥 Backend Raw Response:", |
|
|
|
|
|
JSON.stringify(data), |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
console.log("[GEO_AUTO_LOG] 📥 Backend Raw Response:", JSON.stringify(data)); |
|
|
if (data && (data.country || data.country_code || data.city)) { |
|
|
if (data && (data.country || data.country_code || data.city)) { |
|
|
const rawCountry = data.country || data.country_code || ""; |
|
|
|
|
|
const isoCode = |
|
|
const isoCode = |
|
|
data.country_code || |
|
|
data.country_code || |
|
|
(rawCountry && rawCountry.trim().length === 2 |
|
|
|
|
|
? rawCountry.trim().toUpperCase() |
|
|
|
|
|
|
|
|
(data.country && data.country.trim().length === 2 |
|
|
|
|
|
? data.country.trim().toUpperCase() |
|
|
: undefined); |
|
|
: undefined); |
|
|
const phoneCode = resolvePhoneCodeFromCountryCode(isoCode); |
|
|
const phoneCode = resolvePhoneCodeFromCountryCode(isoCode); |
|
|
const countryName = |
|
|
const countryName = |
|
|
resolveCountryName(rawCountry || isoCode, "en") || rawCountry; |
|
|
|
|
|
|
|
|
resolveCountryName(data.country || isoCode, "en") || data.country; |
|
|
const countryFa = |
|
|
const countryFa = |
|
|
resolveCountryName(rawCountry || isoCode, "fa") || countryName; |
|
|
|
|
|
|
|
|
resolveCountryName(data.country || isoCode, "fa") || countryName; |
|
|
|
|
|
|
|
|
console.log( |
|
|
console.log( |
|
|
`[GEO_AUTO_LOG] 🌍 Resolved Country: FA=${countryFa} | EN=${countryName} | Code=${isoCode} | City=${data.city || "None"} | IP=${data.ip || "None"}`, |
|
|
`[GEO_AUTO_LOG] 🌍 Resolved Country: FA=${countryFa} | EN=${countryName} | Code=${isoCode} | City=${data.city || "None"} | IP=${data.ip || "None"}`, |
|
|
|