@uniai-fe/uds-templates 0.4.7 → 0.4.8
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 +6 -5
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/service-inquiry/components/OpenButton.tsx +6 -3
- package/src/service-inquiry/hooks/index.ts +1 -0
- package/src/service-inquiry/hooks/useNetworkError.ts +46 -0
- package/src/service-inquiry/index.tsx +3 -0
- package/src/service-inquiry/jotai/context.ts +16 -1
- package/src/service-inquiry/styles/open-button.scss +1 -1
- package/src/service-inquiry/types/hooks.ts +52 -0
- package/src/service-inquiry/types/props.ts +12 -0
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
107
107
|
- ui-legacy 스택 기반 모달 Provider/Root/Container + 템플릿(`Modal.Alert`, `Modal.Dialog`)
|
|
108
108
|
- Storybook(`apps/design-storybook/src/stories/templates/modal`)에서 Alert/Confirm 케이스를 검증한다.
|
|
109
109
|
- `/service-inquiry/**`
|
|
110
|
-
- 문의 입력 전용 form, 기본 원형 `?` open button, 커스텀 trigger용 open hook, 페이지 context 등록 hook, request context 조립 hook, modal preset factory를 제공한다.
|
|
110
|
+
- 문의 입력 전용 form, 기본 원형 `?` open button, 커스텀 trigger용 open hook, 페이지 context 등록 hook, request context 조립 hook, 네트워크 오류 수집 hook, modal preset factory를 제공한다.
|
|
111
111
|
- submit transport, React Query mutation, Next.js route handler, 에러 피드백(`Modal.Alert`)은 서비스 앱이 소유한다.
|
|
112
112
|
- 모듈 내부 Jotai registry를 사용하므로, layout 고정 버튼 1개와 페이지별 context 등록 hook 조합으로 ready-to-use 구성이 가능하다.
|
|
113
113
|
- 로그인 후 `farm_name`, `contact`를 auto-fill + readonly로 보여야 할 때는 `formContextOptions.defaultValues`와 `farmNameField.mode`, `contactField.mode`를 함께 전달한다.
|
|
@@ -124,10 +124,11 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
|
|
|
124
124
|
|
|
125
125
|
1. 서비스 앱이 `react-hook-form`으로 `defaultValues`와 `onSubmit`을 준비한다.
|
|
126
126
|
2. layout 고정 버튼은 `ServiceInquiry.useUserContext()`로 모듈 내부 registry 기반 `requestContext`를 읽는다.
|
|
127
|
-
3.
|
|
128
|
-
4.
|
|
129
|
-
5.
|
|
130
|
-
6.
|
|
127
|
+
3. 서비스 앱은 네트워크 오류가 발생했을 때 `ServiceInquiry.useNetworkError().reportNetworkError(...)`만 호출하고, 모듈이 이를 `user_context.network_errors`에 자동 병합한다.
|
|
128
|
+
4. 각 페이지/폼은 `ServiceInquiry.useProvideContext({ labels, userContext })`로 `ServiceInquiryProvidedContext`를 등록한다.
|
|
129
|
+
5. 기본 버튼은 `ServiceInquiry.OpenButton`, 커스텀 버튼은 `ServiceInquiry.useOpen`으로 모달 open을 연결한다.
|
|
130
|
+
6. modal footer confirm이 `ServiceInquiry.Form` submit 진입을 담당한다.
|
|
131
|
+
7. 실제 submit은 서비스 앱의 `useMutation + Next.js route handler + Modal.Alert` 조합으로 처리한다.
|
|
131
132
|
|
|
132
133
|
`service-inquiry`는 구조와 request context까지만 제공하고, 네트워크 상태/재시도/성공·실패 피드백은 서비스 앱이 소유합니다.
|
|
133
134
|
|
package/dist/styles.css
CHANGED
package/package.json
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import { Button } from "@uniai-fe/uds-primitives";
|
|
4
4
|
import { useOpenServiceInquiry } from "../hooks";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ServiceInquiryOpenButtonProps } from "../types";
|
|
6
|
+
import clsx from "clsx";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Service Inquiry Open Button; 문의 모달 trigger adapter
|
|
9
10
|
* @component
|
|
10
11
|
* @param {UseOpenServiceInquiryOptions} props 문의 모달 열기 props
|
|
12
|
+
* @param {string} [props.className]
|
|
11
13
|
* @param {string} props.stackKey modal stack key
|
|
12
14
|
* @param {ServiceInquiryFormProps} props.formProps 문의 form props
|
|
13
15
|
* @param {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [props.dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
@@ -19,11 +21,12 @@ import type { UseOpenServiceInquiryOptions } from "../types";
|
|
|
19
21
|
* />
|
|
20
22
|
*/
|
|
21
23
|
const ServiceInquiryOpenButton = ({
|
|
24
|
+
className,
|
|
22
25
|
stackKey,
|
|
23
26
|
formProps,
|
|
24
27
|
dialogOptions,
|
|
25
28
|
onOpen,
|
|
26
|
-
}:
|
|
29
|
+
}: ServiceInquiryOpenButtonProps) => {
|
|
27
30
|
const { openServiceInquiry } = useOpenServiceInquiry({
|
|
28
31
|
stackKey,
|
|
29
32
|
formProps,
|
|
@@ -33,7 +36,7 @@ const ServiceInquiryOpenButton = ({
|
|
|
33
36
|
|
|
34
37
|
return (
|
|
35
38
|
<Button.Rounded
|
|
36
|
-
className="service-inquiry-open-button"
|
|
39
|
+
className={clsx("service-inquiry-open-button", className)}
|
|
37
40
|
priority="tertiary"
|
|
38
41
|
size="large"
|
|
39
42
|
// 변경 설명: 기본 제공 버튼은 고정 원형 `?` 버튼 사양으로 렌더링한다.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useAtom } from "jotai";
|
|
4
|
+
import { serviceInquiryNetworkErrorsAtom } from "../jotai";
|
|
5
|
+
import type {
|
|
6
|
+
ServiceInquiryNetworkError,
|
|
7
|
+
UseServiceInquiryNetworkErrorReturn,
|
|
8
|
+
} from "../types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Service Inquiry Hook; 네트워크 오류 수집 Hook
|
|
12
|
+
* @hook
|
|
13
|
+
* @returns {UseServiceInquiryNetworkErrorReturn} 최근 오류 목록과 기록/초기화 함수
|
|
14
|
+
* @example
|
|
15
|
+
* const { reportNetworkError } = useServiceInquiryNetworkError();
|
|
16
|
+
* reportNetworkError({ route: "/api/v2/login", message: "timeout" });
|
|
17
|
+
*/
|
|
18
|
+
export function useServiceInquiryNetworkError(): UseServiceInquiryNetworkErrorReturn {
|
|
19
|
+
const [networkErrors, setNetworkErrors] = useAtom(
|
|
20
|
+
serviceInquiryNetworkErrorsAtom,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const reportNetworkError: UseServiceInquiryNetworkErrorReturn["reportNetworkError"] =
|
|
24
|
+
(nextError: ServiceInquiryNetworkError) => {
|
|
25
|
+
setNetworkErrors(currentErrors =>
|
|
26
|
+
[
|
|
27
|
+
{
|
|
28
|
+
...nextError,
|
|
29
|
+
timestamp: nextError.timestamp ?? new Date().toISOString(),
|
|
30
|
+
},
|
|
31
|
+
...currentErrors,
|
|
32
|
+
].slice(0, 5),
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const clearNetworkErrors: UseServiceInquiryNetworkErrorReturn["clearNetworkErrors"] =
|
|
37
|
+
() => {
|
|
38
|
+
setNetworkErrors([]);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
networkErrors,
|
|
43
|
+
reportNetworkError,
|
|
44
|
+
clearNetworkErrors,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -2,6 +2,7 @@ import "./index.scss";
|
|
|
2
2
|
import ServiceInquiryForm from "./components/Form";
|
|
3
3
|
import ServiceInquiryOpenButton from "./components/OpenButton";
|
|
4
4
|
import {
|
|
5
|
+
useServiceInquiryNetworkError,
|
|
5
6
|
useOpenServiceInquiry,
|
|
6
7
|
useProvideServiceInquiryContext,
|
|
7
8
|
useServiceInquiryUserContext,
|
|
@@ -16,6 +17,7 @@ export const ServiceInquiry = {
|
|
|
16
17
|
Form: ServiceInquiryForm,
|
|
17
18
|
OpenButton: ServiceInquiryOpenButton,
|
|
18
19
|
useOpen: useOpenServiceInquiry,
|
|
20
|
+
useNetworkError: useServiceInquiryNetworkError,
|
|
19
21
|
useProvideContext: useProvideServiceInquiryContext,
|
|
20
22
|
useUserContext: useServiceInquiryUserContext,
|
|
21
23
|
createModal: createServiceInquiryModal,
|
|
@@ -24,6 +26,7 @@ export const ServiceInquiry = {
|
|
|
24
26
|
export {
|
|
25
27
|
ServiceInquiryForm,
|
|
26
28
|
ServiceInquiryOpenButton,
|
|
29
|
+
useServiceInquiryNetworkError,
|
|
27
30
|
useOpenServiceInquiry,
|
|
28
31
|
useProvideServiceInquiryContext,
|
|
29
32
|
useServiceInquiryUserContext,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { atom } from "jotai";
|
|
4
4
|
import type {
|
|
5
|
+
ServiceInquiryNetworkError,
|
|
5
6
|
ServiceInquiryRequestContext,
|
|
6
7
|
ServiceInquiryProvidedContext,
|
|
7
8
|
ServiceInquiryUserContext,
|
|
@@ -22,6 +23,14 @@ export const serviceInquiryProvidedContextRegistryAtom = atom<
|
|
|
22
23
|
export const serviceInquiryAdditionalUserContextAtom =
|
|
23
24
|
atom<ServiceInquiryUserContext | null>(null);
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Service Inquiry State; 최근 네트워크 오류 목록
|
|
28
|
+
* @state
|
|
29
|
+
*/
|
|
30
|
+
export const serviceInquiryNetworkErrorsAtom = atom<
|
|
31
|
+
ServiceInquiryNetworkError[]
|
|
32
|
+
>([]);
|
|
33
|
+
|
|
25
34
|
/**
|
|
26
35
|
* Service Inquiry State; registry 병합 context
|
|
27
36
|
* @state
|
|
@@ -64,16 +73,22 @@ export const serviceInquiryRequestContextAtom =
|
|
|
64
73
|
atom<ServiceInquiryRequestContext>(get => {
|
|
65
74
|
const providedContext = get(serviceInquiryProvidedContextAtom);
|
|
66
75
|
const additionalUserContext = get(serviceInquiryAdditionalUserContextAtom);
|
|
76
|
+
const networkErrors = get(serviceInquiryNetworkErrorsAtom);
|
|
67
77
|
|
|
68
78
|
return {
|
|
69
79
|
labels: providedContext.labels ?? [],
|
|
70
80
|
// 변경 설명: page_path는 서비스 입력값이 아니라 모듈이 현재 페이지 URL 전체를 자동 수집하는 시스템 필드로 고정한다.
|
|
71
81
|
page_path: typeof window === "undefined" ? "" : window.location.href,
|
|
72
82
|
user_context:
|
|
73
|
-
providedContext.userContext ||
|
|
83
|
+
providedContext.userContext ||
|
|
84
|
+
additionalUserContext ||
|
|
85
|
+
networkErrors.length > 0
|
|
74
86
|
? {
|
|
75
87
|
...(providedContext.userContext ?? {}),
|
|
76
88
|
...(additionalUserContext ?? {}),
|
|
89
|
+
...(networkErrors.length > 0
|
|
90
|
+
? { network_errors: networkErrors }
|
|
91
|
+
: {}),
|
|
77
92
|
}
|
|
78
93
|
: null,
|
|
79
94
|
};
|
|
@@ -19,6 +19,58 @@ export interface ServiceInquiryProvidedContext {
|
|
|
19
19
|
userContext?: ServiceInquiryUserContext | null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Service Inquiry Hook; 네트워크 오류 기록
|
|
24
|
+
* @property {string} [route] 요청 route 또는 endpoint
|
|
25
|
+
* @property {number} [code] HTTP status code
|
|
26
|
+
* @property {string} [state] 서비스 레이어 상태 문자열
|
|
27
|
+
* @property {string} [message] 사용자/운영 확인용 오류 메시지
|
|
28
|
+
* @property {string} [timestamp] 오류 기록 시각
|
|
29
|
+
*/
|
|
30
|
+
export interface ServiceInquiryNetworkError {
|
|
31
|
+
/**
|
|
32
|
+
* 요청 route 또는 endpoint
|
|
33
|
+
*/
|
|
34
|
+
route?: string;
|
|
35
|
+
/**
|
|
36
|
+
* HTTP status code
|
|
37
|
+
*/
|
|
38
|
+
code?: number;
|
|
39
|
+
/**
|
|
40
|
+
* 서비스 레이어 상태 문자열
|
|
41
|
+
*/
|
|
42
|
+
state?: string;
|
|
43
|
+
/**
|
|
44
|
+
* 사용자/운영 확인용 오류 메시지
|
|
45
|
+
*/
|
|
46
|
+
message?: string;
|
|
47
|
+
/**
|
|
48
|
+
* 오류 기록 시각
|
|
49
|
+
*/
|
|
50
|
+
timestamp?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Service Inquiry Hook; 네트워크 오류 수집 훅 반환값
|
|
55
|
+
* @property {ServiceInquiryNetworkError[]} networkErrors 누적된 최근 네트워크 오류 목록
|
|
56
|
+
* @property {(nextError: ServiceInquiryNetworkError) => void} reportNetworkError 네트워크 오류 1건 기록
|
|
57
|
+
* @property {() => void} clearNetworkErrors 누적된 네트워크 오류 초기화
|
|
58
|
+
*/
|
|
59
|
+
export interface UseServiceInquiryNetworkErrorReturn {
|
|
60
|
+
/**
|
|
61
|
+
* 누적된 최근 네트워크 오류 목록
|
|
62
|
+
*/
|
|
63
|
+
networkErrors: ServiceInquiryNetworkError[];
|
|
64
|
+
/**
|
|
65
|
+
* 네트워크 오류 1건 기록
|
|
66
|
+
*/
|
|
67
|
+
reportNetworkError: (nextError: ServiceInquiryNetworkError) => void;
|
|
68
|
+
/**
|
|
69
|
+
* 누적된 네트워크 오류 초기화
|
|
70
|
+
*/
|
|
71
|
+
clearNetworkErrors: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
22
74
|
/**
|
|
23
75
|
* Service Inquiry Hook; user_context 훅 반환값
|
|
24
76
|
* @property {ServiceInquiryRequestContext} requestContext form submit에 바로 사용할 request context
|
|
@@ -134,6 +134,18 @@ export interface UseOpenServiceInquiryOptions extends ServiceInquiryCreateModalO
|
|
|
134
134
|
onOpen?: () => void;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Service Inquiry Button props; 버튼 옵션
|
|
139
|
+
* @property {string} [className]
|
|
140
|
+
* @property {string} stackKey modal stack key
|
|
141
|
+
* @property {ServiceInquiryFormProps} formProps 문의 form props
|
|
142
|
+
* @property {Partial<DialogTemplateOptions<ServiceInquiryFormValues>>} [dialogOptions] 문의 모달 preset 위에 덮어쓸 dialog option
|
|
143
|
+
* @property {() => void} [onOpen] 모달 open 직전 콜백
|
|
144
|
+
*/
|
|
145
|
+
export interface ServiceInquiryOpenButtonProps extends UseOpenServiceInquiryOptions {
|
|
146
|
+
className?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
137
149
|
/**
|
|
138
150
|
* Service Inquiry Hook; 문의 모달 열기 훅 반환값
|
|
139
151
|
* @property {() => void} openServiceInquiry 문의 모달 open 함수
|