From a04afc47a7ff88705f403512c1fb185cba258a8f Mon Sep 17 00:00:00 2001 From: HyungWookChoi Date: Sun, 17 Dec 2023 01:10:48 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20add=20challenge=20API=20integration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/_components/ChallengeCard.tsx | 17 +++++--- .../_components/ChallengeFormDialog.tsx | 8 +++- app/(route)/challenge/page.tsx | 32 ++++++++++---- app/(route)/challenge/queries.ts | 15 ++++++- app/(route)/invitation/[id]/page.tsx | 43 +++++++++++++++++-- app/(route)/invitation/[id]/queries.ts | 22 ++++++++++ app/_constants/route.ts | 1 + app/_service/challenge/challenge.types.ts | 23 ++++------ app/_service/challenge/index.ts | 11 +++++ 9 files changed, 137 insertions(+), 35 deletions(-) create mode 100644 app/(route)/invitation/[id]/queries.ts diff --git a/app/(route)/challenge/_components/ChallengeCard.tsx b/app/(route)/challenge/_components/ChallengeCard.tsx index 7705b81..f074297 100644 --- a/app/(route)/challenge/_components/ChallengeCard.tsx +++ b/app/(route)/challenge/_components/ChallengeCard.tsx @@ -1,10 +1,17 @@ import Image from 'next/image' +import Link from 'next/link' import RightArrowIcon from '@/app/_components/icons/RightArrowIcon' +import { ROUTE } from '@/app/_constants/route' +import { type Challenge } from '@/app/_service/challenge/challenge.types' -export default function ChallengeCard() { +interface ChallengeCardProps { + challenge: Challenge +} + +export default function ChallengeCard({ challenge }: ChallengeCardProps) { return ( -
+
자기계발 - 스페인어 공부 - 신상 텀블러 + {challenge.name} + {challenge.reward} 10%
-
+ ) } diff --git a/app/(route)/challenge/_components/ChallengeFormDialog.tsx b/app/(route)/challenge/_components/ChallengeFormDialog.tsx index a107ffd..21eb882 100644 --- a/app/(route)/challenge/_components/ChallengeFormDialog.tsx +++ b/app/(route)/challenge/_components/ChallengeFormDialog.tsx @@ -36,8 +36,12 @@ interface Inputs { reward: string } -export default function ChallengeFormDialog() { - const [isOpenDialog, setIsOpenDialog] = useState(false) +interface ChallengeFormDialogProps { + isOpenDialog: boolean + setIsOpenDialog: (isOpen: boolean) => void +} + +export default function ChallengeFormDialog({ isOpenDialog, setIsOpenDialog }: ChallengeFormDialogProps) { const [selectedCategory, setSelectedCategory] = useState('선택안함') const [isChecked, setIsChecked] = useState({ check1: false, diff --git a/app/(route)/challenge/page.tsx b/app/(route)/challenge/page.tsx index a0340a0..a57030b 100644 --- a/app/(route)/challenge/page.tsx +++ b/app/(route)/challenge/page.tsx @@ -6,19 +6,35 @@ import { cn } from '@/app/_styles/utils' import ChallengeCard from './_components/ChallengeCard' import ChallengeFormDialog from './_components/ChallengeFormDialog' +import { useChallengesQuery } from './queries' export default function ChallengePage() { - const [tab, setTab] = useState<'ongoing' | 'completed'>('ongoing') + const [isOpenDialog, setIsOpenDialog] = useState(false) + + const [tab, setTab] = useState<'inProgress' | 'completed'>('inProgress') + + const challengesQuery = useChallengesQuery() + + if (!challengesQuery.isSuccess) { + return null + } + + const challenges = challengesQuery.data.data + + const inProgressChallenges = challenges.filter((challenge) => challenge.challenge_status === 'PROGRESS') + const completedChallenges = challenges.filter((challenge) => challenge.challenge_status === 'SUCCESS') + + const challengesByTab = tab === 'inProgress' ? inProgressChallenges : completedChallenges return ( -
+
-
- {new Array(10).fill(0).map((_, index) => { - return +
+ {challengesByTab.map((challenge) => { + return })}
- +
) } diff --git a/app/(route)/challenge/queries.ts b/app/(route)/challenge/queries.ts index a7338c8..4637119 100644 --- a/app/(route)/challenge/queries.ts +++ b/app/(route)/challenge/queries.ts @@ -1,9 +1,20 @@ -import { useMutation } from '@tanstack/react-query' +import { useMutation, useQuery } from '@tanstack/react-query' -import { createChallenge } from '@/app/_service/challenge' +import { createChallenge, getChallenges } from '@/app/_service/challenge' + +const QUERY_KEY = { + challenges: ['challenges'], +} export const useCreateChallengeMutation = () => { return useMutation({ mutationFn: createChallenge, }) } + +export const useChallengesQuery = () => { + return useQuery({ + queryKey: QUERY_KEY.challenges, + queryFn: getChallenges, + }) +} diff --git a/app/(route)/invitation/[id]/page.tsx b/app/(route)/invitation/[id]/page.tsx index 6d4da4e..91f6b0f 100644 --- a/app/(route)/invitation/[id]/page.tsx +++ b/app/(route)/invitation/[id]/page.tsx @@ -1,6 +1,27 @@ +'use client' + import Image from 'next/image' +import { useRouter } from 'next/navigation' + +import { ROUTE } from '@/app/_constants/route' + +import { useApproveChallengeMutation, useUpcomingChallengeQuery } from './queries' + +export default function InvitationPage({ + params, +}: { + params: { + id: string + } +}) { + const router = useRouter() + + const upcomingChallengeQuery = useUpcomingChallengeQuery({ + challengeId: Number(params.id), + }) + + const approveChallengeMutation = useApproveChallengeMutation() -export default function InvitationPage() { return (
@@ -8,13 +29,29 @@ export default function InvitationPage() {
- 별빛우주 + {upcomingChallengeQuery.data?.data.nickname} 님이 초대장을 보냈어요
목표를 위해 함께 달려볼까요?
- + diff --git a/app/(route)/invitation/[id]/queries.ts b/app/(route)/invitation/[id]/queries.ts new file mode 100644 index 0000000..e088022 --- /dev/null +++ b/app/(route)/invitation/[id]/queries.ts @@ -0,0 +1,22 @@ +import { useMutation, useQuery } from '@tanstack/react-query' + +import { approveChallenge, getUpcomingChallenge } from '@/app/_service/challenge' + +const QUERY_KEY = { + UPCOMING_CHALLENGE: (challengeId: number) => ['upcomingChallenge', challengeId], +} + +export const useUpcomingChallengeQuery = ({ challengeId }: { challengeId: number }) => { + return useQuery({ + queryKey: QUERY_KEY.UPCOMING_CHALLENGE(challengeId), + queryFn: () => { + return getUpcomingChallenge({ challengeId }) + }, + }) +} + +export const useApproveChallengeMutation = () => { + return useMutation({ + mutationFn: approveChallenge, + }) +} diff --git a/app/_constants/route.ts b/app/_constants/route.ts index c50771d..a95fff5 100644 --- a/app/_constants/route.ts +++ b/app/_constants/route.ts @@ -3,6 +3,7 @@ export const ROUTE = { LOGIN: '/login', SIGN_UP: '/sign-up', CHALLENGE: '/challenge', + CHALLENGE_DETAIL: (id: number) => `/challenge/${id}`, ALARM: '/alarm', ME: '/me', OAUTH: { diff --git a/app/_service/challenge/challenge.types.ts b/app/_service/challenge/challenge.types.ts index 522f9e4..598b752 100644 --- a/app/_service/challenge/challenge.types.ts +++ b/app/_service/challenge/challenge.types.ts @@ -23,26 +23,19 @@ export interface GetUpcomingChallengeParams { challengeId: number } +export interface GetUpcomingChallengeResponse { + nickname: string +} + +export type ChallengeStatus = 'WAITING' | 'PROGRESS' | 'FAILURE' | 'SUCCESS' + export interface Challenge { id: number name: string category: Category authentication_method: string reward: string - is_deleted: 0 - created_at: '2023-12-16T13:59:18.000Z' - updated_at: '2023-12-16T13:59:18.000Z' - target_count: 10 - challenge_status: 'WAITING' + challenge_status: ChallengeStatus } -export interface GetUpcomingChallengeResponse { - challengeId: number - name: string - category: Category - authenticationMethod: string - reward: string - champion: Champion - explorationCount: number - certificatedCount: number -} +export type GetChallengesResponse = Challenge[] diff --git a/app/_service/challenge/index.ts b/app/_service/challenge/index.ts index 0448a19..3a91fbb 100644 --- a/app/_service/challenge/index.ts +++ b/app/_service/challenge/index.ts @@ -6,6 +6,7 @@ import { type GetTodayStatus, type GetUpcomingChallengeParams, type GetUpcomingChallengeResponse, + type GetChallengesResponse, } from './challenge.types' export const getTodayStatus = () => { @@ -24,3 +25,13 @@ export const createChallenge = ({ name, category, authenticationMethod, reward } export const getUpcomingChallenge = ({ challengeId }: GetUpcomingChallengeParams) => { return api.get(`/challenges/upcoming/${challengeId}`) } + +export const approveChallenge = ({ challengeId }: { challengeId: number }) => { + return api.post(`/challenges/approve`, { + challengeId, + }) +} + +export const getChallenges = () => { + return api.get('/challenges') +}