Skip to content

Commit

Permalink
Merge pull request #159 from Myongji-Graduate/improve-ux/#136
Browse files Browse the repository at this point in the history
Improve ux/#136
  • Loading branch information
seonghunYang authored Dec 3, 2024
2 parents 0d855d0 + 8fa8325 commit 61ec8fc
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 43 deletions.
31 changes: 18 additions & 13 deletions app/hooks/useFunnel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';

const DEFAULT_STEP_QUERY_KEY = 'funnel-step';
Expand All @@ -15,7 +15,9 @@ export default function useFunnel<Steps extends string>(

const stepQueryKey = options?.stepQueryKey ?? DEFAULT_STEP_QUERY_KEY;

const step = searchParams.get(stepQueryKey) as Steps | undefined;
const stepQueryValue = searchParams.get(stepQueryKey) as Steps | null;

const step = (stepQueryValue ?? defaultStep) as Steps;

const createUrl = useCallback(
(step: Steps) => {
Expand All @@ -36,24 +38,27 @@ export default function useFunnel<Steps extends string>(
);

useEffect(() => {
if (!step) {
if (!stepQueryValue) {
router.replace(createUrl(defaultStep));
}
}, [defaultStep, step, setStep]);
}, [defaultStep, stepQueryValue, setStep]);

const Step = ({ name, children }: React.PropsWithChildren<{ name: Steps }>) => {
const Step = useCallback(({ name, children }: React.PropsWithChildren<{ name: Steps }>) => {
return <>{children}</>;
};
}, []);

const FunnelRoot = ({ children }: React.PropsWithChildren) => {
const targetStep = React.Children.toArray(children).find((childStep) => {
return React.isValidElement(childStep) && childStep.props.name === step;
});
const FunnelRoot = useCallback(
({ children }: React.PropsWithChildren) => {
const targetStep = React.Children.toArray(children).find((childStep) => {
return React.isValidElement(childStep) && childStep.props.name === step;
});

return <>{targetStep}</>;
};
return <>{targetStep}</>;
},
[step],
);

const Funnel = Object.assign(FunnelRoot, { Step });
const Funnel = useMemo(() => Object.assign(FunnelRoot, { Step }), [FunnelRoot, Step]);

return { Funnel, setStep };
}
2 changes: 1 addition & 1 deletion app/ui/user/find-id-form/find-id-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface SignUpFormProps {
function FindIdForm({ onNext }: SignUpFormProps) {
return (
<Form onSuccess={onNext} id="아이디찾기" action={findUserToStudentNumber}>
<Form.TextInput required={true} label="학번" id="studentNumber" placeholder="ex ) 60xxxxxx" />
<Form.TextInput autoFocus={true} required={true} label="학번" id="studentNumber" placeholder="ex ) 60xxxxxx" />
<div className="py-6">
<Form.SubmitButton label="아이디찾기" position="center" variant="primary" />
</div>
Expand Down
1 change: 1 addition & 0 deletions app/ui/user/find-password-from/find-password-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function FindPasswordForm({ authId }: FindPasswordFormProps) {
return (
<Form id="비밀번호 재설정" action={resetPassword} onSuccess={onSuccess} className="flex flex-col gap-4">
<Form.PasswordInput
autoFocus={true}
required={true}
label="비밀번호"
id="newPassword"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ interface FindPasswordValidateFormProps {
function FindPasswordValidateForm({ onNext }: FindPasswordValidateFormProps) {
return (
<Form id="가입자 검증" onSuccess={onNext} action={validateUser} className="flex flex-col gap-4">
<Form.TextInput required={true} label="아이디" id="authId" placeholder="아이디를 입력해주세요." />
<Form.TextInput
autoFocus={true}
required={true}
label="아이디"
id="authId"
placeholder="아이디를 입력해주세요."
/>
<Form.TextInput required={true} label="학번" id="studentNumber" placeholder="ex ) 60xxxxxx" />
<div className="py-6">
<Form.SubmitButton label="검사하기" position="center" variant="primary" />
Expand Down
2 changes: 1 addition & 1 deletion app/ui/user/sign-in-form/sign-in-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function SignInForm({ onSuccess }: SignInForm) {
return (
<>
<Form id="로그인" className="space-y-6" action={authenticate} onSuccess={onSuccess}>
<Form.TextInput required={true} label="아이디" id="authId" placeholder="아이디를 입력하세요" />
<Form.TextInput autoFocus={true} required={true} label="아이디" id="authId" placeholder="아이디를 입력하세요" />
<Form.PasswordInput required={true} label="비밀번호" id="password" placeholder="비밀번호를 입력하세요" />
<div className="pt-6">
<Form.SubmitButton label="로그인" position="center" variant="primary" />
Expand Down
2 changes: 1 addition & 1 deletion app/ui/user/sign-up-form/sign-up-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface SignUpFormProps {
export default function SignUpForm({ onSuccess }: SignUpFormProps) {
return (
<Form className="space-y-6" onSuccess={onSuccess} action={createUser} id="회원가입">
<Form.TextInput required={true} label="아이디" id="authId" placeholder="6자 이상 20자 이하" />
<Form.TextInput autoFocus={true} required={true} label="아이디" id="authId" placeholder="6자 이상 20자 이하" />
<Form.PasswordInput
required={true}
label="비밀번호"
Expand Down
11 changes: 4 additions & 7 deletions app/ui/view/molecule/form/form-number-input.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import TextInput from '../../atom/text-input/text-input';
import { FormInputProps } from './form-root';
import { FormContext } from './form.context';
import { useContext } from 'react';
import { useFormStatus } from 'react-dom';

interface FormNumberInputProps {
label: string;
id: string;
placeholder: string;
required?: boolean;
}
interface FormNumberInputProps extends FormInputProps {}

export function FormNumberInput({ label, id, placeholder, required = false }: FormNumberInputProps) {
export function FormNumberInput({ label, id, placeholder, autoFocus, required = false }: FormNumberInputProps) {
const { errors } = useContext(FormContext);
const { pending } = useFormStatus();

Expand All @@ -23,6 +19,7 @@ export function FormNumberInput({ label, id, placeholder, required = false }: Fo
{label}
</label>
<TextInput
autoFocus={autoFocus}
required={required}
disabled={pending}
error={errors[id] ? true : false}
Expand Down
11 changes: 4 additions & 7 deletions app/ui/view/molecule/form/form-password-input.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import TextInput from '../../atom/text-input/text-input';
import { FormInputProps } from './form-root';
import { FormContext } from './form.context';
import { useContext } from 'react';
import { useFormStatus } from 'react-dom';

interface FormPasswordInputProps {
label: string;
id: string;
placeholder: string;
required?: boolean;
}
interface FormPasswordInputProps extends FormInputProps {}

export function FormPasswordInput({ label, id, placeholder, required = false }: FormPasswordInputProps) {
export function FormPasswordInput({ label, id, placeholder, autoFocus, required = false }: FormPasswordInputProps) {
const { errors } = useContext(FormContext);
const { pending } = useFormStatus();

Expand All @@ -23,6 +19,7 @@ export function FormPasswordInput({ label, id, placeholder, required = false }:
{label}
</label>
<TextInput
autoFocus={autoFocus}
required={required}
disabled={pending}
error={errors[id] ? true : false}
Expand Down
9 changes: 9 additions & 0 deletions app/ui/view/molecule/form/form-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ import { filterChildrenByType } from '@/app/utils/component.util';
import AlertDestructive from '../alert-destructive/alert-destructive';
import { useToast } from '../toast/use-toast';

export interface FormInputProps {
label: string;
id: string;
placeholder: string;
required?: boolean;
autoFocus?: boolean;
}

export interface FormState {
isSuccess: boolean;
isFailure: boolean;
Expand Down Expand Up @@ -57,6 +65,7 @@ export function FormRoot({
return React.Children.map(children, (child, index) => {
if (!React.isValidElement(child) || child.type === FormSubmitButton) return null;
if (child.type === FormSubmitButton) return child;

return <div key={index}>{child}</div>;
});
};
Expand Down
10 changes: 4 additions & 6 deletions app/ui/view/molecule/form/form-select.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import Select from '../select';
import { FormInputProps } from './form-root';
import { FormContext } from './form.context';
import { useContext } from 'react';
import { useFormStatus } from 'react-dom';

interface FormSelectProps {
label: string;
id: string;
interface FormSelectProps extends FormInputProps {
options: { value: string; placeholder: string }[];
placeholder: string;
required?: boolean;
}

export const FormSelect = ({ label, id, options, placeholder, required = true }: FormSelectProps) => {
export const FormSelect = ({ label, id, options, placeholder, autoFocus, required = true }: FormSelectProps) => {
const { errors } = useContext(FormContext);
const { pending } = useFormStatus();

Expand All @@ -24,6 +21,7 @@ export const FormSelect = ({ label, id, options, placeholder, required = true }:
{label}
</label>
<Select
autoFocus={autoFocus}
required={required}
disabled={pending}
error={errors[id] ? true : false}
Expand Down
10 changes: 4 additions & 6 deletions app/ui/view/molecule/form/form-text-input.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import TextInput from '../../atom/text-input/text-input';
import { FormInputProps } from './form-root';
import { FormContext } from './form.context';
import { useContext } from 'react';
import { useFormStatus } from 'react-dom';

interface FormTextInputProps {
label: string;
id: string;
placeholder: string;
required?: boolean;
interface FormTextInputProps extends FormInputProps {
value?: string;
}

export function FormTextInput({ label, id, value, placeholder, required = false }: FormTextInputProps) {
export function FormTextInput({ label, id, value, placeholder, autoFocus, required = false }: FormTextInputProps) {
const { errors } = useContext(FormContext);
const { pending } = useFormStatus();

Expand All @@ -24,6 +21,7 @@ export function FormTextInput({ label, id, value, placeholder, required = false
{label}
</label>
<TextInput
autoFocus={autoFocus}
required={required}
disabled={pending}
error={errors[id] ? true : false}
Expand Down

0 comments on commit 61ec8fc

Please sign in to comment.