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

경북대 FE_이효은 6주차 과제 Step1,2 #33

Open
wants to merge 45 commits into
base: hyoeunkh
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0a0534b
docs: 1단계 구현 내용 작성
Hyoeunkh Aug 1, 2024
c8c3a81
feat: kakao로 로그인하기 api 수정
Hyoeunkh Aug 5, 2024
158395e
feat: GitHub Actions 워크플로우 파일 수정
Hyoeunkh Aug 5, 2024
da1d1c2
fix: homepage 주소 수정
Hyoeunkh Aug 5, 2024
843aa46
fix: homepage 주소 오타 수정..
Hyoeunkh Aug 5, 2024
980e7fd
style: BASE_URL 변수 사용
Hyoeunkh Aug 5, 2024
a6da28b
feat: base href 추가
Hyoeunkh Aug 5, 2024
7249b8f
feat: /react-deploy 경로 변경
Hyoeunkh Aug 5, 2024
a251181
fix: 배포 url 수정 및 navigate 사용
Hyoeunkh Aug 5, 2024
6b3b8f2
style: BASE_URL 인식불가 문제
Hyoeunkh Aug 5, 2024
a8207bf
fix: ROOT_URL 추가
Hyoeunkh Aug 5, 2024
e494e4e
fix: PUBLIC_URL로 변경
Hyoeunkh Aug 5, 2024
a779b8f
feat: 404에러 script 변경으로 해결
Hyoeunkh Aug 5, 2024
144b1f9
feat: kakao login api 주소변경
Hyoeunkh Aug 5, 2024
6bd5ccf
style: api BASE_URL 에러 주석으로 확인
Hyoeunkh Aug 5, 2024
397f9ec
fix: dotenv 추가
Hyoeunkh Aug 5, 2024
6d53d36
feat: .env 개발파일 배포파일 분리
Hyoeunkh Aug 5, 2024
51d068a
remove: dotenv 삭제
Hyoeunkh Aug 5, 2024
467ac0e
feat: 의존성 재설치
Hyoeunkh Aug 5, 2024
706387a
style: dotenv 코드 삭제
Hyoeunkh Aug 5, 2024
21595dd
feat: navigate 다시 변경
Hyoeunkh Aug 5, 2024
0ea3025
feat: 환경변수 설정 추가
Hyoeunkh Aug 5, 2024
606da68
fix: craco env 설정 삭제
Hyoeunkh Aug 5, 2024
b036fdf
feat: BASENAME 추가
Hyoeunkh Aug 5, 2024
625ed7c
feat: bulid scripts 수정
Hyoeunkh Aug 5, 2024
579416a
fix: build scripts 오류 수정
Hyoeunkh Aug 5, 2024
2915433
feat: basename 재설정
Hyoeunkh Aug 5, 2024
d86b255
feat: login시 이동 url 수정
Hyoeunkh Aug 5, 2024
2b04649
feat: html 파일 수정
Hyoeunkh Aug 5, 2024
83781ca
feat: home path 수정
Hyoeunkh Aug 5, 2024
b5f9c90
feat: location을 react router로 변경
Hyoeunkh Aug 5, 2024
ade82e7
fix: home path 재수정
Hyoeunkh Aug 5, 2024
486e2bc
feat: path 수정
Hyoeunkh Aug 5, 2024
2bb85e3
feat: RouterPath로 home 연결
Hyoeunkh Aug 5, 2024
bc8c760
fix: path의 root와 home을 PUBLIC으로 변경
Hyoeunkh Aug 5, 2024
44fb88b
fix: 경로에 PUBLIC을 추가
Hyoeunkh Aug 5, 2024
4b8aa10
fix: Mixed Content 에러 해결을 위해 index.html에 meta 추가
Hyoeunkh Aug 5, 2024
c8ff171
fix: ERR_SSL 에러
Hyoeunkh Aug 6, 2024
2d7a9cd
remove: cloudflare로 재배포를 위한 코드 삭제
Hyoeunkh Aug 6, 2024
b4073d2
remove: cloudflare로 배포를 위한basename 삭제
Hyoeunkh Aug 6, 2024
90091b1
feat: 토큰 유효성 로그 추가
Hyoeunkh Aug 6, 2024
32ee336
test: 토큰 유효성 home 이동 주석처리
Hyoeunkh Aug 6, 2024
9d7a7cd
test: 오류 수정
Hyoeunkh Aug 6, 2024
c172245
test: 주석 해제
Hyoeunkh Aug 6, 2024
5ce400c
docs: 2단계 README 추가
Hyoeunkh Aug 6, 2024
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -15,8 +15,10 @@
.DS_Store
.env.local
.env.development.local
.env.development
.env.test.local
.env.production.local
.env.production

