@flowselections/floriday-voorraad 1.0.110 → 1.0.115
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-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +63 -7
- package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FustenPage.js +10 -6
- package/dist-lib/components/voorraad/PriceStatusBadge.d.ts.map +1 -1
- package/dist-lib/components/voorraad/PriceStatusBadge.js +6 -1
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts +5 -0
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/PublishProgressCard.js +16 -1
- package/dist-lib/components/voorraad/VoorraadPage.d.ts +13 -0
- package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadPage.js +36 -54
- package/dist-lib/hooks/useNoPriceProducts.d.ts +10 -0
- package/dist-lib/hooks/useNoPriceProducts.d.ts.map +1 -0
- package/dist-lib/hooks/useNoPriceProducts.js +56 -0
- package/dist-lib/hooks/useStockPushJobs.d.ts.map +1 -1
- package/dist-lib/hooks/useStockPushJobs.js +6 -1
- package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
- package/dist-lib/hooks/useStockSyncHealth.js +2 -9
- package/dist-lib/hooks/useVoorraadData.d.ts.map +1 -1
- package/dist-lib/hooks/useVoorraadData.js +45 -24
- package/dist-lib/integrations/supabase/types.d.ts +818 -122
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/__tests__/fust-dimensions.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/fust-dimensions.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/fust-dimensions.test.js +27 -0
- package/dist-lib/lib/__tests__/publish-114.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/publish-114.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/publish-114.test.js +31 -0
- package/dist-lib/lib/__tests__/request-guard.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/request-guard.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/request-guard.test.js +50 -0
- package/dist-lib/lib/fusten.d.ts +14 -3
- package/dist-lib/lib/fusten.d.ts.map +1 -1
- package/dist-lib/lib/fusten.js +38 -7
- package/dist-lib/lib/publish-errors.d.ts +6 -1
- package/dist-lib/lib/publish-errors.d.ts.map +1 -1
- package/dist-lib/lib/publish-errors.js +22 -2
- package/dist-lib/lib/request-guard.d.ts +46 -0
- package/dist-lib/lib/request-guard.d.ts.map +1 -0
- package/dist-lib/lib/request-guard.js +100 -0
- package/package.json +1 -1
- package/sql/floriday-voorraad-schema.sql +186 -27
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fust-dimensions.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/fust-dimensions.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
vi.mock("../../integrations/supabase/client", () => ({ supabase: {} }));
|
|
3
|
+
import { customPackageDimsOf, resolveFustDimensions } from "../fusten.js";
|
|
4
|
+
const fc = new Map([["18", { name: "Trayrand", lengthMm: 560, widthMm: 250, heightMm: 170 }]]);
|
|
5
|
+
const cp = new Map([["cp-1", { lengthMm: 400, widthMm: 300, heightMm: 120 }]]);
|
|
6
|
+
const base = { vbn_code: null, custom_package_id: null, length_mm: null, width_mm: null, height_mm: null };
|
|
7
|
+
describe("fustmaten: Floricode → Floriday custom package → handmatig → leeg", () => {
|
|
8
|
+
it("Floricode wint", () => {
|
|
9
|
+
const r = resolveFustDimensions({ ...base, vbn_code: 18, custom_package_id: "cp-1", length_mm: 1 }, fc, cp);
|
|
10
|
+
expect(r).toEqual({ length_mm: 560, width_mm: 250, height_mm: 170, source: "floricode" });
|
|
11
|
+
});
|
|
12
|
+
it("anders custom package", () => {
|
|
13
|
+
const r = resolveFustDimensions({ ...base, custom_package_id: "cp-1", length_mm: 1 }, fc, cp);
|
|
14
|
+
expect(r).toEqual({ length_mm: 400, width_mm: 300, height_mm: 120, source: "floriday" });
|
|
15
|
+
});
|
|
16
|
+
it("anders handmatig", () => {
|
|
17
|
+
const r = resolveFustDimensions({ ...base, custom_package_id: "onbekend", length_mm: 7 }, fc, cp);
|
|
18
|
+
expect(r.source).toBe("handmatig");
|
|
19
|
+
expect(r.length_mm).toBe(7);
|
|
20
|
+
});
|
|
21
|
+
it("anders leeg, nooit standaardwaarden", () => {
|
|
22
|
+
expect(resolveFustDimensions(base, fc, cp)).toEqual({ length_mm: null, width_mm: null, height_mm: null, source: "onbekend" });
|
|
23
|
+
});
|
|
24
|
+
it("leest mm uit data.dimensions", () => {
|
|
25
|
+
expect(customPackageDimsOf({ dimensions: { length: 400, width: 0, height: "120" } })).toEqual({ lengthMm: 400, widthMm: null, heightMm: 120 });
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-114.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/publish-114.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { translatePublishError } from "../publish-errors.js";
|
|
3
|
+
import { effectiveJobStatus } from "../../components/voorraad/PublishProgressCard.js";
|
|
4
|
+
import { countStock } from "../../components/voorraad/VoorraadPage.js";
|
|
5
|
+
describe("1.0.114 publiceren en telling", () => {
|
|
6
|
+
it("toont de echte reden als de poort schrijven tegenhoudt", () => {
|
|
7
|
+
const f = translatePublishError(new Error("publishTradeItem: gateway /api/public/gateway/write → Tegengehouden door poort: in de Floriday-kopie wijkt de verpakking af van Floriday."));
|
|
8
|
+
expect(f.code).toBe("GATE_BLOCKED");
|
|
9
|
+
expect(f.message).toContain("wijkt de verpakking af");
|
|
10
|
+
});
|
|
11
|
+
it("onbekende fout toont de technische reden", () => {
|
|
12
|
+
const f = translatePublishError(new Error("stap x → iets raars"));
|
|
13
|
+
expect(f.message).toContain("iets raars");
|
|
14
|
+
});
|
|
15
|
+
it("job blijft niet op bezig na mislukte productstap", () => {
|
|
16
|
+
expect(effectiveJobStatus("running", [
|
|
17
|
+
{ status: "failed", step_key: "trade-item" },
|
|
18
|
+
{ status: "pending", step_key: "stock" },
|
|
19
|
+
])).toBe("failed");
|
|
20
|
+
expect(effectiveJobStatus("running", [{ status: "running", step_key: "trade-item" }])).toBe("running");
|
|
21
|
+
});
|
|
22
|
+
it("volledig gereserveerd telt als op voorraad", () => {
|
|
23
|
+
const c = countStock([
|
|
24
|
+
{ quantity: 100, availableQuantity: 0, minQuantity: 0 },
|
|
25
|
+
{ quantity: 0, availableQuantity: 0, minQuantity: 0 },
|
|
26
|
+
]);
|
|
27
|
+
expect(c.inStock).toBe(1);
|
|
28
|
+
expect(c.outOfStock).toBe(1);
|
|
29
|
+
expect(c.fullyReserved).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-guard.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/request-guard.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createBundler, createRequestGuard } from "../request-guard.js";
|
|
3
|
+
describe("request guard", () => {
|
|
4
|
+
it("staat 30 aanvragen in 10 s toe en stopt de 31e", () => {
|
|
5
|
+
let t = 0;
|
|
6
|
+
const g = createRequestGuard(30, 10000, () => t);
|
|
7
|
+
const err = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
8
|
+
for (let i = 0; i < 30; i++)
|
|
9
|
+
expect(g.allow("products")).toBe(true);
|
|
10
|
+
expect(g.allow("products")).toBe(false);
|
|
11
|
+
expect(g.trips()[0].table).toBe("products");
|
|
12
|
+
expect(g.allow("trade_item_stock")).toBe(true);
|
|
13
|
+
err.mockRestore();
|
|
14
|
+
});
|
|
15
|
+
it("telt alleen binnen het venster", () => {
|
|
16
|
+
let t = 0;
|
|
17
|
+
const g = createRequestGuard(30, 10000, () => t);
|
|
18
|
+
for (let i = 0; i < 30; i++)
|
|
19
|
+
g.allow("products");
|
|
20
|
+
t = 10001;
|
|
21
|
+
expect(g.allow("products")).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("bundler", () => {
|
|
25
|
+
it("10 seintjes binnen 2 s geven 1 herlaadactie", () => {
|
|
26
|
+
vi.useFakeTimers();
|
|
27
|
+
const run = vi.fn();
|
|
28
|
+
const b = createBundler(run, 2000, { isHidden: () => false });
|
|
29
|
+
for (let i = 0; i < 10; i++)
|
|
30
|
+
b.trigger();
|
|
31
|
+
vi.advanceTimersByTime(1999);
|
|
32
|
+
expect(run).toHaveBeenCalledTimes(1);
|
|
33
|
+
vi.useRealTimers();
|
|
34
|
+
});
|
|
35
|
+
it("verborgen tabblad: 0 herlaadacties, bij terugkeren 1", () => {
|
|
36
|
+
vi.useFakeTimers();
|
|
37
|
+
let hidden = true;
|
|
38
|
+
const run = vi.fn();
|
|
39
|
+
const b = createBundler(run, 2000, { isHidden: () => hidden });
|
|
40
|
+
for (let i = 0; i < 5; i++)
|
|
41
|
+
b.trigger();
|
|
42
|
+
vi.advanceTimersByTime(10000);
|
|
43
|
+
expect(run).toHaveBeenCalledTimes(0);
|
|
44
|
+
hidden = false;
|
|
45
|
+
b.flushIfPending();
|
|
46
|
+
vi.advanceTimersByTime(0);
|
|
47
|
+
expect(run).toHaveBeenCalledTimes(1);
|
|
48
|
+
vi.useRealTimers();
|
|
49
|
+
});
|
|
50
|
+
});
|
package/dist-lib/lib/fusten.d.ts
CHANGED
|
@@ -56,9 +56,20 @@ interface VbnCatalogEntry {
|
|
|
56
56
|
* (eigenaar Floriday-authenticatie). Lege maten blijven null.
|
|
57
57
|
*/
|
|
58
58
|
export declare function fetchFloricodeFustMap(): Promise<Map<string, VbnCatalogEntry>>;
|
|
59
|
-
export type FustDimensionSource = "floricode" | "handmatig" | "onbekend";
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
export type FustDimensionSource = "floricode" | "floriday" | "handmatig" | "onbekend";
|
|
60
|
+
export interface CustomPackageDims {
|
|
61
|
+
lengthMm: number | null;
|
|
62
|
+
widthMm: number | null;
|
|
63
|
+
heightMm: number | null;
|
|
64
|
+
}
|
|
65
|
+
/** Maten uit een Floriday custom package (data van floriday_packings_cache), in mm. */
|
|
66
|
+
export declare function customPackageDimsOf(data: any): CustomPackageDims;
|
|
67
|
+
/** Eigen fusten (Floriday custom packages) per floriday_id. */
|
|
68
|
+
export declare function fetchFloridayCustomPackageMap(): Promise<Map<string, CustomPackageDims>>;
|
|
69
|
+
/** Floricode → Floriday custom package → handmatig → leeg. Nooit standaardwaarden (gelijk aan voorraad_fust_dimensions). */
|
|
70
|
+
export declare function resolveFustDimensions(fust: Pick<FustType, "vbn_code" | "length_mm" | "width_mm" | "height_mm"> & {
|
|
71
|
+
custom_package_id?: string | null;
|
|
72
|
+
}, floricode: Map<string, VbnCatalogEntry> | null, customPackages?: Map<string, CustomPackageDims> | null): {
|
|
62
73
|
length_mm: number | null;
|
|
63
74
|
width_mm: number | null;
|
|
64
75
|
height_mm: number | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fusten.d.ts","sourceRoot":"","sources":["../../src/lib/fusten.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,CAAC,EAAE;IACtC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,MAAM,GAAG,IAAI,CAIhB;AAMD,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,MAAM,GAAG,IAAI,CAO9E;AA8DD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAenF;AAQD,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"fusten.d.ts","sourceRoot":"","sources":["../../src/lib/fusten.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,CAAC,EAAE;IACtC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,MAAM,GAAG,IAAI,CAIhB;AAMD,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,GAAG,MAAM,GAAG,IAAI,CAO9E;AA8DD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAenF;AAQD,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,GAAG,GAAG,iBAAiB,CAOhE;AAED,+DAA+D;AAC/D,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAW7F;AAED,4HAA4H;AAC5H,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG;IAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACjH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,EAC9C,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,GACrD;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAmB9G;AAWD,sEAAsE;AACtE,wBAAsB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAwCxF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAUvF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAgGD;AAED,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,OAAO,CACb,IAAI,CACF,QAAQ,EACR,MAAM,GAAG,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAC5E,CACF,GACA,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,KAAK,SAAK,GACT,OAAO,CAAC,YAAY,EAAE,CAAC,CASzB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ChB"}
|
package/dist-lib/lib/fusten.js
CHANGED
|
@@ -114,15 +114,42 @@ function positiveOrNull(v) {
|
|
|
114
114
|
const n = Number(v);
|
|
115
115
|
return Number.isFinite(n) && n > 0 ? Math.round(n) : null;
|
|
116
116
|
}
|
|
117
|
-
/**
|
|
118
|
-
export function
|
|
117
|
+
/** Maten uit een Floriday custom package (data van floriday_packings_cache), in mm. */
|
|
118
|
+
export function customPackageDimsOf(data) {
|
|
119
|
+
const d = data?.dimensions ?? data?.dimension ?? {};
|
|
120
|
+
return {
|
|
121
|
+
lengthMm: positiveOrNull(d.length ?? data?.lengthMm ?? data?.length),
|
|
122
|
+
widthMm: positiveOrNull(d.width ?? data?.widthMm ?? data?.width),
|
|
123
|
+
heightMm: positiveOrNull(d.height ?? data?.heightMm ?? data?.height),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Eigen fusten (Floriday custom packages) per floriday_id. */
|
|
127
|
+
export async function fetchFloridayCustomPackageMap() {
|
|
128
|
+
const map = new Map();
|
|
129
|
+
const { data, error } = await supabase
|
|
130
|
+
.from("floriday_packings_cache")
|
|
131
|
+
.select("floriday_id,data")
|
|
132
|
+
.eq("is_deleted", false);
|
|
133
|
+
if (error)
|
|
134
|
+
throw new Error(error.message);
|
|
135
|
+
for (const r of (data ?? [])) {
|
|
136
|
+
if (r?.floriday_id)
|
|
137
|
+
map.set(String(r.floriday_id), customPackageDimsOf(r.data));
|
|
138
|
+
}
|
|
139
|
+
return map;
|
|
140
|
+
}
|
|
141
|
+
/** Floricode → Floriday custom package → handmatig → leeg. Nooit standaardwaarden (gelijk aan voorraad_fust_dimensions). */
|
|
142
|
+
export function resolveFustDimensions(fust, floricode, customPackages) {
|
|
119
143
|
const fc = fust.vbn_code != null ? floricode?.get(String(fust.vbn_code)) : undefined;
|
|
120
|
-
|
|
144
|
+
const cp = fust.custom_package_id ? customPackages?.get(fust.custom_package_id) : undefined;
|
|
145
|
+
const has = (x) => !!x && (x.lengthMm != null || x.widthMm != null || x.heightMm != null);
|
|
146
|
+
const pick = (k, m) => fc?.[k] ?? cp?.[k] ?? fust[m] ?? null;
|
|
147
|
+
if (has(fc) || has(cp)) {
|
|
121
148
|
return {
|
|
122
|
-
length_mm:
|
|
123
|
-
width_mm:
|
|
124
|
-
height_mm:
|
|
125
|
-
source: "floricode",
|
|
149
|
+
length_mm: pick("lengthMm", "length_mm"),
|
|
150
|
+
width_mm: pick("widthMm", "width_mm"),
|
|
151
|
+
height_mm: pick("heightMm", "height_mm"),
|
|
152
|
+
source: has(fc) ? "floricode" : "floriday",
|
|
126
153
|
};
|
|
127
154
|
}
|
|
128
155
|
if (fust.length_mm != null || fust.width_mm != null || fust.height_mm != null) {
|
|
@@ -188,6 +215,8 @@ export async function fetchFustTypes(_connectionId) {
|
|
|
188
215
|
.from("fust_types")
|
|
189
216
|
.select("*")
|
|
190
217
|
.is("connection_id", null)
|
|
218
|
+
// Samengevoegde rijen (voorraad_correctie_1112) blijven bewaard maar tellen niet mee.
|
|
219
|
+
.is("merged_into", null)
|
|
191
220
|
.order("name");
|
|
192
221
|
if (error)
|
|
193
222
|
throw new Error(error.message);
|
|
@@ -341,6 +370,7 @@ export async function registerSaleFustUsage(params) {
|
|
|
341
370
|
.select("id")
|
|
342
371
|
.eq("fust_key", key)
|
|
343
372
|
.is("connection_id", null)
|
|
373
|
+
.is("merged_into", null)
|
|
344
374
|
.limit(1);
|
|
345
375
|
let fustTypeId = (data ?? [])[0]?.id;
|
|
346
376
|
if (!fustTypeId) {
|
|
@@ -350,6 +380,7 @@ export async function registerSaleFustUsage(params) {
|
|
|
350
380
|
.select("id")
|
|
351
381
|
.eq("fust_key", key)
|
|
352
382
|
.is("connection_id", null)
|
|
383
|
+
.is("merged_into", null)
|
|
353
384
|
.limit(1);
|
|
354
385
|
fustTypeId = (retry ?? [])[0]?.id;
|
|
355
386
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Woorden als API, gateway, Floriday-intern jargon en modulenamen komen hier
|
|
7
7
|
* bewust niet in voor.
|
|
8
8
|
*/
|
|
9
|
-
export type PublishErrorCode = "MISSING_CHARACTERISTICS" | "NO_CONNECTION" | "WRONG_ENVIRONMENT" | "NOT_LOGGED_IN" | "INVALID_VALUE" | "DUPLICATE" | "NOT_FOUND" | "TEMPORARY" | "TIMEOUT" | "RATE_LIMIT" | "UNKNOWN";
|
|
9
|
+
export type PublishErrorCode = "MISSING_CHARACTERISTICS" | "NO_CONNECTION" | "WRONG_ENVIRONMENT" | "NOT_LOGGED_IN" | "INVALID_VALUE" | "DUPLICATE" | "NOT_FOUND" | "TEMPORARY" | "TIMEOUT" | "RATE_LIMIT" | "GATE_BLOCKED" | "UNKNOWN";
|
|
10
10
|
export interface PublishErrorAction {
|
|
11
11
|
label: string;
|
|
12
12
|
/** Interne route waar de gebruiker het kan oplossen. */
|
|
@@ -34,4 +34,9 @@ export declare function translatePublishError(error: unknown, opts?: {
|
|
|
34
34
|
characteristicLabels?: Record<string, string>;
|
|
35
35
|
}): FriendlyPublishError;
|
|
36
36
|
export declare function friendlyFieldName(field?: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Haalt de leesbare reden uit een technische foutketen
|
|
39
|
+
* ("stap: route → reden") zodat de gebruiker altijd de echte oorzaak ziet.
|
|
40
|
+
*/
|
|
41
|
+
export declare function realReason(raw: string): string;
|
|
37
42
|
//# sourceMappingURL=publish-errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-errors.d.ts","sourceRoot":"","sources":["../../src/lib/publish-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,gBAAgB,GACxB,yBAAyB,GACzB,eAAe,GACf,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,SAAS,GACT,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAIR;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvD,oBAAoB,
|
|
1
|
+
{"version":3,"file":"publish-errors.d.ts","sourceRoot":"","sources":["../../src/lib/publish-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,gBAAgB,GACxB,yBAAyB,GACzB,eAAe,GACf,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,SAAS,GACT,YAAY,GACZ,cAAc,GACd,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAIR;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvD,oBAAoB,CAoJtB;AAgBD,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxD;AAaD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9C"}
|
|
@@ -140,10 +140,20 @@ export function translatePublishError(error, opts) {
|
|
|
140
140
|
detail: raw,
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
+
// Floriday-auth houdt schrijven tegen (floriday_write_mode read_only): toon de echte reden.
|
|
144
|
+
if (lower.includes("tegengehouden door poort") || lower.includes("blocked_by_gate")) {
|
|
145
|
+
return {
|
|
146
|
+
code: "GATE_BLOCKED",
|
|
147
|
+
message: `Floriday-koppeling houdt versturen tegen: ${realReason(raw)}`,
|
|
148
|
+
hint: "Los het verschil op bij Floriday koppeling → Verpakking en probeer opnieuw. Je ingevoerde gegevens zijn bewaard.",
|
|
149
|
+
retryable: false,
|
|
150
|
+
detail: raw,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
143
153
|
return {
|
|
144
154
|
code: "UNKNOWN",
|
|
145
|
-
message: "Het publiceren is niet gelukt.",
|
|
146
|
-
hint: "Probeer het opnieuw.
|
|
155
|
+
message: raw ? `Het publiceren is niet gelukt: ${realReason(raw)}` : "Het publiceren is niet gelukt.",
|
|
156
|
+
hint: "Probeer het opnieuw. Je ingevoerde gegevens zijn bewaard.",
|
|
147
157
|
retryable: false,
|
|
148
158
|
detail: raw,
|
|
149
159
|
};
|
|
@@ -181,3 +191,13 @@ function stepForFieldName(field) {
|
|
|
181
191
|
return "vbn";
|
|
182
192
|
return "artikel";
|
|
183
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Haalt de leesbare reden uit een technische foutketen
|
|
196
|
+
* ("stap: route → reden") zodat de gebruiker altijd de echte oorzaak ziet.
|
|
197
|
+
*/
|
|
198
|
+
export function realReason(raw) {
|
|
199
|
+
const parts = raw.split("→");
|
|
200
|
+
const last = (parts[parts.length - 1] ?? raw).trim();
|
|
201
|
+
const text = last.replace(/^[a-zA-Z]+:\s*/, "").trim() || raw.trim();
|
|
202
|
+
return text.length > 300 ? `${text.slice(0, 297)}…` : text;
|
|
203
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bewaking tegen opvraag-lussen en bundeling van herlaadacties.
|
|
3
|
+
* - Teller per tabel: meer dan MAX aanvragen binnen het venster → die tabel stopt
|
|
4
|
+
* (tot de pagina opnieuw geopend wordt), met console-melding en een regel voor
|
|
5
|
+
* "Details voor beheer".
|
|
6
|
+
* - Bundelaar: hooguit één uitvoering per interval; in een verborgen tabblad wordt
|
|
7
|
+
* alleen onthouden dat er iets veranderd is, en bij terugkeren één keer uitgevoerd.
|
|
8
|
+
*/
|
|
9
|
+
export declare const GUARD_MAX = 30;
|
|
10
|
+
export declare const GUARD_WINDOW_MS = 10000;
|
|
11
|
+
/** Minimaal interval voor periodieke opvragingen op de voorraadpagina. */
|
|
12
|
+
export declare const MIN_POLL_MS = 15000;
|
|
13
|
+
export type GuardTrip = {
|
|
14
|
+
table: string;
|
|
15
|
+
at: number;
|
|
16
|
+
count: number;
|
|
17
|
+
};
|
|
18
|
+
export declare function createRequestGuard(max?: number, windowMs?: number, now?: () => number): {
|
|
19
|
+
/** true = aanvraag mag; false = geblokkeerd. */
|
|
20
|
+
allow(table: string): boolean;
|
|
21
|
+
trips(): GuardTrip[];
|
|
22
|
+
subscribe(l: () => void): () => void;
|
|
23
|
+
reset(): void;
|
|
24
|
+
};
|
|
25
|
+
/** Eén bewaker per geopende pagina (module-instantie in de browser). */
|
|
26
|
+
export declare const pageRequestGuard: {
|
|
27
|
+
/** true = aanvraag mag; false = geblokkeerd. */
|
|
28
|
+
allow(table: string): boolean;
|
|
29
|
+
trips(): GuardTrip[];
|
|
30
|
+
subscribe(l: () => void): () => void;
|
|
31
|
+
reset(): void;
|
|
32
|
+
};
|
|
33
|
+
export declare function isTabHidden(): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Bundelt aanroepen: hooguit één `run` per `intervalMs`. Verborgen tabblad → uitgesteld
|
|
36
|
+
* tot `flushIfPending()` (bij terugkeren naar het tabblad).
|
|
37
|
+
*/
|
|
38
|
+
export declare function createBundler(run: () => void, intervalMs: number, opts?: {
|
|
39
|
+
isHidden?: () => boolean;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
}): {
|
|
42
|
+
trigger(): void;
|
|
43
|
+
flushIfPending(): void;
|
|
44
|
+
cancel(): void;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=request-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-guard.d.ts","sourceRoot":"","sources":["../../src/lib/request-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,eAAe,QAAS,CAAC;AACtC,0EAA0E;AAC1E,eAAO,MAAM,WAAW,QAAS,CAAC;AAElC,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,wBAAgB,kBAAkB,CAAC,GAAG,SAAY,EAAE,QAAQ,SAAkB,EAAE,GAAG,eAAmB;IAMlG,gDAAgD;iBACnC,MAAM,GAAG,OAAO;aAkBpB,SAAS,EAAE;iBAGP,MAAM,IAAI;;EAa1B;AAED,wEAAwE;AACxE,eAAO,MAAM,gBAAgB;IAtCzB,gDAAgD;iBACnC,MAAM,GAAG,OAAO;aAkBpB,SAAS,EAAE;iBAGP,MAAM,IAAI;;CAgByB,CAAC;AAErD,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,IAAI,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO;;;;EAmC5D"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bewaking tegen opvraag-lussen en bundeling van herlaadacties.
|
|
3
|
+
* - Teller per tabel: meer dan MAX aanvragen binnen het venster → die tabel stopt
|
|
4
|
+
* (tot de pagina opnieuw geopend wordt), met console-melding en een regel voor
|
|
5
|
+
* "Details voor beheer".
|
|
6
|
+
* - Bundelaar: hooguit één uitvoering per interval; in een verborgen tabblad wordt
|
|
7
|
+
* alleen onthouden dat er iets veranderd is, en bij terugkeren één keer uitgevoerd.
|
|
8
|
+
*/
|
|
9
|
+
export const GUARD_MAX = 30;
|
|
10
|
+
export const GUARD_WINDOW_MS = 10000;
|
|
11
|
+
/** Minimaal interval voor periodieke opvragingen op de voorraadpagina. */
|
|
12
|
+
export const MIN_POLL_MS = 15000;
|
|
13
|
+
export function createRequestGuard(max = GUARD_MAX, windowMs = GUARD_WINDOW_MS, now = () => Date.now()) {
|
|
14
|
+
const hits = new Map();
|
|
15
|
+
const tripped = new Map();
|
|
16
|
+
const listeners = new Set();
|
|
17
|
+
let snapshot = [];
|
|
18
|
+
return {
|
|
19
|
+
/** true = aanvraag mag; false = geblokkeerd. */
|
|
20
|
+
allow(table) {
|
|
21
|
+
if (tripped.has(table))
|
|
22
|
+
return false;
|
|
23
|
+
const t = now();
|
|
24
|
+
const arr = (hits.get(table) ?? []).filter((x) => t - x < windowMs);
|
|
25
|
+
arr.push(t);
|
|
26
|
+
hits.set(table, arr);
|
|
27
|
+
if (arr.length > max) {
|
|
28
|
+
const trip = { table, at: t, count: arr.length };
|
|
29
|
+
tripped.set(table, trip);
|
|
30
|
+
snapshot = [...tripped.values()];
|
|
31
|
+
console.error(`[voorraad] Opvragingen naar "${table}" gestopt: ${arr.length} aanvragen in ${windowMs / 1000} s. Open de pagina opnieuw.`);
|
|
32
|
+
listeners.forEach((l) => l());
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
},
|
|
37
|
+
trips() {
|
|
38
|
+
return snapshot;
|
|
39
|
+
},
|
|
40
|
+
subscribe(l) {
|
|
41
|
+
listeners.add(l);
|
|
42
|
+
return () => {
|
|
43
|
+
listeners.delete(l);
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
reset() {
|
|
47
|
+
hits.clear();
|
|
48
|
+
tripped.clear();
|
|
49
|
+
snapshot = [];
|
|
50
|
+
listeners.forEach((l) => l());
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Eén bewaker per geopende pagina (module-instantie in de browser). */
|
|
55
|
+
export const pageRequestGuard = createRequestGuard();
|
|
56
|
+
export function isTabHidden() {
|
|
57
|
+
return typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Bundelt aanroepen: hooguit één `run` per `intervalMs`. Verborgen tabblad → uitgesteld
|
|
61
|
+
* tot `flushIfPending()` (bij terugkeren naar het tabblad).
|
|
62
|
+
*/
|
|
63
|
+
export function createBundler(run, intervalMs, opts = {}) {
|
|
64
|
+
const isHidden = opts.isHidden ?? isTabHidden;
|
|
65
|
+
const now = opts.now ?? (() => Date.now());
|
|
66
|
+
let last = -Infinity;
|
|
67
|
+
let timer = null;
|
|
68
|
+
let pending = false;
|
|
69
|
+
const fire = () => {
|
|
70
|
+
timer = null;
|
|
71
|
+
if (isHidden()) {
|
|
72
|
+
pending = true;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
pending = false;
|
|
76
|
+
last = now();
|
|
77
|
+
run();
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
trigger() {
|
|
81
|
+
if (isHidden()) {
|
|
82
|
+
pending = true;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (timer)
|
|
86
|
+
return;
|
|
87
|
+
const wait = Math.max(0, last + intervalMs - now());
|
|
88
|
+
timer = setTimeout(fire, wait);
|
|
89
|
+
},
|
|
90
|
+
flushIfPending() {
|
|
91
|
+
if (pending && !isHidden())
|
|
92
|
+
this.trigger();
|
|
93
|
+
},
|
|
94
|
+
cancel() {
|
|
95
|
+
if (timer)
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
timer = null;
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|