sales-frontend-components 0.0.67 → 0.0.68

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.esm.js CHANGED
@@ -1,17 +1,17 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { useController } from 'react-hook-form';
3
- import { CheckboxButton, Checkbox, DatePicker, DateRangePicker, SegmentGroup, FormField, Icon, Button, Modal, List, ListItem, Segment, Select, Accordion, FormCore, RadioGroup, useModalState, Radio, Table, Tab, ModalUtils } from 'sales-frontend-design-system';
3
+ import { CheckboxButton, Checkbox, DatePicker, DateRangePicker, Accordion, Radio, Table, Button, FormField, Select, Tab, Icon, useModalState, Modal, SegmentGroup, ModalUtils, List, ListItem, Segment, FormCore, RadioGroup } from 'sales-frontend-design-system';
4
4
  import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
5
- import styles from './step-indicator/step-indicator.module.scss';
6
- import styles$1 from './camera/camera.module.scss';
7
- import styles$2 from './debug-tool/debug-tool.module.scss';
5
+ import { useSearchOccupationQuery, useSearchModalAddressQuery, useSearchVehicleQuery } from 'sales-frontend-api/method';
6
+ import styles from './modal/pre-standard/job-search-modal/job-search-modal.module.scss';
7
+ import styles$1 from './step-indicator/step-indicator.module.scss';
8
+ import styles$2 from './camera/camera.module.scss';
9
+ import styles$3 from './debug-tool/debug-tool.module.scss';
8
10
  import { isClient, getEnvironmentFromHostname } from 'sales-frontend-utils';
9
11
  import { useDebugStore } from 'sales-frontend-api';
10
- import styles$3 from './debug-tool/features/network-log/network-log.module.scss';
11
- import { useSearchModalAddressQuery, useSearchOccupationQuery, useSearchVehicleQuery } from 'sales-frontend-api/method';
12
- import styles$4 from './modal/standard/address-search/select-address.module.scss';
13
- import styles$5 from './modal/pre-standard/job-vehicle-search-modal/job-vehicle-search-modal.module.scss';
14
- import styles$6 from './modal/pre-standard/job-search-modal/job-search-modal.module.scss';
12
+ import styles$4 from './debug-tool/features/network-log/network-log.module.scss';
13
+ import styles$5 from './modal/standard/address-search/select-address.module.scss';
14
+ import styles$6 from './modal/pre-standard/job-vehicle-search-modal/job-vehicle-search-modal.module.scss';
15
15
  import styles$7 from './modal/pre-standard/vehicle-search-modal/vehicle-search-modal.module.scss';
16
16
 
17
17
  const FormCheckboxButton = ({
@@ -22,7 +22,21 @@ const FormCheckboxButton = ({
22
22
  ...props
23
23
  }) => {
24
24
  const { field, fieldState } = useController({ name, control, disabled });
25
- return /* @__PURE__ */ jsx(CheckboxButton, { ...props, ...field, id: field.name, checked: field.value, error: fieldState.invalid, children });
25
+ return /* @__PURE__ */ jsx(
26
+ CheckboxButton,
27
+ {
28
+ ...props,
29
+ ...field,
30
+ id: field.name,
31
+ checked: field.value ?? false,
32
+ error: fieldState.invalid,
33
+ onChange: (checked) => {
34
+ field.onChange(checked);
35
+ props.onChange?.(checked);
36
+ },
37
+ children
38
+ }
39
+ );
26
40
  };
27
41
 
28
42
  const FormCheckbox = ({
@@ -100,73 +114,10 @@ const FormDateRangePicker = ({
100
114
  );
101
115
  };
102
116
 
103
- const FormSegmentGroup = ({
104
- name,
105
- control,
106
- disabled,
107
- ...props
108
- }) => {
109
- const { field, fieldState } = useController({ name, control, disabled });
110
- return /* @__PURE__ */ jsx(
111
- SegmentGroup,
112
- {
113
- ...props,
114
- tabIndex: 0,
115
- id: field.name,
116
- ref: field.ref,
117
- defaultValue: field.value,
118
- disabled: field.disabled,
119
- error: fieldState.invalid,
120
- onBlur: field.onBlur,
121
- onValueChange: (selected) => {
122
- field.onChange(selected);
123
- props.onValueChange?.(selected);
124
- }
125
- }
126
- );
127
- };
128
-
129
- const FormTextField = ({
130
- name,
131
- control,
132
- size = "medium",
133
- disabled,
134
- error,
135
- onBlur,
136
- onChange,
137
- rootProps,
138
- ...props
139
- }) => {
140
- const { field, fieldState } = useController({ name, control, disabled });
141
- return /* @__PURE__ */ jsx(
142
- FormField.TextField,
143
- {
144
- ...props,
145
- id: field.name,
146
- size,
147
- autoComplete: "off",
148
- name: field.name,
149
- value: field.value ?? "",
150
- disabled: field.disabled,
151
- error: fieldState.invalid || error,
152
- onChange: (e) => {
153
- field.onChange(e);
154
- onChange?.(e);
155
- },
156
- onBlur: (e) => {
157
- field.onBlur();
158
- onBlur?.(e);
159
- },
160
- rootProps: {
161
- ...rootProps,
162
- onClear: () => {
163
- field.onChange("");
164
- rootProps?.onClear?.();
165
- }
166
- }
167
- }
168
- );
169
- };
117
+ const JOB_SEARCH_TABS = [
118
+ { value: "jobName", label: "\uC9C1\uC885\uBA85 \uAC80\uC0C9" },
119
+ { value: "jobCode", label: "\uBD84\uB958\uB85C \uAC80\uC0C9" }
120
+ ];
170
121
 
171
122
  function getDefaultExportFromCjs (x) {
172
123
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -259,2051 +210,2240 @@ function requireBind () {
259
210
  var bindExports = requireBind();
260
211
  var classNames = /*@__PURE__*/getDefaultExportFromCjs(bindExports);
261
212
 
262
- const cx$9 = classNames.bind(styles);
263
- const StepIndicator = ({
264
- items,
265
- onClickItem,
266
- currentIndex = 0,
267
- defaultValue = "",
268
- dotCount = 3
269
- }) => {
270
- const [current, setCurrent] = React.useState(currentIndex);
271
- React.useEffect(() => {
272
- items.map((item, idx) => {
273
- if (item.value === defaultValue) {
274
- setCurrent(idx);
213
+ const highlightOnSearchKeyword = (originalText, targetString) => {
214
+ if (originalText?.includes(targetString)) {
215
+ const replacedText = [];
216
+ const splitText = originalText.split(targetString);
217
+ for (let i = 0; i < splitText.length; i++) {
218
+ replacedText.push(splitText[i]);
219
+ if (i !== splitText.length - 1) {
220
+ replacedText.push(/* @__PURE__ */ jsx("span", { className: "text-primary", children: targetString }));
275
221
  }
276
- });
277
- }, [items, defaultValue]);
278
- return /* @__PURE__ */ jsxs("div", { className: cx$9("stepper-layout"), children: [
279
- /* @__PURE__ */ jsx("div", { className: cx$9("stepper"), children: items.map((item, idx) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
280
- /* @__PURE__ */ jsx(
281
- "div",
282
- {
283
- className: cx$9("circle", (defaultValue === item.value || current === idx) && "active"),
284
- onClick: () => onClickItem?.(item),
285
- children: item.isCompleted || idx < current ? /* @__PURE__ */ jsx("span", { className: cx$9("completed") }) : ++idx
286
- }
287
- ),
288
- idx < items.length && Array.from({ length: dotCount }).map((_, dotIdx) => /* @__PURE__ */ jsx("span", { className: cx$9("dot") }, `dot-${idx}-${dotIdx}`))
289
- ] }, `num-${idx}`)) }),
290
- /* @__PURE__ */ jsx("ul", { className: cx$9("step-labels"), children: items.map((item, idx) => /* @__PURE__ */ jsx("li", { className: cx$9((defaultValue === item.value || current === idx) && "active"), children: /* @__PURE__ */ jsx("span", { children: item.label ?? item.value }) }, `label-${idx}`)) })
291
- ] });
222
+ }
223
+ return replacedText;
224
+ }
225
+ return originalText;
292
226
  };
293
227
 
294
- const cx$8 = classNames.bind(styles$1);
295
- function Attachment({
296
- photos,
297
- onAddPhoto,
298
- onRemovePhoto,
299
- show,
300
- type = "multiple",
301
- buttonText
302
- }) {
303
- const handleAddPhoto = () => {
304
- onAddPhoto();
305
- };
306
- const handleRemovePhoto = (id) => {
307
- onRemovePhoto(id);
308
- };
309
- const renderPhotoSingle = () => {
310
- if (photos.length === 0) {
311
- return /* @__PURE__ */ jsx("div", { className: cx$8("single-photo-item", "add-photo-item"), children: /* @__PURE__ */ jsxs("button", { className: cx$8("add-photo-button-single"), onClick: handleAddPhoto, children: [
312
- /* @__PURE__ */ jsx(Icon, { name: "illust/camera" }),
313
- /* @__PURE__ */ jsx("span", { children: buttonText || "\uC0AC\uC9C4 \uCCA8\uBD80\uD558\uAE30" })
314
- ] }) });
315
- }
316
- return photos.map((photo) => /* @__PURE__ */ jsxs("div", { className: cx$8("single-photo-item"), children: [
317
- /* @__PURE__ */ jsx("div", { className: cx$8("photo-placeholder"), children: /* @__PURE__ */ jsx("img", { src: photo.src, alt: photo.name, className: cx$8("photo-image") }) }),
318
- /* @__PURE__ */ jsx("button", { className: cx$8("remove-button"), onClick: () => handleRemovePhoto(photo.id), "aria-label": "\uC0AC\uC9C4 \uC0AD\uC81C", children: "\xD7" })
319
- ] }, photo.id));
320
- };
321
- const renderPhotoGrid = () => {
322
- const maxPhotos = type === "single" ? 1 : 4;
323
- const gridItems = [];
324
- if (photos.length < maxPhotos) {
325
- gridItems.push(
326
- /* @__PURE__ */ jsx("div", { className: cx$8("photo-item", "add-photo-item"), children: /* @__PURE__ */ jsxs("button", { className: cx$8("add-photo-button"), onClick: handleAddPhoto, children: [
327
- /* @__PURE__ */ jsx(Icon, { name: "illust/camera" }),
328
- /* @__PURE__ */ jsx("span", { children: buttonText || "\uCCA8\uBD80\uD558\uAE30" }),
329
- /* @__PURE__ */ jsxs("span", { className: cx$8("photo-count"), children: [
228
+ const cx$9 = classNames.bind(styles);
229
+ function JobSearchCategory({ filteredJobs, onJobSelect, searchTerm }) {
230
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$9("category-section"), children: [
231
+ /* @__PURE__ */ jsxs("p", { className: cx$9("result-title"), children: [
232
+ "\uCD1D ",
233
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: filteredJobs.length }),
234
+ "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
235
+ ] }),
236
+ /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$9("job-radio-root"), onToggle: () => {
237
+ }, children: filteredJobs.map((job, index) => /* @__PURE__ */ jsxs(
238
+ Accordion.Item,
239
+ {
240
+ id: `item-${job.occupationIndustryCode}-${index}-accordion`,
241
+ children: [
242
+ /* @__PURE__ */ jsx(Accordion.HeaderDiv, { children: /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(Radio.Item, { size: "small", value: job.occupationIndustryCode, onChange: () => onJobSelect(job), children: [
243
+ highlightOnSearchKeyword(job.occupationIndustryName, searchTerm),
330
244
  "(",
331
- /* @__PURE__ */ jsx("span", { className: cx$8("photo-count-number"), children: photos.length }),
332
- "/",
333
- maxPhotos,
245
+ job.occupationIndustryCode,
334
246
  ")"
335
- ] })
336
- ] }) }, "add-photo")
337
- );
338
- }
339
- photos.forEach((photo) => {
340
- gridItems.push(
341
- /* @__PURE__ */ jsxs("div", { className: cx$8("photo-item"), children: [
342
- /* @__PURE__ */ jsx("div", { className: cx$8("photo-placeholder"), children: /* @__PURE__ */ jsx("img", { src: photo.src, alt: photo.name, className: cx$8("photo-image") }) }),
343
- /* @__PURE__ */ jsx("button", { className: cx$8("remove-button"), onClick: () => handleRemovePhoto(photo.id), "aria-label": "\uC0AC\uC9C4 \uC0AD\uC81C", children: "\xD7" })
344
- ] }, photo.id)
345
- );
346
- });
347
- return gridItems;
348
- };
349
- const isVisible = show || !show && photos.length > 0;
350
- if (!isVisible) {
351
- return null;
352
- }
353
- if (type === "single") {
354
- return /* @__PURE__ */ jsx("div", { className: cx$8("photo-single"), children: renderPhotoSingle() });
355
- }
356
- return /* @__PURE__ */ jsx("div", { className: cx$8("photo-grid", { linear: type === "linear" }), children: renderPhotoGrid() });
247
+ ] }) }) }),
248
+ /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx(Table, { variant: "horizontal", children: /* @__PURE__ */ jsxs("tbody", { children: [
249
+ /* @__PURE__ */ jsxs("tr", { children: [
250
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1" }),
251
+ /* @__PURE__ */ jsx("td", { className: "px-24", children: "1\uD589 1\uBC88\uC9F8" }),
252
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1-2" }),
253
+ /* @__PURE__ */ jsx("td", { className: "px-24 ", children: "1\uD589 2\uBC88\uC9F8" })
254
+ ] }),
255
+ /* @__PURE__ */ jsxs("tr", { children: [
256
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 2" }),
257
+ /* @__PURE__ */ jsx("td", { className: "pl-24 pr-16", colSpan: 3, children: /* @__PURE__ */ jsxs("p", { className: "d-flex-center-center", children: [
258
+ "2\uD589 1\uBC88\uC9F8 ",
259
+ /* @__PURE__ */ jsx("span", { className: "flex-1 pipe-left", children: "\uC11C\uBE0C\uD14D\uC2A4\uD2B8" }),
260
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", size: "xsmall", appearance: "outline", children: "\uBC84\uD2BC\uBA85" })
261
+ ] }) })
262
+ ] })
263
+ ] }) }) })
264
+ ]
265
+ },
266
+ `item-${job.occupationIndustryCode}-${index}`
267
+ )) }) }),
268
+ filteredJobs.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
269
+ "`",
270
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchTerm }),
271
+ "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
272
+ ] })
273
+ ] }) });
357
274
  }
358
275
 
359
- const maxImageSize = 3 * 1024 * 1024;
360
- function resize(image, options = { ext: "jpeg", filesize: maxImageSize }) {
361
- return new Promise((resolve, reject) => {
362
- const canvas = document.createElement("canvas");
363
- const ctx = canvas.getContext("2d");
364
- if (!ctx) {
365
- reject(new Error("Canvas context\uB97C \uC0DD\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
366
- return;
367
- }
368
- const img = new Image();
369
- img.crossOrigin = "anonymous";
370
- img.onload = () => {
371
- let { width, height } = img;
372
- const { filesize, ext } = options;
373
- if (filesize) {
374
- const originalSize = width * height * 4;
375
- if (originalSize > filesize) {
376
- const ratio = Math.sqrt(filesize / originalSize);
377
- width = Math.floor(width * ratio);
378
- height = Math.floor(height * ratio);
379
- }
380
- } else {
381
- const { width: targetWidth, height: targetHeight } = options;
382
- if (targetWidth && targetHeight) {
383
- width = targetWidth;
384
- height = targetHeight;
385
- } else if (targetWidth) {
386
- const ratio = targetWidth / width;
387
- width = targetWidth;
388
- height = Math.floor(height * ratio);
389
- } else if (targetHeight) {
390
- const ratio = targetHeight / height;
391
- height = targetHeight;
392
- width = Math.floor(width * ratio);
393
- }
394
- }
395
- canvas.width = width;
396
- canvas.height = height;
397
- ctx.drawImage(img, 0, 0, width, height);
398
- if (typeof image === "string") {
399
- const mimeType = ext === "png" ? "image/png" : "image/jpeg";
400
- const quality = ext === "png" ? 1 : 0.8;
401
- const base64 = canvas.toDataURL(mimeType, quality);
402
- resolve(base64);
403
- } else {
404
- canvas.toBlob(
405
- (blob) => {
406
- if (!blob) {
407
- reject(new Error("Blob\uC744 \uC0DD\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
408
- return;
409
- }
410
- const mimeType = ext === "png" ? "image/png" : "image/jpeg";
411
- const fileName = image.name ? `${image.name.replace(/\.[^/.]+$/, "")}.${ext}` : `resized.${ext}`;
412
- const resizedFile = new File([blob], fileName, { type: mimeType });
413
- resolve(resizedFile);
414
- },
415
- ext === "png" ? "image/png" : "image/jpeg",
416
- ext === "png" ? 1 : 0.8
417
- );
418
- }
419
- };
420
- img.onerror = () => {
421
- reject(new Error("\uC774\uBBF8\uC9C0\uB97C \uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
422
- };
423
- if (typeof image === "string") {
424
- img.src = image;
425
- } else {
426
- const reader = new FileReader();
427
- reader.onload = (e) => {
428
- if (e.target?.result) {
429
- img.src = e.target.result;
430
- } else {
431
- reject(new Error("\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
432
- }
433
- };
434
- reader.onerror = () => {
435
- reject(new Error("\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
436
- };
437
- reader.readAsDataURL(image);
438
- }
439
- });
276
+ const cx$8 = classNames.bind(styles);
277
+ function JobSearchFavorite({ filteredJobs, onJobSelect }) {
278
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$8("popular-jobs"), children: [
279
+ /* @__PURE__ */ jsx("p", { children: "\uB9CE\uC774 \uCC3E\uB294 \uC9C1\uC885" }),
280
+ /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$8("job-radio-root"), children: filteredJobs.map((job, index) => /* @__PURE__ */ jsxs(
281
+ Accordion.Item,
282
+ {
283
+ id: `item-${job.occupationIndustryCode}-${index}`,
284
+ className: cx$8("accordion-item"),
285
+ children: [
286
+ /* @__PURE__ */ jsx(Accordion.HeaderDiv, { className: cx$8("accordion-header-item"), children: /* @__PURE__ */ jsxs(
287
+ Radio.Item,
288
+ {
289
+ size: "small",
290
+ value: job.occupationIndustryCode,
291
+ onChange: () => onJobSelect(job),
292
+ className: cx$8("radio-item"),
293
+ children: [
294
+ job.occupationIndustryName,
295
+ "(",
296
+ job.occupationIndustryCode,
297
+ ")"
298
+ ]
299
+ }
300
+ ) }),
301
+ /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: "\uD56D\uBAA9 1 \uB0B4\uC6A9" })
302
+ ]
303
+ },
304
+ `item-${job.occupationIndustryCode}-${index}`
305
+ )) }) })
306
+ ] }) });
440
307
  }
441
308
 
442
- const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
443
- function useCamera({
444
- onChange,
445
- resize: resizeOption,
446
- cameraOnly,
447
- onDelete,
448
- show,
449
- type = "multiple",
450
- buttonText
451
- } = {}) {
452
- const [attachedPhotos, setAttachedPhotos] = useState([]);
453
- const findImage = (imageId) => {
454
- return attachedPhotos.find((image) => image.id === imageId);
455
- };
456
- const onClick = () => {
457
- const input = document.createElement("input");
458
- input.type = "file";
459
- input.accept = "image/*";
460
- if (cameraOnly) {
461
- input.capture = "camera";
462
- }
463
- input.addEventListener("change", async (event) => {
464
- const target = event.target;
465
- const { files } = target;
466
- if (files && files.length > 0) {
467
- const file = files[0];
468
- if (file) {
469
- const resizedFile = await resize(file, resizeOption);
470
- const newPhoto = {
471
- id: genImageId(),
472
- src: URL.createObjectURL(resizedFile),
473
- name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
474
- };
475
- if (type === "single") {
476
- setAttachedPhotos([newPhoto]);
477
- } else {
478
- setAttachedPhotos([...attachedPhotos, newPhoto]);
479
- }
480
- onChange && onChange(file);
481
- }
482
- }
483
- document.body.removeChild(input);
484
- });
485
- input.style.display = "none";
486
- document.body.appendChild(input);
487
- input.click();
488
- };
489
- const deleteImage = (imageId) => {
490
- const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
491
- if (imageIndex > -1) {
492
- const item = attachedPhotos.splice(imageIndex, 1);
493
- item[0] && URL.revokeObjectURL(item[0].src);
494
- setAttachedPhotos([...attachedPhotos]);
495
- onDelete && onDelete(imageId);
496
- }
497
- };
498
- const CameraComponent = () => /* @__PURE__ */ jsx(
499
- Attachment,
500
- {
501
- show: !!show,
502
- onAddPhoto: onClick,
503
- onRemovePhoto: deleteImage,
504
- photos: attachedPhotos,
505
- type,
506
- buttonText
507
- }
508
- );
509
- useEffect(() => {
510
- return () => {
511
- attachedPhotos.forEach((image) => {
512
- URL.revokeObjectURL(image.src);
513
- });
514
- };
515
- }, []);
516
- return {
517
- onClick,
518
- getImage: findImage,
519
- deleteImage,
520
- attachedPhotos,
521
- Attachment: CameraComponent
522
- };
309
+ const cx$7 = classNames.bind(styles);
310
+ function JobSearchResult({ filteredJobs, onJobSelect, searchTerm }) {
311
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$7("popular-jobs"), children: [
312
+ /* @__PURE__ */ jsxs("p", { className: cx$7("result-title"), children: [
313
+ "\uCD1D ",
314
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: filteredJobs.length }),
315
+ "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
316
+ ] }),
317
+ /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$7("job-radio-root"), children: filteredJobs.map((job) => /* @__PURE__ */ jsxs(
318
+ Accordion.Item,
319
+ {
320
+ id: `item-${job.occupationIndustryCode}`,
321
+ children: [
322
+ /* @__PURE__ */ jsx(Accordion.HeaderDiv, { children: /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
323
+ Radio.Item,
324
+ {
325
+ id: `item-${job.occupationIndustryCode}`,
326
+ size: "small",
327
+ value: job.occupationIndustryCode,
328
+ onChange: () => {
329
+ onJobSelect(job);
330
+ },
331
+ children: highlightOnSearchKeyword(job.occupationIndustryName, searchTerm)
332
+ }
333
+ ) }) }),
334
+ /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx(Table, { variant: "horizontal", children: /* @__PURE__ */ jsxs("tbody", { children: [
335
+ /* @__PURE__ */ jsxs("tr", { children: [
336
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1" }),
337
+ /* @__PURE__ */ jsx("td", { className: "px-24", children: "1\uD589 1\uBC88\uC9F8" }),
338
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1-2" }),
339
+ /* @__PURE__ */ jsx("td", { className: "px-24 ", children: "1\uD589 2\uBC88\uC9F8" })
340
+ ] }),
341
+ /* @__PURE__ */ jsxs("tr", { children: [
342
+ /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 2" }),
343
+ /* @__PURE__ */ jsx("td", { className: "pl-24 pr-16", colSpan: 3, children: /* @__PURE__ */ jsxs("p", { className: "d-flex-center-center", children: [
344
+ "2\uD589 1\uBC88\uC9F8 ",
345
+ /* @__PURE__ */ jsx("span", { className: "flex-1 pipe-left", children: "\uC11C\uBE0C\uD14D\uC2A4\uD2B8" }),
346
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", size: "xsmall", appearance: "outline", children: "\uBC84\uD2BC\uBA85" })
347
+ ] }) })
348
+ ] })
349
+ ] }) }) })
350
+ ]
351
+ },
352
+ job.occupationIndustryCode
353
+ )) }) }),
354
+ filteredJobs.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
355
+ "`",
356
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchTerm }),
357
+ "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
358
+ ] })
359
+ ] }) });
523
360
  }
524
361
 
