Skip to content

Commit

Permalink
부산대 FE 김도균 Week6 마지막 (#119)
Browse files Browse the repository at this point in the history
* fix : (blocked:mixed-content) 해결

* fix : use http

* Revert "fix : default url"

This reverts commit 806d0e0.

* fix : api default url

* feat : 주문내역 및 포인트 api 연결

* docs : 질문 답변
  • Loading branch information
jasper200207 authored Aug 8, 2024
1 parent 656c314 commit 21a6348
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 110 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
# react-deploy
# react-deploy

### 질문 1. SPA 페이지를 정적 배포를 하려고 할 때 Vercel을 사용하지 않고 한다면 어떻게 할 수 있을까요?

- `npm run build`를 통해 빌드된 파일을 정적 호스팅 서비스에 업로드하면 됩니다.
- AWS S3, Github Pages 등을 사용할 수 있습니다.
- 빌드된 파일을 서버에 올리는 방법은 다음과 같습니다.
- AWS S3: S3 버킷을 생성하고 빌드된 파일을 업로드합니다.
- Github Pages: Github 저장소에 빌드된 파일을 업로드합니다.

### 질문 2. CSRF나 XSS 공격을 막는 방법은 무엇일까요?

- CSRF(Cross-Site Request Forgery) 공격을 막는 방법

- CSRF 토큰을 사용합니다.
- SameSite 쿠키 속성을 사용합니다.
- Referer 검증을 사용합니다.
- 사용자의 동작을 요구하는 방식을 사용합니다.

- XSS(Cross-Site Scripting) 공격을 막는 방법
- 사용자 입력값을 필터링합니다.
- 사용자 입력값을 필터링하여 스크립트를 실행할 수 없도록 합니다.
- 사용자 입력값을 HTML 엔티티로 변환하여 스크립트를 실행할 수 없도록 합니다.
- 사용자 입력값을 JavaScript Escape하여 스크립트를 실행할 수 없도록 합니다.

### 질문 3. 브라우저 렌더링 원리에대해 설명해주세요.

- 브라우저 렌더링 원리
- HTML 문서를 파싱하여 DOM 트리를 생성합니다.
- CSS 스타일을 파싱하여 CSSOM 트리를 생성합니다.
- DOM 트리와 CSSOM 트리를 결합하여 렌더 트리를 생성합니다.
- 렌더 트리를 기반으로 레이아웃을 계산합니다.
- 레이아웃을 기반으로 픽셀을 그리고 화면에 표시합니다.
2 changes: 1 addition & 1 deletion src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const sessionStorageApiWithAuth = (token: string) => {
baseURL: apiSessionStorage.get(),
headers: {
'Content-Type': 'application/json',
Authorization: token,
Authorization: 'Bearer ' + token,
},
});
};
Expand Down
29 changes: 29 additions & 0 deletions src/api/hooks/useGetOrderPrice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { UseQueryResult } from '@tanstack/react-query';

import { useAxiosQuery } from '@/api';
import type { GetOrderPriceResponseBody } from '@/api/type';
type RequestParams = {
optionId: string;
quantity: number;
productId: string;
};

export function getOrderPricePath({ optionId, quantity, productId }: RequestParams): string {
return `/api/orders/price?optionId=${optionId}&quantity=${quantity}&productId=${productId}`;
}

function useGetOrderPrice({
optionId,
quantity,
productId,
}: RequestParams): UseQueryResult<GetOrderPriceResponseBody> {
return useAxiosQuery<GetOrderPriceResponseBody>(
{
method: 'GET',
url: getOrderPricePath({ optionId, quantity, productId }),
},
['orderPrice', optionId, quantity.toString(), productId],
);
}

export default useGetOrderPrice;
34 changes: 34 additions & 0 deletions src/api/hooks/useGetOrders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { UseAxiosQueryWithPageResult } from '@/api';
import { useAxiosQueryWithPage } from '@/api';
import { sessionStorageApiWithAuth } from '@/api/axiosInstance';
import type { GetOrdersResponseBody } from '@/api/type';
import { authSessionStorage } from '@/utils/storage';

type RequestParams = {
size?: number;
page?: number;
sort?: string;
};

