@asteby/storefront-react 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account.cjs.map +1 -1
- package/dist/account.js +1 -1
- package/dist/checkout.cjs +74 -6
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +9 -2
- package/dist/checkout.d.ts +9 -2
- package/dist/checkout.js +74 -6
- package/dist/checkout.js.map +1 -1
- package/dist/{chunk-Q7UTJIKY.js → chunk-D5L7UZIA.js} +25 -4
- package/dist/chunk-D5L7UZIA.js.map +1 -0
- package/dist/{chunk-PPQEUTXJ.js → chunk-VE7WQPMY.js} +48 -6
- package/dist/chunk-VE7WQPMY.js.map +1 -0
- package/dist/fiscal-server.cjs.map +1 -1
- package/dist/fiscal-server.d.cts +2 -2
- package/dist/fiscal-server.d.ts +2 -2
- package/dist/fiscal-server.js +1 -1
- package/dist/fiscal.cjs +418 -17
- package/dist/fiscal.cjs.map +1 -1
- package/dist/fiscal.css +103 -0
- package/dist/fiscal.d.cts +91 -7
- package/dist/fiscal.d.ts +91 -7
- package/dist/fiscal.js +296 -18
- package/dist/fiscal.js.map +1 -1
- package/dist/{types-BnvSbV6t.d.cts → types-CZ3PleG6.d.cts} +1 -1
- package/dist/{types-BnvSbV6t.d.ts → types-CZ3PleG6.d.ts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-PPQEUTXJ.js.map +0 -1
- package/dist/chunk-Q7UTJIKY.js.map +0 -1
package/dist/fiscal.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { validateFiscalValues, regimesFor, usesFor, normalizeTaxId, entryLabel, summarizeExtraction, toInvoiceRequest, maskTaxId } from './chunk-
|
|
2
|
-
export { entryLabel, maskTaxId, normalizeTaxId, personTypeByLength, postalCodeProblem, regimesFor, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues } from './chunk-
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { personTypeResolver, validateFiscalValues, regimesFor, usesFor, normalizeTaxId, entryLabel, suggestInvoiceUse, summarizeExtraction, toInvoiceRequest, maskTaxId } from './chunk-D5L7UZIA.js';
|
|
2
|
+
export { entryLabel, maskTaxId, normalizeTaxId, personTypeByLength, personTypeFromPatterns, personTypeResolver, postalCodeProblem, regimesFor, suggestInvoiceUse, summarizeExtraction, taxIdProblem, toInvoiceRequest, usesFor, validateFiscalValues } from './chunk-D5L7UZIA.js';
|
|
3
|
+
import { useModalDialog } from './chunk-ZBH7JYU4.js';
|
|
4
|
+
import { fiscalMessages, fill } from './chunk-VE7WQPMY.js';
|
|
5
|
+
export { fiscalMessages } from './chunk-VE7WQPMY.js';
|
|
5
6
|
import { CheckoutField, ErrorSummary } from './chunk-DFGLCIEG.js';
|
|
6
7
|
import { useResolvedLocale } from './chunk-T52H5HL3.js';
|
|
7
8
|
import './chunk-DQBL2DFJ.js';
|
|
8
|
-
import { useId, useState, useRef, useEffect,
|
|
9
|
+
import { useId, useState, useMemo, useRef, useEffect, useCallback } from 'react';
|
|
9
10
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
11
|
|
|
11
12
|
var FIELDS = ["tax_id", "legal_name", "postal_code", "tax_regime", "use"];
|
|
@@ -35,7 +36,8 @@ function FiscalIdentityFields({
|
|
|
35
36
|
errors = {},
|
|
36
37
|
namePrefix = "invoice",
|
|
37
38
|
idPrefix,
|
|
38
|
-
personTypeOf,
|
|
39
|
+
personTypeOf: personTypeOverride,
|
|
40
|
+
suggestedUse,
|
|
39
41
|
disabled,
|
|
40
42
|
locale: localeProp,
|
|
41
43
|
messages,
|
|
@@ -50,6 +52,8 @@ function FiscalIdentityFields({
|
|
|
50
52
|
const base = idPrefix ?? `sf-fiscal-${reactId.replace(/:/g, "")}`;
|
|
51
53
|
const [v, setV] = useState({ ...EMPTY, ...values });
|
|
52
54
|
const [shown, setShown] = useState(/* @__PURE__ */ new Set());
|
|
55
|
+
const [autoUse, setAutoUse] = useState(null);
|
|
56
|
+
const personTypeOf = useMemo(() => personTypeResolver(region.fiscal_id, personTypeOverride), [region.fiscal_id, personTypeOverride]);
|
|
53
57
|
const root = useRef(null);
|
|
54
58
|
const valuesKey = JSON.stringify(values ?? null);
|
|
55
59
|
const first = useRef(true);
|
|
@@ -64,10 +68,17 @@ function FiscalIdentityFields({
|
|
|
64
68
|
const set = (patch) => {
|
|
65
69
|
const next = { ...v, ...patch };
|
|
66
70
|
if (patch.tax_regime !== void 0 && next.use && !usesFor(fid, next.tax_regime).some((u) => u.code === next.use)) next.use = "";
|
|
71
|
+
if (patch.tax_regime !== void 0 && !next.use) {
|
|
72
|
+
const suggestion = suggestInvoiceUse(fid, next.tax_regime);
|
|
73
|
+
if (suggestion) {
|
|
74
|
+
next.use = suggestion;
|
|
75
|
+
setAutoUse(suggestion);
|
|
76
|
+
} else setAutoUse(null);
|
|
77
|
+
} else if (patch.use !== void 0) setAutoUse(null);
|
|
67
78
|
setV(next);
|
|
68
79
|
onChange?.(next);
|
|
69
80
|
};
|
|
70
|
-
const person = personTypeOf
|
|
81
|
+
const person = personTypeOf(v.tax_id);
|
|
71
82
|
const taxIdOk = !validateFiscalValues(region, { tax_id: v.tax_id }, personTypeOf).tax_id;
|
|
72
83
|
const problems = useMemo(() => validateFiscalValues(region, v, personTypeOf), [region, v, personTypeOf]);
|
|
73
84
|
const candidates = regimeCandidates?.length ? regimeCandidates : null;
|
|
@@ -235,7 +246,12 @@ function FiscalIdentityFields({
|
|
|
235
246
|
name: name("use"),
|
|
236
247
|
id: `${base}-use`,
|
|
237
248
|
label: m.use,
|
|
238
|
-
hint:
|
|
249
|
+
hint: v.use && (v.use === autoUse || v.use === suggestedUse) ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
250
|
+
/* @__PURE__ */ jsx("span", { className: cx.mark, "data-sf-suggested": true, children: m.suggested }),
|
|
251
|
+
" ",
|
|
252
|
+
"\xB7 ",
|
|
253
|
+
m.useHint
|
|
254
|
+
] }) : m.useHint,
|
|
239
255
|
value: v.use,
|
|
240
256
|
onChange: (e) => set({ use: e.target.value }),
|
|
241
257
|
onBlur: () => touch("use"),
|
|
@@ -254,10 +270,93 @@ function FiscalIdentityFields({
|
|
|
254
270
|
)
|
|
255
271
|
] });
|
|
256
272
|
}
|
|
273
|
+
function cameraSupported() {
|
|
274
|
+
return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function";
|
|
275
|
+
}
|
|
276
|
+
function useCameraQr({ active, onCode, intervalMs = 250 }) {
|
|
277
|
+
const videoRef = useRef(null);
|
|
278
|
+
const [status, setStatus] = useState("idle");
|
|
279
|
+
const streamRef = useRef(null);
|
|
280
|
+
const onCodeRef = useRef(onCode);
|
|
281
|
+
onCodeRef.current = onCode;
|
|
282
|
+
const stop = useCallback(() => {
|
|
283
|
+
for (const track of streamRef.current?.getTracks() ?? []) track.stop();
|
|
284
|
+
streamRef.current = null;
|
|
285
|
+
const v = videoRef.current;
|
|
286
|
+
if (v) v.srcObject = null;
|
|
287
|
+
setStatus((s) => s === "denied" || s === "unsupported" ? s : "idle");
|
|
288
|
+
}, []);
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
if (!active) return;
|
|
291
|
+
if (!cameraSupported()) {
|
|
292
|
+
setStatus("unsupported");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
let cancelled = false;
|
|
296
|
+
let timer;
|
|
297
|
+
let busy = false;
|
|
298
|
+
setStatus("starting");
|
|
299
|
+
const onHidden = () => {
|
|
300
|
+
if (document.visibilityState === "hidden") stop();
|
|
301
|
+
};
|
|
302
|
+
document.addEventListener("visibilitychange", onHidden);
|
|
303
|
+
(async () => {
|
|
304
|
+
let stream;
|
|
305
|
+
try {
|
|
306
|
+
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: "environment" } }, audio: false });
|
|
307
|
+
} catch {
|
|
308
|
+
if (!cancelled) setStatus("denied");
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (cancelled) {
|
|
312
|
+
for (const t of stream.getTracks()) t.stop();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
streamRef.current = stream;
|
|
316
|
+
const video = videoRef.current;
|
|
317
|
+
if (!video) {
|
|
318
|
+
for (const t of stream.getTracks()) t.stop();
|
|
319
|
+
streamRef.current = null;
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
video.srcObject = stream;
|
|
323
|
+
video.muted = true;
|
|
324
|
+
void video.play?.().catch(() => void 0);
|
|
325
|
+
setStatus("scanning");
|
|
326
|
+
const eng = await import('@asteby/storefront/fiscal-document');
|
|
327
|
+
timer = setInterval(async () => {
|
|
328
|
+
if (busy || cancelled || !videoRef.current || videoRef.current.readyState < 2) return;
|
|
329
|
+
busy = true;
|
|
330
|
+
try {
|
|
331
|
+
const text = await eng.decodeImageQr(videoRef.current);
|
|
332
|
+
if (text && !cancelled) {
|
|
333
|
+
cancelled = true;
|
|
334
|
+
clearInterval(timer);
|
|
335
|
+
stop();
|
|
336
|
+
onCodeRef.current(text);
|
|
337
|
+
}
|
|
338
|
+
} catch {
|
|
339
|
+
} finally {
|
|
340
|
+
busy = false;
|
|
341
|
+
}
|
|
342
|
+
}, intervalMs);
|
|
343
|
+
})();
|
|
344
|
+
return () => {
|
|
345
|
+
cancelled = true;
|
|
346
|
+
if (timer) clearInterval(timer);
|
|
347
|
+
document.removeEventListener("visibilitychange", onHidden);
|
|
348
|
+
for (const t of streamRef.current?.getTracks() ?? []) t.stop();
|
|
349
|
+
streamRef.current = null;
|
|
350
|
+
if (videoRef.current) videoRef.current.srcObject = null;
|
|
351
|
+
};
|
|
352
|
+
}, [active, intervalMs, stop]);
|
|
353
|
+
return { videoRef, status, stop };
|
|
354
|
+
}
|
|
257
355
|
var isPdf = (f, accept) => {
|
|
258
356
|
const okType = f.type ? accept.some((a) => a === f.type) || f.type === "application/pdf" : false;
|
|
259
357
|
return okType || /\.pdf$/i.test(f.name);
|
|
260
358
|
};
|
|
359
|
+
var isImage = (f) => f.type.startsWith("image/") || /\.(jpe?g|png|webp|heic|heif)$/i.test(f.name);
|
|
261
360
|
var mib = (bytes) => `${Math.round(bytes / (1024 * 1024) * 10) / 10} MB`;
|
|
262
361
|
function IdentityDocumentReader(props) {
|
|
263
362
|
const { region, workerSrc, onConfirm, onManual, initialValues, data, canSave, serverUpload, personTypeOf, now, namePrefix = "invoice", messages, classNames: cx = {}, confirmLabel } = props;
|
|
@@ -289,14 +388,29 @@ function IdentityDocumentReader(props) {
|
|
|
289
388
|
useEffect(() => () => abort.current?.abort(), []);
|
|
290
389
|
useEffect(() => {
|
|
291
390
|
if (!fromServer) return;
|
|
292
|
-
setValues((cur) =>
|
|
391
|
+
setValues((cur) => {
|
|
392
|
+
const next = { ...cur, ...fromServer.values };
|
|
393
|
+
const suggestion = next.tax_regime && !next.use ? suggestInvoiceUse(region.fiscal_id, next.tax_regime) : null;
|
|
394
|
+
if (suggestion) {
|
|
395
|
+
next.use = suggestion;
|
|
396
|
+
setSuggestedUse(suggestion);
|
|
397
|
+
}
|
|
398
|
+
return next;
|
|
399
|
+
});
|
|
293
400
|
setPhase({ kind: "review", extraction: fromServer, revision: 1 });
|
|
294
401
|
}, [fromServer]);
|
|
295
402
|
useEffect(() => {
|
|
296
403
|
if (phase.kind === "error") errorRef.current?.focus();
|
|
297
404
|
if (phase.kind === "review" && phase.revision > 0) reviewRef.current?.focus();
|
|
298
405
|
}, [phase]);
|
|
299
|
-
const accept = useMemo(() =>
|
|
406
|
+
const accept = useMemo(() => {
|
|
407
|
+
const files = (spec?.accept ?? []).filter((a) => !a.startsWith("image/"));
|
|
408
|
+
return files.length ? files.join(",") : "application/pdf";
|
|
409
|
+
}, [spec]);
|
|
410
|
+
const imageMode = spec?.image_mode && spec.image_mode !== "none" ? spec.image_mode : null;
|
|
411
|
+
const photoInput = useRef(null);
|
|
412
|
+
const [suggestedUse, setSuggestedUse] = useState(null);
|
|
413
|
+
const cameraActive = phase.kind === "camera";
|
|
300
414
|
const fieldErrors = useMemo(() => {
|
|
301
415
|
const out = {};
|
|
302
416
|
for (const [k, v] of Object.entries(data?.fieldErrors ?? {})) out[k] = all.server.errors[v] ?? v;
|
|
@@ -313,9 +427,70 @@ function IdentityDocumentReader(props) {
|
|
|
313
427
|
setPhase({ kind: "review", extraction: null, revision: 1 });
|
|
314
428
|
setLive("");
|
|
315
429
|
}, [onManual]);
|
|
430
|
+
const showExtraction = useCallback(
|
|
431
|
+
(sum) => {
|
|
432
|
+
const base = { tax_id: "", legal_name: "", postal_code: "", tax_regime: "", use: "", ...sum.values };
|
|
433
|
+
const suggestion = base.tax_regime ? suggestInvoiceUse(region.fiscal_id, base.tax_regime) : null;
|
|
434
|
+
if (suggestion && !base.use) base.use = suggestion;
|
|
435
|
+
setSuggestedUse(suggestion && base.use === suggestion ? suggestion : null);
|
|
436
|
+
setValues(base);
|
|
437
|
+
setSummary(null);
|
|
438
|
+
setPhase({ kind: "review", extraction: sum, revision: 1 });
|
|
439
|
+
setLive(m.done);
|
|
440
|
+
},
|
|
441
|
+
[region.fiscal_id, m.done]
|
|
442
|
+
);
|
|
443
|
+
const readQr = useCallback(
|
|
444
|
+
async (text) => {
|
|
445
|
+
if (!spec) return;
|
|
446
|
+
if (!text) return setPhase({ kind: "error", code: "no_qr" });
|
|
447
|
+
const eng = await import('@asteby/storefront/fiscal-document');
|
|
448
|
+
const x = eng.extractIdentityDocument("", spec, {
|
|
449
|
+
catalogs: region.fiscal_id ? eng.catalogsFromRegion(region.fiscal_id) : {},
|
|
450
|
+
qr: text,
|
|
451
|
+
...now ? { now: now() } : {}
|
|
452
|
+
});
|
|
453
|
+
if (!x.fields.tax_id) return setPhase({ kind: "error", code: "no_qr" });
|
|
454
|
+
const evidence = eng.buildDocumentEvidence(x, { sha256: null, source: "qr" });
|
|
455
|
+
showExtraction(summarizeExtraction(x, evidence, region.fiscal_id?.regimes.map((r) => r.code)));
|
|
456
|
+
},
|
|
457
|
+
[spec, region, now, showExtraction]
|
|
458
|
+
);
|
|
459
|
+
const readImage = useCallback(
|
|
460
|
+
async (file) => {
|
|
461
|
+
if (!spec) return;
|
|
462
|
+
if (file.size > spec.max_bytes) return setPhase({ kind: "error", code: "too_large", sizeLimit: spec.max_bytes });
|
|
463
|
+
const ctl = new AbortController();
|
|
464
|
+
abort.current = ctl;
|
|
465
|
+
setPhase({ kind: "reading", fileName: file.name });
|
|
466
|
+
setLive(fill(m.reading, { document: documentName }));
|
|
467
|
+
try {
|
|
468
|
+
const eng = await import('@asteby/storefront/fiscal-document');
|
|
469
|
+
const text = await eng.decodeImageQr(file, { maxBytes: spec.max_bytes, signal: ctl.signal });
|
|
470
|
+
if (ctl.signal.aborted) return;
|
|
471
|
+
await readQr(text);
|
|
472
|
+
} catch (err) {
|
|
473
|
+
if (ctl.signal.aborted) return;
|
|
474
|
+
const code = err?.code;
|
|
475
|
+
setLive("");
|
|
476
|
+
setPhase({ kind: "error", code: code === "too_large" ? "too_large" : code === "not_image" ? "not_image" : "unreadable", sizeLimit: spec.max_bytes });
|
|
477
|
+
} finally {
|
|
478
|
+
if (abort.current === ctl) abort.current = null;
|
|
479
|
+
if (photoInput.current) photoInput.current.value = "";
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
[spec, documentName, m.reading, readQr]
|
|
483
|
+
);
|
|
484
|
+
const camera = useCameraQr({
|
|
485
|
+
active: cameraActive,
|
|
486
|
+
onCode: (text) => {
|
|
487
|
+
void readQr(text).then(() => setLive(`${m.scan.cameraRead}. ${m.done}`)).catch(() => setPhase({ kind: "error", code: "unreadable" }));
|
|
488
|
+
}
|
|
489
|
+
});
|
|
316
490
|
const read = useCallback(
|
|
317
491
|
async (file) => {
|
|
318
492
|
if (!spec) return;
|
|
493
|
+
if (imageMode && isImage(file)) return readImage(file);
|
|
319
494
|
if (!isPdf(file, spec.accept ?? [])) return setPhase({ kind: "error", code: "not_pdf" });
|
|
320
495
|
if (file.size > spec.max_bytes) return setPhase({ kind: "error", code: "too_large", sizeLimit: spec.max_bytes });
|
|
321
496
|
const ctl = new AbortController();
|
|
@@ -340,10 +515,7 @@ function IdentityDocumentReader(props) {
|
|
|
340
515
|
});
|
|
341
516
|
const evidence = eng.buildDocumentEvidence(x, { sha256, source: "pdf_client" });
|
|
342
517
|
const sum = summarizeExtraction(x, evidence, region.fiscal_id?.regimes.map((r) => r.code));
|
|
343
|
-
|
|
344
|
-
setSummary(null);
|
|
345
|
-
setPhase({ kind: "review", extraction: sum, revision: 1 });
|
|
346
|
-
setLive(m.done);
|
|
518
|
+
showExtraction(sum);
|
|
347
519
|
} catch (err) {
|
|
348
520
|
if (ctl.signal.aborted) return;
|
|
349
521
|
const code = err?.code;
|
|
@@ -358,7 +530,7 @@ function IdentityDocumentReader(props) {
|
|
|
358
530
|
if (fileInput.current) fileInput.current.value = "";
|
|
359
531
|
}
|
|
360
532
|
},
|
|
361
|
-
[spec, workerSrc, region, now, documentName, m.reading,
|
|
533
|
+
[spec, workerSrc, region, now, documentName, m.reading, imageMode, readImage, showExtraction]
|
|
362
534
|
);
|
|
363
535
|
if (!spec) return null;
|
|
364
536
|
const onDrop = (e) => {
|
|
@@ -368,7 +540,7 @@ function IdentityDocumentReader(props) {
|
|
|
368
540
|
if (f) void read(f);
|
|
369
541
|
};
|
|
370
542
|
const confirm = () => {
|
|
371
|
-
const problems = validateFiscalValues(region, values, personTypeOf);
|
|
543
|
+
const problems = validateFiscalValues(region, values, personTypeResolver(region.fiscal_id, personTypeOf));
|
|
372
544
|
const keys = Object.keys(problems);
|
|
373
545
|
if (keys.length) {
|
|
374
546
|
const labels = {
|
|
@@ -433,6 +605,27 @@ function IdentityDocumentReader(props) {
|
|
|
433
605
|
]
|
|
434
606
|
}
|
|
435
607
|
),
|
|
608
|
+
imageMode ? /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-scan": true, children: [
|
|
609
|
+
/* @__PURE__ */ jsx(
|
|
610
|
+
"input",
|
|
611
|
+
{
|
|
612
|
+
ref: photoInput,
|
|
613
|
+
type: "file",
|
|
614
|
+
accept: "image/*",
|
|
615
|
+
capture: "environment",
|
|
616
|
+
hidden: true,
|
|
617
|
+
tabIndex: -1,
|
|
618
|
+
"aria-label": m.scan.photo,
|
|
619
|
+
"data-sf-reader-photo-input": true,
|
|
620
|
+
onChange: (e) => {
|
|
621
|
+
const f = e.target.files?.[0];
|
|
622
|
+
if (f) void readImage(f);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
),
|
|
626
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => photoInput.current?.click(), "data-sf-reader-photo": true, children: m.scan.photo }),
|
|
627
|
+
hydrated && cameraSupported() ? /* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => setPhase({ kind: "camera" }), "data-sf-reader-camera": true, children: m.scan.camera }) : null
|
|
628
|
+
] }) : null,
|
|
436
629
|
/* @__PURE__ */ jsx("p", { id: helpId, className: cx.privacy, "data-sf-reader-privacy": true, children: privacy }),
|
|
437
630
|
serverUpload ? /* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("button", { type: "submit", name: "intent", value: "extract-document", formEncType: "multipart/form-data", formMethod: "post", formNoValidate: true, className: cx.secondary, "data-sf-reader-upload": true, children: m.uploadServer }) }) : null,
|
|
438
631
|
/* @__PURE__ */ jsxs("p", { "data-sf-reader-links": true, children: [
|
|
@@ -449,6 +642,48 @@ function IdentityDocumentReader(props) {
|
|
|
449
642
|
] }),
|
|
450
643
|
/* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: cancel, "data-sf-reader-cancel": true, children: m.cancel })
|
|
451
644
|
] });
|
|
645
|
+
const cameraView = phase.kind === "camera" && /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-reader": true, "data-state": "camera", children: [
|
|
646
|
+
/* @__PURE__ */ jsx("h3", { "data-sf-reader-title": true, children: m.scan.cameraTitle }),
|
|
647
|
+
/* @__PURE__ */ jsxs("div", { "data-sf-reader-viewfinder": true, children: [
|
|
648
|
+
/* @__PURE__ */ jsx("video", { ref: camera.videoRef, playsInline: true, muted: true, "aria-label": m.scan.cameraGuide, "data-sf-reader-video": true }),
|
|
649
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", "data-sf-reader-frame": true })
|
|
650
|
+
] }),
|
|
651
|
+
/* @__PURE__ */ jsx("p", { className: cx.status, "data-sf-reader-camera-status": camera.status, children: camera.status === "denied" ? m.scan.cameraDenied : camera.status === "unsupported" ? m.scan.cameraUnavailable : camera.status === "starting" ? m.scan.cameraStarting : m.scan.cameraGuide }),
|
|
652
|
+
/* @__PURE__ */ jsx("p", { className: cx.privacy, "data-sf-reader-privacy": true, children: privacy }),
|
|
653
|
+
/* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-actions": true, children: [
|
|
654
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: cx.secondary, onClick: () => photoInput.current?.click(), "data-sf-reader-photo": true, children: m.scan.choosePhoto }),
|
|
655
|
+
/* @__PURE__ */ jsx(
|
|
656
|
+
"button",
|
|
657
|
+
{
|
|
658
|
+
type: "button",
|
|
659
|
+
className: cx.primary,
|
|
660
|
+
onClick: () => {
|
|
661
|
+
camera.stop();
|
|
662
|
+
setPhase({ kind: "idle" });
|
|
663
|
+
},
|
|
664
|
+
"data-sf-reader-camera-close": true,
|
|
665
|
+
children: m.scan.closeCamera
|
|
666
|
+
}
|
|
667
|
+
)
|
|
668
|
+
] }),
|
|
669
|
+
/* @__PURE__ */ jsx(
|
|
670
|
+
"input",
|
|
671
|
+
{
|
|
672
|
+
ref: photoInput,
|
|
673
|
+
type: "file",
|
|
674
|
+
accept: "image/*",
|
|
675
|
+
capture: "environment",
|
|
676
|
+
hidden: true,
|
|
677
|
+
tabIndex: -1,
|
|
678
|
+
"aria-label": m.scan.choosePhoto,
|
|
679
|
+
"data-sf-reader-photo-input": true,
|
|
680
|
+
onChange: (e) => {
|
|
681
|
+
const f = e.target.files?.[0];
|
|
682
|
+
if (f) void readImage(f);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
)
|
|
686
|
+
] });
|
|
452
687
|
const errored = phase.kind === "error" && /* @__PURE__ */ jsxs("div", { className: cx.root, "data-sf-reader": true, "data-state": "error", children: [
|
|
453
688
|
/* @__PURE__ */ jsx("div", { ref: errorRef, role: "alert", tabIndex: -1, className: cx.error, "data-sf-reader-error": phase.code, children: fill(m.errors[phase.code], { size: mib(phase.sizeLimit ?? spec.max_bytes) }) }),
|
|
454
689
|
/* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-reader-actions": true, children: [
|
|
@@ -481,6 +716,7 @@ function IdentityDocumentReader(props) {
|
|
|
481
716
|
fromDocument: phase.extraction?.from_document ?? [],
|
|
482
717
|
documentName,
|
|
483
718
|
regimeCandidates: phase.extraction && phase.extraction.regime_candidates.length > 1 ? phase.extraction.regime_candidates : void 0,
|
|
719
|
+
suggestedUse,
|
|
484
720
|
...personTypeOf ? { personTypeOf } : {},
|
|
485
721
|
locale,
|
|
486
722
|
...messages ? { messages } : {},
|
|
@@ -508,6 +744,7 @@ function IdentityDocumentReader(props) {
|
|
|
508
744
|
/* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: cx.status, "data-sf-reader-live": true, style: visuallyHidden, children: live }),
|
|
509
745
|
phase.kind === "idle" ? idle : null,
|
|
510
746
|
reading || null,
|
|
747
|
+
cameraView || null,
|
|
511
748
|
errored || null,
|
|
512
749
|
review || null
|
|
513
750
|
] });
|
|
@@ -517,7 +754,8 @@ function Warnings({ x, m, cx }) {
|
|
|
517
754
|
const items = [];
|
|
518
755
|
if (x.qr_match === false) items.push(m.warnings.qrMismatch);
|
|
519
756
|
if (x.stale === true && x.age_days !== null) items.push(fill(m.warnings.stale, { days: x.age_days }));
|
|
520
|
-
if (x.
|
|
757
|
+
if (x.evidence.source === "qr") items.push(m.warnings.qrPartial);
|
|
758
|
+
else if (x.regime_candidates.length === 0 && !x.values.tax_regime) items.push(m.warnings.regimeMissing);
|
|
521
759
|
else if (x.missing.some((k) => k !== "tax_regime" && k !== "document_id" && k !== "issued_on")) items.push(m.warnings.fieldsMissing);
|
|
522
760
|
if (!items.length) return null;
|
|
523
761
|
return /* @__PURE__ */ jsx("ul", { className: cx.warning, "data-sf-reader-warnings": true, children: items.map((t) => /* @__PURE__ */ jsxs("li", { "data-sf-reader-warning": true, children: [
|
|
@@ -525,6 +763,46 @@ function Warnings({ x, m, cx }) {
|
|
|
525
763
|
t
|
|
526
764
|
] }, t)) });
|
|
527
765
|
}
|
|
766
|
+
function ScanTaxDocument(props) {
|
|
767
|
+
const { onConfirm, onManual, classNames: cx = {}, messages, confirmLabel, ...reader } = props;
|
|
768
|
+
const locale = useResolvedLocale(props.locale);
|
|
769
|
+
const m = fiscalMessages(locale, messages).reader;
|
|
770
|
+
const spec = props.document ?? props.region.fiscal_id?.documents?.[0];
|
|
771
|
+
const [open, setOpen] = useState(false);
|
|
772
|
+
const titleId = useId();
|
|
773
|
+
const { ref, onBackdropClick } = useModalDialog({ open, onClose: () => setOpen(false) });
|
|
774
|
+
const opener = useRef(null);
|
|
775
|
+
if (!spec) return null;
|
|
776
|
+
const name = props.documentName ?? spec.label.toLowerCase();
|
|
777
|
+
return /* @__PURE__ */ jsxs("div", { className: cx.actions, "data-sf-scan": true, children: [
|
|
778
|
+
/* @__PURE__ */ jsx("button", { ref: opener, type: "button", className: cx.trigger ?? cx.primary, onClick: () => setOpen(true), "aria-haspopup": "dialog", "data-sf-scan-open": true, children: fill(m.scan.open, { document: spec.label }) }),
|
|
779
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: cx.manual ?? cx.secondary, onClick: onManual, "data-sf-scan-manual": true, children: m.scan.manual }),
|
|
780
|
+
open ? /* @__PURE__ */ jsx("dialog", { ref, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, onClick: onBackdropClick, onClose: () => setOpen(false), className: cx.sheet, "data-sf-scan-sheet": true, children: /* @__PURE__ */ jsxs("div", { className: cx.sheetPanel, "data-sf-scan-panel": true, children: [
|
|
781
|
+
/* @__PURE__ */ jsxs("div", { className: cx.sheetHeader, "data-sf-scan-header": true, children: [
|
|
782
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, className: cx.sheetTitle, "data-sf-scan-title": true, children: fill(m.scan.title, { document: name }) }),
|
|
783
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: cx.sheetClose, onClick: () => setOpen(false), "aria-label": m.scan.close, "data-sf-scan-close": true, "data-sf-autofocus": true, children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2715" }) })
|
|
784
|
+
] }),
|
|
785
|
+
/* @__PURE__ */ jsx(
|
|
786
|
+
IdentityDocumentReader,
|
|
787
|
+
{
|
|
788
|
+
...reader,
|
|
789
|
+
locale,
|
|
790
|
+
...messages ? { messages } : {},
|
|
791
|
+
...confirmLabel ? { confirmLabel } : {},
|
|
792
|
+
classNames: cx,
|
|
793
|
+
onConfirm: (result) => {
|
|
794
|
+
setOpen(false);
|
|
795
|
+
onConfirm(result);
|
|
796
|
+
},
|
|
797
|
+
onManual: () => {
|
|
798
|
+
setOpen(false);
|
|
799
|
+
onManual();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
] }) }) : null
|
|
804
|
+
] });
|
|
805
|
+
}
|
|
528
806
|
var profileValues = (p) => ({
|
|
529
807
|
tax_id: p.tax_id,
|
|
530
808
|
legal_name: p.legal_name,
|
|
@@ -847,6 +1125,6 @@ var ICON = {
|
|
|
847
1125
|
cancelled: "\xD7"
|
|
848
1126
|
};
|
|
849
1127
|
|
|
850
|
-
export { FiscalIdentityFields, IdentityDocumentReader, InvoiceStatusCard, InvoiceToggle, invoiceCardState };
|
|
1128
|
+
export { FiscalIdentityFields, IdentityDocumentReader, InvoiceStatusCard, InvoiceToggle, ScanTaxDocument, cameraSupported, invoiceCardState, useCameraQr };
|
|
851
1129
|
//# sourceMappingURL=fiscal.js.map
|
|
852
1130
|
//# sourceMappingURL=fiscal.js.map
|