@hook-sdk/template 0.13.0 → 0.14.1
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 +335 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +311 -142
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -147,7 +147,11 @@ var DeepLinksSchema = import_zod.z.object({
|
|
|
147
147
|
var AppConfigSchema = import_zod.z.object({
|
|
148
148
|
slug: import_zod.z.string().regex(/^[a-z0-9-]+$/),
|
|
149
149
|
name: import_zod.z.string().min(1),
|
|
150
|
-
branding: import_zod.z.object({
|
|
150
|
+
branding: import_zod.z.object({
|
|
151
|
+
primaryColor: import_zod.z.string(),
|
|
152
|
+
logoUrl: import_zod.z.string().url(),
|
|
153
|
+
iconUrl: import_zod.z.string().url().optional()
|
|
154
|
+
}),
|
|
151
155
|
authFlow: AuthFlowSchema,
|
|
152
156
|
paywall: PaywallSchema,
|
|
153
157
|
persistedKeys: import_zod.z.array(PersistedKeySchema),
|
|
@@ -567,6 +571,7 @@ var import_react8 = require("react");
|
|
|
567
571
|
|
|
568
572
|
// src/hooks/useInstallPrompt.ts
|
|
569
573
|
var import_react6 = require("react");
|
|
574
|
+
var ANDROID_PROMPT_WAIT_MS = 3e3;
|
|
570
575
|
var IOS_RE = /iPad|iPhone|iPod/;
|
|
571
576
|
var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
|
|
572
577
|
var ANDROID_RE = /Android/;
|
|
@@ -636,11 +641,12 @@ function track(event, props) {
|
|
|
636
641
|
if (typeof window === "undefined") return;
|
|
637
642
|
window.posthog?.capture?.(event, props);
|
|
638
643
|
}
|
|
639
|
-
function pickVariant(state) {
|
|
644
|
+
function pickVariant(state, promptWaitElapsed) {
|
|
640
645
|
if (state.isInstalled) return "none";
|
|
641
646
|
switch (state.platform) {
|
|
642
647
|
case "android":
|
|
643
|
-
|
|
648
|
+
if (state.isInstallable) return "android-native";
|
|
649
|
+
return promptWaitElapsed ? "android-manual" : "android-pending";
|
|
644
650
|
case "ios-safari":
|
|
645
651
|
return "ios-safari";
|
|
646
652
|
case "ios-other":
|
|
@@ -710,6 +716,15 @@ function useInstallPrompt(slug) {
|
|
|
710
716
|
const [isDismissedSession, setIsDismissedSession] = (0, import_react6.useState)(() => readSessionSkip(slug));
|
|
711
717
|
const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react6.useState)(() => readPermanentDismiss(slug).dismissed);
|
|
712
718
|
const [skipCount, setSkipCount] = (0, import_react6.useState)(() => readSkipCount(slug));
|
|
719
|
+
const [promptWaitElapsed, setPromptWaitElapsed] = (0, import_react6.useState)(() => {
|
|
720
|
+
if (typeof window === "undefined") return true;
|
|
721
|
+
return window.__pwaInstallPrompt != null;
|
|
722
|
+
});
|
|
723
|
+
(0, import_react6.useEffect)(() => {
|
|
724
|
+
if (promptWaitElapsed) return;
|
|
725
|
+
const id = setTimeout(() => setPromptWaitElapsed(true), ANDROID_PROMPT_WAIT_MS);
|
|
726
|
+
return () => clearTimeout(id);
|
|
727
|
+
}, [promptWaitElapsed]);
|
|
713
728
|
(0, import_react6.useEffect)(() => {
|
|
714
729
|
if (typeof window === "undefined") return;
|
|
715
730
|
if (window.__pwaInstallPrompt) {
|
|
@@ -747,17 +762,20 @@ function useInstallPrompt(slug) {
|
|
|
747
762
|
mq.addEventListener?.("change", handler);
|
|
748
763
|
return () => mq.removeEventListener?.("change", handler);
|
|
749
764
|
}, [slug]);
|
|
750
|
-
const variant = pickVariant(
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
765
|
+
const variant = pickVariant(
|
|
766
|
+
{
|
|
767
|
+
platform,
|
|
768
|
+
iosBrowser,
|
|
769
|
+
androidBrowser,
|
|
770
|
+
inAppApp,
|
|
771
|
+
isInstallable,
|
|
772
|
+
isInstalled,
|
|
773
|
+
isDismissedSession,
|
|
774
|
+
isDismissedPermanent,
|
|
775
|
+
skipCount
|
|
776
|
+
},
|
|
777
|
+
promptWaitElapsed
|
|
778
|
+
);
|
|
761
779
|
const promptInstall = (0, import_react6.useCallback)(async () => {
|
|
762
780
|
if (typeof window === "undefined") return false;
|
|
763
781
|
const prompt = window.__pwaInstallPrompt;
|
|
@@ -1293,15 +1311,51 @@ function Step({ n, icon, children }) {
|
|
|
1293
1311
|
);
|
|
1294
1312
|
}
|
|
1295
1313
|
|
|
1296
|
-
// src/components/InstallGate/
|
|
1314
|
+
// src/components/InstallGate/variants/AndroidPendingVariant.tsx
|
|
1297
1315
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1316
|
+
function AndroidPendingVariant() {
|
|
1317
|
+
const copy = INSTALL_COPY.android.native;
|
|
1318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(InstallSplash, { title: copy.title, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1319
|
+
"div",
|
|
1320
|
+
{
|
|
1321
|
+
style: {
|
|
1322
|
+
display: "flex",
|
|
1323
|
+
flexDirection: "column",
|
|
1324
|
+
alignItems: "center",
|
|
1325
|
+
gap: 16,
|
|
1326
|
+
padding: "24px 0"
|
|
1327
|
+
},
|
|
1328
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, {})
|
|
1329
|
+
}
|
|
1330
|
+
) });
|
|
1331
|
+
}
|
|
1332
|
+
function Spinner() {
|
|
1333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1334
|
+
"div",
|
|
1335
|
+
{
|
|
1336
|
+
"aria-hidden": true,
|
|
1337
|
+
style: {
|
|
1338
|
+
width: 28,
|
|
1339
|
+
height: 28,
|
|
1340
|
+
borderRadius: "50%",
|
|
1341
|
+
border: "3px solid #e5e5e7",
|
|
1342
|
+
borderTopColor: "var(--hook-color-primary)",
|
|
1343
|
+
animation: "hook-install-spin 0.8s linear infinite"
|
|
1344
|
+
},
|
|
1345
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: `@keyframes hook-install-spin { to { transform: rotate(360deg); } }` })
|
|
1346
|
+
}
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// src/components/InstallGate/Step.tsx
|
|
1351
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1298
1352
|
function Step2({
|
|
1299
1353
|
n,
|
|
1300
1354
|
title,
|
|
1301
1355
|
subtitle,
|
|
1302
1356
|
visual
|
|
1303
1357
|
}) {
|
|
1304
|
-
return /* @__PURE__ */ (0,
|
|
1358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1305
1359
|
"div",
|
|
1306
1360
|
{
|
|
1307
1361
|
style: {
|
|
@@ -1312,7 +1366,7 @@ function Step2({
|
|
|
1312
1366
|
textAlign: "left"
|
|
1313
1367
|
},
|
|
1314
1368
|
children: [
|
|
1315
|
-
/* @__PURE__ */ (0,
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1316
1370
|
"div",
|
|
1317
1371
|
{
|
|
1318
1372
|
style: {
|
|
@@ -1331,9 +1385,9 @@ function Step2({
|
|
|
1331
1385
|
children: n
|
|
1332
1386
|
}
|
|
1333
1387
|
),
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
1335
|
-
/* @__PURE__ */ (0,
|
|
1336
|
-
subtitle && /* @__PURE__ */ (0,
|
|
1388
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1 }, children: [
|
|
1389
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
|
|
1390
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
|
|
1337
1391
|
visual
|
|
1338
1392
|
] })
|
|
1339
1393
|
]
|
|
@@ -1342,21 +1396,21 @@ function Step2({
|
|
|
1342
1396
|
}
|
|
1343
1397
|
|
|
1344
1398
|
// src/components/InstallGate/variants/IOSafariVariant.tsx
|
|
1345
|
-
var
|
|
1399
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1346
1400
|
function IOSafariVariant({
|
|
1347
1401
|
state,
|
|
1348
1402
|
actions
|
|
1349
1403
|
}) {
|
|
1350
1404
|
const copy = INSTALL_COPY.iosSafari;
|
|
1351
1405
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1352
|
-
return /* @__PURE__ */ (0,
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1407
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1354
1408
|
Step2,
|
|
1355
1409
|
{
|
|
1356
1410
|
n: 1,
|
|
1357
1411
|
title: copy.step1.title,
|
|
1358
1412
|
subtitle: copy.step1.subtitle,
|
|
1359
|
-
visual: /* @__PURE__ */ (0,
|
|
1413
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1360
1414
|
"div",
|
|
1361
1415
|
{
|
|
1362
1416
|
style: {
|
|
@@ -1368,17 +1422,17 @@ function IOSafariVariant({
|
|
|
1368
1422
|
padding: "12px 0",
|
|
1369
1423
|
marginTop: 8
|
|
1370
1424
|
},
|
|
1371
|
-
children: /* @__PURE__ */ (0,
|
|
1425
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
|
|
1372
1426
|
}
|
|
1373
1427
|
)
|
|
1374
1428
|
}
|
|
1375
1429
|
),
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1377
1431
|
Step2,
|
|
1378
1432
|
{
|
|
1379
1433
|
n: 2,
|
|
1380
1434
|
title: copy.step2.title,
|
|
1381
|
-
visual: /* @__PURE__ */ (0,
|
|
1435
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1382
1436
|
"div",
|
|
1383
1437
|
{
|
|
1384
1438
|
style: {
|
|
@@ -1391,19 +1445,19 @@ function IOSafariVariant({
|
|
|
1391
1445
|
marginTop: 8
|
|
1392
1446
|
},
|
|
1393
1447
|
children: [
|
|
1394
|
-
/* @__PURE__ */ (0,
|
|
1395
|
-
/* @__PURE__ */ (0,
|
|
1448
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
|
|
1396
1450
|
]
|
|
1397
1451
|
}
|
|
1398
1452
|
)
|
|
1399
1453
|
}
|
|
1400
1454
|
),
|
|
1401
|
-
/* @__PURE__ */ (0,
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1402
1456
|
Step2,
|
|
1403
1457
|
{
|
|
1404
1458
|
n: 3,
|
|
1405
1459
|
title: copy.step3.title,
|
|
1406
|
-
visual: /* @__PURE__ */ (0,
|
|
1460
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1407
1461
|
"div",
|
|
1408
1462
|
{
|
|
1409
1463
|
style: {
|
|
@@ -1414,7 +1468,7 @@ function IOSafariVariant({
|
|
|
1414
1468
|
padding: "10px 14px",
|
|
1415
1469
|
marginTop: 8
|
|
1416
1470
|
},
|
|
1417
|
-
children: /* @__PURE__ */ (0,
|
|
1471
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1418
1472
|
"span",
|
|
1419
1473
|
{
|
|
1420
1474
|
style: {
|
|
@@ -1429,7 +1483,7 @@ function IOSafariVariant({
|
|
|
1429
1483
|
)
|
|
1430
1484
|
}
|
|
1431
1485
|
),
|
|
1432
|
-
/* @__PURE__ */ (0,
|
|
1486
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1433
1487
|
"button",
|
|
1434
1488
|
{
|
|
1435
1489
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1439,7 +1493,7 @@ function IOSafariVariant({
|
|
|
1439
1493
|
children: copy.skip
|
|
1440
1494
|
}
|
|
1441
1495
|
),
|
|
1442
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1496
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1443
1497
|
"button",
|
|
1444
1498
|
{
|
|
1445
1499
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1453,21 +1507,21 @@ function IOSafariVariant({
|
|
|
1453
1507
|
}
|
|
1454
1508
|
|
|
1455
1509
|
// src/components/InstallGate/variants/IOSOtherVariant.tsx
|
|
1456
|
-
var
|
|
1510
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1457
1511
|
function IOSOtherVariant({
|
|
1458
1512
|
state,
|
|
1459
1513
|
actions
|
|
1460
1514
|
}) {
|
|
1461
1515
|
const copy = INSTALL_COPY.iosOther;
|
|
1462
1516
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1463
|
-
return /* @__PURE__ */ (0,
|
|
1464
|
-
/* @__PURE__ */ (0,
|
|
1517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1465
1519
|
Step2,
|
|
1466
1520
|
{
|
|
1467
1521
|
n: 1,
|
|
1468
1522
|
title: copy.step1.title,
|
|
1469
1523
|
subtitle: copy.step1.subtitle,
|
|
1470
|
-
visual: /* @__PURE__ */ (0,
|
|
1524
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1471
1525
|
"div",
|
|
1472
1526
|
{
|
|
1473
1527
|
style: {
|
|
@@ -1479,17 +1533,17 @@ function IOSOtherVariant({
|
|
|
1479
1533
|
padding: "12px 0",
|
|
1480
1534
|
marginTop: 8
|
|
1481
1535
|
},
|
|
1482
|
-
children: /* @__PURE__ */ (0,
|
|
1536
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
|
|
1483
1537
|
}
|
|
1484
1538
|
)
|
|
1485
1539
|
}
|
|
1486
1540
|
),
|
|
1487
|
-
/* @__PURE__ */ (0,
|
|
1541
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1488
1542
|
Step2,
|
|
1489
1543
|
{
|
|
1490
1544
|
n: 2,
|
|
1491
1545
|
title: copy.step2.title,
|
|
1492
|
-
visual: /* @__PURE__ */ (0,
|
|
1546
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1493
1547
|
"div",
|
|
1494
1548
|
{
|
|
1495
1549
|
style: {
|
|
@@ -1502,19 +1556,19 @@ function IOSOtherVariant({
|
|
|
1502
1556
|
marginTop: 8
|
|
1503
1557
|
},
|
|
1504
1558
|
children: [
|
|
1505
|
-
/* @__PURE__ */ (0,
|
|
1506
|
-
/* @__PURE__ */ (0,
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
|
|
1560
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
|
|
1507
1561
|
]
|
|
1508
1562
|
}
|
|
1509
1563
|
)
|
|
1510
1564
|
}
|
|
1511
1565
|
),
|
|
1512
|
-
/* @__PURE__ */ (0,
|
|
1566
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1513
1567
|
Step2,
|
|
1514
1568
|
{
|
|
1515
1569
|
n: 3,
|
|
1516
1570
|
title: copy.step3.title,
|
|
1517
|
-
visual: /* @__PURE__ */ (0,
|
|
1571
|
+
visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1518
1572
|
"div",
|
|
1519
1573
|
{
|
|
1520
1574
|
style: {
|
|
@@ -1525,7 +1579,7 @@ function IOSOtherVariant({
|
|
|
1525
1579
|
padding: "10px 14px",
|
|
1526
1580
|
marginTop: 8
|
|
1527
1581
|
},
|
|
1528
|
-
children: /* @__PURE__ */ (0,
|
|
1582
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1529
1583
|
"span",
|
|
1530
1584
|
{
|
|
1531
1585
|
style: {
|
|
@@ -1540,7 +1594,7 @@ function IOSOtherVariant({
|
|
|
1540
1594
|
)
|
|
1541
1595
|
}
|
|
1542
1596
|
),
|
|
1543
|
-
/* @__PURE__ */ (0,
|
|
1597
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1544
1598
|
"button",
|
|
1545
1599
|
{
|
|
1546
1600
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1550,7 +1604,7 @@ function IOSOtherVariant({
|
|
|
1550
1604
|
children: copy.skip
|
|
1551
1605
|
}
|
|
1552
1606
|
),
|
|
1553
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1607
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1554
1608
|
"button",
|
|
1555
1609
|
{
|
|
1556
1610
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1565,7 +1619,7 @@ function IOSOtherVariant({
|
|
|
1565
1619
|
|
|
1566
1620
|
// src/components/InstallGate/variants/InAppBrowserVariant.tsx
|
|
1567
1621
|
var import_react7 = require("react");
|
|
1568
|
-
var
|
|
1622
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1569
1623
|
function InAppBrowserVariant({
|
|
1570
1624
|
state,
|
|
1571
1625
|
actions
|
|
@@ -1581,10 +1635,10 @@ function InAppBrowserVariant({
|
|
|
1581
1635
|
setTimeout(() => setCopied(false), 2e3);
|
|
1582
1636
|
};
|
|
1583
1637
|
const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
|
|
1584
|
-
return /* @__PURE__ */ (0,
|
|
1585
|
-
/* @__PURE__ */ (0,
|
|
1586
|
-
/* @__PURE__ */ (0,
|
|
1587
|
-
/* @__PURE__ */ (0,
|
|
1638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(InstallSplash, { title: appCopy.title, children: [
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1588
1642
|
"button",
|
|
1589
1643
|
{
|
|
1590
1644
|
"data-testid": "install-prompt-cta-inapp-copy",
|
|
@@ -1594,7 +1648,7 @@ function InAppBrowserVariant({
|
|
|
1594
1648
|
children: copied ? copy.copiedToast : copy.copy
|
|
1595
1649
|
}
|
|
1596
1650
|
),
|
|
1597
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1598
1652
|
"button",
|
|
1599
1653
|
{
|
|
1600
1654
|
"data-testid": "install-prompt-skip-session",
|
|
@@ -1604,7 +1658,7 @@ function InAppBrowserVariant({
|
|
|
1604
1658
|
children: copy.skip
|
|
1605
1659
|
}
|
|
1606
1660
|
),
|
|
1607
|
-
showPermanent && /* @__PURE__ */ (0,
|
|
1661
|
+
showPermanent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1608
1662
|
"button",
|
|
1609
1663
|
{
|
|
1610
1664
|
"data-testid": "install-prompt-skip-permanent",
|
|
@@ -1621,7 +1675,7 @@ function Step3({
|
|
|
1621
1675
|
icon,
|
|
1622
1676
|
children
|
|
1623
1677
|
}) {
|
|
1624
|
-
return /* @__PURE__ */ (0,
|
|
1678
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1625
1679
|
"div",
|
|
1626
1680
|
{
|
|
1627
1681
|
style: {
|
|
@@ -1635,7 +1689,7 @@ function Step3({
|
|
|
1635
1689
|
textAlign: "left"
|
|
1636
1690
|
},
|
|
1637
1691
|
children: [
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1692
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1639
1693
|
"div",
|
|
1640
1694
|
{
|
|
1641
1695
|
style: {
|
|
@@ -1654,15 +1708,15 @@ function Step3({
|
|
|
1654
1708
|
children: n
|
|
1655
1709
|
}
|
|
1656
1710
|
),
|
|
1657
|
-
/* @__PURE__ */ (0,
|
|
1658
|
-
/* @__PURE__ */ (0,
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
|
|
1659
1713
|
]
|
|
1660
1714
|
}
|
|
1661
1715
|
);
|
|
1662
1716
|
}
|
|
1663
1717
|
|
|
1664
1718
|
// src/components/InstallGate/variants/DesktopVariant.tsx
|
|
1665
|
-
var
|
|
1719
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1666
1720
|
function DesktopVariant({
|
|
1667
1721
|
state,
|
|
1668
1722
|
actions
|
|
@@ -1671,21 +1725,21 @@ function DesktopVariant({
|
|
|
1671
1725
|
const copy = INSTALL_COPY.desktop;
|
|
1672
1726
|
const iconUrl = theme.icon_url || theme.logo_url || null;
|
|
1673
1727
|
if (!state.isInstallable) return null;
|
|
1674
|
-
return /* @__PURE__ */ (0,
|
|
1728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1675
1729
|
"div",
|
|
1676
1730
|
{
|
|
1677
1731
|
role: "complementary",
|
|
1678
1732
|
"aria-label": copy.title,
|
|
1679
1733
|
style: bannerStyle,
|
|
1680
1734
|
children: [
|
|
1681
|
-
iconUrl ? /* @__PURE__ */ (0,
|
|
1735
|
+
iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1682
1736
|
"img",
|
|
1683
1737
|
{
|
|
1684
1738
|
src: iconUrl,
|
|
1685
1739
|
alt: "",
|
|
1686
1740
|
style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
|
|
1687
1741
|
}
|
|
1688
|
-
) : /* @__PURE__ */ (0,
|
|
1742
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1689
1743
|
"div",
|
|
1690
1744
|
{
|
|
1691
1745
|
style: {
|
|
@@ -1704,11 +1758,11 @@ function DesktopVariant({
|
|
|
1704
1758
|
children: name.charAt(0).toUpperCase()
|
|
1705
1759
|
}
|
|
1706
1760
|
),
|
|
1707
|
-
/* @__PURE__ */ (0,
|
|
1708
|
-
/* @__PURE__ */ (0,
|
|
1709
|
-
/* @__PURE__ */ (0,
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
|
|
1710
1764
|
] }),
|
|
1711
|
-
/* @__PURE__ */ (0,
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1712
1766
|
"button",
|
|
1713
1767
|
{
|
|
1714
1768
|
"data-testid": "install-prompt-cta-desktop",
|
|
@@ -1729,12 +1783,12 @@ function DesktopVariant({
|
|
|
1729
1783
|
flexShrink: 0
|
|
1730
1784
|
},
|
|
1731
1785
|
children: [
|
|
1732
|
-
/* @__PURE__ */ (0,
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DownloadIcon, { size: 14 }),
|
|
1733
1787
|
copy.cta
|
|
1734
1788
|
]
|
|
1735
1789
|
}
|
|
1736
1790
|
),
|
|
1737
|
-
/* @__PURE__ */ (0,
|
|
1791
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1738
1792
|
"button",
|
|
1739
1793
|
{
|
|
1740
1794
|
"data-testid": "install-prompt-desktop-close",
|
|
@@ -1749,7 +1803,7 @@ function DesktopVariant({
|
|
|
1749
1803
|
padding: 4,
|
|
1750
1804
|
flexShrink: 0
|
|
1751
1805
|
},
|
|
1752
|
-
children: /* @__PURE__ */ (0,
|
|
1806
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { size: 16 })
|
|
1753
1807
|
}
|
|
1754
1808
|
)
|
|
1755
1809
|
]
|
|
@@ -1773,7 +1827,7 @@ var bannerStyle = {
|
|
|
1773
1827
|
};
|
|
1774
1828
|
|
|
1775
1829
|
// src/components/InstallGate/InstallGate.tsx
|
|
1776
|
-
var
|
|
1830
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1777
1831
|
function InstallGate({ children }) {
|
|
1778
1832
|
const { slug, features_enabled } = useTemplateConfig();
|
|
1779
1833
|
const enabled = features_enabled.includes("install_prompt");
|
|
@@ -1794,30 +1848,32 @@ function InstallGate({ children }) {
|
|
|
1794
1848
|
variant: installState.variant
|
|
1795
1849
|
});
|
|
1796
1850
|
}, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
|
|
1797
|
-
if (!enabled) return /* @__PURE__ */ (0,
|
|
1798
|
-
if (installState.isInstalled) return /* @__PURE__ */ (0,
|
|
1851
|
+
if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1852
|
+
if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1799
1853
|
if (installState.variant === "desktop") {
|
|
1800
1854
|
const showBanner = !installState.isDismissedSession && !installState.isDismissedPermanent;
|
|
1801
|
-
return /* @__PURE__ */ (0,
|
|
1855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
1802
1856
|
children,
|
|
1803
|
-
showBanner && /* @__PURE__ */ (0,
|
|
1857
|
+
showBanner && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DesktopVariant, { state: installState, actions: installState })
|
|
1804
1858
|
] });
|
|
1805
1859
|
}
|
|
1806
|
-
if (!shouldBlock) return /* @__PURE__ */ (0,
|
|
1860
|
+
if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1807
1861
|
switch (installState.variant) {
|
|
1808
1862
|
case "android-native":
|
|
1809
|
-
return /* @__PURE__ */ (0,
|
|
1863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
|
|
1810
1864
|
case "android-manual":
|
|
1811
|
-
return /* @__PURE__ */ (0,
|
|
1865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidManualVariant, { state: installState, actions: installState });
|
|
1866
|
+
case "android-pending":
|
|
1867
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidPendingVariant, {});
|
|
1812
1868
|
case "ios-safari":
|
|
1813
|
-
return /* @__PURE__ */ (0,
|
|
1869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSafariVariant, { state: installState, actions: installState });
|
|
1814
1870
|
case "ios-other":
|
|
1815
|
-
return /* @__PURE__ */ (0,
|
|
1871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSOtherVariant, { state: installState, actions: installState });
|
|
1816
1872
|
case "in-app":
|
|
1817
|
-
return /* @__PURE__ */ (0,
|
|
1873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
|
|
1818
1874
|
case "none":
|
|
1819
1875
|
default:
|
|
1820
|
-
return /* @__PURE__ */ (0,
|
|
1876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1821
1877
|
}
|
|
1822
1878
|
}
|
|
1823
1879
|
|
|
@@ -1829,7 +1885,7 @@ function PushPrompt() {
|
|
|
1829
1885
|
// src/internal/SessionExpiredBanner.tsx
|
|
1830
1886
|
var import_react9 = require("react");
|
|
1831
1887
|
var import_sdk3 = require("@hook-sdk/sdk");
|
|
1832
|
-
var
|
|
1888
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1833
1889
|
var DISMISS_KEY = "hook:session-expired-dismissed-until";
|
|
1834
1890
|
var DISMISS_TTL_MS = 60 * 60 * 1e3;
|
|
1835
1891
|
function SessionExpiredBanner() {
|
|
@@ -1856,13 +1912,13 @@ function SessionExpiredBanner() {
|
|
|
1856
1912
|
localStorage.setItem(DISMISS_KEY, String(Date.now() + DISMISS_TTL_MS));
|
|
1857
1913
|
setShow(false);
|
|
1858
1914
|
}
|
|
1859
|
-
return /* @__PURE__ */ (0,
|
|
1860
|
-
/* @__PURE__ */ (0,
|
|
1861
|
-
/* @__PURE__ */ (0,
|
|
1915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "alert", className: "fixed top-0 inset-x-0 bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 text-sm shadow", style: { zIndex: 10001 }, children: [
|
|
1916
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
|
|
1917
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Sua sess\xE3o expirou." }),
|
|
1862
1918
|
" Fa\xE7a login novamente para continuar."
|
|
1863
1919
|
] }),
|
|
1864
|
-
/* @__PURE__ */ (0,
|
|
1865
|
-
/* @__PURE__ */ (0,
|
|
1920
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1866
1922
|
"button",
|
|
1867
1923
|
{
|
|
1868
1924
|
type: "button",
|
|
@@ -1871,7 +1927,7 @@ function SessionExpiredBanner() {
|
|
|
1871
1927
|
children: "Fazer login"
|
|
1872
1928
|
}
|
|
1873
1929
|
),
|
|
1874
|
-
/* @__PURE__ */ (0,
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1875
1931
|
"button",
|
|
1876
1932
|
{
|
|
1877
1933
|
type: "button",
|
|
@@ -1887,7 +1943,7 @@ function SessionExpiredBanner() {
|
|
|
1887
1943
|
|
|
1888
1944
|
// src/defaults/ErrorBoundary.tsx
|
|
1889
1945
|
var import_react10 = require("react");
|
|
1890
|
-
var
|
|
1946
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1891
1947
|
var ErrorBoundary = class extends import_react10.Component {
|
|
1892
1948
|
state = { error: null };
|
|
1893
1949
|
static getDerivedStateFromError(error) {
|
|
@@ -1905,28 +1961,32 @@ var ErrorBoundary = class extends import_react10.Component {
|
|
|
1905
1961
|
}
|
|
1906
1962
|
render() {
|
|
1907
1963
|
if (this.state.error) {
|
|
1908
|
-
return this.props.fallback ?? /* @__PURE__ */ (0,
|
|
1909
|
-
/* @__PURE__ */ (0,
|
|
1910
|
-
/* @__PURE__ */ (0,
|
|
1964
|
+
return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
|
|
1965
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { children: "Algo deu errado" }),
|
|
1966
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
|
|
1911
1967
|
] });
|
|
1912
1968
|
}
|
|
1913
|
-
return /* @__PURE__ */ (0,
|
|
1969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: this.props.children });
|
|
1914
1970
|
}
|
|
1915
1971
|
};
|
|
1916
1972
|
|
|
1917
1973
|
// src/internal/PaymentReturnHandler.tsx
|
|
1918
1974
|
var import_react11 = require("react");
|
|
1919
1975
|
var import_sdk4 = require("@hook-sdk/sdk");
|
|
1920
|
-
var
|
|
1976
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1921
1977
|
var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
|
|
1978
|
+
var MAX_CYCLES = 3;
|
|
1979
|
+
var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
|
|
1922
1980
|
function PaymentReturnHandler({ children }) {
|
|
1923
1981
|
const { subscription } = (0, import_sdk4.useHook)();
|
|
1924
1982
|
const subRef = (0, import_react11.useRef)(subscription);
|
|
1925
1983
|
subRef.current = subscription;
|
|
1926
1984
|
const runIdRef = (0, import_react11.useRef)(0);
|
|
1985
|
+
const cyclesRef = (0, import_react11.useRef)(0);
|
|
1927
1986
|
const [state, setState] = (0, import_react11.useState)("idle");
|
|
1928
1987
|
const runPoll = (0, import_react11.useCallback)(() => {
|
|
1929
1988
|
const runId = ++runIdRef.current;
|
|
1989
|
+
cyclesRef.current += 1;
|
|
1930
1990
|
setState("confirming");
|
|
1931
1991
|
let attempts = 0;
|
|
1932
1992
|
const tick = async () => {
|
|
@@ -1942,12 +2002,17 @@ function PaymentReturnHandler({ children }) {
|
|
|
1942
2002
|
const cleanUrl = new URL(window.location.href);
|
|
1943
2003
|
cleanUrl.searchParams.delete("paymentReturn");
|
|
1944
2004
|
window.history.replaceState({}, "", cleanUrl.toString());
|
|
2005
|
+
cyclesRef.current = 0;
|
|
1945
2006
|
setState("idle");
|
|
1946
2007
|
return;
|
|
1947
2008
|
}
|
|
1948
2009
|
const delay = BACKOFF_MS[attempts - 1];
|
|
1949
2010
|
if (delay === void 0) {
|
|
1950
|
-
|
|
2011
|
+
if (cyclesRef.current >= MAX_CYCLES) {
|
|
2012
|
+
setState("timeout");
|
|
2013
|
+
} else {
|
|
2014
|
+
setState("waiting");
|
|
2015
|
+
}
|
|
1951
2016
|
return;
|
|
1952
2017
|
}
|
|
1953
2018
|
setTimeout(tick, delay);
|
|
@@ -1958,21 +2023,67 @@ function PaymentReturnHandler({ children }) {
|
|
|
1958
2023
|
if (typeof window === "undefined") return;
|
|
1959
2024
|
const url = new URL(window.location.href);
|
|
1960
2025
|
if (url.searchParams.get("paymentReturn") !== "1") return;
|
|
2026
|
+
cyclesRef.current = 0;
|
|
1961
2027
|
runPoll();
|
|
1962
2028
|
return () => {
|
|
1963
2029
|
runIdRef.current++;
|
|
1964
2030
|
};
|
|
1965
2031
|
}, [runPoll]);
|
|
2032
|
+
const goHome = (0, import_react11.useCallback)(() => {
|
|
2033
|
+
const cleanUrl = new URL(window.location.href);
|
|
2034
|
+
cleanUrl.searchParams.delete("paymentReturn");
|
|
2035
|
+
cleanUrl.pathname = "/app/home";
|
|
2036
|
+
window.location.href = cleanUrl.toString();
|
|
2037
|
+
}, []);
|
|
1966
2038
|
if (state === "confirming") {
|
|
1967
|
-
return /* @__PURE__ */ (0,
|
|
2039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
|
|
1968
2040
|
}
|
|
1969
2041
|
if (state === "waiting") {
|
|
1970
|
-
return /* @__PURE__ */ (0,
|
|
1971
|
-
/* @__PURE__ */ (0,
|
|
1972
|
-
/* @__PURE__ */ (0,
|
|
2042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2043
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
|
|
2044
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
|
|
2045
|
+
] }) });
|
|
2046
|
+
}
|
|
2047
|
+
if (state === "timeout") {
|
|
2048
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
|
|
2049
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
|
|
2050
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2052
|
+
"button",
|
|
2053
|
+
{
|
|
2054
|
+
type: "button",
|
|
2055
|
+
onClick: () => {
|
|
2056
|
+
cyclesRef.current = 0;
|
|
2057
|
+
runPoll();
|
|
2058
|
+
},
|
|
2059
|
+
style: buttonStyle,
|
|
2060
|
+
"data-testid": "payment-timeout-retry",
|
|
2061
|
+
children: "Tentar de novo"
|
|
2062
|
+
}
|
|
2063
|
+
),
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2065
|
+
"button",
|
|
2066
|
+
{
|
|
2067
|
+
type: "button",
|
|
2068
|
+
onClick: goHome,
|
|
2069
|
+
style: secondaryButtonStyle,
|
|
2070
|
+
"data-testid": "payment-timeout-home",
|
|
2071
|
+
children: "Voltar pro app"
|
|
2072
|
+
}
|
|
2073
|
+
),
|
|
2074
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2075
|
+
"a",
|
|
2076
|
+
{
|
|
2077
|
+
href: SUPPORT_MAILTO,
|
|
2078
|
+
style: linkStyle,
|
|
2079
|
+
"data-testid": "payment-timeout-support",
|
|
2080
|
+
children: "Falar com suporte"
|
|
2081
|
+
}
|
|
2082
|
+
)
|
|
2083
|
+
] })
|
|
1973
2084
|
] }) });
|
|
1974
2085
|
}
|
|
1975
|
-
return /* @__PURE__ */ (0,
|
|
2086
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
|
|
1976
2087
|
}
|
|
1977
2088
|
var overlayStyle2 = {
|
|
1978
2089
|
position: "fixed",
|
|
@@ -1996,9 +2107,22 @@ var buttonStyle = {
|
|
|
1996
2107
|
fontWeight: 600,
|
|
1997
2108
|
cursor: "pointer"
|
|
1998
2109
|
};
|
|
2110
|
+
var secondaryButtonStyle = {
|
|
2111
|
+
...buttonStyle,
|
|
2112
|
+
background: "transparent",
|
|
2113
|
+
color: "white",
|
|
2114
|
+
border: "1px solid rgba(255,255,255,0.5)"
|
|
2115
|
+
};
|
|
2116
|
+
var linkStyle = {
|
|
2117
|
+
color: "white",
|
|
2118
|
+
textDecoration: "underline",
|
|
2119
|
+
fontSize: "0.9rem",
|
|
2120
|
+
marginTop: 4,
|
|
2121
|
+
textAlign: "center"
|
|
2122
|
+
};
|
|
1999
2123
|
|
|
2000
2124
|
// src/AppRoot.tsx
|
|
2001
|
-
var
|
|
2125
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2002
2126
|
function buildLegacyConfigShim(config) {
|
|
2003
2127
|
const paywall = config.paywall;
|
|
2004
2128
|
const isFree = paywall.mode === "free";
|
|
@@ -2008,7 +2132,16 @@ function buildLegacyConfigShim(config) {
|
|
|
2008
2132
|
slug: config.slug,
|
|
2009
2133
|
name: config.name,
|
|
2010
2134
|
email_alias: config.slug,
|
|
2011
|
-
theme
|
|
2135
|
+
// Map branding into the legacy theme shape so InstallSplash (and
|
|
2136
|
+
// anything else reading theme.icon_url / theme.logo_url) can surface
|
|
2137
|
+
// the app icon instead of the generic "first letter of name" fallback.
|
|
2138
|
+
// Falls back to logoUrl when iconUrl is unset — apps that haven't
|
|
2139
|
+
// adopted iconUrl keep their previous behavior unchanged.
|
|
2140
|
+
theme: {
|
|
2141
|
+
primary_color: config.branding.primaryColor,
|
|
2142
|
+
icon_url: config.branding.iconUrl ?? config.branding.logoUrl,
|
|
2143
|
+
logo_url: config.branding.logoUrl
|
|
2144
|
+
},
|
|
2012
2145
|
features_enabled: config.features_enabled ?? [],
|
|
2013
2146
|
dependencies_allowlist: ["react", "react-dom"],
|
|
2014
2147
|
subscription: {
|
|
@@ -2066,10 +2199,10 @@ function AppRoot(props) {
|
|
|
2066
2199
|
const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
|
|
2067
2200
|
const basename = `/app/${config.slug}`;
|
|
2068
2201
|
const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
|
|
2069
|
-
return /* @__PURE__ */ (0,
|
|
2070
|
-
/* @__PURE__ */ (0,
|
|
2071
|
-
/* @__PURE__ */ (0,
|
|
2072
|
-
/* @__PURE__ */ (0,
|
|
2202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Router, { ...routerProps, children: [
|
|
2203
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
|
|
2204
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SessionExpiredBanner, {}),
|
|
2205
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2073
2206
|
AuthGated,
|
|
2074
2207
|
{
|
|
2075
2208
|
config,
|
|
@@ -2081,9 +2214,9 @@ function AppRoot(props) {
|
|
|
2081
2214
|
Paywall,
|
|
2082
2215
|
Onboarding,
|
|
2083
2216
|
PreAuthFlow,
|
|
2084
|
-
children: /* @__PURE__ */ (0,
|
|
2217
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
|
|
2085
2218
|
children,
|
|
2086
|
-
/* @__PURE__ */ (0,
|
|
2219
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PushPrompt, {})
|
|
2087
2220
|
] })
|
|
2088
2221
|
}
|
|
2089
2222
|
) })
|
|
@@ -2103,25 +2236,25 @@ function AuthGated({
|
|
|
2103
2236
|
if (authStatus === "loading") return null;
|
|
2104
2237
|
if (authStatus !== "authenticated") {
|
|
2105
2238
|
if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
|
|
2106
|
-
return /* @__PURE__ */ (0,
|
|
2107
|
-
/* @__PURE__ */ (0,
|
|
2108
|
-
/* @__PURE__ */ (0,
|
|
2109
|
-
/* @__PURE__ */ (0,
|
|
2110
|
-
/* @__PURE__ */ (0,
|
|
2111
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2112
|
-
/* @__PURE__ */ (0,
|
|
2239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
|
|
2241
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
|
|
2244
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
|
|
2245
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PreAuthFlow, {}) })
|
|
2113
2246
|
] });
|
|
2114
2247
|
}
|
|
2115
|
-
return /* @__PURE__ */ (0,
|
|
2116
|
-
/* @__PURE__ */ (0,
|
|
2117
|
-
/* @__PURE__ */ (0,
|
|
2118
|
-
/* @__PURE__ */ (0,
|
|
2119
|
-
/* @__PURE__ */ (0,
|
|
2120
|
-
EmailVerify ? /* @__PURE__ */ (0,
|
|
2121
|
-
/* @__PURE__ */ (0,
|
|
2248
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
|
|
2250
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
|
|
2251
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
|
|
2252
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
|
|
2253
|
+
EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
|
|
2254
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
|
|
2122
2255
|
] });
|
|
2123
2256
|
}
|
|
2124
|
-
return /* @__PURE__ */ (0,
|
|
2257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
|
|
2125
2258
|
}
|
|
2126
2259
|
function FallbackPaywall() {
|
|
2127
2260
|
return null;
|
|
@@ -2212,7 +2345,7 @@ function usePush() {
|
|
|
2212
2345
|
}
|
|
2213
2346
|
|
|
2214
2347
|
// src/components/PushPrompt.tsx
|
|
2215
|
-
var
|
|
2348
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2216
2349
|
function platformRecoveryCopy(texts) {
|
|
2217
2350
|
if (typeof navigator === "undefined") return null;
|
|
2218
2351
|
const ua = navigator.userAgent || "";
|
|
@@ -2235,28 +2368,28 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2235
2368
|
const { state, subscribe } = usePush();
|
|
2236
2369
|
if (state.kind === "subscribed" || state.kind === "dismissed") return null;
|
|
2237
2370
|
if (state.kind === "ios_needs_install") {
|
|
2238
|
-
return /* @__PURE__ */ (0,
|
|
2239
|
-
/* @__PURE__ */ (0,
|
|
2240
|
-
/* @__PURE__ */ (0,
|
|
2241
|
-
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0,
|
|
2371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.iosInstallTitle }),
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.iosInstallBody }),
|
|
2374
|
+
onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
|
|
2242
2375
|
] });
|
|
2243
2376
|
}
|
|
2244
2377
|
if (state.kind === "denied") {
|
|
2245
2378
|
const recovery = platformRecoveryCopy(texts);
|
|
2246
|
-
return /* @__PURE__ */ (0,
|
|
2247
|
-
/* @__PURE__ */ (0,
|
|
2248
|
-
/* @__PURE__ */ (0,
|
|
2249
|
-
recovery && /* @__PURE__ */ (0,
|
|
2379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.deniedTitle }),
|
|
2381
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.deniedBody }),
|
|
2382
|
+
recovery && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
|
|
2250
2383
|
] });
|
|
2251
2384
|
}
|
|
2252
2385
|
if (state.kind === "unsupported") {
|
|
2253
|
-
return /* @__PURE__ */ (0,
|
|
2386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.unsupportedBody }) });
|
|
2254
2387
|
}
|
|
2255
2388
|
if (state.kind === "error") {
|
|
2256
|
-
return /* @__PURE__ */ (0,
|
|
2389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: state.message }) });
|
|
2257
2390
|
}
|
|
2258
|
-
return /* @__PURE__ */ (0,
|
|
2259
|
-
/* @__PURE__ */ (0,
|
|
2391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", children: [
|
|
2392
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2260
2393
|
"button",
|
|
2261
2394
|
{
|
|
2262
2395
|
type: "button",
|
|
@@ -2270,23 +2403,23 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
|
|
|
2270
2403
|
children: texts.cta
|
|
2271
2404
|
}
|
|
2272
2405
|
),
|
|
2273
|
-
onDeclined && /* @__PURE__ */ (0,
|
|
2406
|
+
onDeclined && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
|
|
2274
2407
|
] });
|
|
2275
2408
|
}
|
|
2276
2409
|
|
|
2277
2410
|
// src/defaults/LoadingState.tsx
|
|
2278
|
-
var
|
|
2411
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2279
2412
|
function LoadingState({ message }) {
|
|
2280
|
-
return /* @__PURE__ */ (0,
|
|
2413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: message ?? "Carregando..." }) });
|
|
2281
2414
|
}
|
|
2282
2415
|
|
|
2283
2416
|
// src/defaults/EmptyState.tsx
|
|
2284
|
-
var
|
|
2417
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2285
2418
|
function EmptyState({ title, description, action }) {
|
|
2286
|
-
return /* @__PURE__ */ (0,
|
|
2287
|
-
/* @__PURE__ */ (0,
|
|
2288
|
-
description && /* @__PURE__ */ (0,
|
|
2289
|
-
action && /* @__PURE__ */ (0,
|
|
2419
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
|
|
2421
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: description }),
|
|
2422
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: 16 }, children: action })
|
|
2290
2423
|
] });
|
|
2291
2424
|
}
|
|
2292
2425
|
|
|
@@ -2332,18 +2465,24 @@ function useLoginForm() {
|
|
|
2332
2465
|
const [password, setPassword] = (0, import_react14.useState)("");
|
|
2333
2466
|
const [submitting, setSubmitting] = (0, import_react14.useState)(false);
|
|
2334
2467
|
const [error, setError] = (0, import_react14.useState)(null);
|
|
2335
|
-
const
|
|
2468
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react14.useState)(false);
|
|
2469
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react14.useState)(false);
|
|
2470
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react14.useState)(false);
|
|
2471
|
+
const validateEmail = (0, import_react14.useMemo)(() => {
|
|
2336
2472
|
if (email.length === 0) return null;
|
|
2337
2473
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2338
2474
|
return null;
|
|
2339
2475
|
}, [email]);
|
|
2340
|
-
const
|
|
2476
|
+
const validatePassword = (0, import_react14.useMemo)(() => {
|
|
2341
2477
|
if (password.length === 0) return null;
|
|
2342
2478
|
if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
|
|
2343
2479
|
return null;
|
|
2344
2480
|
}, [password]);
|
|
2345
|
-
const
|
|
2481
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2482
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2483
|
+
const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
|
|
2346
2484
|
const submit = (0, import_react14.useCallback)(async () => {
|
|
2485
|
+
setFormSubmitAttempted(true);
|
|
2347
2486
|
if (!canSubmit) return false;
|
|
2348
2487
|
setSubmitting(true);
|
|
2349
2488
|
setError(null);
|
|
@@ -2361,9 +2500,12 @@ function useLoginForm() {
|
|
|
2361
2500
|
email,
|
|
2362
2501
|
setEmail,
|
|
2363
2502
|
emailError,
|
|
2503
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
2364
2504
|
password,
|
|
2365
2505
|
setPassword,
|
|
2366
2506
|
passwordError,
|
|
2507
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
2508
|
+
formSubmitAttempted,
|
|
2367
2509
|
submit,
|
|
2368
2510
|
submitting,
|
|
2369
2511
|
canSubmit,
|
|
@@ -2384,23 +2526,31 @@ function useSignupForm() {
|
|
|
2384
2526
|
const [password, setPassword] = (0, import_react15.useState)("");
|
|
2385
2527
|
const [submitting, setSubmitting] = (0, import_react15.useState)(false);
|
|
2386
2528
|
const [error, setError] = (0, import_react15.useState)(null);
|
|
2387
|
-
const
|
|
2529
|
+
const [touchedName, setTouchedName] = (0, import_react15.useState)(false);
|
|
2530
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
|
|
2531
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
|
|
2532
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
|
|
2533
|
+
const validateName = (0, import_react15.useMemo)(() => {
|
|
2388
2534
|
if (name.length === 0) return null;
|
|
2389
2535
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
2390
2536
|
return null;
|
|
2391
2537
|
}, [name]);
|
|
2392
|
-
const
|
|
2538
|
+
const validateEmail = (0, import_react15.useMemo)(() => {
|
|
2393
2539
|
if (email.length === 0) return null;
|
|
2394
2540
|
if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2395
2541
|
return null;
|
|
2396
2542
|
}, [email]);
|
|
2397
|
-
const
|
|
2543
|
+
const validatePassword = (0, import_react15.useMemo)(() => {
|
|
2398
2544
|
if (password.length === 0) return null;
|
|
2399
2545
|
if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
|
|
2400
2546
|
return null;
|
|
2401
2547
|
}, [password]);
|
|
2402
|
-
const
|
|
2548
|
+
const nameError = touchedName || formSubmitAttempted ? validateName : null;
|
|
2549
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2550
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2551
|
+
const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
|
|
2403
2552
|
const submit = (0, import_react15.useCallback)(async () => {
|
|
2553
|
+
setFormSubmitAttempted(true);
|
|
2404
2554
|
if (!canSubmit) return false;
|
|
2405
2555
|
setSubmitting(true);
|
|
2406
2556
|
setError(null);
|
|
@@ -2418,12 +2568,16 @@ function useSignupForm() {
|
|
|
2418
2568
|
name,
|
|
2419
2569
|
setName,
|
|
2420
2570
|
nameError,
|
|
2571
|
+
markNameTouched: () => setTouchedName(true),
|
|
2421
2572
|
email,
|
|
2422
2573
|
setEmail,
|
|
2423
2574
|
emailError,
|
|
2575
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
2424
2576
|
password,
|
|
2425
2577
|
setPassword,
|
|
2426
2578
|
passwordError,
|
|
2579
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
2580
|
+
formSubmitAttempted,
|
|
2427
2581
|
submit,
|
|
2428
2582
|
submitting,
|
|
2429
2583
|
canSubmit,
|
|
@@ -2442,13 +2596,17 @@ function useForgotForm() {
|
|
|
2442
2596
|
const [submitting, setSubmitting] = (0, import_react16.useState)(false);
|
|
2443
2597
|
const [sent, setSent] = (0, import_react16.useState)(false);
|
|
2444
2598
|
const [error, setError] = (0, import_react16.useState)(null);
|
|
2445
|
-
const
|
|
2599
|
+
const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
|
|
2600
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
|
|
2601
|
+
const validateEmail = (0, import_react16.useMemo)(() => {
|
|
2446
2602
|
if (email.length === 0) return null;
|
|
2447
2603
|
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
2448
2604
|
return null;
|
|
2449
2605
|
}, [email]);
|
|
2450
|
-
const
|
|
2606
|
+
const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
|
|
2607
|
+
const canSubmit = email.length > 0 && validateEmail === null && !submitting;
|
|
2451
2608
|
const submit = (0, import_react16.useCallback)(async () => {
|
|
2609
|
+
setFormSubmitAttempted(true);
|
|
2452
2610
|
if (!canSubmit) return false;
|
|
2453
2611
|
setSubmitting(true);
|
|
2454
2612
|
setError(null);
|
|
@@ -2467,6 +2625,8 @@ function useForgotForm() {
|
|
|
2467
2625
|
email,
|
|
2468
2626
|
setEmail,
|
|
2469
2627
|
emailError,
|
|
2628
|
+
markEmailTouched: () => setTouchedEmail(true),
|
|
2629
|
+
formSubmitAttempted,
|
|
2470
2630
|
submit,
|
|
2471
2631
|
submitting,
|
|
2472
2632
|
canSubmit,
|
|
@@ -2487,24 +2647,30 @@ function useResetForm() {
|
|
|
2487
2647
|
const [submitting, setSubmitting] = (0, import_react17.useState)(false);
|
|
2488
2648
|
const [done, setDone] = (0, import_react17.useState)(false);
|
|
2489
2649
|
const [error, setError] = (0, import_react17.useState)(null);
|
|
2650
|
+
const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
|
|
2651
|
+
const [touchedConfirm, setTouchedConfirm] = (0, import_react17.useState)(false);
|
|
2652
|
+
const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
|
|
2490
2653
|
(0, import_react17.useEffect)(() => {
|
|
2491
2654
|
if (typeof window === "undefined") return;
|
|
2492
2655
|
const params = new URLSearchParams(window.location.search);
|
|
2493
2656
|
const t = params.get("token");
|
|
2494
2657
|
setToken(t && t.length > 0 ? t : null);
|
|
2495
2658
|
}, []);
|
|
2496
|
-
const
|
|
2659
|
+
const validatePassword = (0, import_react17.useMemo)(() => {
|
|
2497
2660
|
if (password.length === 0) return null;
|
|
2498
2661
|
if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
|
|
2499
2662
|
return null;
|
|
2500
2663
|
}, [password]);
|
|
2501
|
-
const
|
|
2664
|
+
const validateConfirm = (0, import_react17.useMemo)(() => {
|
|
2502
2665
|
if (confirm.length === 0) return null;
|
|
2503
2666
|
if (confirm !== password) return "Senhas n\xE3o coincidem.";
|
|
2504
2667
|
return null;
|
|
2505
2668
|
}, [confirm, password]);
|
|
2506
|
-
const
|
|
2669
|
+
const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
|
|
2670
|
+
const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
|
|
2671
|
+
const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
|
|
2507
2672
|
const submit = (0, import_react17.useCallback)(async () => {
|
|
2673
|
+
setFormSubmitAttempted(true);
|
|
2508
2674
|
if (!canSubmit || token === null) return;
|
|
2509
2675
|
setSubmitting(true);
|
|
2510
2676
|
setError(null);
|
|
@@ -2528,9 +2694,12 @@ function useResetForm() {
|
|
|
2528
2694
|
password,
|
|
2529
2695
|
setPassword,
|
|
2530
2696
|
passwordError,
|
|
2697
|
+
markPasswordTouched: () => setTouchedPassword(true),
|
|
2531
2698
|
confirm,
|
|
2532
2699
|
setConfirm,
|
|
2533
2700
|
confirmError,
|
|
2701
|
+
markConfirmTouched: () => setTouchedConfirm(true),
|
|
2702
|
+
formSubmitAttempted,
|
|
2534
2703
|
submit,
|
|
2535
2704
|
submitting,
|
|
2536
2705
|
canSubmit,
|
|
@@ -2677,20 +2846,20 @@ function useToast() {
|
|
|
2677
2846
|
|
|
2678
2847
|
// src/RouteBoundary.tsx
|
|
2679
2848
|
var import_react_router_dom3 = require("react-router-dom");
|
|
2680
|
-
var
|
|
2849
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2681
2850
|
function RouteBoundary({ children }) {
|
|
2682
|
-
return /* @__PURE__ */ (0,
|
|
2851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_router_dom3.Routes, { children: [
|
|
2683
2852
|
children,
|
|
2684
|
-
/* @__PURE__ */ (0,
|
|
2853
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DefaultNotFound, {}) })
|
|
2685
2854
|
] });
|
|
2686
2855
|
}
|
|
2687
2856
|
function DefaultNotFound() {
|
|
2688
|
-
return /* @__PURE__ */ (0,
|
|
2857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
|
|
2689
2858
|
}
|
|
2690
2859
|
|
|
2691
2860
|
// src/PreAuthShell.tsx
|
|
2692
2861
|
var import_react_router_dom4 = require("react-router-dom");
|
|
2693
|
-
var
|
|
2862
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2694
2863
|
function PreAuthShell({
|
|
2695
2864
|
basename,
|
|
2696
2865
|
testRouter,
|
|
@@ -2698,9 +2867,9 @@ function PreAuthShell({
|
|
|
2698
2867
|
children
|
|
2699
2868
|
}) {
|
|
2700
2869
|
if (testRouter === "memory") {
|
|
2701
|
-
return /* @__PURE__ */ (0,
|
|
2870
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2702
2871
|
}
|
|
2703
|
-
return /* @__PURE__ */ (0,
|
|
2872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.Routes, { children }) });
|
|
2704
2873
|
}
|
|
2705
2874
|
|
|
2706
2875
|
// src/OnboardingFlow.tsx
|
|
@@ -2721,7 +2890,7 @@ function useOnboardingStep() {
|
|
|
2721
2890
|
}
|
|
2722
2891
|
|
|
2723
2892
|
// src/OnboardingFlow.tsx
|
|
2724
|
-
var
|
|
2893
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2725
2894
|
var isFilled = (v) => v != null && v !== "";
|
|
2726
2895
|
var CURRENT_STEP_FIELD = "currentStep";
|
|
2727
2896
|
function readPersistedStepIdx(draft) {
|
|
@@ -2799,7 +2968,7 @@ function OnboardingFlow({
|
|
|
2799
2968
|
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
2800
2969
|
);
|
|
2801
2970
|
}
|
|
2802
|
-
return /* @__PURE__ */ (0,
|
|
2971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Screen, {}) });
|
|
2803
2972
|
}
|
|
2804
2973
|
|
|
2805
2974
|
// src/hooks/useFeature.ts
|