- 로그인 버튼 비활성화 오류 해결 - 로그인 요칭 및 응답에 따른 토스트 구현
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"local": "vite --mode local",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { useState } from 'react';
|
||||
import reactLogo from './assets/react.svg';
|
||||
import viteLogo from '/vite.svg';
|
||||
import './App.css';
|
||||
import SignUpPage from './ui/page/signup/SignUpPage';
|
||||
import Layout from './layouts/Layout';
|
||||
|
||||
@@ -2,4 +2,6 @@ import { BaseResponse } from "../BaseResponse";
|
||||
|
||||
export class LoginResponse extends BaseResponse {
|
||||
success!: boolean;
|
||||
accessToken?: string;
|
||||
refreshToken?: string;
|
||||
}
|
||||
1
src/hooks/use-toast.ts
Normal file
1
src/hooks/use-toast.ts
Normal file
@@ -0,0 +1 @@
|
||||
import { toast } from 'sonner';
|
||||
@@ -3,21 +3,40 @@ import { Outlet } from "react-router-dom";
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
import Header from "@/ui/component/Header";
|
||||
import { useAuthStore } from '@/store/authStore';
|
||||
import { Toaster, type ToasterProps } from "sonner";
|
||||
import {
|
||||
CircleCheckIcon,
|
||||
InfoIcon,
|
||||
Loader2Icon,
|
||||
OctagonXIcon,
|
||||
TriangleAlertIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
export default function Layout() {
|
||||
const { authData } = useAuthStore();
|
||||
|
||||
return (
|
||||
<SidebarProvider
|
||||
defaultOpen={false}
|
||||
id="root"
|
||||
>
|
||||
<SideBar />
|
||||
<div className="flex flex-col w-full h-full">
|
||||
{ authData?.isLogedIn ? <Header /> : null}
|
||||
{/* <Header /> */}
|
||||
<Outlet />
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
<>
|
||||
<Toaster
|
||||
position="top-center"
|
||||
icons={{
|
||||
success: <CircleCheckIcon className="size-4" fill="#15b815" color="white" />,
|
||||
error: <OctagonXIcon className="size-4" fill="#f14e4e" color="white" />,
|
||||
info: <InfoIcon className="size-4" fill="black" color="white" />,
|
||||
warning: <TriangleAlertIcon className="size-4" fill="#ffd500" color="white" />,
|
||||
loading: <Loader2Icon className="size-4 animate-spin" fill="white" color="black" />
|
||||
}}
|
||||
/>
|
||||
<SidebarProvider
|
||||
defaultOpen={false}
|
||||
id="root"
|
||||
>
|
||||
<SideBar />
|
||||
<div className="flex flex-col w-full h-full">
|
||||
{ authData?.isLogedIn ? <Header /> : null}
|
||||
{/* <Header /> */}
|
||||
<Outlet />
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
// <StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
// </StrictMode>,
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Validator } from '@/util/Validator';
|
||||
import { LoginRequest } from '@/data/request/account/LoginRequest';
|
||||
import { AccountNetwork } from '@/network/AccountNetwork';
|
||||
import { toast } from 'sonner';
|
||||
import { LoginResponse } from '@/data/response';
|
||||
|
||||
export default function LoginPage() {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
@@ -26,6 +27,7 @@ export default function LoginPage() {
|
||||
password: ""
|
||||
}
|
||||
});
|
||||
const { id, password } = { id: loginForm.watch('id'), password: loginForm.watch('password') };
|
||||
|
||||
const moveToSignUpPage = useCallback(() => {
|
||||
navigate(PageRouting["SIGN_UP"].path);
|
||||
@@ -42,28 +44,38 @@ export default function LoginPage() {
|
||||
// TODO 33 로그인 기능 구현
|
||||
const login = async () => {
|
||||
if (isLoading) return;
|
||||
|
||||
const { id, password } = loginForm.getValues();
|
||||
const type = Validator.isEmail(id) ? 'email' : 'accountId';
|
||||
|
||||
const data: LoginRequest = new LoginRequest(type, id, password);
|
||||
|
||||
const loginPromise = accountNetwork.login(data);
|
||||
|
||||
toast.promise(
|
||||
loginPromise,
|
||||
toast.promise<{ message?: string }>(
|
||||
() => new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
loginPromise.then((res) => {
|
||||
if (res.data.success) {
|
||||
resolve({message: ''})
|
||||
} else {
|
||||
reject(res.data.message)
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
reject ("서버 에러 발생");
|
||||
}
|
||||
}),
|
||||
{
|
||||
loading: "로그인 중입니다.",
|
||||
success: (res) => res.data.success ? "로그인이 완료되었습니다." : res.data.message,
|
||||
error: "로그인에 실패하였습니다."
|
||||
success: "로그인이 완료되었습니다.",
|
||||
error: (err) => `${err}`
|
||||
}
|
||||
);
|
||||
|
||||
loginPromise.then((res) => {
|
||||
if (res.data.success) {
|
||||
moveToMainPage();
|
||||
}
|
||||
});
|
||||
// loginPromise.then((res) => {
|
||||
// if (res.data.success) {
|
||||
// moveToMainPage();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
const TextSeparator = ({ text }: { text: string }) => {
|
||||
@@ -89,7 +101,7 @@ export default function LoginPage() {
|
||||
control={loginForm.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<Field data-invalid={fieldState.invalid}>
|
||||
<FieldLabel htmlFor="form-login-id">이메일</FieldLabel>
|
||||
<FieldLabel htmlFor="form-login-id">아이디 또는 이메일</FieldLabel>
|
||||
<Input
|
||||
{...field}
|
||||
type="text"
|
||||
@@ -111,6 +123,7 @@ export default function LoginPage() {
|
||||
<Button
|
||||
className="p-0 bg-transparent hover:bg-transparent h-fit w-fit text-xs text-gray-400 hover:text-gray-500 cursor-pointer"
|
||||
onClick={moveToResetPasswordPage}
|
||||
type="button"
|
||||
>
|
||||
비밀번호를 잊으셨습니까?
|
||||
</Button>
|
||||
@@ -133,17 +146,16 @@ export default function LoginPage() {
|
||||
>
|
||||
<Button
|
||||
className="w-full bg-indigo-500 hover:bg-indigo-400"
|
||||
type="submit"
|
||||
form="form-login"
|
||||
disabled={
|
||||
(loginForm.getValues("id").trim.length < 1)
|
||||
&& (loginForm.getValues("password").trim.length < 1)
|
||||
}>
|
||||
type="button"
|
||||
disabled={id.trim().length < 1 || password.trim().length < 1}
|
||||
onClick={login}
|
||||
>
|
||||
로그인
|
||||
</Button>
|
||||
<TextSeparator text="또는" />
|
||||
<Button
|
||||
className="w-full text-violet-500 bg-white border border-violet-500 hover:bg-violet-500 hover:text-white"
|
||||
type="button"
|
||||
onClick={moveToSignUpPage}
|
||||
>
|
||||
회원가입
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export class Validator {
|
||||
static isEmail = (value: string): boolean => {
|
||||
return /^[^\s@]+@[^\s@]+\.[*\s@]+$/.test(value);
|
||||
}
|
||||
static isEmail = (value: any) => {
|
||||
if (typeof value !== 'string') return false;
|
||||
const email = value.trim();
|
||||
return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(email);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user