525
- const HISTORY_SIZE = 100;
526
- const DEFAULT_DOWNLOAD_PROPS = {
527
- fileExtendsion: "png",
528
- fileName: "image",
529
- transparent: true,
530
- backgroundColor: "white",
531
- width: 500,
532
- height: 500
533
- };
534
- function useCanvasPaint(paintProps = {}) {
535
- const { pen = { strokeWeight: 5, strokeColor: "black" }, onChange, onStart, onEnd } = paintProps;
536
- const [canvasRefState, setCanvasRefState] = useState(null);
537
- const contextRef = useRef(null);
538
- const [isPainting, setIsPainting] = useState(false);
539
- const [history, setHistory] = useState([]);
540
- const [historyIndex, setHistoryIndex] = useState(-1);
541
- const saveState = useCallback(() => {
542
- if (!canvasRefState) {
543
- return;
544
- }
545
- const dataUrl = canvasRefState.toDataURL();
546
- const newHistory = history.slice(0, historyIndex + 1);
547
- if (newHistory.length >= HISTORY_SIZE) {
548
- newHistory.shift();
362
+ const { TextField } = FormField;
363
+ const cx$6 = classNames.bind(styles);
364
+ const { Option } = Select;
365
+ function JobSearch({
366
+ activeTab,
367
+ onTabChange,
368
+ searchTerm,
369
+ setSearchInput,
370
+ filteredJobs,
371
+ onJobSelect,
372
+ setSearchTerm,
373
+ searchInput,
374
+ firstCategory,
375
+ setFirstCategory,
376
+ secondCategory,
377
+ setSecondCategory,
378
+ firstCategoryList,
379
+ secondCategoryList
380
+ }) {
381
+ const onKeyUp = (e) => {
382
+ if (e.key === "Enter") {
383
+ setSearchTerm(searchInput);
549
384
  }
550
- newHistory.push(dataUrl);
551
- setHistory(newHistory);
552
- setHistoryIndex(newHistory.length - 1);
553
- onChange && onChange();
554
- }, [history, historyIndex, onChange, canvasRefState]);
555
- const restoreState = useCallback(
556
- (index) => {
557
- const context = contextRef.current;
558
- if (!canvasRefState || !context || !history[index]) {
559
- return;
385
+ };
386
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
387
+ /* @__PURE__ */ jsx(
388
+ Tab.Root,
389
+ {
390
+ defaultValue: activeTab,
391
+ onValueChange: onTabChange,
392
+ scroll: "fixed",
393
+ size: "small",
394
+ variant: "sub",
395
+ style: { gap: 0, overflow: "visible" },
396
+ children: JOB_SEARCH_TABS.map((tab) => /* @__PURE__ */ jsx(Tab.Item, { value: tab.value, children: tab.label }, tab.value))
560
397
  }
561
- const dataUrl = history[index];
562
- const img = new Image();
563
- img.onload = () => {
564
- context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
565
- context.drawImage(img, 0, 0);
566
- };
567
- img.src = dataUrl;
568
- onChange && onChange();
569
- },
570
- [history, onChange, canvasRefState]
571
- );
572
- useEffect(() => {
573
- if (!canvasRefState) {
574
- return;
575
- }
576
- const context = canvasRefState.getContext("2d", { willReadFrequently: true });
577
- if (!context) {
578
- return;
579
- }
580
- contextRef.current = context;
581
- const initialDataUrl = canvasRefState.toDataURL();
582
- setHistory([initialDataUrl]);
583
- setHistoryIndex(0);
584
- }, [canvasRefState]);
585
- useEffect(() => {
586
- const context = contextRef.current;
587
- if (context) {
588
- context.lineWidth = pen.strokeWeight;
589
- context.strokeStyle = pen.strokeColor;
590
- }
591
- }, [pen]);
592
- const getEventPosition = useCallback(
593
- (event) => {
594
- if (!canvasRefState) {
595
- return null;
596
- }
597
- const rect = canvasRefState.getBoundingClientRect();
598
- const scaleX = canvasRefState.width / rect.width;
599
- const scaleY = canvasRefState.height / rect.height;
600
- let clientX;
601
- let clientY;
602
- if (event instanceof MouseEvent) {
603
- clientX = event.clientX;
604
- clientY = event.clientY;
605
- } else if (event instanceof TouchEvent) {
606
- const touch = event.touches[0];
607
- if (!touch) {
608
- return null;
609
- }
610
- clientX = touch.clientX;
611
- clientY = touch.clientY;
612
- } else {
613
- return null;
614
- }
615
- const offsetX = (clientX - rect.left) * scaleX;
616
- const offsetY = (clientY - rect.top) * scaleY;
617
- return { offsetX, offsetY };
618
- },
619
- [canvasRefState]
620
- );
621
- const startPainting = useCallback(
622
- (event) => {
623
- event.preventDefault();
624
- const context = contextRef.current;
625
- if (!context) {
626
- return;
627
- }
628
- const pos = getEventPosition(event);
629
- if (!pos) {
630
- return;
631
- }
632
- onStart && onStart();
633
- const { offsetX, offsetY } = pos;
634
- context.beginPath();
635
- context.moveTo(offsetX, offsetY);
636
- setIsPainting(true);
637
- },
638
- [onStart, getEventPosition]
639
- );
640
- const stopPainting = useCallback(() => {
641
- const context = contextRef.current;
642
- if (!context || !isPainting) {
643
- return;
644
- }
645
- context.closePath();
646
- setIsPainting(false);
647
- onEnd && onEnd();
648
- saveState();
649
- }, [isPainting, onEnd, saveState]);
650
- const paint = useCallback(
651
- (event) => {
652
- event.preventDefault();
653
- if (!isPainting || !contextRef.current) {
654
- return;
655
- }
656
- const pos = getEventPosition(event);
657
- if (!pos) {
658
- return;
659
- }
660
- const { offsetX, offsetY } = pos;
661
- contextRef.current.lineTo(offsetX, offsetY);
662
- contextRef.current.stroke();
663
- },
664
- [isPainting, getEventPosition]
665
- );
666
- useEffect(() => {
667
- if (!canvasRefState) {
668
- return;
669
- }
670
- canvasRefState.addEventListener("mousedown", startPainting);
671
- canvasRefState.addEventListener("mouseup", stopPainting);
672
- canvasRefState.addEventListener("mousemove", paint);
673
- canvasRefState.addEventListener("mouseleave", stopPainting);
674
- canvasRefState.addEventListener("touchstart", startPainting);
675
- canvasRefState.addEventListener("touchend", stopPainting);
676
- canvasRefState.addEventListener("touchmove", paint);
677
- canvasRefState.addEventListener("touchcancel", stopPainting);
678
- return () => {
679
- canvasRefState.removeEventListener("mousedown", startPainting);
680
- canvasRefState.removeEventListener("mouseup", stopPainting);
681
- canvasRefState.removeEventListener("mousemove", paint);
682
- canvasRefState.removeEventListener("mouseleave", stopPainting);
683
- canvasRefState.removeEventListener("touchstart", startPainting);
684
- canvasRefState.removeEventListener("touchend", stopPainting);
685
- canvasRefState.removeEventListener("touchmove", paint);
686
- canvasRefState.removeEventListener("touchcancel", stopPainting);
687
- };
688
- }, [startPainting, stopPainting, paint, canvasRefState]);
689
- const clear = () => {
690
- const context = contextRef.current;
691
- if (canvasRefState && context) {
692
- context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
693
- const initialDataUrl = canvasRefState.toDataURL();
694
- setHistory([initialDataUrl]);
695
- setHistoryIndex(0);
696
- onChange && onChange();
697
- }
698
- };
699
- const undo = () => {
700
- if (historyIndex > 0) {
701
- const newIndex = historyIndex - 1;
702
- setHistoryIndex(newIndex);
703
- restoreState(newIndex);
704
- }
705
- };
706
- const redo = () => {
707
- if (historyIndex < history.length - 1) {
708
- const newIndex = historyIndex + 1;
709
- setHistoryIndex(newIndex);
710
- restoreState(newIndex);
711
- }
712
- };
713
- const loadImage = (base64String) => {
714
- const context = contextRef.current;
715
- if (!canvasRefState || !context) {
716
- return;
717
- }
718
- const img = new Image();
719
- img.onload = () => {
720
- context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
721
- context.drawImage(img, 0, 0, canvasRefState.width, canvasRefState.height);
722
- saveState();
723
- };
724
- img.src = base64String;
725
- };
726
- const getBase64String = (imageProps) => {
727
- const props = { ...DEFAULT_DOWNLOAD_PROPS, ...imageProps };
728
- const { fileExtendsion, transparent, backgroundColor, width, height } = props;
729
- const originalCanvas = canvasRefState;
730
- if (!originalCanvas) {
731
- return;
732
- }
733
- const tempCanvas = document.createElement("canvas");
734
- tempCanvas.width = width;
735
- tempCanvas.height = height;
736
- const tempCtx = tempCanvas.getContext("2d");
737
- if (tempCtx) {
738
- if (!transparent) {
739
- tempCtx.fillStyle = backgroundColor || "white";
740
- tempCtx.fillRect(0, 0, width, height);
741
- }
742
- tempCtx.drawImage(originalCanvas, 0, 0, width, height);
743
- return tempCanvas.toDataURL(`image/${fileExtendsion}`);
744
- }
745
- };
746
- const download = (downloadProps) => {
747
- const props = { ...DEFAULT_DOWNLOAD_PROPS, ...downloadProps };
748
- const { fileName, fileExtendsion, transparent, backgroundColor, width, height } = props;
749
- const originalCanvas = canvasRefState;
750
- if (!originalCanvas) {
751
- return;
752
- }
753
- const tempCanvas = document.createElement("canvas");
754
- tempCanvas.width = width;
755
- tempCanvas.height = height;
756
- const tempCtx = tempCanvas.getContext("2d");
757
- if (tempCtx) {
758
- if (!transparent) {
759
- tempCtx.fillStyle = backgroundColor || "white";
760
- tempCtx.fillRect(0, 0, width, height);
761
- }
762
- tempCtx.drawImage(originalCanvas, 0, 0, width, height);
763
- const link = document.createElement("a");
764
- link.download = `${fileName}.${fileExtendsion}`;
765
- link.href = tempCanvas.toDataURL(`image/${fileExtendsion}`);
766
- link.click();
767
- }
398
+ ),
399
+ /* @__PURE__ */ jsxs("div", { children: [
400
+ activeTab === "jobName" && /* @__PURE__ */ jsxs("div", { className: cx$6("favorite-jobs-section"), children: [
401
+ /* @__PURE__ */ jsx(
402
+ TextField,
403
+ {
404
+ placeholder: "\uC9C1\uC885\uBA85 \uAC80\uC0C9",
405
+ value: searchInput,
406
+ onKeyUp,
407
+ onChange: (e) => setSearchInput(e.target.value),
408
+ className: styles.searchInput,
409
+ size: "medium",
410
+ rootProps: {
411
+ endElement: /* @__PURE__ */ jsx(Icon, { name: "sub-ui/search", onClick: () => setSearchTerm(searchInput) }),
412
+ onClear: () => {
413
+ setSearchTerm("");
414
+ setSearchInput("");
415
+ }
416
+ }
417
+ }
418
+ ),
419
+ !searchTerm && /* @__PURE__ */ jsx(JobSearchFavorite, { filteredJobs, onJobSelect }),
420
+ searchTerm && /* @__PURE__ */ jsx(JobSearchResult, { filteredJobs, onJobSelect, searchTerm })
421
+ ] }),
422
+ activeTab === "jobCode" && /* @__PURE__ */ jsxs("div", { className: cx$6("select-jobs-section"), children: [
423
+ /* @__PURE__ */ jsxs("div", { className: cx$6("category-section"), children: [
424
+ /* @__PURE__ */ jsx(
425
+ Select,
426
+ {
427
+ name: "first_category",
428
+ onChange: (value) => {
429
+ setFirstCategory(value);
430
+ setSecondCategory("");
431
+ },
432
+ placeholder: "\uB300\uBD84\uB958 \uC120\uD0DD",
433
+ rootProps: {
434
+ style: {
435
+ // width: '300px'
436
+ }
437
+ },
438
+ size: "large",
439
+ value: firstCategory,
440
+ children: firstCategoryList.map((option, index) => /* @__PURE__ */ jsx(Option, { value: option.occupationIndustryCode, children: option.occupationIndustryName }, `${index}-${option.occupationIndustryCode}`))
441
+ }
442
+ ),
443
+ /* @__PURE__ */ jsx(
444
+ Select,
445
+ {
446
+ name: "second_category",
447
+ onChange: setSecondCategory,
448
+ placeholder: "\uC911\uBD84\uB958 \uC120\uD0DD",
449
+ rootProps: {
450
+ style: {
451
+ // width: '300px'
452
+ }
453
+ },
454
+ size: "large",
455
+ value: secondCategory,
456
+ disabled: !firstCategory,
457
+ children: secondCategoryList.map((option, index) => /* @__PURE__ */ jsx(Option, { value: option.occupationIndustryCode, children: option.occupationIndustryName }, `${index}-${option.occupationIndustryCode}`))
458
+ }
459
+ )
460
+ ] }),
461
+ firstCategory && secondCategory && /* @__PURE__ */ jsx(JobSearchCategory, { filteredJobs, onJobSelect, searchTerm })
462
+ ] })
463
+ ] })
464
+ ] });
465
+ }
466
+
467
+ const initData = [
468
+ {
469
+ occupationIndustryCode: "430101",
470
+ occupationIndustryName: "\uD68C\uC0AC \uC0AC\uBB34\uC9C1 \uC885\uC0AC\uC790",
471
+ occupationTypeCode: null,
472
+ historySequence: 0
473
+ },
474
+ {
475
+ occupationIndustryCode: "400301",
476
+ occupationIndustryName: "\uACBD\uC601\uC9C0\uC6D0 \uC0AC\uBB34\uC9C1 \uAD00\uB9AC\uC790",
477
+ occupationTypeCode: null,
478
+ historySequence: 0
479
+ },
480
+ {
481
+ occupationIndustryCode: "510201",
482
+ occupationIndustryName: "\uC804\uC5C5\uC8FC\uBD80",
483
+ occupationTypeCode: null,
484
+ historySequence: 0
485
+ },
486
+ {
487
+ occupationIndustryCode: "442501",
488
+ occupationIndustryName: "\uC8FC\uBC29\uC7A5 \uBC0F \uC870\uB9AC\uC0AC(\uC120\uBC15 \uC870\uB9AC\uC0AC \uC81C\uC678)",
489
+ occupationTypeCode: null,
490
+ historySequence: 0
491
+ },
492
+ {
493
+ occupationIndustryCode: "450303",
494
+ occupationIndustryName: "\uBCF4\uD5D8\uC124\uACC4\uC0AC(\uB2F9\uC0AC)",
495
+ occupationTypeCode: null,
496
+ historySequence: 0
497
+ }
498
+ ];
499
+ const useJobSearch = () => {
500
+ const [activeTab, setActiveTab] = useState(JOB_SEARCH_TABS[0]?.value ?? "");
501
+ const [selectedJob, setSelectedJob] = useState(null);
502
+ const [searchTerm, setSearchTerm] = useState("");
503
+ const [searchInput, setSearchInput] = useState("");
504
+ const handleJobSelect = (job) => {
505
+ setSelectedJob(job);
768
506
  };
769
- const isCanvasBlank = () => {
770
- if (!canvasRefState) {
771
- return true;
507
+ const [firstCategory, setFirstCategory] = useState("");
508
+ const [secondCategory, setSecondCategory] = useState("");
509
+ const [jobList, setJobList] = useState(initData);
510
+ const [firstCategoryList, setFirstCategoryList] = useState([]);
511
+ const [secondCategoryList, setSecondCategoryList] = useState([]);
512
+ const { data } = useSearchOccupationQuery({
513
+ occupationMajorCategoryCode: firstCategory,
514
+ occupationSearchTypeCode: searchTerm ? "4" : "3",
515
+ occupationSubCategoryCode: secondCategory,
516
+ searchOccupationIndustryName: searchTerm
517
+ });
518
+ const { data: firstCategoryData } = useSearchOccupationQuery({
519
+ occupationMajorCategoryCode: "",
520
+ occupationSearchTypeCode: "1",
521
+ occupationSubCategoryCode: "",
522
+ searchOccupationIndustryName: ""
523
+ });
524
+ const { data: secondCategoryData } = useSearchOccupationQuery({
525
+ occupationMajorCategoryCode: firstCategory,
526
+ occupationSearchTypeCode: "2",
527
+ occupationSubCategoryCode: "",
528
+ searchOccupationIndustryName: ""
529
+ });
530
+ useEffect(() => {
531
+ if (data && searchTerm && activeTab === "jobName") {
532
+ const filteredJobs = data.data.occupationList.filter((job) => job.occupationIndustryName.includes(searchTerm));
533
+ setJobList(filteredJobs);
534
+ } else if (!data && searchTerm && activeTab === "jobName") {
535
+ setJobList([]);
536
+ } else if (!searchTerm && activeTab === "jobName") {
537
+ setJobList(initData);
538
+ } else if (activeTab === "jobCode" && firstCategory && secondCategory) {
539
+ setJobList(data?.data.occupationList || []);
772
540
  }
773
- const { width, height } = canvasRefState;
774
- const ctx = canvasRefState.getContext("2d");
775
- if (!ctx) {
776
- console.error("2D context not available");
777
- return true;
541
+ }, [searchTerm, data, firstCategory, secondCategory, secondCategoryData, activeTab]);
542
+ useEffect(() => {
543
+ console.log("jobList", jobList);
544
+ }, [jobList]);
545
+ useEffect(() => {
546
+ if (firstCategoryData) {
547
+ setFirstCategoryList(firstCategoryData.data.occupationList);
778
548
  }
779
- const imageData = ctx.getImageData(0, 0, width, height);
780
- const { data } = imageData;
781
- for (let i = 0; i < data.length; i += 4) {
782
- if (data[i + 3] !== 0) {
783
- return false;
784
- }
549
+ }, [firstCategoryData]);
550
+ useEffect(() => {
551
+ if (secondCategoryData) {
552
+ setSecondCategoryList(secondCategoryData.data.occupationList);
785
553
  }
786
- return true;
554
+ }, [secondCategoryData]);
555
+ return {
556
+ activeTab,
557
+ setActiveTab,
558
+ selectedJob,
559
+ searchTerm,
560
+ setSearchTerm,
561
+ handleJobSelect,
562
+ filteredJobs: jobList,
563
+ searchInput,
564
+ setSearchInput,
565
+ firstCategory,
566
+ setFirstCategory,
567
+ secondCategory,
568
+ setSecondCategory,
569
+ secondCategoryList,
570
+ firstCategoryList
571
+ };
572
+ };
573
+ function useJobSearchModal() {
574
+ const {
575
+ activeTab,
576
+ setActiveTab,
577
+ searchTerm,
578
+ setSearchTerm,
579
+ filteredJobs,
580
+ handleJobSelect,
581
+ selectedJob,
582
+ searchInput,
583
+ setSearchInput,
584
+ firstCategory,
585
+ setFirstCategory,
586
+ secondCategory,
587
+ setSecondCategory,
588
+ firstCategoryList,
589
+ secondCategoryList
590
+ } = useJobSearch();
591
+ const { isOpen, openModal, closeModal } = useModalState();
592
+ const onTabChange = (value) => {
593
+ setSearchTerm("");
594
+ setFirstCategory("");
595
+ setSecondCategory("");
596
+ setActiveTab(value);
787
597
  };
788
598
  return {
789
- clear,
790
- undo,
791
- redo,
792
- loadImage,
793
- download,
794
- getBase64String,
795
- isCanvasBlank,
796
- setCanvasRefState,
797
- canvasRefState
599
+ JobSearchModal: /* @__PURE__ */ jsxs(Modal.Root, { isOpen, onClose: closeModal, modalSize: "xlarge", children: [
600
+ /* @__PURE__ */ jsx(Modal.Overlay, {}),
601
+ /* @__PURE__ */ jsxs(Modal.Content, { style: { height: "697px" }, children: [
602
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC9C1\uC885 \uAC80\uC0C9", showCloseButton: true }),
603
+ /* @__PURE__ */ jsx(Modal.Body, { raw: true, children: /* @__PURE__ */ jsx(
604
+ JobSearch,
605
+ {
606
+ firstCategory,
607
+ firstCategoryList,
608
+ secondCategoryList,
609
+ setFirstCategory,
610
+ secondCategory,
611
+ activeTab,
612
+ onTabChange,
613
+ searchTerm,
614
+ setSearchInput,
615
+ filteredJobs: filteredJobs || [],
616
+ onJobSelect: handleJobSelect,
617
+ searchInput,
618
+ setSearchTerm,
619
+ setSecondCategory
620
+ }
621
+ ) }),
622
+ /* @__PURE__ */ jsx(Modal.Footer, { children: /* @__PURE__ */ jsx(Button, { variant: "primary", size: "medium", appearance: "filled", width: "full", onClick: closeModal, children: "\uD655\uC778" }) })
623
+ ] })
624
+ ] }),
625
+ JobSearchComponent: /* @__PURE__ */ jsx(
626
+ JobSearch,
627
+ {
628
+ firstCategoryList,
629
+ secondCategoryList,
630
+ firstCategory,
631
+ setFirstCategory,
632
+ secondCategory,
633
+ setSecondCategory,
634
+ activeTab,
635
+ onTabChange,
636
+ searchTerm,
637
+ setSearchInput,
638
+ filteredJobs: filteredJobs || [],
639
+ onJobSelect: handleJobSelect,
640
+ searchInput,
641
+ setSearchTerm
642
+ }
643
+ ),
644
+ isJobSearchOpen: isOpen,
645
+ openJobSearchModal: openModal,
646
+ closeJobSearchModal: closeModal,
647
+ selectedJob
798
648
  };
799
649
  }
800
650
 
801
- const testSignatureBase64Data = "data:image/png;base64,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";
802
-
803
- const FloatingButton = ({ onClick }) => {
804
- const [position, setPosition] = useState({ x: 0, y: 0 });
805
- const [isDragging, setIsDragging] = useState(false);
806
- const dragHappened = useRef(false);
807
- const dragStartPos = useRef({ x: 0, y: 0 });
808
- const elementStartPos = useRef({ x: 0, y: 0 });
809
- const handleMouseDown = (e) => {
810
- if (e.button !== 0) {
811
- return;
651
+ const FormSearchJobField = ({
652
+ name,
653
+ control,
654
+ disabled,
655
+ rootProps,
656
+ error,
657
+ size = "medium",
658
+ placeholder = "\uC9C1\uC885 \uAC80\uC0C9",
659
+ ...props
660
+ }) => {
661
+ const [selected, setSelected] = useState();
662
+ const { field, fieldState } = useController({ name, control, disabled });
663
+ const { JobSearchModal, openJobSearchModal, selectedJob } = useJobSearchModal();
664
+ useEffect(() => {
665
+ if (selectedJob) {
666
+ setSelected(selectedJob);
667
+ field.onChange(selectedJob.occupationIndustryCode);
668
+ props.onValueChange?.(selectedJob);
812
669
  }
813
- dragHappened.current = false;
814
- setIsDragging(true);
815
- dragStartPos.current = { x: e.clientX, y: e.clientY };
816
- elementStartPos.current = { ...position };
817
- const handleMouseMove = (event) => {
818
- const dx = event.clientX - dragStartPos.current.x;
819
- const dy = event.clientY - dragStartPos.current.y;
820
- if (!dragHappened.current && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
821
- dragHappened.current = true;
670
+ }, [selectedJob]);
671
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
672
+ /* @__PURE__ */ jsx(
673
+ FormField.TextField,
674
+ {
675
+ ...props,
676
+ ...field,
677
+ id: field.name,
678
+ error: fieldState.invalid || error,
679
+ value: selected?.occupationIndustryName ?? "",
680
+ rootProps: {
681
+ ...rootProps,
682
+ endElement: /* @__PURE__ */ jsx(Icon, { name: "sub-ui/search" })
683
+ },
684
+ readOnly: true,
685
+ size,
686
+ placeholder,
687
+ style: { background: "#fff", cursor: "pointer" },
688
+ autoComplete: "off",
689
+ onClick: openJobSearchModal
690
+ }
691
+ ),
692
+ JobSearchModal
693
+ ] });
694
+ };
695
+
696
+ const FormSegmentGroup = ({
697
+ name,
698
+ control,
699
+ disabled,
700
+ disabledItems,
701
+ items,
702
+ ...props
703
+ }) => {
704
+ const { field, fieldState } = useController({ name, control, disabled });
705
+ const itemList = items.map((item) => {
706
+ return {
707
+ ...item,
708
+ disabled: disabledItems?.includes(item.value)
709
+ };
710
+ });
711
+ return /* @__PURE__ */ jsx(
712
+ SegmentGroup,
713
+ {
714
+ ...props,
715
+ tabIndex: 0,
716
+ id: field.name,
717
+ ref: field.ref,
718
+ defaultValue: field.value,
719
+ disabled: field.disabled,
720
+ error: fieldState.invalid,
721
+ onBlur: field.onBlur,
722
+ items: itemList,
723
+ onValueChange: (selected) => {
724
+ field.onChange(selected);
725
+ props.onValueChange?.(selected);
822
726
  }
823
- setPosition({
824
- x: elementStartPos.current.x + dx,
825
- y: elementStartPos.current.y + dy
826
- });
827
- };
828
- const handleMouseUp = () => {
829
- window.removeEventListener("mousemove", handleMouseMove);
830
- window.removeEventListener("mouseup", handleMouseUp);
831
- setIsDragging(false);
832
- };
833
- window.addEventListener("mousemove", handleMouseMove);
834
- window.addEventListener("mouseup", handleMouseUp);
835
- };
836
- const handleClick = (e) => {
837
- if (dragHappened.current) {
838
- e.preventDefault();
839
- e.stopPropagation();
840
- return;
841
727
  }
842
- onClick();
843
- };
728
+ );
729
+ };
730
+
731
+ const FormSelect = ({
732
+ name,
733
+ control,
734
+ disabled,
735
+ error,
736
+ children,
737
+ ...props
738
+ }) => {
739
+ const { field, fieldState } = useController({ name, control, disabled });
844
740
  return /* @__PURE__ */ jsx(
845
- Button,
741
+ Select,
846
742
  {
847
- variant: "secondary",
848
- appearance: "filled",
849
- size: "xsmall",
850
- className: styles$2["debug-floating-button"],
851
- style: {
852
- transform: `translate(${position.x}px, ${position.y}px)`,
853
- cursor: isDragging ? "grabbing" : "grab"
743
+ ...props,
744
+ id: field.name,
745
+ disabled: field.disabled,
746
+ error: fieldState.invalid || error,
747
+ onBlur: field.onBlur,
748
+ value: field.value,
749
+ onChange: (selected) => {
750
+ field.onChange(selected);
854
751
  },
855
- onMouseDown: handleMouseDown,
856
- onClick: handleClick,
857
- children: "DEBUG"
752
+ children
858
753
  }
859
754
  );
860
755
  };
756
+ const FormSelectOption = ({ children, value, ...rest }) => {
757
+ return /* @__PURE__ */ jsx(Select.Option, { value, ...rest, children });
758
+ };
759
+ const FormSelectGroup = ({
760
+ options,
761
+ optionsProps,
762
+ ...props
763
+ }) => {
764
+ return /* @__PURE__ */ jsx(FormSelect, { ...props, children: options.map((option) => /* @__PURE__ */ jsx(FormSelectOption, { value: option.value, ...optionsProps, children: option.label }, option.value)) });
765
+ };
766
+ FormSelect.Option = FormSelectOption;
767
+ FormSelect.Group = FormSelectGroup;
861
768
 
862
- const MenuPanel = ({ menuItems, onMenuItemClick, onClose }) => {
863
- return /* @__PURE__ */ jsxs(Modal.Root, { isOpen: true, onClose, modalSize: "small", children: [
864
- /* @__PURE__ */ jsx(Modal.Overlay, {}),
865
- /* @__PURE__ */ jsxs(Modal.Content, { children: [
866
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "Debug Menu", showCloseButton: true }),
867
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx(List, { selectable: true, children: menuItems.map((item) => /* @__PURE__ */ jsx(ListItem, { onClick: () => onMenuItemClick(item.component), children: item.label }, item.id)) }) })
868
- ] })
869
- ] });
769
+ const FormTextField = ({
770
+ name,
771
+ control,
772
+ size = "medium",
773
+ disabled,
774
+ error,
775
+ onBlur,
776
+ onChange,
777
+ rootProps,
778
+ ...props
779
+ }) => {
780
+ const { field, fieldState } = useController({ name, control, disabled });
781
+ return /* @__PURE__ */ jsx(
782
+ FormField.TextField,
783
+ {
784
+ ...props,
785
+ id: field.name,
786
+ size,
787
+ autoComplete: "off",
788
+ name: field.name,
789
+ value: field.value ?? "",
790
+ disabled: field.disabled,
791
+ error: fieldState.invalid || error,
792
+ onChange: (e) => {
793
+ field.onChange(e);
794
+ onChange?.(e);
795
+ },
796
+ onBlur: (e) => {
797
+ field.onBlur();
798
+ onBlur?.(e);
799
+ },
800
+ rootProps: {
801
+ ...rootProps,
802
+ onClear: () => {
803
+ field.onChange("");
804
+ rootProps?.onClear?.();
805
+ }
806
+ }
807
+ }
808
+ );
870
809
  };
871
810
 
872
- let globalLogs = [];
873
- let listeners = [];
874
- const originalConsoleMethods = {};
875
- let isConsoleOverridden = false;
876
- const addLog = (type, ...args) => {
877
- const newLog = {
878
- id: Date.now() + Math.random(),
879
- type,
880
- timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
881
- message: args
811
+ const cx$5 = classNames.bind(styles$1);
812
+ const StepIndicator = ({
813
+ items,
814
+ onClickItem,
815
+ currentIndex = 0,
816
+ defaultValue = "",
817
+ dotCount = 3,
818
+ isLoading
819
+ }) => {
820
+ const [steps, setSteps] = React.useState(
821
+ Array.from({ length: 10 }).map(() => ({ label: "-", value: "" }))
822
+ );
823
+ const [current, setCurrent] = React.useState(currentIndex);
824
+ React.useEffect(() => {
825
+ if (items.length > 0) {
826
+ setSteps(items);
827
+ items.map((item, idx) => {
828
+ if (item.value === defaultValue) {
829
+ setCurrent(idx);
830
+ }
831
+ });
832
+ }
833
+ }, [items, defaultValue]);
834
+ const handleClickStep = (item) => {
835
+ const index = steps.findIndex((step) => step.value === item.value);
836
+ if (index === -1) {
837
+ console.error("error not found index");
838
+ return;
839
+ }
840
+ if (steps[index < 1 ? index : index - 1]?.isCompleted) {
841
+ onClickItem?.(item);
842
+ } else {
843
+ ModalUtils.alert("\uC774\uC804 \uB2E8\uACC4\uB97C \uBAA8\uB450 \uC644\uB8CC\uD574\uC57C \uC120\uD0DD\uD55C \uB2E8\uACC4\uB85C\n\uC774\uB3D9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "\uC774\uC804 \uB2E8\uACC4\uB97C \uBA3C\uC800 \uC9C4\uD589\uD574\uC8FC\uC138\uC694");
844
+ }
882
845
  };
883
- globalLogs = [...globalLogs, newLog];
884
- listeners.forEach((listener) => listener([...globalLogs]));
846
+ return /* @__PURE__ */ jsxs("div", { className: cx$5("stepper-layout", { loading: isLoading }), children: [
847
+ /* @__PURE__ */ jsx("div", { className: cx$5("stepper"), children: steps.map((item, idx) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
848
+ /* @__PURE__ */ jsx(
849
+ "div",
850
+ {
851
+ className: cx$5(
852
+ "circle",
853
+ { completed: item.isCompleted ?? false },
854
+ { active: defaultValue === item.value || current === idx }
855
+ ),
856
+ onClick: () => handleClickStep?.(item),
857
+ children: item.isCompleted ? /* @__PURE__ */ jsx("span", { className: cx$5("completed-icon") }) : idx + 1
858
+ }
859
+ ),
860
+ idx < steps.length - 1 && Array.from({ length: dotCount }).map((_, dotIdx) => /* @__PURE__ */ jsx("span", { className: cx$5("dot") }, `dot-${idx}-${dotIdx}`))
861
+ ] }, `num-${idx}`)) }),
862
+ /* @__PURE__ */ jsx("ul", { className: cx$5("step-labels"), children: steps.map((item, idx) => /* @__PURE__ */ jsx(
863
+ "li",
864
+ {
865
+ className: cx$5(
866
+ { completed: steps[idx < 1 ? idx : idx - 1]?.isCompleted ?? false },
867
+ { active: defaultValue === item.value || current === idx }
868
+ ),
869
+ onClick: () => handleClickStep?.(item),
870
+ children: /* @__PURE__ */ jsx("span", { className: "text-ellipsis", children: item.label ?? item.value })
871
+ },
872
+ `label-${idx}`
873
+ )) })
874
+ ] });
885
875
  };
886
- const initializeConsoleLogOverride = () => {
887
- if (!isClient() || isConsoleOverridden) {
888
- return;
876
+
877
+ const cx$4 = classNames.bind(styles$2);
878
+ function Attachment({
879
+ photos,
880
+ onAddPhoto,
881
+ onRemovePhoto,
882
+ show,
883
+ type = "multiple",
884
+ buttonText
885
+ }) {
886
+ const handleAddPhoto = () => {
887
+ onAddPhoto();
888
+ };
889
+ const handleRemovePhoto = (id) => {
890
+ onRemovePhoto(id);
891
+ };
892
+ const renderPhotoSingle = () => {
893
+ if (photos.length === 0) {
894
+ return /* @__PURE__ */ jsx("div", { className: cx$4("single-photo-item", "add-photo-item"), children: /* @__PURE__ */ jsxs("button", { className: cx$4("add-photo-button-single"), onClick: handleAddPhoto, children: [
895
+ /* @__PURE__ */ jsx(Icon, { name: "illust/camera" }),
896
+ /* @__PURE__ */ jsx("span", { children: buttonText || "\uC0AC\uC9C4 \uCCA8\uBD80\uD558\uAE30" })
897
+ ] }) });
898
+ }
899
+ return photos.map((photo) => /* @__PURE__ */ jsxs("div", { className: cx$4("single-photo-item"), children: [
900
+ /* @__PURE__ */ jsx("div", { className: cx$4("photo-placeholder"), children: /* @__PURE__ */ jsx("img", { src: photo.src, alt: photo.name, className: cx$4("photo-image") }) }),
901
+ /* @__PURE__ */ jsx("button", { className: cx$4("remove-button"), onClick: () => handleRemovePhoto(photo.id), "aria-label": "\uC0AC\uC9C4 \uC0AD\uC81C", children: "\xD7" })
902
+ ] }, photo.id));
903
+ };
904
+ const renderPhotoGrid = () => {
905
+ const maxPhotos = type === "single" ? 1 : 4;
906
+ const gridItems = [];
907
+ if (photos.length < maxPhotos) {
908
+ gridItems.push(
909
+ /* @__PURE__ */ jsx("div", { className: cx$4("photo-item", "add-photo-item"), children: /* @__PURE__ */ jsxs("button", { className: cx$4("add-photo-button"), onClick: handleAddPhoto, children: [
910
+ /* @__PURE__ */ jsx(Icon, { name: "illust/camera" }),
911
+ /* @__PURE__ */ jsx("span", { children: buttonText || "\uCCA8\uBD80\uD558\uAE30" }),
912
+ /* @__PURE__ */ jsxs("span", { className: cx$4("photo-count"), children: [
913
+ "(",
914
+ /* @__PURE__ */ jsx("span", { className: cx$4("photo-count-number"), children: photos.length }),
915
+ "/",
916
+ maxPhotos,
917
+ ")"
918
+ ] })
919
+ ] }) }, "add-photo")
920
+ );
921
+ }
922
+ photos.forEach((photo) => {
923
+ gridItems.push(
924
+ /* @__PURE__ */ jsxs("div", { className: cx$4("photo-item"), children: [
925
+ /* @__PURE__ */ jsx("div", { className: cx$4("photo-placeholder"), children: /* @__PURE__ */ jsx("img", { src: photo.src, alt: photo.name, className: cx$4("photo-image") }) }),
926
+ /* @__PURE__ */ jsx("button", { className: cx$4("remove-button"), onClick: () => handleRemovePhoto(photo.id), "aria-label": "\uC0AC\uC9C4 \uC0AD\uC81C", children: "\xD7" })
927
+ ] }, photo.id)
928
+ );
929
+ });
930
+ return gridItems;
931
+ };
932
+ const isVisible = show || !show && photos.length > 0;
933
+ if (!isVisible) {
934
+ return null;
889
935
  }
890
- const logTypes = ["log", "info", "warn", "error", "debug"];
891
- logTypes.forEach((type) => {
892
- originalConsoleMethods[type] = console[type];
893
- console[type] = (...args) => {
894
- if (originalConsoleMethods[type]) {
895
- originalConsoleMethods[type]?.apply(console, args);
936
+ if (type === "single") {
937
+ return /* @__PURE__ */ jsx("div", { className: cx$4("photo-single"), children: renderPhotoSingle() });
938
+ }
939
+ return /* @__PURE__ */ jsx("div", { className: cx$4("photo-grid", { linear: type === "linear" }), children: renderPhotoGrid() });
940
+ }
941
+
942
+ const maxImageSize = 3 * 1024 * 1024;
943
+ function resize(image, options = { ext: "jpeg", filesize: maxImageSize }) {
944
+ return new Promise((resolve, reject) => {
945
+ const canvas = document.createElement("canvas");
946
+ const ctx = canvas.getContext("2d");
947
+ if (!ctx) {
948
+ reject(new Error("Canvas context\uB97C \uC0DD\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
949
+ return;
950
+ }
951
+ const img = new Image();
952
+ img.crossOrigin = "anonymous";
953
+ img.onload = () => {
954
+ let { width, height } = img;
955
+ const { filesize, ext } = options;
956
+ if (filesize) {
957
+ const originalSize = width * height * 4;
958
+ if (originalSize > filesize) {
959
+ const ratio = Math.sqrt(filesize / originalSize);
960
+ width = Math.floor(width * ratio);
961
+ height = Math.floor(height * ratio);
962
+ }
963
+ } else {
964
+ const { width: targetWidth, height: targetHeight } = options;
965
+ if (targetWidth && targetHeight) {
966
+ width = targetWidth;
967
+ height = targetHeight;
968
+ } else if (targetWidth) {
969
+ const ratio = targetWidth / width;
970
+ width = targetWidth;
971
+ height = Math.floor(height * ratio);
972
+ } else if (targetHeight) {
973
+ const ratio = targetHeight / height;
974
+ height = targetHeight;
975
+ width = Math.floor(width * ratio);
976
+ }
977
+ }
978
+ canvas.width = width;
979
+ canvas.height = height;
980
+ ctx.drawImage(img, 0, 0, width, height);
981
+ if (typeof image === "string") {
982
+ const mimeType = ext === "png" ? "image/png" : "image/jpeg";
983
+ const quality = ext === "png" ? 1 : 0.8;
984
+ const base64 = canvas.toDataURL(mimeType, quality);
985
+ resolve(base64);
986
+ } else {
987
+ canvas.toBlob(
988
+ (blob) => {
989
+ if (!blob) {
990
+ reject(new Error("Blob\uC744 \uC0DD\uC131\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
991
+ return;
992
+ }
993
+ const mimeType = ext === "png" ? "image/png" : "image/jpeg";
994
+ const fileName = image.name ? `${image.name.replace(/\.[^/.]+$/, "")}.${ext}` : `resized.${ext}`;
995
+ const resizedFile = new File([blob], fileName, { type: mimeType });
996
+ resolve(resizedFile);
997
+ },
998
+ ext === "png" ? "image/png" : "image/jpeg",
999
+ ext === "png" ? 1 : 0.8
1000
+ );
896
1001
  }
897
- addLog(type, ...args);
898
1002
  };
899
- });
900
- isConsoleOverridden = true;
901
- };
902
- const restoreConsoleLog = () => {
903
- if (!isClient() || !isConsoleOverridden) {
904
- return;
905
- }
906
- const logTypes = ["log", "info", "warn", "error", "debug"];
907
- logTypes.forEach((type) => {
908
- if (originalConsoleMethods[type]) {
909
- console[type] = originalConsoleMethods[type];
910
- }
911
- });
912
- isConsoleOverridden = false;
913
- };
914
- const useConsoleLog = () => {
915
- const [logs, setLogs] = useState(globalLogs);
916
- useEffect(() => {
917
- listeners.push(setLogs);
918
- return () => {
919
- listeners = listeners.filter((l) => l !== setLogs);
1003
+ img.onerror = () => {
1004
+ reject(new Error("\uC774\uBBF8\uC9C0\uB97C \uB85C\uB4DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
920
1005
  };
921
- }, []);
922
- const clearLogs = useCallback(() => {
923
- globalLogs = [];
924
- listeners.forEach((listener) => listener([]));
925
- }, []);
926
- return { logs, clearLogs };
927
- };
928
-
929
- const safeStringify$1 = (obj) => {
930
- try {
931
- return JSON.stringify(obj, null, 2);
932
- } catch (e) {
933
- return "[Unserializable Object]";
934
- }
935
- };
936
- const LogMessage = ({ entry }) => {
937
- const messageParts = entry.message.map((part) => {
938
- if (typeof part === "object" && part !== null) {
939
- return safeStringify$1(part);
1006
+ if (typeof image === "string") {
1007
+ img.src = image;
1008
+ } else {
1009
+ const reader = new FileReader();
1010
+ reader.onload = (e) => {
1011
+ if (e.target?.result) {
1012
+ img.src = e.target.result;
1013
+ } else {
1014
+ reject(new Error("\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
1015
+ }
1016
+ };
1017
+ reader.onerror = () => {
1018
+ reject(new Error("\uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
1019
+ };
1020
+ reader.readAsDataURL(image);
940
1021
  }
941
- return String(part);
942
1022
  });
943
- return /* @__PURE__ */ jsx("pre", { className: `${styles$2["log-message"]} ${styles$2[`log-${entry.type}`]}`, children: messageParts.join(" ") });
944
- };
945
- const ConsoleLogPanel = ({ onClose }) => {
946
- const { logs, clearLogs } = useConsoleLog();
947
- const [filter, setFilter] = useState("all");
948
- const logContainerRef = useRef(null);
949
- const filteredLogs = useMemo(() => {
950
- if (filter === "all") {
951
- return logs;
952
- }
953
- return logs.filter((log) => log.type === filter);
954
- }, [logs, filter]);
955
- useEffect(() => {
956
- if (logContainerRef.current) {
957
- logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
1023
+ }
1024
+
1025
+ const genImageId = () => `camera-${Date.now()}-${Math.random()}`;
1026
+ function useCamera({
1027
+ onChange,
1028
+ resize: resizeOption,
1029
+ cameraOnly,
1030
+ onDelete,
1031
+ show,
1032
+ type = "multiple",
1033
+ buttonText
1034
+ } = {}) {
1035
+ const [attachedPhotos, setAttachedPhotos] = useState([]);
1036
+ const findImage = (imageId) => {
1037
+ return attachedPhotos.find((image) => image.id === imageId);
1038
+ };
1039
+ const onClick = () => {
1040
+ const input = document.createElement("input");
1041
+ input.type = "file";
1042
+ input.accept = "image/*";
1043
+ if (cameraOnly) {
1044
+ input.capture = "camera";
958
1045
  }
959
- }, [filteredLogs]);
960
- return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
961
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "Console Logs", showCloseButton: true }),
962
- /* @__PURE__ */ jsxs(Modal.Body, { children: [
963
- /* @__PURE__ */ jsxs("div", { className: styles$2["panel-toolbar"], children: [
964
- /* @__PURE__ */ jsxs(
965
- Segment.Root,
966
- {
967
- size: "xsmall",
968
- appearance: "outline",
969
- align: "left",
970
- defaultValue: filter,
971
- onValueChange: (value) => setFilter(value),
972
- children: [
973
- /* @__PURE__ */ jsx(Segment.Item, { value: "all", children: "All" }),
974
- /* @__PURE__ */ jsx(Segment.Item, { value: "log", children: "Log" }),
975
- /* @__PURE__ */ jsx(Segment.Item, { value: "warn", children: "Warn" }),
976
- /* @__PURE__ */ jsx(Segment.Item, { value: "error", children: "Error" })
977
- ]
978
- }
979
- ),
980
- /* @__PURE__ */ jsx(
981
- Button,
982
- {
983
- variant: "neutral",
984
- appearance: "outline",
985
- size: "xsmall",
986
- onClick: clearLogs,
987
- style: { marginLeft: "auto" },
988
- children: "Clear"
1046
+ input.addEventListener("change", async (event) => {
1047
+ const target = event.target;
1048
+ const { files } = target;
1049
+ if (files && files.length > 0) {
1050
+ const file = files[0];
1051
+ if (file) {
1052
+ const resizedFile = await resize(file, resizeOption);
1053
+ const newPhoto = {
1054
+ id: genImageId(),
1055
+ src: URL.createObjectURL(resizedFile),
1056
+ name: `\uC11C\uB958\uC0AC\uC9C4_${attachedPhotos.length + 1}`
1057
+ };
1058
+ if (type === "single") {
1059
+ setAttachedPhotos([newPhoto]);
1060
+ } else {
1061
+ setAttachedPhotos([...attachedPhotos, newPhoto]);
989
1062
  }
990
- )
991
- ] }),
992
- /* @__PURE__ */ jsx("div", { className: styles$2["log-list-container"], ref: logContainerRef, children: filteredLogs.map((log) => /* @__PURE__ */ jsxs("div", { className: styles$2["log-item"], children: [
993
- /* @__PURE__ */ jsx("span", { className: styles$2["log-timestamp"], children: log.timestamp }),
994
- /* @__PURE__ */ jsx(LogMessage, { entry: log })
995
- ] }, log.id)) })
996
- ] })
997
- ] }) });
998
- };
999
-
1000
- const LoginPanel = ({ onClose, onLogin }) => {
1001
- const [selectedTypeId, setSelectedTypeId] = useState(loginTypes[0]?.id || "");
1002
- const [formData, setFormData] = useState({});
1003
- const selectedType = useMemo(() => loginTypes.find((t) => t.id === selectedTypeId), [selectedTypeId]);
1004
- const handleInputChange = (e) => {
1005
- const { name, value } = e.target;
1006
- setFormData((prev) => ({ ...prev, [name]: value }));
1063
+ onChange && onChange(file);
1064
+ }
1065
+ }
1066
+ document.body.removeChild(input);
1067
+ });
1068
+ input.style.display = "none";
1069
+ document.body.appendChild(input);
1070
+ input.click();
1007
1071
  };
1008
- const handleSubmit = (e) => {
1009
- e.preventDefault();
1010
- if (selectedType) {
1011
- onLogin(selectedType.id, formData);
1012
- onClose();
1072
+ const deleteImage = (imageId) => {
1073
+ const imageIndex = attachedPhotos.findIndex((image) => image.id === imageId);
1074
+ if (imageIndex > -1) {
1075
+ const item = attachedPhotos.splice(imageIndex, 1);
1076
+ item[0] && URL.revokeObjectURL(item[0].src);
1077
+ setAttachedPhotos([...attachedPhotos]);
1078
+ onDelete && onDelete(imageId);
1013
1079
  }
1014
1080
  };
1081
+ const CameraComponent = () => /* @__PURE__ */ jsx(
1082
+ Attachment,
1083
+ {
1084
+ show: !!show,
1085
+ onAddPhoto: onClick,
1086
+ onRemovePhoto: deleteImage,
1087
+ photos: attachedPhotos,
1088
+ type,
1089
+ buttonText
1090
+ }
1091
+ );
1015
1092
  useEffect(() => {
1016
- setFormData({});
1017
- }, [selectedType]);
1018
- return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1019
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uAC04\uD3B8 \uB85C\uADF8\uC778", showCloseButton: true }),
1020
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs("form", { className: styles$2["login-form-container"], onSubmit: handleSubmit, children: [
1021
- /* @__PURE__ */ jsxs(FormField.FieldControl, { children: [
1022
- /* @__PURE__ */ jsx(FormField.Label, { htmlFor: "login-type-select", children: "\uB85C\uADF8\uC778 \uC720\uD615" }),
1023
- /* @__PURE__ */ jsx(
1024
- Select,
1025
- {
1026
- value: selectedTypeId,
1027
- onChange: setSelectedTypeId,
1028
- size: "xsmall",
1029
- rootProps: { style: { width: "100%" } },
1030
- children: loginTypes.map((type) => /* @__PURE__ */ jsx(Select.Option, { value: type.id, children: type.label }, type.id))
1031
- }
1032
- )
1033
- ] }),
1034
- selectedType?.fields.map((field) => /* @__PURE__ */ jsxs(FormField.FieldControl, { children: [
1035
- /* @__PURE__ */ jsx(FormField.Label, { htmlFor: field.name, children: field.label }),
1036
- /* @__PURE__ */ jsx(
1037
- FormField.TextField,
1038
- {
1039
- size: "xsmall",
1040
- type: field.type,
1041
- id: field.name,
1042
- name: field.name,
1043
- placeholder: field.placeholder,
1044
- value: formData[field.name] || "",
1045
- onChange: handleInputChange,
1046
- required: true
1047
- }
1048
- )
1049
- ] }, field.name)),
1050
- /* @__PURE__ */ jsx("div", { className: styles$2["form-actions"], children: /* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", appearance: "filled", size: "xsmall", children: "\uB85C\uADF8\uC778" }) })
1051
- ] }) })
1052
- ] }) });
1053
- };
1093
+ return () => {
1094
+ attachedPhotos.forEach((image) => {
1095
+ URL.revokeObjectURL(image.src);
1096
+ });
1097
+ };
1098
+ }, []);
1099
+ return {
1100
+ onClick,
1101
+ getImage: findImage,
1102
+ deleteImage,
1103
+ attachedPhotos,
1104
+ Attachment: CameraComponent
1105
+ };
1106
+ }
1054
1107
 
1055
- const SEARCH_SECTIONS = [
1056
- { value: "all", label: "\uC804\uCCB4" },
1057
- { value: "url", label: "\uC8FC\uC18C" },
1058
- { value: "headers", label: "\uD5E4\uB354" },
1059
- { value: "params", label: "\uD30C\uB77C\uBBF8\uD130" },
1060
- { value: "data", label: "\uC694\uCCAD" },
1061
- { value: "response", label: "\uC751\uB2F5" },
1062
- { value: "error", label: "\uC5D0\uB7EC" }
1063
- ];
1064
- const getLogInfo = (log) => {
1065
- if (log.holdStatus === "held") {
1066
- if ("request" in log) {
1067
- return log.request;
1108
+ const HISTORY_SIZE = 100;
1109
+ const DEFAULT_DOWNLOAD_PROPS = {
1110
+ fileExtendsion: "png",
1111
+ fileName: "image",
1112
+ transparent: true,
1113
+ backgroundColor: "white",
1114
+ width: 500,
1115
+ height: 500
1116
+ };
1117
+ function useCanvasPaint(paintProps = {}) {
1118
+ const { pen = { strokeWeight: 5, strokeColor: "black" }, onChange, onStart, onEnd } = paintProps;
1119
+ const [canvasRefState, setCanvasRefState] = useState(null);
1120
+ const contextRef = useRef(null);
1121
+ const [isPainting, setIsPainting] = useState(false);
1122
+ const [history, setHistory] = useState([]);
1123
+ const [historyIndex, setHistoryIndex] = useState(-1);
1124
+ const saveState = useCallback(() => {
1125
+ if (!canvasRefState) {
1126
+ return;
1068
1127
  }
1069
- if ("response" in log) {
1070
- return log.response;
1128
+ const dataUrl = canvasRefState.toDataURL();
1129
+ const newHistory = history.slice(0, historyIndex + 1);
1130
+ if (newHistory.length >= HISTORY_SIZE) {
1131
+ newHistory.shift();
1071
1132
  }
1072
- if ("error" in log) {
1073
- return log.error;
1133
+ newHistory.push(dataUrl);
1134
+ setHistory(newHistory);
1135
+ setHistoryIndex(newHistory.length - 1);
1136
+ onChange && onChange();
1137
+ }, [history, historyIndex, onChange, canvasRefState]);
1138
+ const restoreState = useCallback(
1139
+ (index) => {
1140
+ const context = contextRef.current;
1141
+ if (!canvasRefState || !context || !history[index]) {
1142
+ return;
1143
+ }
1144
+ const dataUrl = history[index];
1145
+ const img = new Image();
1146
+ img.onload = () => {
1147
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
1148
+ context.drawImage(img, 0, 0);
1149
+ };
1150
+ img.src = dataUrl;
1151
+ onChange && onChange();
1152
+ },
1153
+ [history, onChange, canvasRefState]
1154
+ );
1155
+ useEffect(() => {
1156
+ if (!canvasRefState) {
1157
+ return;
1074
1158
  }
1075
- }
1076
- return log;
1077
- };
1078
- const NetworkLog = ({ onClose }) => {
1079
- const {
1080
- requests,
1081
- responses,
1082
- errors,
1083
- clear,
1084
- isHold,
1085
- toggleHold,
1086
- heldRequests,
1087
- heldResponses,
1088
- heldErrors,
1089
- playAllRequests,
1090
- playAllResponses
1091
- } = useDebugStore();
1092
- const [searchTerm, setSearchTerm] = useState("");
1093
- const [searchSection, setSearchSection] = useState(SEARCH_SECTIONS[0]?.value);
1094
- const allLogs = useMemo(() => {
1095
- const logs = [];
1096
- requests.forEach((req) => logs.push({ ...req, type: "request" }));
1097
- responses.forEach((res) => logs.push({ ...res, type: "response" }));
1098
- errors.forEach((err) => logs.push({ ...err, type: "error" }));
1099
- heldRequests.forEach((req) => logs.push({ ...req, type: "request", holdStatus: "held" }));
1100
- heldResponses.forEach((res) => logs.push({ ...res, type: "response", holdStatus: "held" }));
1101
- heldErrors.forEach((err) => logs.push({ ...err, type: "error", holdStatus: "held" }));
1102
- logs.sort((a, b) => {
1103
- const aInfo = getLogInfo(a);
1104
- const bInfo = getLogInfo(b);
1105
- const aTime = "startTime" in aInfo ? aInfo.startTime : 0;
1106
- const bTime = "startTime" in bInfo ? bInfo.startTime : 0;
1107
- return bTime - aTime;
1108
- });
1109
- return logs;
1110
- }, [requests, responses, errors, heldRequests, heldResponses, heldErrors]);
1111
- const filteredLogs = useMemo(() => {
1112
- if (!searchTerm) {
1113
- return allLogs;
1159
+ const context = canvasRefState.getContext("2d", { willReadFrequently: true });
1160
+ if (!context) {
1161
+ return;
1114
1162
  }
1115
- const lowercasedTerm = searchTerm.toLowerCase();
1116
- return allLogs.filter((log) => {
1117
- const logInfo = getLogInfo(log);
1118
- switch (searchSection) {
1119
- case "url":
1120
- return logInfo.url?.toLowerCase().includes(lowercasedTerm);
1121
- case "headers":
1122
- return "headers" in logInfo && logInfo.headers && JSON.stringify(logInfo.headers)?.toLowerCase().includes(lowercasedTerm);
1123
- case "params":
1124
- return "params" in logInfo && logInfo.params && JSON.stringify(logInfo.params)?.toLowerCase().includes(lowercasedTerm);
1125
- case "data":
1126
- return "data" in logInfo && logInfo.data && log.type === "request" && JSON.stringify(logInfo.data)?.toLowerCase().includes(lowercasedTerm);
1127
- case "response":
1128
- return "data" in logInfo && logInfo.data && log.type === "response" && JSON.stringify(logInfo.data)?.toLowerCase().includes(lowercasedTerm);
1129
- case "error":
1130
- return log.type === "error" && JSON.stringify(logInfo)?.toLowerCase().includes(lowercasedTerm);
1131
- case "all":
1132
- default:
1133
- return JSON.stringify(logInfo).toLowerCase().includes(lowercasedTerm);
1134
- }
1135
- });
1136
- }, [allLogs, searchTerm, searchSection]);
1137
- const renderLogSummary = (log) => {
1138
- const logInfo = getLogInfo(log);
1139
- const prefix = log.holdStatus === "held" ? "[HELD] " : "";
1140
- if (log.type === "request") {
1141
- return `${prefix}[REQ] ${logInfo.method.toUpperCase()} ${logInfo.url}`;
1163
+ contextRef.current = context;
1164
+ const initialDataUrl = canvasRefState.toDataURL();
1165
+ setHistory([initialDataUrl]);
1166
+ setHistoryIndex(0);
1167
+ }, [canvasRefState]);
1168
+ useEffect(() => {
1169
+ const context = contextRef.current;
1170
+ if (context) {
1171
+ context.lineWidth = pen.strokeWeight;
1172
+ context.strokeStyle = pen.strokeColor;
1142
1173
  }
1143
- if (log.type === "response" && "status" in logInfo) {
1144
- return `${prefix}[RES] ${logInfo.method.toUpperCase()} ${logInfo.url} - ${logInfo.status}`;
1174
+ }, [pen]);
1175
+ const getEventPosition = useCallback(
1176
+ (event) => {
1177
+ if (!canvasRefState) {
1178
+ return null;
1179
+ }
1180
+ const rect = canvasRefState.getBoundingClientRect();
1181
+ const scaleX = canvasRefState.width / rect.width;
1182
+ const scaleY = canvasRefState.height / rect.height;
1183
+ let clientX;
1184
+ let clientY;
1185
+ if (event instanceof MouseEvent) {
1186
+ clientX = event.clientX;
1187
+ clientY = event.clientY;
1188
+ } else if (event instanceof TouchEvent) {
1189
+ const touch = event.touches[0];
1190
+ if (!touch) {
1191
+ return null;
1192
+ }
1193
+ clientX = touch.clientX;
1194
+ clientY = touch.clientY;
1195
+ } else {
1196
+ return null;
1197
+ }
1198
+ const offsetX = (clientX - rect.left) * scaleX;
1199
+ const offsetY = (clientY - rect.top) * scaleY;
1200
+ return { offsetX, offsetY };
1201
+ },
1202
+ [canvasRefState]
1203
+ );
1204
+ const startPainting = useCallback(
1205
+ (event) => {
1206
+ event.preventDefault();
1207
+ const context = contextRef.current;
1208
+ if (!context) {
1209
+ return;
1210
+ }
1211
+ const pos = getEventPosition(event);
1212
+ if (!pos) {
1213
+ return;
1214
+ }
1215
+ onStart && onStart();
1216
+ const { offsetX, offsetY } = pos;
1217
+ context.beginPath();
1218
+ context.moveTo(offsetX, offsetY);
1219
+ setIsPainting(true);
1220
+ },
1221
+ [onStart, getEventPosition]
1222
+ );
1223
+ const stopPainting = useCallback(() => {
1224
+ const context = contextRef.current;
1225
+ if (!context || !isPainting) {
1226
+ return;
1145
1227
  }
1146
- if (log.type === "error" && "message" in logInfo) {
1147
- return `${prefix}[ERR] ${logInfo.method.toUpperCase()} ${logInfo.url} - ${logInfo.message}`;
1228
+ context.closePath();
1229
+ setIsPainting(false);
1230
+ onEnd && onEnd();
1231
+ saveState();
1232
+ }, [isPainting, onEnd, saveState]);
1233
+ const paint = useCallback(
1234
+ (event) => {
1235
+ event.preventDefault();
1236
+ if (!isPainting || !contextRef.current) {
1237
+ return;
1238
+ }
1239
+ const pos = getEventPosition(event);
1240
+ if (!pos) {
1241
+ return;
1242
+ }
1243
+ const { offsetX, offsetY } = pos;
1244
+ contextRef.current.lineTo(offsetX, offsetY);
1245
+ contextRef.current.stroke();
1246
+ },
1247
+ [isPainting, getEventPosition]
1248
+ );
1249
+ useEffect(() => {
1250
+ if (!canvasRefState) {
1251
+ return;
1148
1252
  }
1149
- return "Unknown Log";
1150
- };
1151
- const renderLogContent = (log) => {
1152
- const logInfo = getLogInfo(log);
1153
- return /* @__PURE__ */ jsx("pre", { children: JSON.stringify(logInfo, null, 2) });
1154
- };
1155
- return /* @__PURE__ */ jsxs(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: [
1156
- /* @__PURE__ */ jsx(Modal.Overlay, {}),
1157
- /* @__PURE__ */ jsxs(Modal.Content, { children: [
1158
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uB124\uD2B8\uC6CC\uD06C \uB85C\uADF8", showCloseButton: true }),
1159
- /* @__PURE__ */ jsxs(Modal.Body, { children: [
1160
- /* @__PURE__ */ jsxs("div", { className: styles$3["search-container"], children: [
1161
- /* @__PURE__ */ jsx(Select, { value: searchSection, onChange: (value) => setSearchSection(value), size: "xsmall", children: SEARCH_SECTIONS.map((option) => /* @__PURE__ */ jsx(Select.Option, { value: option.value, children: option.label }, option.value)) }),
1162
- /* @__PURE__ */ jsx(
1163
- FormField.TextField,
1164
- {
1165
- placeholder: "\uAC80\uC0C9...",
1166
- value: searchTerm,
1167
- size: "xsmall",
1168
- onChange: (e) => setSearchTerm(e.target.value)
1169
- }
1170
- ),
1171
- /* @__PURE__ */ jsx(Checkbox, { id: "hold-checkbox", checked: isHold, onChange: toggleHold, size: "small", variant: "main", children: "Hold" }),
1172
- /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: clear, children: "clear" })
1173
- ] }),
1174
- isHold && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "row" }, children: [
1175
- /* @__PURE__ */ jsx(Button, { size: "xsmall", onClick: () => playAllRequests(), variant: "primary", appearance: "outline", children: "REQ Resolve" }),
1176
- /* @__PURE__ */ jsx(Button, { size: "xsmall", onClick: () => playAllResponses(), variant: "primary", appearance: "outline", children: "RES Resolve" })
1177
- ] }),
1178
- /* @__PURE__ */ jsx("div", { className: styles$3["log-list"], children: filteredLogs.length === 0 ? /* @__PURE__ */ jsx("p", { children: "\uD45C\uC2DC\uD560 \uB85C\uADF8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) : /* @__PURE__ */ jsx(Accordion.Root, { children: filteredLogs.map((log, index) => /* @__PURE__ */ jsxs(Accordion.Item, { children: [
1179
- /* @__PURE__ */ jsx(Accordion.HeaderButton, { children: /* @__PURE__ */ jsx("p", { className: styles$3["log-summary"], children: renderLogSummary(log) }) }),
1180
- /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx("div", { className: styles$3["log-content"], children: renderLogContent(log) }) })
1181
- ] }, index)) }) })
1182
- ] })
1183
- ] })
1184
- ] });
1185
- };
1186
-
1187
- const PageNavigationPanel = ({ onClose }) => {
1188
- const [url, setUrl] = useState("");
1189
- const handleNavigate = () => {
1190
- if (url) {
1191
- self.location.href = url;
1253
+ canvasRefState.addEventListener("mousedown", startPainting);
1254
+ canvasRefState.addEventListener("mouseup", stopPainting);
1255
+ canvasRefState.addEventListener("mousemove", paint);
1256
+ canvasRefState.addEventListener("mouseleave", stopPainting);
1257
+ canvasRefState.addEventListener("touchstart", startPainting);
1258
+ canvasRefState.addEventListener("touchend", stopPainting);
1259
+ canvasRefState.addEventListener("touchmove", paint);
1260
+ canvasRefState.addEventListener("touchcancel", stopPainting);
1261
+ return () => {
1262
+ canvasRefState.removeEventListener("mousedown", startPainting);
1263
+ canvasRefState.removeEventListener("mouseup", stopPainting);
1264
+ canvasRefState.removeEventListener("mousemove", paint);
1265
+ canvasRefState.removeEventListener("mouseleave", stopPainting);
1266
+ canvasRefState.removeEventListener("touchstart", startPainting);
1267
+ canvasRefState.removeEventListener("touchend", stopPainting);
1268
+ canvasRefState.removeEventListener("touchmove", paint);
1269
+ canvasRefState.removeEventListener("touchcancel", stopPainting);
1270
+ };
1271
+ }, [startPainting, stopPainting, paint, canvasRefState]);
1272
+ const clear = () => {
1273
+ const context = contextRef.current;
1274
+ if (canvasRefState && context) {
1275
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
1276
+ const initialDataUrl = canvasRefState.toDataURL();
1277
+ setHistory([initialDataUrl]);
1278
+ setHistoryIndex(0);
1279
+ onChange && onChange();
1192
1280
  }
1193
1281
  };
1194
- return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1195
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uD398\uC774\uC9C0 \uC774\uB3D9", showCloseButton: true }),
1196
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs("div", { className: styles$2["page-navigation-content"], children: [
1197
- /* @__PURE__ */ jsx(
1198
- FormField.TextField,
1199
- {
1200
- size: "xsmall",
1201
- type: "text",
1202
- value: url,
1203
- onChange: (e) => setUrl(e.target.value),
1204
- placeholder: "\uC774\uB3D9\uD560 URL\uC744 \uC785\uB825\uD558\uC138\uC694 (\uC608: /main)",
1205
- rootProps: { style: { flex: 1 } }
1206
- }
1207
- ),
1208
- /* @__PURE__ */ jsx(Button, { variant: "primary", appearance: "filled", size: "xsmall", onClick: handleNavigate, children: "\uC774\uB3D9" })
1209
- ] }) })
1210
- ] }) });
1211
- };
1212
-
1213
- const safeStringify = (obj) => {
1214
- try {
1215
- const replacer = (key, value) => typeof value === "bigint" ? value.toString() : value;
1216
- return JSON.stringify(obj, replacer, 2);
1217
- } catch (e) {
1218
- return "[Unserializable Object]";
1219
- }
1220
- };
1221
- const ResultMessage = ({ log }) => {
1222
- const messageParts = log.message.map((part) => {
1223
- if (typeof part === "object" && part !== null) {
1224
- return safeStringify(part);
1282
+ const undo = () => {
1283
+ if (historyIndex > 0) {
1284
+ const newIndex = historyIndex - 1;
1285
+ setHistoryIndex(newIndex);
1286
+ restoreState(newIndex);
1225
1287
  }
1226
- return String(part);
1227
- });
1228
- const prefix = log.type === "return" ? "\u21A9 " : "";
1229
- return /* @__PURE__ */ jsxs("pre", { className: `${styles$2["log-message"]} ${styles$2[`log-${log.type}`]}`, children: [
1230
- prefix,
1231
- messageParts.join(" ")
1232
- ] });
1233
- };
1234
- const ScriptExecutorPanel = ({ onClose }) => {
1235
- const [code, setCode] = useState('// \uC5EC\uAE30\uC5D0 \uC2E4\uD589\uD560 \uCF54\uB4DC\uB97C \uC785\uB825\uD558\uC138\uC694\nconsole.log("Hello, World!");');
1236
- const [results, setResults] = useState([]);
1237
- const addResult = (type, ...args) => {
1238
- setResults((prevResults) => [
1239
- ...prevResults,
1240
- {
1241
- id: Date.now() + Math.random(),
1242
- type,
1243
- timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
1244
- message: args
1245
- }
1246
- ]);
1247
1288
  };
1248
- const handleExecute = () => {
1249
- const originalConsole = { ...console };
1250
- const newConsole = {
1251
- log: (...args) => {
1252
- originalConsole.log(...args);
1253
- addResult("log", ...args);
1254
- },
1255
- warn: (...args) => {
1256
- originalConsole.warn(...args);
1257
- addResult("warn", ...args);
1258
- },
1259
- error: (...args) => {
1260
- originalConsole.error(...args);
1261
- addResult("error", ...args);
1262
- }
1263
- };
1264
- try {
1265
- Object.assign(console, newConsole);
1266
- const result = new Function(code)();
1267
- if (result !== void 0) {
1268
- addResult("return", result);
1269
- }
1270
- } catch (e) {
1271
- addResult("error", e.name, e.message);
1272
- } finally {
1273
- Object.assign(console, originalConsole);
1289
+ const redo = () => {
1290
+ if (historyIndex < history.length - 1) {
1291
+ const newIndex = historyIndex + 1;
1292
+ setHistoryIndex(newIndex);
1293
+ restoreState(newIndex);
1274
1294
  }
1275
1295
  };
1276
- const handleClear = () => {
1277
- setResults([]);
1296
+ const loadImage = (base64String) => {
1297
+ const context = contextRef.current;
1298
+ if (!canvasRefState || !context) {
1299
+ return;
1300
+ }
1301
+ const img = new Image();
1302
+ img.onload = () => {
1303
+ context.clearRect(0, 0, canvasRefState.width, canvasRefState.height);
1304
+ context.drawImage(img, 0, 0, canvasRefState.width, canvasRefState.height);
1305
+ saveState();
1306
+ };
1307
+ img.src = base64String;
1278
1308
  };
1279
- return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1280
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC2A4\uD06C\uB9BD\uD2B8 \uC2E4\uD589", showCloseButton: true }),
1281
- /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx("div", { className: `${styles$2["debug-feature-panel"]} ${styles$2["script-executor-panel"]}`, children: /* @__PURE__ */ jsxs("div", { className: styles$2["script-executor-content"], children: [
1282
- /* @__PURE__ */ jsxs("div", { className: styles$2["script-input-section"], children: [
1283
- /* @__PURE__ */ jsx(
1284
- "textarea",
1285
- {
1286
- className: styles$2["script-textarea"],
1287
- value: code,
1288
- onChange: (e) => setCode(e.target.value),
1289
- spellCheck: "false"
1290
- }
1291
- ),
1292
- /* @__PURE__ */ jsxs("div", { className: styles$2["script-actions"], children: [
1293
- /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleExecute, children: "\uC2E4\uD589 (\u25B6)" }),
1294
- /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleClear, children: "\uACB0\uACFC \uC9C0\uC6B0\uAE30" })
1295
- ] })
1296
- ] }),
1297
- /* @__PURE__ */ jsxs("div", { className: styles$2["script-output-section"], children: [
1298
- /* @__PURE__ */ jsx("div", { className: styles$2["panel-header"], children: /* @__PURE__ */ jsx("h3", { children: "\uACB0\uACFC" }) }),
1299
- /* @__PURE__ */ jsx("div", { className: styles$2["log-list-container"], children: results.map((log) => /* @__PURE__ */ jsxs("div", { className: styles$2["log-item"], children: [
1300
- /* @__PURE__ */ jsx("span", { className: styles$2["log-timestamp"], children: log.timestamp }),
1301
- /* @__PURE__ */ jsx(ResultMessage, { log })
1302
- ] }, log.id)) })
1303
- ] })
1304
- ] }) }) })
1305
- ] }) });
1306
- };
1307
-
1308
- const setCookie = (name, value) => {
1309
- document.cookie = `${name}=${encodeURIComponent(value)};path=/`;
1310
- };
1311
- const removeCookie = (name) => {
1312
- document.cookie = `${name}=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
1313
- };
1314
- const useStorage = (storageType) => {
1315
- const [items, setItems] = useState([]);
1316
- const loadItems = useCallback(() => {
1317
- const newItems = [];
1318
- if (storageType === "localStorage") {
1319
- for (let i = 0; i < localStorage.length; i++) {
1320
- const key = localStorage.key(i);
1321
- if (key) {
1322
- newItems.push({ key, value: localStorage.getItem(key) || "" });
1323
- }
1309
+ const getBase64String = (imageProps) => {
1310
+ const props = { ...DEFAULT_DOWNLOAD_PROPS, ...imageProps };
1311
+ const { fileExtendsion, transparent, backgroundColor, width, height } = props;
1312
+ const originalCanvas = canvasRefState;
1313
+ if (!originalCanvas) {
1314
+ return;
1315
+ }
1316
+ const tempCanvas = document.createElement("canvas");
1317
+ tempCanvas.width = width;
1318
+ tempCanvas.height = height;
1319
+ const tempCtx = tempCanvas.getContext("2d");
1320
+ if (tempCtx) {
1321
+ if (!transparent) {
1322
+ tempCtx.fillStyle = backgroundColor || "white";
1323
+ tempCtx.fillRect(0, 0, width, height);
1324
1324
  }
1325
- } else {
1326
- const cookies = document.cookie.split(";");
1327
- cookies.forEach((cookie) => {
1328
- const parts = cookie.split("=");
1329
- const key = parts.shift()?.trim();
1330
- if (key) {
1331
- newItems.push({ key, value: decodeURIComponent(parts.join("=")) });
1332
- }
1333
- });
1325
+ tempCtx.drawImage(originalCanvas, 0, 0, width, height);
1326
+ return tempCanvas.toDataURL(`image/${fileExtendsion}`);
1334
1327
  }
1335
- setItems(newItems);
1336
- }, [storageType]);
1337
- useEffect(() => {
1338
- loadItems();
1339
- }, [loadItems]);
1340
- const setItem = useCallback(
1341
- (key, value) => {
1342
- if (storageType === "localStorage") {
1343
- localStorage.setItem(key, value);
1344
- } else {
1345
- setCookie(key, value);
1328
+ };
1329
+ const download = (downloadProps) => {
1330
+ const props = { ...DEFAULT_DOWNLOAD_PROPS, ...downloadProps };
1331
+ const { fileName, fileExtendsion, transparent, backgroundColor, width, height } = props;
1332
+ const originalCanvas = canvasRefState;
1333
+ if (!originalCanvas) {
1334
+ return;
1335
+ }
1336
+ const tempCanvas = document.createElement("canvas");
1337
+ tempCanvas.width = width;
1338
+ tempCanvas.height = height;
1339
+ const tempCtx = tempCanvas.getContext("2d");
1340
+ if (tempCtx) {
1341
+ if (!transparent) {
1342
+ tempCtx.fillStyle = backgroundColor || "white";
1343
+ tempCtx.fillRect(0, 0, width, height);
1346
1344
  }
1347
- loadItems();
1348
- },
1349
- [storageType, loadItems]
1350
- );
1351
- const removeItem = useCallback(
1352
- (key) => {
1353
- if (storageType === "localStorage") {
1354
- localStorage.removeItem(key);
1355
- } else {
1356
- removeCookie(key);
1345
+ tempCtx.drawImage(originalCanvas, 0, 0, width, height);
1346
+ const link = document.createElement("a");
1347
+ link.download = `${fileName}.${fileExtendsion}`;
1348
+ link.href = tempCanvas.toDataURL(`image/${fileExtendsion}`);
1349
+ link.click();
1350
+ }
1351
+ };
1352
+ const isCanvasBlank = () => {
1353
+ if (!canvasRefState) {
1354
+ return true;
1355
+ }
1356
+ const { width, height } = canvasRefState;
1357
+ const ctx = canvasRefState.getContext("2d");
1358
+ if (!ctx) {
1359
+ console.error("2D context not available");
1360
+ return true;
1361
+ }
1362
+ const imageData = ctx.getImageData(0, 0, width, height);
1363
+ const { data } = imageData;
1364
+ for (let i = 0; i < data.length; i += 4) {
1365
+ if (data[i + 3] !== 0) {
1366
+ return false;
1357
1367
  }
1358
- loadItems();
1359
- },
1360
- [storageType, loadItems]
1361
- );
1362
- return { items, setItem, removeItem, loadItems };
1363
- };
1368
+ }
1369
+ return true;
1370
+ };
1371
+ return {
1372
+ clear,
1373
+ undo,
1374
+ redo,
1375
+ loadImage,
1376
+ download,
1377
+ getBase64String,
1378
+ isCanvasBlank,
1379
+ setCanvasRefState,
1380
+ canvasRefState
1381
+ };
1382
+ }
1364
1383
 
1365
- const ValueDisplay = ({ value }) => {
1366
- try {
1367
- const parsed = JSON.parse(value);
1368
- if (typeof parsed === "object" && parsed !== null) {
1369
- return /* @__PURE__ */ jsx("pre", { className: styles$2["log-content"], children: JSON.stringify(parsed, null, 2) });
1384
+ const testSignatureBase64Data = "data:image/png;base64,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";
1385
+
1386
+ const FloatingButton = ({ onClick }) => {
1387
+ const [position, setPosition] = useState({ x: 0, y: 0 });
1388
+ const [isDragging, setIsDragging] = useState(false);
1389
+ const dragHappened = useRef(false);
1390
+ const dragStartPos = useRef({ x: 0, y: 0 });
1391
+ const elementStartPos = useRef({ x: 0, y: 0 });
1392
+ const handleMouseDown = (e) => {
1393
+ if (e.button !== 0) {
1394
+ return;
1370
1395
  }
1371
- } catch (e) {
1372
- }
1373
- return /* @__PURE__ */ jsx("div", { className: styles$2["log-content"], children: value });
1374
- };
1375
- const EditableRow = ({ item, onSave, onRemove }) => {
1376
- const [isEditing, setIsEditing] = useState(false);
1377
- const [value, setValue] = useState(item.value);
1378
- const handleSave = () => {
1379
- onSave(item.key, value);
1380
- setIsEditing(false);
1396
+ dragHappened.current = false;
1397
+ setIsDragging(true);
1398
+ dragStartPos.current = { x: e.clientX, y: e.clientY };
1399
+ elementStartPos.current = { ...position };
1400
+ const handleMouseMove = (event) => {
1401
+ const dx = event.clientX - dragStartPos.current.x;
1402
+ const dy = event.clientY - dragStartPos.current.y;
1403
+ if (!dragHappened.current && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
1404
+ dragHappened.current = true;
1405
+ }
1406
+ setPosition({
1407
+ x: elementStartPos.current.x + dx,
1408
+ y: elementStartPos.current.y + dy
1409
+ });
1410
+ };
1411
+ const handleMouseUp = () => {
1412
+ window.removeEventListener("mousemove", handleMouseMove);
1413
+ window.removeEventListener("mouseup", handleMouseUp);
1414
+ setIsDragging(false);
1415
+ };
1416
+ window.addEventListener("mousemove", handleMouseMove);
1417
+ window.addEventListener("mouseup", handleMouseUp);
1381
1418
  };
1382
- const handleEdit = () => {
1383
- setValue(item.value);
1384
- setIsEditing(true);
1419
+ const handleClick = (e) => {
1420
+ if (dragHappened.current) {
1421
+ e.preventDefault();
1422
+ e.stopPropagation();
1423
+ return;
1424
+ }
1425
+ onClick();
1385
1426
  };
1386
- return /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsxs(Accordion.Item, { children: [
1387
- /* @__PURE__ */ jsxs(Accordion.HeaderButton, { children: [
1388
- " ",
1389
- item.key
1390
- ] }),
1391
- /* @__PURE__ */ jsxs(Accordion.Content, { variant: "text", style: { flex: 1, display: "flex", flexDirection: "column" }, children: [
1392
- isEditing ? /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleSave, children: "Save" }) : /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleEdit, children: "Edit" }),
1393
- /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: () => onRemove(item.key), children: "Remove" }),
1394
- isEditing ? /* @__PURE__ */ jsx("textarea", { value, onChange: (e) => setValue(e.target.value) }) : /* @__PURE__ */ jsx(ValueDisplay, { value: item.value })
1395
- ] })
1396
- ] }) });
1397
- };
1398
- const StoragePanel = ({ onClose, storageType }) => {
1399
- const { items, setItem, removeItem } = useStorage(storageType);
1400
- const [filter, setFilter] = useState("");
1401
- const filteredItems = useMemo(() => {
1402
- if (!filter) {
1403
- return items;
1427
+ return /* @__PURE__ */ jsx(
1428
+ Button,
1429
+ {
1430
+ variant: "secondary",
1431
+ appearance: "filled",
1432
+ size: "xsmall",
1433
+ className: styles$3["debug-floating-button"],
1434
+ style: {
1435
+ transform: `translate(${position.x}px, ${position.y}px)`,
1436
+ cursor: isDragging ? "grabbing" : "grab"
1437
+ },
1438
+ onMouseDown: handleMouseDown,
1439
+ onClick: handleClick,
1440
+ children: "DEBUG"
1404
1441
  }
1405
- return items.filter(
1406
- (item) => item.key.toLowerCase().includes(filter.toLowerCase()) || item.value.toLowerCase().includes(filter.toLowerCase())
1407
- );
1408
- }, [items, filter]);
1409
- return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1410
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: storageType === "localStorage" ? "Local Storage" : "Cookies", showCloseButton: true }),
1411
- /* @__PURE__ */ jsxs(Modal.Body, { children: [
1412
- /* @__PURE__ */ jsx("div", { className: styles$2["panel-toolbar"], children: /* @__PURE__ */ jsx(
1413
- FormField.TextField,
1414
- {
1415
- placeholder: "Search key or value...",
1416
- size: "xsmall",
1417
- value: filter,
1418
- onChange: (e) => setFilter(e.target.value),
1419
- rootProps: { style: { width: "100%" } }
1420
- }
1421
- ) }),
1422
- /* @__PURE__ */ jsx("ul", { children: filteredItems.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(EditableRow, { item, onSave: setItem, onRemove: removeItem }) }, item.key)) })
1423
- ] })
1424
- ] }) });
1442
+ );
1425
1443
  };
1426
1444
 
1427
- const loginTypes = [
1428
- {
1429
- id: "fp",
1430
- label: "FP \uB85C\uADF8\uC778",
1431
- fields: [{ name: "employeeId", label: "\uC0AC\uBC88", type: "text", placeholder: "\uC0AC\uBC88\uC744 \uC785\uB825\uD558\uC138\uC694" }]
1432
- },
1433
- {
1434
- id: "customer",
1435
- label: "\uACE0\uAC1D \uB85C\uADF8\uC778",
1436
- fields: [
1437
- { name: "name", label: "\uC774\uB984", type: "text", placeholder: "\uC774\uB984" },
1438
- { name: "phone", label: "\uC804\uD654\uBC88\uD638", type: "tel", placeholder: "\uC804\uD654\uBC88\uD638" },
1439
- { name: "residentNumber", label: "\uC8FC\uBBFC\uBC88\uD638", type: "text", placeholder: "\uC8FC\uBBFC\uBC88\uD638 \uC55E 7\uC790\uB9AC" },
1440
- { name: "userId", label: "\uC544\uC774\uB514", type: "text", placeholder: "\uC544\uC774\uB514" },
1441
- { name: "password", label: "\uBE44\uBC00\uBC88\uD638", type: "password", placeholder: "\uBE44\uBC00\uBC88\uD638" }
1442
- ]
1443
- }
1444
- ];
1445
- const menuItems = [
1446
- {
1447
- id: "network-log",
1448
- label: "\uB124\uD2B8\uC6CC\uD06C \uB85C\uADF8",
1449
- component: NetworkLog,
1450
- display: true
1451
- },
1452
- {
1453
- id: "console-log",
1454
- label: "\uCF58\uC194 \uB85C\uADF8 \uD655\uC778",
1455
- component: ConsoleLogPanel,
1456
- display: true
1457
- },
1458
- {
1459
- id: "local-storage",
1460
- label: "\uB85C\uCEEC \uC2A4\uD1A0\uB9AC\uC9C0 \uAD00\uB9AC",
1461
- // StoragePanel은 재사용 가능한 컴포넌트이므로, props를 통해 어떤 스토리지를 다룰지 지정합니다.
1462
- component: (props) => /* @__PURE__ */ jsx(StoragePanel, { ...props, storageType: "localStorage" }),
1463
- display: true
1464
- },
1465
- {
1466
- id: "cookie-management",
1467
- label: "\uCFE0\uD0A4 \uAD00\uB9AC",
1468
- component: (props) => /* @__PURE__ */ jsx(StoragePanel, { ...props, storageType: "cookie" }),
1469
- display: true
1470
- },
1471
- {
1472
- id: "quick-login",
1473
- label: "\uAC04\uD3B8 \uB85C\uADF8\uC778",
1474
- component: LoginPanel,
1475
- display: true
1476
- // 실제 표시는 DebugTool.tsx에서 onLogin prop 존재 여부에 따라 결정됩니다.
1477
- },
1478
- {
1479
- id: "script-executor",
1480
- label: "\uC2A4\uD06C\uB9BD\uD2B8 \uC2E4\uD589",
1481
- component: ScriptExecutorPanel,
1482
- display: true
1483
- },
1484
- {
1485
- id: "page-navigation",
1486
- label: "\uD398\uC774\uC9C0 \uC774\uB3D9",
1487
- component: PageNavigationPanel,
1488
- display: true
1489
- }
1490
- ];
1491
-
1492
- const useEnvironment = () => {
1493
- const [envInfo, setEnvInfo] = useState({
1494
- env: "prd"
1495
- });
1496
- useEffect(() => {
1497
- const { hostname } = window.location;
1498
- setEnvInfo({ env: getEnvironmentFromHostname(hostname) });
1499
- }, []);
1500
- return envInfo;
1445
+ const MenuPanel = ({ menuItems, onMenuItemClick, onClose }) => {
1446
+ return /* @__PURE__ */ jsxs(Modal.Root, { isOpen: true, onClose, modalSize: "small", children: [
1447
+ /* @__PURE__ */ jsx(Modal.Overlay, {}),
1448
+ /* @__PURE__ */ jsxs(Modal.Content, { children: [
1449
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "Debug Menu", showCloseButton: true }),
1450
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx(List, { selectable: true, children: menuItems.map((item) => /* @__PURE__ */ jsx(ListItem, { onClick: () => onMenuItemClick(item.component), children: item.label }, item.id)) }) })
1451
+ ] })
1452
+ ] });
1501
1453
  };
1502
1454
 
1503
- const DebugTool = ({ onLogin, envOverride, menuItemsOverride }) => {
1504
- useEffect(() => {
1505
- initializeConsoleLogOverride();
1506
- return () => {
1507
- restoreConsoleLog();
1508
- };
1509
- }, []);
1510
- const environment = useEnvironment();
1511
- const env = envOverride || environment.env;
1512
- const menuItems$1 = menuItemsOverride || menuItems;
1513
- const [isMenuOpen, setMenuOpen] = useState(false);
1514
- const [activeFeature, setActiveFeature] = useState(null);
1515
- const isVisible = ["local", "dev", "stg"].includes(env);
1516
- const handleMenuClick = (itemComponent) => {
1517
- setActiveFeature(() => itemComponent);
1518
- setMenuOpen(false);
1519
- };
1520
- const handleCloseFeature = () => {
1521
- setActiveFeature(null);
1522
- };
1523
- if (!isVisible) {
1524
- return null;
1525
- }
1526
- const toggleMenu = () => {
1527
- setMenuOpen((prev) => !prev);
1528
- if (!isMenuOpen) {
1529
- setActiveFeature(null);
1530
- }
1455
+ let globalLogs = [];
1456
+ let listeners = [];
1457
+ const originalConsoleMethods = {};
1458
+ let isConsoleOverridden = false;
1459
+ const addLog = (type, ...args) => {
1460
+ const newLog = {
1461
+ id: Date.now() + Math.random(),
1462
+ type,
1463
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
1464
+ message: args
1531
1465
  };
1532
- const availableMenuItems = menuItems$1.filter(
1533
- (item) => item.display && // config에서 display가 true인 항목만 필터링합니다.
1534
- // 'quick-login' 기능은 onLogin prop이 제공된 경우에만 활성화합니다.
1535
- (item.id !== "quick-login" || item.id === "quick-login" && onLogin)
1536
- );
1537
- if (activeFeature) {
1538
- const FeatureComponent = activeFeature;
1539
- return /* @__PURE__ */ jsx(FeatureComponent, { onClose: handleCloseFeature, onLogin });
1466
+ globalLogs = [...globalLogs, newLog];
1467
+ listeners.forEach((listener) => listener([...globalLogs]));
1468
+ };
1469
+ const initializeConsoleLogOverride = () => {
1470
+ if (!isClient() || isConsoleOverridden) {
1471
+ return;
1540
1472
  }
1541
- return /* @__PURE__ */ jsxs("div", { className: "debug-tool-container", children: [
1542
- /* @__PURE__ */ jsx(FloatingButton, { onClick: toggleMenu }),
1543
- isMenuOpen && /* @__PURE__ */ jsx(
1544
- MenuPanel,
1545
- {
1546
- menuItems: availableMenuItems,
1547
- onMenuItemClick: handleMenuClick,
1548
- onClose: () => setMenuOpen(false)
1473
+ const logTypes = ["log", "info", "warn", "error", "debug"];
1474
+ logTypes.forEach((type) => {
1475
+ originalConsoleMethods[type] = console[type];
1476
+ console[type] = (...args) => {
1477
+ if (originalConsoleMethods[type]) {
1478
+ originalConsoleMethods[type]?.apply(console, args);
1549
1479
  }
1550
- )
1551
- ] });
1480
+ addLog(type, ...args);
1481
+ };
1482
+ });
1483
+ isConsoleOverridden = true;
1552
1484
  };
1553
-
1554
- const highlightOnSearchKeyword = (originalText, targetString) => {
1555
- if (originalText?.includes(targetString)) {
1556
- const replacedText = [];
1557
- const splitText = originalText.split(targetString);
1558
- for (let i = 0; i < splitText.length; i++) {
1559
- replacedText.push(splitText[i]);
1560
- if (i !== splitText.length - 1) {
1561
- replacedText.push(/* @__PURE__ */ jsx("span", { className: "text-primary", children: targetString }));
1562
- }
1563
- }
1564
- return replacedText;
1485
+ const restoreConsoleLog = () => {
1486
+ if (!isClient() || !isConsoleOverridden) {
1487
+ return;
1565
1488
  }
1566
- return originalText;
1567
- };
1568
-
1569
- const cx$7 = classNames.bind(styles$4);
1570
- const { InputBox, Input } = FormCore;
1571
- const AddressSearchInitialText = () => {
1572
- return /* @__PURE__ */ jsxs("div", { children: [
1573
- /* @__PURE__ */ jsx("p", { className: cx$7("guide-title"), children: "\uC774\uB807\uAC8C \uAC80\uC0C9\uD574 \uBCF4\uC138\uC694." }),
1574
- /* @__PURE__ */ jsxs("ul", { className: cx$7("guide"), children: [
1575
- /* @__PURE__ */ jsx("li", { children: "\uB3C4\uB85C\uBA85/\uC9C0\uBA85\uACFC \uAC74\uBB3C\uBC88\uD638\uB97C \uD568\uAED8 \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
1576
- /* @__PURE__ */ jsx("li", { children: "\uC608) 63\uB85C 50, \uC5EC\uC758\uB3C4\uB3D9 60" }),
1577
- /* @__PURE__ */ jsx("li", { children: "\uC9C0\uBA85\uC740 \uB3D9/\uC74D/\uBA74/\uB9AC\uB85C \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
1578
- /* @__PURE__ */ jsx("li", { children: "\uC608) \uC5EC\uC758\uB3C4\uB3D9, \uC5ED\uC0BC\uB3D9" }),
1579
- /* @__PURE__ */ jsx("li", { children: "\uC6B0\uD3B8\uBC88\uD638 \uB2E4\uC12F\uC790\uB9AC\uB97C \uBAA8\uB450 \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
1580
- /* @__PURE__ */ jsx("li", { children: "\uC608) 07345, 06232" })
1581
- ] })
1582
- ] });
1489
+ const logTypes = ["log", "info", "warn", "error", "debug"];
1490
+ logTypes.forEach((type) => {
1491
+ if (originalConsoleMethods[type]) {
1492
+ console[type] = originalConsoleMethods[type];
1493
+ }
1494
+ });
1495
+ isConsoleOverridden = false;
1583
1496
  };
1584
- const AddressSearchResult = ({
1585
- addressSearchList,
1586
- onChange,
1587
- searchKeyword,
1588
- selectedAddress
1589
- }) => {
1590
- const [filterList, setFilterList] = useState([]);
1497
+ const useConsoleLog = () => {
1498
+ const [logs, setLogs] = useState(globalLogs);
1591
1499
  useEffect(() => {
1592
- const filterList2 = addressSearchList.filter(
1593
- (item) => item.address.includes(searchKeyword) || item.oldAddress.includes(searchKeyword)
1594
- ) || [];
1595
- setFilterList(filterList2);
1596
- }, [addressSearchList, searchKeyword]);
1597
- return /* @__PURE__ */ jsxs("div", { children: [
1598
- /* @__PURE__ */ jsxs("p", { className: cx$7("guide-title"), children: [
1599
- "\uCD1D ",
1600
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: filterList.length }),
1601
- "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
1602
- ] }),
1603
- filterList.length > 0 && /* @__PURE__ */ jsx(
1604
- RadioGroup,
1605
- {
1606
- items: filterList.map((item) => ({
1607
- value: item.address,
1608
- select: item.address === selectedAddress?.address && item.zipCode === selectedAddress?.zipCode,
1609
- label: /* @__PURE__ */ jsxs("div", { className: cx$7("search-result"), children: [
1610
- /* @__PURE__ */ jsxs("div", { className: cx$7("zipcode"), children: [
1611
- " ",
1612
- highlightOnSearchKeyword(item.zipCode, searchKeyword)
1613
- ] }),
1614
- /* @__PURE__ */ jsx("div", { className: cx$7("divider") }),
1615
- /* @__PURE__ */ jsxs("div", { className: cx$7("address-info"), children: [
1616
- /* @__PURE__ */ jsx("span", { className: cx$7("address"), children: highlightOnSearchKeyword(item.address, searchKeyword) }),
1617
- /* @__PURE__ */ jsx("span", { className: cx$7("old-address"), children: highlightOnSearchKeyword(item.oldAddress, searchKeyword) })
1618
- ] })
1619
- ] }),
1620
- id: item.address
1621
- })),
1622
- className: cx$7("radio-group"),
1623
- name: "address-search",
1624
- size: "medium",
1625
- defaultValue: "",
1626
- onChange
1627
- }
1628
- ),
1629
- filterList.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1630
- "`",
1631
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchKeyword }),
1632
- "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
1633
- ] })
1634
- ] });
1500
+ listeners.push(setLogs);
1501
+ return () => {
1502
+ listeners = listeners.filter((l) => l !== setLogs);
1503
+ };
1504
+ }, []);
1505
+ const clearLogs = useCallback(() => {
1506
+ globalLogs = [];
1507
+ listeners.forEach((listener) => listener([]));
1508
+ }, []);
1509
+ return { logs, clearLogs };
1635
1510
  };
