@uniai-fe/uds-templates 0.4.3 → 0.4.4

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 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. 필요하면 `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` 조합으로 처리한다.
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-templates",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "UNIAI Design System; UI Templates Package",
5
5
  "type": "module",
6
6
  "private": false,
@@ -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={farmNameField?.inputProps?.width ?? "full"}
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={farmNameField?.inputProps?.block ?? true}
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={contactField?.inputProps?.width ?? "full"}
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={contactField?.inputProps?.block ?? true}
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={textField?.inputProps?.width ?? "full"}
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={textField?.inputProps?.block ?? true}
130
+ block={true}
142
131
  placeholder={
143
132
  textField?.placeholder ?? "문의 내용을 자세히 입력해 주세요."
144
133
  }
145
- height={textField?.inputProps?.height ?? 160}
146
- length={textField?.inputProps?.length ?? 10000}
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,12 @@
1
1
  "use client";
2
2
 
3
3
  import { useOpenServiceInquiry } from "../hooks";
4
- import type { ServiceInquiryOpenButtonProps } from "../types";
4
+ import type { UseOpenServiceInquiryOptions } from "../types";
5
5
 
6
6
  /**
7
7
  * Service Inquiry Open Button; 문의 모달 trigger adapter
8
8
  * @component
9
- * @param {ServiceInquiryOpenButtonProps} props 문의 모달 열기 props
9
+ * @param {UseOpenServiceInquiryOptions} props 문의 모달 열기 props
10
10
  * @param {string} props.stackKey modal stack key
11
11
  * @param {ServiceInquiryFormProps} props.formProps 문의 form props
12
12
  * @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [props.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
@@ -22,7 +22,7 @@ const ServiceInquiryOpenButton = ({
22
22
  formProps,
23
23
  dialogOptions,
24
24
  onOpen,
25
- }: ServiceInquiryOpenButtonProps) => {
25
+ }: UseOpenServiceInquiryOptions) => {
26
26
  const { openServiceInquiry } = useOpenServiceInquiry({
27
27
  stackKey,
28
28
  formProps,
@@ -1,2 +1,3 @@
1
- export * from "./useOpenServiceInquiry";
2
- export * from "./useServiceInquiryUserContext";
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 { useOpenServiceInquiry, useServiceInquiryUserContext } from "./hooks";
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";
@@ -4,47 +4,24 @@ import type {
4
4
  } from "./form-context";
5
5
 
6
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 훅 옵션
7
+ * Service Inquiry Hook; 모듈 내부 공유 context 값
21
8
  * @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
9
+ * @property {string} [pagePath] 문의를 연 페이지 경로
10
+ * @property {ServiceInquiryUserContext | null} [userContext] 페이지/폼이 제공하는 추가 user_context
26
11
  */
27
- export interface UseServiceInquiryUserContextOptions {
12
+ export interface ServiceInquiryProvidedContext {
28
13
  /**
29
14
  * 문의 request에 포함할 labels
30
15
  */
31
16
  labels?: string[];
32
17
  /**
33
- * 고정 page_path
18
+ * 문의를 연 페이지 경로
34
19
  */
35
20
  pagePath?: string;
36
21
  /**
37
- * page_path 동적 resolver
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
- }