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

Next 엄성민 스프린트 미션 9 #59

Open
wants to merge 57 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
575a87a
chore: pr 템플릿 & 머지 후 브랜치 삭제 github action 추가
shyjnnn Jul 28, 2024
13fbcd6
remove: delete github actions
shyjnnn Sep 5, 2024
43c8329
feat: add: auto-labeling and assignee for PRs
shyjnnn Sep 5, 2024
5b1fbb2
docs: update fe readme
sprint-edu Sep 5, 2024
f375c0d
Initial commit from Create Next App
eomsung Jan 10, 2025
f42d8be
wip
eomsung Jan 13, 2025
f580baf
readme update
eomsung Jan 13, 2025
9ed97eb
wip
eomsung Jan 13, 2025
a0def70
Merge branch 'main' of https://github.com/eomsung/4-sprint-mission-fe…
eomsung Jan 13, 2025
2afffe7
test
eomsung Jan 13, 2025
78a9246
tst
eomsung Jan 13, 2025
4620060
make freeBoard page
eomsung Jan 13, 2025
e96ead8
add articlepage, add comment function
eomsung Jan 13, 2025
c02cdf1
add button active
eomsung Jan 13, 2025
520590a
add create article
eomsung Jan 13, 2025
59529d3
add edit/delete function in artcle
eomsung Jan 14, 2025
a72aed8
add edit/delete comment function
eomsung Jan 14, 2025
3d4afc3
add responsive css
eomsung Jan 14, 2025
806ce0d
change baseURL
eomsung Jan 14, 2025
1770d3d
edit
eomsung Jan 14, 2025
4abfb8e
add cancel button in comment edit
eomsung Jan 14, 2025
12d7985
wip homepage
eomsung Jan 14, 2025
9c1afc7
change baseURL
eomsung Jan 14, 2025
d9b473f
feat: mainpage
eomsung Jan 15, 2025
98196eb
add loginpage ui
eomsung Jan 15, 2025
2ac74c5
refactoring : change the name freemarket to artocles
eomsung Jan 15, 2025
47a340b
refactor
eomsung Jan 15, 2025
ad6016a
refactor
eomsung Jan 15, 2025
d3aea30
add windowsize hook
eomsung Jan 15, 2025
f0d87b2
add windowsize hook
eomsung Jan 15, 2025
323c106
edit useDivicesize
eomsung Jan 15, 2025
f935598
edit baseurl
eomsung Jan 21, 2025
a920db3
add AuthContext
eomsung Jan 21, 2025
7395aad
add Tokens
eomsung Jan 21, 2025
732259f
add login/signup error message modal
eomsung Jan 22, 2025
9717752
add visible button
eomsung Jan 22, 2025
774e545
edit dropdown menu add itemdetailpage
eomsung Jan 23, 2025
1289f04
add delete/edit comment function
eomsung Jan 24, 2025
e4f69fd
wip
eomsung Jan 24, 2025
344df1c
add delete modal in product
eomsung Jan 24, 2025
6cdf904
edit typo
eomsung Jan 24, 2025
63b4594
edit signup and add favorite function
eomsung Jan 24, 2025
cb555b6
add responsive css
eomsung Jan 24, 2025
d1a24cc
add editPage in Product
eomsung Jan 27, 2025
109a25f
add type Number in price
eomsung Jan 27, 2025
ddda900
refactoring
eomsung Jan 27, 2025
6770243
refactoring
eomsung Jan 27, 2025
5dfef77
add check login
eomsung Jan 27, 2025
8d30c9b
wip
eomsung Jan 27, 2025
514c0af
wip
eomsung Jan 27, 2025
45adc1c
wip
eomsung Jan 27, 2025
9d5b73f
edit typo
eomsung Jan 27, 2025
fc9f2f0
test
eomsung Jan 27, 2025
ee12ff9
add intercept and stale time
eomsung Feb 3, 2025
884c044
add refetchInterval
eomsung Feb 3, 2025
8d34b68
edti
eomsung Feb 3, 2025
0322a26
edit useEffect in itemDetailpage
eomsung Feb 3, 2025
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
4 changes: 4 additions & 0 deletions .github/pull-request-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
### 기본

