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