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