Skip to content

Commit

Permalink
Merge pull request #295 from leehj322/Next-이형준-sprint10
Browse files Browse the repository at this point in the history
[이형준]sprint10
  • Loading branch information
jyh0521 authored Aug 19, 2024
2 parents 3e3478a + eb8ebdc commit 349d012
Show file tree
Hide file tree
Showing 35 changed files with 984 additions and 152 deletions.
4 changes: 4 additions & 0 deletions public/images/ic_back_arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/ic_kebab_btn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/ic_register_img_file.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/img_del_btn_default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/img_no_comments.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 0 additions & 48 deletions src/apis/getArticles.ts

This file was deleted.

7 changes: 0 additions & 7 deletions src/apis/instance.ts

This file was deleted.

86 changes: 86 additions & 0 deletions src/axios/articles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import axiosInstance from "./instance";

interface Writer {
id: number;
nickname: string;
}

export interface Article {
id: number;
title: string;
content: string;
image: string | null;
likeCount: number;
writer: Writer;
createdAt: string;
updatedAt: string;
}

export type OrderOption = "like" | "recent";

interface GetArticlesProps {
page?: number;
pageSize: number;
orderBy?: OrderOption;
keyword?: string;
}

interface ArticlesResponse {
list: Article[];
totalCount: number;
}

