Skip to content

Commit

Permalink
Merge pull request #102 from Bside-Team-Four/feature/101
Browse files Browse the repository at this point in the history
feat: reward api
  • Loading branch information
thxtome authored Dec 17, 2023
2 parents 5632a50 + 56c1f1e commit 5d5c5e1
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 62 deletions.
5 changes: 1 addition & 4 deletions src/app/(setting)/reward-history/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
'use client';

import RewardHistory from '@/components/reward-history';
import fixtures from '@/fixtures';

export default function RewardHistoryPage() {
const { reward } = fixtures;

return (
<RewardHistory reward={reward} />
<RewardHistory />
);
}
2 changes: 1 addition & 1 deletion src/components/reward-history/RewardItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import RewardItem from './RewardItem';

describe('RewardItem', () => {
const renderRewardItem = () => renderWithProviders(
<RewardItem type={given.type} date="23일 23:59" point={100} />,
<RewardItem type={given.type} regDt="2023-12-14T23:55:27" amount={100} remainAmount={100} />,
);

context('리워드가 적립(ADD) 상태일 경우', () => {
Expand Down
11 changes: 7 additions & 4 deletions src/components/reward-history/RewardItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ import styled from 'styled-components';

import Reward, { RewardType } from '@/types/Reward';

type RewardItemProps = Omit<Reward, 'id'>;
type RewardItemProps = Omit<Reward, 'historyId'>;

const getTypeText = (type: RewardType) => (type === 'ADD' ? '적립' : '사용');

const getPointText = (type: RewardType, point: number) => `${type === 'ADD' ? '+' : '-'}${point} PPP`;

export default function RewardItem({ type, date, point }:RewardItemProps) {
const getRegDtText = (regDt:string) => `${regDt.slice(8, 10)}${regDt.slice(11, 13)}:${regDt.slice(14, 16)}`;

export default function RewardItem({ type, regDt, amount }:RewardItemProps) {
const typeText = getTypeText(type);
const pointText = getPointText(type, point);
const pointText = getPointText(type, amount);
const regDtText = getRegDtText(regDt);

return (
<Container>
<RewardInfo>
<RewardTypeText>{typeText}</RewardTypeText>
<DateText>{date}</DateText>
<DateText>{regDtText}</DateText>
</RewardInfo>
<PointText type={type}>{pointText}</PointText>
</Container>
Expand Down
18 changes: 15 additions & 3 deletions src/components/reward-history/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { screen } from '@testing-library/react';

import fixtures from '@/fixtures';
import useGetInfiniteRewards from '@/hooks/api/useGetInfiniteRewards';
import { renderWithProviders } from '@/utils/testHelper';

import RewardHistory from './index';

jest.mock('@/hooks/api/useGetInfiniteRewards');

describe('RewardHistory', () => {
const renderRewardHistory = () => renderWithProviders(<RewardHistory reward={given.reward} />);
beforeEach(() => {
jest.clearAllMocks();

(useGetInfiniteRewards as jest.Mock).mockImplementation(() => ({
rewards: given.rewards,
refState: { lastItemRef: { current: null } },
}));
});

const renderRewardHistory = () => renderWithProviders(<RewardHistory />);

context('리워드 이용내역이 없을 때', () => {
given('reward', () => []);
given('rewards', () => []);

it("'이용내역이 없어요'텍스트를 화면에 보여준다.", () => {
renderRewardHistory();
Expand All @@ -19,7 +31,7 @@ describe('RewardHistory', () => {
});

context('리워드 이용내역이 있을 때', () => {
given('reward', () => fixtures.reward);
given('rewards', () => fixtures.reward);

it('리워드 이용내역 리스트를 화면에 보여준다.', () => {
renderRewardHistory();
Expand Down
26 changes: 16 additions & 10 deletions src/components/reward-history/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import styled from 'styled-components';

import Reward from '@/types/Reward';
import useGetInfiniteReward from '@/hooks/api/useGetInfiniteRewards';

import NotHistory from './NotHistory';
import RewardItem from './RewardItem';

type RewardHistoryProps = {
reward: Reward[];
};

export default function RewardHistory({ reward }:RewardHistoryProps) {
export default function RewardHistory() {
const {
rewards, isLoading, isFetchingNextPage, refState,
} = useGetInfiniteReward();
return (
<Container>
{reward.length ? reward.map(({
id, type, date, point,
{rewards.length ? rewards.map(({
historyId, type, regDt, amount, remainAmount,
}) => (
<RewardItem key={id} type={type} date={date} point={point} />
<RewardItem
key={historyId}
type={type}
regDt={regDt}
amount={amount}
remainAmount={remainAmount}
/>
))
: <NotHistory /> }
: <NotHistory />}
{!isLoading && !isFetchingNextPage && <div ref={refState.lastItemRef} />}
</Container>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/fixtures/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const profile: ProfileType = {
voteCount: 200,
followerCount: 230,
followeeCount: 50,
email: '',
};

export default profile;
84 changes: 48 additions & 36 deletions src/fixtures/reward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,88 @@ import Reward from '@/types/Reward';

const reward:Reward[] = [
{
id: 1,
historyId: 1,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 2,
historyId: 2,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 3,
historyId: 3,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
{
id: 4,
historyId: 4,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
{
id: 5,
historyId: 5,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 6,
historyId: 6,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 7,
historyId: 7,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
{
id: 8,
historyId: 8,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
{
id: 9,
historyId: 9,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 10,
historyId: 10,
type: 'ADD',
date: '23일 23:59',
point: 100,
regDt: '2023-12-14T15:10:36.647Z',
amount: 100,
remainAmount: 100,
},
{
id: 11,
historyId: 11,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
{
id: 12,
historyId: 12,
type: 'USE',
date: '23일 23:59',
point: 300,
regDt: '2023-12-14T15:10:36.647Z',
amount: 300,
remainAmount: 300,
},
];

Expand Down
38 changes: 38 additions & 0 deletions src/hooks/api/useGetInfiniteRewards.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useInView } from 'react-intersection-observer';

import { renderHook, waitFor } from '@testing-library/react';

import fixtures from '@/fixtures';
import { apiService } from '@/lib/api/ApiService';
import wrapper from '@/test/ReactQueryWrapper';

import useGetInfiniteReward from './useGetInfiniteRewards';

jest.mock('@/lib/api/ApiService');

describe('useGetInfiniteRewards', () => {
const renderUseGetRewardsHook = () => renderHook(() => useGetInfiniteReward(), {
wrapper,
});

beforeEach(() => {
jest.clearAllMocks();

(apiService.fetchGetRewards as jest.Mock).mockImplementation(() => (
{
value: fixtures.reward,
}
));
(useInView as jest.Mock).mockImplementation(() => ({
ref: jest.fn(),
inView: given.inView,
}));
});

it('returns reward data', async () => {
const { result } = renderUseGetRewardsHook();
await waitFor(() => {
expect(result.current.rewards).toEqual(fixtures.reward);
});
});
});
43 changes: 43 additions & 0 deletions src/hooks/api/useGetInfiniteRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import _ from 'lodash/fp';

import useIntersectionObserver from '@/hooks/useIntersectionObserver';
import { apiService } from '@/lib/api/ApiService';

export const GET_INFINITE_REWARD_KEY = 'getInfiniteRewards';

export default function useGetInfiniteRewards() {
const query = useInfiniteQuery(
[GET_INFINITE_REWARD_KEY],
async ({ pageParam: lastId }) => apiService.fetchGetRewards(lastId),
{
getNextPageParam: (res) => {
if (res.value.length < 30) return undefined;
const lastId = res.value[res.value.length - 1].historyId;
return lastId;
},
},
);

const refState = useIntersectionObserver<HTMLDivElement>({
intersectionOptions: {
rootMargin: '20px',
},
isRoot: true,
fetchNextPage: query.fetchNextPage,
hasNextPage: query.hasNextPage,
});

const rewards = query.data ? _.flatten(
query.data.pages.map((res) => res.value),
) : [];

const isEmpty = rewards.length === 0;

return {
...query,
rewards,
isEmpty,
refState,
};
}
14 changes: 13 additions & 1 deletion src/lib/api/ApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { ApiErrorScheme } from '@/lib/excptions/type';
import {
AuthenticateResponse, FollowResponse, GetMyProfileResponse,
GetPollListResponse, GetPollStatusResponse,
GetSchoolsResponse, GetUsersResponse, NotificationSettingsResponse, PasswordMissingAuthResponse,
GetRewardsResponse,
GetSchoolsResponse, GetUsersResponse,
NotificationSettingsResponse,
PasswordMissingAuthResponse,
PasswordMissingResponse,
PasswordResetResponse, RemoveAccountResponse, SignUpAuthEmailResponse,
SignUpResponse, SignUpSendEmailResponse, SkipResponse, UnfollowResponse, VoteResponse,
Expand Down Expand Up @@ -96,6 +99,15 @@ export default class ApiService {
},
});

fetchGetRewards = (
lastId?: number,
) => this.get<GetRewardsResponse>('/user/reward', {
params: {
size: 30,
lastId,
},
});

follow = (followeeId : number) => this.post<FollowResponse>('/relation/request', {
followeeId,
});
Expand Down
6 changes: 6 additions & 0 deletions src/types/ApiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import ProfileType from '@/types/ProfileType';
import School from '@/types/School';
import User from '@/types/User';

import Reward from './Reward';

type DefaultResponse = {
code: number;
message: string;
Expand All @@ -22,6 +24,10 @@ export type GetUsersResponse = DefaultResponse & {
value: User[]
};

export type GetRewardsResponse = DefaultResponse & {
value: Reward[]
};

export type AuthenticateResponse = DefaultResponse & {
value:{
token: string;
Expand Down
Loading

1 comment on commit 5d5c5e1

@vercel
Copy link

@vercel vercel bot commented on 5d5c5e1 Dec 17, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

popo-client – ./

popo-client-popo.vercel.app
popo-client.vercel.app
popo-client-git-main-popo.vercel.app

Please sign in to comment.