1// applytop/app-1.5.107/src/helpers/native-bridge.js 2function nativePlugins() { 3 try { 4 const cap = window.Capacitor; 5 if (!cap || typeof cap.isNativePlatform !== "function" || !cap.isNativePlatform()) return null; 6 return cap.Plugins || {}; 7 } catch (_) { 8 return null; 9 } 10} 11function install(P) { 12 const App = P.App; 13 const Share = P.Share; 14 const Camera = P.Camera; 15 const PushNotifications = P.PushNotifications; 16 const Network = P.Network; 17 const Browser = P.Browser; 18 const SecureStorage = P.SecureStoragePlugin; 19 const BiometricAuth = P.BiometricAuthNative; 20 function getStore() { 21 return typeof window.CdvPurchase !== "undefined" ? window.CdvPurchase.store : null; 22 } 23 const GPB_PRODUCTS = [ 24 { id: "credits_small", type: "consumable" }, 25 { id: "credits_medium", type: "consumable" }, 26 { id: "credits_large", type: "consumable" }, 27 { id: "pro_lifetime", type: "non consumable" }, 28 { id: "pro_weekly", type: "paid subscription" }, 29 { id: "pro_monthly", type: "paid subscription" }, 30 { id: "pro_yearly", type: "paid subscription" }, 31 { id: "career_growth_weekly", type: "paid subscription" } 32 ]; 33 const _pendingPurchases = /* @__PURE__ */ new Map(); 34 let _storeInitialized = false; 35 function initStore() { 36 const store = getStore(); 37 if (!store || _storeInitialized) return; 38 _storeInitialized = true; 39 try { 40 const CdvPurchase = window.CdvPurchase; 41 const Platform = CdvPurchase.Platform; 42 const ProductType = CdvPurchase.ProductType; 43 const typeMap = { 44 "consumable": ProductType.CONSUMABLE, 45 "non consumable": ProductType.NON_CONSUMABLE, 46 "paid subscription": ProductType.PAID_SUBSCRIPTION 47 }; 48 store.register(GPB_PRODUCTS.map((p) => ({ 49 id: p.id, 50 type: typeMap[p.type] || ProductType.CONSUMABLE, 51 platform: Platform.GOOGLE_PLAY 52 }))); 53 store.when().approved((transaction) => { 54 for (const productId of (transaction.products || []).map((p) => p.id)) { 55 const waiter = _pendingPurchases.get(productId); 56 if (waiter) { 57 waiter.resolve({ 58 purchaseToken: transaction.purchaseId || transaction.transactionId, 59 productId, 60 orderId: transaction.transactionId || null 61 }); 62 _pendingPurchases.delete(productId); 63 } 64 } 65 transaction.finish(); 66 }).cancelled((transaction) => { 67 for (const productId of (transaction.products || []).map((p) => p.id)) { 68 const waiter = _pendingPurchases.get(productId); 69 if (waiter) { 70 waiter.resolve(null); 71 _pendingPurchases.delete(productId); 72 } 73 } 74 }); 75 store.error((err) => { 76 console.warn("[AT bridge] Store error:", err); 77 }); 78 store.initialize([Platform.GOOGLE_PLAY]).catch((err) => { 79 console.warn("[AT bridge] Store initialize failed:", err); 80 }); 81 } catch (err) { 82 console.warn("[AT bridge] initStore failed:", err); 83 } 84 } 85 async function startPurchase(productId) { 86 const store = getStore(); 87 if (!store) { 88 console.warn("[AT bridge] cordova-plugin-purchase not loaded"); 89 return null; 90 } 91 initStore(); 92 const offer = store.get(productId)?.getOffer(); 93 if (!offer) { 94 console.warn("[AT bridge] No Play offer for product:", productId); 95 return { error: true, message: "This purchase is not available on this build" }; 96 } 97 return new Promise((resolve, reject) => { 98 _pendingPurchases.set(productId, { resolve, reject }); 99 offer.order().catch((err) => { 100 console.warn("[AT bridge] order() failed:", err); 101 const waiter = _pendingPurchases.get(productId); 102 if (waiter) { 103 waiter.resolve(null); 104 _pendingPurchases.delete(productId); 105 } 106 }); 107 }); 108 } 109 const TOKEN_KEY = "at.token"; 110 const USER_ID_KEY = "at.userId"; 111 const USER_EMAIL_KEY = "at.email"; 112 async function saveToken({ token, userId, email }) { 113 if (!SecureStorage) return false; 114 try { 115 await SecureStorage.set({ key: TOKEN_KEY, value: token }); 116 if (userId) await SecureStorage.set({ key: USER_ID_KEY, value: userId }); 117 if (email) await SecureStorage.set({ key: USER_EMAIL_KEY, value: email }); 118 return true; 119 } catch (err) { 120 console.warn("[AT bridge] saveToken failed:", err); 121 return false;
122 } 123 } 124 async function getToken() { 125 if (!SecureStorage) return null; 126 try { 127 const tokenRes = await SecureStorage.get({ key: TOKEN_KEY }).catch(() => null); 128 const userIdRes = await SecureStorage.get({ key: USER_ID_KEY }).catch(() => null); 129 const emailRes = await SecureStorage.get({ key: USER_EMAIL_KEY }).catch(() => null); 130 if (!tokenRes?.value || !userIdRes?.value) return null; 131 return { token: tokenRes.value, userId: userIdRes.value, email: emailRes?.value || null }; 132 } catch (err) { 133 console.warn("[AT bridge] getToken failed:", err); 134 return null; 135 } 136 } 137 async function clearToken() { 138 if (!SecureStorage) return; 139 try { 140 await SecureStorage.remove({ key: TOKEN_KEY }).catch(() => { 141 }); 142 await SecureStorage.remove({ key: USER_ID_KEY }).catch(() => { 143 }); 144 await SecureStorage.remove({ key: USER_EMAIL_KEY }).catch(() => { 145 }); 146 } catch (_) { 147 } 148 } 149 let _cachedFcmToken = null; 150 let _fcmTokenWaiters = []; 151 function setFcmToken(token) { 152 _cachedFcmToken = token; 153 _fcmTokenWaiters.forEach((fn) => fn(token)); 154 _fcmTokenWaiters = []; 155 } 156 async function pushIsSafe() { 157 try { 158 const ATPush = P.ATPush; 159 if (!ATPush || typeof ATPush.isAvailable !== "function") return false; 160 const res = await ATPush.isAvailable(); 161 return !!(res && res.available); 162 } catch (_) { 163 return false; 164 } 165 } 166 async function getFcmToken() { 167 if (_cachedFcmToken) return _cachedFcmToken; 168 if (!PushNotifications) return null; 169 if (!await pushIsSafe()) { 170 console.warn("[AT bridge] Push unavailable (Firebase not initialised in this build); skipping registration"); 171 return null; 172 } 173 try { 174 const perm = await PushNotifications.requestPermissions(); 175 if (perm.receive !== "granted") return null; 176 await PushNotifications.register(); 177 return await new Promise((resolve) => { 178 const timeout = setTimeout(() => resolve(null), 1e4); 179 _fcmTokenWaiters.push((token) => { 180 clearTimeout(timeout); 181 resolve(token); 182 }); 183 }); 184 } catch (err) { 185 console.warn("[AT bridge] getFcmToken failed:", err); 186 return null; 187 } 188 } 189 async function share({ title, text, url }) { 190 if (!Share) return false; 191 try { 192 await Share.share({ title, text, url, dialogTitle: title }); 193 return true; 194 } catch (_) { 195 return false; 196 } 197 } 198 async function cameraCapture() { 199 if (!Camera) return null; 200 try { 201 const photo = await Camera.getPhoto({ 202 quality: 80, 203 allowEditing: false, 204 resultType: "base64", 205 source: "CAMERA" 206 }); 207 return { base64: photo.base64String, mimeType: "image/" + (photo.format || "jpeg") }; 208 } catch (_) { 209 return null; 210 } 211 } 212 async function enableBiometric() { 213 if (!BiometricAuth) return false; 214 try { 215 const info = await BiometricAuth.checkBiometry(); 216 return !!info?.isAvailable; 217 } catch (_) { 218 return false; 219 } 220 } 221 async function promptBiometric() { 222 if (!BiometricAuth) return true; 223 try { 224 const info = await BiometricAuth.checkBiometry(); 225 if (!info?.isAvailable) return true; 226 await BiometricAuth.authenticate({ 227 reason: "Unlock ApplyTop", 228 cancelTitle: "Use password", 229 allowDeviceCredential: true 230 }); 231 return true; 232 } catch (_) { 233 return false; 234 } 235 } 236 async function logout() { 237 await clearToken(); 238 return true; 239 } 240 async function openExternal2({ url }) { 241 if (!Browser) { 242 window.open(url, "_blank"); 243 return true; 244 } 245 try { 246 await Browser.open({ url }); 247 return true; 248 } catch (err) { 249 console.warn("[AT bridge] openExternal failed:", err); 250 return false; 251 } 252 } 253 function wireLifecycleEvents() { 254 if (App) { 255 try { 256 App.addListener("appStateChange", ({ isActive }) => { 257 window.dispatchEvent(new CustomEvent(isActive ? "at:resume" : "at:pause")); 258 }); 259 App.addListener("backButton", ({ canGoBack }) => { 260 if (window.history.length > 1 || canGoBack) window.history.back(); 261 else App.exitApp(); 262 }); 263 App.addListener("appUrlOpen", ({ url }) => { 264 try { 265 const parsed = new URL(url); 266 if (parsed.protocol === "applytop:") { 267 window.location.href = "/" + parsed.host + parsed.pathname + (parsed.search || ""); 268 } else if (parsed.host && parsed.host.endsWith("applytop.com")) { 269 window.location.href = parsed.pathname + parsed.search + parsed.hash; 270 } 271 } catch (err) { 272 console.warn("[AT bridge] appUrlOpen parse failed:", err); 273 } 274 }); 275 } catch (err) { 276 console.warn("[AT bridge] App listener wiring failed:", err); 277 } 278 } 279 if (Network) {
280 try { 281 Network.addListener("networkStatusChange", (status) => { 282 window.dispatchEvent(new CustomEvent("at:networkchange", { 283 detail: { connected: status.connected, type: status.connectionType } 284 })); 285 }); 286 Network.getStatus().then((status) => { 287 window.dispatchEvent(new CustomEvent("at:networkchange", { 288 detail: { connected: status.connected, type: status.connectionType } 289 })); 290 }).catch(() => { 291 }); 292 } catch (err) { 293 console.warn("[AT bridge] Network listener wiring failed:", err); 294 } 295 } 296 if (PushNotifications) { 297 try { 298 PushNotifications.addListener("registration", ({ value }) => setFcmToken(value)); 299 PushNotifications.addListener("registrationError", (err) => { 300 console.warn("[AT bridge] FCM registration error:", err); 301 }); 302 PushNotifications.addListener("pushNotificationActionPerformed", ({ notification }) => { 303 const data = notification?.data || {}; 304 if (data.url) window.location.href = data.url; 305 else if (data.alertId) window.location.href = "/dashboard/matches?alert=" + encodeURIComponent(data.alertId); 306 else window.location.href = "/dashboard/matches"; 307 }); 308 } catch (err) { 309 console.warn("[AT bridge] Push listener wiring failed:", err); 310 } 311 } 312 } 313 window.AT = { 314 saveToken, 315 getToken, 316 clearToken, 317 purchase: ({ productId }) => startPurchase(productId), 318 purchaseSubscription: ({ productId }) => startPurchase(productId), 319 share, 320 cameraCapture, 321 getFcmToken, 322 enableBiometric, 323 promptBiometric, 324 logout, 325 openExternal: openExternal2 326 }; 327 wireLifecycleEvents(); 328 if (typeof window.CdvPurchase !== "undefined") initStore(); 329 else document.addEventListener("deviceready", initStore, { once: true }); 330} 331try { 332 const P = nativePlugins(); 333 if (P) install(P); 334} catch (err) { 335 console.warn("[AT bridge] install failed:", err); 336} 337
338// applytop/app-1.5.107/src/helpers/net.js 339function nativeHeaders() { 340 try { 341 if (window.Capacitor && window.Capacitor.isNativePlatform && window.Capacitor.isNativePlatform()) { 342 return { 343 "X-AT-Client": "android", 344 "X-AT-App-Version": window.constant && window.constant.appVersion || "" 345 }; 346 } 347 } catch (_) { 348 } 349 return {}; 350} 351function clearSession() { 352 localStorage.removeItem("token"); 353 localStorage.removeItem("user"); 354 try { 355 if (window.AT && window.AT.logout) window.AT.logout(); 356 } catch (_) { 357 } 358} 359async function call(path, method, data) { 360 const cleanPath = path.replace(/^\/+/, "").replace(/\/+$/, ""); 361 const apiUrl = window.constant.apiUrl.replace(/\/+$/, ""); 362 let fullUrl = `${apiUrl}/${cleanPath}`; 363 if (method === "POST") { 364 let response = await fetch(fullUrl, { 365 method: "POST", 366 headers: { 367 "Content-Type": "application/json;charset=utf-8", 368 ...nativeHeaders() 369 }, 370 body: JSON.stringify(data) 371 }); 372 let result = await response.json(); 373 if (result.error && result.errorMessage === "Auth Error") { 374 clearSession(); 375 window.location.href = "/login"; 376 return result; 377 } 378 return result; 379 } else if (method === "FORMDATA") { 380 let response = await fetch(fullUrl, { 381 method: "POST", 382 headers: { ...nativeHeaders() }, 383 body: data 384 }); 385 let result = await response.json(); 386 if (result.error && result.errorMessage === "Auth Error") { 387 clearSession(); 388 window.location.href = "/login"; 389 return result; 390 } 391 return result; 392 } else if (method === "GET") { 393 const authHeaders = {}; 394 if (data) { 395 const separator = fullUrl.includes("?") ? "&" : "?"; 396 const queryParams = []; 397 if (data.token) { 398 authHeaders["Authorization"] = `Bearer ${data.token}`; 399 delete data.token; 400 } 401 if (data.userId) { 402 queryParams.push(`userId=${encodeURIComponent(data.userId)}`); 403 delete data.userId; 404 } 405 for (const key in data) { 406 if (data[key] !== void 0 && data[key] !== null) { 407 queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`); 408 } 409 } 410 if (queryParams.length > 0) { 411 fullUrl += separator + queryParams.join("&"); 412 } 413 } 414 let response = await fetch(fullUrl, { 415 method: "GET", 416 headers: authHeaders 417 }); 418 if (response.ok) { 419 let result = await response.json(); 420 if (result.error && result.errorMessage === "Auth Error") { 421 clearSession(); 422 window.location.href = "/login"; 423 return result; 424 } 425 return result; 426 } else { 427 console.error("GET request failed:", response.status, response.statusText); 428 let result = await response.json(); 429 if (result.error && result.errorMessage === "Auth Error") { 430 clearSession(); 431 window.location.href = "/login"; 432 return result; 433 } 434 return { 435 success: false, 436 error: `Request failed with status ${response.status}` 437 }; 438 } 439 } 440} 441
442// applytop/app-1.5.107/src/helpers/attribution.js 443var STORAGE_KEY = "applytop.attribution"; 444var FIRST_TOUCH_KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "gclid", "fbclid", "ttclid", "ref"]; 445var LAST_TOUCH_KEYS = ["click_id", "sub_id"]; 446function readStoredRaw() { 447 try { 448 return localStorage.getItem(STORAGE_KEY); 449 } catch (e) { 450 return null; 451 } 452} 453function isInternalReferrer(referrer) { 454 if (!referrer) return false; 455 try { 456 const ref = new URL(referrer); 457 const here = window.location.hostname || ""; 458 if (ref.hostname === here) return true; 459 const refApex = ref.hostname.replace(/^.*?([^.]+\.[^.]+)$/, "$1"); 460 const hereApex = here.replace(/^.*?([^.]+\.[^.]+)$/, "$1"); 461 return !!hereApex && refApex === hereApex; 462 } catch (e) { 463 return false; 464 } 465} 466function captureAttribution() { 467 if (typeof window === "undefined" || typeof localStorage === "undefined") return; 468 let params; 469 try { 470 params = new URLSearchParams(window.location.search || ""); 471 } catch (e) { 472 return; 473 } 474 let existing = {}; 475 const raw = readStoredRaw(); 476 if (raw) { 477 try { 478 const parsed = JSON.parse(raw); 479 if (parsed && typeof parsed === "object") existing = parsed; 480 } catch (e) { 481 } 482 } 483 let changed = false; 484 for (const key of LAST_TOUCH_KEYS) { 485 const v = params.get(key); 486 if (v !== null && v !== "" && existing[key] !== v) { 487 existing[key] = v.slice(0, 512); 488 changed = true; 489 } 490 } 491 for (const key of FIRST_TOUCH_KEYS) { 492 if (existing[key]) continue; 493 const v = params.get(key); 494 if (v !== null && v !== "") { 495 existing[key] = v.slice(0, 512); 496 changed = true; 497 } 498 } 499 if (!existing.referrer_url) { 500 const rawReferrer = (document.referrer || "").slice(0, 2048); 501 if (rawReferrer && !isInternalReferrer(rawReferrer)) { 502 existing.referrer_url = rawReferrer; 503 changed = true; 504 } 505 } 506 if (!existing.landing_page) { 507 existing.landing_page = (window.location.pathname || "/") + (window.location.search || ""); 508 existing.landing_page_at = (/* @__PURE__ */ new Date()).toISOString(); 509 changed = true; 510 } 511 if (!changed) return; 512 try { 513 localStorage.setItem(STORAGE_KEY, JSON.stringify(existing)); 514 } catch (e) { 515 } 516} 517function readAttribution() { 518 const raw = readStoredRaw(); 519 if (!raw) return {}; 520 try { 521 const obj = JSON.parse(raw); 522 return obj && typeof obj === "object" ? obj : {}; 523 } catch (e) { 524 return {}; 525 } 526} 527function clearAttribution() { 528 try { 529 localStorage.removeItem(STORAGE_KEY); 530 } catch (e) { 531 } 532} 533captureAttribution(); 534
535// applytop/app-1.5.107/src/helpers/track.js 536var SESSION_KEY = "applytop.anon_session"; 537function getOrCreateSessionId() { 538 try { 539 let id = localStorage.getItem(SESSION_KEY); 540 if (id) return id; 541 const rand = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).slice(2); 542 id = `anon_${rand}`.slice(0, 64); 543 localStorage.setItem(SESSION_KEY, id); 544 return id; 545 } catch (_) { 546 return null; 547 } 548} 549function readAnonSessionId() { 550 try { 551 return localStorage.getItem(SESSION_KEY) || null; 552 } catch (_) { 553 return null; 554 } 555} 556function clearAnonSessionId() { 557 try { 558 localStorage.removeItem(SESSION_KEY); 559 } catch (_) { 560 } 561} 562function abVariant() { 563 const key = getOrCreateSessionId(); 564 if (!key) return "A"; 565 let h = 5381; 566 const s = String(key); 567 for (let i = 0; i < s.length; i++) h = (h << 5) + h + s.charCodeAt(i) | 0; 568 return (h & 1) === 0 ? "A" : "B"; 569} 570function isLandingPath(pathname) { 571 const p = (pathname || "/").replace(/\/+$/, "") || "/"; 572 return p === "/" || p === "/index" || p === "/pl" || p === "/es" || p === "/hi"; 573} 574function track(eventType, opts = {}) { 575 if (!eventType) return; 576 try { 577 let user = null; 578 try { 579 user = JSON.parse(localStorage.getItem("user") || "null"); 580 } catch (_) { 581 } 582 const body = { 583 eventType, 584 metadata: { 585 ...readAttribution(), 586 ...opts.metadata || {} 587 } 588 }; 589 if (user && user.id && user.token) { 590 body.userId = user.id; 591 body.token = user.token; 592 } else { 593 body.sessionId = getOrCreateSessionId(); 594 } 595 if (opts.cvId) body.cvId = opts.cvId; 596 if (opts.jobId) body.jobId = opts.jobId; 597 if (opts.variant) body.variant = opts.variant; 598 if (opts.trigger) body.trigger = opts.trigger; 599 if (opts.path) body.path = opts.path; 600 if (opts.referrer) body.referrer = opts.referrer; 601 call("events/track", "POST", body).catch(() => { 602 }); 603 } catch (_) { 604 } 605} 606var bootstrapped = false; 607function bootstrapAutoTracking() { 608 if (typeof window === "undefined" || typeof document === "undefined") return; 609 if (bootstrapped) return; 610 bootstrapped = true; 611 if (typeof location !== "undefined" && location.pathname && location.pathname.startsWith("/roppongi")) { 612 return; 613 } 614 const firePageView = () => { 615 try { 616 const path = (location.pathname || "/") + (location.search || ""); 617 const referrer = document.referrer || null; 618 const screenStr = typeof screen !== "undefined" && screen.width && screen.height ? `${screen.width}x${screen.height}` : null; 619 track("page_view", { 620 path, 621 referrer, 622 metadata: screenStr ? { screen: screenStr } : {}, 623 // Stamp the hero A/B bucket on landing views so page_view is the 624 // denominator of the variant funnel. 625 variant: isLandingPath(location.pathname) ? abVariant() : void 0 626 }); 627 } catch (_) { 628 } 629 }; 630 if (document.readyState === "loading") { 631 document.addEventListener("DOMContentLoaded", firePageView, { once: true }); 632 } else { 633 firePageView(); 634 } 635 document.addEventListener("click", (e) => { 636 try { 637 const el = e.target && e.target.closest && e.target.closest("[data-track-cta]"); 638 if (!el) return; 639 const cta = el.getAttribute("data-track-cta"); 640 if (!cta) return; 641 const body = { 642 eventType: "landing_cta_clicked", 643 metadata: { ...readAttribution(), cta }, 644 path: (location.pathname || "/") + (location.search || "") 645 }; 646 if (isLandingPath(location.pathname)) body.variant = abVariant(); 647 let user = null; 648 try { 649 user = JSON.parse(localStorage.getItem("user") || "null"); 650 } catch (_) { 651 } 652 if (user && user.id && user.token) { 653 body.userId = user.id; 654 body.token = user.token; 655 } else { 656 body.sessionId = getOrCreateSessionId(); 657 } 658 const apiUrl = typeof window !== "undefined" && window.constant && window.constant.apiUrl ? window.constant.apiUrl.replace(/\/+$/, "") : null; 659 if (apiUrl && navigator.sendBeacon) { 660 navigator.sendBeacon(`${apiUrl}/events/track`, new Blob([JSON.stringify(body)], { type: "application/json" })); 661 } else { 662 track("landing_cta_clicked", { metadata: { cta }, variant: body.variant, path: body.path }); 663 } 664 } catch (_) { 665 } 666 }, true); 667 document.addEventListener("click", (e) => { 668 try { 669 const a = e.target && e.target.closest && e.target.closest("a[href]"); 670 if (!a) return; 671 const href = a.getAttribute("href") || ""; 672 if (!href || href.startsWith("#") || /^(mailto:|tel:|javascript:)/i.test(href)) return; 673 let url;
674 try { 675 url = new URL(href, location.href); 676 } catch (_) { 677 return; 678 } 679 if (!/^https?:$/i.test(url.protocol)) return; 680 if (url.hostname === location.hostname) return; 681 track("outbound_click", { 682 metadata: { 683 url: url.href.slice(0, 512), 684 text: (a.textContent || "").trim().slice(0, 80) || null 685 } 686 }); 687 } catch (_) { 688 } 689 }, true); 690} 691bootstrapAutoTracking(); 692
693// applytop/app-1.5.107/src/helpers/i18n.js 694var STORAGE_KEY2 = "applytopLang"; 695var supportedLanguages = ["en", "pl", "es", "hi"]; 696var dictionaries = { en: {} }; 697var namespaceCache = /* @__PURE__ */ new Map(); 698function normalizeLanguage(language) { 699 const normalized = String(language || "").toLowerCase().split("-")[0]; 700 return supportedLanguages.includes(normalized) ? normalized : ""; 701} 702function getCurrentLanguage() { 703 const pathMatch = window.location.pathname.match(/^\/([a-z]{2})(?:\/|$)/i); 704 const pathLanguage = normalizeLanguage(pathMatch && pathMatch[1]); 705 if (pathLanguage) { 706 try { 707 localStorage.setItem(STORAGE_KEY2, pathLanguage); 708 } catch { 709 } 710 return pathLanguage; 711 } 712 let storedLanguage = ""; 713 try { 714 storedLanguage = normalizeLanguage(localStorage.getItem(STORAGE_KEY2)); 715 } catch { 716 } 717 if (storedLanguage) return storedLanguage; 718 return normalizeLanguage(navigator.language) || "en"; 719} 720function setCurrentLanguage(language) { 721 const normalized = normalizeLanguage(language) || "en"; 722 try { 723 localStorage.setItem(STORAGE_KEY2, normalized); 724 } catch { 725 } 726 return normalized; 727} 728async function loadNamespace(namespace, language) { 729 const normalizedLanguage = normalizeLanguage(language) || "en"; 730 const cacheKey = `${namespace}:${normalizedLanguage}`; 731 if (namespaceCache.has(cacheKey)) { 732 return namespaceCache.get(cacheKey); 733 } 734 const v = typeof window !== "undefined" && window.__STATICA_VERSION ? `?v=${encodeURIComponent(window.__STATICA_VERSION)}` : ""; 735 const request = fetch(`/i18n/${namespace}/${normalizedLanguage}.json${v}`).then((response) => { 736 if (!response.ok) throw new Error(`Missing i18n namespace: ${cacheKey}`); 737 return response.json(); 738 }).then((messages) => { 739 dictionaries[normalizedLanguage] = { 740 ...dictionaries[normalizedLanguage] || {}, 741 ...messages 742 }; 743 return messages; 744 }).catch((error) => { 745 console.warn("[i18n] Failed to load namespace:", cacheKey, error); 746 return {}; 747 }); 748 namespaceCache.set(cacheKey, request); 749 return request; 750} 751async function loadI18nNamespaces(namespaces, language = getCurrentLanguage()) { 752 const normalizedLanguage = normalizeLanguage(language) || "en"; 753 const uniqueNamespaces = [...new Set(Array.isArray(namespaces) ? namespaces : [namespaces])]; 754 await Promise.all(uniqueNamespaces.map((namespace) => loadNamespace(namespace, normalizedLanguage))); 755 if (normalizedLanguage !== "en") { 756 await Promise.all(uniqueNamespaces.map((namespace) => loadNamespace(namespace, "en"))); 757 } 758} 759function t(key, replacements = {}) { 760 const language = getCurrentLanguage(); 761 const dictionary = dictionaries[language] || {}; 762 let value = dictionary[key] || dictionaries.en[key] || key; 763 Object.keys(replacements).forEach((replacementKey) => { 764 value = value.replaceAll(`{${replacementKey}}`, replacements[replacementKey]); 765 }); 766 return value; 767} 768function translatePage(root = document) { 769 root.querySelectorAll("[data-i18n]").forEach((element) => { 770 element.textContent = t(element.getAttribute("data-i18n")); 771 }); 772 root.querySelectorAll("[data-i18n-title]").forEach((element) => { 773 element.setAttribute("title", t(element.getAttribute("data-i18n-title"))); 774 }); 775 root.querySelectorAll("[data-i18n-placeholder]").forEach((element) => { 776 element.setAttribute("placeholder", t(element.getAttribute("data-i18n-placeholder"))); 777 }); 778 root.querySelectorAll("[data-i18n-aria-label]").forEach((element) => { 779 element.setAttribute("aria-label", t(element.getAttribute("data-i18n-aria-label"))); 780 }); 781} 782window.applytopT = t; 783window.applytopTranslatePage = translatePage; 784window.applytopSetLanguage = setCurrentLanguage; 785window.applytopLoadI18nNamespaces = loadI18nNamespaces; 786
787// applytop/app-1.5.107/src/constant.js 788var buildEnv = "production"; 789function resolveEnv() { 790 const h = (typeof window !== "undefined" && window.location && window.location.hostname || "").toLowerCase(); 791 if (!h) return buildEnv === "production" || buildEnv === "beta" ? buildEnv : "production"; 792 if (h === "dev.applytop.com" || h.endsWith(".dev.applytop.com") || h === "localhost" || h === "127.0.0.1") return "development"; 793 if (h === "betaapp.applytop.com" || h === "beta.applytop.com") return "beta"; 794 return "production"; 795} 796var env = resolveEnv(); 797var config = {}; 798console.log("Initializing constants..."); 799console.log("Environment:", env); 800var GOOGLE_CLIENT_ID = "703868592758-vku0qghr1auocbr4kro1442h33aon53m.apps.googleusercontent.com"; 801var TURNSTILE_SITE_KEY = "0x4AAAAAADICj3XqreulgznT"; 802if (env === "production") { 803 config = { 804 apiKey: "DDe80f841ea7bc9e78946e0b9d6d9b7e200ed5468a", 805 apiUrl: "https://applytop.com/api/", 806 appUrl: "https://applytop.com/", 807 toolsUrl: "https://applytop.com/", 808 websiteUrl: "https://applytop.com/", 809 stripePublicKey: "", 810 // TODO: set after running stripe-products.js --prod 811 googleClientId: GOOGLE_CLIENT_ID, 812 turnstileSiteKey: TURNSTILE_SITE_KEY, 813 env, 814 version: "1.9.0.0" 815 }; 816} else if (env === "beta") { 817 config = { 818 apiKey: "DDe80f841ea7bc9e78946e0b9d6d9b7e200ed5468a", 819 apiUrl: "https://betaapp.applytop.com/api/", 820 appUrl: "https://betaapp.applytop.com/", 821 toolsUrl: "https://betaapp.applytop.com/", 822 websiteUrl: "https://beta.applytop.com/", 823 stripePublicKey: "", 824 // TODO: set from Stripe Dashboard 825 googleClientId: GOOGLE_CLIENT_ID, 826 turnstileSiteKey: TURNSTILE_SITE_KEY, 827 env, 828 version: "1.9.0.0" 829 }; 830} else { 831 config = { 832 apiKey: "DDe80f841ea7bc9e78946e0b9d6d9b7e200ed5468a", 833 apiUrl: "https://dev.applytop.com/api/", 834 appUrl: "https://dev.applytop.com/", 835 toolsUrl: "https://dev.applytop.com/", 836 websiteUrl: "https://dev.applytop.com/", 837 stripePublicKey: "pk_test_51RMqqQQ2YLWu4XdPOLFVk4nmnZJsQe8MHPq3BbNfwBo67bexLbB34vCQmybInxcaAKJQXFywwp9sUytySqALlh2G00mSYfcySm", 838 // TODO: set from Stripe Dashboard (test mode) 839 googleClientId: GOOGLE_CLIENT_ID, 840 turnstileSiteKey: TURNSTILE_SITE_KEY, 841 env, 842 version: "1.9.0.0" 843 }; 844} 845console.log("Config initialized:", config); 846window.constant = config; 847console.log("window.constant set:", window.constant); 848loadI18nNamespaces(["index"]).then(() => translatePage()); 849
850// applytop/app-1.5.107/src/helpers/google.js 851function setCookie(cname, cvalue, exdays) { 852 const d = /* @__PURE__ */ new Date(); 853 d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1e3); 854 const expires = "expires=" + d.toUTCString(); 855 document.cookie = `${cname}=${cvalue};${expires};path=/`; 856} 857async function handleGoogle(response) { 858 if (!response || !response.credential) return; 859 const attribution = readAttribution(); 860 const anonSessionId = readAnonSessionId(); 861 const { ref: referralCode, ...restAttribution } = attribution; 862 try { 863 const resp = await call("auth/googleAuthUser", "POST", { 864 data: { 865 credential: response.credential, 866 referrer: document.referrer || document.location.href, 867 ...restAttribution, 868 ...referralCode ? { referral_code: referralCode } : {}, 869 ...anonSessionId ? { anon_session_id: anonSessionId } : {} 870 } 871 }); 872 if (resp && resp.success && resp.data && resp.data.user && resp.data.token) { 873 const { user, token, redirect, isNewUser } = resp.data; 874 localStorage.setItem("token", token); 875 localStorage.setItem("user", JSON.stringify({ ...user, token })); 876 clearAttribution(); 877 clearAnonSessionId(); 878 setCookie("gsid", "true", 90); 879 if (isNewUser && typeof window.gtag === "function") { 880 window.gtag("event", "sign_up", { method: "google" }); 881 } 882 const target = redirect || "/dashboard"; 883 window.location.href = target; 884 } else { 885 console.warn("Google sign-in failed", resp); 886 } 887 } catch (err) { 888 console.error("Google sign-in error", err); 889 } 890} 891window.handleGoogle = handleGoogle; 892
893// applytop/app-1.5.107/src/helpers/dom.js 894function addClass(path, classNames) { 895 [...document.querySelectorAll(path)].map((i) => i.classList.add(...classNames)); 896} 897function removeClass(path, classNames) { 898 [...document.querySelectorAll(path)].map((i) => i.classList.remove(...classNames)); 899} 900function getFormValues(path, prefix = "") { 901 let form = document.querySelector(path); 902 console.log("FORM", form); 903 if (!form) { 904 console.warn(`Form not found: ${path}`); 905 return {}; 906 } 907 let formValues = Object.values(form).reduce((obj, field) => { 908 if (field.type != "submit") { 909 obj[field.id.replace(prefix, "")] = field.type == "checkbox" ? field.checked : field.value; 910 } 911 return obj; 912 }, {}); 913 console.log("FV", formValues); 914 return formValues; 915} 916function showToast(type, message, duration = 3e3) { 917 let toastContainer = document.getElementById("toast"); 918 if (!toastContainer) { 919 toastContainer = document.createElement("div"); 920 toastContainer.id = "toast"; 921 toastContainer.className = "fixed top-4 right-4 z-50 transform transition-transform duration-300 translate-x-full"; 922 document.body.appendChild(toastContainer); 923 } 924 let toastSuccess = document.getElementById("toast-success"); 925 let toastError = document.getElementById("toast-error"); 926 let toastInfo = document.getElementById("toast-info"); 927 if (!toastSuccess) { 928 toastSuccess = document.createElement("div"); 929 toastSuccess.id = "toast-success"; 930 toastSuccess.className = "hidden items-center p-4 mb-4 rounded-lg shadow text-white bg-green-500"; 931 toastSuccess.innerHTML = ` 932 <svg class="size-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 933 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path> 934 </svg> 935 <span class="text-sm font-medium"></span> 936 `; 937 toastContainer.appendChild(toastSuccess); 938 } 939 if (!toastError) { 940 toastError = document.createElement("div"); 941 toastError.id = "toast-error"; 942 toastError.className = "hidden items-center p-4 mb-4 rounded-lg shadow text-white bg-red-500"; 943 toastError.innerHTML = ` 944 <svg class="size-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 945 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> 946 </svg> 947 <span class="text-sm font-medium"></span> 948 `; 949 toastContainer.appendChild(toastError); 950 } 951 if (!toastInfo) { 952 toastInfo = document.createElement("div"); 953 toastInfo.id = "toast-info"; 954 toastInfo.className = "hidden items-center p-4 mb-4 rounded-lg shadow text-white bg-blue-500"; 955 toastInfo.innerHTML = ` 956 <svg class="size-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 957 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> 958 </svg> 959 <span class="text-sm font-medium"></span> 960 `; 961 toastContainer.appendChild(toastInfo); 962 } 963 toastSuccess.classList.add("hidden"); 964 toastError.classList.add("hidden"); 965 toastInfo.classList.add("hidden"); 966 let targetToast; 967 if (type === "success") { 968 targetToast = toastSuccess; 969 } else if (type === "error") { 970 targetToast = toastError; 971 } else if (type === "info") { 972 targetToast = toastInfo; 973 } else { 974 targetToast = toastInfo; 975 } 976 targetToast.querySelector("span").textContent = message; 977 targetToast.classList.remove("hidden"); 978 targetToast.classList.add("flex"); 979 toastContainer.classList.remove("translate-x-full"); 980 toastContainer.classList.add("translate-x-0"); 981 setTimeout(() => { 982 toastContainer.classList.remove("translate-x-0"); 983 toastContainer.classList.add("translate-x-full"); 984 setTimeout(() => { 985 targetToast.classList.remove("flex"); 986 targetToast.classList.add("hidden"); 987 }, 300); 988 }, duration); 989} 990
991// applytop/app-1.5.107/src/helpers/platform.js 992function isNativeShell() { 993 try { 994 return !!(window.Capacitor && window.Capacitor.isNativePlatform && window.Capacitor.isNativePlatform()); 995 } catch (_) { 996 return false; 997 } 998} 999function isNative() { 1000 try { 1001 return isNativeShell() && !!window.AT; 1002 } catch (_) { 1003 return false; 1004 } 1005} 1006var PLAN_TO_PLAY = { 1007 weekly: "pro_weekly", 1008 monthly: "pro_monthly", 1009 yearly: "pro_yearly", 1010 career_growth: "career_growth_weekly", 1011 careerGrowth: "career_growth_weekly", 1012 lifetime: "pro_lifetime" 1013}; 1014var PACK_TO_PLAY = { 1015 small: "credits_small", 1016 medium: "credits_medium", 1017 large: "credits_large" 1018}; 1019function currentUser() { 1020 try { 1021 return JSON.parse(localStorage.getItem("user")) || null; 1022 } catch (_) { 1023 return null; 1024 } 1025} 1026function authBody(extra = {}) { 1027 const user = currentUser(); 1028 return { userId: user?._id || user?.id, token: user?.token, ...extra }; 1029} 1030async function purchasePlan(planId) { 1031 if (!isNative()) return null; 1032 const productId = PLAN_TO_PLAY[planId]; 1033 if (!productId) return { error: true, message: `Unknown plan: ${planId}` }; 1034 if (productId === "pro_lifetime") { 1035 const result2 = await window.AT.purchase({ productId }); 1036 if (!result2) return null; 1037 return call("googleplay/verifyPurchase", "POST", authBody({ 1038 purchaseToken: result2.purchaseToken, 1039 productId: result2.productId, 1040 orderId: result2.orderId 1041 })); 1042 } 1043 const result = await window.AT.purchaseSubscription({ productId }); 1044 if (!result) return null; 1045 return call("googleplay/verifySubscription", "POST", authBody({ 1046 purchaseToken: result.purchaseToken, 1047 productId: result.productId 1048 })); 1049} 1050async function purchasePack(packId) { 1051 if (!isNative()) return null; 1052 const productId = PACK_TO_PLAY[packId]; 1053 if (!productId) return { error: true, message: `Unknown pack: ${packId}` }; 1054 const result = await window.AT.purchase({ productId }); 1055 if (!result) return null; 1056 return call("googleplay/verifyPurchase", "POST", authBody({ 1057 purchaseToken: result.purchaseToken, 1058 productId: result.productId, 1059 orderId: result.orderId 1060 })); 1061} 1062async function registerForPush() { 1063 if (!isNative()) return false; 1064 try { 1065 const fcmToken = await window.AT.getFcmToken(); 1066 if (!fcmToken) return false; 1067 await call("notifications/registerDevice", "POST", authBody({ 1068 fcmToken, 1069 appVersion: window.constant && window.constant.appVersion || "" 1070 })); 1071 return true; 1072 } catch (_) { 1073 return false; 1074 } 1075} 1076async function unregisterForPush() { 1077 if (!isNative()) return; 1078 try { 1079 const fcmToken = await window.AT.getFcmToken(); 1080 await call("notifications/unregisterDevice", "POST", authBody({ fcmToken })); 1081 } catch (_) { 1082 } 1083} 1084async function persistNativeToken(user) { 1085 if (!isNative() || !user) return; 1086 try { 1087 await window.AT.saveToken({ token: user.token, userId: user._id || user.id, email: user.email }); 1088 } catch (_) { 1089 } 1090} 1091async function restoreNativeSession() { 1092 if (!isNative()) return false; 1093 try { 1094 if (currentUser()?.token) return false; 1095 const stored = await window.AT.getToken(); 1096 if (!stored?.token) return false; 1097 localStorage.setItem("token", stored.token); 1098 localStorage.setItem("user", JSON.stringify({ _id: stored.userId, id: stored.userId, email: stored.email, token: stored.token })); 1099 return true; 1100 } catch (_) { 1101 return false; 1102 } 1103} 1104async function nativeLogout() { 1105 if (!isNative()) return; 1106 try { 1107 await unregisterForPush(); 1108 } catch (_) { 1109 } 1110 try { 1111 await window.AT.logout(); 1112 } catch (_) { 1113 } 1114} 1115async function biometricGate() { 1116 if (!isNative()) return true; 1117 try { 1118 return await window.AT.promptBiometric(); 1119 } catch (_) { 1120 return true; 1121 } 1122} 1123async function nativeShare({ title, text, url }) { 1124 if (!isNative()) return false; 1125 try { 1126 return await window.AT.share({ title, text, url }); 1127 } catch (_) { 1128 return false; 1129 } 1130} 1131async function nativeCameraCapture() { 1132 if (!isNative()) return null; 1133 try { 1134 return await window.AT.cameraCapture(); 1135 } catch (_) { 1136 return null; 1137 } 1138} 1139async function openExternal(url) { 1140 if (!isNative()) { 1141 window.open(url, "_blank"); 1142 return true; 1143 } 1144 try { 1145 return await window.AT.openExternal({ url }); 1146 } catch (_) { 1147 return false;
1148 } 1149} 1150if (typeof window !== "undefined") { 1151 window.atPlatform = { 1152 isNative, 1153 isNativeShell, 1154 purchasePlan, 1155 purchasePack, 1156 registerForPush, 1157 unregisterForPush, 1158 persistNativeToken, 1159 restoreNativeSession, 1160 nativeLogout, 1161 biometricGate, 1162 nativeShare, 1163 nativeCameraCapture, 1164 openExternal, 1165 PLAN_TO_PLAY, 1166 PACK_TO_PLAY 1167 }; 1168} 1169
1170// applytop/app-1.5.107/src/components/login/login.js 1171var login = { 1172 init() { 1173 const form = document.querySelector('form[data-form="login"]'); 1174 if (form) { 1175 form.addEventListener("submit", this.handleSubmit.bind(this)); 1176 } 1177 }, 1178 async handleSubmit(event) { 1179 event.preventDefault(); 1180 const formData = getFormValues("#login-form"); 1181 const errorElement = document.querySelector(".error-message"); 1182 if (errorElement) { 1183 addClass(".error-message", ["hidden"]); 1184 } 1185 try { 1186 const response = await call("auth/login", "POST", { 1187 data: { 1188 email: formData.email, 1189 password: formData.password, 1190 rememberMe: formData["remember-me"] || false 1191 } 1192 }); 1193 if (response.success && response.data && response.data.user && response.data.token) { 1194 const { user, token } = response.data; 1195 localStorage.setItem("token", token); 1196 localStorage.setItem("user", JSON.stringify({ ...user, token })); 1197 try { 1198 await persistNativeToken({ ...user, token }); 1199 registerForPush(); 1200 } catch (_) { 1201 } 1202 showToast("success", "Login successful! Checking your profile..."); 1203 const userId = user.userId || user.id || user._id; 1204 if (!userId) { 1205 showToast("error", "User identification failed after login. Please try again."); 1206 return; 1207 } 1208 try { 1209 const cvsResponse = await call("cvs/list", "POST", { token, userId }); 1210 if (cvsResponse.success && cvsResponse.cvs && cvsResponse.cvs.length === 0) { 1211 showToast("info", "Welcome! Let's complete your profile by uploading a CV."); 1212 setTimeout(() => { 1213 window.location.href = "/onboarding"; 1214 }, 1500); 1215 return; 1216 } 1217 if (cvsResponse.success && cvsResponse.cvs && cvsResponse.cvs.length > 0) { 1218 let hasAlerts = false; 1219 try { 1220 const alertsResp = await call("job-alerts", "POST", { token, userId, limit: 1 }); 1221 hasAlerts = alertsResp.success && (alertsResp.count > 0 || alertsResp.alerts && alertsResp.alerts.length > 0); 1222 } catch (e) { 1223 console.warn("job-alerts existence check failed; proceeding to dashboard", e); 1224 hasAlerts = true; 1225 } 1226 if (hasAlerts) { 1227 setTimeout(() => { 1228 window.location.href = "/dashboard"; 1229 }, 500); 1230 return; 1231 } 1232 showToast("info", "Please complete your profile by adding job positions."); 1233 if (cvsResponse.cvs[0]) { 1234 localStorage.setItem("currentCvData", JSON.stringify(cvsResponse.cvs[0])); 1235 } 1236 setTimeout(() => { 1237 window.location.href = "/onboarding?step=job-positions"; 1238 }, 1500); 1239 return; 1240 } 1241 console.warn("Could not reliably determine CV count:", cvsResponse); 1242 showToast("info", "Proceeding to dashboard."); 1243 setTimeout(() => { 1244 window.location.href = "/dashboard"; 1245 }, 1e3); 1246 } catch (cvError) { 1247 console.error("Error checking profile after login:", cvError); 1248 showToast("warning", "Could not check profile status, redirecting to dashboard."); 1249 setTimeout(() => { 1250 window.location.href = "/dashboard"; 1251 }, 1e3); 1252 } 1253 } else { 1254 if (errorElement) { 1255 errorElement.textContent = response.message || response.data?.message || "Invalid email or password"; 1256 removeClass(".error-message", ["hidden"]); 1257 } 1258 showToast("error", response.message || response.data?.message || "Login failed"); 1259 } 1260 } catch (error) { 1261 console.error("Login error:", error); 1262 if (errorElement) { 1263 errorElement.textContent = "An error occurred. Please try again."; 1264 removeClass(".error-message", ["hidden"]); 1265 } 1266 showToast("error", "An error occurred. Please try again."); 1267 } 1268 } 1269}; 1270var login_default = login; 1271
1272// applytop/app-1.5.107/src/components/login/index.js 1273document.addEventListener("DOMContentLoaded", () => { 1274 login_default.init(); 1275});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.