Skip to content

Commit

Permalink
Merge pull request #20 from team-Ollie/11-feature-MyPage-API
Browse files Browse the repository at this point in the history
feat: 마이페이지 API 연결
  • Loading branch information
iOdiO89 authored Jun 26, 2024
2 parents 1885faa + c8aa169 commit 9951202
Show file tree
Hide file tree
Showing 20 changed files with 611 additions and 93 deletions.
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

0 comments on commit 9951202

Please sign in to comment.