Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] (#41) 조각 별 상세 정보 구현 완료 #42

Merged
merged 1 commit into from
Nov 27, 2024
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
81 changes: 81 additions & 0 deletions src/app/archive/components/OverviewHeaderForDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Button, IconLeft, IconRight } from '@/components'
import Modal from '@/components/common/Modal'
import MonthSelect from '@/components/ui/MonthSelect'
import { format } from 'date-fns'
import { useEffect, useState } from 'react'
import { useMonthTotalCount } from '@/store/monthCount'

interface OverviewHeaderProps {
currentDate: Date
setCurrentDate: (date: Date) => void
goToPreviousMonth: () => void
goToNextMonth: () => void
}

export default function OverviewHeaderForDetail({
currentDate,
setCurrentDate,
goToPreviousMonth,
goToNextMonth,
}: OverviewHeaderProps) {
const [isModalOpen, setIsModalOpen] = useState(false)
const { monthCount } = useMonthTotalCount()
const today = new Date()

const canMoveToNextMonth =
currentDate.getFullYear() < today.getFullYear() ||
(currentDate.getFullYear() === today.getFullYear() &&
currentDate.getMonth() < today.getMonth())

useEffect(() => {
setIsModalOpen(false)
}, [currentDate])

return (
<>
<header className="flex flex-row justify-between px-35">
<div className="flex gap-15 items-center">
<Button
onClick={goToPreviousMonth}
className="bg-primary_foundation-5 w-24 h-24 rounded-8"
>
<IconLeft height={13} />
</Button>
<button
type="button"
onClick={() => setIsModalOpen(true)}
className="text-18 font-[500] underline underline-offset-4"
>
{format(currentDate, 'yyyy년 MM월')}
</button>
<Button
onClick={goToNextMonth}
className="bg-primary_foundation-5 w-24 h-24 rounded-8"
disabled={!canMoveToNextMonth}
>
<IconRight
height={13}
color={!canMoveToNextMonth ? '#D1D1D3' : ''}
/>
</Button>
</div>

<span className="text-primary_foundation-60">
총 {monthCount}개의 조각
</span>
</header>

<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="월 선택하기"
className="max-h-350 overflow-auto"
>
<MonthSelect
currentDate={currentDate}
setCurrentDate={setCurrentDate}
/>
</Modal>
</>
)
}
266 changes: 160 additions & 106 deletions src/app/archive/keyword-detail/page.tsx
Original file line number Diff line number Diff line change
@@ -1,123 +1,177 @@
'use client'

import { useRouter } from 'next/navigation'
// import { useEffect, useState } from 'react'
// import { format, parseISO } from 'date-fns'
// import { ko } from 'date-fns/locale'
// import Cookies from 'js-cookie'
import { IconLeft } from '@/components'
// import { KeywordMonthDataResponse, MonthActivity } from './types/type'
// import { transKeyword } from '../components/Treemap/Treemap'
import { useRouter, useSearchParams } from 'next/navigation'
import Image from 'next/image'
import { useEffect, useState } from 'react'
import { format, getMonth, getYear, parseISO } from 'date-fns'
import { ko } from 'date-fns/locale'
import Cookies from 'js-cookie'
import { IconLeft, Clock } from '@/components'
import useUserInfo from '@/store/useUserInfo'
import { useMonthTotalCount } from '@/store/monthCount'
import { KeywordMonthDataResponse, MonthActivity } from './types/type'
import { transKeyword } from '../components/Treemap/Treemap'
import OverviewHeaderForDetail from '../components/OverviewHeaderForDetail'

