Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/api/client/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src';
3 changes: 3 additions & 0 deletions packages/api/client/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './item';
export * from './order';
export * from './student';
1 change: 1 addition & 0 deletions packages/api/client/src/hooks/item/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useGetItemList';
14 changes: 14 additions & 0 deletions packages/api/client/src/hooks/item/useGetItemList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useQuery } from '@tanstack/react-query';

import { itemQueryKeys, itemUrl, get } from 'api/common';

import type { ShopItemType } from 'types';

import type { UseQueryOptions } from '@tanstack/react-query';

export const useGetItemList = (options?: UseQueryOptions<ShopItemType[]>) =>
useQuery<ShopItemType[]>(
itemQueryKeys.getItemList(),
() => get(itemUrl.itemList()),
options
);
1 change: 1 addition & 0 deletions packages/api/client/src/hooks/order/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './usePostItemOrder';
16 changes: 16 additions & 0 deletions packages/api/client/src/hooks/order/usePostItemOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useMutation } from '@tanstack/react-query';

import { post, orderQueryKeys, orderUrl } from 'api/common';

import { AxiosError } from 'axios';

interface ItemOrderRequestType {
itemId: string;
count: number;
}

export const usePostItemOrder = () =>
useMutation<void, AxiosError, ItemOrderRequestType[]>(
orderQueryKeys.postItem(),
(orderList) => post(orderUrl.orderItem(), orderList)
);
1 change: 1 addition & 0 deletions packages/api/client/src/hooks/student/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useGetStudentInfo';
14 changes: 14 additions & 0 deletions packages/api/client/src/hooks/student/useGetStudentInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useQuery } from '@tanstack/react-query';

import { studentQueryKeys, studentUrl, get } from 'api/common';

import type { StudentType } from 'types';

import type { UseQueryOptions } from '@tanstack/react-query';

