@uniai-fe/uds-templates 0.4.3 → 0.4.5
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 +9 -5
- package/dist/styles.css +0 -16
- package/package.json +1 -1
- package/src/service-inquiry/components/Form.tsx +10 -22
- package/src/service-inquiry/components/OpenButton.tsx +8 -7
- package/src/service-inquiry/hooks/index.ts +3 -2
- package/src/service-inquiry/hooks/useProvideContext.ts +49 -0
- package/src/service-inquiry/hooks/useUserContext.ts +57 -0
- package/src/service-inquiry/index.tsx +7 -1
- package/src/service-inquiry/jotai/context.ts +88 -0
- package/src/service-inquiry/jotai/index.ts +1 -0
- package/src/service-inquiry/styles/open-button.scss +15 -15
- package/src/service-inquiry/types/hooks.ts +6 -29
- package/src/service-inquiry/types/props.ts +0 -25
- package/src/service-inquiry/hooks/useServiceInquiryUserContext.ts +0 -89
- /package/src/service-inquiry/hooks/{useOpenServiceInquiry.ts → useOpen.ts} +0 -0
package/README.md
CHANGED
|
@@ -59,11 +59,13 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
59
59
|
- `ServiceInquiry.Form`
|
|
60
60
|
- `ServiceInquiry.OpenButton`
|
|
61
61
|
- `ServiceInquiry.useOpen`
|
|
62
|
+
- `ServiceInquiry.useProvideContext`
|
|
62
63
|
- `ServiceInquiry.useUserContext`
|
|
63
64
|
- `ServiceInquiry.createModal`
|
|
64
65
|
- `ServiceInquiryFieldMode`
|
|
65
66
|
- `ServiceInquiryFormProps`
|
|
66
67
|
- `ServiceInquiryFormValues`
|
|
68
|
+
- `ServiceInquiryProvidedContext`
|
|
67
69
|
- `/cctv`
|
|
68
70
|
- `CCTV.Provider`
|
|
69
71
|
- `CCTV.CamList.Container`
|
|
@@ -105,8 +107,9 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
105
107
|
- ui-legacy 스택 기반 모달 Provider/Root/Container + 템플릿(`Modal.Alert`, `Modal.Dialog`)
|
|
106
108
|
- Storybook(`apps/design-storybook/src/stories/templates/modal`)에서 Alert/Confirm 케이스를 검증한다.
|
|
107
109
|
- `/service-inquiry/**`
|
|
108
|
-
- 문의 입력 전용 form, 기본 원형 `?` open button, 커스텀 trigger용 open hook, request context 조립 hook, modal preset factory를 제공한다.
|
|
110
|
+
- 문의 입력 전용 form, 기본 원형 `?` open button, 커스텀 trigger용 open hook, 페이지 context 등록 hook, request context 조립 hook, modal preset factory를 제공한다.
|
|
109
111
|
- submit transport, React Query mutation, Next.js route handler, 에러 피드백(`Modal.Alert`)은 서비스 앱이 소유한다.
|
|
112
|
+
- 모듈 내부 Jotai registry를 사용하므로, layout 고정 버튼 1개와 페이지별 context 등록 hook 조합으로 ready-to-use 구성이 가능하다.
|
|
110
113
|
- 로그인 후 `farm_name`, `contact`를 auto-fill + readonly로 보여야 할 때는 `formContextOptions.defaultValues`와 `farmNameField.mode`, `contactField.mode`를 함께 전달한다.
|
|
111
114
|
- `/weather/**`
|
|
112
115
|
- page-frame header utility에 결합되는 weather header 템플릿과 weather data hook/mock 도구를 제공한다.
|
|
@@ -120,10 +123,11 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
120
123
|
### Service Inquiry 도입 흐름
|
|
121
124
|
|
|
122
125
|
1. 서비스 앱이 `react-hook-form`으로 `defaultValues`와 `onSubmit`을 준비한다.
|
|
123
|
-
2.
|
|
124
|
-
3.
|
|
125
|
-
4.
|
|
126
|
-
5.
|
|
126
|
+
2. layout 고정 버튼은 `ServiceInquiry.useUserContext()`로 모듈 내부 registry 기반 `requestContext`를 읽는다.
|
|
127
|
+
3. 각 페이지/폼은 `ServiceInquiry.useProvideContext({ labels, pagePath, userContext })`로 `ServiceInquiryProvidedContext`를 등록한다.
|
|
128
|
+
4. 기본 버튼은 `ServiceInquiry.OpenButton`, 커스텀 버튼은 `ServiceInquiry.useOpen`으로 모달 open을 연결한다.
|
|
129
|
+
5. modal footer confirm이 `ServiceInquiry.Form` submit 진입을 담당한다.
|
|
130
|
+
6. 실제 submit은 서비스 앱의 `useMutation + Next.js route handler + Modal.Alert` 조합으로 처리한다.
|
|
127
131
|
|
|
128
132
|
`service-inquiry`는 구조와 request context까지만 제공하고, 네트워크 상태/재시도/성공·실패 피드백은 서비스 앱이 소유합니다.
|
|
129
133
|
|
package/dist/styles.css
CHANGED
|
@@ -1748,19 +1748,3 @@
|
|
|
1748
1748
|
display: flex;
|
|
1749
1749
|
flex-direction: column;
|
|
1750
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
|
@@ -43,9 +43,8 @@ const ServiceInquiryForm = ({
|
|
|
43
43
|
className={clsx(
|
|
44
44
|
"service-inquiry-field",
|
|
45
45
|
"service-inquiry-field-farm-name",
|
|
46
|
-
farmNameField?.className,
|
|
47
46
|
)}
|
|
48
|
-
width=
|
|
47
|
+
width="full"
|
|
49
48
|
headerProps={{
|
|
50
49
|
required: farmNameField?.required,
|
|
51
50
|
...(typeof farmNameField?.label === "string"
|
|
@@ -63,13 +62,9 @@ const ServiceInquiryForm = ({
|
|
|
63
62
|
>
|
|
64
63
|
<Input.Base
|
|
65
64
|
type="text"
|
|
66
|
-
block={
|
|
67
|
-
readOnly={
|
|
68
|
-
farmNameField?.mode === "readonly" ||
|
|
69
|
-
farmNameField?.inputProps?.readOnly === true
|
|
70
|
-
}
|
|
65
|
+
block={true}
|
|
66
|
+
readOnly={farmNameField?.mode === "readonly"}
|
|
71
67
|
placeholder={farmNameField?.placeholder ?? "농장명 입력"}
|
|
72
|
-
{...farmNameField?.inputProps}
|
|
73
68
|
register={form.register("farm_name")}
|
|
74
69
|
/>
|
|
75
70
|
</Form.Field.Template>
|
|
@@ -80,9 +75,8 @@ const ServiceInquiryForm = ({
|
|
|
80
75
|
className={clsx(
|
|
81
76
|
"service-inquiry-field",
|
|
82
77
|
"service-inquiry-field-contact",
|
|
83
|
-
contactField?.className,
|
|
84
78
|
)}
|
|
85
|
-
width=
|
|
79
|
+
width="full"
|
|
86
80
|
headerProps={{
|
|
87
81
|
required: contactField?.required ?? true,
|
|
88
82
|
...(typeof contactField?.label === "string"
|
|
@@ -100,15 +94,11 @@ const ServiceInquiryForm = ({
|
|
|
100
94
|
>
|
|
101
95
|
<Input.Base
|
|
102
96
|
type="text"
|
|
103
|
-
block={
|
|
104
|
-
readOnly={
|
|
105
|
-
contactField?.mode === "readonly" ||
|
|
106
|
-
contactField?.inputProps?.readOnly === true
|
|
107
|
-
}
|
|
97
|
+
block={true}
|
|
98
|
+
readOnly={contactField?.mode === "readonly"}
|
|
108
99
|
placeholder={
|
|
109
100
|
contactField?.placeholder ?? "이메일 또는 전화번호 입력"
|
|
110
101
|
}
|
|
111
|
-
{...contactField?.inputProps}
|
|
112
102
|
register={form.register("contact")}
|
|
113
103
|
/>
|
|
114
104
|
</Form.Field.Template>
|
|
@@ -119,9 +109,8 @@ const ServiceInquiryForm = ({
|
|
|
119
109
|
className={clsx(
|
|
120
110
|
"service-inquiry-field",
|
|
121
111
|
"service-inquiry-field-text",
|
|
122
|
-
textField?.className,
|
|
123
112
|
)}
|
|
124
|
-
width=
|
|
113
|
+
width="full"
|
|
125
114
|
headerProps={{
|
|
126
115
|
required: textField?.required ?? true,
|
|
127
116
|
...(typeof textField?.label === "string"
|
|
@@ -138,13 +127,12 @@ const ServiceInquiryForm = ({
|
|
|
138
127
|
footer={textField?.helper}
|
|
139
128
|
>
|
|
140
129
|
<Input.TextArea
|
|
141
|
-
block={
|
|
130
|
+
block={true}
|
|
142
131
|
placeholder={
|
|
143
132
|
textField?.placeholder ?? "문의 내용을 자세히 입력해 주세요."
|
|
144
133
|
}
|
|
145
|
-
height={
|
|
146
|
-
length={
|
|
147
|
-
{...textField?.inputProps}
|
|
134
|
+
height={160}
|
|
135
|
+
length={10000}
|
|
148
136
|
register={form.register("text")}
|
|
149
137
|
/>
|
|
150
138
|
</Form.Field.Template>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { Button } from "@uniai-fe/uds-primitives";
|
|
3
4
|
import { useOpenServiceInquiry } from "../hooks";
|
|
4
|
-
import type {
|
|
5
|
+
import type { UseOpenServiceInquiryOptions } from "../types";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Service Inquiry Open Button; 문의 모달 trigger adapter
|
|
8
9
|
* @component
|
|
9
|
-
* @param {
|
|
10
|
+
* @param {UseOpenServiceInquiryOptions} props 문의 모달 열기 props
|
|
10
11
|
* @param {string} props.stackKey modal stack key
|
|
11
12
|
* @param {ServiceInquiryFormProps} props.formProps 문의 form props
|
|
12
13
|
* @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [props.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
@@ -22,7 +23,7 @@ const ServiceInquiryOpenButton = ({
|
|
|
22
23
|
formProps,
|
|
23
24
|
dialogOptions,
|
|
24
25
|
onOpen,
|
|
25
|
-
}:
|
|
26
|
+
}: UseOpenServiceInquiryOptions) => {
|
|
26
27
|
const { openServiceInquiry } = useOpenServiceInquiry({
|
|
27
28
|
stackKey,
|
|
28
29
|
formProps,
|
|
@@ -31,15 +32,15 @@ const ServiceInquiryOpenButton = ({
|
|
|
31
32
|
});
|
|
32
33
|
|
|
33
34
|
return (
|
|
34
|
-
<
|
|
35
|
-
type="button"
|
|
35
|
+
<Button.Rounded
|
|
36
36
|
className="service-inquiry-open-button"
|
|
37
|
-
|
|
37
|
+
priority="tertiary"
|
|
38
|
+
size="large"
|
|
38
39
|
// 변경 설명: 기본 제공 버튼은 고정 원형 `?` 버튼 사양으로 렌더링한다.
|
|
39
40
|
onClick={openServiceInquiry}
|
|
40
41
|
>
|
|
41
42
|
?
|
|
42
|
-
</
|
|
43
|
+
</Button.Rounded>
|
|
43
44
|
);
|
|
44
45
|
};
|
|
45
46
|
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./
|
|
1
|
+
export * from "./useOpen";
|
|
2
|
+
export * from "./useProvideContext";
|
|
3
|
+
export * from "./useUserContext";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useId } from "react";
|
|
4
|
+
import { useSetAtom } from "jotai";
|
|
5
|
+
import { serviceInquiryProvidedContextRegistryAtom } from "../jotai";
|
|
6
|
+
import type { ServiceInquiryProvidedContext } from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Service Inquiry Hook; 페이지별 문의 context 등록 Hook
|
|
10
|
+
* @hook
|
|
11
|
+
* @param {ServiceInquiryProvidedContext | null} context 페이지 또는 폼이 등록할 문의 context
|
|
12
|
+
* @example
|
|
13
|
+
* useProvideServiceInquiryContext({
|
|
14
|
+
* labels: ["orders"],
|
|
15
|
+
* userContext: { order_id: selectedOrderId },
|
|
16
|
+
* });
|
|
17
|
+
*/
|
|
18
|
+
export function useProvideServiceInquiryContext(
|
|
19
|
+
context: ServiceInquiryProvidedContext | null,
|
|
20
|
+
): void {
|
|
21
|
+
const registrationId = useId();
|
|
22
|
+
const setProvidedContextRegistry = useSetAtom(
|
|
23
|
+
serviceInquiryProvidedContextRegistryAtom,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
setProvidedContextRegistry(currentRegistry => {
|
|
28
|
+
const nextRegistry = { ...currentRegistry };
|
|
29
|
+
|
|
30
|
+
if (context) {
|
|
31
|
+
nextRegistry[registrationId] = context;
|
|
32
|
+
} else {
|
|
33
|
+
delete nextRegistry[registrationId];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return nextRegistry;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
setProvidedContextRegistry(currentRegistry => {
|
|
41
|
+
const nextRegistry = { ...currentRegistry };
|
|
42
|
+
|
|
43
|
+
delete nextRegistry[registrationId];
|
|
44
|
+
|
|
45
|
+
return nextRegistry;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}, [context, registrationId, setProvidedContextRegistry]);
|
|
49
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useAtom, useAtomValue } from "jotai";
|
|
4
|
+
import type {
|
|
5
|
+
ServiceInquiryUserContext,
|
|
6
|
+
UseServiceInquiryUserContextReturn,
|
|
7
|
+
} from "../types";
|
|
8
|
+
import {
|
|
9
|
+
serviceInquiryAdditionalUserContextAtom,
|
|
10
|
+
serviceInquiryRequestContextAtom,
|
|
11
|
+
} from "../jotai";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Service Inquiry Hook; request context 제어 Hook
|
|
15
|
+
* @hook
|
|
16
|
+
* @returns {UseServiceInquiryUserContextReturn} request context 및 추가 user_context 제어 함수
|
|
17
|
+
* @example
|
|
18
|
+
* const inquiryContext = useServiceInquiryUserContext();
|
|
19
|
+
*/
|
|
20
|
+
export function useServiceInquiryUserContext(): UseServiceInquiryUserContextReturn {
|
|
21
|
+
/** 1) form init — request context snapshot과 trigger 추가 context를 atom 기반으로 읽는다. */
|
|
22
|
+
const requestContext = useAtomValue(serviceInquiryRequestContextAtom);
|
|
23
|
+
const [additionalUserContext, setAdditionalUserContext] = useAtom(
|
|
24
|
+
serviceInquiryAdditionalUserContextAtom,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/** 2) submit/액션 — trigger별 추가 context를 append/reset 할 수 있게 연다. */
|
|
28
|
+
const setNextAdditionalUserContext: UseServiceInquiryUserContextReturn["setAdditionalUserContext"] =
|
|
29
|
+
nextUserContext => {
|
|
30
|
+
setAdditionalUserContext(nextUserContext);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const appendUserContext: UseServiceInquiryUserContextReturn["appendUserContext"] =
|
|
34
|
+
(nextUserContext?: ServiceInquiryUserContext | null) => {
|
|
35
|
+
if (!nextUserContext) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setAdditionalUserContext(currentUserContext => ({
|
|
40
|
+
...(currentUserContext ?? {}),
|
|
41
|
+
...nextUserContext,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const clearAdditionalUserContext: UseServiceInquiryUserContextReturn["clearAdditionalUserContext"] =
|
|
46
|
+
() => {
|
|
47
|
+
setAdditionalUserContext(null);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
requestContext,
|
|
52
|
+
additionalUserContext,
|
|
53
|
+
setAdditionalUserContext: setNextAdditionalUserContext,
|
|
54
|
+
appendUserContext,
|
|
55
|
+
clearAdditionalUserContext,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import "./index.scss";
|
|
2
2
|
import ServiceInquiryForm from "./components/Form";
|
|
3
3
|
import ServiceInquiryOpenButton from "./components/OpenButton";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useOpenServiceInquiry,
|
|
6
|
+
useProvideServiceInquiryContext,
|
|
7
|
+
useServiceInquiryUserContext,
|
|
8
|
+
} from "./hooks";
|
|
5
9
|
import { createServiceInquiryModal } from "./utils/modal-option";
|
|
6
10
|
|
|
7
11
|
/**
|
|
@@ -12,6 +16,7 @@ export const ServiceInquiry = {
|
|
|
12
16
|
Form: ServiceInquiryForm,
|
|
13
17
|
OpenButton: ServiceInquiryOpenButton,
|
|
14
18
|
useOpen: useOpenServiceInquiry,
|
|
19
|
+
useProvideContext: useProvideServiceInquiryContext,
|
|
15
20
|
useUserContext: useServiceInquiryUserContext,
|
|
16
21
|
createModal: createServiceInquiryModal,
|
|
17
22
|
};
|
|
@@ -20,6 +25,7 @@ export {
|
|
|
20
25
|
ServiceInquiryForm,
|
|
21
26
|
ServiceInquiryOpenButton,
|
|
22
27
|
useOpenServiceInquiry,
|
|
28
|
+
useProvideServiceInquiryContext,
|
|
23
29
|
useServiceInquiryUserContext,
|
|
24
30
|
createServiceInquiryModal,
|
|
25
31
|
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { atom } from "jotai";
|
|
4
|
+
import type {
|
|
5
|
+
ServiceInquiryRequestContext,
|
|
6
|
+
ServiceInquiryProvidedContext,
|
|
7
|
+
ServiceInquiryUserContext,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Service Inquiry State; 페이지별 등록 context registry
|
|
12
|
+
* @state
|
|
13
|
+
*/
|
|
14
|
+
export const serviceInquiryProvidedContextRegistryAtom = atom<
|
|
15
|
+
Record<string, ServiceInquiryProvidedContext>
|
|
16
|
+
>({});
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Service Inquiry State; trigger/interaction 추가 user_context
|
|
20
|
+
* @state
|
|
21
|
+
*/
|
|
22
|
+
export const serviceInquiryAdditionalUserContextAtom =
|
|
23
|
+
atom<ServiceInquiryUserContext | null>(null);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Service Inquiry State; registry 병합 context
|
|
27
|
+
* @state
|
|
28
|
+
*/
|
|
29
|
+
export const serviceInquiryProvidedContextAtom =
|
|
30
|
+
atom<ServiceInquiryProvidedContext>(get => {
|
|
31
|
+
const providedContexts = Object.values(
|
|
32
|
+
get(serviceInquiryProvidedContextRegistryAtom),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
labels: Array.from(
|
|
37
|
+
new Set(
|
|
38
|
+
providedContexts.flatMap(
|
|
39
|
+
providedContext => providedContext.labels ?? [],
|
|
40
|
+
),
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
pagePath:
|
|
44
|
+
[...providedContexts].reverse().find(providedContext => {
|
|
45
|
+
return (
|
|
46
|
+
typeof providedContext.pagePath === "string" &&
|
|
47
|
+
providedContext.pagePath.length > 0
|
|
48
|
+
);
|
|
49
|
+
})?.pagePath ?? "",
|
|
50
|
+
userContext: providedContexts.reduce<ServiceInquiryUserContext | null>(
|
|
51
|
+
(currentUserContext, providedContext) => {
|
|
52
|
+
if (!providedContext.userContext) {
|
|
53
|
+
return currentUserContext;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...(currentUserContext ?? {}),
|
|
58
|
+
...providedContext.userContext,
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Service Inquiry State; 최종 request context
|
|
68
|
+
* @state
|
|
69
|
+
*/
|
|
70
|
+
export const serviceInquiryRequestContextAtom =
|
|
71
|
+
atom<ServiceInquiryRequestContext>(get => {
|
|
72
|
+
const providedContext = get(serviceInquiryProvidedContextAtom);
|
|
73
|
+
const additionalUserContext = get(serviceInquiryAdditionalUserContextAtom);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
labels: providedContext.labels ?? [],
|
|
77
|
+
page_path:
|
|
78
|
+
providedContext.pagePath ||
|
|
79
|
+
(typeof window === "undefined" ? "" : window.location.pathname),
|
|
80
|
+
user_context:
|
|
81
|
+
providedContext.userContext || additionalUserContext
|
|
82
|
+
? {
|
|
83
|
+
...(providedContext.userContext ?? {}),
|
|
84
|
+
...(additionalUserContext ?? {}),
|
|
85
|
+
}
|
|
86
|
+
: null,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./context";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
.service-inquiry-open-button {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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-common-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
|
+
// }
|
|
@@ -4,47 +4,24 @@ import type {
|
|
|
4
4
|
} from "./form-context";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Service Inquiry Hook;
|
|
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 훅 옵션
|
|
7
|
+
* Service Inquiry Hook; 모듈 내부 공유 context 값
|
|
21
8
|
* @property {string[]} [labels] 문의 request에 포함할 labels
|
|
22
|
-
* @property {string} [pagePath]
|
|
23
|
-
* @property {
|
|
24
|
-
* @property {ServiceInquiryUserContext | null} [userContext] 서비스 기본 user_context
|
|
25
|
-
* @property {ServiceInquiryUserContextResolver} [resolveUserContext] 서비스 기본 user_context 동적 resolver
|
|
9
|
+
* @property {string} [pagePath] 문의를 연 페이지 경로
|
|
10
|
+
* @property {ServiceInquiryUserContext | null} [userContext] 페이지/폼이 제공하는 추가 user_context
|
|
26
11
|
*/
|
|
27
|
-
export interface
|
|
12
|
+
export interface ServiceInquiryProvidedContext {
|
|
28
13
|
/**
|
|
29
14
|
* 문의 request에 포함할 labels
|
|
30
15
|
*/
|
|
31
16
|
labels?: string[];
|
|
32
17
|
/**
|
|
33
|
-
*
|
|
18
|
+
* 문의를 연 페이지 경로
|
|
34
19
|
*/
|
|
35
20
|
pagePath?: string;
|
|
36
21
|
/**
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
39
|
-
resolvePagePath?: ServiceInquiryPagePathResolver;
|
|
40
|
-
/**
|
|
41
|
-
* 서비스 기본 user_context
|
|
22
|
+
* 페이지/폼이 제공하는 추가 user_context
|
|
42
23
|
*/
|
|
43
24
|
userContext?: ServiceInquiryUserContext | null;
|
|
44
|
-
/**
|
|
45
|
-
* 서비스 기본 user_context 동적 resolver
|
|
46
|
-
*/
|
|
47
|
-
resolveUserContext?: ServiceInquiryUserContextResolver;
|
|
48
25
|
}
|
|
49
26
|
|
|
50
27
|
/**
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { SubmitHandler } from "react-hook-form";
|
|
3
|
-
import type { InputProps, InputTextAreaProps } from "@uniai-fe/uds-primitives";
|
|
4
3
|
import type { DialogTemplateOptions } from "../../modal/types";
|
|
5
4
|
import type { ServiceInquiryFormValues } from "./form-context";
|
|
6
5
|
|
|
@@ -17,16 +16,11 @@ export type ServiceInquiryFieldMode = "editable" | "readonly";
|
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Service Inquiry Form; 공통 field 설정
|
|
20
|
-
* @property {string} [className] field wrapper className
|
|
21
19
|
* @property {ReactNode} [label] field label
|
|
22
20
|
* @property {ReactNode} [helper] field helper
|
|
23
21
|
* @property {boolean} [required] required 표시 여부
|
|
24
22
|
*/
|
|
25
23
|
export interface ServiceInquiryFieldBaseProps {
|
|
26
|
-
/**
|
|
27
|
-
* field wrapper className
|
|
28
|
-
*/
|
|
29
|
-
className?: string;
|
|
30
24
|
/**
|
|
31
25
|
* field label
|
|
32
26
|
*/
|
|
@@ -45,7 +39,6 @@ export interface ServiceInquiryFieldBaseProps {
|
|
|
45
39
|
* Service Inquiry Form; 단일 line input field 설정
|
|
46
40
|
* @property {"editable" | "readonly"} [mode] 서비스가 제어하는 field 입력 모드
|
|
47
41
|
* @property {string} [placeholder] input placeholder
|
|
48
|
-
* @property {InputProps} [inputProps] primitives Input.Base override
|
|
49
42
|
*/
|
|
50
43
|
export interface ServiceInquiryInputFieldProps extends ServiceInquiryFieldBaseProps {
|
|
51
44
|
/**
|
|
@@ -56,26 +49,17 @@ export interface ServiceInquiryInputFieldProps extends ServiceInquiryFieldBasePr
|
|
|
56
49
|
* input placeholder
|
|
57
50
|
*/
|
|
58
51
|
placeholder?: string;
|
|
59
|
-
/**
|
|
60
|
-
* primitives Input.Base override
|
|
61
|
-
*/
|
|
62
|
-
inputProps?: InputProps;
|
|
63
52
|
}
|
|
64
53
|
|
|
65
54
|
/**
|
|
66
55
|
* Service Inquiry Form; textarea field 설정
|
|
67
56
|
* @property {string} [placeholder] textarea placeholder
|
|
68
|
-
* @property {InputTextAreaProps} [inputProps] primitives Input.TextArea override
|
|
69
57
|
*/
|
|
70
58
|
export interface ServiceInquiryTextAreaFieldProps extends ServiceInquiryFieldBaseProps {
|
|
71
59
|
/**
|
|
72
60
|
* textarea placeholder
|
|
73
61
|
*/
|
|
74
62
|
placeholder?: string;
|
|
75
|
-
/**
|
|
76
|
-
* primitives Input.TextArea override
|
|
77
|
-
*/
|
|
78
|
-
inputProps?: InputTextAreaProps;
|
|
79
63
|
}
|
|
80
64
|
|
|
81
65
|
/**
|
|
@@ -160,12 +144,3 @@ export interface UseOpenServiceInquiryReturn {
|
|
|
160
144
|
*/
|
|
161
145
|
openServiceInquiry: () => void;
|
|
162
146
|
}
|
|
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 {}
|
|
@@ -1,89 +0,0 @@
|
|
|
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
|
-
}
|
|
File without changes
|