export async function getArticles({
page = 1,
pageSize,
orderBy = "recent",
keyword = "",
}: GetArticlesProps) {
let query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}`;
if (keyword) {
query += `&keyword=${keyword}`;
}

try {
const res = await axiosInstance.get(`/articles?${query}`);
const { list, totalCount }: ArticlesResponse = res.data;
return { list, totalCount };
} catch (error) {
return { list: [], totalCount: 0 };
}
}

interface GetArticleByIDProps {
articleId: number;
}

export async function getArticleByID({ articleId }: GetArticleByIDProps) {
const res = await axiosInstance.get(`/articles/${articleId}`);
try {
const article: Article = res.data;
return article;
} catch {
throw new Error("게시글 응답이 올바르지 않습니다.");
}
}

export interface PostArticleProps {
image: string | null;
content: string;
title: string;
}

export async function postArticle({ image, content, title }: PostArticleProps) {
try {
let res;
if (image) {
res = await axiosInstance.post("/articles", { image, content, title });
} else {
res = await axiosInstance.post("/articles", { content, title });
}
const postedArticle: Article = res.data;
return postedArticle;
} catch (error) {
console.log(error);
}
}
47 changes: 47 additions & 0 deletions src/axios/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import axiosInstance from "./instance";

export interface LogInUserProps {
email: string;
password: string;
}

export interface SignUpUserProps extends LogInUserProps {
nickname: string;
passwordConfirmation: string;
}

export async function signUpUser({
email,
nickname,
password,
passwordConfirmation,
}: SignUpUserProps) {
try {
const res = await axiosInstance.post("/auth/signUp", {
email,
nickname,
password,
passwordConfirmation,
});
const { accessToken, refreshToken } = res.data;

localStorage.setItem("access_token", accessToken);
localStorage.setItem("refresh_token", refreshToken);
window.location.href = "/";
} catch (error) {
console.log(error);
}
}

export async function logInUser({ email, password }: LogInUserProps) {
try {
const res = await axiosInstance.post("/auth/signIn", { email, password });
const { accessToken, refreshToken } = res.data;

localStorage.setItem("access_token", accessToken);
localStorage.setItem("refresh_token", refreshToken);
window.location.href = "/";
} catch (error) {
console.log(error);
}
}
46 changes: 46 additions & 0 deletions src/axios/comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import axiosInstance from "./instance";

interface Writer {
id: number;
image: string;
nickname: string;
}

export interface Comment {
id: number;
content: string;
updatedAt: string;
createdAt: string;
writer: Writer;
}

interface GetArticleCommentsProps {
articleId: number;
limit: number;
cursor?: number;
}

export interface ArticleCommentsResponse {
nextCursor: number | null;
list: Comment[];
}

export async function getArticleComments({ articleId, limit, cursor }: GetArticleCommentsProps) {
let query = `limit=${limit}`;
if (cursor) {
query += `&cursor=${cursor}`;
}
const res = await axiosInstance.get(`/articles/${articleId}/comments?${query}`);
const { nextCursor, list }: ArticleCommentsResponse = res.data;
return { nextCursor, list };
}

interface PostArticleCommentProps {
articleId: number;
content: string;
}

export async function postArticleComment({ articleId, content }: PostArticleCommentProps) {
const res = await axiosInstance.post(`/articles/${articleId}/comments`, { content });
return res.data as Comment;
}
21 changes: 21 additions & 0 deletions src/axios/images.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import axiosInstance from "./instance";

interface UploadImageProps {
imageFile: File;
}

export default async function uploadImage({ imageFile }: UploadImageProps) {
// image file을 form data로 변경
const formDataForSubmit = new FormData();
formDataForSubmit.append("image", imageFile);

try {
const res = await axiosInstance.post("/images/upload", formDataForSubmit, {
headers: { "Content-Type": "multipart/form-data" },
});
const { url } = res.data;
return url;
} catch (error) {
console.log(error);
}
}
74 changes: 74 additions & 0 deletions src/axios/instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import axios, { AxiosResponse, AxiosError, InternalAxiosRequestConfig } from "axios";

const axiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});

/**
* http request가 넘어가기 전에 call 되는 함수
*/
const onRequest = (config: InternalAxiosRequestConfig) => {
if (typeof window !== "undefined") {
const accessToken = localStorage.getItem("access_token");

if (accessToken && config.headers) {
config.headers["Authorization"] = `Bearer ${accessToken}`;
}
}
return config;
};

/**
* http response가 catch로 넘어가기 전에 call 되는 함수
*/
const onErrorResponse = async (error: AxiosError | Error) => {
if (axios.isAxiosError(error)) {
const { status, data, config } = error.response as AxiosResponse;

switch (status) {
case 400: {
alert("입력한 정보가 올바르지 않습니다.");
break;
}

case 401: {
const refreshToken = localStorage.getItem("refresh_token");

if (refreshToken) {
if (data.message === "jwt expired") {
const res = await axiosInstance.post("/auth/refresh-token", { refreshToken });
const { accessToken } = res.data;

localStorage.setItem("access_token", accessToken);

config.headers["Authorization"] = `Bearer ${accessToken}`;
return axiosInstance(config);
} else if (data.message === "jwt malformed") {
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
alert("세션이 올바르지 않습니다. 다시 로그인 해주세요.");
window.location.href = "/login";
} else {
console.log(data.message);
}
} else {
alert("로그인이 필요합니다.");
window.location.href = "/login";
}
break;
}

default: {
console.log(error.message);
break;
}
}
}

return Promise.reject(error);
};

axiosInstance.interceptors.request.use(onRequest);
axiosInstance.interceptors.response.use((response: AxiosResponse) => response, onErrorResponse);

export default axiosInstance;
3 changes: 2 additions & 1 deletion src/components/@shared/BlueButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
* @param shape default(0.5rem), pill(알약형) 중 한가지 선택
* @returns 공통 스타일 버튼 컴포넌트
*/
export default function BlueButton({ customStyle, shape, children }: ButtonProps) {
export default function BlueButton({ customStyle, shape, children, ...rest }: ButtonProps) {
return (
<button
{...rest}
className={`${customStyle} ${
shape === "pill" ? "rounded-full" : "rounded-lg"
} flex justify-center items-center gap-2 w-full h-full font-semibold bg-brand-blue text-gray-100 hover:bg-blue-hover active:bg-blue-active disabled:bg-gray-400 `}
Expand Down
Loading

0 comments on commit 349d012

Please sign in to comment.