1636
- const AddressSearchDetailInput = ({
1637
- selectedAddress,
1638
- onDetailChange,
1639
- step,
1640
- detailAddressInput
1641
- }) => {
1642
- return /* @__PURE__ */ jsxs("div", { children: [
1643
- /* @__PURE__ */ jsxs("div", { children: [
1644
- /* @__PURE__ */ jsxs("div", { children: [
1645
- " ",
1646
- selectedAddress.zipCode
1647
- ] }),
1648
- /* @__PURE__ */ jsxs("div", { children: [
1649
- "|",
1650
- /* @__PURE__ */ jsx("span", { children: `${selectedAddress.address}` })
1651
- ] })
1652
- ] }),
1653
- /* @__PURE__ */ jsxs("div", { children: [
1654
- /* @__PURE__ */ jsx(FormField.Label, { id: "detail", style: { width: "90px" }, children: "\uC0C1\uC138\uC8FC\uC18C" }),
1655
- /* @__PURE__ */ jsx(
1656
- Input,
1657
- {
1658
- placeholder: "\uC0C1\uC138\uC8FC\uC18C \uC785\uB825",
1659
- onChange: onDetailChange,
1660
- size: "large",
1661
- value: detailAddressInput,
1662
- ...step === "detail-input" && { autoFocus: true }
1663
- }
1664
- )
1665
- ] })
1666
- ] });
1511
+
1512
+ const safeStringify$1 = (obj) => {
1513
+ try {
1514
+ return JSON.stringify(obj, null, 2);
1515
+ } catch (e) {
1516
+ return "[Unserializable Object]";
1517
+ }
1667
1518
  };
1668
- function AddressComponent({ isOpen, onClose, setValue }) {
1669
- const {
1670
- onAddressSearchClear,
1671
- addressSearchKeyword,
1672
- addressSearchStep,
1673
- onAddressSearchNext,
1674
- nextButtonDisabled,
1675
- detailAddressInput,
1676
- addressSearchList,
1677
- onSearch,
1678
- onKeyUp,
1679
- onSelectChange,
1680
- setDetail,
1681
- search,
1682
- searchInput,
1683
- selectedAddress
1684
- } = useSearchAddress({
1685
- setValue,
1686
- onClose,
1687
- isOpen
1519
+ const LogMessage = ({ entry }) => {
1520
+ const messageParts = entry.message.map((part) => {
1521
+ if (typeof part === "object" && part !== null) {
1522
+ return safeStringify$1(part);
1523
+ }
1524
+ return String(part);
1688
1525
  });
1689
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Modal.Root, { isOpen, onClose, modalSize: "full-screen", children: [
1690
- /* @__PURE__ */ jsx(Modal.Overlay, {}),
1691
- /* @__PURE__ */ jsxs(Modal.Content, { children: [
1692
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC8FC\uC18C \uAC80\uC0C9", showCloseButton: true }),
1693
- /* @__PURE__ */ jsxs(Modal.Body, { children: [
1694
- /* @__PURE__ */ jsx(
1695
- InputBox,
1526
+ return /* @__PURE__ */ jsx("pre", { className: `${styles$3["log-message"]} ${styles$3[`log-${entry.type}`]}`, children: messageParts.join(" ") });
1527
+ };
1528
+ const ConsoleLogPanel = ({ onClose }) => {
1529
+ const { logs, clearLogs } = useConsoleLog();
1530
+ const [filter, setFilter] = useState("all");
1531
+ const logContainerRef = useRef(null);
1532
+ const filteredLogs = useMemo(() => {
1533
+ if (filter === "all") {
1534
+ return logs;
1535
+ }
1536
+ return logs.filter((log) => log.type === filter);
1537
+ }, [logs, filter]);
1538
+ useEffect(() => {
1539
+ if (logContainerRef.current) {
1540
+ logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
1541
+ }
1542
+ }, [filteredLogs]);
1543
+ return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1544
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "Console Logs", showCloseButton: true }),
1545
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
1546
+ /* @__PURE__ */ jsxs("div", { className: styles$3["panel-toolbar"], children: [
1547
+ /* @__PURE__ */ jsxs(
1548
+ Segment.Root,
1696
1549
  {
1697
- clearable: true,
1698
- endElement: /* @__PURE__ */ jsx(Icon, { name: "sub-ui/search", onClick: search }),
1699
- onClear: onAddressSearchClear,
1700
- children: /* @__PURE__ */ jsx(
1701
- Input,
1702
- {
1703
- ...addressSearchStep !== "detail-input" && { autoFocus: true },
1704
- onChange: onSearch,
1705
- onKeyUp,
1706
- value: searchInput,
1707
- placeholder: "\uC9C0\uBC88, \uB3C4\uB85C\uBA85, \uAC74\uBB3C\uBA85, \uC6B0\uD3B8\uBC88\uD638 \uC785\uB825",
1708
- size: "large"
1709
- }
1710
- )
1550
+ size: "xsmall",
1551
+ appearance: "outline",
1552
+ align: "left",
1553
+ defaultValue: filter,
1554
+ onValueChange: (value) => setFilter(value),
1555
+ children: [
1556
+ /* @__PURE__ */ jsx(Segment.Item, { value: "all", children: "All" }),
1557
+ /* @__PURE__ */ jsx(Segment.Item, { value: "log", children: "Log" }),
1558
+ /* @__PURE__ */ jsx(Segment.Item, { value: "warn", children: "Warn" }),
1559
+ /* @__PURE__ */ jsx(Segment.Item, { value: "error", children: "Error" })
1560
+ ]
1711
1561
  }
1712
1562
  ),
1713
- addressSearchStep === "initial" && /* @__PURE__ */ jsx(AddressSearchInitialText, {}),
1714
- addressSearchStep === "search-result" && /* @__PURE__ */ jsx(
1715
- AddressSearchResult,
1563
+ /* @__PURE__ */ jsx(
1564
+ Button,
1565
+ {
1566
+ variant: "neutral",
1567
+ appearance: "outline",
1568
+ size: "xsmall",
1569
+ onClick: clearLogs,
1570
+ style: { marginLeft: "auto" },
1571
+ children: "Clear"
1572
+ }
1573
+ )
1574
+ ] }),
1575
+ /* @__PURE__ */ jsx("div", { className: styles$3["log-list-container"], ref: logContainerRef, children: filteredLogs.map((log) => /* @__PURE__ */ jsxs("div", { className: styles$3["log-item"], children: [
1576
+ /* @__PURE__ */ jsx("span", { className: styles$3["log-timestamp"], children: log.timestamp }),
1577
+ /* @__PURE__ */ jsx(LogMessage, { entry: log })
1578
+ ] }, log.id)) })
1579
+ ] })
1580
+ ] }) });
1581
+ };
1582
+
1583
+ const LoginPanel = ({ onClose, onLogin }) => {
1584
+ const [selectedTypeId, setSelectedTypeId] = useState(loginTypes[0]?.id || "");
1585
+ const [formData, setFormData] = useState({});
1586
+ const selectedType = useMemo(() => loginTypes.find((t) => t.id === selectedTypeId), [selectedTypeId]);
1587
+ const handleInputChange = (e) => {
1588
+ const { name, value } = e.target;
1589
+ setFormData((prev) => ({ ...prev, [name]: value }));
1590
+ };
1591
+ const handleSubmit = (e) => {
1592
+ e.preventDefault();
1593
+ if (selectedType) {
1594
+ onLogin(selectedType.id, formData);
1595
+ onClose();
1596
+ }
1597
+ };
1598
+ useEffect(() => {
1599
+ setFormData({});
1600
+ }, [selectedType]);
1601
+ return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1602
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uAC04\uD3B8 \uB85C\uADF8\uC778", showCloseButton: true }),
1603
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs("form", { className: styles$3["login-form-container"], onSubmit: handleSubmit, children: [
1604
+ /* @__PURE__ */ jsxs(FormField.FieldControl, { children: [
1605
+ /* @__PURE__ */ jsx(FormField.Label, { htmlFor: "login-type-select", children: "\uB85C\uADF8\uC778 \uC720\uD615" }),
1606
+ /* @__PURE__ */ jsx(
1607
+ Select,
1716
1608
  {
1717
- onChange: onSelectChange,
1718
- addressSearchList: addressSearchList || [],
1719
- searchKeyword: addressSearchKeyword,
1720
- selectedAddress
1609
+ value: selectedTypeId,
1610
+ onChange: setSelectedTypeId,
1611
+ size: "xsmall",
1612
+ rootProps: { style: { width: "100%" } },
1613
+ children: loginTypes.map((type) => /* @__PURE__ */ jsx(Select.Option, { value: type.id, children: type.label }, type.id))
1721
1614
  }
1722
- ),
1723
- addressSearchStep === "detail-input" && selectedAddress && /* @__PURE__ */ jsx(
1724
- AddressSearchDetailInput,
1615
+ )
1616
+ ] }),
1617
+ selectedType?.fields.map((field) => /* @__PURE__ */ jsxs(FormField.FieldControl, { children: [
1618
+ /* @__PURE__ */ jsx(FormField.Label, { htmlFor: field.name, children: field.label }),
1619
+ /* @__PURE__ */ jsx(
1620
+ FormField.TextField,
1725
1621
  {
1726
- selectedAddress,
1727
- onDetailChange: setDetail,
1728
- step: addressSearchStep,
1729
- detailAddressInput
1622
+ size: "xsmall",
1623
+ type: field.type,
1624
+ id: field.name,
1625
+ name: field.name,
1626
+ placeholder: field.placeholder,
1627
+ value: formData[field.name] || "",
1628
+ onChange: handleInputChange,
1629
+ required: true
1730
1630
  }
1731
1631
  )
1732
- ] }),
1733
- /* @__PURE__ */ jsx(Modal.Footer, { children: addressSearchStep !== "initial" && /* @__PURE__ */ jsxs(
1734
- Button,
1735
- {
1736
- onClick: onAddressSearchNext,
1737
- variant: "primary",
1738
- size: "medium",
1739
- appearance: "filled",
1740
- width: "full",
1741
- disabled: nextButtonDisabled,
1742
- children: [
1743
- addressSearchStep === "search-result" && "\uB2E4\uC74C(1/2)",
1744
- addressSearchStep === "detail-input" && "\uD655\uC778(2/2)"
1745
- ]
1746
- }
1747
- ) })
1748
- ] })
1632
+ ] }, field.name)),
1633
+ /* @__PURE__ */ jsx("div", { className: styles$3["form-actions"], children: /* @__PURE__ */ jsx(Button, { type: "submit", variant: "primary", appearance: "filled", size: "xsmall", children: "\uB85C\uADF8\uC778" }) })
1634
+ ] }) })
1749
1635
  ] }) });
