Skip to content

Commit

Permalink
Merge pull request #68 from Kusitms-29th-ASAP/feat/#26
Browse files Browse the repository at this point in the history
[Feat] 로그인/회원가입 API 연동
  • Loading branch information
yyypearl authored May 21, 2024
2 parents 1b2f916 + fa1cdc6 commit 3ec96fc
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 92 deletions.
24 changes: 20 additions & 4 deletions src/apis/auth/postKakaoToken.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import Axios from "../axios";

export async function postKakaoToken(accessToken: string): Promise<void> {
await Axios.post("/api/v1/auth/login/KAKAO", {
accessToken: accessToken,
});
interface PostKakaoTokenResponse {
accessToken?: string;
refreshToken?: string;
registerToken?: string;
}

export async function postKakaoToken(
accessToken: string
): Promise<PostKakaoTokenResponse> {
try {
const response = await Axios.post<PostKakaoTokenResponse>(
"/api/v1/auth/login/KAKAO",
{
accessToken: accessToken,
}
);
return response.data;
} catch (error) {
throw new Error("Failed to login with Kakao: " + error);
}
}

export default postKakaoToken;
16 changes: 12 additions & 4 deletions src/apis/auth/putTokenReissue.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { TokenResponse } from "@/interface/Auth";
import Axios from "../axios";

export async function putTokenReissue(refreshToken: string): Promise<void> {
await Axios.put("/api/v1/auth/reissue", {
refreshToken: refreshToken,
});
export async function putTokenReissue(
refreshToken: string
): Promise<TokenResponse> {
try {
const response = await Axios.put<TokenResponse>("/api/v1/auth/reissue", {
refreshToken: refreshToken,
});
return response.data;
} catch (error) {
throw new Error("Failed to reissue token: " + error);
}
}

export default putTokenReissue;
13 changes: 13 additions & 0 deletions src/apis/user/postUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PostUserRequest, TokenResponse } from "@/interface/Auth";
import Axios from "../axios";

export async function postUser(user: PostUserRequest): Promise<TokenResponse> {
try {
const response = await Axios.post<TokenResponse>("/api/v1/users", user);
return response.data;
} catch (error) {
throw new Error("Failed to register user: " + error);
}
}

export default postUser;
62 changes: 35 additions & 27 deletions src/app/auth/page.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
"use client";

import postKakaoToken from "@/apis/auth/postKakaoToken";
import { setToken } from "@/redux/slices/authSlice";
import axios from "axios";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { useDispatch } from "react-redux";

const Auth = () => {
const router = useRouter();
const dispatch = useDispatch();
const REST_API_KEY = process.env.NEXT_PUBLIC_REST_API_KEY;
const REDIRECT_URI = process.env.NEXT_PUBLIC_REDIRECT_URI;
("code");

useEffect(() => {
if (typeof window !== "undefined") {
const AUTHORIZATION_CODE = new URL(window.location.href).searchParams.get(
"code"
);
const ACCESS_TOKEN = localStorage.getItem("access_token");
postKakaoToken(ACCESS_TOKEN!!);

const getToken = async () => {
const res = axios.post(
"https://kauth.kakao.com/oauth/token",
{
grant_type: "authorization_code",
client_id: REST_API_KEY,
redirect_uri: REDIRECT_URI,
code: AUTHORIZATION_CODE,
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
try {
const response = await axios.post(
"https://kauth.kakao.com/oauth/token",
{
grant_type: "authorization_code",
client_id: REST_API_KEY,
redirect_uri: REDIRECT_URI,
code: AUTHORIZATION_CODE,
},
}
);
return res;
};
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
);

getToken()
.then((res) => {
if (res) {
localStorage.setItem(
"access_token",
JSON.stringify(res.data.access_token)
);
if (response) {
const accessToken = response.data.access_token;
localStorage.setItem("access_token", accessToken);
router.push("/signin/terms");

const data = await postKakaoToken(accessToken);

dispatch(
setToken({
accessToken: data.accessToken, // 회원가입되어 있을 때
refreshToken: data.refreshToken, // 회원가입되어 있을 때
registerToken: data.registerToken, // 회원가입되어 있지 않을 때
})
);
}
})
.catch((err) => console.log(err));
} catch (error) {
console.error("Error during token handling:", error);
}
};
getToken();
}
}, [REST_API_KEY, REDIRECT_URI, router]);

Expand Down
26 changes: 23 additions & 3 deletions src/app/mypage/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
"use client";

import deleteUser from "@/apis/auth/deleteUser";
import Tabbar from "@/components/common/Tabbar";
import Topbar from "@/components/common/Topbar";
import { RootState } from "@/redux/store";
import { theme } from "@/styles/theme";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useSelector } from "react-redux";
import styled from "styled-components";

const Mypage = () => {
const router = useRouter();
const tokens = useSelector((state: RootState) => state.auth);
const { refreshToken } = tokens;

const handleLogout = () => {
deleteUser(refreshToken);
router.push("/");
};
const handleDeleteUser = () => {};

return (
<Container>
<Padding>
<Topbar text="마이페이지" />
<Topbar text="마이페이지" icon={false} />
</Padding>
<Background>
<RowContainCard>
Expand Down Expand Up @@ -74,8 +85,8 @@ const Mypage = () => {
</Line>
</ColContainCard>
<ColContainCard>
<div>로그아웃</div>
<Gray>회원탈퇴</Gray>
<LogOut onClick={handleLogout}>로그아웃</LogOut>
<DeleteUser onClick={handleDeleteUser}>회원탈퇴</DeleteUser>
</ColContainCard>
</Background>
<Tabbar />
Expand All @@ -91,6 +102,7 @@ const Container = styled.div`
overflow-x: hidden;
overflow-y: scroll;
position: relative;
padding-top: 20px;
`;

const Padding = styled.div`
Expand Down Expand Up @@ -178,3 +190,11 @@ const DarkGray = styled.div`
const DarkGrayCap = styled(DarkGray)`
${(props) => props.theme.fonts.caption1_r};
`;

const LogOut = styled.div`
cursor: pointer;
`;

const DeleteUser = styled(Gray)`
cursor: pointer;
`;
15 changes: 15 additions & 0 deletions src/app/signin/process1/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { useState } from "react";
import styled from "styled-components";
import { useRouter } from "next/navigation";
import Subtitle from "@/components/signin/Subtitle";
import { useDispatch, useSelector } from "react-redux";
import { setUser } from "@/redux/slices/userSlice";
import { RootState } from "@/redux/store";

const TITLE = "안녕하세요!\n스쿨포인트에 오신 걸 환영해요.";
const CONTEXT =
Expand All @@ -18,11 +21,23 @@ const WARNING =
const SigninProcess1 = () => {
const [phoneNumber, setPhoneNumber] = useState("");
const router = useRouter();
const dispatch = useDispatch();
const user = useSelector((state: RootState) => state.user);

const handlePhoneNumberChange = (value: string) => {
setPhoneNumber(value);
};
const handleNextButtonClick = () => {
const cleanPhoneNumber = phoneNumber.replace(/-/g, "");
dispatch(
setUser({
...user,
phoneNumber: {
number: cleanPhoneNumber,
},
})
);

router.push("/signin/process2");
};

Expand Down
51 changes: 34 additions & 17 deletions src/app/signin/process2/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,52 @@ import Input from "@/components/common/CustomInput";
import Topbar from "@/components/common/Topbar";
import ProgressBar from "@/components/signin/ProgressBar";
import Subtitle from "@/components/signin/Subtitle";
import { setUser } from "@/redux/slices/userSlice";
import { RootState } from "@/redux/store";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import styled from "styled-components";

const CONTEXT = "자녀에 대한 정보를\n알려주세요!";

const SigninProcess2 = () => {
const [name, setName] = useState("");
const [date, setDate] = useState("");
const [sexType, setSexType] = useState("");
const [gender, setgender] = useState("");
const router = useRouter();
const dispatch = useDispatch();
const user = useSelector((state: RootState) => state.user);

const parseAndFormatDate = (dateString: any) => {
const [_, year, month, day] = dateString.match(/(\d+)년 (\d+)월 (\d+)일/);
return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
};

const handleNameChange = (value: string) => {
setName(value);
};
const handleDateChange = (value: string) => {
setDate(value);
};
const handleSexTypeChange = (type: string) => {
setSexType(type);
const handlegenderChange = (type: string) => {
setgender(type);
};
const handleNextButtonClick = () => {
const formattedDate = parseAndFormatDate(date);

dispatch(
setUser({
...user,
children: [
{
name: name,
gender: gender,
birth: formattedDate,
},
],
})
);
router.push("/signin/process3");
};

Expand All @@ -53,21 +77,21 @@ const SigninProcess2 = () => {
<Checkbox
label="남성"
checkboxType="checkBtn"
checked={sexType === "male"}
onChange={() => handleSexTypeChange("male")}
checked={gender === "MALE"}
onChange={() => handlegenderChange("MALE")}
/>
<Checkbox
label="여성"
checkboxType="checkBtn"
checked={sexType === "female"}
onChange={() => handleSexTypeChange("female")}
checked={gender === "FEMALE"}
onChange={() => handlegenderChange("FEMALE")}
/>
</CheckButtonBox>
<Checkbox
label="성별 선택 안 함"
checkboxType="checkbox"
checked={sexType === "sex"}
onChange={() => handleSexTypeChange("sex")}
checked={gender === "NONE"}
onChange={() => handlegenderChange("NONE")}
/>
</div>

Expand All @@ -78,7 +102,7 @@ const SigninProcess2 = () => {
</ContentBox>
<Button
text="다음"
disabled={!name || !sexType || !date}
disabled={!name || !gender || !date}
onClick={handleNextButtonClick}
/>
</Container>
Expand Down Expand Up @@ -114,10 +138,3 @@ const CheckButtonBox = styled.div`
margin-bottom: 12px;
gap: 12px;
`;

const SexNonSelected = styled.div`
${({ theme }) => theme.fonts.body3_m};
color: ${({ theme }) => theme.colors.b500};
margin-top: 12px;
cursor: pointer;
`;
Loading

0 comments on commit 3ec96fc

Please sign in to comment.