npm-debug.log*
yarn-debug.log*
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
# 카카오 테크 캠퍼스 - 프론트엔드 카카오 선물하기 편

## 1단계 - API 명세 협의 & 반영
1. 카카오로 로그인하기 버튼 생성
2. 옵션 선택으로 변경
3. 주문 목록 페이지 구현
4. 수정된 API 반영

## 2단계 - 배포
5. cloudflare로 배포
2 changes: 1 addition & 1 deletion craco.config.js
Original file line number Diff line number Diff line change
@@ -13,4 +13,4 @@ module.exports = {
},
},
},
};
};
8,115 changes: 3,619 additions & 4,496 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -31,7 +31,9 @@
"@emotion/styled": "^11.11.0",
"@tanstack/react-query": "^5.24.1",
"axios": "^1.6.7",
"env-cmd": "^10.1.0",
"framer-motion": "^11.0.6",
"gh-pages": "^6.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.12",
@@ -54,7 +56,7 @@
"@storybook/react-webpack5": "^7.6.17",
"@storybook/test": "^7.6.17",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.104",
4 changes: 1 addition & 3 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<!DOCTYPE html>
<!doctype html>
<html lang="ko">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -11,5 +10,4 @@
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>

</html>
60 changes: 60 additions & 0 deletions src/api/hooks/orderList.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { rest } from 'msw';

import { BASE_URL } from '../instance';

import type { OrderlistResponse } from '@/types';

export const orderlistMockHandler = [
rest.get(`${BASE_URL}/api/orders`, (_, res, ctx) => {
return res(ctx.status(200), ctx.json(WISHLIST_RESPONSE_DATA));
}),
];

const WISHLIST_RESPONSE_DATA: OrderlistResponse = {
content: [
{
name: 'Product A',
price: 100,
quantity: 2,
imageUrl:
'https://img1.daumcdn.net/thumb/S104x104/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fgift%2Fhome%2Ftheme%2F292020231106_MXMUB.png',
orderDateTime: '2024-07-20',
},
{
name: 'Product B',
price: 10000,
quantity: 50,
imageUrl:
'https://img1.daumcdn.net/thumb/S104x104/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fgift%2Fhome%2Ftheme%2F292020231106_MXMUB.png',
orderDateTime: '2024-07-20',
},
{
name: 'Product C',
price: 1200,
quantity: 20,
imageUrl:
'https://img1.daumcdn.net/thumb/S104x104/?fname=https%3A%2F%2Ft1.daumcdn.net%2Fgift%2Fhome%2Ftheme%2F292020231106_MXMUB.png',
orderDateTime: '2024-07-21',
},
],
pageable: {
sort: {
sorted: true,
unsorted: false,
empty: false,
},
pageNumber: 0,
pageSize: 10,
offset: 0,
unpaged: false,
paged: true,
},
totalPages: 5,
totalElements: 50,
last: false,
number: 0,
size: 10,
numberOfElements: 2,
first: true,
empty: false,
};
71 changes: 71 additions & 0 deletions src/api/hooks/useGetOrderList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { type InfiniteData, useInfiniteQuery, type UseInfiniteQueryResult } from '@tanstack/react-query';