1750
- }
1636
+ };
1751
1637
 
1752
- function useSearchAddress({ setValue, onClose, isOpen }) {
1753
- const [searchKeyword, setSearchKeyword] = useState("");
1754
- const [step, setStep] = useState("initial");
1755
- const [selectedAddress, setSelectedAddress] = useState(null);
1756
- const [searchInput, setSearchInput] = useState("");
1757
- const [detailAddressInput, setDetailAddressInput] = useState("");
1758
- const { data: addressList } = useSearchModalAddressQuery({ searchKeyword });
1759
- const [nextButtonDisabled, setNextButtonDisabled] = useState(false);
1760
- const onNext = () => {
1761
- if (step === "search-result") {
1762
- setStep("detail-input");
1763
- setNextButtonDisabled(true);
1764
- } else {
1765
- setValue({
1766
- address: selectedAddress?.address || "",
1767
- oldAddress: selectedAddress?.oldAddress || "",
1768
- zipCode: selectedAddress?.zipCode || "",
1769
- detail: detailAddressInput || ""
1770
- });
1771
- onClose();
1638
+ const SEARCH_SECTIONS = [
1639
+ { value: "all", label: "\uC804\uCCB4" },
1640
+ { value: "url", label: "\uC8FC\uC18C" },
1641
+ { value: "headers", label: "\uD5E4\uB354" },
1642
+ { value: "params", label: "\uD30C\uB77C\uBBF8\uD130" },
1643
+ { value: "data", label: "\uC694\uCCAD" },
1644
+ { value: "response", label: "\uC751\uB2F5" },
1645
+ { value: "error", label: "\uC5D0\uB7EC" }
1646
+ ];
1647
+ const getLogInfo = (log) => {
1648
+ if (log.holdStatus === "held") {
1649
+ if ("request" in log) {
1650
+ return log.request;
1772
1651
  }
1773
- };
1774
- const onSearch = (e) => {
1775
- const typeStr = e.target.value;
1776
- setSearchInput(typeStr);
1777
- };
1778
- const search = () => {
1779
- if (searchInput === "") {
1780
- onClear();
1781
- return;
1652
+ if ("response" in log) {
1653
+ return log.response;
1782
1654
  }
1783
- if (searchInput && searchInput.length > 1) {
1784
- setSearchKeyword(searchInput);
1785
- setStep("search-result");
1786
- setSelectedAddress(null);
1787
- setDetailAddressInput("");
1788
- setNextButtonDisabled(true);
1655
+ if ("error" in log) {
1656
+ return log.error;
1789
1657
  }
1790
- };
1791
- const onKeyUp = (e) => {
1792
- if (e.key === "Enter") {
1793
- search();
1658
+ }
1659
+ return log;
1660
+ };
1661
+ const NetworkLog = ({ onClose }) => {
1662
+ const {
1663
+ requests,
1664
+ responses,
1665
+ errors,
1666
+ clear,
1667
+ isHold,
1668
+ toggleHold,
1669
+ heldRequests,
1670
+ heldResponses,
1671
+ heldErrors,
1672
+ playAllRequests,
1673
+ playAllResponses
1674
+ } = useDebugStore();
1675
+ const [searchTerm, setSearchTerm] = useState("");
1676
+ const [searchSection, setSearchSection] = useState(SEARCH_SECTIONS[0]?.value);
1677
+ const allLogs = useMemo(() => {
1678
+ const logs = [];
1679
+ requests.forEach((req) => logs.push({ ...req, type: "request" }));
1680
+ responses.forEach((res) => logs.push({ ...res, type: "response" }));
1681
+ errors.forEach((err) => logs.push({ ...err, type: "error" }));
1682
+ heldRequests.forEach((req) => logs.push({ ...req, type: "request", holdStatus: "held" }));
1683
+ heldResponses.forEach((res) => logs.push({ ...res, type: "response", holdStatus: "held" }));
1684
+ heldErrors.forEach((err) => logs.push({ ...err, type: "error", holdStatus: "held" }));
1685
+ logs.sort((a, b) => {
1686
+ const aInfo = getLogInfo(a);
1687
+ const bInfo = getLogInfo(b);
1688
+ const aTime = "startTime" in aInfo ? aInfo.startTime : 0;
1689
+ const bTime = "startTime" in bInfo ? bInfo.startTime : 0;
1690
+ return bTime - aTime;
1691
+ });
1692
+ return logs;
1693
+ }, [requests, responses, errors, heldRequests, heldResponses, heldErrors]);
1694
+ const filteredLogs = useMemo(() => {
1695
+ if (!searchTerm) {
1696
+ return allLogs;
1794
1697
  }
1795
- };
1796
- const onSelectChange = (e) => {
1797
- const selectedAddress2 = e.target.value;
1798
- if (selectedAddress2) {
1799
- const adr = addressList?.find((addr) => {
1800
- return addr.address === selectedAddress2;
1801
- });
1802
- setSelectedAddress(adr || null);
1803
- setNextButtonDisabled(false);
1698
+ const lowercasedTerm = searchTerm.toLowerCase();
1699
+ return allLogs.filter((log) => {
1700
+ const logInfo = getLogInfo(log);
1701
+ switch (searchSection) {
1702
+ case "url":
1703
+ return logInfo.url?.toLowerCase().includes(lowercasedTerm);
1704
+ case "headers":
1705
+ return "headers" in logInfo && logInfo.headers && JSON.stringify(logInfo.headers)?.toLowerCase().includes(lowercasedTerm);
1706
+ case "params":
1707
+ return "params" in logInfo && logInfo.params && JSON.stringify(logInfo.params)?.toLowerCase().includes(lowercasedTerm);
1708
+ case "data":
1709
+ return "data" in logInfo && logInfo.data && log.type === "request" && JSON.stringify(logInfo.data)?.toLowerCase().includes(lowercasedTerm);
1710
+ case "response":
1711
+ return "data" in logInfo && logInfo.data && log.type === "response" && JSON.stringify(logInfo.data)?.toLowerCase().includes(lowercasedTerm);
1712
+ case "error":
1713
+ return log.type === "error" && JSON.stringify(logInfo)?.toLowerCase().includes(lowercasedTerm);
1714
+ case "all":
1715
+ default:
1716
+ return JSON.stringify(logInfo).toLowerCase().includes(lowercasedTerm);
1717
+ }
1718
+ });
1719
+ }, [allLogs, searchTerm, searchSection]);
1720
+ const renderLogSummary = (log) => {
1721
+ const logInfo = getLogInfo(log);
1722
+ const prefix = log.holdStatus === "held" ? "[HELD] " : "";
1723
+ if (log.type === "request") {
1724
+ return `${prefix}[REQ] ${logInfo.method.toUpperCase()} ${logInfo.url}`;
1804
1725
  }
1805
- };
1806
- const onClear = useCallback(() => {
1807
- setSearchKeyword("");
1808
- setSearchInput("");
1809
- setSelectedAddress(null);
1810
- setDetailAddressInput("");
1811
- setStep("initial");
1812
- }, []);
1813
- const setDetail = (e) => {
1814
- const detail = e.target.value;
1815
- setDetailAddressInput(detail);
1816
- if (detail) {
1817
- setNextButtonDisabled(false);
1818
- } else {
1819
- setNextButtonDisabled(true);
1726
+ if (log.type === "response" && "status" in logInfo) {
1727
+ return `${prefix}[RES] ${logInfo.method.toUpperCase()} ${logInfo.url} - ${logInfo.status}`;
1820
1728
  }
1821
- };
1822
- useEffect(() => {
1823
- if (isOpen) {
1824
- setSelectedAddress(null);
1825
- setDetailAddressInput("");
1826
- setStep("initial");
1827
- setSearchKeyword("");
1729
+ if (log.type === "error" && "message" in logInfo) {
1730
+ return `${prefix}[ERR] ${logInfo.method.toUpperCase()} ${logInfo.url} - ${logInfo.message}`;
1828
1731
  }
1829
- }, [isOpen]);
1830
- return {
1831
- onAddressSearchClear: onClear,
1832
- onAddressSearchNext: onNext,
1833
- addressSearchKeyword: searchKeyword,
1834
- addressSearchList: addressList,
1835
- addressSearchStep: step,
1836
- selectedAddress,
1837
- addressSearchOnValueChange: onSelectChange,
1838
- nextButtonDisabled,
1839
- detailAddressInput,
1840
- onSearch,
1841
- onKeyUp,
1842
- onSelectChange,
1843
- setDetail,
1844
- search,
1845
- searchInput
1846
- };
1847
- }
1848
- const useAddressComponent = () => {
1849
- const [fullAddress, setFullAddress] = useState(null);
1850
- const { isOpen, closeModal, openModal } = useModalState();
1851
- const AddressSearchComponent = () => /* @__PURE__ */ jsx(AddressComponent, { isOpen, onClose: closeModal, setValue: setFullAddress });
1852
- return {
1853
- fullAddress,
1854
- openModal,
1855
- AddressSearchComponent
1856
- };
1857
- };
1858
-
1859
- const cx$6 = classNames.bind(styles$5);
1860
- const JobVehicleSearchGrade = ({ riskGrade, hospitalizationGrade }) => {
1861
- return /* @__PURE__ */ jsxs("div", { className: cx$6("grade-section"), children: [
1862
- /* @__PURE__ */ jsxs("div", { className: cx$6("icon-title"), children: [
1863
- /* @__PURE__ */ jsx(Icon, { name: "illust/grade" }),
1864
- /* @__PURE__ */ jsx("span", { className: "typo-title5 text-body", children: "\uB4F1\uAE09" })
1865
- ] }),
1866
- /* @__PURE__ */ jsx("p", { className: "typo-body2 text-body_3", children: "\uC9C1\uC885, \uC6B4\uC804 \uC5EC\uBD80 \uC120\uD0DD\uC2DC \uC790\uB3D9\uC73C\uB85C \uC0B0\uC815\uB429\uB2C8\uB2E4." }),
1867
- /* @__PURE__ */ jsxs("div", { className: cx$6("grade-list"), children: [
1868
- /* @__PURE__ */ jsxs("div", { className: cx$6("grade"), children: [
1869
- /* @__PURE__ */ jsx("span", { children: "\uC704\uD5D8\uB4F1\uAE09" }),
1870
- /* @__PURE__ */ jsx("span", { className: "text-primary typo-subtitle3", children: riskGrade || "-" })
1871
- ] }),
1872
- /* @__PURE__ */ jsxs("div", { className: cx$6("grade"), children: [
1873
- /* @__PURE__ */ jsx("span", { children: "\uC785\uC6D0\uB4F1\uAE09" }),
1874
- /* @__PURE__ */ jsx("span", { className: "text-primary typo-subtitle3", children: hospitalizationGrade || "-" })
1732
+ return "Unknown Log";
1733
+ };
1734
+ const renderLogContent = (log) => {
1735
+ const logInfo = getLogInfo(log);
1736
+ return /* @__PURE__ */ jsx("pre", { children: JSON.stringify(logInfo, null, 2) });
1737
+ };
1738
+ return /* @__PURE__ */ jsxs(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: [
1739
+ /* @__PURE__ */ jsx(Modal.Overlay, {}),
1740
+ /* @__PURE__ */ jsxs(Modal.Content, { children: [
1741
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uB124\uD2B8\uC6CC\uD06C \uB85C\uADF8", showCloseButton: true }),
1742
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
1743
+ /* @__PURE__ */ jsxs("div", { className: styles$4["search-container"], children: [
1744
+ /* @__PURE__ */ jsx(Select, { value: searchSection, onChange: (value) => setSearchSection(value), size: "xsmall", children: SEARCH_SECTIONS.map((option) => /* @__PURE__ */ jsx(Select.Option, { value: option.value, children: option.label }, option.value)) }),
1745
+ /* @__PURE__ */ jsx(
1746
+ FormField.TextField,
1747
+ {
1748
+ placeholder: "\uAC80\uC0C9...",
1749
+ value: searchTerm,
1750
+ size: "xsmall",
1751
+ onChange: (e) => setSearchTerm(e.target.value)
1752
+ }
1753
+ ),
1754
+ /* @__PURE__ */ jsx(Checkbox, { id: "hold-checkbox", checked: isHold, onChange: toggleHold, size: "small", variant: "main", children: "Hold" }),
1755
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: clear, children: "clear" })
1756
+ ] }),
1757
+ isHold && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "row" }, children: [
1758
+ /* @__PURE__ */ jsx(Button, { size: "xsmall", onClick: () => playAllRequests(), variant: "primary", appearance: "outline", children: "REQ Resolve" }),
1759
+ /* @__PURE__ */ jsx(Button, { size: "xsmall", onClick: () => playAllResponses(), variant: "primary", appearance: "outline", children: "RES Resolve" })
1760
+ ] }),
1761
+ /* @__PURE__ */ jsx("div", { className: styles$4["log-list"], children: filteredLogs.length === 0 ? /* @__PURE__ */ jsx("p", { children: "\uD45C\uC2DC\uD560 \uB85C\uADF8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) : /* @__PURE__ */ jsx(Accordion.Root, { children: filteredLogs.map((log, index) => /* @__PURE__ */ jsxs(Accordion.Item, { children: [
1762
+ /* @__PURE__ */ jsx(Accordion.HeaderButton, { children: /* @__PURE__ */ jsx("p", { className: styles$4["log-summary"], children: renderLogSummary(log) }) }),
1763
+ /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx("div", { className: styles$4["log-content"], children: renderLogContent(log) }) })
1764
+ ] }, index)) }) })
1875
1765
  ] })
1876
1766
  ] })
1877
1767
  ] });
1878
1768
  };
1879
1769
 
1880
- const JOB_SEARCH_TABS = [
1881
- { value: "jobName", label: "\uC9C1\uC885\uBA85 \uAC80\uC0C9" },
1882
- { value: "jobCode", label: "\uBD84\uB958\uB85C \uAC80\uC0C9" }
1883
- ];
1884
-
1885
- const cx$5 = classNames.bind(styles$6);
1886
- function JobSearchCategory({ filteredJobs, onJobSelect, searchTerm }) {
1887
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$5("category-section"), children: [
1888
- /* @__PURE__ */ jsxs("p", { className: cx$5("result-title"), children: [
1889
- "\uCD1D ",
1890
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: filteredJobs.length }),
1891
- "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
1892
- ] }),
1893
- /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$5("job-radio-root"), onToggle: () => {
1894
- }, children: filteredJobs.map((job, index) => /* @__PURE__ */ jsxs(
1895
- Accordion.Item,
1896
- {
1897
- id: `item-${job.occupationIndustryCode}-${index}-accordion`,
1898
- children: [
1899
- /* @__PURE__ */ jsx(Accordion.HeaderDiv, { children: /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsxs(Radio.Item, { size: "small", value: job.occupationIndustryCode, onChange: () => onJobSelect(job), children: [
1900
- highlightOnSearchKeyword(job.occupationIndustryName, searchTerm),
1901
- "(",
1902
- job.occupationIndustryCode,
1903
- ")"
1904
- ] }) }) }),
1905
- /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx(Table, { variant: "horizontal", children: /* @__PURE__ */ jsxs("tbody", { children: [
1906
- /* @__PURE__ */ jsxs("tr", { children: [
1907
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1" }),
1908
- /* @__PURE__ */ jsx("td", { className: "px-24", children: "1\uD589 1\uBC88\uC9F8" }),
1909
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1-2" }),
1910
- /* @__PURE__ */ jsx("td", { className: "px-24 ", children: "1\uD589 2\uBC88\uC9F8" })
1911
- ] }),
1912
- /* @__PURE__ */ jsxs("tr", { children: [
1913
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 2" }),
1914
- /* @__PURE__ */ jsx("td", { className: "pl-24 pr-16", colSpan: 3, children: /* @__PURE__ */ jsxs("p", { className: "d-flex-center-center", children: [
1915
- "2\uD589 1\uBC88\uC9F8 ",
1916
- /* @__PURE__ */ jsx("span", { className: "flex-1 pipe-left", children: "\uC11C\uBE0C\uD14D\uC2A4\uD2B8" }),
1917
- /* @__PURE__ */ jsx(Button, { variant: "neutral", size: "xsmall", appearance: "outline", children: "\uBC84\uD2BC\uBA85" })
1918
- ] }) })
1919
- ] })
1920
- ] }) }) })
1921
- ]
1922
- },
1923
- `item-${job.occupationIndustryCode}-${index}`
1924
- )) }) }),
1925
- filteredJobs.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1926
- "`",
1927
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchTerm }),
1928
- "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
1929
- ] })
1770
+ const PageNavigationPanel = ({ onClose }) => {
1771
+ const [url, setUrl] = useState("");
1772
+ const handleNavigate = () => {
1773
+ if (url) {
1774
+ self.location.href = url;
1775
+ }
1776
+ };
1777
+ return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1778
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uD398\uC774\uC9C0 \uC774\uB3D9", showCloseButton: true }),
1779
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs("div", { className: styles$3["page-navigation-content"], children: [
1780
+ /* @__PURE__ */ jsx(
1781
+ FormField.TextField,
1782
+ {
1783
+ size: "xsmall",
1784
+ type: "text",
1785
+ value: url,
1786
+ onChange: (e) => setUrl(e.target.value),
1787
+ placeholder: "\uC774\uB3D9\uD560 URL\uC744 \uC785\uB825\uD558\uC138\uC694 (\uC608: /main)",
1788
+ rootProps: { style: { flex: 1 } }
1789
+ }
1790
+ ),
1791
+ /* @__PURE__ */ jsx(Button, { variant: "primary", appearance: "filled", size: "xsmall", onClick: handleNavigate, children: "\uC774\uB3D9" })
1792
+ ] }) })
1930
1793
  ] }) });