export default function KeywordDetailPage() {
// const searchParams = useSearchParams()
const searchParams = useSearchParams()
const router = useRouter()
// const [accessToken, setAccessToken] = useState('')
// const [year, setYear] = useState(0)
// const [month, setMonth] = useState(0)
// const [keyword, setKeyword] = useState('')

// const [keywordData, setKeywordData] = useState<KeywordMonthDataResponse>()
// const [sortedDates, setSortedDates] = useState<string[]>()
// const [activitiesByDate, setActivitiesByDate] =
// useState<Record<string, MonthActivity[] | undefined>>()
// const [selectedDate, setSelectedDate] = useState<Date | undefined>()

// useEffect(() => {
// const token = Cookies.get('accessToken')
// if (token) {
// setAccessToken(token)
// }

// const queryYear = searchParams.get('year')
// const queryMonth = searchParams.get('month')
// const quertKeyword = searchParams.get('keyword')
// if (queryYear && queryMonth && quertKeyword) {
// const transYear = parseInt(queryYear, 10)
// const transMonth = parseInt(queryMonth, 10)

// setYear(transYear)
// setMonth(transMonth)
// setKeyword(quertKeyword)

// getMonthData(transYear, transMonth, quertKeyword)
// }
// }, [])

// const getMonthData = async (
// reqyear: number,
// reqmonth: number,
// reqkeyword: string,
// ) => {
// try {
// console.log('dddd', accessToken)
// const response = await fetch(
// `https://cnergy.p-e.kr/v1/activities?year=${reqyear}&month=${reqmonth}&keywordCategory=${reqkeyword}`,
// {
// method: 'GET',
// headers: {
// 'Content-Type': 'application/json',
// Authorization: `Bearer ${accessToken}`,
// },
// },
// )

// if (!response.ok) {
// throw new Error(`HTTP error! status: ${response.status}`)
// }

// const { data } = await response.json()
// console.log('받은 데이터', data)
// setKeywordData(data)
// } catch (error) {
// console.error('Error sending POST request:', error)
// }
// }

// useEffect(() => {
// const monthlyActivities = keywordData?.activities

// const filteredActivities = selectedDate
// ? monthlyActivities?.filter(
// (activity) =>
// format(parseISO(activity.dateOfActivity), 'yyyy-MM-dd') ===
// format(selectedDate, 'yyyy-MM-dd'),
// )
// : monthlyActivities

// const activitiesByDate =
// filteredActivities?.reduce(
// (acc, activity) => {
// const dateKey = format(
// parseISO(activity.dateOfActivity),
// 'yyyy-MM-dd',
// )
// if (!acc[dateKey]) {
// acc[dateKey] = []
// }
// acc[dateKey].push(activity)
// return acc
// },
// {} as Record<string, typeof monthlyActivities>,
// ) ?? {}

// const sortedDates = Object.keys(activitiesByDate)
// setActivitiesByDate(activitiesByDate)
// setSortedDates(sortedDates)
// }, [keywordData])
const { nickname } = useUserInfo().userInfo
const { setMonthCount } = useMonthTotalCount()

const [accessToken, setAccessToken] = useState('')
const [currentDate, setCurrentDate] = useState(new Date())
const [keyword, setKeyword] = useState('')
const [isInitialized, setIsInitialized] = useState(false)

const [keywordData, setKeywordData] = useState<KeywordMonthDataResponse>()
const [sortedDates, setSortedDates] = useState<string[]>()
const [activitiesByDate, setActivitiesByDate] =
useState<Record<string, MonthActivity[] | undefined>>()

useEffect(() => {
const token = Cookies.get('accessToken')

if (token) {
setAccessToken(token)
}

const queryYear = searchParams.get('year')
const queryMonth = searchParams.get('month')
const querytKeyword = searchParams.get('keyword')
if (queryYear && queryMonth && querytKeyword) {
const transYear = parseInt(queryYear, 10)
const transMonth = parseInt(queryMonth, 10)
const initialDate = new Date(transYear, transMonth - 1)

setCurrentDate(initialDate)
setKeyword(querytKeyword)

setIsInitialized(true)
}
}, [])

const getMonthData = async (
reqyear: number,
reqmonth: number,
reqkeyword: string,
) => {
try {
const response = await fetch(
`https://cnergy.p-e.kr/v1/activities?year=${reqyear}&month=${reqmonth}&keywordCategory=${reqkeyword}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
},
)

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}

const { data } = await response.json()

setMonthCount(data.totalActivityCountByKeywordInMonth)
setKeywordData(data)
} catch (error) {
console.error('Error sending POST request:', error)
}
}

useEffect(() => {
if (isInitialized) {
const year = getYear(currentDate)
const month = getMonth(currentDate) + 1
getMonthData(year, month, keyword)
}
}, [keyword, currentDate])

useEffect(() => {
const monthlyActivities = keywordData?.activities

const activitiesByDateSort =
monthlyActivities?.reduce(
(acc, activity) => {
const dateKey = format(
parseISO(activity.dateOfActivity),
'yyyy-MM-dd',
)
if (!acc[dateKey]) {
acc[dateKey] = []
}
acc[dateKey].push(activity)
return acc
},
{} as Record<string, typeof monthlyActivities>,
) ?? {}

const sortedDatesKeys = Object.keys(activitiesByDateSort)
setActivitiesByDate(activitiesByDateSort)
setSortedDates(sortedDatesKeys)
}, [keywordData])

const onBack = () => {
router.back()
}

const goToPreviousMonth = () => {
setCurrentDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1))
}

const goToNextMonth = () => {
setCurrentDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1))
}

return (
<div>
<div className="w-full">
<header className="relative font-semibold flex justify-center items-center py-4 min-h-52">
<IconLeft className="absolute left-20" onClick={onBack} />
<span>조각 별 상세정보</span>
</header>
{/* <section></section>
<section className="p-16 bg-primary_foundation-5">

<section>
<div className="flex flex-col mt-26 mb-10 w-350 mx-auto">
<p className="text-primary_foundation-60 text-14">
{nickname}님의 모은 시간
</p>
<div className="flex flex-col text-24 font-[500]">
<p className="flex items-center">
이달에
<span className="ml-12 mr-4 flex gap-4 items-center text-accent_100 text-28 font-[600] leading-34">
<Clock color="#FF4F38" />
{keywordData?.totalSavedTimeByKeywordInMonth}분
</span>
</p>
<p>
{keywordData && transKeyword(keywordData.keyword.category)}의
조각을 모았어요
</p>
</div>
</div>

<div className="w-390">
<Image
src={keywordData?.keyword.image || ''}
alt="keyword Image"
width={228}
height={228}
className="mx-auto"
/>
</div>
</section>

<OverviewHeaderForDetail
currentDate={currentDate}
setCurrentDate={setCurrentDate}
goToPreviousMonth={goToPreviousMonth}
goToNextMonth={goToNextMonth}
/>

<div className="p-16 bg-primary_foundation-5 mt-20">
{sortedDates?.map((date) => (
<div key={date} className="mb-20">
<h3 className="text-16 font-[500] mb-8 flex items-center">
Expand Down Expand Up @@ -145,7 +199,7 @@ export default function KeywordDetailPage() {
</div>
</div>
))}
</section> */}
</div>
</div>
)
}
14 changes: 14 additions & 0 deletions src/store/monthCount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { create } from 'zustand'

interface MonthCountState {
monthCount: number
setMonthCount: (newCount: number) => void
}

export const useMonthTotalCount = create<MonthCountState>((set) => ({
monthCount: 0,
setMonthCount: (newCount) =>
set({
monthCount: newCount,
}),
}))