Skip to content

Commit

Permalink
✨ add alarm feature
Browse files Browse the repository at this point in the history
  • Loading branch information
wook-hyung committed Dec 16, 2023
1 parent a4e5ba3 commit 85135a7
Show file tree
Hide file tree
Showing 16 changed files with 283 additions and 20 deletions.
19 changes: 19 additions & 0 deletions app/(route)/alarm/_components/re-request-alarm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import AlertIcon from '@/app/_components/icons/AlertIcon'
import { type Alarm } from '@/app/_service/alarm/alarm.types'

interface ReRequestAlarmProps {
alarm: Alarm
}

export default function ReRequestAlarm({ alarm }: ReRequestAlarmProps) {
return (
<div className='flex flex-col gap-3 rounded-xl bg-[#D9D9D9] p-4'>
<div className='flex items-center gap-2 px-3'>
<AlertIcon />
<span className='text-[#595959]'>
<strong className='text-[#482BD9]'>{alarm.name}</strong> 인증 요청이 도착했어요!
</span>
</div>
</div>
)
}
82 changes: 82 additions & 0 deletions app/(route)/alarm/_components/request-alarm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use client'

import Image from 'next/image'

import { useQueryClient } from '@tanstack/react-query'

import { type Alarm } from '@/app/_service/alarm/alarm.types'

import { QUERY_KEY, useApproveCertificationAlarmMutation, useRejectCertificationAlarmMutation } from '../queries'

interface RequestAlarmProps {
alarm: Alarm
}