1931
- }
1794
+ };
1932
1795
 
1933
- const cx$4 = classNames.bind(styles$6);
1934
- function JobSearchFavorite({ filteredJobs, onJobSelect }) {
1935
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$4("popular-jobs"), children: [
1936
- /* @__PURE__ */ jsx("p", { children: "\uB9CE\uC774 \uCC3E\uB294 \uC9C1\uC885" }),
1937
- /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$4("job-radio-root"), children: filteredJobs.map((job, index) => /* @__PURE__ */ jsxs(
1938
- Accordion.Item,
1796
+ const safeStringify = (obj) => {
1797
+ try {
1798
+ const replacer = (key, value) => typeof value === "bigint" ? value.toString() : value;
1799
+ return JSON.stringify(obj, replacer, 2);
1800
+ } catch (e) {
1801
+ return "[Unserializable Object]";
1802
+ }
1803
+ };
1804
+ const ResultMessage = ({ log }) => {
1805
+ const messageParts = log.message.map((part) => {
1806
+ if (typeof part === "object" && part !== null) {
1807
+ return safeStringify(part);
1808
+ }
1809
+ return String(part);
1810
+ });
1811
+ const prefix = log.type === "return" ? "\u21A9 " : "";
1812
+ return /* @__PURE__ */ jsxs("pre", { className: `${styles$3["log-message"]} ${styles$3[`log-${log.type}`]}`, children: [
1813
+ prefix,
1814
+ messageParts.join(" ")
1815
+ ] });
1816
+ };
1817
+ const ScriptExecutorPanel = ({ onClose }) => {
1818
+ const [code, setCode] = useState('// \uC5EC\uAE30\uC5D0 \uC2E4\uD589\uD560 \uCF54\uB4DC\uB97C \uC785\uB825\uD558\uC138\uC694\nconsole.log("Hello, World!");');
1819
+ const [results, setResults] = useState([]);
1820
+ const addResult = (type, ...args) => {
1821
+ setResults((prevResults) => [
1822
+ ...prevResults,
1939
1823
  {
1940
- id: `item-${job.occupationIndustryCode}-${index}`,
1941
- className: cx$4("accordion-item"),
1942
- children: [
1943
- /* @__PURE__ */ jsx(Accordion.HeaderDiv, { className: cx$4("accordion-header-item"), children: /* @__PURE__ */ jsxs(
1944
- Radio.Item,
1945
- {
1946
- size: "small",
1947
- value: job.occupationIndustryCode,
1948
- onChange: () => onJobSelect(job),
1949
- className: cx$4("radio-item"),
1950
- children: [
1951
- job.occupationIndustryName,
1952
- "(",
1953
- job.occupationIndustryCode,
1954
- ")"
1955
- ]
1956
- }
1957
- ) }),
1958
- /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: "\uD56D\uBAA9 1 \uB0B4\uC6A9" })
1959
- ]
1824
+ id: Date.now() + Math.random(),
1825
+ type,
1826
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
1827
+ message: args
1828
+ }
1829
+ ]);
1830
+ };
1831
+ const handleExecute = () => {
1832
+ const originalConsole = { ...console };
1833
+ const newConsole = {
1834
+ log: (...args) => {
1835
+ originalConsole.log(...args);
1836
+ addResult("log", ...args);
1960
1837
  },
1961
- `item-${job.occupationIndustryCode}-${index}`
1962
- )) }) })
1838
+ warn: (...args) => {
1839
+ originalConsole.warn(...args);
1840
+ addResult("warn", ...args);
1841
+ },
1842
+ error: (...args) => {
1843
+ originalConsole.error(...args);
1844
+ addResult("error", ...args);
1845
+ }
1846
+ };
1847
+ try {
1848
+ Object.assign(console, newConsole);
1849
+ const result = new Function(code)();
1850
+ if (result !== void 0) {
1851
+ addResult("return", result);
1852
+ }
1853
+ } catch (e) {
1854
+ addResult("error", e.name, e.message);
1855
+ } finally {
1856
+ Object.assign(console, originalConsole);
1857
+ }
1858
+ };
1859
+ const handleClear = () => {
1860
+ setResults([]);
1861
+ };
1862
+ return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1863
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC2A4\uD06C\uB9BD\uD2B8 \uC2E4\uD589", showCloseButton: true }),
1864
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsx("div", { className: `${styles$3["debug-feature-panel"]} ${styles$3["script-executor-panel"]}`, children: /* @__PURE__ */ jsxs("div", { className: styles$3["script-executor-content"], children: [
1865
+ /* @__PURE__ */ jsxs("div", { className: styles$3["script-input-section"], children: [
1866
+ /* @__PURE__ */ jsx(
1867
+ "textarea",
1868
+ {
1869
+ className: styles$3["script-textarea"],
1870
+ value: code,
1871
+ onChange: (e) => setCode(e.target.value),
1872
+ spellCheck: "false"
1873
+ }
1874
+ ),
1875
+ /* @__PURE__ */ jsxs("div", { className: styles$3["script-actions"], children: [
1876
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleExecute, children: "\uC2E4\uD589 (\u25B6)" }),
1877
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleClear, children: "\uACB0\uACFC \uC9C0\uC6B0\uAE30" })
1878
+ ] })
1879
+ ] }),
1880
+ /* @__PURE__ */ jsxs("div", { className: styles$3["script-output-section"], children: [
1881
+ /* @__PURE__ */ jsx("div", { className: styles$3["panel-header"], children: /* @__PURE__ */ jsx("h3", { children: "\uACB0\uACFC" }) }),
1882
+ /* @__PURE__ */ jsx("div", { className: styles$3["log-list-container"], children: results.map((log) => /* @__PURE__ */ jsxs("div", { className: styles$3["log-item"], children: [
1883
+ /* @__PURE__ */ jsx("span", { className: styles$3["log-timestamp"], children: log.timestamp }),
1884
+ /* @__PURE__ */ jsx(ResultMessage, { log })
1885
+ ] }, log.id)) })
1886
+ ] })
1887
+ ] }) }) })
1963
1888
  ] }) });
