Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 마이페이지 API 연결 #20

Merged
merged 19 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
103 changes: 103 additions & 0 deletions apis/hooks/mypage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { useQuery, useMutation } from "@tanstack/react-query";
import {
getMyInfo,
patchLogout,
patchNicknameChange,
patchPasswordChange,
patchQuitAccount,
postNicknameCheck,
} from "../mypage";
import { useRouter } from "next/router";
import { InputError } from "@/pages/mypage/password";

function useGetMyInfo() {
const { data } = useQuery({
queryKey: ["getMyInfo"],
queryFn: getMyInfo,
});

return { data };
}

function usePatchLogout() {
const router = useRouter();
const { mutate } = useMutation({
mutationKey: ["patchLogout"],
mutationFn: patchLogout,
onSuccess: () => {
localStorage.removeItem("access_token");
router.push("/main");
},
onError: () => router.push("/404"),
});

return { mutate };
}

function usePatchQuitAccount(
setPwError: React.Dispatch<React.SetStateAction<InputError>>,
) {
const router = useRouter();
const { mutate } = useMutation({
mutationKey: ["patchQuitAccount"],
mutationFn: (password: string) => patchQuitAccount(password),
onSuccess: () => {
localStorage.removeItem("access_token");
router.push("/main");
},
onError: () =>
setPwError({ status: true, text: "비밀번호가 올바르지 않습니다." }),
});

return { mutate };
}

function usePatchPasswordChange() {
const router = useRouter();
const { mutate } = useMutation({
mutationKey: ["patchPasswordChange"],
mutationFn: (body: { password: string; newPassword: string }) =>
patchPasswordChange(body),
onSuccess: () => router.push("/mypage/password/success"),
onError: () => router.push("/404"),
});

return { mutate };
}

function usePatchNicknameChange(nickname: string) {
const router = useRouter();
const { mutate } = useMutation({
mutationKey: ["postNicknameCheck", nickname],
mutationFn: () => patchNicknameChange(nickname),
onSuccess: () => router.push("/mypage/nickname/success"),
onError: () => router.push("/404"),
});

return { mutate };
}

function usePostNicknameCheck(
nickname: string,
setNameError: React.Dispatch<React.SetStateAction<InputError>>,
) {
const { mutate } = useMutation({
mutationKey: ["postNicknameCheck", nickname],
mutationFn: () => postNicknameCheck(nickname),
onSuccess: () => setNameError({ status: false, text: "" }),
onError: () => {
setNameError({ status: true, text: "이미 사용 중인 닉네임입니다." });
},
});

return { mutate };
}

export {
useGetMyInfo,
usePatchLogout,
usePatchQuitAccount,
usePatchPasswordChange,
usePatchNicknameChange,
usePostNicknameCheck,
};
71 changes: 71 additions & 0 deletions apis/mypage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import client, { ResponseBody } from "./client";

interface GetMyInfoResponse extends ResponseBody {
result: {
nickname: string;
level: number;
loginId: string;
isAdmin: boolean;
};
}

interface PatchResponse {
isSuccess: boolean;
message: string;
}

interface QuitAccountResponseBody {
timestamp: string;
status: number;
error: string;
code: string;
message: string;
}

async function getMyInfo(): Promise<GetMyInfoResponse> {
const { data } = await client.get(`/users/myPage`);
return data;
}

async function patchLogout(): Promise<PatchResponse> {
const { data } = await client.patch(`/users/logout`);
return data;
}

async function patchQuitAccount(
password: string,
): Promise<QuitAccountResponseBody> {
const { data } = await client.patch(`/users/signout`, { password });
return data;
}

async function patchPasswordChange(body: {
password: string;
newPassword: string;
}): Promise<PatchResponse> {
const { data } = await client.patch(`/users/editPassword`, body);
return data;
}

async function patchNicknameChange(
nickname: string,
): Promise<QuitAccountResponseBody> {
const { data } = await client.patch(`/users/editNickname`, { nickname });
return data;
}

async function postNicknameCheck(
nickname: string,
): Promise<QuitAccountResponseBody> {
const { data } = await client.post(`/users/nickname`, { nickname });
return data;
}

export {
getMyInfo,
patchLogout,
patchQuitAccount,
patchPasswordChange,
patchNicknameChange,
postNicknameCheck,
};
3 changes: 2 additions & 1 deletion components/HeadFunction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useRouter } from "next/router";
import FlexBox from "./Flexbox";
import Image from "next/image";
import Head from "next/head";
import LeftArrowIcon from "@/public/svgs/LeftArrow.svg";