export function getOrdersPath({ size, sort }: RequestParams): string {
return `/api/orders?size=${size}&sort=${sort}`;
}

function useGetOrders({
size = 20,
sort = 'id,desc',
}: RequestParams): UseAxiosQueryWithPageResult<GetOrdersResponseBody> {
const token = authSessionStorage.get()?.token ?? '';

return useAxiosQueryWithPage<GetOrdersResponseBody>(
{
method: 'GET',
url: getOrdersPath({ size, sort }),
},
['orders'],
(lastPage) => (!lastPage.last ? (lastPage.number + 1).toString() : undefined),
sessionStorageApiWithAuth(token),
);
}

export default useGetOrders;
26 changes: 26 additions & 0 deletions src/api/hooks/useGetPoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { UseQueryResult } from '@tanstack/react-query';

import { useAxiosQuery } from '@/api';
import { sessionStorageApiWithAuth } from '@/api/axiosInstance';
import type { GetPointResponseBody } from '@/api/type';
import { authSessionStorage } from '@/utils/storage';

export function getPointPath(): string {
return '/api/members/point';
}

function useGetPoint(): UseQueryResult<GetPointResponseBody> {
const token = authSessionStorage.get()?.token ?? '';

return useAxiosQuery<GetPointResponseBody>(
{
method: 'GET',
url: getPointPath(),
},
['point'],
{},
sessionStorageApiWithAuth(token),
);
}

export default useGetPoint;
13 changes: 7 additions & 6 deletions src/api/hooks/useGetProducts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@ import type { GetCategoriesProductsResponseBody } from '@/api/type';

type RequestParams = {
categoryId: string;
maxResults?: number;
initPageToken?: string;
size?: number;
page?: number;
sort?: string;
};