1964
- }
1889
+ };
1890
+
1891
+ const setCookie = (name, value) => {
1892
+ document.cookie = `${name}=${encodeURIComponent(value)};path=/`;
1893
+ };
1894
+ const removeCookie = (name) => {
1895
+ document.cookie = `${name}=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
1896
+ };
1897
+ const useStorage = (storageType) => {
1898
+ const [items, setItems] = useState([]);
1899
+ const loadItems = useCallback(() => {
1900
+ const newItems = [];
1901
+ if (storageType === "localStorage") {
1902
+ for (let i = 0; i < localStorage.length; i++) {
1903
+ const key = localStorage.key(i);
1904
+ if (key) {
1905
+ newItems.push({ key, value: localStorage.getItem(key) || "" });
1906
+ }
1907
+ }
1908
+ } else {
1909
+ const cookies = document.cookie.split(";");
1910
+ cookies.forEach((cookie) => {
1911
+ const parts = cookie.split("=");
1912
+ const key = parts.shift()?.trim();
1913
+ if (key) {
1914
+ newItems.push({ key, value: decodeURIComponent(parts.join("=")) });
1915
+ }
1916
+ });
1917
+ }
1918
+ setItems(newItems);
1919
+ }, [storageType]);
1920
+ useEffect(() => {
1921
+ loadItems();
1922
+ }, [loadItems]);
1923
+ const setItem = useCallback(
1924
+ (key, value) => {
1925
+ if (storageType === "localStorage") {
1926
+ localStorage.setItem(key, value);
1927
+ } else {
1928
+ setCookie(key, value);
1929
+ }
1930
+ loadItems();
1931
+ },
1932
+ [storageType, loadItems]
1933
+ );
1934
+ const removeItem = useCallback(
1935
+ (key) => {
1936
+ if (storageType === "localStorage") {
1937
+ localStorage.removeItem(key);
1938
+ } else {
1939
+ removeCookie(key);
1940
+ }
1941
+ loadItems();
1942
+ },
1943
+ [storageType, loadItems]
1944
+ );
1945
+ return { items, setItem, removeItem, loadItems };
1946
+ };
1965
1947
 
1966
- const cx$3 = classNames.bind(styles$6);
1967
- function JobSearchResult({ filteredJobs, onJobSelect, searchTerm }) {
1968
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: cx$3("popular-jobs"), children: [
1969
- /* @__PURE__ */ jsxs("p", { className: cx$3("result-title"), children: [
1970
- "\uCD1D ",
1971
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: filteredJobs.length }),
1972
- "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
1948
+ const ValueDisplay = ({ value }) => {
1949
+ try {
1950
+ const parsed = JSON.parse(value);
1951
+ if (typeof parsed === "object" && parsed !== null) {
1952
+ return /* @__PURE__ */ jsx("pre", { className: styles$3["log-content"], children: JSON.stringify(parsed, null, 2) });
1953
+ }
1954
+ } catch (e) {
1955
+ }
1956
+ return /* @__PURE__ */ jsx("div", { className: styles$3["log-content"], children: value });
1957
+ };
1958
+ const EditableRow = ({ item, onSave, onRemove }) => {
1959
+ const [isEditing, setIsEditing] = useState(false);
1960
+ const [value, setValue] = useState(item.value);
1961
+ const handleSave = () => {
1962
+ onSave(item.key, value);
1963
+ setIsEditing(false);
1964
+ };
1965
+ const handleEdit = () => {
1966
+ setValue(item.value);
1967
+ setIsEditing(true);
1968
+ };
1969
+ return /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsxs(Accordion.Item, { children: [
1970
+ /* @__PURE__ */ jsxs(Accordion.HeaderButton, { children: [
1971
+ " ",
1972
+ item.key
1973
1973
  ] }),
1974
- /* @__PURE__ */ jsx(Accordion.Root, { children: /* @__PURE__ */ jsx(Radio.Root, { name: "job-selection", size: "small", className: cx$3("job-radio-root"), children: filteredJobs.map((job) => /* @__PURE__ */ jsxs(
1975
- Accordion.Item,
1976
- {
1977
- id: `item-${job.occupationIndustryCode}`,
1978
- children: [
1979
- /* @__PURE__ */ jsx(Accordion.HeaderDiv, { children: /* @__PURE__ */ jsx("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
1980
- Radio.Item,
1981
- {
1982
- id: `item-${job.occupationIndustryCode}`,
1983
- size: "small",
1984
- value: job.occupationIndustryCode,
1985
- onChange: () => {
1986
- onJobSelect(job);
1987
- },
1988
- children: highlightOnSearchKeyword(job.occupationIndustryName, searchTerm)
1989
- }
1990
- ) }) }),
1991
- /* @__PURE__ */ jsx(Accordion.Content, { variant: "text", children: /* @__PURE__ */ jsx(Table, { variant: "horizontal", children: /* @__PURE__ */ jsxs("tbody", { children: [
1992
- /* @__PURE__ */ jsxs("tr", { children: [
1993
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1" }),
1994
- /* @__PURE__ */ jsx("td", { className: "px-24", children: "1\uD589 1\uBC88\uC9F8" }),
1995
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 1-2" }),
1996
- /* @__PURE__ */ jsx("td", { className: "px-24 ", children: "1\uD589 2\uBC88\uC9F8" })
1997
- ] }),
1998
- /* @__PURE__ */ jsxs("tr", { children: [
1999
- /* @__PURE__ */ jsx("th", { children: "\uD5E4\uB354 2" }),
2000
- /* @__PURE__ */ jsx("td", { className: "pl-24 pr-16", colSpan: 3, children: /* @__PURE__ */ jsxs("p", { className: "d-flex-center-center", children: [
2001
- "2\uD589 1\uBC88\uC9F8 ",
2002
- /* @__PURE__ */ jsx("span", { className: "flex-1 pipe-left", children: "\uC11C\uBE0C\uD14D\uC2A4\uD2B8" }),
2003
- /* @__PURE__ */ jsx(Button, { variant: "neutral", size: "xsmall", appearance: "outline", children: "\uBC84\uD2BC\uBA85" })
2004
- ] }) })
2005
- ] })
2006
- ] }) }) })
2007
- ]
2008
- },
2009
- job.occupationIndustryCode
2010
- )) }) }),
2011
- filteredJobs.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2012
- "`",
2013
- /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchTerm }),
2014
- "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
1974
+ /* @__PURE__ */ jsxs(Accordion.Content, { variant: "text", style: { flex: 1, display: "flex", flexDirection: "column" }, children: [
1975
+ isEditing ? /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleSave, children: "Save" }) : /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: handleEdit, children: "Edit" }),
1976
+ /* @__PURE__ */ jsx(Button, { variant: "neutral", appearance: "outline", size: "xsmall", onClick: () => onRemove(item.key), children: "Remove" }),
1977
+ isEditing ? /* @__PURE__ */ jsx("textarea", { value, onChange: (e) => setValue(e.target.value) }) : /* @__PURE__ */ jsx(ValueDisplay, { value: item.value })
2015
1978
  ] })
