Skip to content

Commit

Permalink
Merge pull request #14 from sweshelo/main
Browse files Browse the repository at this point in the history
v0.3.0
  • Loading branch information
sweshelo authored Feb 15, 2025
2 parents 441327b + 7029fa8 commit 45869e1
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "medusa",
"version": "0.2.1",
"version": "0.3.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
Expand Down
12 changes: 12 additions & 0 deletions src/app/deviation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import DeviationRankingPage from '@/features/deviation'
import { fetchDeviationRanking } from '@/service/supabase/deviation-ranking'

export default async function Page() {
const ranking = await fetchDeviationRanking()

return ranking ? (
<DeviationRankingPage ranking={ranking} />
) : (
<>ランキング情報の取得に失敗しました</>
)
}
21 changes: 13 additions & 8 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'

import { Drawer } from '@/components/drawer'
import { Header } from '@/components/header'
import { DrawerProvider } from '@/hooks/drawer'

import type { Metadata } from 'next'
import './globals.css'
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: {
Expand Down Expand Up @@ -49,14 +51,17 @@ export default async function RootLayout({
<meta name="theme-color" content="#7f1d1d" />
</head>
<body className={`antialiased font-mplus`}>
<Header />
<div className="w-full min-h-screen mx-auto bg-gray-100 sm:p-7">
<div className="max-w-[700px] mx-auto bg-sky-50 p-4 sm:p-8 sm:rounded-lg shadow-2xl">
{children}
<DrawerProvider>
<Header />
<Drawer />
<div className="w-full min-h-screen mx-auto bg-gray-100 sm:p-7">
<div className="max-w-[700px] mx-auto bg-sky-50 p-4 sm:p-8 sm:rounded-lg shadow-2xl">
{children}
</div>
</div>
</div>
<Analytics />
<SpeedInsights />
<Analytics />
<SpeedInsights />
</DrawerProvider>
</body>
</html>
)
Expand Down
12 changes: 12 additions & 0 deletions src/app/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default async function Page() {
return (
<>
<div className="text-center">
<h1>プレーヤー検索</h1>
<div className="m-4">
<p>準備中です</p>
</div>
</div>
</>
)
}
2 changes: 1 addition & 1 deletion src/components/charts/line-chart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const PointsLineChart = ({ records }: PointsLineChartProps) => {
.filter(record => record.elapsed && record.elapsed <= 600)
.reduce<Record<string, { total: number; counts: number; records: number[] }>>(
(acc, record) => {
const date = format(new Date(record.created_at), 'yy/MM/dd')
const date = format(new Date(record.recorded_at ?? ''), 'yy/MM/dd')
if (!acc[date]) acc[date] = { total: 0, counts: 0, records: [] }
acc[date].total += record.diff ?? 0
acc[date].counts += 1
Expand Down
55 changes: 55 additions & 0 deletions src/components/drawer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client'

import Link from 'next/link'

import { useDrawer } from '@/hooks/drawer'

export const Drawer = () => {
const { isOpen, closeDrawer } = useDrawer()

return (
<div>
{/* オーバーレイ */}
<div
className={`fixed inset-0 bg-black bg-opacity-50 transition-opacity z-[1000] ${
isOpen ? 'opacity-100 visible' : 'opacity-0 invisible'
}`}
onClick={closeDrawer}
/>

{/* ドロワー本体 */}
<div
className={`fixed top-0 left-0 h-full w-64 bg-white shadow-lg transform transition-transform z-[2000] ${
isOpen ? 'translate-x-0' : '-translate-x-full'
}`}
>
<div className="w-full bg-red-900">
<div className="max-w-[800px] mx-auto p-4 flex items-center space-x-4">
<button className="w-12 h-12 bg-gray-800 rounded-lg flex items-center justify-center bg-[url('/image/icon.png')] bg-contain" />
<div>
<h1 className="text-white text-2xl font-bold">閻魔帳</h1>
<p className="text-gray-300 text-xs">v2 &quot;medusa&quot; - @sweshelo</p>
</div>
</div>
</div>
<ul className="p-4 space-y-2">
<li>
<Link href="/ranking" className="block p-2 hover:bg-gray-100">
ランキング
</Link>
</li>
<li>
<Link href="/deviation" className="block p-2 hover:bg-gray-100">
偏差値ランキング
</Link>
</li>
<li>
<Link href="/search" className="block p-2 hover:bg-gray-100">
プレイヤー検索
</Link>
</li>
</ul>
</div>
</div>
)
}
27 changes: 17 additions & 10 deletions src/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
'use client'

import Link from 'next/link'

import { useDrawer } from '@/hooks/drawer'

export const Header = () => {
const { openDrawer } = useDrawer()

return (
<Link href={'/'}>
<div className="w-full bg-red-900">
<div className="max-w-[800px] mx-auto p-4 flex items-center space-x-4">
<div className="w-12 h-12 bg-gray-800 rounded-lg flex items-center justify-center bg-[url('/image/icon.png')] bg-contain" />
<div className="flex-grow">
<h1 className="text-white text-2xl font-bold">閻魔帳</h1>
<p className="text-gray-300 text-xs">v2 &quot;medusa&quot; - @sweshelo</p>
</div>
</div>
<div className="w-full bg-red-900">
<div className="max-w-[800px] mx-auto p-4 flex items-center space-x-4">
<button
className="w-12 h-12 bg-gray-800 rounded-lg flex items-center justify-center bg-[url('/image/icon.png')] bg-contain z-1"
onClick={openDrawer}
/>
<Link className="flex-grow" href={'/'}>
<h1 className="text-white text-2xl font-bold">閻魔帳</h1>
<p className="text-gray-300 text-xs">v2 &quot;medusa&quot; - @sweshelo</p>
</Link>
</div>
</Link>
</div>
)
}
8 changes: 6 additions & 2 deletions src/components/player/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ interface PlayerCardProps {
player: Player | Ranking // FIXME: キモすぎるので辞めたい
chara: Record['chara']
ranking: Record['ranking']
children?: React.ReactElement | React.ReactElement[]
}

export const PlayerCard = ({ player, chara, ranking }: PlayerCardProps) => {
export const PlayerCard = ({ player, chara, ranking, children }: PlayerCardProps) => {
return (
<Link className="bg-white rounded-lg flex items-center shadow" href={`/player/${player.name}`}>
<Image
Expand All @@ -22,7 +23,10 @@ export const PlayerCard = ({ player, chara, ranking }: PlayerCardProps) => {
className="w-[80px] h-[60px] rounded-l-lg"
/>
<div className="ml-3 flex-grow">
<div className="text-sm text-gray-600">{ranking}</div>
<div className="flex">
<div className="text-sm text-gray-600">{ranking}</div>
{children}
</div>
<div className="text-3xl font-bold">{player.name}</div>
</div>
</Link>
Expand Down
29 changes: 29 additions & 0 deletions src/features/deviation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react'

import { Headline } from '@/components/common/headline'
import { PlayerCard } from '@/components/player/card'
import { Player } from '@/types/player'
import { Record } from '@/types/record'

interface RankingPageProps {
ranking: (Player & {
record: Record
})[]
}

const DeviationRankingPage = ({ ranking }: RankingPageProps) => {
return (
<>
<Headline title="偏差値ランキング" />
<div className="mt-4 mb-4 space-y-2">
{ranking.map((player, index) => (
<PlayerCard player={player} chara={player.record.chara} ranking={index + 1} key={index}>
<div className="text-sm text-gray-600 ml-1">{`| ${player.deviation_value}`}</div>
</PlayerCard>
))}
</div>
</>
)
}

export default DeviationRankingPage
32 changes: 32 additions & 0 deletions src/hooks/drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client'

import { createContext, useContext, useState, ReactNode } from 'react'

type DrawerContextType = {
isOpen: boolean
openDrawer: () => void
closeDrawer: () => void
}

const DrawerContext = createContext<DrawerContextType | undefined>(undefined)

export const DrawerProvider = ({ children }: { children: ReactNode }) => {
const [isOpen, setIsOpen] = useState(false)

const openDrawer = () => setIsOpen(true)
const closeDrawer = () => setIsOpen(false)

return (
<DrawerContext.Provider value={{ isOpen, openDrawer, closeDrawer }}>
{children}
</DrawerContext.Provider>
)
}

export const useDrawer = () => {
const context = useContext(DrawerContext)
if (!context) {
throw new Error('useDrawer must be used within a DrawerProvider')
}
return context
}
41 changes: 41 additions & 0 deletions src/service/supabase/deviation-ranking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use cache'

import { supabase } from './client'

export const fetchDeviationRanking = async () => {
const { data: players, error: playerError } = await supabase
.from('player')
.select('*')
.gt('deviation_value', 50)
.order('deviation_value', { ascending: false })

if (playerError) {
console.error(`Error fetching player: ${playerError.message}`)
}

// 各プレイヤーに対して最新の record を取得する
const playersWithRecord = await Promise.all(
(players ?? []).map(async player => {
const { data: records, error: recordError } = await supabase
.from('record')
.select('*')
.eq('player_name', player.name)
// 最新のレコードを取得するため created_at で降順にソートし、1件だけ取得
.order('created_at', { ascending: false })
.limit(1)

if (recordError) {
console.error(`Error fetching record for player ${player.name}: ${recordError.message}`)
}

const [record] = records ?? []

return {
...player,
record,
}
})
)

return playersWithRecord
}

0 comments on commit 45869e1

Please sign in to comment.