Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 37 additions & 30 deletions src/hooks/useUserStore.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";

type User = {
id: string;
Expand All @@ -20,36 +21,42 @@ interface UserState {
clearUser: () => void;
}

export const useUserStore = create<UserState>((set, get) => ({
user: null,
token: null,
isLoggedIn: false,

setUserAndToken: (user, token) =>
set(() => ({
user,
token,
isLoggedIn: true,
})),

updateShopId: (shopId) => {
const current = get();
if (!current.user || !current.token) return;

const updatedUser = {
...current.user,
shopId,
};

set({
user: updatedUser,
});
},

clearUser: () =>
set(() => ({
export const useUserStore = create<UserState>()(
persist(
(set, get) => ({
user: null,
token: null,
isLoggedIn: false,
})),
}));

setUserAndToken: (user, token) =>
set({
user,
token,
isLoggedIn: true,
}),

updateShopId: (shopId) => {
const current = get();
if (!current.user || !current.token) return;

set({
user: {
...current.user,
shopId,
},
});
},

clearUser: () =>
set({
user: null,
token: null,
isLoggedIn: false,
}),
}),
{
name: "user-storage",
storage: createJSONStorage(() => localStorage),
},
),
);
131 changes: 130 additions & 1 deletion src/pages/SigninPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,132 @@
import { AxiosError } from "axios";
import { useNavigate, Link } from "react-router-dom";

import Logo from "../assets/logo/thejulge.svg?react";
import { useAuthForm } from "../hooks/useAuthForm";

import { postAuthentication } from "@/apis/services/authenticationService";
import Button from "@/components/Button";
import TextField from "@/components/TextField";
import { ROUTES } from "@/constants/router";
import { useUserStore } from "@/hooks/useUserStore";
import { useModalStore } from "@/store/useModalStore";

export default function SigninPage() {
return <div>SigninPage</div>;
const navigate = useNavigate();
const { setUserAndToken } = useUserStore();
const { openModal, closeModal } = useModalStore();

const { formData, errors, isFormValid, handleChange, resetForm } =
useAuthForm("signin");

const handleSubmit = async () => {
try {
const res = await postAuthentication({
email: formData.email,
password: formData.password,
});

const token = res.data.item.token;
const user = res.data.item.user.item;

setUserAndToken(user, token);

resetForm();

const route =
user.type === "employer" ? ROUTES.SHOP.ROOT : ROUTES.PROFILE.ROOT;

openModal({
type: "message",
message: "로그인에 성공했습니다!",
iconType: "none",
buttons: [
{
label: "확인",
style: "primary",
onClick: () => {
closeModal();
},
},
],
onClose: () => {
navigate(route);
},
});
} catch (error: unknown) {
const axiosError = error as AxiosError<{ message: string }>;
const message =
axiosError.response?.data?.message ?? "로그인 실패! 다시 시도해주세요.";

openModal({
type: "message",
message: message,
iconType: "none",
buttons: [
{
label: "확인",
style: "primary",
onClick: () => {
closeModal();
},
},
],
});
}
};

return (
<div className="w-full">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하위에 있는 단위를 px대신 rem으로 사용하면 좋을 것 같습니다 !

<Link to={ROUTES.NOTICE.ROOT}>
<Logo className="mx-auto mb-2 h-[2.8125rem] w-[15.5rem]" />
</Link>

<form
className="mt-[2.5rem] mx-auto flex max-w-sm flex-col gap-[1.75rem]"
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
>
<TextField.Input
id="email"
label="이메일"
type="email"
placeholder="입력"
value={formData.email}
onChange={handleChange("email")}
fullWidth
validateMessage={errors.email}
/>

<TextField.Input
id="password"
label="비밀번호"
type="password"
placeholder="입력"
value={formData.password}
onChange={handleChange("password")}
fullWidth
validateMessage={errors.password}
/>

<Button
type="button"
fullWidth
className="py-[0.875rem]"
onClick={handleSubmit}
disabled={!isFormValid}
>
로그인하기
</Button>
</form>

<p className="mt-[1rem] text-center text-sm">
회원이 아니신가요?{" "}
<Link to={ROUTES.AUTH.SIGNUP} className="text-[#5534DA] underline">
회원가입하기
</Link>
</p>
</div>
);
}
80 changes: 45 additions & 35 deletions src/pages/SignupPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import Button from "@/components/Button";
import TextField from "@/components/TextField";
import { ROUTES } from "@/constants/router";
import { useUserStore } from "@/hooks/useUserStore";
import { useModalStore } from "@/store/useModalStore";

export default function SignupPage() {
const navigate = useNavigate();
const { setUserAndToken } = useUserStore();
const { openModal, closeModal } = useModalStore();

const {
formData,
Expand All @@ -25,9 +27,6 @@ export default function SignupPage() {
setFormData,
resetForm,
} = useAuthForm("signup");
//Alert 사용시
// const [alertMessage, setAlertMessage] = useState("");
// const [nextRoute, setNextRoute] = useState<string | null>(null);

const handleSubmit = async () => {
try {
Expand All @@ -50,33 +49,58 @@ export default function SignupPage() {

resetForm();

navigate(
user.type === "employer" ? ROUTES.SHOP.ROOT : ROUTES.PROFILE.ROOT,
);
//Alert 사용
// setAlertMessage("가입이 완료되었습니다!");
// setNextRoute(user.type === "employer" ? ROUTES.SHOP.ROOT : ROUTES.PROFILE.ROOT);
const route =
user.type === "employer" ? ROUTES.SHOP.ROOT : ROUTES.PROFILE.ROOT;

openModal({
type: "message",
message: "가입이 완료되었습니다!",
iconType: "none",
buttons: [
{
label: "확인",
style: "primary",
onClick: () => {
closeModal();
},
},
],
onClose: () => {
navigate(route);
},
});
}
} catch (error: unknown) {
const axiosError = error as AxiosError<{ message: string }>;
const message =
axiosError.response?.data?.message ?? "알 수 없는 에러 발생";

console.log(message);
//Alert 사용시
// setAlertMessage(message ?? "회원가입 실패! 다시 시도해주세요.");
// setNextRoute(null);
axiosError.response?.data?.message ??
"회원가입 실패! 다시 시도해주세요.";

openModal({
type: "message",
message,
iconType: "none",
buttons: [
{
label: "확인",
style: "primary",
onClick: () => {
closeModal();
},
},
],
});
}
};

return (
<div className="w-full">
<Link to={ROUTES.NOTICE.ROOT}>
<Logo className="mx-auto mb-2 h-[45px] w-[248px]" />
<Logo className="mx-auto mb-2 h-[2.8125rem] w-[15.5rem]" />
</Link>

<form
className="mt-[40px] mx-auto flex max-w-sm flex-col gap-[28px]"
className="mt-[2.5rem] mx-auto flex max-w-sm flex-col gap-[1.75rem]"
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
Expand Down Expand Up @@ -128,7 +152,7 @@ export default function SignupPage() {
setFormData((prev) => ({ ...prev, userType: "employee" }))
}
className={clsx(
"flex items-center justify-center gap-[9px] rounded-[30px] border px-[41px] py-[13px]",
"flex items-center justify-center gap-[0.5625rem] rounded-[1.875rem] border px-[2.5625rem] py-[0.8125rem]",
formData.userType === "employee"
? "border-primary"
: "border-gray-30",
Expand All @@ -155,7 +179,7 @@ export default function SignupPage() {
setFormData((prev) => ({ ...prev, userType: "employer" }))
}
className={clsx(
"flex items-center justify-center gap-[9px] rounded-[30px] border px-[41px] py-[13px]",
"flex items-center justify-center gap-[0.5625rem] rounded-[1.875rem] border px-[2.5625rem] py-[0.8125rem]",
formData.userType === "employer"
? "border-primary"
: "border-gray-30",
Expand All @@ -179,34 +203,20 @@ export default function SignupPage() {
<Button
type="button"
fullWidth
className="py-[14px]"
className="py-[0.875rem]"
onClick={handleSubmit}
disabled={!isFormValid}
>
가입하기
</Button>
</form>

<p className="mt-[16px] text-center text-sm">
<p className="mt-[1rem] text-center text-sm">
이미 가입하셨나요?{" "}
<Link to={ROUTES.AUTH.SIGNIN} className="text-[#5534DA] underline">
로그인하기
</Link>
</p>

{/* 임시 Alert */}
{/* {alertMessage && (
<AlertModal
message={alertMessage}
onClose={() => {
setAlertMessage("");
if (nextRoute) {
navigate(nextRoute);
setNextRoute(null);
}
}}
/>
)} */}
</div>
);
}