@uniai-fe/uds-templates 0.1.3 → 0.1.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/package.json +4 -4
- package/src/auth/common/find/hooks/useFindAccountForm.ts +2 -0
- package/src/auth/common/find/markup/CodeStep.tsx +2 -0
- package/src/auth/common/find/markup/InfoStep.tsx +2 -0
- package/src/auth/common/password/hooks/useCheckPassword.ts +2 -0
- package/src/auth/common/password/markup/PasswordSetField.tsx +2 -0
- package/src/auth/find-id/markup/StepComplete.tsx +3 -1
- package/src/auth/find-id/markup/StepIdentify.tsx +2 -0
- package/src/auth/find-id/markup/StepVerifyCode.tsx +2 -0
- package/src/auth/find-password/markup/StepResetPassword.tsx +2 -0
- package/src/auth/login/hooks/useAuthLoginForm.ts +2 -0
- package/src/auth/login/markup/FormField.tsx +2 -0
- package/src/auth/signup/hooks/useSignupAccountForm.ts +2 -0
- package/src/auth/signup/hooks/useSignupUserInfoForm.ts +2 -0
- package/src/auth/signup/hooks/useSignupVerificationForm.ts +2 -0
- package/src/auth/signup/markup/AccountForm.tsx +2 -0
- package/src/auth/signup/markup/UserInfoForm.tsx +2 -0
- package/src/auth/signup/markup/VerificationForm.tsx +109 -9
- package/src/auth/signup/types/props.ts +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/uds-templates",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "UNIAI Design System; UI Templates Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"publishConfig": {
|
|
13
13
|
"access": "public"
|
|
14
14
|
},
|
|
15
|
-
"packageManager": "pnpm@10.
|
|
15
|
+
"packageManager": "pnpm@10.27.0",
|
|
16
16
|
"engines": {
|
|
17
17
|
"node": ">=24",
|
|
18
18
|
"pnpm": ">=10"
|
|
@@ -73,9 +73,9 @@
|
|
|
73
73
|
"eslint": "^9.39.2",
|
|
74
74
|
"next": "^15.5.9",
|
|
75
75
|
"prettier": "^3.7.4",
|
|
76
|
-
"react-hook-form": "^7.
|
|
76
|
+
"react-hook-form": "^7.70.0",
|
|
77
77
|
"jotai": "^2.16.1",
|
|
78
|
-
"sass": "^1.97.
|
|
78
|
+
"sass": "^1.97.2",
|
|
79
79
|
"typescript": "~5.9.3"
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import clsx from "clsx";
|
|
2
4
|
import type { FindAccountIdCompleteProps } from "../types";
|
|
3
5
|
import AuthCompleteTemplate from "../../common/complete/Template";
|
|
@@ -5,7 +7,7 @@ import AuthCompleteTemplate from "../../common/complete/Template";
|
|
|
5
7
|
const DEFAULT_TITLE = "아이디 찾기 완료";
|
|
6
8
|
const DEFAULT_ID_LABEL = "아이디";
|
|
7
9
|
const DEFAULT_REGISTERED_LABEL = "가입일";
|
|
8
|
-
const DEFAULT_DESCRIPTION = "
|
|
10
|
+
const DEFAULT_DESCRIPTION = "로그인 페이지로 이동하여 로그인합니다.";
|
|
9
11
|
const DEFAULT_CTA_LABEL = "로그인하기";
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import { useMemo, useState } from "react";
|
|
2
4
|
import { useForm } from "react-hook-form";
|
|
3
5
|
import {
|
|
@@ -26,9 +28,38 @@ import { getSignupFieldDefaultValue } from "../utils/getSignupFieldDefaultValue"
|
|
|
26
28
|
import CheckAgreeIcon from "../img/check-agree.svg";
|
|
27
29
|
import ChevronOpenDetailIcon from "../img/chevron-open-detail.svg";
|
|
28
30
|
|
|
29
|
-
const
|
|
31
|
+
const INITIAL_AGREEMENT_LABEL = "동의하고 진행하기";
|
|
30
32
|
const REQUEST_CODE_LABEL = "인증코드 요청";
|
|
31
33
|
const RESEND_CODE_LABEL = "인증번호 재요청";
|
|
34
|
+
const COMPLETE_LABEL = "완료";
|
|
35
|
+
|
|
36
|
+
const clampCodeLength = (length: number) =>
|
|
37
|
+
Math.max(4, Math.min(8, length ?? 6));
|
|
38
|
+
|
|
39
|
+
const resolveCodeLength = (preferred?: number, fallback?: number): number => {
|
|
40
|
+
if (typeof preferred === "number" && Number.isFinite(preferred)) {
|
|
41
|
+
return clampCodeLength(preferred);
|
|
42
|
+
}
|
|
43
|
+
if (typeof fallback === "number" && Number.isFinite(fallback)) {
|
|
44
|
+
return clampCodeLength(fallback);
|
|
45
|
+
}
|
|
46
|
+
return clampCodeLength(6);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const resolveCodeValue = (
|
|
50
|
+
inputProps?: EmailInputProps["codeInputProps"],
|
|
51
|
+
): string => {
|
|
52
|
+
if (!inputProps) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
if (typeof inputProps.value === "string") {
|
|
56
|
+
return inputProps.value;
|
|
57
|
+
}
|
|
58
|
+
if (typeof inputProps.defaultValue === "string") {
|
|
59
|
+
return inputProps.defaultValue;
|
|
60
|
+
}
|
|
61
|
+
return "";
|
|
62
|
+
};
|
|
32
63
|
|
|
33
64
|
/**
|
|
34
65
|
* 회원가입 Step2; 약관 동의 + 이메일 인증
|
|
@@ -40,6 +71,8 @@ const RESEND_CODE_LABEL = "인증번호 재요청";
|
|
|
40
71
|
* @param {(options?: AuthSignupAgreementToggleAllOptions) => void} props.onToggleAll 전체 동의(필수 only) 토글
|
|
41
72
|
* @param {(agreementId: string) => void} [props.onOpenAgreementDetail] 약관 상세 보기
|
|
42
73
|
* @param {React.FormHTMLAttributes<HTMLFormElement>} [props.formAttr] form attr
|
|
74
|
+
* @param {AuthSignupVerificationProps["verificationState"]} [props.verificationState] 수동 verify state
|
|
75
|
+
* @param {boolean} [props.verificationReady] CTA 활성화 여부 override
|
|
43
76
|
* @param {import("react").ReactNode} [props.submitLabel] CTA 라벨
|
|
44
77
|
*/
|
|
45
78
|
export function AuthSignupVerificationForm({
|
|
@@ -51,6 +84,9 @@ export function AuthSignupVerificationForm({
|
|
|
51
84
|
onOpenAgreementDetail,
|
|
52
85
|
formAttr,
|
|
53
86
|
submitLabel,
|
|
87
|
+
submitDisabled,
|
|
88
|
+
verificationState,
|
|
89
|
+
verificationReady,
|
|
54
90
|
onSubmit,
|
|
55
91
|
}: AuthSignupVerificationProps) {
|
|
56
92
|
const [openedAgreementId, setOpenedAgreementId] = useState<string | null>(
|
|
@@ -137,12 +173,66 @@ export function AuthSignupVerificationForm({
|
|
|
137
173
|
requestButtonDisabled: undefined,
|
|
138
174
|
};
|
|
139
175
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
const codeVerificationMeta = useMemo(() => {
|
|
177
|
+
const value = resolveCodeValue(normalizedEmailFieldProps.codeInputProps);
|
|
178
|
+
const length = resolveCodeLength(
|
|
179
|
+
normalizedEmailFieldProps.codeLength,
|
|
180
|
+
normalizedEmailFieldProps.codeInputProps?.length,
|
|
181
|
+
);
|
|
182
|
+
const ready =
|
|
183
|
+
Boolean(normalizedEmailFieldProps.codeVisible) && value.length === length;
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
ready,
|
|
187
|
+
};
|
|
188
|
+
}, [
|
|
189
|
+
normalizedEmailFieldProps.codeInputProps,
|
|
190
|
+
normalizedEmailFieldProps.codeLength,
|
|
191
|
+
normalizedEmailFieldProps.codeVisible,
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
const isRequestStage = Boolean(emailRequestHandler) && !codeRequested;
|
|
195
|
+
const hasVerificationFlow = isRequestStage || codeRequested;
|
|
196
|
+
const requestReady = allRequiredChecked && !disabled;
|
|
197
|
+
const derivedVerificationReady = hasVerificationFlow
|
|
198
|
+
? codeRequested
|
|
199
|
+
? codeVerificationMeta.ready
|
|
200
|
+
: requestReady
|
|
201
|
+
: !disabled;
|
|
202
|
+
const resolvedVerificationReady =
|
|
203
|
+
typeof verificationReady === "boolean"
|
|
204
|
+
? verificationReady
|
|
205
|
+
: derivedVerificationReady;
|
|
206
|
+
const resolvedVerificationState =
|
|
207
|
+
verificationState ??
|
|
208
|
+
(() => {
|
|
209
|
+
if (!hasVerificationFlow) {
|
|
210
|
+
return "idle";
|
|
211
|
+
}
|
|
212
|
+
if (!codeRequested) {
|
|
213
|
+
if (!allRequiredChecked) {
|
|
214
|
+
return "agreements-pending";
|
|
215
|
+
}
|
|
216
|
+
return resolvedVerificationReady ? "request-ready" : "idle";
|
|
217
|
+
}
|
|
218
|
+
return resolvedVerificationReady ? "code-ready" : "code-pending";
|
|
219
|
+
})();
|
|
220
|
+
|
|
221
|
+
const derivedCtaLabel = (() => {
|
|
222
|
+
if (!hasVerificationFlow) {
|
|
223
|
+
return INITIAL_AGREEMENT_LABEL;
|
|
224
|
+
}
|
|
225
|
+
if (codeRequested) {
|
|
226
|
+
return COMPLETE_LABEL;
|
|
227
|
+
}
|
|
228
|
+
return resolvedVerificationReady
|
|
229
|
+
? REQUEST_CODE_LABEL
|
|
230
|
+
: INITIAL_AGREEMENT_LABEL;
|
|
231
|
+
})();
|
|
232
|
+
|
|
233
|
+
const ctaLabel = submitLabel ?? derivedCtaLabel;
|
|
234
|
+
const ctaDisabled =
|
|
235
|
+
disabled || Boolean(submitDisabled) || !resolvedVerificationReady;
|
|
146
236
|
|
|
147
237
|
const handleFormSubmit = (event: FormEvent<HTMLFormElement>) => {
|
|
148
238
|
formAttr?.onSubmit?.(event);
|
|
@@ -150,10 +240,18 @@ export function AuthSignupVerificationForm({
|
|
|
150
240
|
return;
|
|
151
241
|
}
|
|
152
242
|
|
|
153
|
-
if (
|
|
243
|
+
if (isRequestStage && emailRequestHandler) {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
event.stopPropagation();
|
|
246
|
+
if (resolvedVerificationReady) {
|
|
247
|
+
emailRequestHandler();
|
|
248
|
+
}
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (codeRequested && !resolvedVerificationReady) {
|
|
154
253
|
event.preventDefault();
|
|
155
254
|
event.stopPropagation();
|
|
156
|
-
emailRequestHandler();
|
|
157
255
|
return;
|
|
158
256
|
}
|
|
159
257
|
|
|
@@ -176,6 +274,8 @@ export function AuthSignupVerificationForm({
|
|
|
176
274
|
<form
|
|
177
275
|
className="auth-signup-form auth-signup-form--verification"
|
|
178
276
|
{...formAttr}
|
|
277
|
+
data-verify-state={resolvedVerificationState}
|
|
278
|
+
data-verify-ready={resolvedVerificationReady ? "true" : "false"}
|
|
179
279
|
onSubmit={handleFormSubmit}
|
|
180
280
|
>
|
|
181
281
|
<div className="auth-signup-fields">
|
|
@@ -51,6 +51,13 @@ export type AuthSignupVerificationFields = {
|
|
|
51
51
|
|
|
52
52
|
export type AuthSignupVerificationValues = Record<string, string>;
|
|
53
53
|
|
|
54
|
+
export type AuthSignupVerificationState =
|
|
55
|
+
| "idle"
|
|
56
|
+
| "agreements-pending"
|
|
57
|
+
| "request-ready"
|
|
58
|
+
| "code-pending"
|
|
59
|
+
| "code-ready";
|
|
60
|
+
|
|
54
61
|
export interface AuthSignupVerificationProps {
|
|
55
62
|
fields: AuthSignupVerificationFields;
|
|
56
63
|
agreements: AuthSignupAgreementOption[];
|
|
@@ -59,6 +66,9 @@ export interface AuthSignupVerificationProps {
|
|
|
59
66
|
onToggleAll: (options?: AuthSignupAgreementToggleAllOptions) => void;
|
|
60
67
|
onOpenAgreementDetail?: (agreementId: string) => void;
|
|
61
68
|
submitLabel?: ReactNode;
|
|
69
|
+
submitDisabled?: boolean;
|
|
70
|
+
verificationState?: AuthSignupVerificationState;
|
|
71
|
+
verificationReady?: boolean;
|
|
62
72
|
formAttr?: React.FormHTMLAttributes<HTMLFormElement>;
|
|
63
73
|
onSubmit: SubmitHandler<AuthSignupVerificationValues>;
|
|
64
74
|
}
|