- 로그인 화면, 회원가입 화면, 비밀번호 초기화 화면 모바일 ui 대비 작업
This commit is contained in:
@@ -1 +1 @@
|
|||||||
VITE_API_URL=http://localhost:8080
|
VITE_API_URL=http://localhost:8088
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ import { toast } from 'sonner';
|
|||||||
import { useAuthStore } from '@/store/authStore';
|
import { useAuthStore } from '@/store/authStore';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
|
import { useIsMobile } from '@/hooks/use-mobile';
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [autoLogin, setAutoLogin] = useState<boolean>(false);
|
const [autoLogin, setAutoLogin] = useState<boolean>(false);
|
||||||
const { login } = useAuthStore();
|
const { login } = useAuthStore();
|
||||||
|
const isMobile = useIsMobile();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const accountNetwork = new AccountNetwork();
|
const accountNetwork = new AccountNetwork();
|
||||||
const loginForm = useForm<z.infer<typeof LoginSchema>>({
|
const loginForm = useForm<z.infer<typeof LoginSchema>>({
|
||||||
@@ -73,7 +75,7 @@ export default function LoginPage() {
|
|||||||
};
|
};
|
||||||
login({...data});
|
login({...data});
|
||||||
moveToHomePage();
|
moveToHomePage();
|
||||||
return "";
|
return "로그인 성공";
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.data.message);
|
throw new Error(res.data.message);
|
||||||
}
|
}
|
||||||
@@ -102,7 +104,7 @@ export default function LoginPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex flex-col justify-center items-center">
|
<div className="w-full h-full flex flex-col justify-center items-center">
|
||||||
<Card className="w-md pl-2 pr-2">
|
<Card className={isMobile ? "w-full pl-2 pr-2" : "w-md pl-2 pr-2"}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
로그인
|
로그인
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import { AccountNetwork } from '@/network/AccountNetwork';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { PageRouting } from '@/const/PageRouting';
|
import { PageRouting } from '@/const/PageRouting';
|
||||||
|
import { useIsMobile } from '@/hooks/use-mobile';
|
||||||
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
|
|
||||||
export default function SignUpPage() {
|
export default function SignUpPage() {
|
||||||
const [emailVerificationModalOpen, setEmailVerificationModalOpen] = useState<boolean>(false);
|
const [emailVerificationModalOpen, setEmailVerificationModalOpen] = useState<boolean>(false);
|
||||||
@@ -28,6 +30,7 @@ export default function SignUpPage() {
|
|||||||
|
|
||||||
const accountNetwork = new AccountNetwork();
|
const accountNetwork = new AccountNetwork();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const signUpForm = useForm<z.infer<typeof SignUpSchema>>({
|
const signUpForm = useForm<z.infer<typeof SignUpSchema>>({
|
||||||
resolver: zodResolver(SignUpSchema),
|
resolver: zodResolver(SignUpSchema),
|
||||||
@@ -119,145 +122,150 @@ export default function SignUpPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full flex flex-col justify-center items-center">
|
<div className={"w-full h-full flex flex-col justify-center items-center"}>
|
||||||
<Card className="w-md pl-2 pr-2">
|
|
||||||
<CardHeader>회원가입</CardHeader>
|
<Card className={isMobile ? "w-full pl-2 pr-2" : "w-md pl-2 pr-2"}>
|
||||||
<CardContent>
|
<CardHeader>회원가입</CardHeader>
|
||||||
<form id="form-signup">
|
<ScrollArea className="h-72 [&>div>div:last-child]:hidden">
|
||||||
<FieldGroup>
|
<CardContent>
|
||||||
<Controller
|
<form id="form-signup">
|
||||||
name="accountId"
|
<FieldGroup>
|
||||||
control={signUpForm.control}
|
<Controller
|
||||||
render={({ field, fieldState }) => (
|
name="accountId"
|
||||||
<Field data-invalid={fieldState.invalid}>
|
control={signUpForm.control}
|
||||||
<FieldLabel htmlFor="form-signup-account-id">아이디</FieldLabel>
|
render={({ field, fieldState }) => (
|
||||||
<div id="accountId-group" className="w-full flex flex-row justify-between gap-2.5">
|
<Field data-invalid={fieldState.invalid}>
|
||||||
|
<FieldLabel htmlFor="form-signup-account-id">아이디</FieldLabel>
|
||||||
|
<div id="accountId-group" className="w-full flex flex-row justify-between gap-2.5">
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
id="form-signup-account-id"
|
||||||
|
aria-invalid={fieldState.invalid}
|
||||||
|
onInput={handleOnChangeAccountId}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleDuplicationCheckButtonClick('accountId')}
|
||||||
|
className="bg-indigo-500 hover:bg-indigo-400"
|
||||||
|
>
|
||||||
|
중복 확인
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{ isCheckedAccountIdDuplication && <p className="text-green-500 text-sm font-normal">사용할 수 있는 아이디입니다</p> }
|
||||||
|
<FieldError errors={[fieldState.error]}/>
|
||||||
|
</Field>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="name"
|
||||||
|
control={signUpForm.control}
|
||||||
|
render={({ field, fieldState }) => (
|
||||||
|
<Field data-invalid={fieldState.invalid}>
|
||||||
|
<FieldLabel htmlFor="form-signup-name">이름</FieldLabel>
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
id="form-signup-account-id"
|
id="form-signup-name"
|
||||||
aria-invalid={fieldState.invalid}
|
aria-invalid={fieldState.invalid}
|
||||||
onInput={handleOnChangeAccountId}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<FieldError errors={[fieldState.error]} />
|
||||||
type="button"
|
</Field>
|
||||||
onClick={() => handleDuplicationCheckButtonClick('accountId')}
|
)}
|
||||||
className="bg-indigo-500 hover:bg-indigo-400"
|
/>
|
||||||
>
|
<Controller
|
||||||
중복 확인
|
name="nickname"
|
||||||
</Button>
|
control={signUpForm.control}
|
||||||
</div>
|
render={({ field, fieldState }) => (
|
||||||
{ isCheckedAccountIdDuplication && <p className="text-green-500 text-sm font-normal">사용할 수 있는 아이디입니다</p> }
|
<Field data-invalid={fieldState.invalid}>
|
||||||
<FieldError errors={[fieldState.error]}/>
|
<FieldLabel htmlFor="form-signup-nickname">닉네임</FieldLabel>
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="name"
|
|
||||||
control={signUpForm.control}
|
|
||||||
render={({ field, fieldState }) => (
|
|
||||||
<Field data-invalid={fieldState.invalid}>
|
|
||||||
<FieldLabel htmlFor="form-signup-name">이름</FieldLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="form-signup-name"
|
|
||||||
aria-invalid={fieldState.invalid}
|
|
||||||
/>
|
|
||||||
<FieldError errors={[fieldState.error]} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="nickname"
|
|
||||||
control={signUpForm.control}
|
|
||||||
render={({ field, fieldState }) => (
|
|
||||||
<Field data-invalid={fieldState.invalid}>
|
|
||||||
<FieldLabel htmlFor="form-signup-nickname">닉네임</FieldLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="form-signup-nickname"
|
|
||||||
aria-invalid={fieldState.invalid}
|
|
||||||
/>
|
|
||||||
<FieldError errors={[fieldState.error]} />
|
|
||||||
</Field>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="email"
|
|
||||||
control={signUpForm.control}
|
|
||||||
render={({ field, fieldState }) => (
|
|
||||||
<Field data-invalid={fieldState.invalid}>
|
|
||||||
<FieldLabel htmlFor="form-signup-email">이메일</FieldLabel>
|
|
||||||
<div id="email-group" className="w-full flex flex-row justify-between gap-2.5">
|
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
id="form-signup-email"
|
id="form-signup-nickname"
|
||||||
aria-invalid={fieldState.invalid}
|
aria-invalid={fieldState.invalid}
|
||||||
placeholder="example@domain.com"
|
|
||||||
type="email"
|
|
||||||
onInput={handleOnChangeEmail}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<FieldError errors={[fieldState.error]} />
|
||||||
type="button"
|
</Field>
|
||||||
onClick={() => handleDuplicationCheckButtonClick('email')}
|
)}
|
||||||
className="bg-indigo-500 hover:bg-indigo-400"
|
/>
|
||||||
>
|
<Controller
|
||||||
중복 확인
|
name="email"
|
||||||
</Button>
|
control={signUpForm.control}
|
||||||
</div>
|
render={({ field, fieldState }) => (
|
||||||
{ isCheckedEmailDuplication && <p className="text-green-500 text-sm font-normal">사용할 수 있는 이메일입니다</p> }
|
<Field data-invalid={fieldState.invalid}>
|
||||||
<FieldError errors={[fieldState.error]}/>
|
<FieldLabel htmlFor="form-signup-email">이메일</FieldLabel>
|
||||||
</Field>
|
<div id="email-group" className="w-full flex flex-row justify-between gap-2.5">
|
||||||
)}
|
<Input
|
||||||
/>
|
{...field}
|
||||||
<Controller
|
id="form-signup-email"
|
||||||
name="password"
|
aria-invalid={fieldState.invalid}
|
||||||
control={signUpForm.control}
|
placeholder="example@domain.com"
|
||||||
render={({ field, fieldState }) => (
|
type="email"
|
||||||
<Field data-invalid={fieldState.invalid}>
|
onInput={handleOnChangeEmail}
|
||||||
<FieldLabel htmlFor="form-signup-password">비밀번호</FieldLabel>
|
/>
|
||||||
<Input
|
<Button
|
||||||
{...field}
|
type="button"
|
||||||
id="form-signup-password"
|
onClick={() => handleDuplicationCheckButtonClick('email')}
|
||||||
aria-invalid={fieldState.invalid}
|
className="bg-indigo-500 hover:bg-indigo-400"
|
||||||
type="password"
|
>
|
||||||
/>
|
중복 확인
|
||||||
<FieldError errors={[fieldState.error]} />
|
</Button>
|
||||||
</Field>
|
</div>
|
||||||
)}
|
{ isCheckedEmailDuplication && <p className="text-green-500 text-sm font-normal">사용할 수 있는 이메일입니다</p> }
|
||||||
/>
|
<FieldError errors={[fieldState.error]}/>
|
||||||
<Controller
|
</Field>
|
||||||
name="passwordConfirm"
|
)}
|
||||||
control={signUpForm.control}
|
/>
|
||||||
render={({ field, fieldState }) => (
|
<Controller
|
||||||
<Field data-invalid={fieldState.invalid}>
|
name="password"
|
||||||
<FieldLabel htmlFor="form-signup-password-confirm">비밀번호 확인</FieldLabel>
|
control={signUpForm.control}
|
||||||
<Input
|
render={({ field, fieldState }) => (
|
||||||
{...field}
|
<Field data-invalid={fieldState.invalid}>
|
||||||
id="form-signup-password-confirm"
|
<FieldLabel htmlFor="form-signup-password">비밀번호</FieldLabel>
|
||||||
aria-invalid={fieldState.invalid}
|
<Input
|
||||||
type="password"
|
{...field}
|
||||||
/>
|
id="form-signup-password"
|
||||||
<FieldError errors={[fieldState.error]} />
|
aria-invalid={fieldState.invalid}
|
||||||
</Field>
|
type="password"
|
||||||
)}
|
/>
|
||||||
/>
|
<FieldError errors={[fieldState.error]} />
|
||||||
</FieldGroup>
|
</Field>
|
||||||
</form>
|
)}
|
||||||
</CardContent>
|
/>
|
||||||
<CardFooter>
|
<Controller
|
||||||
<EmailVerificationModal
|
name="passwordConfirm"
|
||||||
trigger={
|
control={signUpForm.control}
|
||||||
<Button type="button" onClick={handleOnSignUpButtonClick} className="0">
|
render={({ field, fieldState }) => (
|
||||||
회원가입
|
<Field data-invalid={fieldState.invalid}>
|
||||||
</Button>
|
<FieldLabel htmlFor="form-signup-password-confirm">비밀번호 확인</FieldLabel>
|
||||||
}
|
<Input
|
||||||
email={duplicationCheckedEmail}
|
{...field}
|
||||||
open={emailVerificationModalOpen} // ✅ 부모 상태 연결
|
id="form-signup-password-confirm"
|
||||||
setOpen={setEmailVerificationModalOpen} // ✅ 부모 상태 변경 함수 전달
|
aria-invalid={fieldState.invalid}
|
||||||
onVerifySuccess={signup} // ✅ 인증 성공 시 signup 호출
|
type="password"
|
||||||
/>
|
/>
|
||||||
</CardFooter>
|
<FieldError errors={[fieldState.error]} />
|
||||||
</Card>
|
</Field>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FieldGroup>
|
||||||
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</ScrollArea>
|
||||||
|
<CardFooter>
|
||||||
|
<EmailVerificationModal
|
||||||
|
trigger={
|
||||||
|
<Button type="button" onClick={handleOnSignUpButtonClick} className="0">
|
||||||
|
회원가입
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
email={duplicationCheckedEmail}
|
||||||
|
open={emailVerificationModalOpen} // ✅ 부모 상태 연결
|
||||||
|
setOpen={setEmailVerificationModalOpen} // ✅ 부모 상태 변경 함수 전달
|
||||||
|
onVerifySuccess={signup} // ✅ 인증 성공 시 signup 호출
|
||||||
|
/>
|
||||||
|
</CardFooter>
|
||||||
|
|
||||||
|
</Card>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/ui/page/schedule/ScheduleMainPage.tsx
Normal file
26
src/ui/page/schedule/ScheduleMainPage.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Calendar } from "@/components/ui/calendar";
|
||||||
|
import { DayButton } from "react-day-picker";
|
||||||
|
|
||||||
|
export function ScheduleMainPage() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full flex flex-col justify-start items-center">
|
||||||
|
<Calendar
|
||||||
|
mode="single"
|
||||||
|
className="rounded-lg w-full h-full max-h-10/12 border"
|
||||||
|
components={{
|
||||||
|
Weeks: (props) => (
|
||||||
|
<tbody {...props} className={props.className}></tbody>
|
||||||
|
),
|
||||||
|
Week: (props) => (
|
||||||
|
<tr {...props} className={props.className + " h-1/10"}></tr>
|
||||||
|
),
|
||||||
|
Day: (props) => (
|
||||||
|
<td {...props} className={props.className + " h-1"}></td>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
</Calendar>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user