@hook-sdk/template 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1600 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -1
- package/dist/index.d.ts +114 -1
- package/dist/index.js +1581 -175
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -28,11 +28,21 @@ __export(index_exports, {
|
|
|
28
28
|
DefaultSignupScreen: () => DefaultSignupScreen,
|
|
29
29
|
EmptyState: () => EmptyState,
|
|
30
30
|
ErrorBoundary: () => ErrorBoundary,
|
|
31
|
+
InstallGate: () => InstallGate,
|
|
32
|
+
InstallSplash: () => InstallSplash,
|
|
31
33
|
LoadingState: () => LoadingState,
|
|
32
34
|
PushPrompt: () => PushPrompt2,
|
|
35
|
+
detectAndroidBrowser: () => detectAndroidBrowser,
|
|
36
|
+
detectIOSBrowser: () => detectIOSBrowser,
|
|
37
|
+
detectInAppApp: () => detectInAppApp,
|
|
38
|
+
detectPlatform: () => detectPlatform,
|
|
39
|
+
detectStandalone: () => detectStandalone,
|
|
40
|
+
shouldBlockInstall: () => shouldBlockInstall,
|
|
41
|
+
shouldShowPermanentOption: () => shouldShowPermanentOption,
|
|
33
42
|
useAuth: () => useAuth,
|
|
34
43
|
useAuthPrimitives: () => useAuthPrimitives,
|
|
35
44
|
useForgotForm: () => useForgotForm,
|
|
45
|
+
useInstallPrompt: () => useInstallPrompt,
|
|
36
46
|
useLoginForm: () => useLoginForm,
|
|
37
47
|
usePaywallState: () => usePaywallState,
|
|
38
48
|
usePush: () => usePush,
|
|
@@ -45,7 +55,7 @@ __export(index_exports, {
|
|
|
45
55
|
module.exports = __toCommonJS(index_exports);
|
|
46
56
|
|
|
47
57
|
// src/AppRoot.tsx
|
|
48
|
-
var
|
|
58
|
+
var import_react16 = require("react");
|
|
49
59
|
var import_sdk9 = require("@hook-sdk/sdk");
|
|
50
60
|
|
|
51
61
|
// src/internal/TemplateConfigContext.tsx
|
|
@@ -210,10 +220,1226 @@ function PushPrompt() {
|
|
|
210
220
|
return null;
|
|
211
221
|
}
|
|
212
222
|
|
|
213
|
-
// src/
|
|
223
|
+
// src/components/InstallGate/InstallGate.tsx
|
|
224
|
+
var import_react8 = require("react");
|
|
225
|
+
|
|
226
|
+
// src/hooks/useInstallPrompt.ts
|
|
214
227
|
var import_react5 = require("react");
|
|
228
|
+
var IOS_RE = /iPad|iPhone|iPod/;
|
|
229
|
+
var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
|
|
230
|
+
var ANDROID_RE = /Android/;
|
|
231
|
+
var IN_APP_RE = /Instagram|FBAN|FBAV|BytedanceWebview|TikTok|Line\/|Twitter|Snapchat|Pinterest|LinkedIn|WhatsApp|MicroMessenger|Telegram/i;
|
|
232
|
+
var PERMANENT_DISMISS_REPROMPT_DAYS = 14;
|
|
233
|
+
var SESSION_SKIPS_BEFORE_PERMANENT_OPTION = 2;
|
|
234
|
+
var storageKey = {
|
|
235
|
+
sessionSkip: (slug) => `install:${slug}:session-skip`,
|
|
236
|
+
dismissedAt: (slug) => `install:${slug}:dismissed-at`,
|
|
237
|
+
installedAt: (slug) => `install:${slug}:installed-at`,
|
|
238
|
+
skipCount: (slug) => `install:${slug}:skip-count`
|
|
239
|
+
};
|
|
240
|
+
function detectPlatform(ua) {
|
|
241
|
+
if (IN_APP_RE.test(ua)) return "in-app";
|
|
242
|
+
const isIOS = IOS_RE.test(ua);
|
|
243
|
+
if (isIOS) {
|
|
244
|
+
const isSafari = /Safari/.test(ua) && !IOS_NON_SAFARI_RE.test(ua);
|
|
245
|
+
return isSafari ? "ios-safari" : "ios-other";
|
|
246
|
+
}
|
|
247
|
+
if (ANDROID_RE.test(ua)) return "android";
|
|
248
|
+
return "desktop";
|
|
249
|
+
}
|
|
250
|
+
function detectIOSBrowser(ua) {
|
|
251
|
+
if (!IOS_RE.test(ua)) return null;
|
|
252
|
+
if (/CriOS/.test(ua)) return "chrome";
|
|
253
|
+
if (/FxiOS/.test(ua)) return "firefox";
|
|
254
|
+
if (/EdgiOS/.test(ua)) return "edge";
|
|
255
|
+
if (/Safari/.test(ua)) return "safari";
|
|
256
|
+
return "other";
|
|
257
|
+
}
|
|
258
|
+
function detectAndroidBrowser(ua) {
|
|
259
|
+
if (!ANDROID_RE.test(ua)) return null;
|
|
260
|
+
if (/EdgA/.test(ua)) return "edge";
|
|
261
|
+
if (/OPR|OPT/.test(ua)) return "opera";
|
|
262
|
+
if (/SamsungBrowser/.test(ua)) return "samsung";
|
|
263
|
+
if (/Firefox/.test(ua)) return "firefox";
|
|
264
|
+
if (/Chrome/.test(ua)) return "chrome";
|
|
265
|
+
return "other";
|
|
266
|
+
}
|
|
267
|
+
function detectInAppApp(ua) {
|
|
268
|
+
if (!IN_APP_RE.test(ua)) return null;
|
|
269
|
+
if (/Instagram/i.test(ua)) return "instagram";
|
|
270
|
+
if (/FBAN|FBAV/.test(ua)) return "facebook";
|
|
271
|
+
if (/BytedanceWebview|TikTok/i.test(ua)) return "tiktok";
|
|
272
|
+
if (/WhatsApp/i.test(ua)) return "whatsapp";
|
|
273
|
+
if (/Twitter/i.test(ua)) return "twitter";
|
|
274
|
+
if (/LinkedIn/i.test(ua)) return "linkedin";
|
|
275
|
+
if (/Telegram/i.test(ua)) return "telegram";
|
|
276
|
+
if (/Line\//i.test(ua)) return "line";
|
|
277
|
+
if (/Snapchat/i.test(ua)) return "snapchat";
|
|
278
|
+
if (/Pinterest/i.test(ua)) return "pinterest";
|
|
279
|
+
if (/MicroMessenger/i.test(ua)) return "wechat";
|
|
280
|
+
return "other";
|
|
281
|
+
}
|
|
282
|
+
function detectStandalone() {
|
|
283
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
284
|
+
return { installed: false, source: null };
|
|
285
|
+
}
|
|
286
|
+
const mm = window.matchMedia?.("(display-mode: standalone)");
|
|
287
|
+
if (mm?.matches) return { installed: true, source: "match_media" };
|
|
288
|
+
const fs = window.matchMedia?.("(display-mode: fullscreen)");
|
|
289
|
+
if (fs?.matches) return { installed: true, source: "match_media" };
|
|
290
|
+
if (navigator.standalone === true) return { installed: true, source: "navigator_standalone" };
|
|
291
|
+
return { installed: false, source: null };
|
|
292
|
+
}
|
|
293
|
+
function track(event, props) {
|
|
294
|
+
if (typeof window === "undefined") return;
|
|
295
|
+
window.posthog?.capture?.(event, props);
|
|
296
|
+
}
|
|
297
|
+
function pickVariant(state) {
|
|
298
|
+
if (state.isInstalled) return "none";
|
|
299
|
+
switch (state.platform) {
|
|
300
|
+
case "android":
|
|
301
|
+
return state.isInstallable ? "android-native" : "android-manual";
|
|
302
|
+
case "ios-safari":
|
|
303
|
+
return "ios-safari";
|
|
304
|
+
case "ios-other":
|
|
305
|
+
return "ios-other";
|
|
306
|
+
case "in-app":
|
|
307
|
+
return "in-app";
|
|
308
|
+
case "desktop":
|
|
309
|
+
return state.isInstallable ? "desktop" : "none";
|
|
310
|
+
default:
|
|
311
|
+
return "none";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function safeStorage() {
|
|
315
|
+
if (typeof localStorage === "undefined") return null;
|
|
316
|
+
try {
|
|
317
|
+
localStorage.setItem("__install_probe", "1");
|
|
318
|
+
localStorage.removeItem("__install_probe");
|
|
319
|
+
return localStorage;
|
|
320
|
+
} catch {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function readPermanentDismiss(slug) {
|
|
325
|
+
const storage = safeStorage();
|
|
326
|
+
if (!storage) return { dismissed: false, dismissedAt: null };
|
|
327
|
+
const raw = storage.getItem(storageKey.dismissedAt(slug));
|
|
328
|
+
if (!raw) return { dismissed: false, dismissedAt: null };
|
|
329
|
+
const parsed = Date.parse(raw);
|
|
330
|
+
if (Number.isNaN(parsed)) return { dismissed: false, dismissedAt: null };
|
|
331
|
+
const daysAgo = (Date.now() - parsed) / (1e3 * 60 * 60 * 24);
|
|
332
|
+
return { dismissed: daysAgo < PERMANENT_DISMISS_REPROMPT_DAYS, dismissedAt: raw };
|
|
333
|
+
}
|
|
334
|
+
function readInstalledMarker(slug) {
|
|
335
|
+
const storage = safeStorage();
|
|
336
|
+
if (!storage) return false;
|
|
337
|
+
return storage.getItem(storageKey.installedAt(slug)) !== null;
|
|
338
|
+
}
|
|
339
|
+
function readSkipCount(slug) {
|
|
340
|
+
const storage = safeStorage();
|
|
341
|
+
if (!storage) return 0;
|
|
342
|
+
const raw = storage.getItem(storageKey.skipCount(slug));
|
|
343
|
+
const n = raw ? Number.parseInt(raw, 10) : 0;
|
|
344
|
+
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
345
|
+
}
|
|
346
|
+
function readSessionSkip(slug) {
|
|
347
|
+
if (typeof sessionStorage === "undefined") return false;
|
|
348
|
+
try {
|
|
349
|
+
return sessionStorage.getItem(storageKey.sessionSkip(slug)) === "true";
|
|
350
|
+
} catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function useInstallPrompt(slug) {
|
|
355
|
+
const ua = typeof navigator !== "undefined" && typeof navigator.userAgent === "string" ? navigator.userAgent : "";
|
|
356
|
+
const platform = detectPlatform(ua);
|
|
357
|
+
const iosBrowser = detectIOSBrowser(ua);
|
|
358
|
+
const androidBrowser = detectAndroidBrowser(ua);
|
|
359
|
+
const inAppApp = detectInAppApp(ua);
|
|
360
|
+
const [isInstallable, setIsInstallable] = (0, import_react5.useState)(() => {
|
|
361
|
+
if (typeof window === "undefined") return false;
|
|
362
|
+
return window.__pwaInstallPrompt != null;
|
|
363
|
+
});
|
|
364
|
+
const [isInstalled, setIsInstalled] = (0, import_react5.useState)(() => {
|
|
365
|
+
const { installed } = detectStandalone();
|
|
366
|
+
return installed || readInstalledMarker(slug);
|
|
367
|
+
});
|
|
368
|
+
const [isDismissedSession, setIsDismissedSession] = (0, import_react5.useState)(() => readSessionSkip(slug));
|
|
369
|
+
const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react5.useState)(() => readPermanentDismiss(slug).dismissed);
|
|
370
|
+
const [skipCount, setSkipCount] = (0, import_react5.useState)(() => readSkipCount(slug));
|
|
371
|
+
(0, import_react5.useEffect)(() => {
|
|
372
|
+
if (typeof window === "undefined") return;
|
|
373
|
+
if (window.__pwaInstallPrompt) {
|
|
374
|
+
setIsInstallable(true);
|
|
375
|
+
}
|
|
376
|
+
const onPrompt = (e) => {
|
|
377
|
+
e.preventDefault();
|
|
378
|
+
window.__pwaInstallPrompt = e;
|
|
379
|
+
setIsInstallable(true);
|
|
380
|
+
};
|
|
381
|
+
const onInstalled = () => {
|
|
382
|
+
setIsInstalled(true);
|
|
383
|
+
setIsInstallable(false);
|
|
384
|
+
window.__pwaInstallPrompt = null;
|
|
385
|
+
const storage = safeStorage();
|
|
386
|
+
if (storage) storage.setItem(storageKey.installedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
|
|
387
|
+
};
|
|
388
|
+
window.addEventListener("beforeinstallprompt", onPrompt);
|
|
389
|
+
window.addEventListener("appinstalled", onInstalled);
|
|
390
|
+
return () => {
|
|
391
|
+
window.removeEventListener("beforeinstallprompt", onPrompt);
|
|
392
|
+
window.removeEventListener("appinstalled", onInstalled);
|
|
393
|
+
};
|
|
394
|
+
}, [slug]);
|
|
395
|
+
(0, import_react5.useEffect)(() => {
|
|
396
|
+
if (typeof window === "undefined") return;
|
|
397
|
+
const mq = window.matchMedia?.("(display-mode: standalone)");
|
|
398
|
+
if (!mq) return;
|
|
399
|
+
const handler = (e) => {
|
|
400
|
+
if (e.matches) {
|
|
401
|
+
setIsInstalled(true);
|
|
402
|
+
track("pwa_install_standalone_detected", { slug, source: "match_media" });
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
mq.addEventListener?.("change", handler);
|
|
406
|
+
return () => mq.removeEventListener?.("change", handler);
|
|
407
|
+
}, [slug]);
|
|
408
|
+
const variant = pickVariant({
|
|
409
|
+
platform,
|
|
410
|
+
iosBrowser,
|
|
411
|
+
androidBrowser,
|
|
412
|
+
inAppApp,
|
|
413
|
+
isInstallable,
|
|
414
|
+
isInstalled,
|
|
415
|
+
isDismissedSession,
|
|
416
|
+
isDismissedPermanent,
|
|
417
|
+
skipCount
|
|
418
|
+
});
|
|
419
|
+
const promptInstall = (0, import_react5.useCallback)(async () => {
|
|
420
|
+
if (typeof window === "undefined") return false;
|
|
421
|
+
const prompt = window.__pwaInstallPrompt;
|
|
422
|
+
if (!prompt) return false;
|
|
423
|
+
track("pwa_install_prompt_clicked", { slug });
|
|
424
|
+
try {
|
|
425
|
+
await prompt.prompt();
|
|
426
|
+
const { outcome } = await prompt.userChoice;
|
|
427
|
+
track("pwa_install_prompt_outcome", { slug, outcome });
|
|
428
|
+
if (outcome === "accepted") {
|
|
429
|
+
setIsInstalled(true);
|
|
430
|
+
setIsInstallable(false);
|
|
431
|
+
window.__pwaInstallPrompt = null;
|
|
432
|
+
const storage = safeStorage();
|
|
433
|
+
if (storage) storage.setItem(storageKey.installedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
return false;
|
|
437
|
+
} catch {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
}, [slug]);
|
|
441
|
+
const dismissSession = (0, import_react5.useCallback)(() => {
|
|
442
|
+
if (typeof sessionStorage !== "undefined") {
|
|
443
|
+
try {
|
|
444
|
+
sessionStorage.setItem(storageKey.sessionSkip(slug), "true");
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
const storage = safeStorage();
|
|
449
|
+
const newCount = skipCount + 1;
|
|
450
|
+
if (storage) storage.setItem(storageKey.skipCount(slug), String(newCount));
|
|
451
|
+
setSkipCount(newCount);
|
|
452
|
+
setIsDismissedSession(true);
|
|
453
|
+
track("pwa_install_session_skip", { slug, platform, skip_count: newCount });
|
|
454
|
+
}, [slug, skipCount, platform]);
|
|
455
|
+
const dismissPermanent = (0, import_react5.useCallback)(() => {
|
|
456
|
+
const storage = safeStorage();
|
|
457
|
+
if (storage) storage.setItem(storageKey.dismissedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
|
|
458
|
+
setIsDismissedPermanent(true);
|
|
459
|
+
track("pwa_install_permanent_dismiss", { slug, platform, prior_skip_count: skipCount });
|
|
460
|
+
}, [slug, platform, skipCount]);
|
|
461
|
+
const redirectToSafari = (0, import_react5.useCallback)(() => {
|
|
462
|
+
if (typeof location === "undefined") return;
|
|
463
|
+
track("pwa_install_redirect_to_safari", { slug });
|
|
464
|
+
const url = `safari-https://${location.host}${location.pathname}${location.search}${location.hash}`;
|
|
465
|
+
try {
|
|
466
|
+
window.location.href = url;
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
}, [slug]);
|
|
470
|
+
const copyLink = (0, import_react5.useCallback)(async () => {
|
|
471
|
+
if (typeof navigator === "undefined" || typeof location === "undefined") return;
|
|
472
|
+
try {
|
|
473
|
+
await navigator.clipboard?.writeText?.(location.href);
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
476
|
+
}, []);
|
|
477
|
+
const reset = (0, import_react5.useCallback)(() => {
|
|
478
|
+
const storage = safeStorage();
|
|
479
|
+
if (storage) {
|
|
480
|
+
storage.removeItem(storageKey.dismissedAt(slug));
|
|
481
|
+
storage.removeItem(storageKey.installedAt(slug));
|
|
482
|
+
storage.removeItem(storageKey.skipCount(slug));
|
|
483
|
+
}
|
|
484
|
+
if (typeof sessionStorage !== "undefined") {
|
|
485
|
+
try {
|
|
486
|
+
sessionStorage.removeItem(storageKey.sessionSkip(slug));
|
|
487
|
+
} catch {
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
setIsDismissedSession(false);
|
|
491
|
+
setIsDismissedPermanent(false);
|
|
492
|
+
setSkipCount(0);
|
|
493
|
+
}, [slug]);
|
|
494
|
+
return {
|
|
495
|
+
platform,
|
|
496
|
+
iosBrowser,
|
|
497
|
+
androidBrowser,
|
|
498
|
+
inAppApp,
|
|
499
|
+
isInstallable,
|
|
500
|
+
isInstalled,
|
|
501
|
+
isDismissedSession,
|
|
502
|
+
isDismissedPermanent,
|
|
503
|
+
skipCount,
|
|
504
|
+
variant,
|
|
505
|
+
promptInstall,
|
|
506
|
+
dismissSession,
|
|
507
|
+
dismissPermanent,
|
|
508
|
+
redirectToSafari,
|
|
509
|
+
copyLink,
|
|
510
|
+
reset
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function shouldBlockInstall(state, now = Date.now()) {
|
|
514
|
+
if (state.isInstalled) return false;
|
|
515
|
+
if (state.variant === "none") return false;
|
|
516
|
+
if (state.isDismissedSession) return false;
|
|
517
|
+
if (state.isDismissedPermanent) {
|
|
518
|
+
void now;
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
if (state.platform === "desktop" && !state.isInstallable) return false;
|
|
522
|
+
if (state.platform === "unknown") return false;
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
function shouldShowPermanentOption(state) {
|
|
526
|
+
return state.skipCount >= SESSION_SKIPS_BEFORE_PERMANENT_OPTION;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/components/InstallGate/copy.ts
|
|
530
|
+
var INSTALL_COPY = {
|
|
531
|
+
android: {
|
|
532
|
+
native: {
|
|
533
|
+
title: "Instale no seu celular",
|
|
534
|
+
subtitle: "Acesso r\xE1pido, sem precisar do navegador",
|
|
535
|
+
cta: "Baixar",
|
|
536
|
+
skip: "Continuar no navegador",
|
|
537
|
+
skipPermanent: "N\xE3o me pergunte mais"
|
|
538
|
+
},
|
|
539
|
+
manual: {
|
|
540
|
+
title: "Instale em 2 toques",
|
|
541
|
+
subtitle: 'Toque no menu do navegador e escolha "Instalar aplicativo"',
|
|
542
|
+
step1: "Toque no menu do navegador",
|
|
543
|
+
step2: 'Escolha "Instalar aplicativo"',
|
|
544
|
+
cta: "Entendi",
|
|
545
|
+
skip: "Continuar no navegador",
|
|
546
|
+
skipPermanent: "N\xE3o me pergunte mais"
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
iosSafari: {
|
|
550
|
+
title: "Adicione \xE0 sua Tela de In\xEDcio",
|
|
551
|
+
subtitle: "Siga os 3 passos",
|
|
552
|
+
step1: {
|
|
553
|
+
title: "Toque em Compartilhar",
|
|
554
|
+
subtitle: "Na barra inferior do Safari"
|
|
555
|
+
},
|
|
556
|
+
step2: {
|
|
557
|
+
title: 'Role e toque em "Adicionar \xE0 Tela de In\xEDcio"',
|
|
558
|
+
iconLabel: "Adicionar \xE0 Tela de In\xEDcio"
|
|
559
|
+
},
|
|
560
|
+
step3: {
|
|
561
|
+
title: 'Toque em "Adicionar" pra confirmar',
|
|
562
|
+
buttonLabel: "Adicionar"
|
|
563
|
+
},
|
|
564
|
+
skip: "Continuar no Safari",
|
|
565
|
+
skipPermanent: "N\xE3o me pergunte mais"
|
|
566
|
+
},
|
|
567
|
+
iosOther: {
|
|
568
|
+
title: "Abra no Safari pra instalar",
|
|
569
|
+
subtitle: "No Chrome/Firefox/Edge do iPhone n\xE3o d\xE1 pra instalar PWA. Abra o link no Safari.",
|
|
570
|
+
ctaPrimary: "Abrir no Safari",
|
|
571
|
+
ctaSecondary: "Copiar link",
|
|
572
|
+
copiedToast: "Link copiado. Cole no Safari.",
|
|
573
|
+
skip: "Continuar mesmo assim",
|
|
574
|
+
skipPermanent: "N\xE3o me pergunte mais"
|
|
575
|
+
},
|
|
576
|
+
inApp: {
|
|
577
|
+
instagram: {
|
|
578
|
+
title: "Pra instalar, abra fora do Instagram",
|
|
579
|
+
step1: "Toque em \u22EF (canto superior direito)",
|
|
580
|
+
step2: 'Escolha "Abrir no navegador externo"'
|
|
581
|
+
},
|
|
582
|
+
facebook: {
|
|
583
|
+
title: "Pra instalar, abra fora do Facebook",
|
|
584
|
+
step1: "Toque em \u22EE",
|
|
585
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
586
|
+
},
|
|
587
|
+
tiktok: {
|
|
588
|
+
title: "Pra instalar, abra fora do TikTok",
|
|
589
|
+
step1: "Toque em \u22EF",
|
|
590
|
+
step2: 'Escolha "Abrir no Safari" (iOS) ou "Abrir no Chrome" (Android)'
|
|
591
|
+
},
|
|
592
|
+
whatsapp: {
|
|
593
|
+
title: "Pra instalar, abra fora do WhatsApp",
|
|
594
|
+
step1: "Toque longo no link",
|
|
595
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
596
|
+
},
|
|
597
|
+
twitter: {
|
|
598
|
+
title: "Pra instalar, abra fora do Twitter",
|
|
599
|
+
step1: "Toque em \u22EF",
|
|
600
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
601
|
+
},
|
|
602
|
+
linkedin: {
|
|
603
|
+
title: "Pra instalar, abra fora do LinkedIn",
|
|
604
|
+
step1: "Toque em \u22EF",
|
|
605
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
606
|
+
},
|
|
607
|
+
telegram: {
|
|
608
|
+
title: "Pra instalar, abra fora do Telegram",
|
|
609
|
+
step1: "Toque em \u22EE",
|
|
610
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
611
|
+
},
|
|
612
|
+
line: {
|
|
613
|
+
title: "Pra instalar, abra fora do LINE",
|
|
614
|
+
step1: "Toque em \u22EF",
|
|
615
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
616
|
+
},
|
|
617
|
+
snapchat: {
|
|
618
|
+
title: "Pra instalar, abra fora do Snapchat",
|
|
619
|
+
step1: "Mantenha pressionado o link",
|
|
620
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
621
|
+
},
|
|
622
|
+
pinterest: {
|
|
623
|
+
title: "Pra instalar, abra fora do Pinterest",
|
|
624
|
+
step1: "Toque em \u22EF",
|
|
625
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
626
|
+
},
|
|
627
|
+
wechat: {
|
|
628
|
+
title: "Pra instalar, abra fora do WeChat",
|
|
629
|
+
step1: "Toque em \u22EF",
|
|
630
|
+
step2: 'Escolha "Abrir no navegador"'
|
|
631
|
+
},
|
|
632
|
+
other: {
|
|
633
|
+
title: "Abra no navegador do celular",
|
|
634
|
+
step1: "Toque no menu do app atual",
|
|
635
|
+
step2: 'Escolha "Abrir no Chrome" ou "Abrir no Safari"'
|
|
636
|
+
},
|
|
637
|
+
copy: "Copiar link",
|
|
638
|
+
copiedToast: "Link copiado. Cole no Chrome/Safari.",
|
|
639
|
+
skip: "Continuar aqui mesmo",
|
|
640
|
+
skipPermanent: "N\xE3o me pergunte mais"
|
|
641
|
+
},
|
|
642
|
+
desktop: {
|
|
643
|
+
title: "Instale no computador",
|
|
644
|
+
subtitle: "Acesso r\xE1pido",
|
|
645
|
+
cta: "Baixar",
|
|
646
|
+
close: "Fechar"
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
// src/components/InstallGate/InstallSplash.tsx
|
|
215
651
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
216
|
-
|
|
652
|
+
function InstallSplash({ children, title, subtitle }) {
|
|
653
|
+
const { name, theme } = useTemplateConfig();
|
|
654
|
+
const iconUrl = theme.icon_url || theme.logo_url || null;
|
|
655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
656
|
+
"div",
|
|
657
|
+
{
|
|
658
|
+
role: "dialog",
|
|
659
|
+
"aria-modal": "true",
|
|
660
|
+
"aria-labelledby": "install-splash-title",
|
|
661
|
+
"aria-describedby": subtitle ? "install-splash-subtitle" : void 0,
|
|
662
|
+
style: overlayStyle,
|
|
663
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: cardStyle, children: [
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", justifyContent: "center", marginBottom: 16 }, children: iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
665
|
+
"img",
|
|
666
|
+
{
|
|
667
|
+
src: iconUrl,
|
|
668
|
+
alt: `\xCDcone de ${name}`,
|
|
669
|
+
style: { width: 80, height: 80, borderRadius: 20, objectFit: "cover" }
|
|
670
|
+
}
|
|
671
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
672
|
+
"div",
|
|
673
|
+
{
|
|
674
|
+
style: {
|
|
675
|
+
width: 80,
|
|
676
|
+
height: 80,
|
|
677
|
+
borderRadius: 20,
|
|
678
|
+
background: "var(--hook-color-primary)",
|
|
679
|
+
color: "#fff",
|
|
680
|
+
display: "flex",
|
|
681
|
+
alignItems: "center",
|
|
682
|
+
justifyContent: "center",
|
|
683
|
+
fontSize: 36,
|
|
684
|
+
fontWeight: 700
|
|
685
|
+
},
|
|
686
|
+
children: name.charAt(0).toUpperCase()
|
|
687
|
+
}
|
|
688
|
+
) }),
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { id: "install-splash-title", style: titleStyle, children: title }),
|
|
690
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { id: "install-splash-subtitle", style: subtitleStyle, children: subtitle }),
|
|
691
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 24 }, children }),
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: footerStyle, children: "por Hook" })
|
|
693
|
+
] })
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
var primaryButtonStyle = {
|
|
698
|
+
width: "100%",
|
|
699
|
+
padding: "14px 20px",
|
|
700
|
+
background: "var(--hook-color-primary)",
|
|
701
|
+
color: "#fff",
|
|
702
|
+
border: "none",
|
|
703
|
+
borderRadius: 999,
|
|
704
|
+
fontSize: 17,
|
|
705
|
+
fontWeight: 600,
|
|
706
|
+
cursor: "pointer",
|
|
707
|
+
marginBottom: 12
|
|
708
|
+
};
|
|
709
|
+
var secondaryButtonStyle = {
|
|
710
|
+
width: "100%",
|
|
711
|
+
padding: "12px 20px",
|
|
712
|
+
background: "transparent",
|
|
713
|
+
color: "var(--hook-color-primary)",
|
|
714
|
+
border: "1px solid var(--hook-color-primary)",
|
|
715
|
+
borderRadius: 999,
|
|
716
|
+
fontSize: 15,
|
|
717
|
+
fontWeight: 500,
|
|
718
|
+
cursor: "pointer",
|
|
719
|
+
marginBottom: 12
|
|
720
|
+
};
|
|
721
|
+
var skipLinkStyle = {
|
|
722
|
+
display: "block",
|
|
723
|
+
width: "100%",
|
|
724
|
+
padding: "10px",
|
|
725
|
+
marginTop: 8,
|
|
726
|
+
background: "transparent",
|
|
727
|
+
color: "#555",
|
|
728
|
+
border: "none",
|
|
729
|
+
fontSize: 14,
|
|
730
|
+
textDecoration: "underline",
|
|
731
|
+
cursor: "pointer",
|
|
732
|
+
textAlign: "center"
|
|
733
|
+
};
|
|
734
|
+
var skipPermanentLinkStyle = {
|
|
735
|
+
...skipLinkStyle,
|
|
736
|
+
color: "#999",
|
|
737
|
+
fontSize: 13,
|
|
738
|
+
marginTop: 4
|
|
739
|
+
};
|
|
740
|
+
var overlayStyle = {
|
|
741
|
+
position: "fixed",
|
|
742
|
+
inset: 0,
|
|
743
|
+
background: "var(--hook-color-background, #fafafa)",
|
|
744
|
+
zIndex: 1e4,
|
|
745
|
+
display: "flex",
|
|
746
|
+
alignItems: "center",
|
|
747
|
+
justifyContent: "center",
|
|
748
|
+
padding: 20,
|
|
749
|
+
overflow: "auto"
|
|
750
|
+
};
|
|
751
|
+
var cardStyle = {
|
|
752
|
+
width: "100%",
|
|
753
|
+
maxWidth: 420,
|
|
754
|
+
padding: 24,
|
|
755
|
+
textAlign: "center"
|
|
756
|
+
};
|
|
757
|
+
var titleStyle = {
|
|
758
|
+
fontSize: 24,
|
|
759
|
+
fontWeight: 700,
|
|
760
|
+
lineHeight: 1.2,
|
|
761
|
+
margin: "0 0 8px 0",
|
|
762
|
+
color: "#111"
|
|
763
|
+
};
|
|
764
|
+
var subtitleStyle = {
|
|
765
|
+
fontSize: 15,
|
|
766
|
+
lineHeight: 1.4,
|
|
767
|
+
color: "#555",
|
|
768
|
+
margin: 0
|
|
769
|
+
};
|
|
770
|
+
var footerStyle = {
|
|
771
|
+
fontSize: 11,
|
|
772
|
+
color: "#aaa",
|
|
773
|
+
marginTop: 32,
|
|
774
|
+
letterSpacing: 0.5
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// src/components/InstallGate/icons.tsx
|
|
778
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
779
|
+
var defaultSvgProps = (size) => ({
|
|
780
|
+
width: size,
|
|
781
|
+
height: size,
|
|
782
|
+
viewBox: "0 0 24 24",
|
|
783
|
+
fill: "none",
|
|
784
|
+
stroke: "currentColor",
|
|
785
|
+
strokeWidth: 2,
|
|
786
|
+
strokeLinecap: "round",
|
|
787
|
+
strokeLinejoin: "round"
|
|
788
|
+
});
|
|
789
|
+
function ShareIconIOS({ size = 24, style, className }) {
|
|
790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 2L12 15" }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 6L12 2L16 6" }),
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 11v9a2 2 0 002 2h12a2 2 0 002-2v-9" })
|
|
794
|
+
] });
|
|
795
|
+
}
|
|
796
|
+
function MenuDotsVerticalIcon({ size = 24, style, className }) {
|
|
797
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "5", r: "1.5" }),
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "19", r: "1.5" })
|
|
801
|
+
] });
|
|
802
|
+
}
|
|
803
|
+
function MenuDotsHorizontalIcon({ size = 24, style, className }) {
|
|
804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "5", cy: "12", r: "1.5" }),
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "19", cy: "12", r: "1.5" })
|
|
808
|
+
] });
|
|
809
|
+
}
|
|
810
|
+
function SquarePlusIcon({ size = 24, style, className }) {
|
|
811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 8v8" }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 12h8" })
|
|
815
|
+
] });
|
|
816
|
+
}
|
|
817
|
+
function DownloadIcon({ size = 24, style, className }) {
|
|
818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "7 10 12 15 17 10" }),
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
822
|
+
] });
|
|
823
|
+
}
|
|
824
|
+
function ExternalLinkIcon({ size = 24, style, className }) {
|
|
825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
829
|
+
] });
|
|
830
|
+
}
|
|
831
|
+
function XIcon({ size = 20, style, className }) {
|
|
832
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { ...defaultSvgProps(size), style, className, "aria-hidden": "true", children: [
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
835
|
+
] });
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/components/InstallGate/variants/AndroidNativeVariant.tsx
|
|
839
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
840
|
+
function AndroidNativeVariant({
|
|
841
|
+
state,
|
|
842
|
+
actions
|
|
843
|
+
}) {
|
|
844
|
+
const copy = INSTALL_COPY.android.native;
|
|
845
|
+
const showPermanent = shouldShowPermanentOption(state);
|
|
846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
848
|
+
"button",
|
|
849
|
+
{
|
|
850
|
+
"data-testid": "install-prompt-cta-android-native",
|
|
851
|
+
type: "button",
|
|
852
|
+
onClick: () => void actions.promptInstall(),
|
|
853
|
+
style: { ...primaryButtonStyle, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8 },
|
|
854
|
+
children: [
|
|
855
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DownloadIcon, { size: 18 }),
|
|
856
|
+
copy.cta
|
|
857
|
+
]
|
|
858
|
+
}
|
|
859
|
+
),
|
|
860
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
861
|
+
"button",
|
|
862
|
+
{
|
|
863
|
+
"data-testid": "install-prompt-skip-session",
|
|
864
|
+
type: "button",
|
|
865
|
+
onClick: actions.dismissSession,
|
|
866
|
+
style: skipLinkStyle,
|
|
867
|
+
children: copy.skip
|
|
868
|
+
}
|
|
869
|
+
),
|
|
870
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
871
|
+
"button",
|
|
872
|
+
{
|
|
873
|
+
"data-testid": "install-prompt-skip-permanent",
|
|
874
|
+
type: "button",
|
|
875
|
+
onClick: actions.dismissPermanent,
|
|
876
|
+
style: skipPermanentLinkStyle,
|
|
877
|
+
children: copy.skipPermanent
|
|
878
|
+
}
|
|
879
|
+
)
|
|
880
|
+
] });
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// src/components/InstallGate/variants/AndroidManualVariant.tsx
|
|
884
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
885
|
+
function AndroidManualVariant({
|
|
886
|
+
state,
|
|
887
|
+
actions
|
|
888
|
+
}) {
|
|
889
|
+
const copy = INSTALL_COPY.android.manual;
|
|
890
|
+
const showPermanent = shouldShowPermanentOption(state);
|
|
891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(InstallSplash, { title: copy.title, children: [
|
|
892
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuDotsVerticalIcon, { size: 20 }), children: copy.step1 }),
|
|
893
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Step, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DownloadIcon, { size: 18 }), children: copy.step2 }),
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
895
|
+
"button",
|
|
896
|
+
{
|
|
897
|
+
"data-testid": "install-prompt-cta-android-manual",
|
|
898
|
+
type: "button",
|
|
899
|
+
onClick: actions.dismissSession,
|
|
900
|
+
style: primaryButtonStyle,
|
|
901
|
+
children: copy.cta
|
|
902
|
+
}
|
|
903
|
+
),
|
|
904
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
905
|
+
"button",
|
|
906
|
+
{
|
|
907
|
+
"data-testid": "install-prompt-skip-session",
|
|
908
|
+
type: "button",
|
|
909
|
+
onClick: actions.dismissSession,
|
|
910
|
+
style: skipLinkStyle,
|
|
911
|
+
children: copy.skip
|
|
912
|
+
}
|
|
913
|
+
),
|
|
914
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
915
|
+
"button",
|
|
916
|
+
{
|
|
917
|
+
"data-testid": "install-prompt-skip-permanent",
|
|
918
|
+
type: "button",
|
|
919
|
+
onClick: actions.dismissPermanent,
|
|
920
|
+
style: skipPermanentLinkStyle,
|
|
921
|
+
children: copy.skipPermanent
|
|
922
|
+
}
|
|
923
|
+
)
|
|
924
|
+
] });
|
|
925
|
+
}
|
|
926
|
+
function Step({ n, icon, children }) {
|
|
927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
928
|
+
"div",
|
|
929
|
+
{
|
|
930
|
+
style: {
|
|
931
|
+
display: "flex",
|
|
932
|
+
alignItems: "center",
|
|
933
|
+
gap: 12,
|
|
934
|
+
padding: "12px 14px",
|
|
935
|
+
background: "#f5f5f7",
|
|
936
|
+
borderRadius: 12,
|
|
937
|
+
marginBottom: 10,
|
|
938
|
+
textAlign: "left"
|
|
939
|
+
},
|
|
940
|
+
children: [
|
|
941
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
942
|
+
"div",
|
|
943
|
+
{
|
|
944
|
+
style: {
|
|
945
|
+
width: 28,
|
|
946
|
+
height: 28,
|
|
947
|
+
borderRadius: "50%",
|
|
948
|
+
background: "var(--hook-color-primary)",
|
|
949
|
+
color: "#fff",
|
|
950
|
+
display: "flex",
|
|
951
|
+
alignItems: "center",
|
|
952
|
+
justifyContent: "center",
|
|
953
|
+
fontSize: 14,
|
|
954
|
+
fontWeight: 700,
|
|
955
|
+
flexShrink: 0
|
|
956
|
+
},
|
|
957
|
+
children: n
|
|
958
|
+
}
|
|
959
|
+
),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, fontSize: 15, color: "#333" }, children }),
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
|
|
962
|
+
]
|
|
963
|
+
}
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// src/components/InstallGate/variants/IOSafariVariant.tsx
|
|
968
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
969
|
+
function IOSafariVariant({
|
|
970
|
+
state,
|
|
971
|
+
actions
|
|
972
|
+
}) {
|
|
973
|
+
const copy = INSTALL_COPY.iosSafari;
|
|
974
|
+
const showPermanent = shouldShowPermanentOption(state);
|
|
975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
976
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
977
|
+
Step2,
|
|
978
|
+
{
|
|
979
|
+
n: 1,
|
|
980
|
+
title: copy.step1.title,
|
|
981
|
+
subtitle: copy.step1.subtitle,
|
|
982
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
983
|
+
"div",
|
|
984
|
+
{
|
|
985
|
+
style: {
|
|
986
|
+
display: "flex",
|
|
987
|
+
justifyContent: "center",
|
|
988
|
+
alignItems: "center",
|
|
989
|
+
background: "#f5f5f7",
|
|
990
|
+
borderRadius: 12,
|
|
991
|
+
padding: "12px 0",
|
|
992
|
+
marginTop: 8
|
|
993
|
+
},
|
|
994
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
|
|
995
|
+
}
|
|
996
|
+
)
|
|
997
|
+
}
|
|
998
|
+
),
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1000
|
+
Step2,
|
|
1001
|
+
{
|
|
1002
|
+
n: 2,
|
|
1003
|
+
title: copy.step2.title,
|
|
1004
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1005
|
+
"div",
|
|
1006
|
+
{
|
|
1007
|
+
style: {
|
|
1008
|
+
display: "flex",
|
|
1009
|
+
alignItems: "center",
|
|
1010
|
+
gap: 10,
|
|
1011
|
+
background: "#f5f5f7",
|
|
1012
|
+
borderRadius: 12,
|
|
1013
|
+
padding: "12px 14px",
|
|
1014
|
+
marginTop: 8
|
|
1015
|
+
},
|
|
1016
|
+
children: [
|
|
1017
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
)
|
|
1022
|
+
}
|
|
1023
|
+
),
|
|
1024
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1025
|
+
Step2,
|
|
1026
|
+
{
|
|
1027
|
+
n: 3,
|
|
1028
|
+
title: copy.step3.title,
|
|
1029
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1030
|
+
"div",
|
|
1031
|
+
{
|
|
1032
|
+
style: {
|
|
1033
|
+
display: "flex",
|
|
1034
|
+
justifyContent: "flex-end",
|
|
1035
|
+
background: "#f5f5f7",
|
|
1036
|
+
borderRadius: 12,
|
|
1037
|
+
padding: "10px 14px",
|
|
1038
|
+
marginTop: 8
|
|
1039
|
+
},
|
|
1040
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1041
|
+
"span",
|
|
1042
|
+
{
|
|
1043
|
+
style: {
|
|
1044
|
+
color: "var(--hook-color-primary)",
|
|
1045
|
+
fontSize: 15,
|
|
1046
|
+
fontWeight: 600
|
|
1047
|
+
},
|
|
1048
|
+
children: copy.step3.buttonLabel
|
|
1049
|
+
}
|
|
1050
|
+
)
|
|
1051
|
+
}
|
|
1052
|
+
)
|
|
1053
|
+
}
|
|
1054
|
+
),
|
|
1055
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1056
|
+
"button",
|
|
1057
|
+
{
|
|
1058
|
+
"data-testid": "install-prompt-skip-session",
|
|
1059
|
+
type: "button",
|
|
1060
|
+
onClick: actions.dismissSession,
|
|
1061
|
+
style: { ...skipLinkStyle, marginTop: 16 },
|
|
1062
|
+
children: copy.skip
|
|
1063
|
+
}
|
|
1064
|
+
),
|
|
1065
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1066
|
+
"button",
|
|
1067
|
+
{
|
|
1068
|
+
"data-testid": "install-prompt-skip-permanent",
|
|
1069
|
+
type: "button",
|
|
1070
|
+
onClick: actions.dismissPermanent,
|
|
1071
|
+
style: skipPermanentLinkStyle,
|
|
1072
|
+
children: copy.skipPermanent
|
|
1073
|
+
}
|
|
1074
|
+
)
|
|
1075
|
+
] });
|
|
1076
|
+
}
|
|
1077
|
+
function Step2({
|
|
1078
|
+
n,
|
|
1079
|
+
title,
|
|
1080
|
+
subtitle,
|
|
1081
|
+
visual
|
|
1082
|
+
}) {
|
|
1083
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1084
|
+
"div",
|
|
1085
|
+
{
|
|
1086
|
+
style: {
|
|
1087
|
+
display: "flex",
|
|
1088
|
+
alignItems: "flex-start",
|
|
1089
|
+
gap: 12,
|
|
1090
|
+
marginBottom: 16,
|
|
1091
|
+
textAlign: "left"
|
|
1092
|
+
},
|
|
1093
|
+
children: [
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1095
|
+
"div",
|
|
1096
|
+
{
|
|
1097
|
+
style: {
|
|
1098
|
+
width: 32,
|
|
1099
|
+
height: 32,
|
|
1100
|
+
borderRadius: 10,
|
|
1101
|
+
background: "var(--hook-color-primary)",
|
|
1102
|
+
color: "#fff",
|
|
1103
|
+
display: "flex",
|
|
1104
|
+
alignItems: "center",
|
|
1105
|
+
justifyContent: "center",
|
|
1106
|
+
fontSize: 15,
|
|
1107
|
+
fontWeight: 700,
|
|
1108
|
+
flexShrink: 0
|
|
1109
|
+
},
|
|
1110
|
+
children: n
|
|
1111
|
+
}
|
|
1112
|
+
),
|
|
1113
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1 }, children: [
|
|
1114
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
|
|
1115
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
|
|
1116
|
+
visual
|
|
1117
|
+
] })
|
|
1118
|
+
]
|
|
1119
|
+
}
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// src/components/InstallGate/variants/IOSOtherVariant.tsx
|
|
1124
|
+
var import_react6 = require("react");
|
|
1125
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1126
|
+
function IOSOtherVariant({
|
|
1127
|
+
state,
|
|
1128
|
+
actions
|
|
1129
|
+
}) {
|
|
1130
|
+
const copy = INSTALL_COPY.iosOther;
|
|
1131
|
+
const showPermanent = shouldShowPermanentOption(state);
|
|
1132
|
+
const [copied, setCopied] = (0, import_react6.useState)(false);
|
|
1133
|
+
const handleCopy = async () => {
|
|
1134
|
+
await actions.copyLink();
|
|
1135
|
+
setCopied(true);
|
|
1136
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1137
|
+
};
|
|
1138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
"data-testid": "install-prompt-cta-ios-other-primary",
|
|
1143
|
+
type: "button",
|
|
1144
|
+
onClick: actions.redirectToSafari,
|
|
1145
|
+
style: primaryButtonStyle,
|
|
1146
|
+
children: copy.ctaPrimary
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1150
|
+
"button",
|
|
1151
|
+
{
|
|
1152
|
+
"data-testid": "install-prompt-cta-ios-other-secondary",
|
|
1153
|
+
type: "button",
|
|
1154
|
+
onClick: () => void handleCopy(),
|
|
1155
|
+
style: secondaryButtonStyle,
|
|
1156
|
+
children: copied ? copy.copiedToast : copy.ctaSecondary
|
|
1157
|
+
}
|
|
1158
|
+
),
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1160
|
+
"button",
|
|
1161
|
+
{
|
|
1162
|
+
"data-testid": "install-prompt-skip-session",
|
|
1163
|
+
type: "button",
|
|
1164
|
+
onClick: actions.dismissSession,
|
|
1165
|
+
style: skipLinkStyle,
|
|
1166
|
+
children: copy.skip
|
|
1167
|
+
}
|
|
1168
|
+
),
|
|
1169
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1170
|
+
"button",
|
|
1171
|
+
{
|
|
1172
|
+
"data-testid": "install-prompt-skip-permanent",
|
|
1173
|
+
type: "button",
|
|
1174
|
+
onClick: actions.dismissPermanent,
|
|
1175
|
+
style: skipPermanentLinkStyle,
|
|
1176
|
+
children: copy.skipPermanent
|
|
1177
|
+
}
|
|
1178
|
+
)
|
|
1179
|
+
] });
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/components/InstallGate/variants/InAppBrowserVariant.tsx
|
|
1183
|
+
var import_react7 = require("react");
|
|
1184
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1185
|
+
function InAppBrowserVariant({
|
|
1186
|
+
state,
|
|
1187
|
+
actions
|
|
1188
|
+
}) {
|
|
1189
|
+
const app = state.inAppApp ?? "other";
|
|
1190
|
+
const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
|
|
1191
|
+
const copy = INSTALL_COPY.inApp;
|
|
1192
|
+
const showPermanent = shouldShowPermanentOption(state);
|
|
1193
|
+
const [copied, setCopied] = (0, import_react7.useState)(false);
|
|
1194
|
+
const handleCopy = async () => {
|
|
1195
|
+
await actions.copyLink();
|
|
1196
|
+
setCopied(true);
|
|
1197
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1198
|
+
};
|
|
1199
|
+
const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
|
|
1200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: appCopy.title, children: [
|
|
1201
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1204
|
+
"button",
|
|
1205
|
+
{
|
|
1206
|
+
"data-testid": "install-prompt-cta-inapp-copy",
|
|
1207
|
+
type: "button",
|
|
1208
|
+
onClick: () => void handleCopy(),
|
|
1209
|
+
style: { ...primaryButtonStyle, marginTop: 8 },
|
|
1210
|
+
children: copied ? copy.copiedToast : copy.copy
|
|
1211
|
+
}
|
|
1212
|
+
),
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1214
|
+
"button",
|
|
1215
|
+
{
|
|
1216
|
+
"data-testid": "install-prompt-skip-session",
|
|
1217
|
+
type: "button",
|
|
1218
|
+
onClick: actions.dismissSession,
|
|
1219
|
+
style: skipLinkStyle,
|
|
1220
|
+
children: copy.skip
|
|
1221
|
+
}
|
|
1222
|
+
),
|
|
1223
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1224
|
+
"button",
|
|
1225
|
+
{
|
|
1226
|
+
"data-testid": "install-prompt-skip-permanent",
|
|
1227
|
+
type: "button",
|
|
1228
|
+
onClick: actions.dismissPermanent,
|
|
1229
|
+
style: skipPermanentLinkStyle,
|
|
1230
|
+
children: copy.skipPermanent
|
|
1231
|
+
}
|
|
1232
|
+
)
|
|
1233
|
+
] });
|
|
1234
|
+
}
|
|
1235
|
+
function Step3({
|
|
1236
|
+
n,
|
|
1237
|
+
icon,
|
|
1238
|
+
children
|
|
1239
|
+
}) {
|
|
1240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1241
|
+
"div",
|
|
1242
|
+
{
|
|
1243
|
+
style: {
|
|
1244
|
+
display: "flex",
|
|
1245
|
+
alignItems: "center",
|
|
1246
|
+
gap: 12,
|
|
1247
|
+
padding: "12px 14px",
|
|
1248
|
+
background: "#f5f5f7",
|
|
1249
|
+
borderRadius: 12,
|
|
1250
|
+
marginBottom: 10,
|
|
1251
|
+
textAlign: "left"
|
|
1252
|
+
},
|
|
1253
|
+
children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1255
|
+
"div",
|
|
1256
|
+
{
|
|
1257
|
+
style: {
|
|
1258
|
+
width: 28,
|
|
1259
|
+
height: 28,
|
|
1260
|
+
borderRadius: "50%",
|
|
1261
|
+
background: "var(--hook-color-primary)",
|
|
1262
|
+
color: "#fff",
|
|
1263
|
+
display: "flex",
|
|
1264
|
+
alignItems: "center",
|
|
1265
|
+
justifyContent: "center",
|
|
1266
|
+
fontSize: 14,
|
|
1267
|
+
fontWeight: 700,
|
|
1268
|
+
flexShrink: 0
|
|
1269
|
+
},
|
|
1270
|
+
children: n
|
|
1271
|
+
}
|
|
1272
|
+
),
|
|
1273
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
|
|
1274
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
|
|
1275
|
+
]
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/components/InstallGate/variants/DesktopVariant.tsx
|
|
1281
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1282
|
+
function DesktopVariant({
|
|
1283
|
+
state,
|
|
1284
|
+
actions
|
|
1285
|
+
}) {
|
|
1286
|
+
const { name, theme } = useTemplateConfig();
|
|
1287
|
+
const copy = INSTALL_COPY.desktop;
|
|
1288
|
+
const iconUrl = theme.icon_url || theme.logo_url || null;
|
|
1289
|
+
if (!state.isInstallable) return null;
|
|
1290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1291
|
+
"div",
|
|
1292
|
+
{
|
|
1293
|
+
role: "complementary",
|
|
1294
|
+
"aria-label": copy.title,
|
|
1295
|
+
style: bannerStyle,
|
|
1296
|
+
children: [
|
|
1297
|
+
iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1298
|
+
"img",
|
|
1299
|
+
{
|
|
1300
|
+
src: iconUrl,
|
|
1301
|
+
alt: "",
|
|
1302
|
+
style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
|
|
1303
|
+
}
|
|
1304
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1305
|
+
"div",
|
|
1306
|
+
{
|
|
1307
|
+
style: {
|
|
1308
|
+
width: 40,
|
|
1309
|
+
height: 40,
|
|
1310
|
+
borderRadius: 10,
|
|
1311
|
+
background: "var(--hook-color-primary)",
|
|
1312
|
+
color: "#fff",
|
|
1313
|
+
display: "flex",
|
|
1314
|
+
alignItems: "center",
|
|
1315
|
+
justifyContent: "center",
|
|
1316
|
+
fontSize: 18,
|
|
1317
|
+
fontWeight: 700,
|
|
1318
|
+
flexShrink: 0
|
|
1319
|
+
},
|
|
1320
|
+
children: name.charAt(0).toUpperCase()
|
|
1321
|
+
}
|
|
1322
|
+
),
|
|
1323
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
|
|
1326
|
+
] }),
|
|
1327
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1328
|
+
"button",
|
|
1329
|
+
{
|
|
1330
|
+
"data-testid": "install-prompt-cta-desktop",
|
|
1331
|
+
type: "button",
|
|
1332
|
+
onClick: () => void actions.promptInstall(),
|
|
1333
|
+
style: {
|
|
1334
|
+
padding: "8px 14px",
|
|
1335
|
+
background: "var(--hook-color-primary)",
|
|
1336
|
+
color: "#fff",
|
|
1337
|
+
border: "none",
|
|
1338
|
+
borderRadius: 999,
|
|
1339
|
+
fontSize: 13,
|
|
1340
|
+
fontWeight: 600,
|
|
1341
|
+
cursor: "pointer",
|
|
1342
|
+
display: "inline-flex",
|
|
1343
|
+
alignItems: "center",
|
|
1344
|
+
gap: 6,
|
|
1345
|
+
flexShrink: 0
|
|
1346
|
+
},
|
|
1347
|
+
children: [
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DownloadIcon, { size: 14 }),
|
|
1349
|
+
copy.cta
|
|
1350
|
+
]
|
|
1351
|
+
}
|
|
1352
|
+
),
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1354
|
+
"button",
|
|
1355
|
+
{
|
|
1356
|
+
"data-testid": "install-prompt-desktop-close",
|
|
1357
|
+
type: "button",
|
|
1358
|
+
onClick: actions.dismissPermanent,
|
|
1359
|
+
"aria-label": copy.close,
|
|
1360
|
+
style: {
|
|
1361
|
+
background: "transparent",
|
|
1362
|
+
border: "none",
|
|
1363
|
+
cursor: "pointer",
|
|
1364
|
+
color: "#888",
|
|
1365
|
+
padding: 4,
|
|
1366
|
+
flexShrink: 0
|
|
1367
|
+
},
|
|
1368
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(XIcon, { size: 16 })
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
]
|
|
1372
|
+
}
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
var bannerStyle = {
|
|
1376
|
+
position: "fixed",
|
|
1377
|
+
bottom: 24,
|
|
1378
|
+
right: 24,
|
|
1379
|
+
zIndex: 1e4,
|
|
1380
|
+
display: "flex",
|
|
1381
|
+
alignItems: "center",
|
|
1382
|
+
gap: 12,
|
|
1383
|
+
padding: "12px 16px",
|
|
1384
|
+
background: "#fff",
|
|
1385
|
+
border: "1px solid rgba(0,0,0,0.08)",
|
|
1386
|
+
borderRadius: 16,
|
|
1387
|
+
boxShadow: "0 10px 30px rgba(0,0,0,0.12)",
|
|
1388
|
+
maxWidth: 400
|
|
1389
|
+
};
|
|
1390
|
+
|
|
1391
|
+
// src/components/InstallGate/InstallGate.tsx
|
|
1392
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1393
|
+
function InstallGate({ children }) {
|
|
1394
|
+
const { slug, features_enabled } = useTemplateConfig();
|
|
1395
|
+
const enabled = features_enabled.includes("install_prompt");
|
|
1396
|
+
const installState = useInstallPrompt(slug);
|
|
1397
|
+
const shouldBlock = enabled && shouldBlockInstall(installState);
|
|
1398
|
+
const trackedRef = (0, import_react8.useRef)(null);
|
|
1399
|
+
(0, import_react8.useEffect)(() => {
|
|
1400
|
+
if (!shouldBlock) return;
|
|
1401
|
+
if (typeof window === "undefined") return;
|
|
1402
|
+
const variantKey = `${slug}:${installState.variant}`;
|
|
1403
|
+
if (trackedRef.current === variantKey) return;
|
|
1404
|
+
trackedRef.current = variantKey;
|
|
1405
|
+
window.posthog?.capture?.("pwa_install_splash_shown", {
|
|
1406
|
+
slug,
|
|
1407
|
+
platform: installState.platform,
|
|
1408
|
+
browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
|
|
1409
|
+
in_app_app: installState.inAppApp,
|
|
1410
|
+
variant: installState.variant
|
|
1411
|
+
});
|
|
1412
|
+
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
|
|
1413
|
+
if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1414
|
+
if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1415
|
+
if (installState.variant === "desktop") {
|
|
1416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
1417
|
+
children,
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DesktopVariant, { state: installState, actions: installState })
|
|
1419
|
+
] });
|
|
1420
|
+
}
|
|
1421
|
+
if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1422
|
+
switch (installState.variant) {
|
|
1423
|
+
case "android-native":
|
|
1424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
|
|
1425
|
+
case "android-manual":
|
|
1426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidManualVariant, { state: installState, actions: installState });
|
|
1427
|
+
case "ios-safari":
|
|
1428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSafariVariant, { state: installState, actions: installState });
|
|
1429
|
+
case "ios-other":
|
|
1430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSOtherVariant, { state: installState, actions: installState });
|
|
1431
|
+
case "in-app":
|
|
1432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
|
|
1433
|
+
case "none":
|
|
1434
|
+
default:
|
|
1435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// src/defaults/ErrorBoundary.tsx
|
|
1440
|
+
var import_react9 = require("react");
|
|
1441
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1442
|
+
var ErrorBoundary = class extends import_react9.Component {
|
|
217
1443
|
state = { error: null };
|
|
218
1444
|
static getDerivedStateFromError(error) {
|
|
219
1445
|
return { error };
|
|
@@ -223,17 +1449,17 @@ var ErrorBoundary = class extends import_react5.Component {
|
|
|
223
1449
|
}
|
|
224
1450
|
render() {
|
|
225
1451
|
if (this.state.error) {
|
|
226
|
-
return this.props.fallback ?? /* @__PURE__ */ (0,
|
|
227
|
-
/* @__PURE__ */ (0,
|
|
228
|
-
/* @__PURE__ */ (0,
|
|
1452
|
+
return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
|
|
1453
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { children: "Algo deu errado" }),
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
|
|
229
1455
|
] });
|
|
230
1456
|
}
|
|
231
|
-
return /* @__PURE__ */ (0,
|
|
1457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: this.props.children });
|
|
232
1458
|
}
|
|
233
1459
|
};
|
|
234
1460
|
|
|
235
1461
|
// src/hooks/useLoginForm.ts
|
|
236
|
-
var
|
|
1462
|
+
var import_react10 = require("react");
|
|
237
1463
|
var import_sdk5 = require("@hook-sdk/sdk");
|
|
238
1464
|
|
|
239
1465
|
// src/errors.ts
|
|
@@ -270,22 +1496,22 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
270
1496
|
var MIN_PASSWORD = 8;
|
|
271
1497
|
function useLoginForm() {
|
|
272
1498
|
const { auth } = (0, import_sdk5.useHook)();
|
|
273
|
-
const [email, setEmail] = (0,
|
|
274
|
-
const [password, setPassword] = (0,
|
|
275
|
-
const [submitting, setSubmitting] = (0,
|
|
276
|
-
const [error, setError] = (0,
|
|
277
|
-
const emailError = (0,
|
|
1499
|
+
const [email, setEmail] = (0, import_react10.useState)("");
|
|
1500
|
+
const [password, setPassword] = (0, import_react10.useState)("");
|
|
1501
|
+
const [submitting, setSubmitting] = (0, import_react10.useState)(false);
|
|
1502
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1503
|
+
const emailError = (0, import_react10.useMemo)(() => {
|
|
278
1504
|
if (email.length === 0) return null;
|
|
279
1505
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
280
1506
|
return null;
|
|
281
1507
|
}, [email]);
|
|
282
|
-
const passwordError = (0,
|
|
1508
|
+
const passwordError = (0, import_react10.useMemo)(() => {
|
|
283
1509
|
if (password.length === 0) return null;
|
|
284
1510
|
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
285
1511
|
return null;
|
|
286
1512
|
}, [password]);
|
|
287
1513
|
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && emailError === null && passwordError === null && !submitting;
|
|
288
|
-
const submit = (0,
|
|
1514
|
+
const submit = (0, import_react10.useCallback)(async () => {
|
|
289
1515
|
if (!canSubmit) return false;
|
|
290
1516
|
setSubmitting(true);
|
|
291
1517
|
setError(null);
|
|
@@ -309,25 +1535,183 @@ function useLoginForm() {
|
|
|
309
1535
|
submit,
|
|
310
1536
|
submitting,
|
|
311
1537
|
canSubmit,
|
|
312
|
-
error
|
|
1538
|
+
error,
|
|
1539
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
313
1540
|
};
|
|
314
1541
|
}
|
|
315
1542
|
|
|
1543
|
+
// src/internal/GoogleSignInButton.tsx
|
|
1544
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1545
|
+
function GoogleSignInButton({
|
|
1546
|
+
onClick,
|
|
1547
|
+
testId = "oauth-google",
|
|
1548
|
+
label = "Continuar com Google"
|
|
1549
|
+
}) {
|
|
1550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
1551
|
+
"button",
|
|
1552
|
+
{
|
|
1553
|
+
"data-testid": testId,
|
|
1554
|
+
type: "button",
|
|
1555
|
+
onClick,
|
|
1556
|
+
style: {
|
|
1557
|
+
width: "100%",
|
|
1558
|
+
padding: "10px 12px",
|
|
1559
|
+
display: "flex",
|
|
1560
|
+
alignItems: "center",
|
|
1561
|
+
justifyContent: "center",
|
|
1562
|
+
gap: 10,
|
|
1563
|
+
background: "#fff",
|
|
1564
|
+
color: "#1f1f1f",
|
|
1565
|
+
border: "1px solid #dadce0",
|
|
1566
|
+
borderRadius: 8,
|
|
1567
|
+
cursor: "pointer",
|
|
1568
|
+
fontSize: 14,
|
|
1569
|
+
fontWeight: 500,
|
|
1570
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
1571
|
+
},
|
|
1572
|
+
children: [
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GoogleGlyph, {}),
|
|
1574
|
+
label
|
|
1575
|
+
]
|
|
1576
|
+
}
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
function GoogleGlyph() {
|
|
1580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
1581
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1582
|
+
"path",
|
|
1583
|
+
{
|
|
1584
|
+
d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.874 2.684-6.615z",
|
|
1585
|
+
fill: "#4285F4"
|
|
1586
|
+
}
|
|
1587
|
+
),
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1589
|
+
"path",
|
|
1590
|
+
{
|
|
1591
|
+
d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z",
|
|
1592
|
+
fill: "#34A853"
|
|
1593
|
+
}
|
|
1594
|
+
),
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1596
|
+
"path",
|
|
1597
|
+
{
|
|
1598
|
+
d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z",
|
|
1599
|
+
fill: "#FBBC05"
|
|
1600
|
+
}
|
|
1601
|
+
),
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1603
|
+
"path",
|
|
1604
|
+
{
|
|
1605
|
+
d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z",
|
|
1606
|
+
fill: "#EA4335"
|
|
1607
|
+
}
|
|
1608
|
+
)
|
|
1609
|
+
] });
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// src/internal/OAuthErrorBanner.tsx
|
|
1613
|
+
var import_react11 = require("react");
|
|
1614
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1615
|
+
var ERROR_MESSAGES = {
|
|
1616
|
+
invalid_state: "Sess\xE3o expirou, tente de novo.",
|
|
1617
|
+
access_denied: "Voc\xEA cancelou o login com Google.",
|
|
1618
|
+
provider_error: "O Google recusou a autentica\xE7\xE3o. Tente de novo em alguns segundos.",
|
|
1619
|
+
invalid_return_to: "Link inv\xE1lido. Tente entrar novamente."
|
|
1620
|
+
};
|
|
1621
|
+
function readErrorCode() {
|
|
1622
|
+
if (typeof window === "undefined") return null;
|
|
1623
|
+
const code = new URLSearchParams(window.location.search).get("oauth_error");
|
|
1624
|
+
if (!code) return null;
|
|
1625
|
+
return code;
|
|
1626
|
+
}
|
|
1627
|
+
function stripErrorFromUrl() {
|
|
1628
|
+
if (typeof window === "undefined") return;
|
|
1629
|
+
const url = new URL(window.location.href);
|
|
1630
|
+
url.searchParams.delete("oauth_error");
|
|
1631
|
+
window.history.replaceState({}, "", url.toString());
|
|
1632
|
+
}
|
|
1633
|
+
function OAuthErrorBanner() {
|
|
1634
|
+
const [code, setCode] = (0, import_react11.useState)(() => readErrorCode());
|
|
1635
|
+
(0, import_react11.useEffect)(() => {
|
|
1636
|
+
if (code !== null) stripErrorFromUrl();
|
|
1637
|
+
}, [code]);
|
|
1638
|
+
if (!code) return null;
|
|
1639
|
+
const message = ERROR_MESSAGES[code] ?? "N\xE3o conseguimos conectar ao Google. Tente de novo.";
|
|
1640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1641
|
+
"div",
|
|
1642
|
+
{
|
|
1643
|
+
role: "alert",
|
|
1644
|
+
"data-testid": "oauth-error-banner",
|
|
1645
|
+
style: {
|
|
1646
|
+
padding: "10px 12px",
|
|
1647
|
+
marginBottom: 16,
|
|
1648
|
+
background: "#fce8e6",
|
|
1649
|
+
color: "#a50e0e",
|
|
1650
|
+
borderRadius: 8,
|
|
1651
|
+
fontSize: 14
|
|
1652
|
+
},
|
|
1653
|
+
children: [
|
|
1654
|
+
message,
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1656
|
+
"button",
|
|
1657
|
+
{
|
|
1658
|
+
type: "button",
|
|
1659
|
+
onClick: () => setCode(null),
|
|
1660
|
+
"aria-label": "Fechar",
|
|
1661
|
+
style: {
|
|
1662
|
+
float: "right",
|
|
1663
|
+
background: "none",
|
|
1664
|
+
border: "none",
|
|
1665
|
+
color: "#a50e0e",
|
|
1666
|
+
cursor: "pointer",
|
|
1667
|
+
fontSize: 16,
|
|
1668
|
+
lineHeight: 1,
|
|
1669
|
+
padding: 0
|
|
1670
|
+
},
|
|
1671
|
+
children: "\xD7"
|
|
1672
|
+
}
|
|
1673
|
+
)
|
|
1674
|
+
]
|
|
1675
|
+
}
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
316
1679
|
// src/defaults/DefaultLoginScreen.tsx
|
|
317
|
-
var
|
|
1680
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
318
1681
|
function DefaultLoginScreen({ onNavigate }) {
|
|
319
1682
|
const { name } = useTemplateConfig();
|
|
320
1683
|
const f = useLoginForm();
|
|
321
|
-
return /* @__PURE__ */ (0,
|
|
322
|
-
/* @__PURE__ */ (0,
|
|
323
|
-
/* @__PURE__ */ (0,
|
|
324
|
-
/* @__PURE__ */ (0,
|
|
1684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
1685
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
1686
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Entre na sua conta" }),
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(OAuthErrorBanner, {}),
|
|
1688
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "login-oauth-google" }),
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1690
|
+
"div",
|
|
1691
|
+
{
|
|
1692
|
+
"aria-hidden": "true",
|
|
1693
|
+
style: {
|
|
1694
|
+
display: "flex",
|
|
1695
|
+
alignItems: "center",
|
|
1696
|
+
gap: 8,
|
|
1697
|
+
margin: "16px 0",
|
|
1698
|
+
color: "rgba(0,0,0,0.45)",
|
|
1699
|
+
fontSize: 12
|
|
1700
|
+
},
|
|
1701
|
+
children: [
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
|
|
1703
|
+
"ou",
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
|
|
1705
|
+
]
|
|
1706
|
+
}
|
|
1707
|
+
),
|
|
1708
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("form", { onSubmit: (e) => {
|
|
325
1709
|
e.preventDefault();
|
|
326
1710
|
void f.submit();
|
|
327
1711
|
}, children: [
|
|
328
|
-
/* @__PURE__ */ (0,
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
329
1713
|
"E-mail",
|
|
330
|
-
/* @__PURE__ */ (0,
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
331
1715
|
"input",
|
|
332
1716
|
{
|
|
333
1717
|
"data-testid": "login-email",
|
|
@@ -337,11 +1721,11 @@ function DefaultLoginScreen({ onNavigate }) {
|
|
|
337
1721
|
style: { display: "block", width: "100%" }
|
|
338
1722
|
}
|
|
339
1723
|
),
|
|
340
|
-
f.emailError && /* @__PURE__ */ (0,
|
|
1724
|
+
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
341
1725
|
] }),
|
|
342
|
-
/* @__PURE__ */ (0,
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
343
1727
|
"Senha",
|
|
344
|
-
/* @__PURE__ */ (0,
|
|
1728
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
345
1729
|
"input",
|
|
346
1730
|
{
|
|
347
1731
|
"data-testid": "login-password",
|
|
@@ -351,10 +1735,10 @@ function DefaultLoginScreen({ onNavigate }) {
|
|
|
351
1735
|
style: { display: "block", width: "100%" }
|
|
352
1736
|
}
|
|
353
1737
|
),
|
|
354
|
-
f.passwordError && /* @__PURE__ */ (0,
|
|
1738
|
+
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
355
1739
|
] }),
|
|
356
|
-
f.error && /* @__PURE__ */ (0,
|
|
357
|
-
/* @__PURE__ */ (0,
|
|
1740
|
+
f.error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
1741
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
358
1742
|
"button",
|
|
359
1743
|
{
|
|
360
1744
|
"data-testid": "login-submit",
|
|
@@ -373,42 +1757,42 @@ function DefaultLoginScreen({ onNavigate }) {
|
|
|
373
1757
|
}
|
|
374
1758
|
)
|
|
375
1759
|
] }),
|
|
376
|
-
/* @__PURE__ */ (0,
|
|
377
|
-
/* @__PURE__ */ (0,
|
|
378
|
-
/* @__PURE__ */ (0,
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { marginTop: 16, display: "flex", justifyContent: "space-between" }, children: [
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { "data-testid": "login-goto-signup", type: "button", onClick: () => onNavigate("signup"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Criar conta" }),
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { "data-testid": "login-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Esqueci senha" })
|
|
379
1763
|
] })
|
|
380
1764
|
] });
|
|
381
1765
|
}
|
|
382
1766
|
|
|
383
1767
|
// src/hooks/useSignupForm.ts
|
|
384
|
-
var
|
|
1768
|
+
var import_react12 = require("react");
|
|
385
1769
|
var import_sdk6 = require("@hook-sdk/sdk");
|
|
386
1770
|
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
387
1771
|
var MIN_PASSWORD2 = 8;
|
|
388
1772
|
function useSignupForm() {
|
|
389
1773
|
const { auth } = (0, import_sdk6.useHook)();
|
|
390
|
-
const [name, setName] = (0,
|
|
391
|
-
const [email, setEmail] = (0,
|
|
392
|
-
const [password, setPassword] = (0,
|
|
393
|
-
const [submitting, setSubmitting] = (0,
|
|
394
|
-
const [error, setError] = (0,
|
|
395
|
-
const nameError = (0,
|
|
1774
|
+
const [name, setName] = (0, import_react12.useState)("");
|
|
1775
|
+
const [email, setEmail] = (0, import_react12.useState)("");
|
|
1776
|
+
const [password, setPassword] = (0, import_react12.useState)("");
|
|
1777
|
+
const [submitting, setSubmitting] = (0, import_react12.useState)(false);
|
|
1778
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1779
|
+
const nameError = (0, import_react12.useMemo)(() => {
|
|
396
1780
|
if (name.length === 0) return null;
|
|
397
1781
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
398
1782
|
return null;
|
|
399
1783
|
}, [name]);
|
|
400
|
-
const emailError = (0,
|
|
1784
|
+
const emailError = (0, import_react12.useMemo)(() => {
|
|
401
1785
|
if (email.length === 0) return null;
|
|
402
1786
|
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
403
1787
|
return null;
|
|
404
1788
|
}, [email]);
|
|
405
|
-
const passwordError = (0,
|
|
1789
|
+
const passwordError = (0, import_react12.useMemo)(() => {
|
|
406
1790
|
if (password.length === 0) return null;
|
|
407
1791
|
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
408
1792
|
return null;
|
|
409
1793
|
}, [password]);
|
|
410
1794
|
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && nameError === null && emailError === null && passwordError === null && !submitting;
|
|
411
|
-
const submit = (0,
|
|
1795
|
+
const submit = (0, import_react12.useCallback)(async () => {
|
|
412
1796
|
if (!canSubmit) return false;
|
|
413
1797
|
setSubmitting(true);
|
|
414
1798
|
setError(null);
|
|
@@ -435,61 +1819,83 @@ function useSignupForm() {
|
|
|
435
1819
|
submit,
|
|
436
1820
|
submitting,
|
|
437
1821
|
canSubmit,
|
|
438
|
-
error
|
|
1822
|
+
error,
|
|
1823
|
+
loginWithGoogle: () => auth.loginWithGoogle()
|
|
439
1824
|
};
|
|
440
1825
|
}
|
|
441
1826
|
|
|
442
1827
|
// src/defaults/DefaultSignupScreen.tsx
|
|
443
|
-
var
|
|
1828
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
444
1829
|
function DefaultSignupScreen({ onNavigate }) {
|
|
445
1830
|
const { name } = useTemplateConfig();
|
|
446
1831
|
const f = useSignupForm();
|
|
447
|
-
return /* @__PURE__ */ (0,
|
|
448
|
-
/* @__PURE__ */ (0,
|
|
449
|
-
/* @__PURE__ */ (0,
|
|
450
|
-
/* @__PURE__ */ (0,
|
|
1832
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
1833
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
1834
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Criar sua conta" }),
|
|
1835
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OAuthErrorBanner, {}),
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GoogleSignInButton, { onClick: f.loginWithGoogle, testId: "signup-oauth-google" }),
|
|
1837
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1838
|
+
"div",
|
|
1839
|
+
{
|
|
1840
|
+
"aria-hidden": "true",
|
|
1841
|
+
style: {
|
|
1842
|
+
display: "flex",
|
|
1843
|
+
alignItems: "center",
|
|
1844
|
+
gap: 8,
|
|
1845
|
+
margin: "16px 0",
|
|
1846
|
+
color: "rgba(0,0,0,0.45)",
|
|
1847
|
+
fontSize: 12
|
|
1848
|
+
},
|
|
1849
|
+
children: [
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } }),
|
|
1851
|
+
"ou",
|
|
1852
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(0,0,0,0.1)" } })
|
|
1853
|
+
]
|
|
1854
|
+
}
|
|
1855
|
+
),
|
|
1856
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("form", { onSubmit: (e) => {
|
|
451
1857
|
e.preventDefault();
|
|
452
1858
|
void f.submit();
|
|
453
1859
|
}, children: [
|
|
454
|
-
/* @__PURE__ */ (0,
|
|
1860
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
455
1861
|
"Nome",
|
|
456
|
-
/* @__PURE__ */ (0,
|
|
457
|
-
f.nameError && /* @__PURE__ */ (0,
|
|
1862
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-name", value: f.name, onChange: (e) => f.setName(e.target.value), style: { display: "block", width: "100%" } }),
|
|
1863
|
+
f.nameError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.nameError })
|
|
458
1864
|
] }),
|
|
459
|
-
/* @__PURE__ */ (0,
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
460
1866
|
"E-mail",
|
|
461
|
-
/* @__PURE__ */ (0,
|
|
462
|
-
f.emailError && /* @__PURE__ */ (0,
|
|
1867
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
|
|
1868
|
+
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
463
1869
|
] }),
|
|
464
|
-
/* @__PURE__ */ (0,
|
|
1870
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
465
1871
|
"Senha",
|
|
466
|
-
/* @__PURE__ */ (0,
|
|
467
|
-
f.passwordError && /* @__PURE__ */ (0,
|
|
1872
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { "data-testid": "signup-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" } }),
|
|
1873
|
+
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
468
1874
|
] }),
|
|
469
|
-
f.error && /* @__PURE__ */ (0,
|
|
470
|
-
/* @__PURE__ */ (0,
|
|
1875
|
+
f.error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
1876
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "signup-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Criando..." : "Criar conta" })
|
|
471
1877
|
] }),
|
|
472
|
-
/* @__PURE__ */ (0,
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { "data-testid": "signup-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "J\xE1 tem conta? Entre" }) })
|
|
473
1879
|
] });
|
|
474
1880
|
}
|
|
475
1881
|
|
|
476
1882
|
// src/hooks/useForgotForm.ts
|
|
477
|
-
var
|
|
1883
|
+
var import_react13 = require("react");
|
|
478
1884
|
var import_sdk7 = require("@hook-sdk/sdk");
|
|
479
1885
|
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
480
1886
|
function useForgotForm() {
|
|
481
1887
|
const { auth } = (0, import_sdk7.useHook)();
|
|
482
|
-
const [email, setEmail] = (0,
|
|
483
|
-
const [submitting, setSubmitting] = (0,
|
|
484
|
-
const [sent, setSent] = (0,
|
|
485
|
-
const [error, setError] = (0,
|
|
486
|
-
const emailError = (0,
|
|
1888
|
+
const [email, setEmail] = (0, import_react13.useState)("");
|
|
1889
|
+
const [submitting, setSubmitting] = (0, import_react13.useState)(false);
|
|
1890
|
+
const [sent, setSent] = (0, import_react13.useState)(false);
|
|
1891
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1892
|
+
const emailError = (0, import_react13.useMemo)(() => {
|
|
487
1893
|
if (email.length === 0) return null;
|
|
488
1894
|
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
489
1895
|
return null;
|
|
490
1896
|
}, [email]);
|
|
491
1897
|
const canSubmit = email.length > 0 && emailError === null && !submitting;
|
|
492
|
-
const submit = (0,
|
|
1898
|
+
const submit = (0, import_react13.useCallback)(async () => {
|
|
493
1899
|
if (!canSubmit) return false;
|
|
494
1900
|
setSubmitting(true);
|
|
495
1901
|
setError(null);
|
|
@@ -517,66 +1923,66 @@ function useForgotForm() {
|
|
|
517
1923
|
}
|
|
518
1924
|
|
|
519
1925
|
// src/defaults/DefaultForgotScreen.tsx
|
|
520
|
-
var
|
|
1926
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
521
1927
|
function DefaultForgotScreen({ onNavigate }) {
|
|
522
1928
|
const { name } = useTemplateConfig();
|
|
523
1929
|
const f = useForgotForm();
|
|
524
1930
|
if (f.sent) {
|
|
525
|
-
return /* @__PURE__ */ (0,
|
|
526
|
-
/* @__PURE__ */ (0,
|
|
527
|
-
/* @__PURE__ */ (0,
|
|
528
|
-
/* @__PURE__ */ (0,
|
|
1931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
1932
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { children: "Verifique seu e-mail" }),
|
|
1933
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7 }, children: "Enviamos um link pra redefinir sua senha." }),
|
|
1934
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-back-login", type: "button", onClick: () => onNavigate("login"), children: "Voltar pro login" })
|
|
529
1935
|
] });
|
|
530
1936
|
}
|
|
531
|
-
return /* @__PURE__ */ (0,
|
|
532
|
-
/* @__PURE__ */ (0,
|
|
533
|
-
/* @__PURE__ */ (0,
|
|
534
|
-
/* @__PURE__ */ (0,
|
|
1937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
1938
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
1939
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Redefinir senha" }),
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("form", { onSubmit: (e) => {
|
|
535
1941
|
e.preventDefault();
|
|
536
1942
|
void f.submit();
|
|
537
1943
|
}, children: [
|
|
538
|
-
/* @__PURE__ */ (0,
|
|
1944
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
539
1945
|
"E-mail",
|
|
540
|
-
/* @__PURE__ */ (0,
|
|
541
|
-
f.emailError && /* @__PURE__ */ (0,
|
|
1946
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "data-testid": "forgot-email", type: "email", value: f.email, onChange: (e) => f.setEmail(e.target.value), style: { display: "block", width: "100%" } }),
|
|
1947
|
+
f.emailError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { style: { color: "#c00" }, children: f.emailError })
|
|
542
1948
|
] }),
|
|
543
|
-
f.error && /* @__PURE__ */ (0,
|
|
544
|
-
/* @__PURE__ */ (0,
|
|
1949
|
+
f.error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Enviando..." : "Enviar link" })
|
|
545
1951
|
] }),
|
|
546
|
-
/* @__PURE__ */ (0,
|
|
1952
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginTop: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { "data-testid": "forgot-goto-login", type: "button", onClick: () => onNavigate("login"), style: { background: "none", border: "none", cursor: "pointer" }, children: "Voltar pro login" }) })
|
|
547
1953
|
] });
|
|
548
1954
|
}
|
|
549
1955
|
|
|
550
1956
|
// src/hooks/useResetForm.ts
|
|
551
|
-
var
|
|
1957
|
+
var import_react14 = require("react");
|
|
552
1958
|
var import_sdk8 = require("@hook-sdk/sdk");
|
|
553
1959
|
var MIN_PASSWORD3 = 12;
|
|
554
1960
|
function useResetForm() {
|
|
555
1961
|
const { auth } = (0, import_sdk8.useHook)();
|
|
556
|
-
const [token, setToken] = (0,
|
|
557
|
-
const [password, setPassword] = (0,
|
|
558
|
-
const [confirm, setConfirm] = (0,
|
|
559
|
-
const [submitting, setSubmitting] = (0,
|
|
560
|
-
const [done, setDone] = (0,
|
|
561
|
-
const [error, setError] = (0,
|
|
562
|
-
(0,
|
|
1962
|
+
const [token, setToken] = (0, import_react14.useState)(null);
|
|
1963
|
+
const [password, setPassword] = (0, import_react14.useState)("");
|
|
1964
|
+
const [confirm, setConfirm] = (0, import_react14.useState)("");
|
|
1965
|
+
const [submitting, setSubmitting] = (0, import_react14.useState)(false);
|
|
1966
|
+
const [done, setDone] = (0, import_react14.useState)(false);
|
|
1967
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1968
|
+
(0, import_react14.useEffect)(() => {
|
|
563
1969
|
if (typeof window === "undefined") return;
|
|
564
1970
|
const params = new URLSearchParams(window.location.search);
|
|
565
1971
|
const t = params.get("token");
|
|
566
1972
|
setToken(t && t.length > 0 ? t : null);
|
|
567
1973
|
}, []);
|
|
568
|
-
const passwordError = (0,
|
|
1974
|
+
const passwordError = (0, import_react14.useMemo)(() => {
|
|
569
1975
|
if (password.length === 0) return null;
|
|
570
1976
|
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
571
1977
|
return null;
|
|
572
1978
|
}, [password]);
|
|
573
|
-
const confirmError = (0,
|
|
1979
|
+
const confirmError = (0, import_react14.useMemo)(() => {
|
|
574
1980
|
if (confirm.length === 0) return null;
|
|
575
1981
|
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
576
1982
|
return null;
|
|
577
1983
|
}, [confirm, password]);
|
|
578
1984
|
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && passwordError === null && confirmError === null && !submitting && !done;
|
|
579
|
-
const submit = (0,
|
|
1985
|
+
const submit = (0, import_react14.useCallback)(async () => {
|
|
580
1986
|
if (!canSubmit || token === null) return;
|
|
581
1987
|
setSubmitting(true);
|
|
582
1988
|
setError(null);
|
|
@@ -612,67 +2018,67 @@ function useResetForm() {
|
|
|
612
2018
|
}
|
|
613
2019
|
|
|
614
2020
|
// src/defaults/DefaultResetScreen.tsx
|
|
615
|
-
var
|
|
2021
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
616
2022
|
function DefaultResetScreen({ onNavigate }) {
|
|
617
2023
|
const { name } = useTemplateConfig();
|
|
618
2024
|
const f = useResetForm();
|
|
619
2025
|
if (f.done) {
|
|
620
|
-
return /* @__PURE__ */ (0,
|
|
621
|
-
/* @__PURE__ */ (0,
|
|
622
|
-
/* @__PURE__ */ (0,
|
|
623
|
-
/* @__PURE__ */ (0,
|
|
2026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
2027
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Senha alterada" }),
|
|
2028
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Agora \xE9 s\xF3 fazer login com a nova senha." }),
|
|
2029
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-back-login", type: "button", onClick: () => onNavigate("login"), children: "Ir pro login" })
|
|
624
2030
|
] });
|
|
625
2031
|
}
|
|
626
2032
|
if (f.token === null) {
|
|
627
|
-
return /* @__PURE__ */ (0,
|
|
628
|
-
/* @__PURE__ */ (0,
|
|
629
|
-
/* @__PURE__ */ (0,
|
|
630
|
-
/* @__PURE__ */ (0,
|
|
2033
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto", textAlign: "center" }, children: [
|
|
2034
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { children: "Link inv\xE1lido" }),
|
|
2035
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: "Pe\xE7a um novo link de reset." }),
|
|
2036
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-goto-forgot", type: "button", onClick: () => onNavigate("forgot"), children: "Pedir novo link" })
|
|
631
2037
|
] });
|
|
632
2038
|
}
|
|
633
|
-
return /* @__PURE__ */ (0,
|
|
634
|
-
/* @__PURE__ */ (0,
|
|
635
|
-
/* @__PURE__ */ (0,
|
|
636
|
-
/* @__PURE__ */ (0,
|
|
2039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("main", { style: { padding: 24, maxWidth: 360, margin: "0 auto" }, children: [
|
|
2040
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { marginBottom: 8 }, children: name }),
|
|
2041
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: "Escolha uma nova senha" }),
|
|
2042
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("form", { onSubmit: (e) => {
|
|
637
2043
|
e.preventDefault();
|
|
638
2044
|
void f.submit();
|
|
639
2045
|
}, children: [
|
|
640
|
-
/* @__PURE__ */ (0,
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
641
2047
|
"Nova senha",
|
|
642
|
-
/* @__PURE__ */ (0,
|
|
643
|
-
f.passwordError && /* @__PURE__ */ (0,
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "reset-password", type: "password", value: f.password, onChange: (e) => f.setPassword(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
|
|
2049
|
+
f.passwordError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.passwordError })
|
|
644
2050
|
] }),
|
|
645
|
-
/* @__PURE__ */ (0,
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { display: "block", marginBottom: 12 }, children: [
|
|
646
2052
|
"Confirmar senha",
|
|
647
|
-
/* @__PURE__ */ (0,
|
|
648
|
-
f.confirmError && /* @__PURE__ */ (0,
|
|
2053
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("input", { "data-testid": "reset-confirm", type: "password", value: f.confirm, onChange: (e) => f.setConfirm(e.target.value), style: { display: "block", width: "100%" }, autoComplete: "new-password" }),
|
|
2054
|
+
f.confirmError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { style: { color: "#c00" }, children: f.confirmError })
|
|
649
2055
|
] }),
|
|
650
|
-
f.error && /* @__PURE__ */ (0,
|
|
651
|
-
/* @__PURE__ */ (0,
|
|
2056
|
+
f.error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: f.error.message }),
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { "data-testid": "reset-submit", type: "submit", disabled: !f.canSubmit, style: { width: "100%", padding: 12, background: "var(--hook-color-primary)", color: "#fff", border: "none", borderRadius: 8, opacity: f.canSubmit ? 1 : 0.5 }, children: f.submitting ? "Alterando..." : "Alterar senha" })
|
|
652
2058
|
] })
|
|
653
2059
|
] });
|
|
654
2060
|
}
|
|
655
2061
|
|
|
656
2062
|
// src/defaults/DefaultPaywall.tsx
|
|
657
|
-
var
|
|
658
|
-
var
|
|
2063
|
+
var import_react15 = require("react");
|
|
2064
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
659
2065
|
function DefaultPaywall() {
|
|
660
2066
|
const config = useTemplateConfig();
|
|
661
2067
|
const { checkout, opening, error } = usePaywallState();
|
|
662
2068
|
const p = config.subscription.paywall_config;
|
|
663
|
-
const [cpf, setCpf] = (0,
|
|
2069
|
+
const [cpf, setCpf] = (0, import_react15.useState)("");
|
|
664
2070
|
const cpfDigits = cpf.replace(/\D/g, "");
|
|
665
2071
|
const canCheckout = cpfDigits.length === 11 && !opening;
|
|
666
|
-
return /* @__PURE__ */ (0,
|
|
667
|
-
/* @__PURE__ */ (0,
|
|
668
|
-
p.subtitle && /* @__PURE__ */ (0,
|
|
669
|
-
/* @__PURE__ */ (0,
|
|
670
|
-
/* @__PURE__ */ (0,
|
|
671
|
-
/* @__PURE__ */ (0,
|
|
2072
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
|
|
2073
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { style: { marginBottom: 8 }, children: p.title }),
|
|
2074
|
+
p.subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7, marginBottom: 24 }, children: p.subtitle }),
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { style: { listStyle: "none", padding: 0, textAlign: "left", marginBottom: 24 }, children: p.benefits.map((b) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { style: { padding: "8px 0", display: "flex", alignItems: "center" }, children: [
|
|
2076
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, style: { marginRight: 8 }, children: "\u2713" }),
|
|
2077
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: b })
|
|
672
2078
|
] }, b)) }),
|
|
673
|
-
/* @__PURE__ */ (0,
|
|
674
|
-
/* @__PURE__ */ (0,
|
|
675
|
-
/* @__PURE__ */ (0,
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { textAlign: "left", marginBottom: 16 }, children: [
|
|
2080
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("label", { style: { display: "block", fontSize: 14, opacity: 0.7, marginBottom: 4 }, children: "Seu CPF (pra emiss\xE3o de recibo)" }),
|
|
2081
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
676
2082
|
"input",
|
|
677
2083
|
{
|
|
678
2084
|
"data-testid": "paywall-cpf",
|
|
@@ -685,8 +2091,8 @@ function DefaultPaywall() {
|
|
|
685
2091
|
}
|
|
686
2092
|
)
|
|
687
2093
|
] }),
|
|
688
|
-
error && /* @__PURE__ */ (0,
|
|
689
|
-
/* @__PURE__ */ (0,
|
|
2094
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", style: { color: "#c00", marginBottom: 12 }, children: error.message }),
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
690
2096
|
"button",
|
|
691
2097
|
{
|
|
692
2098
|
"data-testid": "paywall-cta",
|
|
@@ -707,21 +2113,21 @@ function DefaultPaywall() {
|
|
|
707
2113
|
children: opening ? "Abrindo..." : p.cta
|
|
708
2114
|
}
|
|
709
2115
|
),
|
|
710
|
-
p.priceHint && /* @__PURE__ */ (0,
|
|
711
|
-
p.footerNote && /* @__PURE__ */ (0,
|
|
2116
|
+
p.priceHint && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.6, marginTop: 12 }, children: p.priceHint }),
|
|
2117
|
+
p.footerNote && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.5, marginTop: 16, fontSize: 12 }, children: p.footerNote })
|
|
712
2118
|
] });
|
|
713
2119
|
}
|
|
714
2120
|
|
|
715
2121
|
// src/AppRoot.tsx
|
|
716
|
-
var
|
|
2122
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
717
2123
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
718
2124
|
function PaymentReturnHandler({ children }) {
|
|
719
2125
|
const { subscription } = (0, import_sdk9.useHook)();
|
|
720
|
-
const subRef = (0,
|
|
2126
|
+
const subRef = (0, import_react16.useRef)(subscription);
|
|
721
2127
|
subRef.current = subscription;
|
|
722
|
-
const runIdRef = (0,
|
|
723
|
-
const [state, setState] = (0,
|
|
724
|
-
const runPoll = (0,
|
|
2128
|
+
const runIdRef = (0, import_react16.useRef)(0);
|
|
2129
|
+
const [state, setState] = (0, import_react16.useState)("idle");
|
|
2130
|
+
const runPoll = (0, import_react16.useCallback)(() => {
|
|
725
2131
|
const runId = ++runIdRef.current;
|
|
726
2132
|
setState("confirming");
|
|
727
2133
|
let attempts = 0;
|
|
@@ -750,7 +2156,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
750
2156
|
};
|
|
751
2157
|
void tick();
|
|
752
2158
|
}, []);
|
|
753
|
-
(0,
|
|
2159
|
+
(0, import_react16.useEffect)(() => {
|
|
754
2160
|
if (typeof window === "undefined") return;
|
|
755
2161
|
const url = new URL(window.location.href);
|
|
756
2162
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
@@ -760,20 +2166,20 @@ function PaymentReturnHandler({ children }) {
|
|
|
760
2166
|
};
|
|
761
2167
|
}, [runPoll]);
|
|
762
2168
|
if (state === "confirming") {
|
|
763
|
-
return /* @__PURE__ */ (0,
|
|
2169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
764
2170
|
"div",
|
|
765
2171
|
{
|
|
766
2172
|
role: "status",
|
|
767
2173
|
"aria-live": "polite",
|
|
768
|
-
style:
|
|
2174
|
+
style: overlayStyle2,
|
|
769
2175
|
children: "Confirmando pagamento\u2026"
|
|
770
2176
|
}
|
|
771
2177
|
);
|
|
772
2178
|
}
|
|
773
2179
|
if (state === "waiting") {
|
|
774
|
-
return /* @__PURE__ */ (0,
|
|
775
|
-
/* @__PURE__ */ (0,
|
|
776
|
-
/* @__PURE__ */ (0,
|
|
2180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2182
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
777
2183
|
"button",
|
|
778
2184
|
{
|
|
779
2185
|
type: "button",
|
|
@@ -784,9 +2190,9 @@ function PaymentReturnHandler({ children }) {
|
|
|
784
2190
|
)
|
|
785
2191
|
] }) });
|
|
786
2192
|
}
|
|
787
|
-
return /* @__PURE__ */ (0,
|
|
2193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children });
|
|
788
2194
|
}
|
|
789
|
-
var
|
|
2195
|
+
var overlayStyle2 = {
|
|
790
2196
|
position: "fixed",
|
|
791
2197
|
inset: 0,
|
|
792
2198
|
display: "flex",
|
|
@@ -817,14 +2223,14 @@ function AppRoot({
|
|
|
817
2223
|
Reset = DefaultResetScreen,
|
|
818
2224
|
Paywall = DefaultPaywall
|
|
819
2225
|
}) {
|
|
820
|
-
return /* @__PURE__ */ (0,
|
|
2226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PaymentReturnHandler, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TemplateConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AuthGate, { Login, Signup, Forgot, Reset, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PersistedKeysPrefetch, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(SubscriptionGate, { Paywall, children: [
|
|
821
2227
|
children,
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
823
|
-
] }) }) }) }) }) }) });
|
|
2228
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(PushPrompt, {})
|
|
2229
|
+
] }) }) }) }) }) }) }) });
|
|
824
2230
|
}
|
|
825
2231
|
|
|
826
2232
|
// src/hooks/usePush.ts
|
|
827
|
-
var
|
|
2233
|
+
var import_react17 = require("react");
|
|
828
2234
|
var import_sdk10 = require("@hook-sdk/sdk");
|
|
829
2235
|
function detectIosNeedsInstall() {
|
|
830
2236
|
if (typeof navigator === "undefined" || typeof window === "undefined") return false;
|
|
@@ -852,11 +2258,11 @@ function deriveState(push) {
|
|
|
852
2258
|
}
|
|
853
2259
|
function usePush() {
|
|
854
2260
|
const { push } = (0, import_sdk10.useHook)();
|
|
855
|
-
const [state, setState] = (0,
|
|
856
|
-
(0,
|
|
2261
|
+
const [state, setState] = (0, import_react17.useState)(() => deriveState(push));
|
|
2262
|
+
(0, import_react17.useEffect)(() => {
|
|
857
2263
|
setState(deriveState(push));
|
|
858
2264
|
}, [push]);
|
|
859
|
-
const subscribe = (0,
|
|
2265
|
+
const subscribe = (0, import_react17.useCallback)(async () => {
|
|
860
2266
|
try {
|
|
861
2267
|
await push.subscribe();
|
|
862
2268
|
setState({ kind: "subscribed" });
|
|
@@ -868,7 +2274,7 @@ function usePush() {
|
|
|
868
2274
|
throw e;
|
|
869
2275
|
}
|
|
870
2276
|
}, [push]);
|
|
871
|
-
const unsubscribe = (0,
|
|
2277
|
+
const unsubscribe = (0, import_react17.useCallback)(async () => {
|
|
872
2278
|
try {
|
|
873
2279
|
await push.unsubscribe();
|
|
874
2280
|
setState({ kind: "prompt" });
|
|
@@ -881,31 +2287,31 @@ function usePush() {
|
|
|
881
2287
|
}
|
|
882
2288
|
|
|
883
2289
|
// src/components/PushPrompt.tsx
|
|
884
|
-
var
|
|
2290
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
885
2291
|
function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
|
|
886
2292
|
const { state, subscribe } = usePush();
|
|
887
2293
|
if (state.kind === "subscribed") return null;
|
|
888
2294
|
if (state.kind === "ios_needs_install") {
|
|
889
|
-
return /* @__PURE__ */ (0,
|
|
890
|
-
/* @__PURE__ */ (0,
|
|
891
|
-
/* @__PURE__ */ (0,
|
|
892
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0,
|
|
2295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2296
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2297
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.iosInstallBody }),
|
|
2298
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
893
2299
|
] });
|
|
894
2300
|
}
|
|
895
2301
|
if (state.kind === "denied") {
|
|
896
|
-
return /* @__PURE__ */ (0,
|
|
897
|
-
/* @__PURE__ */ (0,
|
|
898
|
-
/* @__PURE__ */ (0,
|
|
2302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h3", { children: texts.deniedTitle }),
|
|
2304
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.deniedBody })
|
|
899
2305
|
] });
|
|
900
2306
|
}
|
|
901
2307
|
if (state.kind === "unsupported") {
|
|
902
|
-
return /* @__PURE__ */ (0,
|
|
2308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: texts.unsupportedBody }) });
|
|
903
2309
|
}
|
|
904
2310
|
if (state.kind === "error") {
|
|
905
|
-
return /* @__PURE__ */ (0,
|
|
2311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { children: state.message }) });
|
|
906
2312
|
}
|
|
907
|
-
return /* @__PURE__ */ (0,
|
|
908
|
-
/* @__PURE__ */ (0,
|
|
2313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className, role: "region", children: [
|
|
2314
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
909
2315
|
"button",
|
|
910
2316
|
{
|
|
911
2317
|
type: "button",
|
|
@@ -919,27 +2325,27 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
919
2325
|
children: texts.cta
|
|
920
2326
|
}
|
|
921
2327
|
),
|
|
922
|
-
onDeclined && /* @__PURE__ */ (0,
|
|
2328
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
923
2329
|
] });
|
|
924
2330
|
}
|
|
925
2331
|
|
|
926
2332
|
// src/defaults/EmptyState.tsx
|
|
927
|
-
var
|
|
2333
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
928
2334
|
function EmptyState({ title, description, action }) {
|
|
929
|
-
return /* @__PURE__ */ (0,
|
|
930
|
-
/* @__PURE__ */ (0,
|
|
931
|
-
description && /* @__PURE__ */ (0,
|
|
932
|
-
action && /* @__PURE__ */ (0,
|
|
2335
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2337
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2338
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
933
2339
|
] });
|
|
934
2340
|
}
|
|
935
2341
|
|
|
936
2342
|
// src/hooks/useAuthPrimitives.ts
|
|
937
|
-
var
|
|
2343
|
+
var import_react18 = require("react");
|
|
938
2344
|
var import_sdk11 = require("@hook-sdk/sdk");
|
|
939
2345
|
var warned = false;
|
|
940
2346
|
function useAuthPrimitives() {
|
|
941
2347
|
const { auth } = (0, import_sdk11.useHook)();
|
|
942
|
-
(0,
|
|
2348
|
+
(0, import_react18.useEffect)(() => {
|
|
943
2349
|
if (!warned && process.env.NODE_ENV !== "production") {
|
|
944
2350
|
warned = true;
|
|
945
2351
|
console.warn(
|
|
@@ -970,14 +2376,14 @@ function useSubscription() {
|
|
|
970
2376
|
}
|
|
971
2377
|
|
|
972
2378
|
// src/hooks/useReminders.ts
|
|
973
|
-
var
|
|
2379
|
+
var import_react19 = require("react");
|
|
974
2380
|
var import_sdk13 = require("@hook-sdk/sdk");
|
|
975
2381
|
function useReminders() {
|
|
976
2382
|
const { push } = (0, import_sdk13.useHook)();
|
|
977
2383
|
const r = push.reminders;
|
|
978
|
-
const [reminders, setReminders] = (0,
|
|
979
|
-
const [loading, setLoading] = (0,
|
|
980
|
-
const reload = (0,
|
|
2384
|
+
const [reminders, setReminders] = (0, import_react19.useState)([]);
|
|
2385
|
+
const [loading, setLoading] = (0, import_react19.useState)(true);
|
|
2386
|
+
const reload = (0, import_react19.useCallback)(async () => {
|
|
981
2387
|
setLoading(true);
|
|
982
2388
|
try {
|
|
983
2389
|
const next = await r.list();
|
|
@@ -986,38 +2392,38 @@ function useReminders() {
|
|
|
986
2392
|
setLoading(false);
|
|
987
2393
|
}
|
|
988
2394
|
}, [r]);
|
|
989
|
-
(0,
|
|
2395
|
+
(0, import_react19.useEffect)(() => {
|
|
990
2396
|
void reload();
|
|
991
2397
|
}, [reload]);
|
|
992
|
-
const setReminder = (0,
|
|
2398
|
+
const setReminder = (0, import_react19.useCallback)(async (input) => {
|
|
993
2399
|
await r.set(input);
|
|
994
2400
|
await reload();
|
|
995
2401
|
}, [r, reload]);
|
|
996
|
-
const deleteReminder = (0,
|
|
2402
|
+
const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
|
|
997
2403
|
await r.delete(slot);
|
|
998
2404
|
await reload();
|
|
999
2405
|
}, [r, reload]);
|
|
1000
|
-
const schedule = (0,
|
|
2406
|
+
const schedule = (0, import_react19.useCallback)(async (items) => {
|
|
1001
2407
|
return r.schedule(items);
|
|
1002
2408
|
}, [r]);
|
|
1003
|
-
const setFallbacks = (0,
|
|
2409
|
+
const setFallbacks = (0, import_react19.useCallback)(async (items) => {
|
|
1004
2410
|
return r.setFallbacks(items);
|
|
1005
2411
|
}, [r]);
|
|
1006
2412
|
return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
|
|
1007
2413
|
}
|
|
1008
2414
|
|
|
1009
2415
|
// src/hooks/useToast.ts
|
|
1010
|
-
var
|
|
2416
|
+
var import_react20 = require("react");
|
|
1011
2417
|
function useToast() {
|
|
1012
|
-
const [items, setItems] = (0,
|
|
1013
|
-
const show = (0,
|
|
2418
|
+
const [items, setItems] = (0, import_react20.useState)([]);
|
|
2419
|
+
const show = (0, import_react20.useCallback)((message, kind = "info") => {
|
|
1014
2420
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1015
2421
|
setItems((prev) => [...prev, { id, message, kind }]);
|
|
1016
2422
|
setTimeout(() => {
|
|
1017
2423
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
1018
2424
|
}, 4e3);
|
|
1019
2425
|
}, []);
|
|
1020
|
-
const dismiss = (0,
|
|
2426
|
+
const dismiss = (0, import_react20.useCallback)((id) => {
|
|
1021
2427
|
setItems((prev) => prev.filter((t) => t.id !== id));
|
|
1022
2428
|
}, []);
|
|
1023
2429
|
return { items, show, dismiss };
|
|
@@ -1032,11 +2438,21 @@ function useToast() {
|
|
|
1032
2438
|
DefaultSignupScreen,
|
|
1033
2439
|
EmptyState,
|
|
1034
2440
|
ErrorBoundary,
|
|
2441
|
+
InstallGate,
|
|
2442
|
+
InstallSplash,
|
|
1035
2443
|
LoadingState,
|
|
1036
2444
|
PushPrompt,
|
|
2445
|
+
detectAndroidBrowser,
|
|
2446
|
+
detectIOSBrowser,
|
|
2447
|
+
detectInAppApp,
|
|
2448
|
+
detectPlatform,
|
|
2449
|
+
detectStandalone,
|
|
2450
|
+
shouldBlockInstall,
|
|
2451
|
+
shouldShowPermanentOption,
|
|
1037
2452
|
useAuth,
|
|
1038
2453
|
useAuthPrimitives,
|
|
1039
2454
|
useForgotForm,
|
|
2455
|
+
useInstallPrompt,
|
|
1040
2456
|
useLoginForm,
|
|
1041
2457
|
usePaywallState,
|
|
1042
2458
|
usePush,
|