- [x]
<<<<<<< HEAD
- [테스트s]
=======
- []
>>>>>>> upstream/next-엄성민
- []

### 심화
Expand Down
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ _위 이미지는 판다마켓의 대표 이미지입니다._ 📸
- **스프린트 미션 8부터** 시작하는 프론트엔드 내용을 포함하고 있어요.
- 만약 스프린트 미션 9부터 프론트엔드 코드를 React가 아닌 Next로 구현하고 싶다면 next 브랜치를 사용해요.

<<<<<<< HEAD
> _스프린트 미션 내 백엔드 요구사항은 [백엔드 레포지토리](https://github.com/codeit-sprint-fullstack/4-sprint-mission-be)의 브랜치에서 관리해주세요_
=======
> _스프린트 미션 내 백엔드 요구사항은 [백엔드 레포지토리](https://github.com/codeit-sprint-fullstack/2-Sprint-mission-Be)의 브랜치에서 관리해주세요_
>>>>>>> upstream/next-엄성민

---

Expand Down
254 changes: 254 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
import config from "@/postcss.config.mjs";
import axios from "axios";
import { jwtDecode } from "jwt-decode";

// const baseURL = "http://localhost:3100";
const baseURL = "https://four-sprint-mission-be-1.onrender.com";

const client = axios.create({
baseURL,
});

// 게시글 관련 api
const getArticles = async (keyword = "", order = "recent") => {
const options = {
params: {
keyword,
orderBy: order,
},
};
const url = `/article`;
const response = await client.get(url, options);
const data = response.data;
return data;
};

const getArticle = async (id) => {
const url = `/article/${id}`;
const response = await client.get(url);
const data = response.data;
return data;
};

const createArticle = async (newArticle) => {
const url = `/article`;
const response = await client.post(url, newArticle);
const data = response.data;
return data;
};

const deleteArticle = async (id) => {
const url = `/article/${id}`;
const response = await client.delete(url);
const data = response.data;
return data;
};

const patchArticle = async (id, article) => {
const url = `/article/${id}`;
const response = await client.patch(url, article);
const data = response.data;
return data;
};

const createCommentInArticle = async (id, content) => {
const url = `/article/${id}/comment`;
const response = await client.post(url, { content });
const data = response.data;
return data;
};

const getCommentsinArticle = async (id) => {
const url = `article/${id}/comments`;
const response = await client.get(url);
const data = response.data;
return data;
};

const deleteCommentInArticle = async (id) => {
const url = `article/${id}/comment`;
const response = await client.delete(url);
const data = response.data;
return data;
};

const patchCommentInArticle = async (id, content) => {
const url = `article/${id}/comment`;
const response = await client.patch(url, { content });
const data = response.data;
return data;
};

// 상품 관련 api
const getProducts = async () => {
const url = "/products";
const response = await client.get(url);
const data = response.data;
return data;
};

// 로그인 관련 api
const codeitURL = "https://panda-market-api.vercel.app";

export const codeitClient = axios.create({
baseURL: codeitURL,
});

codeitClient.interceptors.request.use(async (config) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

access token 은 매번 발급받는게 아닙니다

최초 발급된 이후 localStorage 에 저장한 후에 만약 만료가 되었다면 refersh token 을 통해 다시 재발급을 해주고 활용하는 방식으로 처리하는걸 권장드립니다

if (config.url === "/auth/refresh-token") return config;
const Authorization = config.headers.Authorization || "";
const accessToken = Authorization.split("Bearer ")[1];

if (!accessToken) return config;

const { exp } = jwtDecode(accessToken);
Copy link
Collaborator

Choose a reason for hiding this comment

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

decode 하다가 예외가 발생 할 수 있으니 try-catch 로 한번 감싸주시는걸 권장드립니다!

if (exp * 1000 >= Date.now()) return config;

const prevRefreshToken = localStorage.getItem("refreshToken");
const { accessToken: newAccessToken } = await api.refreshToken(
prevRefreshToken
);
config.headers.Authorization = `Bearer ${newAccessToken}`;

return config;
});

const signUp = async (dto) => {
const url = "/auth/signUp";
const response = await codeitClient.post(url, dto);
const data = response.data;

const { accessToken, refreshToken } = data;
codeitClient.defaults.headers.Authorization = `Bearer ${accessToken}`;
localStorage.setItem("refreshToken", refreshToken);
return data;
};

const logIn = async (dto) => {
const url = "/auth/signIn";
const response = await codeitClient.post(url, dto);
const data = response.data;

const { accessToken, refreshToken } = data;
codeitClient.defaults.headers.Authorization = `Bearer ${accessToken}`;
localStorage.setItem("refreshToken", refreshToken);

return data;
};

const refreshToken = async (prevRefreshToken) => {
const url = "/auth/refresh-token";
const response = await codeitClient.post(url, {
refreshToken: prevRefreshToken,
});
const data = response.data;
const { accessToken } = data;
codeitClient.defaults.headers.Authorization = `Bearer ${accessToken}`;

return data;
};

// 유저정보 관련
const getUserData = async () => {
const url = "/users/me";
const response = await codeitClient.get(url);
const data = response.data;
return data;
};

// product
const getProduct = async (productId) => {
const url = `/products/${productId}`;
const response = await codeitClient.get(url);
const data = response.data;
return data;
};

const deleteProduct = async (productId) => {
const url = `/products/${productId}`;
const response = await codeitClient.delete(url);
const data = response.data;
return data;
};

const patchProduct = async (productId, dto) => {
const url = `/products/${productId}`;
const response = await codeitClient.patch(url, dto);
const data = response.data;
return data;
};

const getCommentsInProduct = async (productId, limit = 10) => {
const options = {
params: {
limit,
},
};
const url = `/products/${productId}/comments`;
const response = await codeitClient.get(url, options);
const data = response.data;
return data;
};

const deleteCommentInProduct = async (commentId) => {
const url = `/comments/${commentId}`;
const response = await codeitClient.delete(url);
const data = response.data;
return data;
};

const patchCommentInProduct = async (commentId, content) => {
const url = `/comments/${commentId}`;
const response = await codeitClient.patch(url, { content });
const data = response.data;
return data;
};

const createCommentInProduct = async (productId, content) => {
const url = `/products/${productId}/comments`;
const response = await codeitClient.post(url, { content });
const data = response.data;
return data;
};

const createFavoriteProduct = async (productId) => {
const url = `/products/${productId}/favorite`;
const response = await codeitClient.post(url);
const data = response.data;
return data;
};

const deleteFavoriteProduct = async (productId) => {
const url = `/products/${productId}/favorite`;
const response = await codeitClient.delete(url);
const data = response.data;
return data;
};

const api = {
getArticles,
getArticle,
createArticle,
deleteArticle,
patchArticle,
createCommentInArticle,
getCommentsinArticle,
deleteCommentInArticle,
patchCommentInArticle,
getProducts,
signUp,
logIn,
refreshToken,
getUserData,
getProduct,
deleteProduct,
patchProduct,
getCommentsInProduct,
deleteCommentInProduct,
patchCommentInProduct,
createCommentInProduct,
createFavoriteProduct,
deleteFavoriteProduct,
};

export default api;
22 changes: 22 additions & 0 deletions app/(provider)/(auth)/_components/ErrorModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use client";

import Button from "@/components/Button";
import Modal from "@/components/Modal";
import { useModal } from "@/contexts/ModalContext";

function LoginErrorModal({ children }) {
const modal = useModal();
return (
<Modal>
<div className="text-[18px] font-medium text-nowrap">{children}</div>
<Button
onClick={modal.close}
className="w-[120px] h-[48px] rounded-lg py-3 px-[23px] md:w-[165px]"
>
확인
</Button>
</Modal>
);
}

export default LoginErrorModal;
Loading