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

Develop #51

Merged
merged 9 commits into from
Feb 23, 2025
3 changes: 2 additions & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
npm run build:verify
npm run check:deps
npm run check:types
3 changes: 0 additions & 3 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ const nextConfig: NextConfig = {
},
],
},
experimental: {
useCache: true,
},
}

export default nextConfig
3,162 changes: 1,702 additions & 1,460 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.5.1",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev": "next dev --turbo",
"build": "next build",
"build:verify": "rimraf .next-verify && cross-env NEXT_BUILD_DIR=.next-verify next build && rimraf .next-verify",
"start": "next start",
Expand All @@ -24,7 +24,7 @@
"date-fns": "^4.1.0",
"highcharts": "^11.4.8",
"highcharts-react-official": "^3.2.1",
"next": "^15.2.0-canary.56",
"next": "^15.1.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.4.0",
Expand Down
2 changes: 0 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use cache'

import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'
import { ToastContainer } from 'react-toastify'
Expand Down
15 changes: 8 additions & 7 deletions src/app/player/[name]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
'use cache'

import { Metadata } from 'next'
import { cacheLife } from 'next/dist/server/use-cache/cache-life'
import { cacheTag } from 'next/dist/server/use-cache/cache-tag'

import { PlayerPage } from '@/features/player'
import { fetchAchievement } from '@/service/supabase/achievement'
import { fetchPlayer } from '@/service/supabase/player'
import { fetchAllPlayersName, fetchPlayer } from '@/service/supabase/player'

interface PageProps {
params: Promise<{ name: string }>
}

export const revalidate = 86400 // 丸一日キャッシュする
export const dynamicParams = true