export default function RequestAlarm({ alarm }: RequestAlarmProps) {
const approveCertificationAlarmMutation = useApproveCertificationAlarmMutation()
const rejectCertificationAlarmMutation = useRejectCertificationAlarmMutation()

const queryClient = useQueryClient()

return (
<div className='flex flex-col gap-3 rounded-xl bg-[#D9D9D9] p-4'>
<div className='flex items-center gap-2 px-3'>
<svg xmlns='http://www.w3.org/2000/svg' width='17' height='16' viewBox='0 0 17 16' fill='none'>
<circle cx='8.5' cy='8' r='8' fill='#482BD9' />
<path
d='M12.3167 4.84038C12.2638 4.78536 12.2009 4.74169 12.1315 4.71189C12.0621 4.68209 11.9877 4.66675 11.9126 4.66675C11.8374 4.66675 11.763 4.68209 11.6937 4.71189C11.6243 4.74169 11.5613 4.78536 11.5084 4.84038L7.2676 9.21934L5.48588 7.37619C5.43093 7.32146 5.36607 7.27842 5.295 7.24954C5.22393 7.22066 5.14804 7.20649 5.07166 7.20786C4.99527 7.20922 4.9199 7.22608 4.84984 7.25748C4.77978 7.28888 4.7164 7.3342 4.66333 7.39086C4.61025 7.44752 4.56852 7.5144 4.54051 7.58769C4.5125 7.66098 4.49877 7.73924 4.50009 7.818C4.50141 7.89677 4.51776 7.97449 4.54821 8.04674C4.57866 8.11898 4.62261 8.18434 4.67756 8.23907L6.86344 10.4931C6.91635 10.5481 6.97931 10.5918 7.04868 10.6216C7.11805 10.6514 7.19245 10.6667 7.2676 10.6667C7.34274 10.6667 7.41714 10.6514 7.48651 10.6216C7.55588 10.5918 7.61884 10.5481 7.67175 10.4931L12.3167 5.70326C12.3745 5.64829 12.4206 5.58158 12.4522 5.50732C12.4837 5.43307 12.5 5.35288 12.5 5.27182C12.5 5.19075 12.4837 5.11057 12.4522 5.03631C12.4206 4.96206 12.3745 4.89535 12.3167 4.84038Z'
fill='white'
/>
</svg>
<span className='text-[#595959]'>
<strong className='text-[#482BD9]'>{alarm.name}</strong> 인증 요청이 도착했어요!
</span>
</div>
<div className=''>
<div className='relative aspect-square w-full'>
<Image className='rounded-lg' src={alarm.authenticateImageUrl} fill alt='' />
</div>
</div>
<div className='flex gap-2 '>
<button
className='h-11 w-full rounded-lg bg-[#A6A6A6] text-sm font-semibold'
onClick={() => {
approveCertificationAlarmMutation.mutate(
{
challengeCertificationId: alarm.challenge_certification_id,
},
{
onSuccess: () => {
return queryClient.invalidateQueries({
queryKey: QUERY_KEY.ALARM,
})
},
}
)
}}
>
다시 찍어줘!
</button>
<button
className='h-11 w-full rounded-lg bg-[#482BD9] text-sm font-semibold'
onClick={() => {
rejectCertificationAlarmMutation.mutate(
{
challengeCertificationId: alarm.challenge_certification_id,
},
{
onSuccess: () => {
return queryClient.invalidateQueries({
queryKey: QUERY_KEY.ALARM,
})
},
}
)
}}
>
잘했어!
</button>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Image from 'next/image'
import { type Alarm } from '@/app/_service/alarm/alarm.types'

export default function RequestAlarm() {
interface SuccessAlarmProps {
alarm: Alarm
}

export default function SuccessAlarm({ alarm }: SuccessAlarmProps) {
return (
<div className='flex flex-col gap-3 rounded-xl bg-[#D9D9D9] p-4'>
<div className='flex items-center gap-2 px-3'>
Expand All @@ -12,14 +16,10 @@ export default function RequestAlarm() {
/>
</svg>
<span className='text-[#595959]'>
<strong className='text-[#482BD9]'>매일 일기쓰기</strong> 인증 요청이 도착했어요!
업로드한
<strong className='text-[#482BD9]'>{alarm.name}</strong> 인증 완료!
</span>
</div>
<div className='px-6'>
<div className='relative aspect-square w-full'>
<Image className='rounded-lg' src='/images/TEST_IMAGE.jpeg' fill alt='' />
</div>
</div>
</div>
)
}
31 changes: 27 additions & 4 deletions app/(route)/alarm/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
'use client'

import { UserContextProvider } from '@/app/_components/providers/UserProvider'

import BackButton from './_components/BackButton'
import RequestAlarm from './_components/requestAlarm'
import ReRequestAlarm from './_components/re-request-alarm'
import RequestAlarm from './_components/request-alarm'
import SuccessAlarm from './_components/success-alarm'
import { useAlarmQuery } from './queries'

export default function AlarmPage() {
const alarmQuery = useAlarmQuery()

if (!alarmQuery.isSuccess) {
return null
}

return (
<UserContextProvider>
<main className='flex flex-col gap-3'>
Expand All @@ -14,9 +25,21 @@ export default function AlarmPage() {
</header>

<div className='flex flex-col gap-3 px-4 pb-6'>
<RequestAlarm />
<RequestAlarm />
<RequestAlarm />
{alarmQuery.data.data.alarms.map((alarm) => {
if (alarm.alarm_type === 'REQUEST') {
return <RequestAlarm key={alarm.id} alarm={alarm} />
}

if (alarm.alarm_type === 'SUCCESS') {
return <SuccessAlarm key={alarm.id} alarm={alarm} />
}

if (alarm.alarm_type === 'RE-REQUEST') {
return <ReRequestAlarm key={alarm.id} alarm={alarm} />
}

return null
})}
</div>
</main>
</UserContextProvider>
Expand Down
32 changes: 32 additions & 0 deletions app/(route)/alarm/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useMutation, useQuery } from '@tanstack/react-query'

import { approveCertificationAlarm, getAlarms } from '@/app/_service/alarm'

export const QUERY_KEY = {
ALARM: ['alarm'],
}

export const useAlarmQuery = () => {
return useQuery({
queryKey: QUERY_KEY.ALARM,
queryFn: () => {
return getAlarms()
},
})
}

export const useApproveCertificationAlarmMutation = () => {
return useMutation({
mutationFn: ({ challengeCertificationId }: { challengeCertificationId: number }) => {
return approveCertificationAlarm({ challengeCertificationId })
},
})
}

export const useRejectCertificationAlarmMutation = () => {
return useMutation({
mutationFn: ({ challengeCertificationId }: { challengeCertificationId: number }) => {
return approveCertificationAlarm({ challengeCertificationId })
},
})
}
10 changes: 10 additions & 0 deletions app/(route)/challenge/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Image from 'next/image'
import { useState } from 'react'

import CertificationDialog from './_components/certification-dialog'
import { useChallengeDetailQuery } from './queries'

export default function ChallengeDetailPage({
params,
Expand All @@ -14,6 +15,15 @@ export default function ChallengeDetailPage({
}
}) {
const [isOpenCertificationDialog, setIsOpenCertificationDialog] = useState(false)
const challengeDetailQuery = useChallengeDetailQuery({ challengeId: params.id })

if (!challengeDetailQuery.isSuccess) {
return null
}

const result = challengeDetailQuery.data.data

console.log(result)

return (
<div className='flex-1 overflow-y-auto'>
Expand Down
17 changes: 15 additions & 2 deletions app/(route)/challenge/[id]/queries.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { useMutation } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'

import { submitCertification } from '@/app/_service/challenge'
import { getChallengeDetail, submitCertification } from '@/app/_service/challenge'

const QUERY_KEY = {
CHALLENGE_DETAIL: (id: number) => ['challengeDetail', id],
}

export const useSubmitCertificationMutation = () => {
return useMutation({
mutationFn: submitCertification,
})
}

export const useChallengeDetailQuery = ({ challengeId }: { challengeId: number }) => {
return useQuery({
queryKey: QUERY_KEY.CHALLENGE_DETAIL(challengeId),
queryFn: () => {
return getChallengeDetail({ challengeId })
},
})
}
25 changes: 20 additions & 5 deletions app/(route)/me/page.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,52 @@
'use client'

import Image from 'next/image'

import RightArrowCircleIcon from '@/app/_components/icons/RightArrowCircleIcon'
import { useUserContext } from '@/app/_components/providers/UserProvider'

import { CHAMPION } from '../sign-up/page'

import BadgeCard from './_components/badge-card'
import { useUserStatusQuery } from './queries'

export default function MePage() {
const userStatusQuery = useUserStatusQuery()
const { user } = useUserContext()

if (!userStatusQuery.isSuccess) {
return null
}

const { completedCount, startedCount, friendCount } = userStatusQuery.data.data

return (
<div className='pb-20 pt-28'>
<div className='mb-5 flex flex-col gap-5 border-b border-white pb-6'>
<div className='flex flex-col items-center gap-3'>
<Image
className='rounded-full bg-white'
src='https://dodals3.s3.ap-northeast-2.amazonaws.com/asset/profile_red.png'
src={CHAMPION.DEFAULT[user.champion]}
width={187}
height={187}
alt=''
/>
<span className='text-xl font-semibold'>달다구리</span>
<span className='text-xl font-semibold'>{user.nickname}</span>
</div>
<div className='flex flex-col items-center gap-1'>
<div className='flex items-center'>
<span className='mr-2'>🚀</span>
<span className='mr-1 text-lg font-semibold'>235개</span>
<span className='mr-1 text-lg font-semibold'>{startedCount}</span>
<span className='text-[#C8C8C8]'>의 달을 여행했어요</span>
</div>
<div className='flex items-center'>
<span className='mr-2'>🌕</span>
<span className='mr-1 text-lg font-semibold'>175개</span>
<span className='mr-1 text-lg font-semibold'>{completedCount}</span>
<span className='text-[#C8C8C8]'>의 달에 도착했어요</span>
</div>
<div className='flex items-center'>
<span className='mr-2'>👩‍🚀</span>
<span className='mr-1 text-lg font-semibold'>175명</span>
<span className='mr-1 text-lg font-semibold'>{friendCount}</span>
<span className='text-[#C8C8C8]'>의 친구들과 여행했어요</span>
</div>
</div>
Expand Down
16 changes: 16 additions & 0 deletions app/(route)/me/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useQuery } from '@tanstack/react-query'

import { getUserStatus } from '@/app/_service/auth'

const QUERY_KEY = {
USER_STATUS: ['userStatus'],
}

export const useUserStatusQuery = () => {
return useQuery({
queryKey: QUERY_KEY.USER_STATUS,
queryFn: () => {
return getUserStatus()
},
})
}
2 changes: 1 addition & 1 deletion app/(route)/sign-up/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getKakaoAccessToken, removeKakaoAccessToken, setAccessToken } from '@/a

import { useLoginQuery, useSignUpMutation } from './queries'

const CHAMPION = {
export const CHAMPION = {
DEFAULT: {
RED: 'https://dodals3.s3.ap-northeast-2.amazonaws.com/asset/profile_red.png',
YELLOW: 'https://dodals3.s3.ap-northeast-2.amazonaws.com/asset/profile_yellow.png',
Expand Down
8 changes: 8 additions & 0 deletions app/_service/alarm/alarm.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface Alarm {
id: number
member_id: number
challenge_certification_id: number
alarm_type: 'REQUEST' | 'RE-REQUEST' | 'SUCCESS'
authenticateImageUrl: 'https://dodals3.s3.ap-northeast-2.amazonaws.com/1702758664871'
name: string
}
15 changes: 15 additions & 0 deletions app/_service/alarm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import api from '../core/api'

import { type Alarm } from './alarm.types'

export const getAlarms = () => {
return api.get<{ alarms: Alarm[] }>('/alarms')
}

export const approveCertificationAlarm = ({ challengeCertificationId }: { challengeCertificationId: number }) => {
return api.post('/alarms/approve', { challengeCertificationId })
}

export const rejectCertificationAlarm = ({ challengeCertificationId }: { challengeCertificationId: number }) => {
return api.post('/alarms/reject', { challengeCertificationId })
}
6 changes: 6 additions & 0 deletions app/_service/auth/auth.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ export interface SignUpParams {
nickname: string
champion: Champion
}

export interface UserStatus {
completedCount: number
friendCount: number
startedCount: number
}
5 changes: 5 additions & 0 deletions app/_service/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
type GetTokenFromKakaoParams,
type GetTokenFromKakaoResponse,
type SignUpParams,
type UserStatus,
} from './auth.types'

export const getTokenByAuthorizationCode = async ({ code }: GetTokenFromKakaoParams) => {
Expand All @@ -26,3 +27,7 @@ export const login = ({ accessToken }: { accessToken: string }) => {
export const signUp = ({ accessToken, nickname, champion }: SignUpParams) => {
return api.post('/users/signUp', { accessToken, nickname, champion })
}

export const getUserStatus = () => {
return api.get<UserStatus>('/users/status')
}
Loading

0 comments on commit 85135a7

Please sign in to comment.