@uniai-fe/uds-templates 0.4.2 → 0.4.3
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/README.md +23 -0
- package/dist/styles.css +32 -0
- package/package.json +1 -1
- package/src/index.scss +1 -0
- package/src/index.tsx +1 -0
- package/src/service-inquiry/components/Form.tsx +157 -0
- package/src/service-inquiry/components/OpenButton.tsx +46 -0
- package/src/service-inquiry/hooks/index.ts +2 -0
- package/src/service-inquiry/hooks/useOpenServiceInquiry.ts +48 -0
- package/src/service-inquiry/hooks/useServiceInquiryUserContext.ts +89 -0
- package/src/service-inquiry/index.scss +1 -0
- package/src/service-inquiry/index.tsx +26 -0
- package/src/service-inquiry/styles/form.scss +15 -0
- package/src/service-inquiry/styles/index.scss +2 -0
- package/src/service-inquiry/styles/open-button.scss +15 -0
- package/src/service-inquiry/types/api.ts +68 -0
- package/src/service-inquiry/types/form-context.ts +48 -0
- package/src/service-inquiry/types/hooks.ts +83 -0
- package/src/service-inquiry/types/index.ts +4 -0
- package/src/service-inquiry/types/props.ts +171 -0
- package/src/service-inquiry/utils/modal-option.tsx +38 -0
package/README.md
CHANGED
|
@@ -55,6 +55,15 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
55
55
|
- `weatherCoordinate`
|
|
56
56
|
- `useWeatherKorea`
|
|
57
57
|
- `useOpenWeatherMap`
|
|
58
|
+
- `/service-inquiry`
|
|
59
|
+
- `ServiceInquiry.Form`
|
|
60
|
+
- `ServiceInquiry.OpenButton`
|
|
61
|
+
- `ServiceInquiry.useOpen`
|
|
62
|
+
- `ServiceInquiry.useUserContext`
|
|
63
|
+
- `ServiceInquiry.createModal`
|
|
64
|
+
- `ServiceInquiryFieldMode`
|
|
65
|
+
- `ServiceInquiryFormProps`
|
|
66
|
+
- `ServiceInquiryFormValues`
|
|
58
67
|
- `/cctv`
|
|
59
68
|
- `CCTV.Provider`
|
|
60
69
|
- `CCTV.CamList.Container`
|
|
@@ -95,6 +104,10 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
95
104
|
- `/modal/**`
|
|
96
105
|
- ui-legacy 스택 기반 모달 Provider/Root/Container + 템플릿(`Modal.Alert`, `Modal.Dialog`)
|
|
97
106
|
- Storybook(`apps/design-storybook/src/stories/templates/modal`)에서 Alert/Confirm 케이스를 검증한다.
|
|
107
|
+
- `/service-inquiry/**`
|
|
108
|
+
- 문의 입력 전용 form, 기본 원형 `?` open button, 커스텀 trigger용 open hook, request context 조립 hook, modal preset factory를 제공한다.
|
|
109
|
+
- submit transport, React Query mutation, Next.js route handler, 에러 피드백(`Modal.Alert`)은 서비스 앱이 소유한다.
|
|
110
|
+
- 로그인 후 `farm_name`, `contact`를 auto-fill + readonly로 보여야 할 때는 `formContextOptions.defaultValues`와 `farmNameField.mode`, `contactField.mode`를 함께 전달한다.
|
|
98
111
|
- `/weather/**`
|
|
99
112
|
- page-frame header utility에 결합되는 weather header 템플릿과 weather data hook/mock 도구를 제공한다.
|
|
100
113
|
- `/cctv/**`
|
|
@@ -104,6 +117,16 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
104
117
|
|
|
105
118
|
각 템플릿의 상세한 범위와 의사결정은 `CONTEXT-*.md` 문서에서 관리합니다.
|
|
106
119
|
|
|
120
|
+
### Service Inquiry 도입 흐름
|
|
121
|
+
|
|
122
|
+
1. 서비스 앱이 `react-hook-form`으로 `defaultValues`와 `onSubmit`을 준비한다.
|
|
123
|
+
2. 필요하면 `ServiceInquiry.useUserContext`로 `labels`, `page_path`, 추가 `user_context`를 조립한다.
|
|
124
|
+
3. 기본 버튼은 `ServiceInquiry.OpenButton`, 커스텀 버튼은 `ServiceInquiry.useOpen`으로 모달 open을 연결한다.
|
|
125
|
+
4. modal footer confirm이 `ServiceInquiry.Form` submit 진입을 담당한다.
|
|
126
|
+
5. 실제 submit은 서비스 앱의 `useMutation + Next.js route handler + Modal.Alert` 조합으로 처리한다.
|
|
127
|
+
|
|
128
|
+
`service-inquiry`는 구조와 request context까지만 제공하고, 네트워크 상태/재시도/성공·실패 피드백은 서비스 앱이 소유합니다.
|
|
129
|
+
|
|
107
130
|
### 회원가입 Step 구조
|
|
108
131
|
|
|
109
132
|
1. **Step1 — User Info (name + phone)**: 기본 정보 입력. PhoneInput은 인증 UI 없이 마스킹만 제공한다.
|
package/dist/styles.css
CHANGED
|
@@ -1732,3 +1732,35 @@
|
|
|
1732
1732
|
.cctv-viewer-desktop-pagination-container {
|
|
1733
1733
|
margin-top: var(--spacing-gap-8);
|
|
1734
1734
|
}
|
|
1735
|
+
|
|
1736
|
+
.service-inquiry-form {
|
|
1737
|
+
display: flex;
|
|
1738
|
+
flex-direction: column;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
.service-inquiry-fields {
|
|
1742
|
+
display: flex;
|
|
1743
|
+
flex-direction: column;
|
|
1744
|
+
gap: var(--spacing-padding-5);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
.service-inquiry-field {
|
|
1748
|
+
display: flex;
|
|
1749
|
+
flex-direction: column;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
.service-inquiry-open-button {
|
|
1753
|
+
width: 40px;
|
|
1754
|
+
height: 40px;
|
|
1755
|
+
border-radius: 20px;
|
|
1756
|
+
border: 1px solid var(--color-border-standard-cool-gray);
|
|
1757
|
+
background: var(--color_100);
|
|
1758
|
+
color: var(--color-label-neutral);
|
|
1759
|
+
font-size: 24px;
|
|
1760
|
+
font-weight: 400;
|
|
1761
|
+
display: flex;
|
|
1762
|
+
align-items: center;
|
|
1763
|
+
justify-content: center;
|
|
1764
|
+
padding: 0;
|
|
1765
|
+
cursor: pointer;
|
|
1766
|
+
}
|
package/package.json
CHANGED
package/src/index.scss
CHANGED
package/src/index.tsx
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { Form, Input } from "@uniai-fe/uds-primitives";
|
|
5
|
+
import { useFormContext } from "react-hook-form";
|
|
6
|
+
import type { ServiceInquiryFieldKey, ServiceInquiryFormProps } from "../types";
|
|
7
|
+
import type { ServiceInquiryFormValues } from "../types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Service Inquiry Form; 문의 입력 form
|
|
11
|
+
* @component
|
|
12
|
+
* @param {ServiceInquiryFormProps} props 문의 form props
|
|
13
|
+
* @param {string} [props.className] form className
|
|
14
|
+
* @param {ServiceInquiryFieldKey[]} [props.visibleFields] 노출 필드 목록
|
|
15
|
+
* @param {ServiceInquiryInputFieldProps} [props.farmNameField] 농장명 필드 설정
|
|
16
|
+
* @param {ServiceInquiryInputFieldProps} [props.contactField] 연락처 필드 설정
|
|
17
|
+
* @param {ServiceInquiryTextAreaFieldProps} [props.textField] 문의 본문 필드 설정
|
|
18
|
+
* @param {SubmitHandler<ServiceInquiryFormValues>} props.onSubmit 문의 제출 핸들러
|
|
19
|
+
* @example
|
|
20
|
+
* <ServiceInquiryForm onSubmit={values => console.info(values)} />
|
|
21
|
+
*/
|
|
22
|
+
const ServiceInquiryForm = ({
|
|
23
|
+
className,
|
|
24
|
+
visibleFields,
|
|
25
|
+
farmNameField,
|
|
26
|
+
contactField,
|
|
27
|
+
textField,
|
|
28
|
+
onSubmit,
|
|
29
|
+
}: ServiceInquiryFormProps) => {
|
|
30
|
+
const form = useFormContext<ServiceInquiryFormValues>();
|
|
31
|
+
|
|
32
|
+
// 변경 설명: Modal.Dialog confirm 기본 submit과 연결되도록 form.handleSubmit 결과를 그대로 onSubmit에 바인딩한다.
|
|
33
|
+
const handleSubmit = form.handleSubmit(onSubmit);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<form
|
|
37
|
+
className={clsx("service-inquiry-form", className)}
|
|
38
|
+
onSubmit={handleSubmit}
|
|
39
|
+
>
|
|
40
|
+
<div className="service-inquiry-fields">
|
|
41
|
+
{(visibleFields?.includes("farm_name") ?? true) ? (
|
|
42
|
+
<Form.Field.Template
|
|
43
|
+
className={clsx(
|
|
44
|
+
"service-inquiry-field",
|
|
45
|
+
"service-inquiry-field-farm-name",
|
|
46
|
+
farmNameField?.className,
|
|
47
|
+
)}
|
|
48
|
+
width={farmNameField?.inputProps?.width ?? "full"}
|
|
49
|
+
headerProps={{
|
|
50
|
+
required: farmNameField?.required,
|
|
51
|
+
...(typeof farmNameField?.label === "string"
|
|
52
|
+
? { label: farmNameField.label }
|
|
53
|
+
: typeof farmNameField?.label === "number"
|
|
54
|
+
? { label: String(farmNameField.label) }
|
|
55
|
+
: {
|
|
56
|
+
labelJsx:
|
|
57
|
+
typeof farmNameField?.label === "undefined"
|
|
58
|
+
? "농장명"
|
|
59
|
+
: farmNameField.label,
|
|
60
|
+
}),
|
|
61
|
+
}}
|
|
62
|
+
footer={farmNameField?.helper}
|
|
63
|
+
>
|
|
64
|
+
<Input.Base
|
|
65
|
+
type="text"
|
|
66
|
+
block={farmNameField?.inputProps?.block ?? true}
|
|
67
|
+
readOnly={
|
|
68
|
+
farmNameField?.mode === "readonly" ||
|
|
69
|
+
farmNameField?.inputProps?.readOnly === true
|
|
70
|
+
}
|
|
71
|
+
placeholder={farmNameField?.placeholder ?? "농장명 입력"}
|
|
72
|
+
{...farmNameField?.inputProps}
|
|
73
|
+
register={form.register("farm_name")}
|
|
74
|
+
/>
|
|
75
|
+
</Form.Field.Template>
|
|
76
|
+
) : null}
|
|
77
|
+
|
|
78
|
+
{(visibleFields?.includes("contact") ?? true) ? (
|
|
79
|
+
<Form.Field.Template
|
|
80
|
+
className={clsx(
|
|
81
|
+
"service-inquiry-field",
|
|
82
|
+
"service-inquiry-field-contact",
|
|
83
|
+
contactField?.className,
|
|
84
|
+
)}
|
|
85
|
+
width={contactField?.inputProps?.width ?? "full"}
|
|
86
|
+
headerProps={{
|
|
87
|
+
required: contactField?.required ?? true,
|
|
88
|
+
...(typeof contactField?.label === "string"
|
|
89
|
+
? { label: contactField.label }
|
|
90
|
+
: typeof contactField?.label === "number"
|
|
91
|
+
? { label: String(contactField.label) }
|
|
92
|
+
: {
|
|
93
|
+
labelJsx:
|
|
94
|
+
typeof contactField?.label === "undefined"
|
|
95
|
+
? "연락처"
|
|
96
|
+
: contactField.label,
|
|
97
|
+
}),
|
|
98
|
+
}}
|
|
99
|
+
footer={contactField?.helper}
|
|
100
|
+
>
|
|
101
|
+
<Input.Base
|
|
102
|
+
type="text"
|
|
103
|
+
block={contactField?.inputProps?.block ?? true}
|
|
104
|
+
readOnly={
|
|
105
|
+
contactField?.mode === "readonly" ||
|
|
106
|
+
contactField?.inputProps?.readOnly === true
|
|
107
|
+
}
|
|
108
|
+
placeholder={
|
|
109
|
+
contactField?.placeholder ?? "이메일 또는 전화번호 입력"
|
|
110
|
+
}
|
|
111
|
+
{...contactField?.inputProps}
|
|
112
|
+
register={form.register("contact")}
|
|
113
|
+
/>
|
|
114
|
+
</Form.Field.Template>
|
|
115
|
+
) : null}
|
|
116
|
+
|
|
117
|
+
{(visibleFields?.includes("text") ?? true) ? (
|
|
118
|
+
<Form.Field.Template
|
|
119
|
+
className={clsx(
|
|
120
|
+
"service-inquiry-field",
|
|
121
|
+
"service-inquiry-field-text",
|
|
122
|
+
textField?.className,
|
|
123
|
+
)}
|
|
124
|
+
width={textField?.inputProps?.width ?? "full"}
|
|
125
|
+
headerProps={{
|
|
126
|
+
required: textField?.required ?? true,
|
|
127
|
+
...(typeof textField?.label === "string"
|
|
128
|
+
? { label: textField.label }
|
|
129
|
+
: typeof textField?.label === "number"
|
|
130
|
+
? { label: String(textField.label) }
|
|
131
|
+
: {
|
|
132
|
+
labelJsx:
|
|
133
|
+
typeof textField?.label === "undefined"
|
|
134
|
+
? "문의 내용"
|
|
135
|
+
: textField.label,
|
|
136
|
+
}),
|
|
137
|
+
}}
|
|
138
|
+
footer={textField?.helper}
|
|
139
|
+
>
|
|
140
|
+
<Input.TextArea
|
|
141
|
+
block={textField?.inputProps?.block ?? true}
|
|
142
|
+
placeholder={
|
|
143
|
+
textField?.placeholder ?? "문의 내용을 자세히 입력해 주세요."
|
|
144
|
+
}
|
|
145
|
+
height={textField?.inputProps?.height ?? 160}
|
|
146
|
+
length={textField?.inputProps?.length ?? 10000}
|
|
147
|
+
{...textField?.inputProps}
|
|
148
|
+
register={form.register("text")}
|
|
149
|
+
/>
|
|
150
|
+
</Form.Field.Template>
|
|
151
|
+
) : null}
|
|
152
|
+
</div>
|
|
153
|
+
</form>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default ServiceInquiryForm;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useOpenServiceInquiry } from "../hooks";
|
|
4
|
+
import type { ServiceInquiryOpenButtonProps } from "../types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Service Inquiry Open Button; 문의 모달 trigger adapter
|
|
8
|
+
* @component
|
|
9
|
+
* @param {ServiceInquiryOpenButtonProps} props 문의 모달 열기 props
|
|
10
|
+
* @param {string} props.stackKey modal stack key
|
|
11
|
+
* @param {ServiceInquiryFormProps} props.formProps 문의 form props
|
|
12
|
+
* @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [props.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
13
|
+
* @param {() => void} [props.onOpen] 모달 open 직전 콜백
|
|
14
|
+
* @example
|
|
15
|
+
* <ServiceInquiryOpenButton
|
|
16
|
+
* stackKey="sample"
|
|
17
|
+
* formProps={{ onSubmit: values => console.info(values) }}
|
|
18
|
+
* />
|
|
19
|
+
*/
|
|
20
|
+
const ServiceInquiryOpenButton = ({
|
|
21
|
+
stackKey,
|
|
22
|
+
formProps,
|
|
23
|
+
dialogOptions,
|
|
24
|
+
onOpen,
|
|
25
|
+
}: ServiceInquiryOpenButtonProps) => {
|
|
26
|
+
const { openServiceInquiry } = useOpenServiceInquiry({
|
|
27
|
+
stackKey,
|
|
28
|
+
formProps,
|
|
29
|
+
dialogOptions,
|
|
30
|
+
onOpen,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<button
|
|
35
|
+
type="button"
|
|
36
|
+
className="service-inquiry-open-button"
|
|
37
|
+
aria-label="문의하기"
|
|
38
|
+
// 변경 설명: 기본 제공 버튼은 고정 원형 `?` 버튼 사양으로 렌더링한다.
|
|
39
|
+
onClick={openServiceInquiry}
|
|
40
|
+
>
|
|
41
|
+
?
|
|
42
|
+
</button>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default ServiceInquiryOpenButton;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Modal } from "../../modal";
|
|
4
|
+
import { createServiceInquiryModal } from "../utils/modal-option";
|
|
5
|
+
import type {
|
|
6
|
+
UseOpenServiceInquiryOptions,
|
|
7
|
+
UseOpenServiceInquiryReturn,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Service Inquiry Hook; 문의 모달 열기 Hook
|
|
12
|
+
* @hook
|
|
13
|
+
* @param {UseOpenServiceInquiryOptions} options 문의 모달 열기 훅 옵션
|
|
14
|
+
* @param {string} options.stackKey modal stack key
|
|
15
|
+
* @param {ServiceInquiryFormProps} options.formProps 문의 form props
|
|
16
|
+
* @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [options.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
17
|
+
* @param {() => void} [options.onOpen] 모달 open 직전 콜백
|
|
18
|
+
* @returns {UseOpenServiceInquiryReturn} 문의 모달 open 함수
|
|
19
|
+
* @example
|
|
20
|
+
* const { openServiceInquiry } = useOpenServiceInquiry({
|
|
21
|
+
* stackKey: "sample",
|
|
22
|
+
* formProps: { onSubmit: values => console.info(values) },
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
export function useOpenServiceInquiry({
|
|
26
|
+
stackKey,
|
|
27
|
+
formProps,
|
|
28
|
+
dialogOptions,
|
|
29
|
+
onOpen,
|
|
30
|
+
}: UseOpenServiceInquiryOptions): UseOpenServiceInquiryReturn {
|
|
31
|
+
const { newModal } = Modal.useModal();
|
|
32
|
+
|
|
33
|
+
// 변경 설명: 커스텀 버튼은 render prop 대신 hook이 돌려주는 단일 open 함수로 연결한다.
|
|
34
|
+
const openServiceInquiry = () => {
|
|
35
|
+
onOpen?.();
|
|
36
|
+
newModal(
|
|
37
|
+
createServiceInquiryModal({
|
|
38
|
+
stackKey,
|
|
39
|
+
formProps,
|
|
40
|
+
dialogOptions,
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
openServiceInquiry,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import type {
|
|
5
|
+
ServiceInquiryRequestContext,
|
|
6
|
+
ServiceInquiryUserContext,
|
|
7
|
+
UseServiceInquiryUserContextOptions,
|
|
8
|
+
UseServiceInquiryUserContextReturn,
|
|
9
|
+
} from "../types";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Service Inquiry Hook; request context 제어 Hook
|
|
13
|
+
* @hook
|
|
14
|
+
* @param {UseServiceInquiryUserContextOptions} options user_context 훅 옵션
|
|
15
|
+
* @param {string[]} [options.labels] 문의 request에 포함할 labels
|
|
16
|
+
* @param {string} [options.pagePath] 고정 page_path
|
|
17
|
+
* @param {ServiceInquiryPagePathResolver} [options.resolvePagePath] page_path 동적 resolver
|
|
18
|
+
* @param {ServiceInquiryUserContext | null} [options.userContext] 서비스 기본 user_context
|
|
19
|
+
* @param {ServiceInquiryUserContextResolver} [options.resolveUserContext] 서비스 기본 user_context 동적 resolver
|
|
20
|
+
* @returns {UseServiceInquiryUserContextReturn} request context 및 추가 user_context 제어 함수
|
|
21
|
+
* @example
|
|
22
|
+
* const inquiryContext = useServiceInquiryUserContext({
|
|
23
|
+
* labels: ["help-desk"],
|
|
24
|
+
* resolveUserContext: () => ({ section: "dashboard" }),
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
export function useServiceInquiryUserContext({
|
|
28
|
+
labels,
|
|
29
|
+
pagePath,
|
|
30
|
+
resolvePagePath,
|
|
31
|
+
userContext,
|
|
32
|
+
resolveUserContext,
|
|
33
|
+
}: UseServiceInquiryUserContextOptions): UseServiceInquiryUserContextReturn {
|
|
34
|
+
/** 1) form init — 서비스 기본 context와 별도 trigger 추가 context를 나눠 관리한다. */
|
|
35
|
+
const [additionalUserContext, setAdditionalUserContext] =
|
|
36
|
+
useState<ServiceInquiryUserContext | null>(null);
|
|
37
|
+
|
|
38
|
+
/** 2) register merge — 서비스 기본 context와 trigger 추가 context를 한 payload로 합친다. */
|
|
39
|
+
const resolvedPagePath =
|
|
40
|
+
pagePath ??
|
|
41
|
+
resolvePagePath?.() ??
|
|
42
|
+
(typeof window === "undefined" ? "" : window.location.pathname);
|
|
43
|
+
const resolvedBaseUserContext = userContext ?? resolveUserContext?.() ?? null;
|
|
44
|
+
const mergedUserContext =
|
|
45
|
+
resolvedBaseUserContext || additionalUserContext
|
|
46
|
+
? {
|
|
47
|
+
...(resolvedBaseUserContext ?? {}),
|
|
48
|
+
...(additionalUserContext ?? {}),
|
|
49
|
+
}
|
|
50
|
+
: null;
|
|
51
|
+
|
|
52
|
+
/** 3) helper/state — submit에 바로 연결할 request context snapshot을 노출한다. */
|
|
53
|
+
const requestContext: ServiceInquiryRequestContext = {
|
|
54
|
+
labels: labels ?? [],
|
|
55
|
+
page_path: resolvedPagePath,
|
|
56
|
+
user_context: mergedUserContext,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** 4) submit/액션 — trigger별 추가 context를 append/reset 할 수 있게 연다. */
|
|
60
|
+
const setNextAdditionalUserContext: UseServiceInquiryUserContextReturn["setAdditionalUserContext"] =
|
|
61
|
+
nextUserContext => {
|
|
62
|
+
setAdditionalUserContext(nextUserContext);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const appendUserContext: UseServiceInquiryUserContextReturn["appendUserContext"] =
|
|
66
|
+
(nextUserContext?: ServiceInquiryUserContext | null) => {
|
|
67
|
+
if (!nextUserContext) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setAdditionalUserContext(currentUserContext => ({
|
|
72
|
+
...(currentUserContext ?? {}),
|
|
73
|
+
...nextUserContext,
|
|
74
|
+
}));
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const clearAdditionalUserContext: UseServiceInquiryUserContextReturn["clearAdditionalUserContext"] =
|
|
78
|
+
() => {
|
|
79
|
+
setAdditionalUserContext(null);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
requestContext,
|
|
84
|
+
additionalUserContext,
|
|
85
|
+
setAdditionalUserContext: setNextAdditionalUserContext,
|
|
86
|
+
appendUserContext,
|
|
87
|
+
clearAdditionalUserContext,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@use "./styles/index.scss";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "./index.scss";
|
|
2
|
+
import ServiceInquiryForm from "./components/Form";
|
|
3
|
+
import ServiceInquiryOpenButton from "./components/OpenButton";
|
|
4
|
+
import { useOpenServiceInquiry, useServiceInquiryUserContext } from "./hooks";
|
|
5
|
+
import { createServiceInquiryModal } from "./utils/modal-option";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Service Inquiry; 문의 form + modal option 엔트리
|
|
9
|
+
* - 변경 설명: Step 2에서 Form과 Modal.Dialog 기반 factory를 첫 runtime 조각으로 연다.
|
|
10
|
+
*/
|
|
11
|
+
export const ServiceInquiry = {
|
|
12
|
+
Form: ServiceInquiryForm,
|
|
13
|
+
OpenButton: ServiceInquiryOpenButton,
|
|
14
|
+
useOpen: useOpenServiceInquiry,
|
|
15
|
+
useUserContext: useServiceInquiryUserContext,
|
|
16
|
+
createModal: createServiceInquiryModal,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
ServiceInquiryForm,
|
|
21
|
+
ServiceInquiryOpenButton,
|
|
22
|
+
useOpenServiceInquiry,
|
|
23
|
+
useServiceInquiryUserContext,
|
|
24
|
+
createServiceInquiryModal,
|
|
25
|
+
};
|
|
26
|
+
export type * from "./types";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.service-inquiry-form {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.service-inquiry-fields {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--spacing-padding-5);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.service-inquiry-field {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.service-inquiry-open-button {
|
|
2
|
+
width: 40px;
|
|
3
|
+
height: 40px;
|
|
4
|
+
border-radius: 20px;
|
|
5
|
+
border: 1px solid var(--color-border-standard-cool-gray);
|
|
6
|
+
background: var(--color_100);
|
|
7
|
+
color: var(--color-label-neutral);
|
|
8
|
+
font-size: 24px;
|
|
9
|
+
font-weight: 400;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
padding: 0;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ServiceInquiryUserContext } from "./form-context";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Service Inquiry API; 문의 등록 요청
|
|
5
|
+
* @property {string} text 문의 본문
|
|
6
|
+
* @property {string} farm_name 문의 대상 농장명 또는 빈 문자열
|
|
7
|
+
* @property {string[]} labels JIRA label 목록
|
|
8
|
+
* @property {string} contact 문의자 연락처(email 또는 phone number)
|
|
9
|
+
* @property {string} page_path 문의하기를 연 페이지 경로
|
|
10
|
+
* @property {ServiceInquiryUserContext | null} user_context 문의 시점 사용자/환경 맥락
|
|
11
|
+
*/
|
|
12
|
+
export interface API_Req_ServiceInquiry {
|
|
13
|
+
/**
|
|
14
|
+
* 문의 본문
|
|
15
|
+
*/
|
|
16
|
+
text: string;
|
|
17
|
+
/**
|
|
18
|
+
* 문의 대상 농장명 또는 빈 문자열
|
|
19
|
+
*/
|
|
20
|
+
farm_name: string;
|
|
21
|
+
/**
|
|
22
|
+
* JIRA label 목록
|
|
23
|
+
*/
|
|
24
|
+
labels: string[];
|
|
25
|
+
/**
|
|
26
|
+
* 문의자 연락처
|
|
27
|
+
*/
|
|
28
|
+
contact: string;
|
|
29
|
+
/**
|
|
30
|
+
* 문의하기를 연 페이지 경로
|
|
31
|
+
*/
|
|
32
|
+
page_path: string;
|
|
33
|
+
/**
|
|
34
|
+
* 문의 시점 사용자/환경 맥락
|
|
35
|
+
*/
|
|
36
|
+
user_context: ServiceInquiryUserContext | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Service Inquiry API; 문의 등록 응답
|
|
41
|
+
* @property {boolean} success 문의 등록 성공 여부
|
|
42
|
+
* @property {string} issue_key JIRA issue key
|
|
43
|
+
* @property {string} issue_url JIRA issue URL
|
|
44
|
+
* @property {string} summary JIRA issue 제목
|
|
45
|
+
* @property {string} message 서버 응답 메시지
|
|
46
|
+
*/
|
|
47
|
+
export interface API_Res_ServiceInquiry {
|
|
48
|
+
/**
|
|
49
|
+
* 문의 등록 성공 여부
|
|
50
|
+
*/
|
|
51
|
+
success: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* JIRA issue key
|
|
54
|
+
*/
|
|
55
|
+
issue_key: string;
|
|
56
|
+
/**
|
|
57
|
+
* JIRA issue URL
|
|
58
|
+
*/
|
|
59
|
+
issue_url: string;
|
|
60
|
+
/**
|
|
61
|
+
* JIRA issue 제목
|
|
62
|
+
*/
|
|
63
|
+
summary: string;
|
|
64
|
+
/**
|
|
65
|
+
* 서버 응답 메시지
|
|
66
|
+
*/
|
|
67
|
+
message: string;
|
|
68
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Inquiry Form; 사용자 입력값
|
|
3
|
+
* @property {string} text 문의 본문
|
|
4
|
+
* @property {string} farm_name 농장명 또는 빈 문자열
|
|
5
|
+
* @property {string} contact 문의자 연락처
|
|
6
|
+
*/
|
|
7
|
+
export interface ServiceInquiryFormValues {
|
|
8
|
+
/**
|
|
9
|
+
* 문의 본문
|
|
10
|
+
*/
|
|
11
|
+
text: string;
|
|
12
|
+
/**
|
|
13
|
+
* 농장명 또는 빈 문자열
|
|
14
|
+
*/
|
|
15
|
+
farm_name: string;
|
|
16
|
+
/**
|
|
17
|
+
* 문의자 연락처
|
|
18
|
+
*/
|
|
19
|
+
contact: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Service Inquiry Form; 시스템 주입 request context
|
|
24
|
+
* @property {string[]} labels JIRA label 목록
|
|
25
|
+
* @property {string} page_path 문의를 연 페이지 경로
|
|
26
|
+
* @property {ServiceInquiryUserContext | null} user_context 문의 시점 사용자/환경 맥락
|
|
27
|
+
*/
|
|
28
|
+
export interface ServiceInquiryRequestContext {
|
|
29
|
+
/**
|
|
30
|
+
* JIRA label 목록
|
|
31
|
+
*/
|
|
32
|
+
labels: string[];
|
|
33
|
+
/**
|
|
34
|
+
* 문의를 연 페이지 경로
|
|
35
|
+
*/
|
|
36
|
+
page_path: string;
|
|
37
|
+
/**
|
|
38
|
+
* 문의 시점 사용자/환경 맥락
|
|
39
|
+
*/
|
|
40
|
+
user_context: ServiceInquiryUserContext | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Service Inquiry Form; 사용자/환경 맥락 payload
|
|
45
|
+
* @property {unknown} [key] 디버깅을 위한 사용자 동작/환경 스냅샷
|
|
46
|
+
*/
|
|
47
|
+
// 변경 설명: user_context는 서비스별 arbitrary object 확장 지점이므로 Record 기반 의도를 타입 이름에서 바로 읽히게 맞춘다.
|
|
48
|
+
export interface ServiceInquiryUserContext extends Record<string, unknown> {}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ServiceInquiryRequestContext,
|
|
3
|
+
ServiceInquiryUserContext,
|
|
4
|
+
} from "./form-context";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Service Inquiry Hook; 페이지 경로 resolver
|
|
8
|
+
* @returns {string} 문의하기를 연 페이지 경로
|
|
9
|
+
*/
|
|
10
|
+
export type ServiceInquiryPagePathResolver = () => string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Service Inquiry Hook; 서비스 user context resolver
|
|
14
|
+
* @returns {ServiceInquiryUserContext | null} 서비스가 제공하는 기본 user_context
|
|
15
|
+
*/
|
|
16
|
+
export type ServiceInquiryUserContextResolver =
|
|
17
|
+
() => ServiceInquiryUserContext | null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Service Inquiry Hook; user_context 훅 옵션
|
|
21
|
+
* @property {string[]} [labels] 문의 request에 포함할 labels
|
|
22
|
+
* @property {string} [pagePath] 고정 page_path
|
|
23
|
+
* @property {ServiceInquiryPagePathResolver} [resolvePagePath] page_path 동적 resolver
|
|
24
|
+
* @property {ServiceInquiryUserContext | null} [userContext] 서비스 기본 user_context
|
|
25
|
+
* @property {ServiceInquiryUserContextResolver} [resolveUserContext] 서비스 기본 user_context 동적 resolver
|
|
26
|
+
*/
|
|
27
|
+
export interface UseServiceInquiryUserContextOptions {
|
|
28
|
+
/**
|
|
29
|
+
* 문의 request에 포함할 labels
|
|
30
|
+
*/
|
|
31
|
+
labels?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* 고정 page_path
|
|
34
|
+
*/
|
|
35
|
+
pagePath?: string;
|
|
36
|
+
/**
|
|
37
|
+
* page_path 동적 resolver
|
|
38
|
+
*/
|
|
39
|
+
resolvePagePath?: ServiceInquiryPagePathResolver;
|
|
40
|
+
/**
|
|
41
|
+
* 서비스 기본 user_context
|
|
42
|
+
*/
|
|
43
|
+
userContext?: ServiceInquiryUserContext | null;
|
|
44
|
+
/**
|
|
45
|
+
* 서비스 기본 user_context 동적 resolver
|
|
46
|
+
*/
|
|
47
|
+
resolveUserContext?: ServiceInquiryUserContextResolver;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Service Inquiry Hook; user_context 훅 반환값
|
|
52
|
+
* @property {ServiceInquiryRequestContext} requestContext form submit에 바로 사용할 request context
|
|
53
|
+
* @property {ServiceInquiryUserContext | null} additionalUserContext trigger/interaction에서 추가된 user_context
|
|
54
|
+
* @property {(nextUserContext: ServiceInquiryUserContext | null) => void} setAdditionalUserContext 추가 user_context 교체 함수
|
|
55
|
+
* @property {(nextUserContext?: ServiceInquiryUserContext | null) => void} appendUserContext 추가 user_context 병합 함수
|
|
56
|
+
* @property {() => void} clearAdditionalUserContext 추가 user_context 초기화 함수
|
|
57
|
+
*/
|
|
58
|
+
export interface UseServiceInquiryUserContextReturn {
|
|
59
|
+
/**
|
|
60
|
+
* form submit에 바로 사용할 request context
|
|
61
|
+
*/
|
|
62
|
+
requestContext: ServiceInquiryRequestContext;
|
|
63
|
+
/**
|
|
64
|
+
* trigger/interaction에서 추가된 user_context
|
|
65
|
+
*/
|
|
66
|
+
additionalUserContext: ServiceInquiryUserContext | null;
|
|
67
|
+
/**
|
|
68
|
+
* 추가 user_context 교체 함수
|
|
69
|
+
*/
|
|
70
|
+
setAdditionalUserContext: (
|
|
71
|
+
nextUserContext: ServiceInquiryUserContext | null,
|
|
72
|
+
) => void;
|
|
73
|
+
/**
|
|
74
|
+
* 추가 user_context 병합 함수
|
|
75
|
+
*/
|
|
76
|
+
appendUserContext: (
|
|
77
|
+
nextUserContext?: ServiceInquiryUserContext | null,
|
|
78
|
+
) => void;
|
|
79
|
+
/**
|
|
80
|
+
* 추가 user_context 초기화 함수
|
|
81
|
+
*/
|
|
82
|
+
clearAdditionalUserContext: () => void;
|
|
83
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { SubmitHandler } from "react-hook-form";
|
|
3
|
+
import type { InputProps, InputTextAreaProps } from "@uniai-fe/uds-primitives";
|
|
4
|
+
import type { DialogTemplateOptions } from "../../modal/types";
|
|
5
|
+
import type { ServiceInquiryFormValues } from "./form-context";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Service Inquiry; 노출 필드 키
|
|
9
|
+
*/
|
|
10
|
+
export type ServiceInquiryFieldKey = "farm_name" | "contact" | "text";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Service Inquiry Form; field 입력 모드
|
|
14
|
+
* @typedef {"editable" | "readonly"} ServiceInquiryFieldMode
|
|
15
|
+
*/
|
|
16
|
+
export type ServiceInquiryFieldMode = "editable" | "readonly";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Service Inquiry Form; 공통 field 설정
|
|
20
|
+
* @property {string} [className] field wrapper className
|
|
21
|
+
* @property {ReactNode} [label] field label
|
|
22
|
+
* @property {ReactNode} [helper] field helper
|
|
23
|
+
* @property {boolean} [required] required 표시 여부
|
|
24
|
+
*/
|
|
25
|
+
export interface ServiceInquiryFieldBaseProps {
|
|
26
|
+
/**
|
|
27
|
+
* field wrapper className
|
|
28
|
+
*/
|
|
29
|
+
className?: string;
|
|
30
|
+
/**
|
|
31
|
+
* field label
|
|
32
|
+
*/
|
|
33
|
+
label?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* field helper
|
|
36
|
+
*/
|
|
37
|
+
helper?: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* required 표시 여부
|
|
40
|
+
*/
|
|
41
|
+
required?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Service Inquiry Form; 단일 line input field 설정
|
|
46
|
+
* @property {"editable" | "readonly"} [mode] 서비스가 제어하는 field 입력 모드
|
|
47
|
+
* @property {string} [placeholder] input placeholder
|
|
48
|
+
* @property {InputProps} [inputProps] primitives Input.Base override
|
|
49
|
+
*/
|
|
50
|
+
export interface ServiceInquiryInputFieldProps extends ServiceInquiryFieldBaseProps {
|
|
51
|
+
/**
|
|
52
|
+
* 서비스가 제어하는 field 입력 모드
|
|
53
|
+
*/
|
|
54
|
+
mode?: ServiceInquiryFieldMode;
|
|
55
|
+
/**
|
|
56
|
+
* input placeholder
|
|
57
|
+
*/
|
|
58
|
+
placeholder?: string;
|
|
59
|
+
/**
|
|
60
|
+
* primitives Input.Base override
|
|
61
|
+
*/
|
|
62
|
+
inputProps?: InputProps;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Service Inquiry Form; textarea field 설정
|
|
67
|
+
* @property {string} [placeholder] textarea placeholder
|
|
68
|
+
* @property {InputTextAreaProps} [inputProps] primitives Input.TextArea override
|
|
69
|
+
*/
|
|
70
|
+
export interface ServiceInquiryTextAreaFieldProps extends ServiceInquiryFieldBaseProps {
|
|
71
|
+
/**
|
|
72
|
+
* textarea placeholder
|
|
73
|
+
*/
|
|
74
|
+
placeholder?: string;
|
|
75
|
+
/**
|
|
76
|
+
* primitives Input.TextArea override
|
|
77
|
+
*/
|
|
78
|
+
inputProps?: InputTextAreaProps;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Service Inquiry Form; 문의 입력 폼 props
|
|
83
|
+
* @property {string} [className] form className
|
|
84
|
+
* @property {ServiceInquiryFieldKey[]} [visibleFields] 노출 필드 목록
|
|
85
|
+
* @property {ServiceInquiryInputFieldProps} [farmNameField] 농장명 필드 설정
|
|
86
|
+
* @property {ServiceInquiryInputFieldProps} [contactField] 연락처 필드 설정
|
|
87
|
+
* @property {ServiceInquiryTextAreaFieldProps} [textField] 문의 본문 필드 설정
|
|
88
|
+
* @property {SubmitHandler<ServiceInquiryFormValues>} props.onSubmit 문의 제출 핸들러
|
|
89
|
+
*/
|
|
90
|
+
export interface ServiceInquiryFormProps {
|
|
91
|
+
/**
|
|
92
|
+
* form className
|
|
93
|
+
*/
|
|
94
|
+
className?: string;
|
|
95
|
+
/**
|
|
96
|
+
* 노출 필드 목록
|
|
97
|
+
*/
|
|
98
|
+
visibleFields?: ServiceInquiryFieldKey[];
|
|
99
|
+
/**
|
|
100
|
+
* 농장명 필드 설정
|
|
101
|
+
*/
|
|
102
|
+
farmNameField?: ServiceInquiryInputFieldProps;
|
|
103
|
+
/**
|
|
104
|
+
* 연락처 필드 설정
|
|
105
|
+
*/
|
|
106
|
+
contactField?: ServiceInquiryInputFieldProps;
|
|
107
|
+
/**
|
|
108
|
+
* 문의 본문 필드 설정
|
|
109
|
+
*/
|
|
110
|
+
textField?: ServiceInquiryTextAreaFieldProps;
|
|
111
|
+
/**
|
|
112
|
+
* 문의 제출 핸들러
|
|
113
|
+
*/
|
|
114
|
+
onSubmit: SubmitHandler<ServiceInquiryFormValues>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Service Inquiry Modal; 문의 모달 preset 생성 옵션
|
|
119
|
+
* @property {string} stackKey modal stack key
|
|
120
|
+
* @property {ServiceInquiryFormProps} formProps 문의 form props
|
|
121
|
+
* @property {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
122
|
+
*/
|
|
123
|
+
// 변경 설명: DialogTemplateOptions를 거의 다시 적는 wrapper 대신, 모듈 고유 필드와 dialog override bag만 가진 preset 입력 타입으로 줄인다.
|
|
124
|
+
export interface ServiceInquiryCreateModalOptions {
|
|
125
|
+
/**
|
|
126
|
+
* modal stack key
|
|
127
|
+
*/
|
|
128
|
+
stackKey: string;
|
|
129
|
+
/**
|
|
130
|
+
* 문의 form props
|
|
131
|
+
*/
|
|
132
|
+
formProps: ServiceInquiryFormProps;
|
|
133
|
+
/**
|
|
134
|
+
* 문의 모달 preset 위에 덮어쓸 dialog option
|
|
135
|
+
*/
|
|
136
|
+
dialogOptions?: Partial<DialogTemplateOptions<ServiceInquiryFormValues>>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Service Inquiry Hook; 문의 모달 열기 훅 옵션
|
|
141
|
+
* @property {string} stackKey modal stack key
|
|
142
|
+
* @property {ServiceInquiryFormProps} formProps 문의 form props
|
|
143
|
+
* @property {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
144
|
+
* @property {() => void} [onOpen] 모달 open 직전 콜백
|
|
145
|
+
*/
|
|
146
|
+
export interface UseOpenServiceInquiryOptions extends ServiceInquiryCreateModalOptions {
|
|
147
|
+
/**
|
|
148
|
+
* 모달 open 직전 콜백
|
|
149
|
+
*/
|
|
150
|
+
onOpen?: () => void;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Service Inquiry Hook; 문의 모달 열기 훅 반환값
|
|
155
|
+
* @property {() => void} openServiceInquiry 문의 모달 open 함수
|
|
156
|
+
*/
|
|
157
|
+
export interface UseOpenServiceInquiryReturn {
|
|
158
|
+
/**
|
|
159
|
+
* 문의 모달 open 함수
|
|
160
|
+
*/
|
|
161
|
+
openServiceInquiry: () => void;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Service Inquiry Open Button; 문의 모달 기본 버튼 props
|
|
166
|
+
* @property {string} stackKey modal stack key
|
|
167
|
+
* @property {ServiceInquiryFormProps} formProps 문의 form props
|
|
168
|
+
* @property {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
169
|
+
* @property {() => void} [onOpen] 모달 open 직전 콜백
|
|
170
|
+
*/
|
|
171
|
+
export interface ServiceInquiryOpenButtonProps extends UseOpenServiceInquiryOptions {}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createDialogModal } from "../../modal/components/dialog/Template";
|
|
2
|
+
import ServiceInquiryForm from "../components/Form";
|
|
3
|
+
import type {
|
|
4
|
+
ServiceInquiryCreateModalOptions,
|
|
5
|
+
ServiceInquiryFormValues,
|
|
6
|
+
} from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Service Inquiry Modal; 문의 form이 포함된 Dialog option 생성기
|
|
10
|
+
* @component
|
|
11
|
+
* @param {ServiceInquiryCreateModalOptions} options 문의 모달 preset 생성 옵션
|
|
12
|
+
* @param {string} options.stackKey modal stack key
|
|
13
|
+
* @param {ServiceInquiryFormProps} options.formProps 문의 form props
|
|
14
|
+
* @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [options.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
15
|
+
* @example
|
|
16
|
+
* createServiceInquiryModal({
|
|
17
|
+
* stackKey: "service-inquiry",
|
|
18
|
+
* formProps: { onSubmit: values => console.info(values) },
|
|
19
|
+
* })
|
|
20
|
+
*/
|
|
21
|
+
export function createServiceInquiryModal({
|
|
22
|
+
stackKey,
|
|
23
|
+
formProps,
|
|
24
|
+
dialogOptions,
|
|
25
|
+
}: ServiceInquiryCreateModalOptions) {
|
|
26
|
+
return createDialogModal<ServiceInquiryFormValues>({
|
|
27
|
+
...dialogOptions,
|
|
28
|
+
stackKey,
|
|
29
|
+
title: dialogOptions?.title ?? "문의하기",
|
|
30
|
+
// 변경 설명: 문의 모달은 title과 안내 문구를 좌측 정렬로 읽히게 하기 위해 split header를 기본값으로 사용한다.
|
|
31
|
+
headerLayout: dialogOptions?.headerLayout ?? "split",
|
|
32
|
+
content: <ServiceInquiryForm {...formProps} />,
|
|
33
|
+
confirm: {
|
|
34
|
+
label: "문의 접수",
|
|
35
|
+
...dialogOptions?.confirm,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|