export const useGetStudentInfo = (options?: UseQueryOptions<StudentType>) =>
useQuery<StudentType>(
studentQueryKeys.getStudentInfo(),
() => get(studentUrl.studentInfo()),
options
);
1 change: 1 addition & 0 deletions packages/api/client/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './hooks';
6 changes: 4 additions & 2 deletions packages/api/common/src/hooks/auth/usePostLoginCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ export const usePostLoginCode = () =>
(loginCode) => post(authUrl.auth(), loginCode),
{
onSuccess: (data) => {
localStorage.setItem('refresh_token', data.refreshToken);
localStorage.setItem('access_token', data.accessToken);
if (data.refreshToken)
Comment thread
frorong marked this conversation as resolved.
localStorage.setItem('refresh_token', data.refreshToken);
if (data.accessToken)
localStorage.setItem('access_token', data.accessToken);
},
}
);
2 changes: 1 addition & 1 deletion packages/api/common/src/libs/api/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ apiInstance.interceptors.response.use(
return Promise.reject(response.data);
},
async (error) => {
if (error.config.url === authUrl.auth()) {
if (error.config.url === authUrl.auth() && error.response.status === 404) {
location.replace('/auth/login');

return Promise.reject(error);
Expand Down
9 changes: 9 additions & 0 deletions packages/api/common/src/libs/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const missionQueryKeys = {

export const studentQueryKeys = {
getRankingList: () => ['student', 'rankingList'],
getStudentInfo: () => ['student', 'info'],
};

export const authQueryKeys = {
Expand All @@ -17,3 +18,11 @@ export const userQueryKeys = {
getScoringList: () => ['user', 'scoring'],
postScoringResult: (solveId: string) => ['user', 'scoring', solveId],
};

export const itemQueryKeys = {
getItemList: () => ['item', 'list'],
};

export const orderQueryKeys = {
postItem: () => ['order'],
Comment thread
frorong marked this conversation as resolved.
};
9 changes: 9 additions & 0 deletions packages/api/common/src/libs/urlController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const missionUrl = {

export const studentUrl = {
rankingList: () => `/student/ranking`,
studentInfo: () => `/student/my`,
};

export const authUrl = {
Expand All @@ -15,3 +16,11 @@ export const userUrl = {
scoring: (pageNumber: number) => `/user/scoring/${pageNumber}`,
scoringResult: (solveId: string) => `/user/scoring/${solveId}`,
};

export const itemUrl = {
itemList: () => `/item`,
};

export const orderUrl = {
orderItem: () => `/order`,
};
1 change: 1 addition & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './tokenResponseType';
export * from './mission';
export * from './scoringListType';
export * from './solveStatusType';
export * from './studentType';
10 changes: 10 additions & 0 deletions packages/types/src/studentType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface StudentType {
id: string;
cumulatePoint: number;
user: {
id: string;
email: string;
name: string;
profileImage: string | '';
};
}
80 changes: 28 additions & 52 deletions projects/client/src/PageContainer/ShopPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,14 @@ import { slicePoint } from 'common';

import { useEffect, useRef, useState } from 'react';

const list = [
{
itemId: 'id',
name: '자장면1',
text: '자장면',
price: 5000,
image:
'https://mblogthumb-phinf.pstatic.net/MjAxNzAxMjNfNDkg/MDAxNDg1MTYwMTQ1MDc5.H7I84KnCb0_U0Fb312NMMk10dbmNhdMb45jDiNYs13Eg.e3185KBkHafPDJpOjsZ7vvvH741l0TzEt2vVNvePS7Mg.JPEG.china_lab/shutterstock_524181190.jpg?type=w800',
},
{
itemId: 'id',
name: '자장면2',
text: '자장면',
price: 5000,
image:
'https://mblogthumb-phinf.pstatic.net/MjAxNzAxMjNfNDkg/MDAxNDg1MTYwMTQ1MDc5.H7I84KnCb0_U0Fb312NMMk10dbmNhdMb45jDiNYs13Eg.e3185KBkHafPDJpOjsZ7vvvH741l0TzEt2vVNvePS7Mg.JPEG.china_lab/shutterstock_524181190.jpg?type=w800',
},
{
itemId: 'id',
name: '자장면3',
text: '자장면',
price: 5000,
image:
'https://mblogthumb-phinf.pstatic.net/MjAxNzAxMjNfNDkg/MDAxNDg1MTYwMTQ1MDc5.H7I84KnCb0_U0Fb312NMMk10dbmNhdMb45jDiNYs13Eg.e3185KBkHafPDJpOjsZ7vvvH741l0TzEt2vVNvePS7Mg.JPEG.china_lab/shutterstock_524181190.jpg?type=w800',
},
{
itemId: 'id',
name: '자장면4',
text: '자장면',
price: 5000,
image:
'https://mblogthumb-phinf.pstatic.net/MjAxNzAxMjNfNDkg/MDAxNDg1MTYwMTQ1MDc5.H7I84KnCb0_U0Fb312NMMk10dbmNhdMb45jDiNYs13Eg.e3185KBkHafPDJpOjsZ7vvvH741l0TzEt2vVNvePS7Mg.JPEG.china_lab/shutterstock_524181190.jpg?type=w800',
},
];
import { useGetItemList, useGetStudentInfo } from 'api/client';

const ShopPage = () => {
const dialog = useRef<HTMLDialogElement>(null);

const { data } = useGetItemList();
const { data: student } = useGetStudentInfo();

const [itemStatus, setItemStatus] = useState<boolean[]>([]);

const onItemClick = (index: number) => {
Expand All @@ -54,38 +24,44 @@ const ShopPage = () => {
};

useEffect(() => {
setItemStatus(new Array(list.length).fill(false));
setItemStatus(new Array(data?.length).fill(false));
}, []);

return (
<S.PageWrapper>
<S.MiledgeTitle>현재 마일리지</S.MiledgeTitle>
<S.FlexWrapper>
<S.MilidgePoint>{slicePoint(1000)}</S.MilidgePoint>
<S.MilidgePoint>
{slicePoint(student?.cumulatePoint ?? 0)}
</S.MilidgePoint>
<S.MilidgeUnit>M</S.MilidgeUnit>
</S.FlexWrapper>
<S.ListWrapper>
<S.ItemText>상품</S.ItemText>
<S.ItemList>
{list.map((item, index) => (
<ShopItem
index={index}
onItemClick={onItemClick}
key={item.itemId + index}
data={item}
itemStatus={itemStatus[index]}
/>
))}
</S.ItemList>
{data && (
<S.ItemList>
{data.map((item, index) => (
<ShopItem
index={index}
onItemClick={onItemClick}
key={item.itemId}
data={item}
itemStatus={itemStatus[index]}
/>
))}
</S.ItemList>
)}
</S.ListWrapper>
<S.SelectButton onClick={() => dialog.current?.showModal()}>
선택하기
</S.SelectButton>
<S.ModalWrapper ref={dialog}>
<ShopModal
selectedList={list.filter((_, index) => itemStatus[index])}
/>
</S.ModalWrapper>
{data && (
<S.ModalWrapper ref={dialog}>
<ShopModal
selectedList={data.filter((_, index) => itemStatus[index])}
/>
</S.ModalWrapper>
)}
</S.PageWrapper>
);
};
Expand Down
2 changes: 1 addition & 1 deletion projects/client/src/components/MissionCarousel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const MissionCarousel = () => {
{missionList[pageIndex]?.map((item, index) => (
<TaskCard
onClick={() => onCardClick(item.id)}
key={item.id + index}
key={item.id}
userName={item.user.name}
taskTitle={item.title}
miledge={item.point}
Expand Down
36 changes: 32 additions & 4 deletions projects/client/src/components/ShopModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,57 @@
import * as S from './style';
import { XIcon } from 'client/assets';
import { ShopModalItem } from 'client/components';

import { useEffect, useState } from 'react';

import { usePostItemOrder } from 'api/client';

import { ShopItemType } from 'types';

import { useRouter } from 'next/navigation';

interface ShopModalProps {
selectedList: ShopItemType[] | [];
}

const ShopModal: React.FC<ShopModalProps> = ({ selectedList }) => {
const [countList, setCountList] = useState<number[]>([]);

const { push } = useRouter();

const { mutate, isSuccess, isError, error } = usePostItemOrder();

useEffect(() => {
setCountList(new Array(selectedList.length).fill(0));
setCountList(new Array(selectedList.length).fill(1));
}, [selectedList]);

const calculateCount = (index: number, isPlus: boolean) => {
const newCountList = [...countList];
isPlus
? newCountList[index]++
: newCountList[index] !== 0 && newCountList[index]--;
: newCountList[index] !== 1 && newCountList[index]--;
setCountList(newCountList);
};

const handleSubmit = () => {
const orderList = countList.map((item, i) => {
return { itemId: selectedList[i].itemId, count: item };
});
mutate(orderList);
};

if (isSuccess) {
push('/');
alert('상품이 구매되었습니다!');
}

if (isError) {
if (error && error.response?.status === 400) {
alert('마일리지가 부족합니다');
location.reload();
}
}

return (
<S.ModalWrapper>
<form method='dialog'>
Expand All @@ -37,7 +65,7 @@ const ShopModal: React.FC<ShopModalProps> = ({ selectedList }) => {
<S.ItemList>
{selectedList?.map((selectedItem, index) => (
<ShopModalItem
key={selectedItem.itemId + index}
key={selectedItem.itemId}
data={selectedItem}
count={countList[index]}
calculateCount={calculateCount}
Expand All @@ -46,7 +74,7 @@ const ShopModal: React.FC<ShopModalProps> = ({ selectedList }) => {
))}
</S.ItemList>
<form method='dialog'>
<S.PurchusButton>구매하기</S.PurchusButton>
<S.PurchusButton onClick={handleSubmit}>구매하기</S.PurchusButton>
</form>
</S.ModalWrapper>
);
Expand Down