2016
1979
  ] }) });
2017
- }
1980
+ };
1981
+ const StoragePanel = ({ onClose, storageType }) => {
1982
+ const { items, setItem, removeItem } = useStorage(storageType);
1983
+ const [filter, setFilter] = useState("");
1984
+ const filteredItems = useMemo(() => {
1985
+ if (!filter) {
1986
+ return items;
1987
+ }
1988
+ return items.filter(
1989
+ (item) => item.key.toLowerCase().includes(filter.toLowerCase()) || item.value.toLowerCase().includes(filter.toLowerCase())
1990
+ );
1991
+ }, [items, filter]);
1992
+ return /* @__PURE__ */ jsx(Modal.Root, { isOpen: true, onClose, modalSize: "full-screen", children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1993
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: storageType === "localStorage" ? "Local Storage" : "Cookies", showCloseButton: true }),
1994
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
1995
+ /* @__PURE__ */ jsx("div", { className: styles$3["panel-toolbar"], children: /* @__PURE__ */ jsx(
1996
+ FormField.TextField,
1997
+ {
1998
+ placeholder: "Search key or value...",
1999
+ size: "xsmall",
2000
+ value: filter,
2001
+ onChange: (e) => setFilter(e.target.value),
2002
+ rootProps: { style: { width: "100%" } }
2003
+ }
2004
+ ) }),
2005
+ /* @__PURE__ */ jsx("ul", { children: filteredItems.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(EditableRow, { item, onSave: setItem, onRemove: removeItem }) }, item.key)) })
2006
+ ] })
2007
+ ] }) });
2008
+ };
2018
2009
 