interface Props {
leftIcon?: boolean;
Expand All @@ -26,7 +27,7 @@ export default function HeadFunction({
className="w-5 h-5 shrink-0 items-center align-center"
onClick={router.back}
>
<Image src="/svgs/LeftArrow.svg" width={20} height={20} />
<LeftArrowIcon width={20} height={20} />
</div>
<FlexBox className="w-full h-full justify-center">
<div className="h2">{title}</div>
Expand Down
70 changes: 37 additions & 33 deletions components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MypageIcon from "@/public/svgs/MypageIcon.svg";
import { useRouter } from "next/router";
import NavBarItem from "./NavBarItem";
import { useEffect } from "react";
import FlexBox from "./Flexbox";

const NavBar = () => {
const router = useRouter();
Expand All @@ -18,40 +19,43 @@ const NavBar = () => {
}, []);

return (
<div
className="flex flex-basis h-[4rem] w-full absolute inset-x-0 bottom-0 "
style={{
borderTop: "0.5px solid rgba(112, 115, 124, 0.16)",
backgroundColor: "#ffffff",
}}
>
<div className="flex flex-basis h-full w-full flex-row justify-between items-center ">
<NavBarItem
isActive={pathname === "/"}
text="홈"
onClick={() => handleNavigate("/")}
iconType="home"
>
<HomeIcon />
</NavBarItem>
<NavBarItem
isActive={pathname === "/calendar"}
text="캘린더"
onClick={() => handleNavigate("/calendar")}
iconType="calendar"
>
<CalenderIcon />
</NavBarItem>
<NavBarItem
isActive={pathname === "/mypage"}
text="마이페이지"
onClick={() => handleNavigate("/mypage")}
iconType="mypage"
>
<MypageIcon />
</NavBarItem>
<>
<div className="w-full min-h-[4rem]" />
<div
className="flex flex-basis h-[4rem] w-full fixed inset-x-0 bottom-0 "
style={{
borderTop: "0.5px solid rgba(112, 115, 124, 0.16)",
backgroundColor: "#ffffff",
}}
>
<FlexBox className="w-full justify-between">
<NavBarItem
isActive={pathname === "/"}
text="홈"
onClick={() => handleNavigate("/")}
iconType="home"
>
<HomeIcon />
</NavBarItem>
<NavBarItem
isActive={pathname === "/calendar"}
text="캘린더"
onClick={() => handleNavigate("/calendar")}
iconType="calendar"
>
<CalenderIcon />
</NavBarItem>
<NavBarItem
isActive={pathname === "/mypage"}
text="마이페이지"
onClick={() => handleNavigate("/mypage")}
iconType="mypage"
>
<MypageIcon />
</NavBarItem>
</FlexBox>
</div>
</div>
</>
);
};

Expand Down
52 changes: 52 additions & 0 deletions components/mypage/NicknameInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ChangeEvent, HTMLInputTypeAttribute, useState } from "react";

export interface TextInputProps {
value: string;
setValue: React.Dispatch<React.SetStateAction<string>>;
isError: boolean;
errorText?: string;
isSuccess: boolean;
placeholder?: string;
}

export default function NicknameInput({
value,
setValue,
isError,
errorText,
isSuccess,
placeholder = "",
}: TextInputProps) {
const onChangeText = (e: ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};

const borderStyle = () => {
if (isSuccess) return "border-green-600";
else if (isError) return "border-red-500";
return "border-transparent";
};

return (
<div className="w-full relative">
<div
className={`w-full border ${borderStyle()} bg-gray-100 rounded-lg p-2`}
>
<input
className="w-full outline-none border-none bg-gray-100 h4"
value={value}
onChange={(event) => onChangeText(event)}
placeholder={placeholder}
/>
</div>
{!isSuccess && isError && (
<div className="text-red-500 h5 px-2 absolute">{errorText}</div>
)}
{isSuccess && (
<div className="text-green-600 h5 px-2 absolute">
사용 가능한 닉네임입니다.
</div>
)}
</div>
);
}
44 changes: 40 additions & 4 deletions components/mypage/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,56 @@
import Image from "next/image";
import FlexBox from "../Flexbox";
import { useRouter } from "next/router";
import RightArrowIcon from "@/public/svgs/RightArrow.svg";
import Level1Icon from "@/public/svgs/badges/1.svg";
import Level2Icon from "@/public/svgs/badges/2.svg";
import Level3Icon from "@/public/svgs/badges/3.svg";
import Level4Icon from "@/public/svgs/badges/4.svg";
import Level5Icon from "@/public/svgs/badges/5.svg";
import Level6Icon from "@/public/svgs/badges/6.svg";

export default function Profile() {
interface ProfileProps {
nickname: string;
level: number;
}

export default function Profile({ nickname, level }: ProfileProps) {
const router = useRouter();

const returnBadge = () => {
switch (level) {
case 1:
return <Level1Icon width={24} height={24} />;
break;
case 2:
return <Level2Icon width={24} height={24} />;
break;
case 3:
return <Level3Icon width={24} height={24} />;
break;
case 4:
return <Level4Icon width={24} height={24} />;
break;
case 5:
return <Level5Icon width={24} height={24} />;
break;
case 6:
default:
return <Level6Icon width={24} height={24} />;
break;
}
};
return (
<FlexBox
className="w-full py-7 px-6 justify-between"
onClick={() => router.push("/mypage/profile")}
>
<FlexBox className="gap-2">
<div className="w-10 h-10 rounded-full bg-gray-200" />
<div className="h2">서울복지관 관리자</div>
<Image src={"/svgs/badges/3.svg"} width={24} height={24} />
<div className="h2">{nickname}</div>
{returnBadge()}
</FlexBox>
<Image src={"/svgs/RightArrow.svg"} width={20} height={20} />
<RightArrowIcon width={20} height={20} />
</FlexBox>
);
}
Loading