@wral/report-it 0.1.3 → 0.1.4
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { css as f, html as a, nothing as c, LitElement as
|
|
2
|
-
import { getAuthContext as
|
|
3
|
-
const
|
|
1
|
+
import { css as f, html as a, nothing as c, LitElement as T } from "lit";
|
|
2
|
+
import { getAuthContext as Q, createStorage as G, verifyCode as J, extractTokens as D, saveTokens as z, decodeJwtPayload as B, refreshTokenSimple as X, sendCode as Z, createUserPool as ee, signUpIfNeeded as te, createCognitoUser as re, getAuthHeaders as se, STORAGE_KEYS as I, isAuthenticatedSimple as ie } from "@wral/sdk-auth-audience";
|
|
3
|
+
const ne = f`
|
|
4
4
|
:host {
|
|
5
5
|
display: block;
|
|
6
6
|
box-sizing: border-box;
|
|
@@ -24,7 +24,7 @@ const se = f`
|
|
|
24
24
|
position: absolute; width: 1px; height: 1px; overflow: hidden;
|
|
25
25
|
clip: rect(0 0 0 0); white-space: nowrap;
|
|
26
26
|
}
|
|
27
|
-
`,
|
|
27
|
+
`, ae = f`
|
|
28
28
|
@keyframes pop-in {
|
|
29
29
|
0% { opacity: 0; transform: translateY(16px) scale(0.95); }
|
|
30
30
|
100% { opacity: 1; transform: translateY(0) scale(1); }
|
|
@@ -55,7 +55,7 @@ const se = f`
|
|
|
55
55
|
animation: none !important;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
`,
|
|
58
|
+
`, oe = f`
|
|
59
59
|
.msg { max-width: 85%; padding: 12px 16px; border-radius: 14px; font-size: 15px; }
|
|
60
60
|
.msg.bot {
|
|
61
61
|
background: var(--wral-semantic-surface-default, #FFFFFF);
|
|
@@ -77,7 +77,7 @@ const se = f`
|
|
|
77
77
|
.msg .sub { display: block; font-size: 13px; color: var(--wral-semantic-fg-muted, #64748B); margin-top: 4px; }
|
|
78
78
|
.msg.user .sub { color: rgba(255, 255, 255, 0.75); }
|
|
79
79
|
.msg.error { border-left: 3px solid var(--wral-base-red-on-light, #D1232A); }
|
|
80
|
-
`,
|
|
80
|
+
`, le = f`
|
|
81
81
|
.options { display: flex; flex-wrap: wrap; gap: 8px; align-self: flex-start; max-width: 92%; padding: 2px 0 6px; }
|
|
82
82
|
.chip {
|
|
83
83
|
font-family: var(--wral-base-font-ui, 'IBM Plex Sans Condensed', sans-serif);
|
|
@@ -91,7 +91,7 @@ const se = f`
|
|
|
91
91
|
.chip:hover { background: var(--wral-base-secondary-1, #2594E3); color: #FFFFFF; }
|
|
92
92
|
.chip:focus-visible { outline: 2px solid var(--wral-base-secondary-1, #2594E3); outline-offset: 2px; }
|
|
93
93
|
.chip:active { transform: scale(0.97); }
|
|
94
|
-
`,
|
|
94
|
+
`, de = f`
|
|
95
95
|
.form-card {
|
|
96
96
|
align-self: stretch;
|
|
97
97
|
background: var(--wral-semantic-surface-default, #FFFFFF);
|
|
@@ -156,7 +156,7 @@ const se = f`
|
|
|
156
156
|
.btn-ghost:hover { border-color: var(--wral-base-secondary-1, #2594E3); }
|
|
157
157
|
.btn-ghost:active { transform: scale(0.97); }
|
|
158
158
|
.btn-ghost:focus-visible { outline: 2px solid var(--wral-base-secondary-1, #2594E3); outline-offset: 2px; }
|
|
159
|
-
`,
|
|
159
|
+
`, ce = f`
|
|
160
160
|
.login-card { padding: 28px 26px; }
|
|
161
161
|
.login-card h2 {
|
|
162
162
|
font-family: var(--wral-base-font-display, 'IBM Plex Sans Condensed', sans-serif);
|
|
@@ -243,7 +243,7 @@ const se = f`
|
|
|
243
243
|
.anon-costs .x { flex-shrink: 0; font-weight: 700; color: var(--wral-base-red-on-light, #D1232A); }
|
|
244
244
|
.anon-actions { display: flex; flex-direction: column; gap: 10px; }
|
|
245
245
|
.anon-actions .btn-ghost { width: 100%; }
|
|
246
|
-
`,
|
|
246
|
+
`, ue = f`
|
|
247
247
|
.review-list { margin: 0; padding: 0; list-style: none; font-size: 14px; }
|
|
248
248
|
.review-list li {
|
|
249
249
|
display: grid; grid-template-columns: 130px 1fr; gap: 10px;
|
|
@@ -275,7 +275,7 @@ const se = f`
|
|
|
275
275
|
color: var(--wral-base-primary-1, #001D68);
|
|
276
276
|
}
|
|
277
277
|
@media (max-width: 540px) { .review-list li { grid-template-columns: 1fr; gap: 2px; } }
|
|
278
|
-
`,
|
|
278
|
+
`, pe = f`
|
|
279
279
|
.upload-row { display: flex; align-items: center; gap: 10px; padding: 7px 0; font-size: 13.5px; }
|
|
280
280
|
.upload-row .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
281
281
|
.upload-row .state { font-size: 12px; color: var(--wral-semantic-fg-subtle, #64748B); }
|
|
@@ -291,7 +291,7 @@ const se = f`
|
|
|
291
291
|
border-radius: 999px; padding: 3px 12px; cursor: pointer;
|
|
292
292
|
}
|
|
293
293
|
.retry-chip:focus-visible { outline: 2px solid var(--wral-base-secondary-1, #2594E3); outline-offset: 2px; }
|
|
294
|
-
`,
|
|
294
|
+
`, he = f`
|
|
295
295
|
.confirm-card {
|
|
296
296
|
align-self: stretch;
|
|
297
297
|
background: var(--wral-base-primary-1, #001D68);
|
|
@@ -341,7 +341,7 @@ const se = f`
|
|
|
341
341
|
.c-again:hover { background: rgba(255, 255, 255, 0.12); }
|
|
342
342
|
.c-again:focus-visible { outline: 2px solid var(--wral-base-secondary-2, #50A9E8); outline-offset: 2px; }
|
|
343
343
|
.c-again:active { transform: scale(0.97); }
|
|
344
|
-
`,
|
|
344
|
+
`, fe = f`
|
|
345
345
|
.journey {
|
|
346
346
|
align-self: stretch;
|
|
347
347
|
background: var(--wral-semantic-surface-default, #FFFFFF);
|
|
@@ -382,7 +382,7 @@ const se = f`
|
|
|
382
382
|
color: var(--wral-base-primary-1, #001D68); margin-bottom: 2px;
|
|
383
383
|
}
|
|
384
384
|
.j-body .j-d { font-size: 13.5px; color: var(--wral-semantic-fg-muted, #475569); line-height: 1.55; }
|
|
385
|
-
`,
|
|
385
|
+
`, ge = f`
|
|
386
386
|
.bottom-bar {
|
|
387
387
|
position: sticky; bottom: 0; z-index: 20;
|
|
388
388
|
background: var(--wral-semantic-surface-default, #FFFFFF);
|
|
@@ -395,7 +395,7 @@ const se = f`
|
|
|
395
395
|
}
|
|
396
396
|
.bottom-bar .note { margin-left: auto; font-size: 12px; color: var(--wral-semantic-fg-subtle, #64748B); }
|
|
397
397
|
@media (max-width: 540px) { .bottom-bar .note { display: none; } }
|
|
398
|
-
`,
|
|
398
|
+
`, me = [ne, ae, oe, le, de, ce, ue, pe, he, fe, ge];
|
|
399
399
|
function h(r, e, { noAnim: t = !1, error: s = !1 } = {}) {
|
|
400
400
|
return a`
|
|
401
401
|
<div class="msg bot ${t ? "no-anim" : ""} ${s ? "error" : ""}">
|
|
@@ -404,63 +404,65 @@ function h(r, e, { noAnim: t = !1, error: s = !1 } = {}) {
|
|
|
404
404
|
</div>
|
|
405
405
|
`;
|
|
406
406
|
}
|
|
407
|
-
function
|
|
407
|
+
function $(r, { noAnim: e = !1 } = {}) {
|
|
408
408
|
return a`<div class="msg user ${e ? "no-anim" : ""}">${r}</div>`;
|
|
409
409
|
}
|
|
410
|
-
function
|
|
410
|
+
function E() {
|
|
411
411
|
return a`<div class="msg bot typing"><span></span><span></span><span></span></div>`;
|
|
412
412
|
}
|
|
413
|
-
function
|
|
413
|
+
function be(r) {
|
|
414
414
|
return r ? a`<span class="flag-pill ${r}">${r === "urgent" ? "Urgent" : "Moderate"}</span>` : c;
|
|
415
415
|
}
|
|
416
|
-
function
|
|
416
|
+
function ye() {
|
|
417
417
|
return a`
|
|
418
418
|
<svg viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="3"
|
|
419
419
|
stroke-linecap="round" stroke-linejoin="round" width="20" height="20"
|
|
420
420
|
aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
421
421
|
`;
|
|
422
422
|
}
|
|
423
|
-
|
|
423
|
+
const we = 15e3;
|
|
424
|
+
class x extends Error {
|
|
424
425
|
constructor(e, t) {
|
|
425
426
|
super(`api-forms request failed with status ${e}`), this.status = e, this.body = t;
|
|
426
427
|
}
|
|
427
428
|
}
|
|
428
|
-
const
|
|
429
|
-
function
|
|
429
|
+
const P = Object.freeze({ enabled: !1, humanCheck: null });
|
|
430
|
+
function xe({
|
|
430
431
|
baseUrl: r,
|
|
431
432
|
fetchFn: e = (...i) => fetch(...i),
|
|
432
433
|
xhrFactory: t = () => new XMLHttpRequest(),
|
|
433
434
|
getAuthHeaders: s
|
|
434
435
|
}) {
|
|
435
436
|
const i = String(r || "").replace(/\/+$/, "");
|
|
436
|
-
let n =
|
|
437
|
-
async function l(d, { method: u = "GET", body: g, auth:
|
|
438
|
-
const
|
|
439
|
-
|
|
437
|
+
let n = P, o = null;
|
|
438
|
+
async function l(d, { method: u = "GET", body: g, auth: y = !1, timeoutMs: p } = {}) {
|
|
439
|
+
const k = { Accept: "application/json" };
|
|
440
|
+
y && Object.assign(k, o ? { Authorization: `Bearer ${o}` } : await s()), g !== void 0 && (k["Content-Type"] = "application/json");
|
|
440
441
|
let w;
|
|
441
442
|
try {
|
|
442
443
|
w = await e(`${i}${d}`, {
|
|
443
444
|
method: u,
|
|
444
|
-
headers:
|
|
445
|
+
headers: k,
|
|
446
|
+
...p ? { signal: AbortSignal.timeout(p) } : {},
|
|
445
447
|
...g !== void 0 ? { body: JSON.stringify(g) } : {}
|
|
446
448
|
});
|
|
447
|
-
} catch (
|
|
448
|
-
throw Object.assign(new
|
|
449
|
+
} catch (_) {
|
|
450
|
+
throw Object.assign(new x(0, null), { cause: _ });
|
|
449
451
|
}
|
|
450
|
-
let
|
|
452
|
+
let m = null;
|
|
451
453
|
try {
|
|
452
|
-
|
|
454
|
+
m = await w.json();
|
|
453
455
|
} catch {
|
|
454
456
|
}
|
|
455
457
|
if (!w.ok)
|
|
456
|
-
throw new
|
|
457
|
-
return
|
|
458
|
+
throw new x(w.status, m);
|
|
459
|
+
return m;
|
|
458
460
|
}
|
|
459
461
|
return {
|
|
460
462
|
/** @returns {Promise<Array>} published form documents */
|
|
461
463
|
listForms: async () => {
|
|
462
|
-
const d = await l("/v1/forms");
|
|
463
|
-
return n = d?.anonymous?.enabled === !0 ? { enabled: !0, humanCheck: d.anonymous.humanCheck || null } :
|
|
464
|
+
const d = await l("/v1/forms", { timeoutMs: we });
|
|
465
|
+
return n = d?.anonymous?.enabled === !0 ? { enabled: !0, humanCheck: d.anonymous.humanCheck || null } : P, (d?.forms || []).filter((u) => u?.formId && u?.start && Array.isArray(u?.nodes));
|
|
464
466
|
},
|
|
465
467
|
/**
|
|
466
468
|
* What the server advertised on the last listForms.
|
|
@@ -473,13 +475,13 @@ function be({
|
|
|
473
475
|
* @returns {Promise<{expiresIn: number}>}
|
|
474
476
|
*/
|
|
475
477
|
createAnonSession: async ({ formId: d, requestId: u, humanToken: g }) => {
|
|
476
|
-
const
|
|
478
|
+
const y = await l("/v1/anon/sessions", {
|
|
477
479
|
method: "POST",
|
|
478
480
|
body: { formId: d, requestId: u, ...g ? { humanToken: g } : {} }
|
|
479
481
|
});
|
|
480
|
-
if (o =
|
|
481
|
-
throw new
|
|
482
|
-
return { expiresIn:
|
|
482
|
+
if (o = y?.token || null, !o)
|
|
483
|
+
throw new x(502, { message: "The anonymous session had no token" });
|
|
484
|
+
return { expiresIn: y.expiresIn };
|
|
483
485
|
},
|
|
484
486
|
/** Drop the anonymous session so identity headers apply again. */
|
|
485
487
|
endAnonSession: () => {
|
|
@@ -495,43 +497,43 @@ function be({
|
|
|
495
497
|
* progress is observable. Resolves on 2xx; rejects with
|
|
496
498
|
* ApiError(status) otherwise. Returns { promise, abort }.
|
|
497
499
|
*/
|
|
498
|
-
uploadFile: ({ url: d, file: u, contentType: g, onProgress:
|
|
500
|
+
uploadFile: ({ url: d, file: u, contentType: g, onProgress: y = () => {
|
|
499
501
|
} }) => {
|
|
500
502
|
const p = t();
|
|
501
|
-
return { promise: new Promise((
|
|
502
|
-
p.open("PUT", d), p.setRequestHeader("Content-Type", g || u.type), p.upload && (p.upload.onprogress = (
|
|
503
|
-
|
|
503
|
+
return { promise: new Promise((w, m) => {
|
|
504
|
+
p.open("PUT", d), p.setRequestHeader("Content-Type", g || u.type), p.upload && (p.upload.onprogress = (_) => {
|
|
505
|
+
y({ loaded: _.loaded, total: _.total || u.size });
|
|
504
506
|
}), p.onload = () => {
|
|
505
|
-
p.status >= 200 && p.status < 300 ?
|
|
506
|
-
}, p.onerror = () =>
|
|
507
|
+
p.status >= 200 && p.status < 300 ? w({ status: p.status }) : m(new x(p.status, null));
|
|
508
|
+
}, p.onerror = () => m(new x(0, null)), p.onabort = () => m(new x(0, { aborted: !0 })), p.send(u);
|
|
507
509
|
}), abort: () => p.abort() };
|
|
508
510
|
},
|
|
509
511
|
/** @returns {Promise<{requestId,reference,confirmation,routing}>} */
|
|
510
512
|
putRequest: async (d, u) => await l(`/v1/requests/${d}`, { method: "PUT", body: u, auth: !0 })
|
|
511
513
|
};
|
|
512
514
|
}
|
|
513
|
-
function
|
|
514
|
-
const { config: r, storage: e } =
|
|
515
|
+
function ve() {
|
|
516
|
+
const { config: r, storage: e } = Q();
|
|
515
517
|
let t = null;
|
|
516
518
|
return {
|
|
517
|
-
isAuthenticated: () =>
|
|
518
|
-
signedInEmail: () => e.get(
|
|
519
|
-
getAuthHeaders: () =>
|
|
519
|
+
isAuthenticated: () => ie(),
|
|
520
|
+
signedInEmail: () => e.get(I.userEmail) || null,
|
|
521
|
+
getAuthHeaders: () => se(r, e),
|
|
520
522
|
/**
|
|
521
523
|
* Email step. Keeps the challenge user in memory for verifyCode.
|
|
522
524
|
* @returns {{challengeRequired?: boolean, authenticated?: boolean}}
|
|
523
525
|
*/
|
|
524
526
|
sendCode: async (s) => {
|
|
525
|
-
const i = await
|
|
527
|
+
const i = await Z(
|
|
526
528
|
r,
|
|
527
529
|
s,
|
|
528
530
|
e,
|
|
529
|
-
X,
|
|
530
|
-
Z,
|
|
531
531
|
ee,
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
D
|
|
532
|
+
te,
|
|
533
|
+
re,
|
|
534
|
+
D,
|
|
535
|
+
z,
|
|
536
|
+
B
|
|
535
537
|
);
|
|
536
538
|
return t = i.cognitoUser || null, {
|
|
537
539
|
challengeRequired: !!i.challengeRequired,
|
|
@@ -546,22 +548,22 @@ function ye() {
|
|
|
546
548
|
if (!t)
|
|
547
549
|
throw new Error("Please enter your email again to get a new code.");
|
|
548
550
|
try {
|
|
549
|
-
await
|
|
551
|
+
await J(
|
|
550
552
|
t,
|
|
551
553
|
s,
|
|
552
554
|
e,
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
555
|
+
D,
|
|
556
|
+
z,
|
|
557
|
+
B
|
|
556
558
|
);
|
|
557
559
|
} catch {
|
|
558
560
|
throw new Error("Invalid or expired code. Please request a new one and try again.");
|
|
559
561
|
}
|
|
560
|
-
return await
|
|
562
|
+
return await X(), { success: !0 };
|
|
561
563
|
},
|
|
562
564
|
/** Local sign-out only ("use a different email"). */
|
|
563
565
|
signOut: () => {
|
|
564
|
-
t = null,
|
|
566
|
+
t = null, G().clear();
|
|
565
567
|
},
|
|
566
568
|
/**
|
|
567
569
|
* Detect a login completed in ANOTHER tab (the storage event
|
|
@@ -569,24 +571,24 @@ function ye() {
|
|
|
569
571
|
*/
|
|
570
572
|
onCrossTabLogin: (s) => {
|
|
571
573
|
const i = (n) => {
|
|
572
|
-
(n.key ===
|
|
574
|
+
(n.key === I.accessToken || n.key === I.idToken) && s();
|
|
573
575
|
};
|
|
574
576
|
return window.addEventListener("storage", i), () => window.removeEventListener("storage", i);
|
|
575
577
|
}
|
|
576
578
|
};
|
|
577
579
|
}
|
|
578
|
-
function
|
|
579
|
-
const e =
|
|
580
|
-
return { ...
|
|
580
|
+
function ke({ baseUrl: r }) {
|
|
581
|
+
const e = ve();
|
|
582
|
+
return { ...xe({ baseUrl: r, getAuthHeaders: e.getAuthHeaders }), ...e };
|
|
581
583
|
}
|
|
582
|
-
function
|
|
584
|
+
function b(r, e) {
|
|
583
585
|
return (r?.nodes || []).find((t) => t.id === e);
|
|
584
586
|
}
|
|
585
|
-
function
|
|
587
|
+
function V(r, e = []) {
|
|
586
588
|
const t = [];
|
|
587
589
|
let s = r?.start;
|
|
588
590
|
for (const n of e) {
|
|
589
|
-
const o =
|
|
591
|
+
const o = b(r, s);
|
|
590
592
|
if (!o)
|
|
591
593
|
return { nodeId: null, node: null, flags: t, error: { step: n, reason: `unknown node: ${s}` } };
|
|
592
594
|
if (o.type === "terminal" || o.type === "redirect")
|
|
@@ -602,58 +604,58 @@ function N(r, e = []) {
|
|
|
602
604
|
}
|
|
603
605
|
s = o.next;
|
|
604
606
|
}
|
|
605
|
-
const i =
|
|
606
|
-
return i ? { nodeId: s, node: i, flags:
|
|
607
|
+
const i = b(r, s);
|
|
608
|
+
return i ? { nodeId: s, node: i, flags: H(t), error: null } : { nodeId: null, node: null, flags: t, error: { step: null, reason: `unknown node: ${s}` } };
|
|
607
609
|
}
|
|
608
|
-
function
|
|
610
|
+
function _e(r, e = []) {
|
|
609
611
|
const t = [];
|
|
610
612
|
for (const s of e) {
|
|
611
613
|
if (s.kind !== "collect") continue;
|
|
612
|
-
const i =
|
|
614
|
+
const i = b(r, s.nodeId);
|
|
613
615
|
t.push(...i?.fields || []);
|
|
614
616
|
}
|
|
615
617
|
return t;
|
|
616
618
|
}
|
|
617
|
-
function
|
|
619
|
+
function $e(r = []) {
|
|
618
620
|
const e = {};
|
|
619
621
|
for (const t of r)
|
|
620
622
|
t.kind === "collect" && Object.assign(e, t.values || {});
|
|
621
623
|
return e;
|
|
622
624
|
}
|
|
623
|
-
function
|
|
625
|
+
function Fe(r = []) {
|
|
624
626
|
return r.filter((e) => e.kind === "choice").map((e) => `${e.nodeId}:${e.optionId}`);
|
|
625
627
|
}
|
|
626
|
-
function
|
|
628
|
+
function Y(r, e = []) {
|
|
627
629
|
const t = [];
|
|
628
630
|
for (const s of e) {
|
|
629
631
|
if (s.kind !== "choice") continue;
|
|
630
|
-
const n = (
|
|
632
|
+
const n = (b(r, s.nodeId)?.options || []).find((o) => o.id === s.optionId);
|
|
631
633
|
t.push(...n?.flags || []);
|
|
632
634
|
}
|
|
633
|
-
return
|
|
635
|
+
return H(t);
|
|
634
636
|
}
|
|
635
|
-
function
|
|
637
|
+
function Ie(r = []) {
|
|
636
638
|
return r.includes("urgent") ? "urgent" : r.includes("moderate") ? "moderate" : null;
|
|
637
639
|
}
|
|
638
|
-
function
|
|
640
|
+
function H(r) {
|
|
639
641
|
return [...new Set(r)];
|
|
640
642
|
}
|
|
641
|
-
const
|
|
643
|
+
const Ee = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/, M = {
|
|
642
644
|
text: 500,
|
|
643
645
|
textarea: 5e3,
|
|
644
646
|
url: 2048
|
|
645
647
|
};
|
|
646
|
-
function
|
|
647
|
-
if (e == null || e === "" || r.kind === "location" &&
|
|
648
|
+
function Se(r, e) {
|
|
649
|
+
if (e == null || e === "" || r.kind === "location" && Ae(e))
|
|
648
650
|
return r.required ? `Please fill in: ${r.label.toLowerCase()}.` : null;
|
|
649
651
|
switch (r.kind) {
|
|
650
652
|
case "text":
|
|
651
653
|
case "textarea": {
|
|
652
|
-
const s = r.maxLength ||
|
|
654
|
+
const s = r.maxLength || M[r.kind];
|
|
653
655
|
return typeof e != "string" ? `Please enter text for ${r.label.toLowerCase()}.` : e.length > s ? `Please keep ${r.label.toLowerCase()} under ${s} characters.` : null;
|
|
654
656
|
}
|
|
655
657
|
case "url": {
|
|
656
|
-
if (typeof e != "string" || e.length >
|
|
658
|
+
if (typeof e != "string" || e.length > M.url)
|
|
657
659
|
return "Please enter a valid link.";
|
|
658
660
|
try {
|
|
659
661
|
return new URL(e), null;
|
|
@@ -662,35 +664,35 @@ function Fe(r, e) {
|
|
|
662
664
|
}
|
|
663
665
|
}
|
|
664
666
|
case "datetime":
|
|
665
|
-
return
|
|
667
|
+
return Ee.test(String(e)) ? null : "Please pick a date and time.";
|
|
666
668
|
case "select":
|
|
667
669
|
return (r.options || []).map((i) => i.id).includes(e) ? null : `Please choose one of the options for ${r.label.toLowerCase()}.`;
|
|
668
670
|
case "consent":
|
|
669
671
|
return e === !0 ? null : "Please confirm the rights statement so we can use what you send.";
|
|
670
672
|
case "location":
|
|
671
|
-
return
|
|
673
|
+
return Ce(r, e);
|
|
672
674
|
case "media":
|
|
673
675
|
return null;
|
|
674
676
|
default:
|
|
675
677
|
return `Unsupported field: ${r.kind}`;
|
|
676
678
|
}
|
|
677
679
|
}
|
|
678
|
-
function
|
|
680
|
+
function Ae(r) {
|
|
679
681
|
return r == null ? !0 : typeof r != "object" ? !1 : !r.county && !r.where && !(Array.isArray(r.gps) && r.gps.length);
|
|
680
682
|
}
|
|
681
|
-
function
|
|
683
|
+
function Ce(r, e) {
|
|
682
684
|
return typeof e != "object" || Array.isArray(e) ? "Please tell us where this was." : e.county !== void 0 && (typeof e.county != "string" || e.county.length > 100) ? "Please choose a county." : e.where !== void 0 && (typeof e.where != "string" || e.where.length > 500) ? "Please shorten the location description." : e.gps !== void 0 && !(Array.isArray(e.gps) && e.gps.length === 2 && e.gps.every((s) => typeof s == "number" && Number.isFinite(s))) ? "Location coordinates look wrong; try re-sharing your location." : r.required && !e.county && !e.where ? `Please fill in: ${r.label.toLowerCase()}.` : null;
|
|
683
685
|
}
|
|
684
|
-
function
|
|
686
|
+
function O(r, e = {}) {
|
|
685
687
|
const t = {};
|
|
686
688
|
for (const s of r) {
|
|
687
689
|
if (s.kind === "media") continue;
|
|
688
|
-
const i =
|
|
690
|
+
const i = Se(s, e[s.key]);
|
|
689
691
|
i && (t[s.key] = i);
|
|
690
692
|
}
|
|
691
693
|
return { ok: Object.keys(t).length === 0, errors: t };
|
|
692
694
|
}
|
|
693
|
-
function
|
|
695
|
+
function C(r = [], e = {}, { required: t = !1 } = {}) {
|
|
694
696
|
const {
|
|
695
697
|
maxFiles: s = 5,
|
|
696
698
|
maxFileBytes: i = 512 * 1024 * 1024,
|
|
@@ -711,15 +713,15 @@ function E(r = [], e = {}, { required: t = !1 } = {}) {
|
|
|
711
713
|
});
|
|
712
714
|
}), { ok: o.length === 0, errors: o };
|
|
713
715
|
}
|
|
714
|
-
function
|
|
716
|
+
function U({ formId: r, requestId: e, files: t }) {
|
|
715
717
|
return {
|
|
716
718
|
formId: r,
|
|
717
719
|
requestId: e,
|
|
718
720
|
files: t.map((s) => ({ contentType: s.type, size: s.size }))
|
|
719
721
|
};
|
|
720
722
|
}
|
|
721
|
-
function
|
|
722
|
-
const s =
|
|
723
|
+
function Te({ form: r, steps: e, media: t = [] }) {
|
|
724
|
+
const s = _e(r, e), i = $e(e), n = {};
|
|
723
725
|
for (const o of s) {
|
|
724
726
|
if (o.kind === "media") continue;
|
|
725
727
|
const l = i[o.key];
|
|
@@ -735,12 +737,12 @@ function Ae({ form: r, steps: e, media: t = [] }) {
|
|
|
735
737
|
return {
|
|
736
738
|
formId: r.formId,
|
|
737
739
|
flowVersion: r.flowVersion,
|
|
738
|
-
path:
|
|
740
|
+
path: Fe(e),
|
|
739
741
|
answers: n,
|
|
740
742
|
media: t.map(({ assetId: o, type: l }) => ({ assetId: o, type: l }))
|
|
741
743
|
};
|
|
742
744
|
}
|
|
743
|
-
function
|
|
745
|
+
function q(r, e) {
|
|
744
746
|
if (r === 429)
|
|
745
747
|
return {
|
|
746
748
|
kind: "throttled",
|
|
@@ -778,15 +780,15 @@ function M(r, e) {
|
|
|
778
780
|
message: "Something went wrong on our end; please try again."
|
|
779
781
|
};
|
|
780
782
|
}
|
|
781
|
-
const
|
|
782
|
-
function
|
|
783
|
+
const Re = 34, De = 44;
|
|
784
|
+
function L(r, e) {
|
|
783
785
|
const t = String(r);
|
|
784
786
|
return t.length > e ? `${t.slice(0, e)}…` : t;
|
|
785
787
|
}
|
|
786
|
-
function
|
|
788
|
+
function ze(r) {
|
|
787
789
|
return !r || typeof r != "object" ? "" : [r.county, r.where].filter(Boolean).join(", ");
|
|
788
790
|
}
|
|
789
|
-
function
|
|
791
|
+
function Be(r, e = {}, t = []) {
|
|
790
792
|
const s = [];
|
|
791
793
|
for (const i of r) {
|
|
792
794
|
if (i.kind === "consent") continue;
|
|
@@ -794,21 +796,21 @@ function Te(r, e = {}, t = []) {
|
|
|
794
796
|
t.length && s.push(`${t.length} ${t.length === 1 ? "file" : "files"}`);
|
|
795
797
|
continue;
|
|
796
798
|
}
|
|
797
|
-
const n = i.kind === "location" ?
|
|
798
|
-
n == null || n === "" || (i.kind === "textarea" ? s.push(`"${
|
|
799
|
+
const n = i.kind === "location" ? ze(e[i.key]) : e[i.key];
|
|
800
|
+
n == null || n === "" || (i.kind === "textarea" ? s.push(`"${L(n, De)}"`) : s.push(L(n, Re)));
|
|
799
801
|
}
|
|
800
802
|
return s.join(" · ") || "Details provided";
|
|
801
803
|
}
|
|
802
|
-
function
|
|
804
|
+
function Pe(r, e = [], t = null) {
|
|
803
805
|
const s = [];
|
|
804
806
|
for (const n of e) {
|
|
805
|
-
const o =
|
|
807
|
+
const o = b(r, n.nodeId);
|
|
806
808
|
n.kind === "choice" && o && s.push({ k: (o.prompt || "").replace(/\?$/, ""), v: n.label || n.optionId }), n.kind === "collect" && s.push({ k: "Details", v: n.summary || "Details provided" }), n.kind === "gate" && (n.anonymous ? s.push({ k: "Contact", v: "Anonymous — we will have no way to reach you" }) : (n.email || t) && s.push({ k: "Verified email", v: n.email || t }));
|
|
807
809
|
}
|
|
808
|
-
const i =
|
|
810
|
+
const i = Ie(Y(r, e));
|
|
809
811
|
return i && s.push({ k: "Priority", v: i === "urgent" ? "Urgent" : "Moderate", pill: i }), s;
|
|
810
812
|
}
|
|
811
|
-
function
|
|
813
|
+
function Me(r, e = []) {
|
|
812
814
|
const t = r?.confirmation || {};
|
|
813
815
|
return {
|
|
814
816
|
title: t.title || "Report received.",
|
|
@@ -816,11 +818,11 @@ function ze(r, e = []) {
|
|
|
816
818
|
urgentNote: e.includes("urgent") ? t.urgentNote : void 0
|
|
817
819
|
};
|
|
818
820
|
}
|
|
819
|
-
function
|
|
821
|
+
function Oe(r, e) {
|
|
820
822
|
const t = e === "failed" ? " The notification is queued for a delivery retry." : "";
|
|
821
823
|
return r?.startsWith("studio+email:") ? `Sent to the Studio review queue; the desk is emailed.${t}` : r?.startsWith("studio:") ? "Sent to the Studio review queue." : r?.startsWith("jsm:") ? `A ticket is opened for tech support with your details as fields, not prose.${t}` : r?.startsWith("email:") ? `Emailed to the owning desk with a link to your report.${t}` : "Routed to the right team.";
|
|
822
824
|
}
|
|
823
|
-
function
|
|
825
|
+
function Ue({ routing: r = {}, flags: e = [], reference: t = "", anonymous: s = !1 }) {
|
|
824
826
|
const i = e.includes("urgent");
|
|
825
827
|
return [
|
|
826
828
|
{
|
|
@@ -829,7 +831,7 @@ function Be({ routing: r = {}, flags: e = [], reference: t = "", anonymous: s =
|
|
|
829
831
|
},
|
|
830
832
|
{
|
|
831
833
|
title: "Routed",
|
|
832
|
-
body:
|
|
834
|
+
body: Oe(r.destination, r.state),
|
|
833
835
|
pill: i ? "Urgent · pinned first" : void 0
|
|
834
836
|
},
|
|
835
837
|
{
|
|
@@ -846,30 +848,30 @@ function Be({ routing: r = {}, flags: e = [], reference: t = "", anonymous: s =
|
|
|
846
848
|
}
|
|
847
849
|
];
|
|
848
850
|
}
|
|
849
|
-
const
|
|
851
|
+
const R = "wral-report-it:draft:v1", K = 1;
|
|
850
852
|
function qe(r, e) {
|
|
851
853
|
try {
|
|
852
|
-
r.setItem(
|
|
854
|
+
r.setItem(R, JSON.stringify({ ...e, v: K, savedAt: Date.now() }));
|
|
853
855
|
} catch {
|
|
854
856
|
}
|
|
855
857
|
}
|
|
856
|
-
function
|
|
858
|
+
function Le(r) {
|
|
857
859
|
try {
|
|
858
|
-
const e = r.getItem(
|
|
860
|
+
const e = r.getItem(R);
|
|
859
861
|
if (!e) return null;
|
|
860
862
|
const t = JSON.parse(e);
|
|
861
|
-
return t?.v !==
|
|
863
|
+
return t?.v !== K ? null : t;
|
|
862
864
|
} catch {
|
|
863
865
|
return null;
|
|
864
866
|
}
|
|
865
867
|
}
|
|
866
|
-
function
|
|
868
|
+
function j(r) {
|
|
867
869
|
try {
|
|
868
|
-
r.removeItem(
|
|
870
|
+
r.removeItem(R);
|
|
869
871
|
} catch {
|
|
870
872
|
}
|
|
871
873
|
}
|
|
872
|
-
function
|
|
874
|
+
function je({ apiOrigin: r, form: e, steps: t, requestId: s = null, mediaMeta: i = {} }) {
|
|
873
875
|
return {
|
|
874
876
|
apiOrigin: r,
|
|
875
877
|
formId: e.formId,
|
|
@@ -879,13 +881,13 @@ function Ue({ apiOrigin: r, form: e, steps: t, requestId: s = null, mediaMeta: i
|
|
|
879
881
|
media: i
|
|
880
882
|
};
|
|
881
883
|
}
|
|
882
|
-
function
|
|
884
|
+
function Ne(r, e, { apiOrigin: t } = {}) {
|
|
883
885
|
if (!r) return { status: "discarded" };
|
|
884
886
|
if (t && r.apiOrigin && r.apiOrigin !== t)
|
|
885
887
|
return { status: "discarded" };
|
|
886
888
|
const s = (e || []).find((o) => o.formId === r.formId);
|
|
887
889
|
if (!s) return { status: "discarded" };
|
|
888
|
-
const { error: i } =
|
|
890
|
+
const { error: i } = V(s, r.steps || []);
|
|
889
891
|
if (i) return { status: "discarded" };
|
|
890
892
|
const n = {};
|
|
891
893
|
for (const [o, l] of Object.entries(r.media || {}))
|
|
@@ -898,7 +900,7 @@ function Oe(r, e, { apiOrigin: t } = {}) {
|
|
|
898
900
|
lostMedia: n
|
|
899
901
|
};
|
|
900
902
|
}
|
|
901
|
-
function
|
|
903
|
+
function F(r = []) {
|
|
902
904
|
return {
|
|
903
905
|
stage: "idle",
|
|
904
906
|
resumeStage: null,
|
|
@@ -918,7 +920,7 @@ function $(r = []) {
|
|
|
918
920
|
error: null
|
|
919
921
|
};
|
|
920
922
|
}
|
|
921
|
-
function
|
|
923
|
+
function We(r, e) {
|
|
922
924
|
switch (e.type) {
|
|
923
925
|
case "START":
|
|
924
926
|
return { ...r, stage: r.files.length ? "minting" : "requesting", error: null };
|
|
@@ -939,29 +941,29 @@ function je(r, e) {
|
|
|
939
941
|
return { ...r, stage: "uploading", files: t };
|
|
940
942
|
}
|
|
941
943
|
case "FILE_PROGRESS":
|
|
942
|
-
return
|
|
944
|
+
return v(r, e.i, (t) => ({
|
|
943
945
|
...t,
|
|
944
946
|
progress: e.total ? e.loaded / e.total : 0
|
|
945
947
|
}));
|
|
946
948
|
case "FILE_DONE": {
|
|
947
|
-
const t =
|
|
948
|
-
return
|
|
949
|
+
const t = v(r, e.i, (s) => ({ ...s, status: "done", progress: 1 }));
|
|
950
|
+
return Ve(t);
|
|
949
951
|
}
|
|
950
952
|
case "FILE_FAIL":
|
|
951
|
-
return { ...
|
|
953
|
+
return { ...v(r, e.i, (s) => ({
|
|
952
954
|
...s,
|
|
953
955
|
status: "failed",
|
|
954
956
|
error: e.error || "upload failed"
|
|
955
957
|
})), stage: "uploading-error" };
|
|
956
958
|
case "RETRY_FILE":
|
|
957
|
-
return { ...
|
|
959
|
+
return { ...v(r, e.i, (s) => ({
|
|
958
960
|
...s,
|
|
959
961
|
status: "uploading",
|
|
960
962
|
progress: 0,
|
|
961
963
|
error: null
|
|
962
964
|
})), stage: "uploading" };
|
|
963
965
|
case "REMINT_FILE":
|
|
964
|
-
return { ...
|
|
966
|
+
return { ...v(r, e.i, (s) => ({
|
|
965
967
|
...s,
|
|
966
968
|
assetId: e.upload.assetId,
|
|
967
969
|
url: e.upload.url,
|
|
@@ -977,23 +979,23 @@ function je(r, e) {
|
|
|
977
979
|
case "REQUEST_FAIL":
|
|
978
980
|
return { ...r, stage: "requesting-error", error: e.error };
|
|
979
981
|
case "RESET":
|
|
980
|
-
return
|
|
982
|
+
return F([]);
|
|
981
983
|
default:
|
|
982
984
|
return r;
|
|
983
985
|
}
|
|
984
986
|
}
|
|
985
|
-
function
|
|
987
|
+
function v(r, e, t) {
|
|
986
988
|
const s = r.files.map((i, n) => n === e ? t(i) : i);
|
|
987
989
|
return { ...r, files: s };
|
|
988
990
|
}
|
|
989
|
-
function
|
|
991
|
+
function Ve(r) {
|
|
990
992
|
const e = r.files.every((s) => s.status === "done"), t = r.files.some((s) => s.status === "failed");
|
|
991
993
|
return e ? { ...r, stage: "requesting" } : t ? { ...r, stage: "uploading-error" } : r;
|
|
992
994
|
}
|
|
993
|
-
function
|
|
995
|
+
function N(r) {
|
|
994
996
|
return r.files.map((e, t) => ({ ...e, i: t })).filter((e) => e.status === "failed");
|
|
995
997
|
}
|
|
996
|
-
const
|
|
998
|
+
const Ye = [
|
|
997
999
|
"Wake",
|
|
998
1000
|
"Durham",
|
|
999
1001
|
"Orange",
|
|
@@ -1010,18 +1012,18 @@ const Ne = [
|
|
|
1010
1012
|
"Moore",
|
|
1011
1013
|
"Sampson",
|
|
1012
1014
|
"Other / outside the area"
|
|
1013
|
-
],
|
|
1015
|
+
], W = "(919) 821-8600", He = "https://www.wral.com/my-wral/", Ke = Object.freeze([
|
|
1014
1016
|
"We cannot come back to you for the detail that often turns a tip into a story.",
|
|
1015
1017
|
"We cannot credit you if we use your photos or video.",
|
|
1016
1018
|
"If you lose your reference number, we cannot look it up for you."
|
|
1017
1019
|
]);
|
|
1018
|
-
function
|
|
1020
|
+
function Qe(r) {
|
|
1019
1021
|
const e = String(r).replace(/\D/g, "");
|
|
1020
1022
|
return `tel:+1${e.length === 11 && e.startsWith("1") ? e.slice(1) : e}`;
|
|
1021
1023
|
}
|
|
1022
|
-
const
|
|
1023
|
-
class
|
|
1024
|
-
static styles =
|
|
1024
|
+
const Ge = "https://api.wral.com/forms", Je = 480, Xe = 2, S = "Welcome to Report It. What would you like to send us?", A = "A few quick questions route your report to the right team.", Ze = 2500;
|
|
1025
|
+
class at extends T {
|
|
1026
|
+
static styles = me;
|
|
1025
1027
|
static properties = {
|
|
1026
1028
|
api: { type: String },
|
|
1027
1029
|
_phase: { state: !0 },
|
|
@@ -1029,6 +1031,7 @@ class rt extends A {
|
|
|
1029
1031
|
_form: { state: !0 },
|
|
1030
1032
|
_steps: { state: !0 },
|
|
1031
1033
|
_typing: { state: !0 },
|
|
1034
|
+
_loadingSlow: { state: !0 },
|
|
1032
1035
|
_cardValues: { state: !0 },
|
|
1033
1036
|
_fieldErrors: { state: !0 },
|
|
1034
1037
|
_gate: { state: !0 },
|
|
@@ -1044,35 +1047,36 @@ class rt extends A {
|
|
|
1044
1047
|
#r = {};
|
|
1045
1048
|
#s = {};
|
|
1046
1049
|
#i = /* @__PURE__ */ new Map();
|
|
1047
|
-
#
|
|
1048
|
-
#
|
|
1050
|
+
#y = null;
|
|
1051
|
+
#p = null;
|
|
1052
|
+
#w = !1;
|
|
1049
1053
|
#d = null;
|
|
1050
|
-
#
|
|
1054
|
+
#I = 0;
|
|
1051
1055
|
constructor() {
|
|
1052
|
-
super(), this.api =
|
|
1056
|
+
super(), this.api = Ge, this._phase = "loading", this._forms = [], this._form = null, this._steps = [], this._typing = !1, this._loadingSlow = !1, this._cardValues = {}, this._fieldErrors = {}, this._gate = { stage: null, email: "", error: "", loading: !1 }, this._submit = F([]), this._banner = null, this._notice = null, this._result = null;
|
|
1053
1057
|
}
|
|
1054
1058
|
get client() {
|
|
1055
|
-
return this.#l ? this.#l : ((!this.#a || this.#u !== this.api) && (this.#a =
|
|
1059
|
+
return this.#l ? this.#l : ((!this.#a || this.#u !== this.api) && (this.#a = ke({ baseUrl: this.api }), this.#u = this.api), this.#a);
|
|
1056
1060
|
}
|
|
1057
1061
|
set client(e) {
|
|
1058
|
-
this.#l = e || null, this.isConnected && this.#
|
|
1062
|
+
this.#l = e || null, this.isConnected && this.#x();
|
|
1059
1063
|
}
|
|
1060
1064
|
connectedCallback() {
|
|
1061
|
-
super.connectedCallback(), this.#
|
|
1065
|
+
super.connectedCallback(), this.#x();
|
|
1062
1066
|
}
|
|
1063
1067
|
disconnectedCallback() {
|
|
1064
|
-
super.disconnectedCallback(), clearTimeout(this.#
|
|
1068
|
+
super.disconnectedCallback(), clearTimeout(this.#y), clearTimeout(this.#p), this.#d?.();
|
|
1065
1069
|
for (const { abort: e } of this.#i.values()) e?.();
|
|
1066
1070
|
this.#i.clear();
|
|
1067
1071
|
}
|
|
1068
|
-
get #
|
|
1072
|
+
get #z() {
|
|
1069
1073
|
try {
|
|
1070
1074
|
return matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1071
1075
|
} catch {
|
|
1072
1076
|
return !0;
|
|
1073
1077
|
}
|
|
1074
1078
|
}
|
|
1075
|
-
get #
|
|
1079
|
+
get #h() {
|
|
1076
1080
|
try {
|
|
1077
1081
|
return sessionStorage;
|
|
1078
1082
|
} catch {
|
|
@@ -1087,27 +1091,31 @@ class rt extends A {
|
|
|
1087
1091
|
* submission is enabled on this deployment, and a form whose desk needs
|
|
1088
1092
|
* a way to reach the viewer opts out with allowAnonymous: false.
|
|
1089
1093
|
*/
|
|
1090
|
-
get #
|
|
1094
|
+
get #B() {
|
|
1091
1095
|
return this.client.anonymousCapability?.().enabled === !0 && this._form?.allowAnonymous !== !1;
|
|
1092
1096
|
}
|
|
1093
1097
|
/* Derived from the gate step, so a reload restores the choice. */
|
|
1094
|
-
get #
|
|
1098
|
+
get #f() {
|
|
1095
1099
|
return this._steps.some((e) => e.kind === "gate" && e.anonymous === !0);
|
|
1096
1100
|
}
|
|
1097
1101
|
// ── Loading + draft restore ─────────────────────────────────────
|
|
1098
|
-
async #
|
|
1099
|
-
const e = ++this.#
|
|
1100
|
-
this._phase = "loading", this._banner = null
|
|
1102
|
+
async #x() {
|
|
1103
|
+
const e = ++this.#I, t = () => e === this.#I;
|
|
1104
|
+
this._phase = "loading", this._banner = null, this._loadingSlow = !1, clearTimeout(this.#p), this.#p = setTimeout(() => {
|
|
1105
|
+
this._loadingSlow = !0;
|
|
1106
|
+
}, Ze);
|
|
1101
1107
|
let s;
|
|
1102
1108
|
try {
|
|
1103
1109
|
s = await this.client.listForms();
|
|
1104
1110
|
} catch {
|
|
1105
1111
|
t() && (this._phase = "load-error");
|
|
1106
1112
|
return;
|
|
1113
|
+
} finally {
|
|
1114
|
+
t() && (clearTimeout(this.#p), this._loadingSlow = !1);
|
|
1107
1115
|
}
|
|
1108
1116
|
if (!t()) return;
|
|
1109
1117
|
this._forms = s;
|
|
1110
|
-
const i =
|
|
1118
|
+
const i = Ne(Le(this.#h), this._forms, { apiOrigin: this.api });
|
|
1111
1119
|
if (i.status === "ok" || i.status === "review-required") {
|
|
1112
1120
|
this._form = i.form, this._steps = i.steps, this.#t = i.requestId, this.#s = i.lostMedia || {}, i.status === "review-required" ? this._notice = "This form changed since your last visit — please review your answers." : Object.keys(this.#s).length && (this._notice = "Welcome back — your answers were saved, but attachments need to be re-attached."), this.#o({ animate: !1 });
|
|
1113
1121
|
return;
|
|
@@ -1119,7 +1127,7 @@ class rt extends A {
|
|
|
1119
1127
|
const e = {};
|
|
1120
1128
|
for (const [t, s] of Object.entries(this.#r))
|
|
1121
1129
|
s.length && (e[t] = s.map(({ name: i, type: n, size: o }) => ({ name: i, type: n, size: o })));
|
|
1122
|
-
qe(this.#
|
|
1130
|
+
qe(this.#h, je({
|
|
1123
1131
|
apiOrigin: this.api,
|
|
1124
1132
|
form: this._form,
|
|
1125
1133
|
steps: this._steps,
|
|
@@ -1129,44 +1137,44 @@ class rt extends A {
|
|
|
1129
1137
|
}
|
|
1130
1138
|
// ── Walk mechanics ──────────────────────────────────────────────
|
|
1131
1139
|
#o({ animate: e = !0 } = {}) {
|
|
1132
|
-
this._phase = "walk", this._cardValues = {}, this._fieldErrors = {}, this._gate = { stage: null, email: "", error: "", loading: !1 }, e && !this.#
|
|
1140
|
+
this._phase = "walk", this._cardValues = {}, this._fieldErrors = {}, this._gate = { stage: null, email: "", error: "", loading: !1 }, e && !this.#z ? (this._typing = !0, clearTimeout(this.#y), this.#y = setTimeout(() => {
|
|
1133
1141
|
this._typing = !1;
|
|
1134
|
-
},
|
|
1142
|
+
}, Je)) : this._typing = !1;
|
|
1135
1143
|
}
|
|
1136
|
-
get #
|
|
1137
|
-
return this._form ?
|
|
1144
|
+
get #v() {
|
|
1145
|
+
return this._form ? V(this._form, this._steps) : { node: null };
|
|
1138
1146
|
}
|
|
1139
1147
|
#P(e) {
|
|
1140
1148
|
this._form = e, this._steps = [], this.#t = null, this.#r = {}, this.#s = {}, this._notice = null, this.#c(), this.#o();
|
|
1141
1149
|
}
|
|
1142
|
-
#
|
|
1150
|
+
#g(e) {
|
|
1143
1151
|
this._steps = [...this._steps, e], this.#c(), this.#o();
|
|
1144
1152
|
}
|
|
1145
|
-
#
|
|
1153
|
+
#M() {
|
|
1146
1154
|
if (this._phase === "done" || this._phase === "submitting") return;
|
|
1147
1155
|
if (this._phase === "review") {
|
|
1148
1156
|
this.#o({ animate: !1 });
|
|
1149
1157
|
return;
|
|
1150
1158
|
}
|
|
1151
1159
|
if (!this._steps.length) {
|
|
1152
|
-
this.#
|
|
1160
|
+
this.#k();
|
|
1153
1161
|
return;
|
|
1154
1162
|
}
|
|
1155
1163
|
const e = this._steps.at(-1);
|
|
1156
1164
|
this._steps = this._steps.slice(0, -1), e.kind === "collect" && (this._cardValues = { ...e.values }), this.#c(), this.#o({ animate: !1 });
|
|
1157
1165
|
}
|
|
1158
|
-
#
|
|
1159
|
-
this.client.endAnonSession?.(), this._form = null, this._steps = [], this.#t = null, this.#r = {}, this.#s = {}, this._result = null, this._banner = null, this._notice = null, this._submit =
|
|
1166
|
+
#k() {
|
|
1167
|
+
this.client.endAnonSession?.(), this._form = null, this._steps = [], this.#t = null, this.#r = {}, this.#s = {}, this._result = null, this._banner = null, this._notice = null, this._submit = F([]), j(this.#h), this._phase = "pick";
|
|
1160
1168
|
}
|
|
1161
1169
|
// ── Collect card ────────────────────────────────────────────────
|
|
1162
|
-
#
|
|
1170
|
+
#_(e, t) {
|
|
1163
1171
|
this._cardValues = { ...this._cardValues, [e]: t };
|
|
1164
1172
|
}
|
|
1165
|
-
#
|
|
1166
|
-
const t = e.fields || [], { ok: s, errors: i } =
|
|
1173
|
+
#O(e) {
|
|
1174
|
+
const t = e.fields || [], { ok: s, errors: i } = O(t, this._cardValues), n = t.find((d) => d.kind === "media");
|
|
1167
1175
|
let o = !0;
|
|
1168
1176
|
if (n) {
|
|
1169
|
-
const d = this.#r[e.id] || [], u =
|
|
1177
|
+
const d = this.#r[e.id] || [], u = C(d, this._form.budget, {
|
|
1170
1178
|
required: !!n.required
|
|
1171
1179
|
});
|
|
1172
1180
|
u.ok ? d.length && (this.#s = { ...this.#s, [e.id]: [] }) : (o = !1, i[n.key] = u.errors[0].message);
|
|
@@ -1176,29 +1184,29 @@ class rt extends A {
|
|
|
1176
1184
|
return;
|
|
1177
1185
|
}
|
|
1178
1186
|
const l = this.#r[e.id] || [];
|
|
1179
|
-
this.#
|
|
1187
|
+
this.#g({
|
|
1180
1188
|
nodeId: e.id,
|
|
1181
1189
|
kind: "collect",
|
|
1182
1190
|
values: { ...this._cardValues },
|
|
1183
|
-
summary:
|
|
1191
|
+
summary: Be(t, this._cardValues, l)
|
|
1184
1192
|
});
|
|
1185
1193
|
}
|
|
1186
1194
|
// ── Gate ────────────────────────────────────────────────────────
|
|
1187
|
-
async #
|
|
1188
|
-
if (!(this._gate.stage || this.#
|
|
1189
|
-
this.#
|
|
1195
|
+
async #E() {
|
|
1196
|
+
if (!(this._gate.stage || this.#w)) {
|
|
1197
|
+
this.#w = !0;
|
|
1190
1198
|
try {
|
|
1191
1199
|
const e = await this.client.isAuthenticated();
|
|
1192
1200
|
this._gate = e ? { stage: "signedin", email: this.client.signedInEmail?.() || "", error: "", loading: !1 } : { stage: "email", email: "", error: "", loading: !1 };
|
|
1193
1201
|
} finally {
|
|
1194
|
-
this.#
|
|
1202
|
+
this.#w = !1;
|
|
1195
1203
|
}
|
|
1196
1204
|
this._gate.stage === "email" && this.client.onCrossTabLogin && !this.#d && (this.#d = this.client.onCrossTabLogin(() => {
|
|
1197
|
-
this.#d?.(), this.#d = null, this._gate = { stage: null, email: "", error: "", loading: !1 }, this.#
|
|
1205
|
+
this.#d?.(), this.#d = null, this._gate = { stage: null, email: "", error: "", loading: !1 }, this.#E();
|
|
1198
1206
|
}));
|
|
1199
1207
|
}
|
|
1200
1208
|
}
|
|
1201
|
-
async
|
|
1209
|
+
async #$() {
|
|
1202
1210
|
const e = this._gate.email.trim();
|
|
1203
1211
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)) {
|
|
1204
1212
|
this._gate = { ...this._gate, error: "Please enter a valid email address." };
|
|
@@ -1216,7 +1224,7 @@ class rt extends A {
|
|
|
1216
1224
|
};
|
|
1217
1225
|
}
|
|
1218
1226
|
}
|
|
1219
|
-
async #
|
|
1227
|
+
async #S(e) {
|
|
1220
1228
|
this._gate = { ...this._gate, error: "", loading: !0 };
|
|
1221
1229
|
try {
|
|
1222
1230
|
await this.client.verifyCode(e), this.#A(this._gate.email);
|
|
@@ -1233,17 +1241,17 @@ class rt extends A {
|
|
|
1233
1241
|
this.#e({ type: "AUTH_OK" }), this._phase = "submitting", this.#n();
|
|
1234
1242
|
return;
|
|
1235
1243
|
}
|
|
1236
|
-
const { node: t } = this.#
|
|
1237
|
-
t?.type === "gate" && this.#
|
|
1244
|
+
const { node: t } = this.#v;
|
|
1245
|
+
t?.type === "gate" && this.#g({ nodeId: t.id, kind: "gate", email: e });
|
|
1238
1246
|
}
|
|
1239
|
-
#
|
|
1247
|
+
#U() {
|
|
1240
1248
|
this.client.signOut?.(), this._gate = { stage: "email", email: "", error: "", loading: !1 };
|
|
1241
1249
|
}
|
|
1242
1250
|
// ── Anonymous route ─────────────────────────────────────────────
|
|
1243
|
-
#
|
|
1251
|
+
#q() {
|
|
1244
1252
|
this._gate = { ...this._gate, stage: "anon-confirm", error: "" };
|
|
1245
1253
|
}
|
|
1246
|
-
#
|
|
1254
|
+
#L() {
|
|
1247
1255
|
this._gate = { ...this._gate, stage: "email", error: "" };
|
|
1248
1256
|
}
|
|
1249
1257
|
/*
|
|
@@ -1251,8 +1259,8 @@ class rt extends A {
|
|
|
1251
1259
|
* the requestId, so an abandoned form leaves nothing behind.
|
|
1252
1260
|
*/
|
|
1253
1261
|
#j() {
|
|
1254
|
-
const { node: e } = this.#
|
|
1255
|
-
e?.type === "gate" && (this._gate = { stage: null, email: "", error: "", loading: !1 }, this.#
|
|
1262
|
+
const { node: e } = this.#v;
|
|
1263
|
+
e?.type === "gate" && (this._gate = { stage: null, email: "", error: "", loading: !1 }, this.#g({ nodeId: e.id, kind: "gate", anonymous: !0 }));
|
|
1256
1264
|
}
|
|
1257
1265
|
async #C() {
|
|
1258
1266
|
try {
|
|
@@ -1261,12 +1269,12 @@ class rt extends A {
|
|
|
1261
1269
|
requestId: this.#t
|
|
1262
1270
|
}), !0;
|
|
1263
1271
|
} catch (e) {
|
|
1264
|
-
return this._banner =
|
|
1272
|
+
return this._banner = q(e?.status ?? 0, e?.body ?? null), !1;
|
|
1265
1273
|
}
|
|
1266
1274
|
}
|
|
1267
1275
|
/* An anonymous session outliving the upload run re-mints in place; there
|
|
1268
1276
|
* is no identity to send back to the sign-in card. */
|
|
1269
|
-
async #
|
|
1277
|
+
async #N() {
|
|
1270
1278
|
if (await this.#C()) {
|
|
1271
1279
|
this.#e({ type: "AUTH_OK" }), this._phase = "submitting", this.#n();
|
|
1272
1280
|
return;
|
|
@@ -1274,7 +1282,7 @@ class rt extends A {
|
|
|
1274
1282
|
this.#e({ type: "REQUEST_FAIL", error: this._banner });
|
|
1275
1283
|
}
|
|
1276
1284
|
// ── Submit pipeline ─────────────────────────────────────────────
|
|
1277
|
-
get #
|
|
1285
|
+
get #m() {
|
|
1278
1286
|
const e = [];
|
|
1279
1287
|
for (const t of this._steps)
|
|
1280
1288
|
if (t.kind === "collect")
|
|
@@ -1283,17 +1291,17 @@ class rt extends A {
|
|
|
1283
1291
|
return e;
|
|
1284
1292
|
}
|
|
1285
1293
|
#e(e) {
|
|
1286
|
-
this._submit =
|
|
1294
|
+
this._submit = We(this._submit, e);
|
|
1287
1295
|
}
|
|
1288
|
-
async #
|
|
1296
|
+
async #W() {
|
|
1289
1297
|
this._banner = null;
|
|
1290
1298
|
for (let e = 0; e < this._steps.length; e++) {
|
|
1291
1299
|
const t = this._steps[e];
|
|
1292
1300
|
if (t.kind !== "collect") continue;
|
|
1293
|
-
const s =
|
|
1301
|
+
const s = b(this._form, t.nodeId), { ok: i, errors: n } = O(s?.fields || [], t.values), o = (s?.fields || []).find((d) => d.kind === "media");
|
|
1294
1302
|
let l = !0;
|
|
1295
1303
|
if (o) {
|
|
1296
|
-
const d = this.#r[t.nodeId] || [], u =
|
|
1304
|
+
const d = this.#r[t.nodeId] || [], u = C(d, this._form.budget, {
|
|
1297
1305
|
required: !!o.required
|
|
1298
1306
|
});
|
|
1299
1307
|
u.ok || (l = !1, n[o.key] = u.errors[0].message);
|
|
@@ -1303,11 +1311,11 @@ class rt extends A {
|
|
|
1303
1311
|
return;
|
|
1304
1312
|
}
|
|
1305
1313
|
}
|
|
1306
|
-
if (this.#t = this.#t || crypto.randomUUID(), this.#c(), this.#
|
|
1314
|
+
if (this.#t = this.#t || crypto.randomUUID(), this.#c(), this.#f) {
|
|
1307
1315
|
if (!await this.#C()) return;
|
|
1308
1316
|
} else
|
|
1309
1317
|
this.client.endAnonSession?.();
|
|
1310
|
-
if (this._submit =
|
|
1318
|
+
if (this._submit = F(this.#m), this._phase = "submitting", this.#f) {
|
|
1311
1319
|
this.#e({ type: "START" }), this.#n();
|
|
1312
1320
|
return;
|
|
1313
1321
|
}
|
|
@@ -1319,30 +1327,30 @@ class rt extends A {
|
|
|
1319
1327
|
}
|
|
1320
1328
|
async #n() {
|
|
1321
1329
|
const e = this._submit.stage;
|
|
1322
|
-
if (e === "minting") return this.#
|
|
1323
|
-
if (e === "uploading") return this.#
|
|
1324
|
-
if (e === "requesting") return this.#
|
|
1330
|
+
if (e === "minting") return this.#V();
|
|
1331
|
+
if (e === "uploading") return this.#T();
|
|
1332
|
+
if (e === "requesting") return this.#K();
|
|
1325
1333
|
}
|
|
1326
|
-
async #
|
|
1334
|
+
async #V() {
|
|
1327
1335
|
try {
|
|
1328
|
-
const e = await this.client.createUploads(
|
|
1336
|
+
const e = await this.client.createUploads(U({
|
|
1329
1337
|
formId: this._form.formId,
|
|
1330
1338
|
requestId: this.#t,
|
|
1331
|
-
files: this.#
|
|
1339
|
+
files: this.#m
|
|
1332
1340
|
}));
|
|
1333
1341
|
this.#e({ type: "MINTED", uploads: e }), this.#n();
|
|
1334
1342
|
} catch (e) {
|
|
1335
|
-
this
|
|
1343
|
+
this.#F(e);
|
|
1336
1344
|
}
|
|
1337
1345
|
}
|
|
1338
|
-
#
|
|
1346
|
+
#T() {
|
|
1339
1347
|
const e = this._submit.files, t = this.#i.size;
|
|
1340
1348
|
let s = 0;
|
|
1341
|
-
for (let i = 0; i < e.length && t + s <
|
|
1342
|
-
e[i].status !== "uploading" || this.#i.has(i) || (s += 1, this.#
|
|
1349
|
+
for (let i = 0; i < e.length && t + s < Xe; i++)
|
|
1350
|
+
e[i].status !== "uploading" || this.#i.has(i) || (s += 1, this.#Y(i));
|
|
1343
1351
|
}
|
|
1344
|
-
#
|
|
1345
|
-
const t = this._submit.files[e], s = this.#
|
|
1352
|
+
#Y(e) {
|
|
1353
|
+
const t = this._submit.files[e], s = this.#m[e], { promise: i, abort: n } = this.client.uploadFile({
|
|
1346
1354
|
url: t.url,
|
|
1347
1355
|
file: s,
|
|
1348
1356
|
contentType: t.type,
|
|
@@ -1360,52 +1368,52 @@ class rt extends A {
|
|
|
1360
1368
|
});
|
|
1361
1369
|
});
|
|
1362
1370
|
}
|
|
1363
|
-
async #
|
|
1371
|
+
async #H(e) {
|
|
1364
1372
|
if (this._submit.files[e].error === "expired")
|
|
1365
1373
|
try {
|
|
1366
|
-
const [s] = await this.client.createUploads(
|
|
1374
|
+
const [s] = await this.client.createUploads(U({
|
|
1367
1375
|
formId: this._form.formId,
|
|
1368
1376
|
requestId: this.#t,
|
|
1369
|
-
files: [this.#
|
|
1377
|
+
files: [this.#m[e]]
|
|
1370
1378
|
}));
|
|
1371
1379
|
this.#e({ type: "REMINT_FILE", i: e, upload: s });
|
|
1372
1380
|
} catch (s) {
|
|
1373
|
-
this
|
|
1381
|
+
this.#F(s);
|
|
1374
1382
|
return;
|
|
1375
1383
|
}
|
|
1376
1384
|
else
|
|
1377
1385
|
this.#e({ type: "RETRY_FILE", i: e });
|
|
1378
|
-
this.#
|
|
1386
|
+
this.#T();
|
|
1379
1387
|
}
|
|
1380
|
-
async #
|
|
1388
|
+
async #K() {
|
|
1381
1389
|
try {
|
|
1382
|
-
const e = this._submit.files.map(({ assetId: s, type: i }) => ({ assetId: s, type: i })), t = await this.client.putRequest(this.#t,
|
|
1390
|
+
const e = this._submit.files.map(({ assetId: s, type: i }) => ({ assetId: s, type: i })), t = await this.client.putRequest(this.#t, Te({
|
|
1383
1391
|
form: this._form,
|
|
1384
1392
|
steps: this._steps,
|
|
1385
1393
|
media: e
|
|
1386
1394
|
}));
|
|
1387
|
-
this.#e({ type: "REQUEST_OK", result: t }), this._result = t,
|
|
1395
|
+
this.#e({ type: "REQUEST_OK", result: t }), this._result = t, j(this.#h), this.client.endAnonSession?.(), this._phase = "done";
|
|
1388
1396
|
} catch (e) {
|
|
1389
|
-
this
|
|
1397
|
+
this.#F(e);
|
|
1390
1398
|
}
|
|
1391
1399
|
}
|
|
1392
|
-
|
|
1393
|
-
const t =
|
|
1400
|
+
#F(e) {
|
|
1401
|
+
const t = q(e?.status ?? 0, e?.body ?? null);
|
|
1394
1402
|
if (t.kind === "auth") {
|
|
1395
|
-
if (this.#e({ type: "AUTH_REQUIRED" }), this.#
|
|
1396
|
-
this.#
|
|
1403
|
+
if (this.#e({ type: "AUTH_REQUIRED" }), this.#f) {
|
|
1404
|
+
this.#N();
|
|
1397
1405
|
return;
|
|
1398
1406
|
}
|
|
1399
1407
|
this._gate = { stage: "email", email: "", error: "", loading: !1 };
|
|
1400
1408
|
return;
|
|
1401
1409
|
}
|
|
1402
1410
|
if (t.kind === "stale") {
|
|
1403
|
-
this._banner = t, this.#e({ type: "REQUEST_FAIL", error: t }), this.#
|
|
1411
|
+
this._banner = t, this.#e({ type: "REQUEST_FAIL", error: t }), this.#Q();
|
|
1404
1412
|
return;
|
|
1405
1413
|
}
|
|
1406
1414
|
this._banner = t, this.#e({ type: "REQUEST_FAIL", error: t });
|
|
1407
1415
|
}
|
|
1408
|
-
async #
|
|
1416
|
+
async #Q() {
|
|
1409
1417
|
try {
|
|
1410
1418
|
this._forms = await this.client.listForms();
|
|
1411
1419
|
const e = this._forms.find((t) => t.formId === this._form.formId);
|
|
@@ -1413,50 +1421,48 @@ class rt extends A {
|
|
|
1413
1421
|
} catch {
|
|
1414
1422
|
}
|
|
1415
1423
|
}
|
|
1416
|
-
#
|
|
1424
|
+
#G() {
|
|
1417
1425
|
this._banner = null, this.#e({ type: "REQUEST_START" }), this.#n();
|
|
1418
1426
|
}
|
|
1419
1427
|
// ── Render ──────────────────────────────────────────────────────
|
|
1420
1428
|
render() {
|
|
1421
1429
|
return a`
|
|
1422
1430
|
<div class="chat" aria-live="polite">
|
|
1423
|
-
${this.#
|
|
1431
|
+
${this.#J()}
|
|
1424
1432
|
</div>
|
|
1425
|
-
${this.#
|
|
1433
|
+
${this.#ce()}
|
|
1426
1434
|
`;
|
|
1427
1435
|
}
|
|
1428
|
-
#
|
|
1436
|
+
#J() {
|
|
1429
1437
|
switch (this._phase) {
|
|
1430
1438
|
case "loading":
|
|
1431
|
-
return
|
|
1439
|
+
return a`${h(S, this._loadingSlow ? "Loading the form list…" : A)}
|
|
1440
|
+
${E()}`;
|
|
1432
1441
|
case "load-error":
|
|
1433
1442
|
return a`
|
|
1434
1443
|
${h("We could not load the forms.", "Check your connection and try again.", { error: !0 })}
|
|
1435
1444
|
<div class="options">
|
|
1436
|
-
<button type="button" class="chip" @click=${() => this.#
|
|
1445
|
+
<button type="button" class="chip" @click=${() => this.#x()}>Try again</button>
|
|
1437
1446
|
</div>
|
|
1438
1447
|
`;
|
|
1439
1448
|
case "pick":
|
|
1440
|
-
return this.#
|
|
1449
|
+
return this.#X();
|
|
1441
1450
|
case "walk":
|
|
1442
|
-
return a`${this.#
|
|
1451
|
+
return a`${this.#b()}${this._typing ? E() : this.#Z()}`;
|
|
1443
1452
|
case "review":
|
|
1444
|
-
return a`${this.#
|
|
1453
|
+
return a`${this.#b()}${this.#D()}`;
|
|
1445
1454
|
case "submitting":
|
|
1446
|
-
return a`${this.#
|
|
1455
|
+
return a`${this.#b()}${this.#le()}`;
|
|
1447
1456
|
case "done":
|
|
1448
|
-
return a`${this.#
|
|
1457
|
+
return a`${this.#b()}${this.#de()}`;
|
|
1449
1458
|
default:
|
|
1450
1459
|
return c;
|
|
1451
1460
|
}
|
|
1452
1461
|
}
|
|
1453
|
-
#
|
|
1462
|
+
#X() {
|
|
1454
1463
|
const e = this._forms;
|
|
1455
1464
|
return a`
|
|
1456
|
-
${h(
|
|
1457
|
-
"Welcome to Report It. What would you like to send us?",
|
|
1458
|
-
"A few quick questions route your report to the right team."
|
|
1459
|
-
)}
|
|
1465
|
+
${h(S, A, { noAnim: !0 })}
|
|
1460
1466
|
<div class="options" role="group" aria-label="What would you like to send us?">
|
|
1461
1467
|
${e.map((t, s) => a`
|
|
1462
1468
|
<button type="button" class="chip" style="animation-delay: ${60 + s * 50}ms"
|
|
@@ -1465,15 +1471,11 @@ class rt extends A {
|
|
|
1465
1471
|
</div>
|
|
1466
1472
|
`;
|
|
1467
1473
|
}
|
|
1468
|
-
#
|
|
1474
|
+
#b() {
|
|
1469
1475
|
const e = [];
|
|
1470
|
-
this._form && (e.push(h(
|
|
1471
|
-
"Welcome to Report It. What would you like to send us?",
|
|
1472
|
-
"A few quick questions route your report to the right team.",
|
|
1473
|
-
{ noAnim: !0 }
|
|
1474
|
-
)), e.push(_(this._form.title, { noAnim: !0 }))), this._notice && e.push(h(this._notice, "", { noAnim: !0 }));
|
|
1476
|
+
this._form && (e.push(h(S, A, { noAnim: !0 })), e.push($(this._form.title, { noAnim: !0 }))), this._notice && e.push(h(this._notice, "", { noAnim: !0 }));
|
|
1475
1477
|
for (const t of this._steps) {
|
|
1476
|
-
const s =
|
|
1478
|
+
const s = b(this._form, t.nodeId);
|
|
1477
1479
|
s?.prompt && e.push(h(s.prompt, s.help, { noAnim: !0 })), s?.type === "gate" && e.push(t.anonymous ? h(
|
|
1478
1480
|
"Last step: how can we reach you?",
|
|
1479
1481
|
"You chose to send this anonymously.",
|
|
@@ -1482,21 +1484,21 @@ class rt extends A {
|
|
|
1482
1484
|
"Last step: verify your email so we can follow up.",
|
|
1483
1485
|
"One address, one code. No password needed.",
|
|
1484
1486
|
{ noAnim: !0 }
|
|
1485
|
-
)), t.kind === "choice" && e.push(
|
|
1487
|
+
)), t.kind === "choice" && e.push($(t.label || t.optionId, { noAnim: !0 })), t.kind === "collect" && e.push($(t.summary || "Details provided", { noAnim: !0 })), t.kind === "gate" && e.push($(t.anonymous ? "Send anonymously" : t.email, { noAnim: !0 }));
|
|
1486
1488
|
}
|
|
1487
1489
|
return e;
|
|
1488
1490
|
}
|
|
1489
|
-
#
|
|
1490
|
-
const { node: e, error: t } = this.#
|
|
1491
|
-
return t || !e ? h("Something went sideways with this form.", "Please start over.", { error: !0 }) : e.type === "choice" ? this.#
|
|
1491
|
+
#Z() {
|
|
1492
|
+
const { node: e, error: t } = this.#v;
|
|
1493
|
+
return t || !e ? h("Something went sideways with this form.", "Please start over.", { error: !0 }) : e.type === "choice" ? this.#ee(e) : e.type === "collect" ? this.#te(e) : e.type === "gate" ? this.#R(e) : e.type === "redirect" ? this.#oe(e) : e.type === "terminal" ? this.#D() : c;
|
|
1492
1494
|
}
|
|
1493
|
-
#
|
|
1495
|
+
#ee(e) {
|
|
1494
1496
|
return a`
|
|
1495
1497
|
${h(e.prompt, e.help)}
|
|
1496
1498
|
<div class="options" role="group" aria-label=${e.prompt || "Choose one"}>
|
|
1497
1499
|
${(e.options || []).map((t, s) => a`
|
|
1498
1500
|
<button type="button" class="chip" style="animation-delay: ${60 + s * 50}ms"
|
|
1499
|
-
@click=${() => this.#
|
|
1501
|
+
@click=${() => this.#g({
|
|
1500
1502
|
nodeId: e.id,
|
|
1501
1503
|
kind: "choice",
|
|
1502
1504
|
optionId: t.id,
|
|
@@ -1506,32 +1508,32 @@ class rt extends A {
|
|
|
1506
1508
|
</div>
|
|
1507
1509
|
`;
|
|
1508
1510
|
}
|
|
1509
|
-
#
|
|
1511
|
+
#te(e) {
|
|
1510
1512
|
const t = e.fields || [];
|
|
1511
1513
|
return a`
|
|
1512
1514
|
${h(e.prompt, e.help)}
|
|
1513
1515
|
<div class="form-card">
|
|
1514
|
-
${t.map((s) => this.#
|
|
1515
|
-
<button type="button" class="btn-primary" @click=${() => this.#
|
|
1516
|
+
${t.map((s) => this.#re(e, s))}
|
|
1517
|
+
<button type="button" class="btn-primary" @click=${() => this.#O(e)}>
|
|
1516
1518
|
Continue
|
|
1517
1519
|
</button>
|
|
1518
1520
|
</div>
|
|
1519
1521
|
`;
|
|
1520
1522
|
}
|
|
1521
|
-
#
|
|
1523
|
+
#re(e, t) {
|
|
1522
1524
|
const s = this._cardValues[t.key], i = this._fieldErrors[t.key], n = !t.required && t.kind !== "consent" ? a` <span class="opt">optional</span>` : c, o = t.kind === "consent" ? c : a`
|
|
1523
1525
|
<label for="f-${t.key}">${t.label}${n}</label>
|
|
1524
1526
|
`;
|
|
1525
1527
|
return a`
|
|
1526
1528
|
<div class="field">
|
|
1527
1529
|
${o}
|
|
1528
|
-
${this.#
|
|
1530
|
+
${this.#se(e, t, s)}
|
|
1529
1531
|
${i ? a`<div class="err" role="alert">${i}</div>` : c}
|
|
1530
1532
|
</div>
|
|
1531
1533
|
`;
|
|
1532
1534
|
}
|
|
1533
|
-
#
|
|
1534
|
-
const i = (n) => (o) => this.#
|
|
1535
|
+
#se(e, t, s) {
|
|
1536
|
+
const i = (n) => (o) => this.#_(n, o.target.value);
|
|
1535
1537
|
switch (t.kind) {
|
|
1536
1538
|
case "text":
|
|
1537
1539
|
return a`<input type="text" id="f-${t.key}" .value=${s || ""}
|
|
@@ -1555,12 +1557,12 @@ class rt extends A {
|
|
|
1555
1557
|
</select>
|
|
1556
1558
|
`;
|
|
1557
1559
|
case "location":
|
|
1558
|
-
return this.#
|
|
1560
|
+
return this.#ie(t, s || {});
|
|
1559
1561
|
case "consent":
|
|
1560
1562
|
return a`
|
|
1561
1563
|
<div class="consent-row">
|
|
1562
1564
|
<input type="checkbox" id="f-${t.key}" .checked=${s === !0}
|
|
1563
|
-
@change=${(n) => this.#
|
|
1565
|
+
@change=${(n) => this.#_(t.key, n.target.checked)}>
|
|
1564
1566
|
<label for="f-${t.key}" style="all: unset; cursor: pointer;">
|
|
1565
1567
|
I took or own this material and give WRAL permission to use it
|
|
1566
1568
|
on air and online with credit to me.
|
|
@@ -1583,8 +1585,8 @@ class rt extends A {
|
|
|
1583
1585
|
return c;
|
|
1584
1586
|
}
|
|
1585
1587
|
}
|
|
1586
|
-
#
|
|
1587
|
-
const s = e.counties ||
|
|
1588
|
+
#ie(e, t) {
|
|
1589
|
+
const s = e.counties || Ye, i = (n) => this.#_(e.key, { ...t, ...n });
|
|
1588
1590
|
return a`
|
|
1589
1591
|
<select id="f-${e.key}" aria-label="County"
|
|
1590
1592
|
@change=${(n) => i({ county: n.target.value || void 0 })}>
|
|
@@ -1601,7 +1603,7 @@ class rt extends A {
|
|
|
1601
1603
|
`;
|
|
1602
1604
|
}
|
|
1603
1605
|
#R(e) {
|
|
1604
|
-
this.#
|
|
1606
|
+
this.#E();
|
|
1605
1607
|
const t = this._gate, s = h(
|
|
1606
1608
|
"Last step: verify your email so we can follow up.",
|
|
1607
1609
|
"One address, one code. No password needed."
|
|
@@ -1615,7 +1617,7 @@ class rt extends A {
|
|
|
1615
1617
|
<button type="button" class="btn-primary"
|
|
1616
1618
|
@click=${() => this.#A(t.email)}>Continue</button>
|
|
1617
1619
|
<button type="button" class="btn-ghost"
|
|
1618
|
-
@click=${() => this.#
|
|
1620
|
+
@click=${() => this.#U()}>Use a different email</button>
|
|
1619
1621
|
</div>
|
|
1620
1622
|
` : t.stage === "email" ? a`
|
|
1621
1623
|
${s}
|
|
@@ -1632,12 +1634,12 @@ class rt extends A {
|
|
|
1632
1634
|
this._gate = { ...t, email: i.target.value };
|
|
1633
1635
|
}}
|
|
1634
1636
|
@keydown=${(i) => {
|
|
1635
|
-
i.key === "Enter" && this
|
|
1637
|
+
i.key === "Enter" && this.#$();
|
|
1636
1638
|
}}>
|
|
1637
1639
|
</div>
|
|
1638
1640
|
${t.error ? a`<div class="err" role="alert">${t.error}</div>` : c}
|
|
1639
1641
|
<button type="button" class="login-btn" ?disabled=${t.loading}
|
|
1640
|
-
@click=${() => this
|
|
1642
|
+
@click=${() => this.#$()}>
|
|
1641
1643
|
${t.loading ? "Sending…" : "Continue with email"}
|
|
1642
1644
|
</button>
|
|
1643
1645
|
<div class="login-why">
|
|
@@ -1646,12 +1648,12 @@ class rt extends A {
|
|
|
1646
1648
|
<li>We can follow up on your report</li>
|
|
1647
1649
|
<li>Your contact information fills in automatically next time</li>
|
|
1648
1650
|
<li>You are credited by name when we use your photos or video</li>
|
|
1649
|
-
<li><a href=${
|
|
1651
|
+
<li><a href=${He} target="_blank" rel="noopener">All other My WRAL account benefits</a></li>
|
|
1650
1652
|
</ul>
|
|
1651
1653
|
</div>
|
|
1652
|
-
${this._submit.stage === "auth" ? c : this.#
|
|
1654
|
+
${this._submit.stage === "auth" ? c : this.#ne()}
|
|
1653
1655
|
</div>
|
|
1654
|
-
` : t.stage === "anon-confirm" ? this.#
|
|
1656
|
+
` : t.stage === "anon-confirm" ? this.#ae(s) : a`
|
|
1655
1657
|
${s}
|
|
1656
1658
|
<div class="form-card login-card">
|
|
1657
1659
|
<h2>Enter verification code</h2>
|
|
@@ -1665,39 +1667,39 @@ class rt extends A {
|
|
|
1665
1667
|
<div class="field">
|
|
1666
1668
|
<label>Verification code</label>
|
|
1667
1669
|
<wral-code-input
|
|
1668
|
-
@code-complete=${(i) => this.#
|
|
1670
|
+
@code-complete=${(i) => this.#S(i.detail?.code ?? i.detail?.value ?? i.target.value)}>
|
|
1669
1671
|
</wral-code-input>
|
|
1670
1672
|
</div>
|
|
1671
1673
|
${t.error ? a`<div class="err" role="alert">${t.error}</div>` : c}
|
|
1672
1674
|
<button type="button" class="login-btn" ?disabled=${t.loading}
|
|
1673
1675
|
@click=${() => {
|
|
1674
1676
|
const i = this.renderRoot.querySelector("wral-code-input");
|
|
1675
|
-
this.#
|
|
1677
|
+
this.#S(i?.value || "");
|
|
1676
1678
|
}}>
|
|
1677
1679
|
${t.loading ? "Checking…" : "Sign in"}
|
|
1678
1680
|
</button>
|
|
1679
1681
|
<p class="login-help">
|
|
1680
1682
|
Didn’t receive a code? Check your spam folder or
|
|
1681
|
-
<button type="button" @click=${() => this
|
|
1683
|
+
<button type="button" @click=${() => this.#$()}>resend a new code</button>.
|
|
1682
1684
|
</p>
|
|
1683
1685
|
</div>
|
|
1684
|
-
` : a`${s}${
|
|
1686
|
+
` : a`${s}${E()}`;
|
|
1685
1687
|
}
|
|
1686
1688
|
/* Collapsed by default: findable for whoever needs it, never the
|
|
1687
1689
|
* first thing a viewer reaches for. */
|
|
1688
|
-
#
|
|
1690
|
+
#ne() {
|
|
1689
1691
|
return a`
|
|
1690
1692
|
<details class="login-alt">
|
|
1691
1693
|
<summary>Other ways to send this</summary>
|
|
1692
1694
|
<div class="alt-body">
|
|
1693
1695
|
<p class="alt-row">
|
|
1694
1696
|
Call the newsroom desk at
|
|
1695
|
-
<a href=${
|
|
1697
|
+
<a href=${Qe(W)}>${W}</a>.
|
|
1696
1698
|
</p>
|
|
1697
|
-
${this.#
|
|
1699
|
+
${this.#B ? a`
|
|
1698
1700
|
<p class="alt-row">
|
|
1699
1701
|
<button type="button" class="alt-link"
|
|
1700
|
-
@click=${() => this.#
|
|
1702
|
+
@click=${() => this.#q()}>Send this anonymously</button>
|
|
1701
1703
|
— no follow-up, and no credit if we use your photos or video.
|
|
1702
1704
|
</p>
|
|
1703
1705
|
` : c}
|
|
@@ -1705,7 +1707,7 @@ class rt extends A {
|
|
|
1705
1707
|
</details>
|
|
1706
1708
|
`;
|
|
1707
1709
|
}
|
|
1708
|
-
#
|
|
1710
|
+
#ae(e) {
|
|
1709
1711
|
return a`
|
|
1710
1712
|
${e}
|
|
1711
1713
|
<div class="form-card login-card">
|
|
@@ -1714,20 +1716,20 @@ class rt extends A {
|
|
|
1714
1716
|
You can send this report without an account. Here is what it costs you.
|
|
1715
1717
|
</p>
|
|
1716
1718
|
<ul class="anon-costs">
|
|
1717
|
-
${
|
|
1719
|
+
${Ke.map((t) => a`
|
|
1718
1720
|
<li><span class="x" aria-hidden="true">✕</span><span>${t}</span></li>
|
|
1719
1721
|
`)}
|
|
1720
1722
|
</ul>
|
|
1721
1723
|
<div class="anon-actions">
|
|
1722
1724
|
<button type="button" class="login-btn"
|
|
1723
|
-
@click=${() => this.#
|
|
1725
|
+
@click=${() => this.#L()}>Sign in instead</button>
|
|
1724
1726
|
<button type="button" class="btn-ghost"
|
|
1725
1727
|
@click=${() => this.#j()}>Continue anonymously</button>
|
|
1726
1728
|
</div>
|
|
1727
1729
|
</div>
|
|
1728
1730
|
`;
|
|
1729
1731
|
}
|
|
1730
|
-
#
|
|
1732
|
+
#oe(e) {
|
|
1731
1733
|
const t = e.redirect || {};
|
|
1732
1734
|
return a`
|
|
1733
1735
|
<div class="form-card">
|
|
@@ -1746,8 +1748,8 @@ class rt extends A {
|
|
|
1746
1748
|
</div>
|
|
1747
1749
|
`;
|
|
1748
1750
|
}
|
|
1749
|
-
#
|
|
1750
|
-
const e =
|
|
1751
|
+
#D() {
|
|
1752
|
+
const e = Pe(this._form, this._steps);
|
|
1751
1753
|
return a`
|
|
1752
1754
|
${h("Here is what you are sending.", "Check it over, then submit.")}
|
|
1753
1755
|
<div class="form-card">
|
|
@@ -1755,7 +1757,7 @@ class rt extends A {
|
|
|
1755
1757
|
${e.map((t) => a`
|
|
1756
1758
|
<li>
|
|
1757
1759
|
<span class="k">${t.k}</span>
|
|
1758
|
-
<span>${t.pill ?
|
|
1760
|
+
<span>${t.pill ? be(t.pill) : t.v}</span>
|
|
1759
1761
|
</li>
|
|
1760
1762
|
`)}
|
|
1761
1763
|
</ul>
|
|
@@ -1763,14 +1765,14 @@ class rt extends A {
|
|
|
1763
1765
|
<div class="err" role="alert" style="margin-top: 12px;">${this._banner.message}</div>
|
|
1764
1766
|
` : c}
|
|
1765
1767
|
<div style="margin-top: 16px;">
|
|
1766
|
-
<button type="button" class="btn-primary" @click=${() => this.#
|
|
1768
|
+
<button type="button" class="btn-primary" @click=${() => this.#W()}>
|
|
1767
1769
|
Submit report
|
|
1768
1770
|
</button>
|
|
1769
1771
|
</div>
|
|
1770
1772
|
</div>
|
|
1771
1773
|
`;
|
|
1772
1774
|
}
|
|
1773
|
-
#
|
|
1775
|
+
#le() {
|
|
1774
1776
|
const e = this._submit;
|
|
1775
1777
|
if (e.stage === "auth") return this.#R({ id: null, type: "gate" });
|
|
1776
1778
|
const t = {
|
|
@@ -1795,7 +1797,7 @@ class rt extends A {
|
|
|
1795
1797
|
${s.status === "done" ? "Done" : s.status === "failed" ? "Failed" : "Uploading"}
|
|
1796
1798
|
</span>
|
|
1797
1799
|
${s.status === "failed" ? a`
|
|
1798
|
-
<button type="button" class="retry-chip" @click=${() => this.#
|
|
1800
|
+
<button type="button" class="retry-chip" @click=${() => this.#H(i)}>
|
|
1799
1801
|
Retry
|
|
1800
1802
|
</button>
|
|
1801
1803
|
` : c}
|
|
@@ -1808,26 +1810,26 @@ class rt extends A {
|
|
|
1808
1810
|
${Math.ceil(this._banner.retryAfter / 60)} minutes.</div>
|
|
1809
1811
|
` : c}
|
|
1810
1812
|
<button type="button" class="btn-primary" style="margin-top: 8px;"
|
|
1811
|
-
@click=${() => this.#
|
|
1813
|
+
@click=${() => this.#G()}>Try again</button>
|
|
1812
1814
|
` : c}
|
|
1813
|
-
${
|
|
1815
|
+
${N(e).length && e.stage === "uploading-error" ? a`
|
|
1814
1816
|
<div class="err" role="alert">Retry the failed
|
|
1815
|
-
${
|
|
1817
|
+
${N(e).length === 1 ? "file" : "files"} to continue.</div>
|
|
1816
1818
|
` : c}
|
|
1817
1819
|
</div>
|
|
1818
1820
|
`;
|
|
1819
1821
|
}
|
|
1820
|
-
#
|
|
1821
|
-
const e =
|
|
1822
|
+
#de() {
|
|
1823
|
+
const e = Y(this._form, this._steps), t = Me(this._result, e), s = Ue({
|
|
1822
1824
|
routing: this._result?.routing || {},
|
|
1823
1825
|
flags: e,
|
|
1824
1826
|
reference: this._result?.reference || "",
|
|
1825
|
-
anonymous: this.#
|
|
1827
|
+
anonymous: this.#f
|
|
1826
1828
|
});
|
|
1827
1829
|
return a`
|
|
1828
1830
|
<div class="confirm-card">
|
|
1829
1831
|
<div class="c-head">
|
|
1830
|
-
<div class="c-check">${
|
|
1832
|
+
<div class="c-check">${ye()}</div>
|
|
1831
1833
|
<div>
|
|
1832
1834
|
<div class="eyebrow">Report received</div>
|
|
1833
1835
|
<h2>${t.title}</h2>
|
|
@@ -1838,7 +1840,7 @@ class rt extends A {
|
|
|
1838
1840
|
<div class="refs">
|
|
1839
1841
|
<span class="ref"><span class="rk">Reference</span>${this._result?.reference || ""}</span>
|
|
1840
1842
|
</div>
|
|
1841
|
-
<button type="button" class="c-again" @click=${() => this.#
|
|
1843
|
+
<button type="button" class="c-again" @click=${() => this.#k()}>
|
|
1842
1844
|
Start a new report
|
|
1843
1845
|
</button>
|
|
1844
1846
|
</div>
|
|
@@ -1859,15 +1861,15 @@ class rt extends A {
|
|
|
1859
1861
|
</div>
|
|
1860
1862
|
`;
|
|
1861
1863
|
}
|
|
1862
|
-
#
|
|
1864
|
+
#ce() {
|
|
1863
1865
|
const e = this._phase === "submitting" || this._phase === "done" || this._phase === "loading" || this._phase === "load-error";
|
|
1864
1866
|
return a`
|
|
1865
1867
|
<div class="bottom-bar">
|
|
1866
1868
|
<div class="inner">
|
|
1867
1869
|
<button type="button" class="btn-ghost" ?disabled=${e || this._phase === "pick"}
|
|
1868
|
-
@click=${() => this.#
|
|
1870
|
+
@click=${() => this.#M()}>← Back</button>
|
|
1869
1871
|
<button type="button" class="btn-ghost" ?disabled=${this._phase === "submitting"}
|
|
1870
|
-
@click=${() => this.#
|
|
1872
|
+
@click=${() => this.#k()}>Start over</button>
|
|
1871
1873
|
<span class="note">Your report goes to a person on the right desk.</span>
|
|
1872
1874
|
</div>
|
|
1873
1875
|
</div>
|
|
@@ -1877,7 +1879,7 @@ class rt extends A {
|
|
|
1877
1879
|
this.renderRoot?.querySelector(".chat")?.lastElementChild?.scrollIntoView?.({ block: "nearest" });
|
|
1878
1880
|
}
|
|
1879
1881
|
}
|
|
1880
|
-
class
|
|
1882
|
+
class ot extends T {
|
|
1881
1883
|
static properties = {
|
|
1882
1884
|
files: { attribute: !1 },
|
|
1883
1885
|
lostMeta: { attribute: !1 },
|
|
@@ -1926,7 +1928,7 @@ class st extends A {
|
|
|
1926
1928
|
t.splice(e, 1), this.#a(t);
|
|
1927
1929
|
}
|
|
1928
1930
|
render() {
|
|
1929
|
-
const e = this.files || [], { errors: t } =
|
|
1931
|
+
const e = this.files || [], { errors: t } = C(e, this.budget, { required: !1 });
|
|
1930
1932
|
return a`
|
|
1931
1933
|
<input type="file" multiple
|
|
1932
1934
|
accept=${this.#l || c}
|
|
@@ -1937,7 +1939,7 @@ class st extends A {
|
|
|
1937
1939
|
${e.map((s, i) => a`
|
|
1938
1940
|
<li>
|
|
1939
1941
|
<span>${s.name}</span>
|
|
1940
|
-
<span class="size">${
|
|
1942
|
+
<span class="size">${et(s.size)}</span>
|
|
1941
1943
|
<button type="button" class="remove"
|
|
1942
1944
|
aria-label="Remove ${s.name}"
|
|
1943
1945
|
@click=${() => this.#t(i)}>✕</button>
|
|
@@ -1956,15 +1958,15 @@ class st extends A {
|
|
|
1956
1958
|
`;
|
|
1957
1959
|
}
|
|
1958
1960
|
}
|
|
1959
|
-
function
|
|
1961
|
+
function et(r) {
|
|
1960
1962
|
return Number.isFinite(r) ? r >= 1024 * 1024 ? `${(r / (1024 * 1024)).toFixed(1)} MB` : r >= 1024 ? `${Math.round(r / 1024)} KB` : `${r} B` : "";
|
|
1961
1963
|
}
|
|
1962
|
-
const
|
|
1964
|
+
const tt = (r, e, t, s) => {
|
|
1963
1965
|
const i = e.target.value.replace(/\D/g, "").slice(-1), n = [...t];
|
|
1964
1966
|
n[r] = i;
|
|
1965
1967
|
const o = n.join(""), l = n.every((d) => d !== "");
|
|
1966
1968
|
return s("code-change", { value: o, complete: l }), i && l && s("code-complete", { value: o }), n;
|
|
1967
|
-
},
|
|
1969
|
+
}, rt = (r, e, t, s) => {
|
|
1968
1970
|
if (e.key === "Backspace") {
|
|
1969
1971
|
const i = [...t];
|
|
1970
1972
|
!i[r] && r > 0 ? i[r - 1] = "" : i[r] && (i[r] = "");
|
|
@@ -1972,7 +1974,7 @@ const Je = (r, e, t, s) => {
|
|
|
1972
1974
|
return s("code-change", { value: n, complete: !1 }), i;
|
|
1973
1975
|
}
|
|
1974
1976
|
return t;
|
|
1975
|
-
},
|
|
1977
|
+
}, st = (r, e, t) => {
|
|
1976
1978
|
r.preventDefault();
|
|
1977
1979
|
const s = r.clipboardData.getData("text").replace(/\D/g, "").slice(0, 6);
|
|
1978
1980
|
if (s.length === 0) return e;
|
|
@@ -1982,7 +1984,7 @@ const Je = (r, e, t, s) => {
|
|
|
1982
1984
|
const n = i.join(""), o = i.every((l) => l !== "");
|
|
1983
1985
|
return t("code-change", { value: n, complete: o }), s.length === 6 && t("code-complete", { value: n }), i;
|
|
1984
1986
|
};
|
|
1985
|
-
class
|
|
1987
|
+
class lt extends T {
|
|
1986
1988
|
static formAssociated = !0;
|
|
1987
1989
|
static properties = {
|
|
1988
1990
|
_values: { type: Array, state: !0 },
|
|
@@ -2087,7 +2089,7 @@ class it extends A {
|
|
|
2087
2089
|
this.getInputs()[e]?.focus();
|
|
2088
2090
|
}
|
|
2089
2091
|
inputHandler(e, t) {
|
|
2090
|
-
this._values =
|
|
2092
|
+
this._values = tt(
|
|
2091
2093
|
e,
|
|
2092
2094
|
t,
|
|
2093
2095
|
this._values,
|
|
@@ -2097,7 +2099,7 @@ class it extends A {
|
|
|
2097
2099
|
keydownHandler(e, t) {
|
|
2098
2100
|
if (t.key === "Backspace") {
|
|
2099
2101
|
const s = !this._values[e];
|
|
2100
|
-
this._values =
|
|
2102
|
+
this._values = rt(
|
|
2101
2103
|
e,
|
|
2102
2104
|
t,
|
|
2103
2105
|
this._values,
|
|
@@ -2106,7 +2108,7 @@ class it extends A {
|
|
|
2106
2108
|
}
|
|
2107
2109
|
}
|
|
2108
2110
|
pasteHandler(e) {
|
|
2109
|
-
this._values =
|
|
2111
|
+
this._values = st(e, this._values, this.dispatchCustomEvent.bind(this));
|
|
2110
2112
|
}
|
|
2111
2113
|
render() {
|
|
2112
2114
|
return a`
|
|
@@ -2131,10 +2133,10 @@ class it extends A {
|
|
|
2131
2133
|
}
|
|
2132
2134
|
}
|
|
2133
2135
|
export {
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2136
|
+
lt as W,
|
|
2137
|
+
ot as a,
|
|
2138
|
+
at as b,
|
|
2139
|
+
ve as c,
|
|
2140
|
+
xe as d,
|
|
2141
|
+
ke as e
|
|
2140
2142
|
};
|