import { BASE_URL } from '../instance';
import { fetchInstance } from './../instance/index';

import type { OrderListData } from '@/types';
import { authSessionStorage } from '@/utils/storage';

type RequestParams = {
pageToken?: string;
maxResults?: number;
};

type OrderListsResponseData = {
products: OrderListData[];
nextPageToken?: string;
pageInfo: {
totalResults: number;
resultsPerPage: number;
};
};

type OrderListsResponseRawData = {
content: OrderListData[];
number: number;
totalElements: number;
size: number;
last: boolean;
};

export const getOrderListPath = ({ pageToken, maxResults }: RequestParams) => {
const params = new URLSearchParams();

if (pageToken) params.append('page', pageToken);
if (maxResults) params.append('size', maxResults.toString());
params.append('sort', 'orderDateTime,desc');

return `${BASE_URL}/api/orders?${params.toString()}`;
};

export const getOrderLists = async (params: RequestParams): Promise<OrderListsResponseData> => {
const response = await fetchInstance.get<OrderListsResponseRawData>(getOrderListPath(params), {
headers: {
Authorization: `Bearer ${authSessionStorage.get()?.token}`,
},
});
const data = response.data;
return {
products: data.content,
nextPageToken: data.last === false ? (data.number + 1).toString() : undefined,
pageInfo: {
totalResults: data.totalElements,
resultsPerPage: data.size,
},
};
};

type Params = Pick<RequestParams, 'maxResults'> & { initPageToken?: string };
export const useGetOrderList = ({
maxResults = 10,
initPageToken,
}: Params): UseInfiniteQueryResult<InfiniteData<OrderListsResponseData>> => {
return useInfiniteQuery({
queryKey: ['orderLists', maxResults, initPageToken],
queryFn: async ({ pageParam = initPageToken }) => {
return getOrderLists({ pageToken: pageParam, maxResults });
},
initialPageParam: initPageToken,
getNextPageParam: (lastPage) => lastPage.nextPageToken,
});
};
4 changes: 2 additions & 2 deletions src/api/hooks/useGetProducts.ts
Original file line number Diff line number Diff line change
@@ -31,10 +31,10 @@ type ProductsResponseRawData = {
export const getProductsPath = ({ categoryId, pageToken, maxResults }: RequestParams) => {
const params = new URLSearchParams();

params.append('categoryId', categoryId);
params.append('sort', 'name,asc');
if (pageToken) params.append('page', pageToken);
if (maxResults) params.append('size', maxResults.toString());
params.append('sort', 'name,asc');
params.append('categoryId', categoryId);

return `${BASE_URL}/api/products?${params.toString()}`;
};
3 changes: 1 addition & 2 deletions src/api/hooks/useGetWishList.ts
Original file line number Diff line number Diff line change
@@ -22,10 +22,9 @@ type WishListResponseData = {
export const getWishListPath = ({ pageToken, maxResults }: RequestParams) => {
const params = new URLSearchParams();

params.append('sort', 'name,asc');
if (pageToken) params.append('page', pageToken);
if (maxResults) params.append('size', maxResults.toString());

params.append('sort', 'createdDate,desc');
return `${BASE_URL}/api/wishes?${params.toString()}`;
};

33 changes: 33 additions & 0 deletions src/api/hooks/useOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useMutation } from '@tanstack/react-query';

import { BASE_URL, fetchInstance } from '../instance';

import { authSessionStorage } from '@/utils/storage';

type OrderRequestData = {
productId: number;
optionId: number;
quantity: number;
message: string;
};
const postOrder = async ({ productId, optionId, quantity, message }: OrderRequestData) => {
const response = await fetchInstance.post(`${BASE_URL}/api/orders`, {
headers: {
Authorization: `Bearer ${authSessionStorage.get()?.token}`,
},
body: {
productId: productId,
optionId: optionId,
quantity: quantity,
message: message,
},
});
return response.data;
};

export const useOrder = () => {
return useMutation({
mutationFn: ({ productId, optionId, quantity, message }: OrderRequestData) =>
postOrder({ productId, optionId, quantity, message }),
});
};
14 changes: 4 additions & 10 deletions src/api/hooks/usePostWishs.ts
Original file line number Diff line number Diff line change
@@ -5,17 +5,11 @@ import { BASE_URL, fetchInstance } from '../instance';
import { authSessionStorage } from '@/utils/storage';

const postWishs = async (productId: number) => {
const response = await fetchInstance.post(
`${BASE_URL}/api/wishes`,
{
productId,
const response = await fetchInstance.post(`${BASE_URL}/api/wishes/${productId}`, {
headers: {
Authorization: `Bearer ${authSessionStorage.get()?.token}`,
},
{
headers: {
Authorization: `Bearer ${authSessionStorage.get()?.token}`,
},
},
);
});
return response.data;
};

6 changes: 2 additions & 4 deletions src/api/instance/index.ts
Original file line number Diff line number Diff line change
@@ -12,14 +12,12 @@ const initInstance = (config: AxiosRequestConfig): AxiosInstance => {
...config.headers,
},
});