export async function generateStaticParams() {
return (await fetchAllPlayersName()).map(name => ({ name }))
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const name = decodeURI((await params).name)

Expand All @@ -23,8 +26,6 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>

export default async function Page({ params }: PageProps) {
const name = decodeURI((await params).name)
cacheLife('days')
cacheTag(name)

const player = await fetchPlayer(name)
const achievement = (await fetchAchievement(player.records[0].achievement)) ?? undefined
Expand Down
2 changes: 0 additions & 2 deletions src/app/ranking/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use cache'

import { Metadata } from 'next'

import RankingPage from '@/features/ranking'
Expand Down
6 changes: 5 additions & 1 deletion src/components/revalidater/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use server'

import { revalidateTag } from 'next/cache'
import { revalidatePath, revalidateTag } from 'next/cache'

export const revalidateUserData = async (tags: string | string[]) => {
if (Array.isArray(tags)) {
Expand All @@ -9,3 +9,7 @@ export const revalidateUserData = async (tags: string | string[]) => {
revalidateTag(tags)
}
}

export const revalidatePage = async (path: string) => {
revalidatePath(path)
}
82 changes: 69 additions & 13 deletions src/components/revalidater/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,81 @@
'use client'

import { useCallback } from 'react'
import classNames from 'classnames'
import { addSeconds, differenceInMinutes, format } from 'date-fns'
import { usePathname } from 'next/navigation'
import { useCallback, useEffect, useState } from 'react'
import { toast } from 'react-toastify'
import { Tooltip } from 'react-tooltip'

import { revalidateUserData } from './action'
import { revalidatePage } from './action'

interface Props {
tags: string | string[]
interface RevalidateLog {
[key: string]: {
timestamp: string
}
}

export const Revalidater = ({ tags }: Props) => {
const onClick = useCallback(async () => {
await revalidateUserData(tags)
const getRevalidateLog = (): RevalidateLog => {
return JSON.parse(localStorage.getItem('revalidate') ?? '{}')
}

const RefreshSpan = 300

export const Revalidater = () => {
const pathname = usePathname()
const handleButtonClick = useCallback(async () => {
await revalidatePage(pathname)
toast.success('データベースと同期しました')
}, [tags])
localStorage.setItem(
'revalidate',
JSON.stringify({
...getRevalidateLog(),
[pathname]: {
timestamp: new Date().toISOString(),
},
})
)
setEnabled(false)
setStoredDate(new Date())
}, [pathname])

const [isEnabled, setEnabled] = useState<boolean>(false)
const [storedDate, setStoredDate] = useState<Date | null>(null)
useEffect(() => {
setEnabled(storedDate ? differenceInMinutes(new Date(), storedDate) >= RefreshSpan : true)
}, [pathname, storedDate])

useEffect(() => {
const timestamp = getRevalidateLog()[pathname]?.timestamp
if (timestamp) setStoredDate(new Date(timestamp))
}, [pathname])

return (
<div className="p-[3px] rounded-lg bg-green-300 shadow mt-4 outline outline-1 outline-green-500">
<button className="w-full text-center" onClick={onClick}>
最新の状態に更新する
</button>
</div>
<>
<div
className={classNames('p-[3px] rounded-lg shadow mt-4 outline outline-1', {
'bg-green-300': isEnabled,
'outline-green-500': isEnabled,
'text-black': isEnabled,
'bg-gray-300': !isEnabled,
'outline-gray-400': !isEnabled,
'text-gray-500': !isEnabled,
})}
data-tooltip-id={'revalidate'}
>
<button className="w-full text-center" onClick={handleButtonClick} disabled={!isEnabled}>
最新の状態に更新する
</button>
</div>
{!isEnabled && (
<Tooltip id="revalidate">
<p>
このページは
{format(storedDate ? addSeconds(storedDate, RefreshSpan) : new Date(), 'HH時mm分ss秒')}
に再度更新が可能です。
</p>
</Tooltip>
)}
</>
)
}
5 changes: 2 additions & 3 deletions src/components/search-box/action.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use server'

import { fetchPlayerWithRecord } from '@/service/supabase/player'
import { fetchAllPlayersName } from '@/service/supabase/player'

const action = async () => {
'use cache'
return await fetchPlayerWithRecord()
return await fetchAllPlayersName()
}

export default action
7 changes: 1 addition & 6 deletions src/features/player/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
'use cache'

import { cacheTag } from 'next/dist/server/use-cache/cache-tag'

import { AchievementView } from '@/components/achievement'
import { PointsLineChart } from '@/components/charts/line-chart'
import { Shiny } from '@/components/common/shiny'
Expand All @@ -25,7 +21,6 @@ interface PlayerPageProps {
}

export const PlayerPage = async ({ player, achievement }: PlayerPageProps) => {
cacheTag(player.name)
const [digest] = player.records

const count = await fetchPlayerCount()
Expand Down Expand Up @@ -96,7 +91,7 @@ export const PlayerPage = async ({ player, achievement }: PlayerPageProps) => {
)}
/>
</div>
<Revalidater tags={[player.name, 'stats']} />
<Revalidater />
<div className="my-4">
<RecordsTable records={player.records} />
</div>
Expand Down
4 changes: 0 additions & 4 deletions src/service/original/ranking.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as cheerio from 'cheerio'
import { format } from 'date-fns'
import { cacheLife } from 'next/dist/server/use-cache/cache-life'

import { Ranking } from '@/types/ranking'

Expand All @@ -10,9 +9,6 @@ const originalPageURL = (index: number) => {
}

export const fetchRankingTable = async () => {
'use cache'
cacheLife('hours')

const ranking: Ranking[] = []

await Promise.all(
Expand Down
2 changes: 0 additions & 2 deletions src/service/supabase/deviation-ranking.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use cache'

import { supabase } from './client'

export const fetchDeviationRanking = async () => {
Expand Down
3 changes: 0 additions & 3 deletions src/service/supabase/online.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { tz } from '@date-fns/tz'
import { sub } from 'date-fns'
import { cacheLife } from 'next/dist/server/use-cache/cache-life'

import { supabase } from './client'

export const fetchOnlinePlayers = async () => {
'use cache'
cacheLife('minutes')
const { data, error } = await supabase(['online'])
.from('record')
.select('player_name, chara, recorded_at')
Expand Down
15 changes: 1 addition & 14 deletions src/service/supabase/player.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { cacheLife } from 'next/dist/server/use-cache/cache-life'
import { cacheTag } from 'next/dist/server/use-cache/cache-tag'

import { supabase } from './client'

export const fetchPlayer = async (playerName: string) => {
'use cache'
cacheTag(playerName)
cacheLife('days')

// プレイヤー情報を取得
const { data: players, error: playerError } = await supabase([playerName])
.from('player')
Expand Down Expand Up @@ -59,9 +52,7 @@ export const fetchPlayer = async (playerName: string) => {
}
}

export const fetchPlayerWithRecord = async (): Promise<string[]> => {
'use cache'
cacheLife('days')
export const fetchAllPlayersName = async (): Promise<string[]> => {
const { data: players, error: joinError } = await supabase(['ranking'])
.from('player')
.select(`name`)
Expand All @@ -76,10 +67,6 @@ export const fetchPlayerWithRecord = async (): Promise<string[]> => {
}

export const fetchPlayerCount = async () => {
'use cache'
cacheTag('stats')
cacheLife('days')

// プレイヤー情報を取得
const result = await supabase(['stats'])
.from('player')
Expand Down
2 changes: 0 additions & 2 deletions src/service/supabase/schedule.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use cache'

import { supabase } from './client'

export const fetchSchedule = async () => {
Expand Down