export function getProductsPath({ categoryId, maxResults }: RequestParams): string {
return `/api/products?categoryId=${categoryId}` + (maxResults ? `&maxResults=${maxResults}` : '');
export function getProductsPath({ categoryId, size, sort = 'id,desc' }: RequestParams): string {
return `/api/products?categoryId=${categoryId}` + (size ? `&size=${size}` : '') + `&sort=${sort}`;
}

function useGetProducts({
categoryId,
maxResults = 20,
size = 20,
}: RequestParams): UseAxiosQueryWithPageResult<GetCategoriesProductsResponseBody> {
return useAxiosQueryWithPage<GetCategoriesProductsResponseBody>(
{
method: 'GET',
url: getProductsPath({ categoryId, maxResults }),
url: getProductsPath({ categoryId, size }),
},
['products', categoryId],
(lastPage) => (!lastPage.last ? (lastPage.number + 1).toString() : undefined),
Expand Down
7 changes: 5 additions & 2 deletions src/api/hooks/useGetWishes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function getWishesPath({ size, sort }: RequestParams): string {

function useGetWishes({
size = 10,
sort = 'createdDate,desc',
sort = 'id,desc',
}: RequestParams): UseAxiosQueryWithPageResult<GetWishesResponseBody> {
const token = authSessionStorage.get()?.token ?? '';

Expand All @@ -25,7 +25,10 @@ function useGetWishes({
url: getWishesPath({ size, sort }),
},
['wishes'],
(lastPage) => (!lastPage.last ? (lastPage.number + 1).toString() : undefined),
(lastPage) =>
lastPage.last !== undefined && !lastPage.last
? (lastPage?.number || 0 + 1).toString()
: undefined,
sessionStorageApiWithAuth(token),
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/api/hooks/usePostLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useAxiosMutation } from '@/api';
import type { PostLoginRequestBody, PostLoginResponseBody } from '@/api/type';

export function getLoginPath(): string {
return '/api/login';
return '/api/members/login';
}

function usePostLogin(): UseAxiosMutationResult<PostLoginResponseBody, PostLoginRequestBody> {
Expand Down
23 changes: 23 additions & 0 deletions src/api/hooks/usePostOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { UseAxiosMutationResult } from '@/api';
import { useAxiosMutation } from '@/api';
import { sessionStorageApiWithAuth } from '@/api/axiosInstance';
import type { PostOrderRequestBody } from '@/api/type';
import { authSessionStorage } from '@/utils/storage';

export function postOrderPath(): string {
return '/api/orders';
}

function usePostOrder(): UseAxiosMutationResult<void, PostOrderRequestBody> {
const token = authSessionStorage.get()?.token ?? '';

return useAxiosMutation<void, PostOrderRequestBody>(
{
method: 'POST',
url: postOrderPath(),
},
sessionStorageApiWithAuth(token),
);
}

export default usePostOrder;
2 changes: 1 addition & 1 deletion src/api/hooks/usePostRegister.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useAxiosMutation, type UseAxiosMutationResult } from '@/api';
import type { PostRegisterRequestBody, PostRegisterResponseBody } from '@/api/type';

export function getRegisterPath(): string {
return '/api/register';
return '/api/members/register';
}

function usePostRegister(): UseAxiosMutationResult<
Expand Down
2 changes: 1 addition & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function useAxiosQueryWithPage<T>(
queryFn: async ({ pageParam }: QueryFunctionContext) =>
axiosInstance({
...axiosOptions,
params: { ...axiosOptions.params, initPageToken: pageParam },
params: { ...axiosOptions.params, page: pageParam },
}).then((res) => res.data),
initialPageParam: '0',
getNextPageParam: getNextPageParam as GetNextPageParamFunction<unknown>,
Expand Down
77 changes: 43 additions & 34 deletions src/api/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,13 @@ export type ProductData = {
price: number;
};

export type ProductDetailData = ProductData & {
isAccessableProductPage: boolean;
review: {
averageRating: number;
totalReviewCount: number;
};
productDescription: {
images: string[];
};
productDetailInfo: {
announcements: {
displayOrder: number;
name: string;
value: string;
}[];
terms: {
displayOrder: number;
title: string;
description: string;
}[];
};
};
export type ProductDetailData = ProductData;

export type CategoryData = {
id: number;
key: string;
name: string;
imageUrl: string;
title: string;
description?: string;
description: string;
color: string;
};

Expand Down Expand Up @@ -95,6 +72,19 @@ export type WishesData = {
product: ProductData;
};

export type OrderLog = {
id: number;
productId: number;
name: string;
imageUrl: string;
optionId: number;
count: number;
price: number;
orderDateTime: string;
message: string;
success: boolean;
};

// RequestBody Types
export type ProductOrderRequestBody = {
productId: number;
Expand Down Expand Up @@ -132,6 +122,16 @@ export type DeleteWishesRequestBody = {
wishId: number;
};

export type PostOrderRequestBody = {
optionId: number;
message: string;
quantity: number;
productId: number;
point: number;
phone: string;
receipt: boolean;
};

// ResponseBody Types
export type GetRankingProductsResponseBody = {
products: ProductData[];
Expand All @@ -140,7 +140,7 @@ export type GetRankingProductsResponseBody = {
export type GetCategoriesResponseBody = CategoryData[];

export type GetCategoriesProductsResponseBody = {
content: ProductData[];
products: ProductData[];
number: number;
totalElements: number;
size: number;
Expand All @@ -161,20 +161,29 @@ export type PostRegisterResponseBody = {
token: string;
};

export type PostWishesResponseBody = {
id: number;
productId: number;
};
export type PostWishesResponseBody = void;

export type GetWishesResponseBody = {
content: WishesData[];
pageable: PageableData;
totalPage: number;
totalElements: number;
last: boolean;
number: number;
size: number;
numberOfElements: number;
first: boolean;
empty: boolean;
};

export type GetOrderPriceResponseBody = {
price: number;
};

export type GetPointResponseBody = {
point: number;
};

export type GetOrdersResponseBody = {
contents: OrderLog[];
number: number;
totalElements: number;
size: number;
last: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const CategoryGoodsSection = ({ categoryId }: Props) => {
categoryId,
});

const flattenGoodsList = data?.pages.map((page) => page?.content ?? []).flat();
const flattenGoodsList = data?.pages.map((page) => page?.products ?? []).flat();

useEffect(() => {
if (inView && hasNextPage) {
Expand Down
Loading

0 comments on commit 21a6348

Please sign in to comment.