@isi-ui7/bos7-shared 0.4.0 → 0.4.2
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/form-renderer-utils.d.ts +11 -0
- package/dist/{index-C_114Ysm.js → index-DqWPV29B.js} +71 -71
- package/dist/{index.es-B-MluT1E.js → index.es-9cvhYbjn.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{jspdf.es.min-C5VEsLZd.js → jspdf.es.min-CCBzPHw4.js} +2 -2
- package/dist/{jspdf.plugin.autotable-DcntYaes.js → jspdf.plugin.autotable-DFaknRns.js} +19 -22
- package/dist/purify.es-Cm3utOpm.js +560 -0
- package/package.json +6 -6
- package/src/date-and-hidden-validation.test.ts +43 -1
- package/src/date-field-render.test.tsx +83 -0
- package/src/form-renderer-utils.ts +34 -0
- package/src/form-renderer.tsx +7 -2
- package/dist/purify.es-CiEWEeUM.js +0 -605
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { SchemaFormRenderer } from "./form-renderer";
|
|
5
|
+
import type { FormSection } from "./form-types";
|
|
6
|
+
|
|
7
|
+
type D = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
// Laporan DG-00 (agent7, 2026-08-31): field "date" di form-renderer.tsx punya
|
|
10
|
+
// DUA cacat. Cacat B (TERBUKTI + DIPERBAIKI di sini): `value={asString(rawValue)}`
|
|
11
|
+
// mengirim string ISO mentah ke DatePicker Carbon (flatpickr) yang
|
|
12
|
+
// dikonfigurasi dateFormat="d-m-Y", jadi flatpickr mem-parse ULANG string ISO
|
|
13
|
+
// itu SEOLAH ia format d-m-Y — tanggal TERSIMPAN tampil SALAH saat re-render.
|
|
14
|
+
// Diperbaiki dgn `fromLocalISODate()` (Date, bukan string) di form-renderer.tsx.
|
|
15
|
+
//
|
|
16
|
+
// Cacat A (diklaim DG-00 dari fiber React browser sungguhan: tanggal yg
|
|
17
|
+
// DIKETIK nol pernah masuk state) — TIDAK bisa direproduksi di tes terisolasi
|
|
18
|
+
// ini, bahkan pada kode SEBELUM perbaikan (lihat ledger dg-05 2026-08-31):
|
|
19
|
+
// `allowInput` Carbon versi ini SUDAH default `true` (DatePicker.js:377,
|
|
20
|
+
// `allowInput ?? true`), dan `fireEvent.blur` mengonfirmasi commit-on-blur
|
|
21
|
+
// bekerja di kedua kode lama & baru. Tes di bawah HANYA membuktikan alur
|
|
22
|
+
// commit bekerja di form-renderer terisolasi — ia BUKAN bukti Cacat A sudah
|
|
23
|
+
// tuntas di halaman produksi (mungkin bergantung interaksi re-render field
|
|
24
|
+
// lain yg tak tercakup harness minimal ini). Perlu re-verifikasi Tester/
|
|
25
|
+
// DG-00 langsung di browser thd kode yg sudah diperbaiki.
|
|
26
|
+
|
|
27
|
+
const dateSection: FormSection<D> = {
|
|
28
|
+
title: "Tanggal",
|
|
29
|
+
fields: [{ key: "tanggal_lahir", label: "Tanggal Lahir", type: "date", span: 4 }],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
describe("field date — re-render dari value tersimpan (Cacat B)", () => {
|
|
33
|
+
it("ISO tersimpan tampil sbg tanggal yg SAMA dlm format d-m-Y, bukan digeser", () => {
|
|
34
|
+
render(
|
|
35
|
+
<SchemaFormRenderer<D>
|
|
36
|
+
mode="edit"
|
|
37
|
+
value={{ tanggal_lahir: "1990-06-15" }}
|
|
38
|
+
sections={[dateSection]}
|
|
39
|
+
onChange={() => {}}
|
|
40
|
+
/>,
|
|
41
|
+
);
|
|
42
|
+
const input = screen.getByLabelText("Tanggal Lahir") as HTMLInputElement;
|
|
43
|
+
// Harus 15-06-1990 (hari yg SAMA, cuma beda format tampilan) — BUKAN
|
|
44
|
+
// tanggal lain hasil salah-parse "1990-06-15" seolah format d-m-Y.
|
|
45
|
+
expect(input.value).toBe("15-06-1990");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("kontrol: tanggal akhir-tahun tetap utuh (bukan kebetulan lolos di satu kasus)", () => {
|
|
49
|
+
render(
|
|
50
|
+
<SchemaFormRenderer<D>
|
|
51
|
+
mode="edit"
|
|
52
|
+
value={{ tanggal_lahir: "2026-12-31" }}
|
|
53
|
+
sections={[dateSection]}
|
|
54
|
+
onChange={() => {}}
|
|
55
|
+
/>,
|
|
56
|
+
);
|
|
57
|
+
const input = screen.getByLabelText("Tanggal Lahir") as HTMLInputElement;
|
|
58
|
+
expect(input.value).toBe("31-12-2026");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("field date — ketik tangan lalu commit (Cacat A)", () => {
|
|
63
|
+
it("tanggal yg DIKETIK (bukan dipilih dari kalender) masuk ke onChange", async () => {
|
|
64
|
+
const user = userEvent.setup();
|
|
65
|
+
const onChange = vi.fn();
|
|
66
|
+
|
|
67
|
+
render(
|
|
68
|
+
<SchemaFormRenderer<D>
|
|
69
|
+
mode="create"
|
|
70
|
+
value={{}}
|
|
71
|
+
sections={[dateSection]}
|
|
72
|
+
onChange={onChange}
|
|
73
|
+
/>,
|
|
74
|
+
);
|
|
75
|
+
const input = screen.getByLabelText("Tanggal Lahir") as HTMLInputElement;
|
|
76
|
+
await user.type(input, "15-06-1990");
|
|
77
|
+
fireEvent.blur(input); // commit alami operator (pindah fokus keluar kotak)
|
|
78
|
+
|
|
79
|
+
const patches = onChange.mock.calls.map((c) => c[0]);
|
|
80
|
+
const got = patches.find((p) => p?.tanggal_lahir);
|
|
81
|
+
expect(got?.tanggal_lahir).toBe("1990-06-15");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -185,3 +185,37 @@ export function toLocalISODate(date: Date | undefined | null): string {
|
|
|
185
185
|
const d = String(date.getDate()).padStart(2, "0");
|
|
186
186
|
return `${y}-${m}-${d}`;
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Kebalikan `toLocalISODate` — mem-parse "YYYY-MM-DD" jadi `Date` lokal
|
|
191
|
+
* (bukan `new Date(iso)` yang mem-parse sbg UTC dan bisa menggeser sehari,
|
|
192
|
+
* kelas bug yang sama dgn di atas, arah terbalik).
|
|
193
|
+
*
|
|
194
|
+
* Dipakai supaya prop `value` DatePicker Carbon menerima `Date`, BUKAN
|
|
195
|
+
* string ISO mentah — string ISO yang diberikan ke DatePicker dgn
|
|
196
|
+
* `dateFormat="d-m-Y"` di-parse ULANG flatpickr SEOLAH ia format d-m-Y,
|
|
197
|
+
* menghasilkan tanggal lain sama sekali (laporan DG-00, agent7 2026-08-31).
|
|
198
|
+
*/
|
|
199
|
+
export function fromLocalISODate(iso: string | undefined | null): Date | undefined {
|
|
200
|
+
if (!iso) return undefined;
|
|
201
|
+
// Regex TIDAK ber-akhiran `$` dengan sengaja: field "date" (bukan
|
|
202
|
+
// "datetime") menerima "YYYY-MM-DD" polos MAUPUN RFC3339 penuh
|
|
203
|
+
// ("2029-12-31T00:00:00Z" atau ber-offset) — keduanya nyata dikirim
|
|
204
|
+
// backend, tergantung tipe kolom Go di sisi server (time.Time vs string
|
|
205
|
+
// yang sudah diformat). Sebelum perbaikan ini, RFC3339 gagal match diam-
|
|
206
|
+
// diam dan DatePicker menerima `undefined` — field tampak KOSONG tanpa
|
|
207
|
+
// satu pun galat (laporan PM, ditemukan lewat verifikasi browser
|
|
208
|
+
// sungguhan atas core7-service-cif FT-573/574, 2026-08-31).
|
|
209
|
+
//
|
|
210
|
+
// Ambil HANYA digit tanggalnya, JANGAN `new Date(iso)` — itu persis bug
|
|
211
|
+
// asli yang diperbaiki lewat fungsi ini (lihat komentar di atas):
|
|
212
|
+
// `new Date("2029-12-31T00:00:00Z")` mem-parse sbg UTC, dan di zona
|
|
213
|
+
// timur UTC (WIB) itu bisa MUNDUR sehari. Regex + konstruktor
|
|
214
|
+
// komponen-lokal di bawah membaca digitnya apa adanya, sama seperti
|
|
215
|
+
// jalur "YYYY-MM-DD" polos.
|
|
216
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
|
|
217
|
+
if (!m) return undefined;
|
|
218
|
+
const [, y, mo, d] = m;
|
|
219
|
+
const date = new Date(Number(y), Number(mo) - 1, Number(d));
|
|
220
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
221
|
+
}
|
package/src/form-renderer.tsx
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
import type { Ui7FormDensity, Ui7FormWidth } from "./style-contract";
|
|
34
34
|
import { useBosSharedI18n } from "./i18n";
|
|
35
35
|
import type { FormField, FormMode, FormSection } from "./form-types";
|
|
36
|
-
import { toLocalISODate } from "./form-renderer-utils";
|
|
36
|
+
import { toLocalISODate, fromLocalISODate } from "./form-renderer-utils";
|
|
37
37
|
import { DetailModalField } from "./detail-modal-field";
|
|
38
38
|
|
|
39
39
|
export type SchemaFormRendererProps<TData extends Record<string, unknown>> = {
|
|
@@ -847,7 +847,12 @@ export function SchemaFormRenderer<TData extends Record<string, unknown>>({
|
|
|
847
847
|
// DISIMPAN tetap ISO. Dua hal berbeda: yang satu untuk
|
|
848
848
|
// dibaca manusia, yang satu kontrak dgn backend.
|
|
849
849
|
dateFormat="d-m-Y"
|
|
850
|
-
value
|
|
850
|
+
// `value` HARUS `Date`, bukan string ISO — string ISO
|
|
851
|
+
// di sini di-parse ULANG flatpickr seolah format
|
|
852
|
+
// tampilan (d-m-Y), menghasilkan tanggal lain sama
|
|
853
|
+
// sekali pada setiap re-render (laporan DG-00,
|
|
854
|
+
// agent7 2026-08-31, kena SEMUA field tanggal).
|
|
855
|
+
value={fromLocalISODate(asString(rawValue))}
|
|
851
856
|
onChange={([date]) =>
|
|
852
857
|
setValue(field.key, toLocalISODate(date) as TData[keyof TData])
|
|
853
858
|
}
|