2019
- const { TextField } = FormField;
2020
- const cx$2 = classNames.bind(styles$6);
2021
- const { Option } = Select;
2022
- function JobSearch({
2023
- activeTab,
2024
- onTabChange,
2025
- searchTerm,
2026
- setSearchInput,
2027
- filteredJobs,
2028
- onJobSelect,
2029
- setSearchTerm,
2030
- searchInput,
2031
- firstCategory,
2032
- setFirstCategory,
2033
- secondCategory,
2034
- setSecondCategory,
2035
- firstCategoryList,
2036
- secondCategoryList
2037
- }) {
2038
- const onKeyUp = (e) => {
2039
- if (e.key === "Enter") {
2040
- setSearchTerm(searchInput);
2010
+ const loginTypes = [
2011
+ {
2012
+ id: "fp",
2013
+ label: "FP \uB85C\uADF8\uC778",
2014
+ fields: [{ name: "employeeId", label: "\uC0AC\uBC88", type: "text", placeholder: "\uC0AC\uBC88\uC744 \uC785\uB825\uD558\uC138\uC694" }]
2015
+ },
2016
+ {
2017
+ id: "customer",
2018
+ label: "\uACE0\uAC1D \uB85C\uADF8\uC778",
2019
+ fields: [
2020
+ { name: "name", label: "\uC774\uB984", type: "text", placeholder: "\uC774\uB984" },
2021
+ { name: "phone", label: "\uC804\uD654\uBC88\uD638", type: "tel", placeholder: "\uC804\uD654\uBC88\uD638" },
2022
+ { name: "residentNumber", label: "\uC8FC\uBBFC\uBC88\uD638", type: "text", placeholder: "\uC8FC\uBBFC\uBC88\uD638 \uC55E 7\uC790\uB9AC" },
2023
+ { name: "userId", label: "\uC544\uC774\uB514", type: "text", placeholder: "\uC544\uC774\uB514" },
2024
+ { name: "password", label: "\uBE44\uBC00\uBC88\uD638", type: "password", placeholder: "\uBE44\uBC00\uBC88\uD638" }
2025
+ ]
2026
+ }
2027
+ ];
2028
+ const menuItems = [
2029
+ {
2030
+ id: "network-log",
2031
+ label: "\uB124\uD2B8\uC6CC\uD06C \uB85C\uADF8",
2032
+ component: NetworkLog,
2033
+ display: true
2034
+ },
2035
+ {
2036
+ id: "console-log",
2037
+ label: "\uCF58\uC194 \uB85C\uADF8 \uD655\uC778",
2038
+ component: ConsoleLogPanel,
2039
+ display: true
2040
+ },
2041
+ {
2042
+ id: "local-storage",
2043
+ label: "\uB85C\uCEEC \uC2A4\uD1A0\uB9AC\uC9C0 \uAD00\uB9AC",
2044
+ // StoragePanel은 재사용 가능한 컴포넌트이므로, props를 통해 어떤 스토리지를 다룰지 지정합니다.
2045
+ component: (props) => /* @__PURE__ */ jsx(StoragePanel, { ...props, storageType: "localStorage" }),
2046
+ display: true
2047
+ },
2048
+ {
2049
+ id: "cookie-management",
2050
+ label: "\uCFE0\uD0A4 \uAD00\uB9AC",
2051
+ component: (props) => /* @__PURE__ */ jsx(StoragePanel, { ...props, storageType: "cookie" }),
2052
+ display: true
2053
+ },
2054
+ {
2055
+ id: "quick-login",
2056
+ label: "\uAC04\uD3B8 \uB85C\uADF8\uC778",
2057
+ component: LoginPanel,
2058
+ display: true
2059
+ // 실제 표시는 DebugTool.tsx에서 onLogin prop 존재 여부에 따라 결정됩니다.
2060
+ },
2061
+ {
2062
+ id: "script-executor",
2063
+ label: "\uC2A4\uD06C\uB9BD\uD2B8 \uC2E4\uD589",
2064
+ component: ScriptExecutorPanel,
2065
+ display: true
2066
+ },
2067
+ {
2068
+ id: "page-navigation",
2069
+ label: "\uD398\uC774\uC9C0 \uC774\uB3D9",
2070
+ component: PageNavigationPanel,
2071
+ display: true
2072
+ }
2073
+ ];
2074
+
2075
+ const useEnvironment = () => {
2076
+ const [envInfo, setEnvInfo] = useState({
2077
+ env: "prd"
2078
+ });
2079
+ useEffect(() => {
2080
+ const { hostname } = window.location;
2081
+ setEnvInfo({ env: getEnvironmentFromHostname(hostname) });
2082
+ }, []);
2083
+ return envInfo;
2084
+ };
2085
+
2086
+ const DebugTool = ({ onLogin, envOverride, menuItemsOverride }) => {
2087
+ useEffect(() => {
2088
+ initializeConsoleLogOverride();
2089
+ return () => {
2090
+ restoreConsoleLog();
2091
+ };
2092
+ }, []);
2093
+ const environment = useEnvironment();
2094
+ const env = envOverride || environment.env;
2095
+ const menuItems$1 = menuItemsOverride || menuItems;
2096
+ const [isMenuOpen, setMenuOpen] = useState(false);
2097
+ const [activeFeature, setActiveFeature] = useState(null);
2098
+ const isVisible = ["local", "dev", "stg"].includes(env);
2099
+ const handleMenuClick = (itemComponent) => {
2100
+ setActiveFeature(() => itemComponent);
2101
+ setMenuOpen(false);
2102
+ };
2103
+ const handleCloseFeature = () => {
2104
+ setActiveFeature(null);
2105
+ };
2106
+ if (!isVisible) {
2107
+ return null;
2108
+ }
2109
+ const toggleMenu = () => {
2110
+ setMenuOpen((prev) => !prev);
2111
+ if (!isMenuOpen) {
2112
+ setActiveFeature(null);
2041
2113
  }
2042
2114
  };
2043
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2044
- /* @__PURE__ */ jsx(
2045
- Tab.Root,
2115
+ const availableMenuItems = menuItems$1.filter(
2116
+ (item) => item.display && // config에서 display가 true인 항목만 필터링합니다.
2117
+ // 'quick-login' 기능은 onLogin prop이 제공된 경우에만 활성화합니다.
2118
+ (item.id !== "quick-login" || item.id === "quick-login" && onLogin)
2119
+ );
2120
+ if (activeFeature) {
2121
+ const FeatureComponent = activeFeature;
2122
+ return /* @__PURE__ */ jsx(FeatureComponent, { onClose: handleCloseFeature, onLogin });
2123
+ }
2124
+ return /* @__PURE__ */ jsxs("div", { className: "debug-tool-container", children: [
2125
+ /* @__PURE__ */ jsx(FloatingButton, { onClick: toggleMenu }),
2126
+ isMenuOpen && /* @__PURE__ */ jsx(
2127
+ MenuPanel,
2128
+ {
2129
+ menuItems: availableMenuItems,
2130
+ onMenuItemClick: handleMenuClick,
2131
+ onClose: () => setMenuOpen(false)
2132
+ }
2133
+ )
2134
+ ] });
2135
+ };
2136
+
2137
+ const cx$3 = classNames.bind(styles$5);
2138
+ const { InputBox, Input } = FormCore;
2139
+ const AddressSearchInitialText = () => {
2140
+ return /* @__PURE__ */ jsxs("div", { children: [
2141
+ /* @__PURE__ */ jsx("p", { className: cx$3("guide-title"), children: "\uC774\uB807\uAC8C \uAC80\uC0C9\uD574 \uBCF4\uC138\uC694." }),
2142
+ /* @__PURE__ */ jsxs("ul", { className: cx$3("guide"), children: [
2143
+ /* @__PURE__ */ jsx("li", { children: "\uB3C4\uB85C\uBA85/\uC9C0\uBA85\uACFC \uAC74\uBB3C\uBC88\uD638\uB97C \uD568\uAED8 \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
2144
+ /* @__PURE__ */ jsx("li", { children: "\uC608) 63\uB85C 50, \uC5EC\uC758\uB3C4\uB3D9 60" }),
2145
+ /* @__PURE__ */ jsx("li", { children: "\uC9C0\uBA85\uC740 \uB3D9/\uC74D/\uBA74/\uB9AC\uB85C \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
2146
+ /* @__PURE__ */ jsx("li", { children: "\uC608) \uC5EC\uC758\uB3C4\uB3D9, \uC5ED\uC0BC\uB3D9" }),
2147
+ /* @__PURE__ */ jsx("li", { children: "\uC6B0\uD3B8\uBC88\uD638 \uB2E4\uC12F\uC790\uB9AC\uB97C \uBAA8\uB450 \uC785\uB825\uD574\uC8FC\uC138\uC694" }),
2148
+ /* @__PURE__ */ jsx("li", { children: "\uC608) 07345, 06232" })
2149
+ ] })
2150
+ ] });
2151
+ };
2152
+ const AddressSearchResult = ({
2153
+ addressSearchList,
2154
+ onChange,
2155
+ searchKeyword,
2156
+ selectedAddress
2157
+ }) => {
2158
+ const [filterList, setFilterList] = useState([]);
2159
+ useEffect(() => {
2160
+ const filterList2 = addressSearchList.filter(
2161
+ (item) => item.address.includes(searchKeyword) || item.oldAddress.includes(searchKeyword)
2162
+ ) || [];
2163
+ setFilterList(filterList2);
2164
+ }, [addressSearchList, searchKeyword]);
2165
+ return /* @__PURE__ */ jsxs("div", { children: [
2166
+ /* @__PURE__ */ jsxs("p", { className: cx$3("guide-title"), children: [
2167
+ "\uCD1D ",
2168
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: filterList.length }),
2169
+ "\uAC74\uC758 \uAC80\uC0C9\uACB0\uACFC"
2170
+ ] }),
2171
+ filterList.length > 0 && /* @__PURE__ */ jsx(
2172
+ RadioGroup,
2046
2173
  {
2047
- defaultValue: activeTab,
2048
- onValueChange: onTabChange,
2049
- scroll: "fixed",
2050
- size: "small",
2051
- variant: "sub",
2052
- style: { gap: 0, overflow: "visible" },
2053
- children: JOB_SEARCH_TABS.map((tab) => /* @__PURE__ */ jsx(Tab.Item, { value: tab.value, children: tab.label }, tab.value))
2174
+ items: filterList.map((item) => ({
2175
+ value: item.address,
2176
+ select: item.address === selectedAddress?.address && item.zipCode === selectedAddress?.zipCode,
2177
+ label: /* @__PURE__ */ jsxs("div", { className: cx$3("search-result"), children: [
2178
+ /* @__PURE__ */ jsxs("div", { className: cx$3("zipcode"), children: [
2179
+ " ",
2180
+ highlightOnSearchKeyword(item.zipCode, searchKeyword)
2181
+ ] }),
2182
+ /* @__PURE__ */ jsx("div", { className: cx$3("divider") }),
2183
+ /* @__PURE__ */ jsxs("div", { className: cx$3("address-info"), children: [
2184
+ /* @__PURE__ */ jsx("span", { className: cx$3("address"), children: highlightOnSearchKeyword(item.address, searchKeyword) }),
2185
+ /* @__PURE__ */ jsx("span", { className: cx$3("old-address"), children: highlightOnSearchKeyword(item.oldAddress, searchKeyword) })
2186
+ ] })
2187
+ ] }),
2188
+ id: item.address
2189
+ })),
2190
+ className: cx$3("radio-group"),
2191
+ name: "address-search",
2192
+ size: "medium",
2193
+ defaultValue: "",
2194
+ onChange
2054
2195
  }
2055
2196
  ),
2197
+ filterList.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2198
+ "`",
2199
+ /* @__PURE__ */ jsx("span", { className: "text-primary", children: searchKeyword }),
2200
+ "`\uC5D0 \uB300\uD55C \uAC80\uC0C9\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
2201
+ ] })
2202
+ ] });
2203
+ };
2204
+ const AddressSearchDetailInput = ({
2205
+ selectedAddress,
2206
+ onDetailChange,
2207
+ step,
2208
+ detailAddressInput
2209
+ }) => {
2210
+ return /* @__PURE__ */ jsxs("div", { children: [
2211
+ /* @__PURE__ */ jsxs("div", { children: [
2212
+ /* @__PURE__ */ jsxs("div", { children: [
2213
+ " ",
2214
+ selectedAddress.zipCode
2215
+ ] }),
2216
+ /* @__PURE__ */ jsxs("div", { children: [
2217
+ "|",
2218
+ /* @__PURE__ */ jsx("span", { children: `${selectedAddress.address}` })
2219
+ ] })
2220
+ ] }),
2056
2221
  /* @__PURE__ */ jsxs("div", { children: [
2057
- activeTab === "jobName" && /* @__PURE__ */ jsxs("div", { className: cx$2("favorite-jobs-section"), children: [
2222
+ /* @__PURE__ */ jsx(FormField.Label, { id: "detail", style: { width: "90px" }, children: "\uC0C1\uC138\uC8FC\uC18C" }),
2223
+ /* @__PURE__ */ jsx(
2224
+ Input,
2225
+ {
2226
+ placeholder: "\uC0C1\uC138\uC8FC\uC18C \uC785\uB825",
2227
+ onChange: onDetailChange,
2228
+ size: "large",
2229
+ value: detailAddressInput,
2230
+ ...step === "detail-input" && { autoFocus: true }
2231
+ }
2232
+ )
2233
+ ] })
2234
+ ] });
2235
+ };
2236
+ function AddressComponent({ isOpen, onClose, setValue }) {
2237
+ const {
2238
+ onAddressSearchClear,
2239
+ addressSearchKeyword,
2240
+ addressSearchStep,
2241
+ onAddressSearchNext,
2242
+ nextButtonDisabled,
2243
+ detailAddressInput,
2244
+ addressSearchList,
2245
+ onSearch,
2246
+ onKeyUp,
2247
+ onSelectChange,
2248
+ setDetail,
2249
+ search,
2250
+ searchInput,
2251
+ selectedAddress
2252
+ } = useSearchAddress({
2253
+ setValue,
2254
+ onClose,
2255
+ isOpen
2256
+ });
2257
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Modal.Root, { isOpen, onClose, modalSize: "full-screen", children: [
2258
+ /* @__PURE__ */ jsx(Modal.Overlay, {}),
2259
+ /* @__PURE__ */ jsxs(Modal.Content, { children: [
2260
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC8FC\uC18C \uAC80\uC0C9", showCloseButton: true }),
2261
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
2058
2262
  /* @__PURE__ */ jsx(
2059
- TextField,
2263
+ InputBox,
2060
2264
  {
2061
- placeholder: "\uC9C1\uC885\uBA85 \uAC80\uC0C9",
2062
- value: searchInput,
2063
- onKeyUp,
2064
- onChange: (e) => setSearchInput(e.target.value),
2065
- className: styles$6.searchInput,
2066
- size: "medium",
2067
- rootProps: {
2068
- endElement: /* @__PURE__ */ jsx(Icon, { name: "sub-ui/search", onClick: () => setSearchTerm(searchInput) }),
2069
- onClear: () => {
2070
- setSearchTerm("");
2071
- setSearchInput("");
2265
+ clearable: true,
2266
+ endElement: /* @__PURE__ */ jsx(Icon, { name: "sub-ui/search", onClick: search }),
2267
+ onClear: onAddressSearchClear,
2268
+ children: /* @__PURE__ */ jsx(
2269
+ Input,
2270
+ {
2271
+ ...addressSearchStep !== "detail-input" && { autoFocus: true },
2272
+ onChange: onSearch,
2273
+ onKeyUp,
2274
+ value: searchInput,
2275
+ placeholder: "\uC9C0\uBC88, \uB3C4\uB85C\uBA85, \uAC74\uBB3C\uBA85, \uC6B0\uD3B8\uBC88\uD638 \uC785\uB825",
2276
+ size: "large"
2072
2277
  }
2073
- }
2278
+ )
2074
2279
  }
2075
2280
  ),
2076
- !searchTerm && /* @__PURE__ */ jsx(JobSearchFavorite, { filteredJobs, onJobSelect }),
2077
- searchTerm && /* @__PURE__ */ jsx(JobSearchResult, { filteredJobs, onJobSelect, searchTerm })
2281
+ addressSearchStep === "initial" && /* @__PURE__ */ jsx(AddressSearchInitialText, {}),
2282
+ addressSearchStep === "search-result" && /* @__PURE__ */ jsx(
2283
+ AddressSearchResult,
2284
+ {
2285
+ onChange: onSelectChange,
2286
+ addressSearchList: addressSearchList || [],
2287
+ searchKeyword: addressSearchKeyword,
2288
+ selectedAddress
2289
+ }
2290
+ ),
2291
+ addressSearchStep === "detail-input" && selectedAddress && /* @__PURE__ */ jsx(
2292
+ AddressSearchDetailInput,
2293
+ {
2294
+ selectedAddress,
2295
+ onDetailChange: setDetail,
2296
+ step: addressSearchStep,
2297
+ detailAddressInput
2298
+ }
2299
+ )
2078
2300
  ] }),
2079
- activeTab === "jobCode" && /* @__PURE__ */ jsxs("div", { className: cx$2("select-jobs-section"), children: [
2080
- /* @__PURE__ */ jsxs("div", { className: cx$2("category-section"), children: [
2081
- /* @__PURE__ */ jsx(
2082
- Select,
2083
- {
2084
- name: "first_category",
2085
- onChange: (value) => {
2086
- setFirstCategory(value);
2087
- setSecondCategory("");
2088
- },
2089
- placeholder: "\uB300\uBD84\uB958 \uC120\uD0DD",
2090
- rootProps: {
2091
- style: {
2092
- // width: '300px'
2093
- }
2094
- },
2095
- size: "large",
2096
- value: firstCategory,
2097
- children: firstCategoryList.map((option, index) => /* @__PURE__ */ jsx(Option, { value: option.occupationIndustryCode, children: option.occupationIndustryName }, `${index}-${option.occupationIndustryCode}`))
2098
- }
2099
- ),
2100
- /* @__PURE__ */ jsx(
2101
- Select,
2102
- {
2103
- name: "second_category",
2104
- onChange: setSecondCategory,
2105
- placeholder: "\uC911\uBD84\uB958 \uC120\uD0DD",
2106
- rootProps: {
2107
- style: {
2108
- // width: '300px'
2109
- }
2110
- },
2111
- size: "large",
2112
- value: secondCategory,
2113
- disabled: !firstCategory,
2114
- children: secondCategoryList.map((option, index) => /* @__PURE__ */ jsx(Option, { value: option.occupationIndustryCode, children: option.occupationIndustryName }, `${index}-${option.occupationIndustryCode}`))
2115
- }
2116
- )
2117
- ] }),
2118
- firstCategory && secondCategory && /* @__PURE__ */ jsx(JobSearchCategory, { filteredJobs, onJobSelect, searchTerm })
2119
- ] })
2301
+ /* @__PURE__ */ jsx(Modal.Footer, { children: addressSearchStep !== "initial" && /* @__PURE__ */ jsxs(
2302
+ Button,
2303
+ {
2304
+ onClick: onAddressSearchNext,
2305
+ variant: "primary",
2306
+ size: "medium",
2307
+ appearance: "filled",
2308
+ width: "full",
2309
+ disabled: nextButtonDisabled,
2310
+ children: [
2311
+ addressSearchStep === "search-result" && "\uB2E4\uC74C(1/2)",
2312
+ addressSearchStep === "detail-input" && "\uD655\uC778(2/2)"
2313
+ ]
2314
+ }
2315
+ ) })
2120
2316
  ] })
2121
- ] });
2122
- }
2123
-
2124
- const initData = [
2125
- {
2126
- occupationIndustryCode: "430101",
2127
- occupationIndustryName: "\uD68C\uC0AC \uC0AC\uBB34\uC9C1 \uC885\uC0AC\uC790",
2128
- occupationTypeCode: null,
2129
- historySequence: 0
2130
- },
2131
- {
2132
- occupationIndustryCode: "400301",
2133
- occupationIndustryName: "\uACBD\uC601\uC9C0\uC6D0 \uC0AC\uBB34\uC9C1 \uAD00\uB9AC\uC790",
2134
- occupationTypeCode: null,
2135
- historySequence: 0
2136
- },
2137
- {
2138
- occupationIndustryCode: "510201",
2139
- occupationIndustryName: "\uC804\uC5C5\uC8FC\uBD80",
2140
- occupationTypeCode: null,
2141
- historySequence: 0
2142
- },
2143
- {
2144
- occupationIndustryCode: "442501",
2145
- occupationIndustryName: "\uC8FC\uBC29\uC7A5 \uBC0F \uC870\uB9AC\uC0AC(\uC120\uBC15 \uC870\uB9AC\uC0AC \uC81C\uC678)",
2146
- occupationTypeCode: null,
2147
- historySequence: 0
2148
- },
2149
- {
2150
- occupationIndustryCode: "450303",
2151
- occupationIndustryName: "\uBCF4\uD5D8\uC124\uACC4\uC0AC(\uB2F9\uC0AC)",
2152
- occupationTypeCode: null,
2153
- historySequence: 0
2154
- }
2155
- ];
2156
- const useJobSearch = () => {
2157
- const [activeTab, setActiveTab] = useState(JOB_SEARCH_TABS[0]?.value ?? "");
2158
- const [selectedJob, setSelectedJob] = useState(null);
2159
- const [searchTerm, setSearchTerm] = useState("");
2317
+ ] }) });
2318
+ }
2319
+
2320
+ function useSearchAddress({ setValue, onClose, isOpen }) {
2321
+ const [searchKeyword, setSearchKeyword] = useState("");
2322
+ const [step, setStep] = useState("initial");
2323
+ const [selectedAddress, setSelectedAddress] = useState(null);
2160
2324
  const [searchInput, setSearchInput] = useState("");
2161
- const handleJobSelect = (job) => {
2162
- setSelectedJob(job);
2325
+ const [detailAddressInput, setDetailAddressInput] = useState("");
2326
+ const { data: addressList } = useSearchModalAddressQuery({ searchKeyword });
2327
+ const [nextButtonDisabled, setNextButtonDisabled] = useState(false);
2328
+ const onNext = () => {
2329
+ if (step === "search-result") {
2330
+ setStep("detail-input");
2331
+ setNextButtonDisabled(true);
2332
+ } else {
2333
+ setValue({
2334
+ address: selectedAddress?.address || "",
2335
+ oldAddress: selectedAddress?.oldAddress || "",
2336
+ zipCode: selectedAddress?.zipCode || "",
2337
+ detail: detailAddressInput || ""
2338
+ });
2339
+ onClose();
2340
+ }
2163
2341
  };
2164
- const [firstCategory, setFirstCategory] = useState("");
2165
- const [secondCategory, setSecondCategory] = useState("");
2166
- const [jobList, setJobList] = useState(initData);
2167
- const [firstCategoryList, setFirstCategoryList] = useState([]);
2168
- const [secondCategoryList, setSecondCategoryList] = useState([]);
2169
- const { data } = useSearchOccupationQuery({
2170
- occupationMajorCategoryCode: firstCategory,
2171
- occupationSearchTypeCode: searchTerm ? "4" : "3",
2172
- occupationSubCategoryCode: secondCategory,
2173
- searchOccupationIndustryName: searchTerm
2174
- });
2175
- const { data: firstCategoryData } = useSearchOccupationQuery({
2176
- occupationMajorCategoryCode: "",
2177
- occupationSearchTypeCode: "1",
2178
- occupationSubCategoryCode: "",
2179
- searchOccupationIndustryName: ""
2180
- });
2181
- const { data: secondCategoryData } = useSearchOccupationQuery({
2182
- occupationMajorCategoryCode: firstCategory,
2183
- occupationSearchTypeCode: "2",
2184
- occupationSubCategoryCode: "",
2185
- searchOccupationIndustryName: ""
2186
- });
2187
- useEffect(() => {
2188
- if (data && searchTerm && activeTab === "jobName") {
2189
- const filteredJobs = data.data.occupationList.filter((job) => job.occupationIndustryName.includes(searchTerm));
2190
- setJobList(filteredJobs);
2191
- } else if (!data && searchTerm && activeTab === "jobName") {
2192
- setJobList([]);
2193
- } else if (!searchTerm && activeTab === "jobName") {
2194
- setJobList(initData);
2195
- } else if (activeTab === "jobCode" && firstCategory && secondCategory) {
2196
- setJobList(data?.data.occupationList || []);
2342
+ const onSearch = (e) => {
2343
+ const typeStr = e.target.value;
2344
+ setSearchInput(typeStr);
2345
+ };
2346
+ const search = () => {
2347
+ if (searchInput === "") {
2348
+ onClear();
2349
+ return;
2197
2350
  }
2198
- }, [searchTerm, data, firstCategory, secondCategory, secondCategoryData, activeTab]);
2199
- useEffect(() => {
2200
- console.log("jobList", jobList);
2201
- }, [jobList]);
2202
- useEffect(() => {
2203
- if (firstCategoryData) {
2204
- setFirstCategoryList(firstCategoryData.data.occupationList);
2351
+ if (searchInput && searchInput.length > 1) {
2352
+ setSearchKeyword(searchInput);
2353
+ setStep("search-result");
2354
+ setSelectedAddress(null);
2355
+ setDetailAddressInput("");
2356
+ setNextButtonDisabled(true);
2205
2357
  }
2206
- }, [firstCategoryData]);
2207
- useEffect(() => {
2208
- if (secondCategoryData) {
2209
- setSecondCategoryList(secondCategoryData.data.occupationList);
2358
+ };
2359
+ const onKeyUp = (e) => {
2360
+ if (e.key === "Enter") {
2361
+ search();
2210
2362
  }
2211
- }, [secondCategoryData]);
2212
- return {
2213
- activeTab,
2214
- setActiveTab,
2215
- selectedJob,
2216
- searchTerm,
2217
- setSearchTerm,
2218
- handleJobSelect,
2219
- filteredJobs: jobList,
2220
- searchInput,
2221
- setSearchInput,
2222
- firstCategory,
2223
- setFirstCategory,
2224
- secondCategory,
2225
- setSecondCategory,
2226
- secondCategoryList,
2227
- firstCategoryList
2228
2363
  };
2229
- };
2230
- function useJobSearchModal() {
2231
- const {
2232
- activeTab,
2233
- setActiveTab,
2234
- searchTerm,
2235
- setSearchTerm,
2236
- filteredJobs,
2237
- handleJobSelect,
2238
- selectedJob,
2239
- searchInput,
2240
- setSearchInput,
2241
- firstCategory,
2242
- setFirstCategory,
2243
- secondCategory,
2244
- setSecondCategory,
2245
- firstCategoryList,
2246
- secondCategoryList
2247
- } = useJobSearch();
2248
- const { isOpen, openModal, closeModal } = useModalState();
2249
- const onTabChange = (value) => {
2250
- setSearchTerm("");
2251
- setFirstCategory("");
2252
- setSecondCategory("");
2253
- setActiveTab(value);
2364
+ const onSelectChange = (e) => {
2365
+ const selectedAddress2 = e.target.value;
2366
+ if (selectedAddress2) {
2367
+ const adr = addressList?.find((addr) => {
2368
+ return addr.address === selectedAddress2;
2369
+ });
2370
+ setSelectedAddress(adr || null);
2371
+ setNextButtonDisabled(false);
2372
+ }
2373
+ };
2374
+ const onClear = useCallback(() => {
2375
+ setSearchKeyword("");
2376
+ setSearchInput("");
2377
+ setSelectedAddress(null);
2378
+ setDetailAddressInput("");
2379
+ setStep("initial");
2380
+ }, []);
2381
+ const setDetail = (e) => {
2382
+ const detail = e.target.value;
2383
+ setDetailAddressInput(detail);
2384
+ if (detail) {
2385
+ setNextButtonDisabled(false);
2386
+ } else {
2387
+ setNextButtonDisabled(true);
2388
+ }
2254
2389
  };
2390
+ useEffect(() => {
2391
+ if (isOpen) {
2392
+ setSelectedAddress(null);
2393
+ setDetailAddressInput("");
2394
+ setStep("initial");
2395
+ setSearchKeyword("");
2396
+ }
2397
+ }, [isOpen]);
2255
2398
  return {
2256
- JobSearchModal: /* @__PURE__ */ jsxs(Modal.Root, { isOpen, onClose: closeModal, modalSize: "xlarge", children: [
2257
- /* @__PURE__ */ jsx(Modal.Overlay, {}),
2258
- /* @__PURE__ */ jsxs(Modal.Content, { style: { height: "697px" }, children: [
2259
- /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC9C1\uC885 \uAC80\uC0C9", showCloseButton: true }),
2260
- /* @__PURE__ */ jsx(Modal.Body, { raw: true, children: /* @__PURE__ */ jsx(
2261
- JobSearch,
2262
- {
2263
- firstCategory,
2264
- firstCategoryList,
2265
- secondCategoryList,
2266
- setFirstCategory,
2267
- secondCategory,
2268
- activeTab,
2269
- onTabChange,
2270
- searchTerm,
2271
- setSearchInput,
2272
- filteredJobs: filteredJobs || [],
2273
- onJobSelect: handleJobSelect,
2274
- searchInput,
2275
- setSearchTerm,
2276
- setSecondCategory
2277
- }
2278
- ) }),
2279
- /* @__PURE__ */ jsx(Modal.Footer, { children: /* @__PURE__ */ jsx(Button, { variant: "primary", size: "medium", appearance: "filled", width: "full", onClick: closeModal, children: "\uD655\uC778" }) })
2280
- ] })
2281
- ] }),
2282
- JobSearchComponent: /* @__PURE__ */ jsx(
2283
- JobSearch,
2284
- {
2285
- firstCategoryList,
2286
- secondCategoryList,
2287
- firstCategory,
2288
- setFirstCategory,
2289
- secondCategory,
2290
- setSecondCategory,
2291
- activeTab,
2292
- onTabChange,
2293
- searchTerm,
2294
- setSearchInput,
2295
- filteredJobs: filteredJobs || [],
2296
- onJobSelect: handleJobSelect,
2297
- searchInput,
2298
- setSearchTerm
2299
- }
2300
- ),
2301
- isJobSearchOpen: isOpen,
2302
- openJobSearchModal: openModal,
2303
- closeJobSearchModal: closeModal,
2304
- selectedJob
2399
+ onAddressSearchClear: onClear,
2400
+ onAddressSearchNext: onNext,
2401
+ addressSearchKeyword: searchKeyword,
2402
+ addressSearchList: addressList,
2403
+ addressSearchStep: step,
2404
+ selectedAddress,
2405
+ addressSearchOnValueChange: onSelectChange,
2406
+ nextButtonDisabled,
2407
+ detailAddressInput,
2408
+ onSearch,
2409
+ onKeyUp,
2410
+ onSelectChange,
2411
+ setDetail,
2412
+ search,
2413
+ searchInput
2305
2414
  };
2306
2415
  }
2416
+ const useAddressComponent = () => {
2417
+ const [fullAddress, setFullAddress] = useState(null);
2418
+ const { isOpen, closeModal, openModal } = useModalState();
2419
+ const AddressSearchComponent = () => /* @__PURE__ */ jsx(AddressComponent, { isOpen, onClose: closeModal, setValue: setFullAddress });
2420
+ return {
2421
+ fullAddress,
2422
+ openModal,
2423
+ AddressSearchComponent
2424
+ };
2425
+ };
2426
+
2427
+ const cx$2 = classNames.bind(styles$6);
2428
+ const JobVehicleSearchGrade = ({ riskGrade, hospitalizationGrade }) => {
2429
+ return /* @__PURE__ */ jsxs("div", { className: cx$2("grade-section"), children: [
2430
+ /* @__PURE__ */ jsxs("div", { className: cx$2("icon-title"), children: [
2431
+ /* @__PURE__ */ jsx(Icon, { name: "illust/grade" }),
2432
+ /* @__PURE__ */ jsx("span", { className: "typo-title5 text-body", children: "\uB4F1\uAE09" })
2433
+ ] }),
2434
+ /* @__PURE__ */ jsx("p", { className: "typo-body2 text-body_3", children: "\uC9C1\uC885, \uC6B4\uC804 \uC5EC\uBD80 \uC120\uD0DD\uC2DC \uC790\uB3D9\uC73C\uB85C \uC0B0\uC815\uB429\uB2C8\uB2E4." }),
2435
+ /* @__PURE__ */ jsxs("div", { className: cx$2("grade-list"), children: [
2436
+ /* @__PURE__ */ jsxs("div", { className: cx$2("grade"), children: [
2437
+ /* @__PURE__ */ jsx("span", { children: "\uC704\uD5D8\uB4F1\uAE09" }),
2438
+ /* @__PURE__ */ jsx("span", { className: "text-primary typo-subtitle3", children: riskGrade || "-" })
2439
+ ] }),
2440
+ /* @__PURE__ */ jsxs("div", { className: cx$2("grade"), children: [
2441
+ /* @__PURE__ */ jsx("span", { children: "\uC785\uC6D0\uB4F1\uAE09" }),
2442
+ /* @__PURE__ */ jsx("span", { className: "text-primary typo-subtitle3", children: hospitalizationGrade || "-" })
2443
+ ] })
2444
+ ] })
2445
+ ] });
2446
+ };
2307
2447
 
2308
2448
  const cx$1 = classNames.bind(styles$7);
2309
2449
  function VehicleSearch({ vehicles, onVehicleSelect }) {
@@ -2371,7 +2511,7 @@ const useJobVehicleSearch = () => {
2371
2511
  };
2372
2512
  };
2373
2513
 
2374
- const cx = classNames.bind(styles$5);
2514
+ const cx = classNames.bind(styles$6);
2375
2515
  function useJobVehicleSearchModal() {
2376
2516
  const {
2377
2517
  selectedVehicle,
@@ -2464,5 +2604,17 @@ function useJobVehicleSearchModal() {
2464
2604
  };
2465
2605
  }
2466
2606
 
2467
- export { Attachment, DebugTool, FormCheckbox, FormCheckboxButton, FormDatePicker, FormDateRangePicker, FormSegmentGroup, FormTextField, StepIndicator, resize, testSignatureBase64Data, useAddressComponent, useCamera, useCanvasPaint, useJobVehicleSearchModal, useSearchAddress };
2607
+ const JobSearchModal = ({ onClose }) => {
2608
+ const { JobSearchComponent } = useJobSearchModal();
2609
+ return /* @__PURE__ */ jsxs(Modal.Root, { isOpen: true, onClose, modalSize: "xlarge", children: [
2610
+ /* @__PURE__ */ jsx(Modal.Overlay, {}),
2611
+ /* @__PURE__ */ jsxs(Modal.Content, { style: { height: "697px" }, children: [
2612
+ /* @__PURE__ */ jsx(Modal.Header, { headerTitle: "\uC9C1\uC885 \uAC80\uC0C9", showCloseButton: true }),
2613
+ /* @__PURE__ */ jsx(Modal.Body, { raw: true, children: JobSearchComponent }),
2614
+ /* @__PURE__ */ jsx(Modal.Footer, { children: /* @__PURE__ */ jsx(Button, { variant: "primary", size: "medium", appearance: "filled", width: "full", onClick: onClose, children: "\uD655\uC778" }) })
2615
+ ] })
2616
+ ] });
2617
+ };
2618
+
2619
+ export { Attachment, DebugTool, FormCheckbox, FormCheckboxButton, FormDatePicker, FormDateRangePicker, FormSearchJobField, FormSegmentGroup, FormSelect, FormTextField, JobSearchModal, StepIndicator, resize, testSignatureBase64Data, useAddressComponent, useCamera, useCanvasPaint, useJobVehicleSearchModal, useSearchAddress };
2468
2620
  //# sourceMappingURL=index.esm.js.map