return instance;
};

export const BASE_URL = 'https://api.example.com';
// TODO: 추후 서버 API 주소 변경 필요
export const BASE_URL = process.env.REACT_APP_API;
export const fetchInstance = initInstance({
baseURL: 'https://api.example.com',
baseURL: process.env.REACT_APP_API,
});
Comment on lines -20 to 21
Copy link

Choose a reason for hiding this comment

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

바로 위에 상수를 선언했는데 다시 env를 참조하고 있네요...?

Copy link
Author

Choose a reason for hiding this comment

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

수정했습니다 감사합니다!


export const queryClient = new QueryClient({
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ type Props = {
onChange: (value: string) => void;
};

export const CountOptionItem = ({ name, minValues = 1, maxValues = 100, value, onChange }: Props) => {
export const CountOptionItem = ({ name = '수량', minValues = 1, maxValues = 100, value, onChange }: Props) => {
const { getInputProps, getIncrementButtonProps, getDecrementButtonProps } = useNumberInput({
step: 1,
min: minValues,
58 changes: 58 additions & 0 deletions src/components/features/Goods/Detail/OptionItem/OptionSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Select } from '@chakra-ui/react';
import styled from '@emotion/styled';
import { Controller, useFormContext } from 'react-hook-form';

import type { ProductOptionsResponseData } from '@/api/hooks/useGetProductOptions';
import type { ProductOptionsData } from '@/types';

interface OptionSelectProps {
options: ProductOptionsResponseData;
}

export const OptionSelect = ({ options }: OptionSelectProps) => {
const { control, setValue, watch } = useFormContext();

// Watch the current selected option id
const selectedOptionId = watch('optionSelectId');

const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const selectedId = e.target.value;
const selectedOption = options.find((option) => option.id === parseInt(selectedId));
setValue('optionSelectId', selectedId); // Update only the id
setValue('optionSelect', selectedOption); // Set the entire option object
};

return (
<Wrapper>
<Title>옵션</Title>
<Controller
name="optionSelectId"
control={control}
render={({ field }) => (
<Select {...field} placeholder="옵션을 선택하세요" onChange={handleChange} value={selectedOptionId || ''}>
{options.map((option: ProductOptionsData) => (
<option key={option.id} value={option.id}>
{option.name}
</option>
))}
</Select>
)}
/>
</Wrapper>
);
};

const Wrapper = styled.div`
width: 100%;
padding: 12px 14px 16px;
border: 1px solid #ededed;
border-radius: 2px;
`;

const Title = styled.p`
font-weight: 700;
line-height: 22px;
color: #111;
word-wrap: break-word;
word-break: break-all;
`;
Loading