@asdp/ferryui 0.1.22-dev.8893 → 0.1.22-dev.8898

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/index.js CHANGED
@@ -7873,6 +7873,24 @@ var DEFAULT_LABELS22 = {
7873
7873
  idTypeOtherPlaceholder: "DD/MM/YYYY",
7874
7874
  countryLabel: "Negara Penerbit Passport",
7875
7875
  countryPlaceholder: "Masukkan Negara",
7876
+ autofill: "Isi Data Otomatis",
7877
+ // Scan Identity
7878
+ selectIdTypeTitle: "Isi Data Dengan Scan Identitas",
7879
+ scanIdentityTitle: "Scan Identitas",
7880
+ scanInstructions1: "Posisikan kartu identitas Anda di dalam bingkai.",
7881
+ scanInstructions2: "Pastikan foto terlihat jelas dan tidak buram.",
7882
+ readingData: "Membaca data dari foto...",
7883
+ nameRead: "Nama berhasil dibaca",
7884
+ idNumberRead: "Nomor identitas berhasil dibaca",
7885
+ cityRead: "Kota berhasil dibaca",
7886
+ scanUnreadable: "Hasil scan tidak terbaca",
7887
+ photoNotClear: "Tulisan pada foto tidak terlihat jelas.",
7888
+ retakeAdvice: "Coba ambil ulang foto dengan pencahayaan yang lebih baik.",
7889
+ retakeButton: "Ambil Ulang",
7890
+ manualInputButton: "Input Manual",
7891
+ cancelScanButton: "Batal",
7892
+ savePhotoButton: "Simpan Foto",
7893
+ cameraPermissionError: "Tidak dapat mengakses kamera. Pastikan Anda memberikan izin akses kamera.",
7876
7894
  errors: {
7877
7895
  requiredTitle: "Title harus dipilih",
7878
7896
  requiredName: "Nama lengkap harus diisi",
@@ -7911,6 +7929,24 @@ var DEFAULT_LABELS22 = {
7911
7929
  idTypeOtherPlaceholder: "DD/MM/YYYY",
7912
7930
  countryLabel: "Country of Issue",
7913
7931
  countryPlaceholder: "Enter Country",
7932
+ autofill: "Autofill",
7933
+ // Scan Identity
7934
+ selectIdTypeTitle: "Fill Data by Scanning Identity",
7935
+ scanIdentityTitle: "Scan Identity",
7936
+ scanInstructions1: "Position your identity card within the frame.",
7937
+ scanInstructions2: "Make sure the photo is clear and not blurry.",
7938
+ readingData: "Reading data from photo...",
7939
+ nameRead: "Name read successfully",
7940
+ idNumberRead: "Identity number read successfully",
7941
+ cityRead: "City read successfully",
7942
+ scanUnreadable: "Scan result is unreadable",
7943
+ photoNotClear: "The text on the photo is not clear.",
7944
+ retakeAdvice: "Try retaking the photo with better lighting.",
7945
+ retakeButton: "Retake",
7946
+ manualInputButton: "Manual Input",
7947
+ cancelScanButton: "Cancel",
7948
+ savePhotoButton: "Save Photo",
7949
+ cameraPermissionError: "Cannot access camera. Please make sure you have granted camera permission.",
7914
7950
  errors: {
7915
7951
  requiredTitle: "Title is required",
7916
7952
  requiredName: "Full name is required",
@@ -7961,6 +7997,152 @@ var useStyles22 = reactComponents.makeStyles({
7961
7997
  gap: "1rem",
7962
7998
  justifyContent: "flex-end",
7963
7999
  marginTop: "1rem"
8000
+ },
8001
+ closeButton: {
8002
+ minWidth: "32px",
8003
+ minHeight: "32px"
8004
+ },
8005
+ idTypeList: {
8006
+ display: "flex",
8007
+ flexDirection: "column"
8008
+ },
8009
+ idTypeItem: {
8010
+ display: "flex",
8011
+ alignItems: "center",
8012
+ justifyContent: "space-between",
8013
+ padding: "1rem 0",
8014
+ cursor: "pointer"
8015
+ },
8016
+ idTypeText: {
8017
+ fontSize: reactComponents.tokens.fontSizeBase300,
8018
+ fontWeight: reactComponents.tokens.fontWeightRegular
8019
+ },
8020
+ // Scan Identity styles
8021
+ scanSurface: {
8022
+ width: "520px"
8023
+ },
8024
+ scannerWrapper: {
8025
+ position: "relative",
8026
+ width: "100%",
8027
+ height: "280px",
8028
+ overflow: "hidden",
8029
+ backgroundColor: "#2f2f2f",
8030
+ marginTop: "30px",
8031
+ marginBottom: "30px"
8032
+ },
8033
+ videoElement: {
8034
+ width: "100%",
8035
+ height: "100%",
8036
+ objectFit: "cover"
8037
+ },
8038
+ scanOverlay: {
8039
+ position: "absolute",
8040
+ top: 0,
8041
+ left: 0,
8042
+ right: 0,
8043
+ bottom: 0,
8044
+ pointerEvents: "none"
8045
+ },
8046
+ darkOverlay: {
8047
+ position: "absolute",
8048
+ background: "rgba(0, 0, 0, 0.6)"
8049
+ },
8050
+ overlayTop: {
8051
+ top: 0,
8052
+ left: 0,
8053
+ right: 0,
8054
+ height: "10px"
8055
+ },
8056
+ overlayBottom: {
8057
+ bottom: 0,
8058
+ left: 0,
8059
+ right: 0,
8060
+ height: "10px"
8061
+ },
8062
+ overlayLeft: {
8063
+ top: "10px",
8064
+ left: 0,
8065
+ width: "10px",
8066
+ bottom: "10px"
8067
+ },
8068
+ overlayRight: {
8069
+ top: "10px",
8070
+ right: 0,
8071
+ width: "10px",
8072
+ bottom: "10px"
8073
+ },
8074
+ scanFrame: {
8075
+ position: "absolute",
8076
+ top: "10px",
8077
+ left: "10px",
8078
+ right: "10px",
8079
+ bottom: "10px",
8080
+ border: "3px solid rgba(255, 255, 255, 0.9)",
8081
+ borderRadius: "8px"
8082
+ },
8083
+ corner: {
8084
+ position: "absolute",
8085
+ width: "30px",
8086
+ height: "30px",
8087
+ border: "4px solid white"
8088
+ },
8089
+ cornerTopLeft: {
8090
+ top: "-2px",
8091
+ left: "-2px",
8092
+ borderRight: "none",
8093
+ borderBottom: "none",
8094
+ borderTopLeftRadius: "8px"
8095
+ },
8096
+ cornerTopRight: {
8097
+ top: "-2px",
8098
+ right: "-2px",
8099
+ borderLeft: "none",
8100
+ borderBottom: "none",
8101
+ borderTopRightRadius: "8px"
8102
+ },
8103
+ cornerBottomLeft: {
8104
+ bottom: "-2px",
8105
+ left: "-2px",
8106
+ borderRight: "none",
8107
+ borderTop: "none",
8108
+ borderBottomLeftRadius: "8px"
8109
+ },
8110
+ cornerBottomRight: {
8111
+ bottom: "-2px",
8112
+ right: "-2px",
8113
+ borderLeft: "none",
8114
+ borderTop: "none",
8115
+ borderBottomRightRadius: "8px"
8116
+ },
8117
+ scanLine: {
8118
+ position: "absolute",
8119
+ top: 0,
8120
+ left: 0,
8121
+ right: 0,
8122
+ height: "2px",
8123
+ background: "linear-gradient(90deg, transparent, #0be6e6, transparent)",
8124
+ animationName: {
8125
+ from: { top: "0" },
8126
+ to: { top: "100%" }
8127
+ },
8128
+ animationDuration: "2s",
8129
+ animationTimingFunction: "linear",
8130
+ animationIterationCount: "infinite"
8131
+ },
8132
+ checklistItem: {
8133
+ display: "flex",
8134
+ alignItems: "center",
8135
+ gap: "14px"
8136
+ },
8137
+ spin: {
8138
+ display: "inline-flex",
8139
+ animationName: {
8140
+ from: { transform: "rotate(0deg)" },
8141
+ to: { transform: "rotate(360deg)" }
8142
+ },
8143
+ animationDuration: "1s",
8144
+ animationTimingFunction: "linear",
8145
+ animationIterationCount: "infinite"
7964
8146
  }
7965
8147
  });
7966
8148
  var ModalPassengerForm = ({
@@ -7974,7 +8156,8 @@ var ModalPassengerForm = ({
7974
8156
  isAdultForm = true,
7975
8157
  titleOptions,
7976
8158
  cityOptions,
7977
- ticketClassOptions
8159
+ ticketClassOptions,
8160
+ onScanComplete
7978
8161
  }) => {
7979
8162
  const styles = useStyles22();
7980
8163
  const mergedLabels = { ...DEFAULT_LABELS22[language], ...labels };
@@ -7983,6 +8166,15 @@ var ModalPassengerForm = ({
7983
8166
  ...labels?.errors
7984
8167
  };
7985
8168
  const displayTitle = title || mergedLabels.title;
8169
+ const idTypes = ["KTP", "SIM", "Paspor"];
8170
+ const [isModalSelectIdTypeOpen, setIsModalSelectIdTypeOpen] = React5.useState(false);
8171
+ const [isModalScanOpen, setIsModalScanOpen] = React5.useState(false);
8172
+ const [scannedIdType, setScannedIdType] = React5.useState(null);
8173
+ const [scanStatus, setScanStatus] = React5.useState("idle");
8174
+ const [scanStep, setScanStep] = React5.useState(0);
8175
+ const [capturedImage, setCapturedImage] = React5.useState(null);
8176
+ const [stream, setStream] = React5.useState(null);
8177
+ const videoRef = React5.useRef(null);
7986
8178
  const { control, handleSubmit, reset, watch, setValue } = reactHookForm.useForm({
7987
8179
  defaultValues
7988
8180
  });
@@ -7996,6 +8188,139 @@ var ModalPassengerForm = ({
7996
8188
  setValue("idNumber", "");
7997
8189
  }
7998
8190
  }, [idType, watchPassportCountry, setValue]);
8191
+ const stopCamera = React5.useCallback(() => {
8192
+ if (stream) {
8193
+ stream.getTracks().forEach((track) => track.stop());
8194
+ setStream(null);
8195
+ }
8196
+ if (videoRef.current) {
8197
+ videoRef.current.pause();
8198
+ videoRef.current.srcObject = null;
8199
+ }
8200
+ }, [stream]);
8201
+ const startCamera = React5.useCallback(async () => {
8202
+ try {
8203
+ const mediaStream = await navigator.mediaDevices.getUserMedia({
8204
+ video: {
8205
+ facingMode: "environment",
8206
+ width: { ideal: 1280 },
8207
+ height: { ideal: 720 }
8208
+ }
8209
+ });
8210
+ setStream(mediaStream);
8211
+ } catch (err) {
8212
+ console.error("Failed to start camera:", err);
8213
+ alert(mergedLabels.cameraPermissionError);
8214
+ }
8215
+ }, [mergedLabels.cameraPermissionError]);
8216
+ const capturePhoto = React5.useCallback(() => {
8217
+ if (videoRef.current) {
8218
+ const canvas = document.createElement("canvas");
8219
+ canvas.width = videoRef.current.videoWidth;
8220
+ canvas.height = videoRef.current.videoHeight;
8221
+ const ctx = canvas.getContext("2d");
8222
+ if (ctx) {
8223
+ ctx.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height);
8224
+ setCapturedImage(canvas.toDataURL("image/jpeg"));
8225
+ stopCamera();
8226
+ if (scannedIdType === "KTP") {
8227
+ setScanStatus("reading");
8228
+ } else {
8229
+ setScanStatus("error");
8230
+ }
8231
+ }
8232
+ }
8233
+ }, [scannedIdType, stopCamera]);
8234
+ React5.useEffect(() => {
8235
+ if (isModalScanOpen && scanStatus === "idle") {
8236
+ startCamera();
8237
+ }
8238
+ }, [isModalScanOpen, scanStatus, startCamera]);
8239
+ React5.useEffect(() => {
8240
+ if (isModalScanOpen && scanStatus === "idle" && stream && videoRef.current) {
8241
+ if (videoRef.current.srcObject !== stream) {
8242
+ videoRef.current.srcObject = stream;
8243
+ const playPromise = videoRef.current.play();
8244
+ if (playPromise !== void 0) {
8245
+ playPromise.catch((error) => {
8246
+ if (error.name !== "AbortError") {
8247
+ console.error("Video play error:", error);
8248
+ }
8249
+ });
8250
+ }
8251
+ }
8252
+ }
8253
+ }, [isModalScanOpen, scanStatus, stream]);
8254
+ React5.useEffect(() => {
8255
+ if (!isModalScanOpen) {
8256
+ stopCamera();
8257
+ setScanStep(0);
8258
+ }
8259
+ }, [isModalScanOpen, stopCamera]);
8260
+ React5.useEffect(() => {
8261
+ return () => {
8262
+ stopCamera();
8263
+ };
8264
+ }, [stopCamera]);
8265
+ React5.useEffect(() => {
8266
+ if (scanStatus !== "reading" || !capturedImage) return;
8267
+ let isCancelled = false;
8268
+ const performOCR = async () => {
8269
+ try {
8270
+ const Tesseract = await import('tesseract.js');
8271
+ const { data: { text } } = await Tesseract.recognize(capturedImage, "ind");
8272
+ if (isCancelled) return;
8273
+ setScanStep(1);
8274
+ await new Promise((resolve) => setTimeout(resolve, 500));
8275
+ setScanStep(2);
8276
+ await new Promise((resolve) => setTimeout(resolve, 500));
8277
+ setScanStep(3);
8278
+ await new Promise((resolve) => setTimeout(resolve, 500));
8279
+ if (isCancelled) return;
8280
+ const lines = text.split("\n").filter((l) => l.trim().length > 0);
8281
+ let name = "";
8282
+ let idNumber = "";
8283
+ let city = "";
8284
+ for (const line of lines) {
8285
+ const lower = line.toLowerCase();
8286
+ console.log({ lower });
8287
+ if (lower.includes("nama") && !lower.includes("kewarganegaraan")) {
8288
+ name = line.replace(/.*nama\s*[:;]?\s*/i, "").trim();
8289
+ } else if (lower.includes("nik")) {
8290
+ idNumber = line.replace(/[^0-9]/g, "");
8291
+ } else if (lower.includes("kota") || lower.includes("kabupaten")) {
8292
+ city = line.trim();
8293
+ }
8294
+ }
8295
+ stopCamera();
8296
+ if (name) {
8297
+ setValue("name", name, {
8298
+ shouldValidate: true,
8299
+ shouldDirty: true
8300
+ });
8301
+ }
8302
+ if (idNumber && scannedIdType) {
8303
+ setValue("idType", scannedIdType.toLowerCase());
8304
+ setValue("idNumber", idNumber);
8305
+ }
8306
+ onScanComplete?.({ name, idNumber, city });
8307
+ setScanStatus("success");
8308
+ setIsModalScanOpen(false);
8309
+ setScanStep(0);
8310
+ setCapturedImage(null);
8311
+ } catch (err) {
8312
+ console.error("OCR Failed:", err);
8313
+ if (!isCancelled) {
8314
+ setScanStatus("error");
8315
+ setCapturedImage(null);
8316
+ }
8317
+ }
8318
+ };
8319
+ performOCR();
8320
+ return () => {
8321
+ isCancelled = true;
8322
+ };
8323
+ }, [scanStatus, capturedImage, stopCamera, setValue, scannedIdType, onScanComplete]);
7999
8324
  const handleFormSubmit = (data) => {
8000
8325
  onSubmit(data);
8001
8326
  reset();
@@ -8004,218 +8329,536 @@ var ModalPassengerForm = ({
8004
8329
  onClose();
8005
8330
  reset();
8006
8331
  };
8007
- return /* @__PURE__ */ jsxRuntime.jsx(
8332
+ const handleAutoFill = () => {
8333
+ setIsModalSelectIdTypeOpen(true);
8334
+ };
8335
+ const handleCloseModalSelectTypeId = () => {
8336
+ setIsModalSelectIdTypeOpen(false);
8337
+ };
8338
+ const handleSelectIdType = (selectedIdType) => {
8339
+ setScannedIdType(selectedIdType);
8340
+ setIsModalSelectIdTypeOpen(false);
8341
+ setScanStatus("idle");
8342
+ setIsModalScanOpen(true);
8343
+ };
8344
+ const handleCloseScanModal = () => {
8345
+ stopCamera();
8346
+ setIsModalScanOpen(false);
8347
+ setScanStatus("idle");
8348
+ setScanStep(0);
8349
+ setCapturedImage(null);
8350
+ };
8351
+ const handleRetake = () => {
8352
+ setScanStep(0);
8353
+ setScanStatus("idle");
8354
+ setCapturedImage(null);
8355
+ startCamera();
8356
+ };
8357
+ const renderModalSelectIdType = () => /* @__PURE__ */ jsxRuntime.jsx(
8008
8358
  reactComponents.Dialog,
8009
8359
  {
8010
- open,
8011
- onOpenChange: (_, data) => {
8012
- if (!data.open) {
8013
- handleClose();
8014
- }
8015
- },
8360
+ open: isModalSelectIdTypeOpen,
8361
+ onOpenChange: (_, data) => !data.open && handleCloseModalSelectTypeId(),
8016
8362
  children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { className: styles.dialogSurface, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
8017
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Subtitle1, { children: displayTitle }) }),
8018
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { className: styles.content, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit(handleFormSubmit), children: [
8019
- /* @__PURE__ */ jsxRuntime.jsx(
8020
- InputDynamic_default,
8021
- {
8022
- name: "title",
8023
- control,
8024
- type: "select",
8025
- label: mergedLabels.titleLabel,
8026
- placeholder: mergedLabels.titlePlaceholder,
8027
- options: titleOptions,
8028
- size: "large",
8029
- required: true,
8030
- validationRules: {
8031
- required: mergedErrors.requiredTitle
8363
+ /* @__PURE__ */ jsxRuntime.jsx(
8364
+ reactComponents.DialogTitle,
8365
+ {
8366
+ action: /* @__PURE__ */ jsxRuntime.jsx(
8367
+ reactComponents.Button,
8368
+ {
8369
+ appearance: "subtle",
8370
+ "aria-label": "close",
8371
+ icon: /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { icon: "fluent:dismiss-24-regular" }),
8372
+ onClick: handleCloseModalSelectTypeId,
8373
+ className: styles.closeButton
8032
8374
  }
8033
- }
8034
- ),
8035
- /* @__PURE__ */ jsxRuntime.jsx(
8036
- InputDynamic_default,
8037
- {
8038
- name: "name",
8039
- control,
8040
- type: "text",
8041
- label: mergedLabels.nameLabel,
8042
- placeholder: mergedLabels.namePlaceholder,
8043
- size: "large",
8044
- required: true,
8045
- validationRules: {
8046
- required: mergedErrors.requiredName,
8047
- minLength: {
8048
- value: 3,
8049
- message: mergedErrors.minLengthName
8050
- }
8375
+ ),
8376
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Subtitle1, { children: mergedLabels.selectIdTypeTitle })
8377
+ }
8378
+ ),
8379
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogContent, { className: styles.content, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.idTypeList, children: idTypes.map((type) => /* @__PURE__ */ jsxRuntime.jsx(
8380
+ "div",
8381
+ {
8382
+ className: styles.idTypeItem,
8383
+ onClick: () => handleSelectIdType(type),
8384
+ onKeyDown: (e) => {
8385
+ if (e.key === "Enter" || e.key === " ") {
8386
+ e.preventDefault();
8387
+ handleSelectIdType(type);
8051
8388
  }
8052
- }
8053
- ),
8389
+ },
8390
+ role: "button",
8391
+ tabIndex: 0,
8392
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.idTypeText, children: type })
8393
+ },
8394
+ type
8395
+ )) }) })
8396
+ ] }) })
8397
+ }
8398
+ );
8399
+ const renderModalScanIdentity = () => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Dialog, { open: isModalScanOpen, modalType: "modal", children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { className: styles.scanSurface, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
8400
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: mergedLabels.scanIdentityTitle }),
8401
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogContent, { children: [
8402
+ scanStatus === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8403
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.scannerWrapper, children: [
8054
8404
  /* @__PURE__ */ jsxRuntime.jsx(
8055
- InputDynamic_default,
8405
+ "video",
8056
8406
  {
8057
- name: "age",
8058
- control,
8059
- type: "number",
8060
- label: mergedLabels.ageLabel,
8061
- placeholder: mergedLabels.agePlaceholder,
8062
- size: "large",
8063
- required: true,
8064
- validationRules: {
8065
- required: mergedErrors.requiredAge,
8066
- min: {
8067
- value: 1,
8068
- message: mergedErrors.minAge
8069
- },
8070
- max: {
8071
- value: 150,
8072
- message: mergedErrors.maxAge
8073
- }
8074
- }
8407
+ ref: videoRef,
8408
+ className: styles.videoElement,
8409
+ autoPlay: true,
8410
+ playsInline: true,
8411
+ muted: true
8075
8412
  }
8076
8413
  ),
8077
- /* @__PURE__ */ jsxRuntime.jsx(
8078
- InputDynamic_default,
8079
- {
8080
- name: "cityId",
8081
- control,
8082
- type: "select",
8083
- label: mergedLabels.cityLabel,
8084
- options: cityOptions,
8085
- placeholder: mergedLabels.cityPlaceholder,
8086
- size: "large",
8087
- required: true,
8088
- validationRules: {
8089
- required: mergedErrors.requiredCity
8414
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.scanOverlay, children: [
8415
+ /* @__PURE__ */ jsxRuntime.jsx(
8416
+ "div",
8417
+ {
8418
+ className: `${styles.darkOverlay} ${styles.overlayTop}`
8090
8419
  }
8091
- }
8092
- ),
8093
- isAdultForm ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8420
+ ),
8094
8421
  /* @__PURE__ */ jsxRuntime.jsx(
8095
- InputDynamic_default,
8422
+ "div",
8096
8423
  {
8097
- name: "idType",
8098
- control,
8099
- type: "select",
8100
- label: mergedLabels.idTypeLabel,
8101
- placeholder: mergedLabels.idTypePlaceholder,
8102
- options: TYPE_OPTIONS,
8103
- size: "large",
8104
- required: true,
8105
- validationRules: {
8106
- required: mergedErrors.requiredIdType
8107
- }
8424
+ className: `${styles.darkOverlay} ${styles.overlayBottom}`
8108
8425
  }
8109
8426
  ),
8110
- idType ? idType === "lainnya" ? /* @__PURE__ */ jsxRuntime.jsx(
8111
- InputDynamic_default,
8427
+ /* @__PURE__ */ jsxRuntime.jsx(
8428
+ "div",
8112
8429
  {
8113
- name: "idNumber",
8114
- control,
8115
- type: "date",
8116
- label: mergedLabels.idTypeOtherLabel,
8117
- placeholder: mergedLabels.idTypeOtherPlaceholder,
8118
- size: "large",
8119
- required: true,
8120
- max: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
8121
- validationRules: {
8122
- required: mergedErrors.requiredDate
8430
+ className: `${styles.darkOverlay} ${styles.overlayLeft}`
8431
+ }
8432
+ ),
8433
+ /* @__PURE__ */ jsxRuntime.jsx(
8434
+ "div",
8435
+ {
8436
+ className: `${styles.darkOverlay} ${styles.overlayRight}`
8437
+ }
8438
+ ),
8439
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.scanFrame, children: [
8440
+ /* @__PURE__ */ jsxRuntime.jsx(
8441
+ "div",
8442
+ {
8443
+ className: `${styles.corner} ${styles.cornerTopLeft}`
8444
+ }
8445
+ ),
8446
+ /* @__PURE__ */ jsxRuntime.jsx(
8447
+ "div",
8448
+ {
8449
+ className: `${styles.corner} ${styles.cornerTopRight}`
8450
+ }
8451
+ ),
8452
+ /* @__PURE__ */ jsxRuntime.jsx(
8453
+ "div",
8454
+ {
8455
+ className: `${styles.corner} ${styles.cornerBottomLeft}`
8456
+ }
8457
+ ),
8458
+ /* @__PURE__ */ jsxRuntime.jsx(
8459
+ "div",
8460
+ {
8461
+ className: `${styles.corner} ${styles.cornerBottomRight}`
8462
+ }
8463
+ ),
8464
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.scanLine })
8465
+ ] })
8466
+ ] })
8467
+ ] }),
8468
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { block: true, children: mergedLabels.scanInstructions1 }),
8469
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { block: true, style: { marginTop: "10px", marginBottom: "30px" }, children: mergedLabels.scanInstructions2 })
8470
+ ] }),
8471
+ scanStatus === "reading" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8472
+ /* @__PURE__ */ jsxRuntime.jsxs(
8473
+ reactComponents.Text,
8474
+ {
8475
+ weight: "semibold",
8476
+ style: {
8477
+ display: "flex",
8478
+ justifyContent: "center",
8479
+ alignItems: "center",
8480
+ gap: "14px",
8481
+ textAlign: "center",
8482
+ marginTop: "30px",
8483
+ color: "#00B3BD",
8484
+ marginBottom: "30px"
8485
+ },
8486
+ children: [
8487
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles.spin, children: /* @__PURE__ */ jsxRuntime.jsx(
8488
+ react.Icon,
8489
+ {
8490
+ icon: "fluent:arrow-sync-24-regular",
8491
+ color: "#00B3BD",
8492
+ width: 24
8493
+ }
8494
+ ) }),
8495
+ mergedLabels.readingData
8496
+ ]
8497
+ }
8498
+ ),
8499
+ /* @__PURE__ */ jsxRuntime.jsxs(
8500
+ "div",
8501
+ {
8502
+ style: {
8503
+ display: "flex",
8504
+ flexDirection: "column",
8505
+ gap: 14
8506
+ },
8507
+ children: [
8508
+ scanStep >= 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.checklistItem, children: [
8509
+ /* @__PURE__ */ jsxRuntime.jsx(
8510
+ react.Icon,
8511
+ {
8512
+ icon: "fluent:checkmark-circle-24-regular",
8513
+ color: "#16a34a",
8514
+ width: 24
8515
+ }
8516
+ ),
8517
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { children: mergedLabels.nameRead })
8518
+ ] }),
8519
+ scanStep >= 2 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.checklistItem, children: [
8520
+ /* @__PURE__ */ jsxRuntime.jsx(
8521
+ react.Icon,
8522
+ {
8523
+ icon: "fluent:checkmark-circle-24-regular",
8524
+ color: "#16a34a",
8525
+ width: 24
8526
+ }
8527
+ ),
8528
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { children: mergedLabels.idNumberRead })
8529
+ ] }),
8530
+ scanStep >= 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.checklistItem, children: [
8531
+ /* @__PURE__ */ jsxRuntime.jsx(
8532
+ react.Icon,
8533
+ {
8534
+ icon: "fluent:checkmark-circle-24-regular",
8535
+ color: "#16a34a",
8536
+ width: 24
8537
+ }
8538
+ ),
8539
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { children: mergedLabels.cityRead })
8540
+ ] })
8541
+ ]
8542
+ }
8543
+ )
8544
+ ] }),
8545
+ scanStatus === "error" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 20, textAlign: "center" }, children: [
8546
+ /* @__PURE__ */ jsxRuntime.jsxs(
8547
+ reactComponents.Text,
8548
+ {
8549
+ weight: "semibold",
8550
+ style: {
8551
+ display: "flex",
8552
+ justifyContent: "center",
8553
+ alignItems: "center",
8554
+ gap: "14px",
8555
+ textAlign: "center"
8556
+ },
8557
+ children: [
8558
+ /* @__PURE__ */ jsxRuntime.jsx(
8559
+ react.Icon,
8560
+ {
8561
+ icon: "fluent:dismiss-circle-24-regular",
8562
+ color: "red",
8563
+ width: 24
8564
+ }
8565
+ ),
8566
+ mergedLabels.scanUnreadable
8567
+ ]
8568
+ }
8569
+ ),
8570
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { block: true, style: { marginTop: 30 }, children: mergedLabels.photoNotClear }),
8571
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Text, { block: true, style: { marginTop: 10, marginBottom: 30 }, children: mergedLabels.retakeAdvice }),
8572
+ /* @__PURE__ */ jsxRuntime.jsxs(
8573
+ "div",
8574
+ {
8575
+ style: {
8576
+ display: "flex",
8577
+ gap: 12,
8578
+ justifyContent: "flex-end"
8579
+ },
8580
+ children: [
8581
+ /* @__PURE__ */ jsxRuntime.jsx(
8582
+ reactComponents.Button,
8583
+ {
8584
+ appearance: "primary",
8585
+ size: "medium",
8586
+ onClick: handleRetake,
8587
+ shape: "circular",
8588
+ children: mergedLabels.retakeButton
8589
+ }
8590
+ ),
8591
+ /* @__PURE__ */ jsxRuntime.jsx(
8592
+ reactComponents.Button,
8593
+ {
8594
+ size: "medium",
8595
+ appearance: "secondary",
8596
+ onClick: handleCloseScanModal,
8597
+ shape: "circular",
8598
+ children: mergedLabels.manualInputButton
8123
8599
  }
8600
+ )
8601
+ ]
8602
+ }
8603
+ )
8604
+ ] })
8605
+ ] }),
8606
+ scanStatus === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogActions, { children: [
8607
+ /* @__PURE__ */ jsxRuntime.jsx(
8608
+ reactComponents.Button,
8609
+ {
8610
+ appearance: "secondary",
8611
+ onClick: handleCloseScanModal,
8612
+ shape: "circular",
8613
+ children: mergedLabels.cancelScanButton
8614
+ }
8615
+ ),
8616
+ /* @__PURE__ */ jsxRuntime.jsx(
8617
+ reactComponents.Button,
8618
+ {
8619
+ appearance: "primary",
8620
+ onClick: capturePhoto,
8621
+ shape: "circular",
8622
+ children: mergedLabels.savePhotoButton
8623
+ }
8624
+ )
8625
+ ] })
8626
+ ] }) }) });
8627
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8628
+ /* @__PURE__ */ jsxRuntime.jsx(
8629
+ reactComponents.Dialog,
8630
+ {
8631
+ open,
8632
+ onOpenChange: (_, data) => {
8633
+ if (!data.open) {
8634
+ handleClose();
8635
+ }
8636
+ },
8637
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogSurface, { className: styles.dialogSurface, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogBody, { children: [
8638
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.DialogTitle, { children: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Subtitle1, { children: displayTitle }) }),
8639
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.DialogContent, { className: styles.content, children: [
8640
+ /* @__PURE__ */ jsxRuntime.jsx(
8641
+ reactComponents.Button,
8642
+ {
8643
+ appearance: "outline",
8644
+ shape: "circular",
8645
+ style: {
8646
+ flex: 1,
8647
+ borderColor: reactComponents.tokens.colorBrandBackground,
8648
+ color: reactComponents.tokens.colorBrandBackground,
8649
+ padding: reactComponents.tokens.spacingVerticalM
8650
+ },
8651
+ onClick: handleAutoFill,
8652
+ icon: /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { icon: "fluent:camera-20-filled" }),
8653
+ size: "large",
8654
+ children: mergedLabels.autofill
8124
8655
  }
8125
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8126
- idType === "paspor" && /* @__PURE__ */ jsxRuntime.jsx(
8656
+ ),
8657
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit(handleFormSubmit), children: [
8658
+ /* @__PURE__ */ jsxRuntime.jsx(
8127
8659
  InputDynamic_default,
8128
8660
  {
8129
- menuPlacement: "top",
8130
- name: "country",
8661
+ name: "title",
8131
8662
  control,
8132
- type: "country",
8133
- label: mergedLabels.countryLabel,
8134
- placeholder: mergedLabels.countryPlaceholder,
8663
+ type: "select",
8664
+ label: mergedLabels.titleLabel,
8665
+ placeholder: mergedLabels.titlePlaceholder,
8666
+ options: titleOptions,
8135
8667
  size: "large",
8136
8668
  required: true,
8137
8669
  validationRules: {
8138
- required: mergedErrors.requiredCountry
8670
+ required: mergedErrors.requiredTitle
8139
8671
  }
8140
8672
  }
8141
8673
  ),
8142
8674
  /* @__PURE__ */ jsxRuntime.jsx(
8143
8675
  InputDynamic_default,
8144
8676
  {
8145
- name: "idNumber",
8677
+ name: "name",
8146
8678
  control,
8147
- type: idType === "ktp" ? "number" : "text",
8148
- label: mergedLabels.idNumberLabel,
8149
- placeholder: mergedLabels.idNumberPlaceholder,
8679
+ type: "text",
8680
+ label: mergedLabels.nameLabel,
8681
+ placeholder: mergedLabels.namePlaceholder,
8150
8682
  size: "large",
8151
8683
  required: true,
8152
8684
  validationRules: {
8153
- required: mergedErrors.requiredIdNumber,
8685
+ required: mergedErrors.requiredName,
8154
8686
  minLength: {
8155
- value: 6,
8156
- message: mergedErrors.minLengthIdNumber
8687
+ value: 3,
8688
+ message: mergedErrors.minLengthName
8157
8689
  }
8158
8690
  }
8159
8691
  }
8160
- )
8161
- ] }) : null
8162
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
8163
- InputDynamic_default,
8164
- {
8165
- name: "date",
8166
- control,
8167
- type: "date",
8168
- label: mergedLabels.dateLabel,
8169
- placeholder: mergedLabels.datePlaceholder,
8170
- size: "large",
8171
- required: true,
8172
- validationRules: {
8173
- required: mergedErrors.requiredDate
8174
- }
8175
- }
8176
- ) }),
8177
- /* @__PURE__ */ jsxRuntime.jsx("br", {}),
8178
- /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Divider, {}),
8179
- /* @__PURE__ */ jsxRuntime.jsx("br", {}),
8180
- /* @__PURE__ */ jsxRuntime.jsx(
8181
- InputDynamic_default,
8182
- {
8183
- name: "ticketClass",
8184
- control,
8185
- type: "radiobutton",
8186
- label: mergedLabels.ticketClassLabel,
8187
- options: ticketClassOptions,
8188
- required: true,
8189
- disabled: true
8190
- }
8191
- ),
8192
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.actions, children: [
8193
- /* @__PURE__ */ jsxRuntime.jsx(
8194
- reactComponents.Button,
8195
- {
8196
- appearance: "primary",
8197
- size: "large",
8198
- shape: "circular",
8199
- type: "submit",
8200
- children: mergedLabels.saveButton
8201
- }
8202
- ),
8203
- /* @__PURE__ */ jsxRuntime.jsx(
8204
- reactComponents.Button,
8205
- {
8206
- appearance: "secondary",
8207
- size: "large",
8208
- shape: "circular",
8209
- type: "button",
8210
- onClick: handleClose,
8211
- children: mergedLabels.cancelButton
8212
- }
8213
- )
8692
+ ),
8693
+ /* @__PURE__ */ jsxRuntime.jsx(
8694
+ InputDynamic_default,
8695
+ {
8696
+ name: "age",
8697
+ control,
8698
+ type: "number",
8699
+ label: mergedLabels.ageLabel,
8700
+ placeholder: mergedLabels.agePlaceholder,
8701
+ size: "large",
8702
+ required: true,
8703
+ validationRules: {
8704
+ required: mergedErrors.requiredAge,
8705
+ min: {
8706
+ value: 1,
8707
+ message: mergedErrors.minAge
8708
+ },
8709
+ max: {
8710
+ value: 150,
8711
+ message: mergedErrors.maxAge
8712
+ }
8713
+ }
8714
+ }
8715
+ ),
8716
+ /* @__PURE__ */ jsxRuntime.jsx(
8717
+ InputDynamic_default,
8718
+ {
8719
+ name: "cityId",
8720
+ control,
8721
+ type: "select",
8722
+ label: mergedLabels.cityLabel,
8723
+ options: cityOptions,
8724
+ placeholder: mergedLabels.cityPlaceholder,
8725
+ size: "large",
8726
+ required: true,
8727
+ validationRules: {
8728
+ required: mergedErrors.requiredCity
8729
+ }
8730
+ }
8731
+ ),
8732
+ isAdultForm ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8733
+ /* @__PURE__ */ jsxRuntime.jsx(
8734
+ InputDynamic_default,
8735
+ {
8736
+ name: "idType",
8737
+ control,
8738
+ type: "select",
8739
+ label: mergedLabels.idTypeLabel,
8740
+ placeholder: mergedLabels.idTypePlaceholder,
8741
+ options: TYPE_OPTIONS,
8742
+ size: "large",
8743
+ required: true,
8744
+ validationRules: {
8745
+ required: mergedErrors.requiredIdType
8746
+ }
8747
+ }
8748
+ ),
8749
+ idType ? idType === "lainnya" ? /* @__PURE__ */ jsxRuntime.jsx(
8750
+ InputDynamic_default,
8751
+ {
8752
+ name: "idNumber",
8753
+ control,
8754
+ type: "date",
8755
+ label: mergedLabels.idTypeOtherLabel,
8756
+ placeholder: mergedLabels.idTypeOtherPlaceholder,
8757
+ size: "large",
8758
+ required: true,
8759
+ max: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
8760
+ validationRules: {
8761
+ required: mergedErrors.requiredDate
8762
+ }
8763
+ }
8764
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8765
+ idType === "paspor" && /* @__PURE__ */ jsxRuntime.jsx(
8766
+ InputDynamic_default,
8767
+ {
8768
+ menuPlacement: "top",
8769
+ name: "country",
8770
+ control,
8771
+ type: "country",
8772
+ label: mergedLabels.countryLabel,
8773
+ placeholder: mergedLabels.countryPlaceholder,
8774
+ size: "large",
8775
+ required: true,
8776
+ validationRules: {
8777
+ required: mergedErrors.requiredCountry
8778
+ }
8779
+ }
8780
+ ),
8781
+ /* @__PURE__ */ jsxRuntime.jsx(
8782
+ InputDynamic_default,
8783
+ {
8784
+ name: "idNumber",
8785
+ control,
8786
+ type: idType === "ktp" ? "number" : "text",
8787
+ label: mergedLabels.idNumberLabel,
8788
+ placeholder: mergedLabels.idNumberPlaceholder,
8789
+ size: "large",
8790
+ required: true,
8791
+ validationRules: {
8792
+ required: mergedErrors.requiredIdNumber,
8793
+ minLength: {
8794
+ value: 6,
8795
+ message: mergedErrors.minLengthIdNumber
8796
+ }
8797
+ }
8798
+ }
8799
+ )
8800
+ ] }) : null
8801
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
8802
+ InputDynamic_default,
8803
+ {
8804
+ name: "date",
8805
+ control,
8806
+ type: "date",
8807
+ label: mergedLabels.dateLabel,
8808
+ placeholder: mergedLabels.datePlaceholder,
8809
+ size: "large",
8810
+ required: true,
8811
+ validationRules: {
8812
+ required: mergedErrors.requiredDate
8813
+ }
8814
+ }
8815
+ ) }),
8816
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
8817
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.Divider, {}),
8818
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
8819
+ /* @__PURE__ */ jsxRuntime.jsx(
8820
+ InputDynamic_default,
8821
+ {
8822
+ name: "ticketClass",
8823
+ control,
8824
+ type: "radiobutton",
8825
+ label: mergedLabels.ticketClassLabel,
8826
+ options: ticketClassOptions,
8827
+ required: true,
8828
+ disabled: true
8829
+ }
8830
+ ),
8831
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.actions, children: [
8832
+ /* @__PURE__ */ jsxRuntime.jsx(
8833
+ reactComponents.Button,
8834
+ {
8835
+ appearance: "primary",
8836
+ size: "large",
8837
+ shape: "circular",
8838
+ type: "submit",
8839
+ children: mergedLabels.saveButton
8840
+ }
8841
+ ),
8842
+ /* @__PURE__ */ jsxRuntime.jsx(
8843
+ reactComponents.Button,
8844
+ {
8845
+ appearance: "secondary",
8846
+ size: "large",
8847
+ shape: "circular",
8848
+ type: "button",
8849
+ onClick: handleClose,
8850
+ children: mergedLabels.cancelButton
8851
+ }
8852
+ )
8853
+ ] })
8854
+ ] })
8214
8855
  ] })
8215
8856
  ] }) })
8216
- ] }) })
8217
- }
8218
- );
8857
+ }
8858
+ ),
8859
+ renderModalSelectIdType(),
8860
+ renderModalScanIdentity()
8861
+ ] });
8219
8862
  };
8220
8863
 
8221
8864
  // src/components/CardPassengerList/CardPassengerList.constants.ts