@uniai-fe/uds-templates 0.0.11 → 0.0.13
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 +11 -0
- package/dist/styles.css +916 -1074
- package/package.json +3 -3
- package/src/auth/common/complete/Template.tsx +47 -0
- package/src/auth/common/complete/img/circle-check-complete.svg +4 -0
- package/src/auth/common/complete/index.scss +38 -0
- package/src/auth/common/complete/types.ts +15 -0
- package/src/auth/common/container/header/StageHeader.tsx +61 -0
- package/src/auth/common/container/header/index.tsx +5 -0
- package/src/auth/common/container/header/stage-header.scss +50 -0
- package/src/{components/auth → auth/common}/container/index.tsx +2 -0
- package/src/auth/common/find/hooks/useFindAccountForm.ts +79 -0
- package/src/auth/common/find/markup/CodeStep.tsx +166 -0
- package/src/auth/common/find/markup/Header.tsx +46 -0
- package/src/auth/common/find/markup/InfoStep.tsx +109 -0
- package/src/auth/common/find/styles/email.scss +55 -0
- package/src/auth/common/find/styles/find-account.scss +4 -0
- package/src/auth/common/find/styles/layout.scss +19 -0
- package/src/auth/common/find/styles/password.scss +39 -0
- package/src/auth/common/find/styles/result.scss +78 -0
- package/src/auth/common/find/types/forms.ts +30 -0
- package/src/auth/common/find/types/index.ts +121 -0
- package/src/auth/common/find/utils/composeFieldProps.ts +45 -0
- package/src/auth/common/password/constants.ts +19 -0
- package/src/auth/common/password/hooks/useCheckPassword.ts +133 -0
- package/src/auth/common/password/img/check-password.svg +3 -0
- package/src/auth/common/password/markup/PasswordSetField.tsx +250 -0
- package/src/auth/common/password/styles/password-set-field.scss +49 -0
- package/src/auth/common/password/types.ts +142 -0
- package/src/auth/common/password/utils/composePasswordFieldProps.ts +44 -0
- package/src/auth/find-account.ts +28 -0
- package/src/auth/find-id/hooks/index.ts +1 -0
- package/src/auth/find-id/index.scss +1 -0
- package/src/auth/find-id/index.ts +23 -0
- package/src/auth/find-id/markup/StepComplete.tsx +58 -0
- package/src/auth/find-id/markup/StepIdentify.tsx +46 -0
- package/src/auth/find-id/markup/StepVerifyCode.tsx +48 -0
- package/src/auth/find-id/types/index.ts +66 -0
- package/src/auth/find-password/index.scss +1 -0
- package/src/auth/find-password/index.ts +30 -0
- package/src/auth/find-password/markup/StepComplete.tsx +30 -0
- package/src/auth/find-password/markup/StepIdentify.tsx +45 -0
- package/src/auth/find-password/markup/StepResetPassword.tsx +150 -0
- package/src/auth/find-password/markup/StepVerifyCode.tsx +48 -0
- package/src/auth/index.tsx +41 -0
- package/src/{components/auth → auth}/login/markup/Container.tsx +1 -1
- package/src/{components/auth → auth}/login/types/props.ts +1 -1
- package/src/{components/auth → auth}/signup/hooks/useSignupAccountForm.ts +26 -2
- package/src/{components/auth → auth}/signup/hooks/useSignupUserInfoForm.ts +10 -3
- package/src/auth/signup/img/check-agree.svg +3 -0
- package/src/auth/signup/img/chevron-open-detail.svg +3 -0
- package/src/{components/auth → auth}/signup/index.ts +3 -0
- package/src/auth/signup/markup/AccountForm.tsx +113 -0
- package/src/auth/signup/markup/Complete.tsx +59 -0
- package/src/auth/signup/markup/Template.tsx +110 -0
- package/src/{components/auth → auth}/signup/markup/UserInfoForm.tsx +23 -13
- package/src/auth/signup/markup/VerificationForm.tsx +285 -0
- package/src/{components/auth → auth}/signup/markup/index.ts +1 -0
- package/src/auth/signup/styles/signup.scss +187 -0
- package/src/{components/auth → auth}/signup/types/hooks.ts +1 -0
- package/src/{components/auth → auth}/signup/types/props.ts +49 -9
- package/src/auth/signup/utils/getSignupFieldDefaultValue.ts +40 -0
- package/src/index.scss +5 -4
- package/src/index.tsx +3 -3
- package/src/page-frame/mobile/header/PageFrameMobileHeader.tsx +52 -0
- package/src/page-frame/mobile/header/index.ts +4 -0
- package/src/page-frame/mobile/header/page-frame-mobile-header.scss +48 -0
- package/src/page-frame/mobile/img/chevron-backward.svg +3 -0
- package/src/components/auth/index.tsx +0 -20
- package/src/components/auth/signup/markup/AccountForm.tsx +0 -124
- package/src/components/auth/signup/markup/Complete.tsx +0 -61
- package/src/components/auth/signup/markup/VerificationForm.tsx +0 -155
- package/src/components/auth/signup/styles/signup.scss +0 -135
- /package/src/{components/auth → auth/common}/container/AuthContainer.tsx +0 -0
- /package/src/{components/auth → auth/common}/container/index.scss +0 -0
- /package/src/{components/auth → auth/common}/container/types.ts +0 -0
- /package/src/{components/auth → auth}/login/data/valid-options.ts +0 -0
- /package/src/{components/auth → auth}/login/hooks/index.ts +0 -0
- /package/src/{components/auth → auth}/login/hooks/useAuthLoginForm.ts +0 -0
- /package/src/{components/auth → auth}/login/index.scss +0 -0
- /package/src/{components/auth → auth}/login/index.tsx +0 -0
- /package/src/{components/auth → auth}/login/markup/FormField.tsx +0 -0
- /package/src/{components/auth → auth}/login/markup/LinkButtons.tsx +0 -0
- /package/src/{components/auth → auth}/login/styles/login.scss +0 -0
- /package/src/{components/auth → auth}/login/types/form.ts +0 -0
- /package/src/{components/auth → auth}/login/types/hooks.ts +0 -0
- /package/src/{components/auth → auth}/login/types.ts +0 -0
- /package/src/{components/auth → auth}/signup/hooks/index.ts +0 -0
- /package/src/{components/auth → auth}/signup/hooks/useSignupVerificationForm.ts +0 -0
- /package/src/{components/auth → auth}/signup/types/index.ts +0 -0
- /package/src/{components/auth → auth}/signup/utils/composeFieldProps.ts +0 -0
- /package/src/{components/modal → modal}/core/components/Container.tsx +0 -0
- /package/src/{components/modal → modal}/core/components/FooterButtons.tsx +0 -0
- /package/src/{components/modal → modal}/core/components/Provider.tsx +0 -0
- /package/src/{components/modal → modal}/core/components/Root.tsx +0 -0
- /package/src/{components/modal → modal}/core/hooks/useModal.ts +0 -0
- /package/src/{components/modal → modal}/core/jotai/atoms.ts +0 -0
- /package/src/{components/modal → modal}/index.scss +0 -0
- /package/src/{components/modal → modal}/index.tsx +0 -0
- /package/src/{components/modal → modal}/styles/animations.scss +0 -0
- /package/src/{components/modal → modal}/styles/base.scss +0 -0
- /package/src/{components/modal → modal}/styles/container.scss +0 -0
- /package/src/{components/modal → modal}/styles/dimmer.scss +0 -0
- /package/src/{components/modal → modal}/templates/Alert.tsx +0 -0
- /package/src/{components/modal → modal}/templates/Dialog.tsx +0 -0
- /package/src/{components/modal → modal}/types/footer.ts +0 -0
- /package/src/{components/modal → modal}/types/index.ts +0 -0
- /package/src/{components/modal → modal}/types/options.ts +0 -0
- /package/src/{components/modal → modal}/types/state.ts +0 -0
- /package/src/{components/modal → modal}/types/templates.ts +0 -0
- /package/src/{components/page-frame → page-frame}/container/PageFrameContainer.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/container/index.scss +0 -0
- /package/src/{components/page-frame → page-frame}/container/index.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/container/types.ts +0 -0
- /package/src/{components/page-frame → page-frame}/index.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/mobile/PageFrameMobile.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/mobile/index.scss +0 -0
- /package/src/{components/page-frame → page-frame}/mobile/index.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/mobile/types.ts +0 -0
- /package/src/{components/page-frame → page-frame}/navigation/PageFrameNavigation.tsx +0 -0
- /package/src/{components/page-frame → page-frame}/navigation/index.scss +0 -0
- /package/src/{components/page-frame → page-frame}/navigation/index.tsx +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import type { AuthContainerProps } from "../../common/container";
|
|
3
|
+
import type { SubmitHandler } from "react-hook-form";
|
|
4
|
+
import type {
|
|
5
|
+
InputFieldProps,
|
|
6
|
+
InputPasswordProps,
|
|
7
|
+
} from "@uniai-fe/uds-primitives";
|
|
8
|
+
import type { FindAccountCTAProps } from "../../common/find/types";
|
|
9
|
+
import type { AuthPasswordRule } from "../../common/password/types";
|
|
10
|
+
|
|
11
|
+
export type * from "../../common/find/types";
|
|
12
|
+
|
|
13
|
+
export type FindAccountIdSummaryProps = {
|
|
14
|
+
label?: React.ReactNode;
|
|
15
|
+
userId: React.ReactNode;
|
|
16
|
+
userIdLabel?: React.ReactNode;
|
|
17
|
+
registeredAt?: React.ReactNode;
|
|
18
|
+
registeredAtLabel?: React.ReactNode;
|
|
19
|
+
helper?: React.ReactNode;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type FindAccountIdCompleteProps = Omit<
|
|
23
|
+
AuthContainerProps,
|
|
24
|
+
"children"
|
|
25
|
+
> & {
|
|
26
|
+
title?: React.ReactNode;
|
|
27
|
+
summary: FindAccountIdSummaryProps;
|
|
28
|
+
description?: React.ReactNode;
|
|
29
|
+
cta?: FindAccountCTAProps;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type FindAccountPasswordValues = Record<string, string>;
|
|
33
|
+
|
|
34
|
+
export type FindAccountPasswordFields = {
|
|
35
|
+
password: InputFieldProps<InputPasswordProps>;
|
|
36
|
+
confirm: InputFieldProps<InputPasswordProps>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type FindAccountPasswordFieldOptions<
|
|
40
|
+
TFields extends FindAccountPasswordFields = FindAccountPasswordFields,
|
|
41
|
+
> = {
|
|
42
|
+
fields: TFields;
|
|
43
|
+
formAttr?: React.FormHTMLAttributes<HTMLFormElement>;
|
|
44
|
+
onSubmit: SubmitHandler<FindAccountPasswordValues>;
|
|
45
|
+
isSubmittable?: (values?: FindAccountPasswordValues) => boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type FindAccountPasswordRule = AuthPasswordRule;
|
|
49
|
+
|
|
50
|
+
export type FindAccountPasswordFormProps<
|
|
51
|
+
TFields extends FindAccountPasswordFields = FindAccountPasswordFields,
|
|
52
|
+
> = Omit<AuthContainerProps, "children"> & {
|
|
53
|
+
fieldOptions: FindAccountPasswordFieldOptions<TFields>;
|
|
54
|
+
rules?: FindAccountPasswordRule[];
|
|
55
|
+
helper?: React.ReactNode;
|
|
56
|
+
cta?: FindAccountCTAProps;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type FindAccountPasswordCompleteProps = Omit<
|
|
60
|
+
AuthContainerProps,
|
|
61
|
+
"children"
|
|
62
|
+
> & {
|
|
63
|
+
title?: React.ReactNode;
|
|
64
|
+
description?: React.ReactNode;
|
|
65
|
+
cta?: FindAccountCTAProps;
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@use "../common/find/styles/find-account.scss";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./index.scss";
|
|
2
|
+
import FindPasswordStepIdentify from "./markup/StepIdentify";
|
|
3
|
+
import FindPasswordStepVerifyCode from "./markup/StepVerifyCode";
|
|
4
|
+
import FindPasswordStepReset from "./markup/StepResetPassword";
|
|
5
|
+
import FindPasswordStepComplete from "./markup/StepComplete";
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
FindAccountPasswordFormProps,
|
|
9
|
+
FindAccountPasswordValues,
|
|
10
|
+
FindAccountPasswordCompleteProps,
|
|
11
|
+
} from "../find-id/types";
|
|
12
|
+
|
|
13
|
+
export const FindAccountPasswordForm = FindPasswordStepReset;
|
|
14
|
+
export const FindAccountPasswordComplete = FindPasswordStepComplete;
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
FindPasswordStepIdentify,
|
|
18
|
+
FindPasswordStepVerifyCode,
|
|
19
|
+
FindPasswordStepReset,
|
|
20
|
+
FindPasswordStepComplete,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const FindPassword = {
|
|
24
|
+
StepIdentify: FindPasswordStepIdentify,
|
|
25
|
+
StepVerifyCode: FindPasswordStepVerifyCode,
|
|
26
|
+
StepReset: FindPasswordStepReset,
|
|
27
|
+
StepComplete: FindPasswordStepComplete,
|
|
28
|
+
Form: FindAccountPasswordForm,
|
|
29
|
+
Complete: FindAccountPasswordComplete,
|
|
30
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import type { FindAccountPasswordCompleteProps } from "../../find-id/types";
|
|
3
|
+
import AuthCompleteTemplate from "../../common/complete/Template";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_TITLE = "비밀번호 변경 완료";
|
|
6
|
+
const DEFAULT_DESCRIPTION = "로그인 페이지로 이동하여 로그인해 주세요.";
|
|
7
|
+
const DEFAULT_CTA_LABEL = "로그인하기";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 비밀번호 변경 완료 화면
|
|
11
|
+
* @component
|
|
12
|
+
*/
|
|
13
|
+
export default function FindPasswordStepComplete({
|
|
14
|
+
className,
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
cta,
|
|
18
|
+
}: FindAccountPasswordCompleteProps) {
|
|
19
|
+
return (
|
|
20
|
+
<AuthCompleteTemplate
|
|
21
|
+
className={clsx("auth-find-account-container", className)}
|
|
22
|
+
title={title ?? DEFAULT_TITLE}
|
|
23
|
+
description={description ?? DEFAULT_DESCRIPTION}
|
|
24
|
+
cta={{
|
|
25
|
+
label: cta?.label ?? DEFAULT_CTA_LABEL,
|
|
26
|
+
buttonProps: cta?.buttonProps,
|
|
27
|
+
}}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import FindAccountInfoStep from "../../common/find/markup/InfoStep";
|
|
2
|
+
import type { FindAccountInfoStepProps } from "../../common/find/types";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_NAVIGATION = {
|
|
5
|
+
title: "비밀번호 찾기",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const DEFAULT_HEADLINE = {
|
|
9
|
+
progress: { total: 3, current: 1 },
|
|
10
|
+
title: (
|
|
11
|
+
<>
|
|
12
|
+
가입한 이름과 메일 주소를
|
|
13
|
+
<br />
|
|
14
|
+
입력해 주세요
|
|
15
|
+
</>
|
|
16
|
+
),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const DEFAULT_CTA_LABEL = "인증코드 요청";
|
|
20
|
+
|
|
21
|
+
export type FindPasswordStepIdentifyProps = FindAccountInfoStepProps;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Find Password Step1 — 이름/메일 입력
|
|
25
|
+
* @component
|
|
26
|
+
*/
|
|
27
|
+
export default function FindPasswordStepIdentify({
|
|
28
|
+
navigation,
|
|
29
|
+
headline,
|
|
30
|
+
cta,
|
|
31
|
+
...rest
|
|
32
|
+
}: FindPasswordStepIdentifyProps) {
|
|
33
|
+
const resolvedNavigation = navigation ?? DEFAULT_NAVIGATION;
|
|
34
|
+
const resolvedHeadline = headline ?? DEFAULT_HEADLINE;
|
|
35
|
+
const resolvedCTA = cta ?? { label: DEFAULT_CTA_LABEL };
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<FindAccountInfoStep
|
|
39
|
+
{...rest}
|
|
40
|
+
navigation={resolvedNavigation}
|
|
41
|
+
headline={resolvedHeadline}
|
|
42
|
+
cta={resolvedCTA}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { FormProvider, useForm } from "react-hook-form";
|
|
4
|
+
import { AuthContainer } from "../../common/container";
|
|
5
|
+
import { AuthStageHeader } from "../../common/container/header";
|
|
6
|
+
import { Button, type InputPasswordProps } from "@uniai-fe/uds-primitives";
|
|
7
|
+
import AuthPasswordSetField from "../../common/password/markup/PasswordSetField";
|
|
8
|
+
import { DEFAULT_PASSWORD_RULES } from "../../common/password/constants";
|
|
9
|
+
import type {
|
|
10
|
+
FindAccountPasswordFormProps,
|
|
11
|
+
FindAccountPasswordValues,
|
|
12
|
+
} from "../../find-id/types";
|
|
13
|
+
|
|
14
|
+
const DEFAULT_CTA_LABEL = "비밀번호 변경";
|
|
15
|
+
const DEFAULT_HEADER = (
|
|
16
|
+
<AuthStageHeader
|
|
17
|
+
className="auth-find-account-header"
|
|
18
|
+
navigationTitle="비밀번호 찾기"
|
|
19
|
+
headline={
|
|
20
|
+
<>
|
|
21
|
+
새로운 비밀번호를
|
|
22
|
+
<br />
|
|
23
|
+
입력해 주세요
|
|
24
|
+
</>
|
|
25
|
+
}
|
|
26
|
+
indicator={{ total: 3, current: 3 }}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 새 비밀번호 입력 화면
|
|
32
|
+
* @component
|
|
33
|
+
*/
|
|
34
|
+
export default function FindPasswordStepReset({
|
|
35
|
+
className,
|
|
36
|
+
header,
|
|
37
|
+
footer,
|
|
38
|
+
fieldOptions,
|
|
39
|
+
rules,
|
|
40
|
+
helper,
|
|
41
|
+
cta,
|
|
42
|
+
}: FindAccountPasswordFormProps) {
|
|
43
|
+
const { fields, formAttr, onSubmit, isSubmittable } = fieldOptions;
|
|
44
|
+
|
|
45
|
+
// 1) 필드 정의를 순회해 RHF 초기값을 만든다.
|
|
46
|
+
const defaultValues = useMemo(
|
|
47
|
+
() =>
|
|
48
|
+
(Object.keys(fields) as Array<keyof typeof fields>).reduce((acc, key) => {
|
|
49
|
+
const config = fields[key];
|
|
50
|
+
const fieldName = config.attr?.name ?? String(key);
|
|
51
|
+
acc[fieldName] = "";
|
|
52
|
+
return acc;
|
|
53
|
+
}, {} as FindAccountPasswordValues),
|
|
54
|
+
[fields],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// 2) RHF form 인스턴스를 초기화한다.
|
|
58
|
+
const form = useForm<FindAccountPasswordValues>({
|
|
59
|
+
mode: "onChange",
|
|
60
|
+
defaultValues,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const watchedValues = form.watch();
|
|
64
|
+
const normalizedValues: FindAccountPasswordValues = {
|
|
65
|
+
...defaultValues,
|
|
66
|
+
...watchedValues,
|
|
67
|
+
};
|
|
68
|
+
const baseFilled =
|
|
69
|
+
normalizedValues &&
|
|
70
|
+
Object.values(normalizedValues).every(value =>
|
|
71
|
+
typeof value === "string" ? value.trim().length > 0 : Boolean(value),
|
|
72
|
+
);
|
|
73
|
+
const resolvedFilled = isSubmittable
|
|
74
|
+
? isSubmittable(normalizedValues)
|
|
75
|
+
: Boolean(baseFilled);
|
|
76
|
+
const disabled = form.formState.isSubmitting || !resolvedFilled;
|
|
77
|
+
const handleSubmit = form.handleSubmit(onSubmit);
|
|
78
|
+
|
|
79
|
+
const buttonProps = {
|
|
80
|
+
type: "submit" as const,
|
|
81
|
+
scale: "solid-xlarge" as const,
|
|
82
|
+
priority: "primary" as const,
|
|
83
|
+
block: true,
|
|
84
|
+
...cta?.buttonProps,
|
|
85
|
+
disabled: cta?.buttonProps?.disabled ?? disabled,
|
|
86
|
+
};
|
|
87
|
+
const passwordFieldConfig = useMemo(() => {
|
|
88
|
+
const priority = (fields.password.props?.priority ??
|
|
89
|
+
"secondary") as InputPasswordProps["priority"];
|
|
90
|
+
const size = (fields.password.props?.size ??
|
|
91
|
+
"large") as InputPasswordProps["size"];
|
|
92
|
+
return {
|
|
93
|
+
...fields.password,
|
|
94
|
+
props: {
|
|
95
|
+
...fields.password.props,
|
|
96
|
+
priority,
|
|
97
|
+
size,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}, [fields.password]);
|
|
101
|
+
const confirmFieldConfig = useMemo(() => {
|
|
102
|
+
const priority = (fields.confirm.props?.priority ??
|
|
103
|
+
"secondary") as InputPasswordProps["priority"];
|
|
104
|
+
const size = (fields.confirm.props?.size ??
|
|
105
|
+
"large") as InputPasswordProps["size"];
|
|
106
|
+
return {
|
|
107
|
+
...fields.confirm,
|
|
108
|
+
props: {
|
|
109
|
+
...fields.confirm.props,
|
|
110
|
+
priority,
|
|
111
|
+
size,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}, [fields.confirm]);
|
|
115
|
+
|
|
116
|
+
const resolvedPasswordRules =
|
|
117
|
+
rules && rules.length > 0 ? rules : DEFAULT_PASSWORD_RULES;
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<AuthContainer
|
|
121
|
+
className={clsx("auth-find-account-container", className)}
|
|
122
|
+
header={header ?? DEFAULT_HEADER}
|
|
123
|
+
footer={footer}
|
|
124
|
+
>
|
|
125
|
+
<FormProvider {...form}>
|
|
126
|
+
<form
|
|
127
|
+
className="auth-find-account-form auth-find-account-form--password"
|
|
128
|
+
{...formAttr}
|
|
129
|
+
onSubmit={handleSubmit}
|
|
130
|
+
>
|
|
131
|
+
<AuthPasswordSetField
|
|
132
|
+
passwordField={passwordFieldConfig}
|
|
133
|
+
confirmPasswordField={confirmFieldConfig}
|
|
134
|
+
passwordRules={resolvedPasswordRules}
|
|
135
|
+
messages={{
|
|
136
|
+
missing: "새 비밀번호를 먼저 입력해 주세요.",
|
|
137
|
+
mismatch: "비밀번호가 일치하지 않습니다.",
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
{helper ? (
|
|
141
|
+
<p className="auth-find-account-password-helper">{helper}</p>
|
|
142
|
+
) : null}
|
|
143
|
+
<Button.Default {...buttonProps}>
|
|
144
|
+
{cta?.label ?? DEFAULT_CTA_LABEL}
|
|
145
|
+
</Button.Default>
|
|
146
|
+
</form>
|
|
147
|
+
</FormProvider>
|
|
148
|
+
</AuthContainer>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import FindAccountCodeStep from "../../common/find/markup/CodeStep";
|
|
2
|
+
import type { FindAccountCodeStepProps } from "../../common/find/types";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_NAVIGATION = {
|
|
5
|
+
title: "비밀번호 찾기",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const DEFAULT_HEADLINE = {
|
|
9
|
+
progress: { total: 3, current: 2 },
|
|
10
|
+
title: (
|
|
11
|
+
<>
|
|
12
|
+
메일 주소로
|
|
13
|
+
<br />
|
|
14
|
+
인증을 진행해 주세요
|
|
15
|
+
</>
|
|
16
|
+
),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const DEFAULT_EMAIL_LABEL = "메일";
|
|
20
|
+
|
|
21
|
+
export type FindPasswordStepVerifyCodeProps = FindAccountCodeStepProps;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Find Password Step2 — 인증코드 입력
|
|
25
|
+
* @component
|
|
26
|
+
*/
|
|
27
|
+
export default function FindPasswordStepVerifyCode({
|
|
28
|
+
navigation,
|
|
29
|
+
headline,
|
|
30
|
+
emailDisplay,
|
|
31
|
+
...rest
|
|
32
|
+
}: FindPasswordStepVerifyCodeProps) {
|
|
33
|
+
const resolvedNavigation = navigation ?? DEFAULT_NAVIGATION;
|
|
34
|
+
const resolvedHeadline = headline ?? DEFAULT_HEADLINE;
|
|
35
|
+
const resolvedEmailDisplay = {
|
|
36
|
+
label: DEFAULT_EMAIL_LABEL,
|
|
37
|
+
...emailDisplay,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<FindAccountCodeStep
|
|
42
|
+
{...rest}
|
|
43
|
+
navigation={resolvedNavigation}
|
|
44
|
+
headline={resolvedHeadline}
|
|
45
|
+
emailDisplay={resolvedEmailDisplay}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import "./login/index.scss";
|
|
2
|
+
|
|
3
|
+
import { AuthContainer } from "./common/container";
|
|
4
|
+
import AuthCompleteTemplate from "./common/complete/Template";
|
|
5
|
+
import AuthPasswordSetField from "./common/password/markup/PasswordSetField";
|
|
6
|
+
import { AuthLogin } from "./login";
|
|
7
|
+
import { AuthSignup } from "./signup";
|
|
8
|
+
import { FindAccount } from "./find-account";
|
|
9
|
+
import { FindId } from "./find-id";
|
|
10
|
+
import { FindPassword } from "./find-password";
|
|
11
|
+
|
|
12
|
+
export const Auth = {
|
|
13
|
+
Container: AuthContainer,
|
|
14
|
+
Common: {
|
|
15
|
+
Container: AuthContainer,
|
|
16
|
+
Complete: AuthCompleteTemplate,
|
|
17
|
+
PasswordSetField: AuthPasswordSetField,
|
|
18
|
+
},
|
|
19
|
+
Login: AuthLogin,
|
|
20
|
+
Signup: AuthSignup,
|
|
21
|
+
FindAccount,
|
|
22
|
+
FindId,
|
|
23
|
+
FindPassword,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
useSignupUserInfoForm,
|
|
28
|
+
useSignupVerificationForm,
|
|
29
|
+
useSignupAccountForm,
|
|
30
|
+
} from "./signup";
|
|
31
|
+
|
|
32
|
+
export { useCheckPassword } from "./common/password/hooks/useCheckPassword";
|
|
33
|
+
export { DEFAULT_PASSWORD_RULES } from "./common/password/constants";
|
|
34
|
+
export { FindAccount, useFindAccountForm } from "./find-account";
|
|
35
|
+
export * from "./find-id";
|
|
36
|
+
export * from "./find-password";
|
|
37
|
+
export { default as AuthCompleteTemplate } from "./common/complete/Template";
|
|
38
|
+
export type * from "./common/password/types";
|
|
39
|
+
export type * from "./login";
|
|
40
|
+
export type * from "./signup";
|
|
41
|
+
export type * from "./find-account";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import clsx from "clsx";
|
|
2
|
-
import { AuthContainer } from "../../container";
|
|
2
|
+
import { AuthContainer } from "../../common/container";
|
|
3
3
|
import AuthLoginFormField from "./FormField";
|
|
4
4
|
import AuthLoginLinkButtons from "./LinkButtons";
|
|
5
5
|
import type { AuthLoginProps } from "../types";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { SubmitHandler } from "react-hook-form";
|
|
3
|
-
import type { AuthContainerProps } from "../../container";
|
|
3
|
+
import type { AuthContainerProps } from "../../common/container";
|
|
4
4
|
import type {
|
|
5
5
|
InputFieldProps,
|
|
6
6
|
InputPasswordProps,
|
|
@@ -29,23 +29,45 @@ export function useSignupAccountForm<
|
|
|
29
29
|
| AuthSignupAccountValues
|
|
30
30
|
| undefined;
|
|
31
31
|
|
|
32
|
+
const passwordFieldName = useMemo(() => {
|
|
33
|
+
const config = (fields as Partial<AuthSignupAccountFields>).password;
|
|
34
|
+
return (
|
|
35
|
+
(config?.attr?.name as keyof AuthSignupAccountValues | undefined) ??
|
|
36
|
+
("password" as keyof AuthSignupAccountValues)
|
|
37
|
+
);
|
|
38
|
+
}, [fields]);
|
|
39
|
+
|
|
40
|
+
const confirmFieldName = useMemo(() => {
|
|
41
|
+
const config = (fields as Partial<AuthSignupAccountFields>).confirmPassword;
|
|
42
|
+
return (
|
|
43
|
+
(config?.attr?.name as keyof AuthSignupAccountValues | undefined) ??
|
|
44
|
+
("confirmPassword" as keyof AuthSignupAccountValues)
|
|
45
|
+
);
|
|
46
|
+
}, [fields]);
|
|
47
|
+
|
|
32
48
|
const register = useMemo(() => {
|
|
33
49
|
return (Object.keys(fields) as Array<keyof TFields>).reduce(
|
|
34
50
|
(acc, fieldKey) => {
|
|
35
51
|
const config = fields[fieldKey] as AuthSignupFieldProps;
|
|
36
52
|
const fieldName = config.attr?.name ?? String(fieldKey);
|
|
53
|
+
if (fieldName === passwordFieldName || fieldName === confirmFieldName) {
|
|
54
|
+
return acc;
|
|
55
|
+
}
|
|
37
56
|
acc[fieldKey] = form.register(fieldName);
|
|
38
57
|
return acc;
|
|
39
58
|
},
|
|
40
59
|
{} as UseSignupAccountFormReturn<TFields>["register"],
|
|
41
60
|
);
|
|
42
|
-
}, [fields, form]);
|
|
61
|
+
}, [confirmFieldName, fields, form, passwordFieldName]);
|
|
43
62
|
|
|
44
63
|
const helpers = useMemo(() => {
|
|
45
64
|
return (Object.keys(fields) as Array<keyof TFields>).reduce(
|
|
46
65
|
(acc, fieldKey) => {
|
|
47
66
|
const config = fields[fieldKey] as AuthSignupFieldProps;
|
|
48
67
|
const fieldName = config.attr?.name ?? String(fieldKey);
|
|
68
|
+
if (fieldName === passwordFieldName || fieldName === confirmFieldName) {
|
|
69
|
+
return acc;
|
|
70
|
+
}
|
|
49
71
|
const state = form.getFieldState(fieldName);
|
|
50
72
|
acc[fieldKey] = {
|
|
51
73
|
text:
|
|
@@ -56,7 +78,7 @@ export function useSignupAccountForm<
|
|
|
56
78
|
},
|
|
57
79
|
{} as UseSignupAccountFormReturn<TFields>["helpers"],
|
|
58
80
|
);
|
|
59
|
-
}, [fields, form]);
|
|
81
|
+
}, [confirmFieldName, fields, form, passwordFieldName]);
|
|
60
82
|
|
|
61
83
|
const trimmedFilled =
|
|
62
84
|
values &&
|
|
@@ -75,3 +97,5 @@ export function useSignupAccountForm<
|
|
|
75
97
|
onSubmit: onSubmitHandler,
|
|
76
98
|
};
|
|
77
99
|
}
|
|
100
|
+
|
|
101
|
+
export default useSignupAccountForm;
|
|
@@ -28,6 +28,7 @@ export function useSignupUserInfoForm<
|
|
|
28
28
|
fields,
|
|
29
29
|
form,
|
|
30
30
|
onSubmit,
|
|
31
|
+
activeFields,
|
|
31
32
|
}: UseSignupUserInfoFormOptions<TFields>): UseSignupUserInfoFormReturn<TFields> {
|
|
32
33
|
const values = useWatch({ control: form.control }) as
|
|
33
34
|
| AuthSignupUserInfoValues
|
|
@@ -62,11 +63,17 @@ export function useSignupUserInfoForm<
|
|
|
62
63
|
);
|
|
63
64
|
}, [fields, form]);
|
|
64
65
|
|
|
66
|
+
const targetKeys =
|
|
67
|
+
activeFields ?? (Object.keys(fields) as Array<keyof TFields>);
|
|
68
|
+
|
|
65
69
|
const trimmedFilled =
|
|
66
70
|
values &&
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
targetKeys.every(fieldKey => {
|
|
72
|
+
const fieldName = (fields[fieldKey].attr?.name ??
|
|
73
|
+
String(fieldKey)) as keyof AuthSignupUserInfoValues;
|
|
74
|
+
const value = values[fieldName];
|
|
75
|
+
return typeof value === "string" ? value.trim().length > 0 : false;
|
|
76
|
+
});
|
|
70
77
|
|
|
71
78
|
const disabled = form.formState.isSubmitting || !trimmedFilled;
|
|
72
79
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M5.87377 3.74906L10.1164 7.9917L5.87377 12.2343C5.56135 12.5468 5.56135 13.0533 5.87377 13.3657C6.18619 13.6781 6.69272 13.6781 7.00514 13.3657L11.8135 8.55739C12.1259 8.24497 12.1259 7.73843 11.8135 7.42601L7.00514 2.61769C6.69272 2.30527 6.18619 2.30527 5.87377 2.61769C5.56135 2.93011 5.56135 3.43664 5.87377 3.74906Z" fill="#CACBCE"/>
|
|
3
|
+
</svg>
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
AuthSignupVerificationForm,
|
|
4
4
|
AuthSignupAccountForm,
|
|
5
5
|
AuthSignupComplete,
|
|
6
|
+
AuthSignupTemplate,
|
|
6
7
|
} from "./markup";
|
|
7
8
|
|
|
8
9
|
import "./styles/signup.scss";
|
|
@@ -14,9 +15,11 @@ export {
|
|
|
14
15
|
AuthSignupVerificationForm,
|
|
15
16
|
AuthSignupAccountForm,
|
|
16
17
|
AuthSignupComplete,
|
|
18
|
+
AuthSignupTemplate,
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export const AuthSignup = {
|
|
22
|
+
Template: AuthSignupTemplate,
|
|
20
23
|
StepUserInfo: AuthSignupUserInfoForm,
|
|
21
24
|
StepVerification: AuthSignupVerificationForm,
|
|
22
25
|
StepAccount: AuthSignupAccountForm,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { FormProvider, useForm } from "react-hook-form";
|
|
3
|
+
import { Button, Input, type InputProps } from "@uniai-fe/uds-primitives";
|
|
4
|
+
import type { AuthSignupAccountProps, AuthSignupAccountValues } from "../types";
|
|
5
|
+
import { useSignupAccountForm } from "../hooks";
|
|
6
|
+
import { composeSignupFieldProps } from "../utils/composeFieldProps";
|
|
7
|
+
import { getSignupFieldDefaultValue } from "../utils/getSignupFieldDefaultValue";
|
|
8
|
+
import AuthPasswordSetField from "../../common/password/markup/PasswordSetField";
|
|
9
|
+
import { DEFAULT_PASSWORD_RULES } from "../../common/password/constants";
|
|
10
|
+
|
|
11
|
+
const DEFAULT_SUBMIT_LABEL = "가입 요청";
|
|
12
|
+
/**
|
|
13
|
+
* 회원가입 Step3; 계정 정보 입력(아이디/비밀번호)
|
|
14
|
+
* @component
|
|
15
|
+
* @param {AuthSignupAccountProps} props account props
|
|
16
|
+
* @param {AuthSignupAccountProps["fields"]} props.fields 아이디/비밀번호 필드
|
|
17
|
+
* @param {AuthSignupPasswordRule[]} [props.passwordRules] 비밀번호 규칙 상태
|
|
18
|
+
* @param {React.FormHTMLAttributes<HTMLFormElement>} [props.formAttr] form attr
|
|
19
|
+
* @param {import("react").ReactNode} [props.submitLabel] CTA 라벨
|
|
20
|
+
*/
|
|
21
|
+
export function AuthSignupAccountForm({
|
|
22
|
+
fields,
|
|
23
|
+
passwordRules,
|
|
24
|
+
formAttr,
|
|
25
|
+
submitLabel,
|
|
26
|
+
onSubmit,
|
|
27
|
+
}: AuthSignupAccountProps) {
|
|
28
|
+
// 필드 구성에서 name attr을 추출해 RHF default 값을 정의한다.
|
|
29
|
+
const defaultValues = useMemo(
|
|
30
|
+
() =>
|
|
31
|
+
(Object.keys(fields) as Array<keyof typeof fields>).reduce(
|
|
32
|
+
(acc, fieldKey) => {
|
|
33
|
+
const config = fields[fieldKey];
|
|
34
|
+
const fieldName = config.attr?.name ?? String(fieldKey);
|
|
35
|
+
acc[fieldName] = getSignupFieldDefaultValue(config);
|
|
36
|
+
return acc;
|
|
37
|
+
},
|
|
38
|
+
{} as AuthSignupAccountValues,
|
|
39
|
+
),
|
|
40
|
+
[fields],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const form = useForm<AuthSignupAccountValues>({
|
|
44
|
+
mode: "onChange",
|
|
45
|
+
defaultValues,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
register,
|
|
50
|
+
helpers,
|
|
51
|
+
disabled,
|
|
52
|
+
onSubmit: handleSubmit,
|
|
53
|
+
} = useSignupAccountForm({
|
|
54
|
+
fields,
|
|
55
|
+
form,
|
|
56
|
+
onSubmit,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const passwordFieldName =
|
|
60
|
+
(fields.password.attr?.name as keyof AuthSignupAccountValues | undefined) ??
|
|
61
|
+
("password" as keyof AuthSignupAccountValues);
|
|
62
|
+
const confirmFieldName =
|
|
63
|
+
(fields.confirmPassword.attr?.name as
|
|
64
|
+
| keyof AuthSignupAccountValues
|
|
65
|
+
| undefined) ?? ("confirmPassword" as keyof AuthSignupAccountValues);
|
|
66
|
+
|
|
67
|
+
const resolvedPasswordRules =
|
|
68
|
+
passwordRules && passwordRules.length > 0
|
|
69
|
+
? passwordRules
|
|
70
|
+
: DEFAULT_PASSWORD_RULES;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<FormProvider {...form}>
|
|
74
|
+
<form
|
|
75
|
+
className="auth-signup-form auth-signup-form--account"
|
|
76
|
+
{...formAttr}
|
|
77
|
+
onSubmit={handleSubmit}
|
|
78
|
+
>
|
|
79
|
+
<div className="auth-signup-fields">
|
|
80
|
+
<Input
|
|
81
|
+
{...composeSignupFieldProps<InputProps>(
|
|
82
|
+
fields.accountId,
|
|
83
|
+
helpers.accountId,
|
|
84
|
+
)}
|
|
85
|
+
register={register.accountId}
|
|
86
|
+
/>
|
|
87
|
+
<AuthPasswordSetField
|
|
88
|
+
passwordField={fields.password}
|
|
89
|
+
confirmPasswordField={fields.confirmPassword}
|
|
90
|
+
passwordFieldName={passwordFieldName}
|
|
91
|
+
confirmPasswordFieldName={confirmFieldName}
|
|
92
|
+
passwordRules={resolvedPasswordRules}
|
|
93
|
+
messages={{
|
|
94
|
+
missing: "비밀번호를 먼저 입력해 주세요.",
|
|
95
|
+
mismatch: "비밀번호 불일치",
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
<Button.Default
|
|
100
|
+
type="submit"
|
|
101
|
+
scale="solid-xlarge"
|
|
102
|
+
priority="primary"
|
|
103
|
+
block
|
|
104
|
+
disabled={disabled}
|
|
105
|
+
>
|
|
106
|
+
{submitLabel ?? DEFAULT_SUBMIT_LABEL}
|
|
107
|
+
</Button.Default>
|
|
108
|
+
</form>
|
|
109
|
+
</FormProvider>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default AuthSignupAccountForm;
|