diff --git a/cmd/cmd.go b/cmd/cmd.go index c6dbd4a..11150e2 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -120,6 +120,17 @@ func (ch *CommandHandler) GetSessions(userId, date string, limit uint8, offset u return sessions, err } +func (ch *CommandHandler) GetSessionsStatistics(userId string) (*model.SessionsStatistics, error) { + sessionStatistics, err := ch.sqlDb.GetSessionsStatistics(context.Background(), userId) + if err != nil { + log.Println(err) + if !errorsx.ContainsFormattedError(err) { + err = errorsx.NewFormattedError(http.StatusNotFound, fmt.Errorf(`failed to get monthly session counts %w`, err)) + } + } + return sessionStatistics, err +} + func (ch *CommandHandler) GetMatches(sessionId uint16, userId string, limit uint8, offset uint16) ([]*model.Match, error) { matches, err := ch.sqlDb.GetMatches(context.Background(), sessionId, userId, limit, offset) if err != nil { diff --git a/gui/src/main/router.tsx b/gui/src/main/router.tsx index 31c4d04..0da14d1 100644 --- a/gui/src/main/router.tsx +++ b/gui/src/main/router.tsx @@ -38,14 +38,7 @@ const router = createHashRouter([ }, { element: , - path: '/sessions/:userId?/:date?/:page?/:limit?', - loader: ({ params }) => - GetSessions( - params.userId ?? '', - '', - Number(params.page ?? 0), - Number(params.limit ?? 0) - ) + path: '/sessions' }, { element: , diff --git a/gui/src/pages/sessions.tsx b/gui/src/pages/sessions.tsx index 1aa0180..3afeec4 100644 --- a/gui/src/pages/sessions.tsx +++ b/gui/src/pages/sessions.tsx @@ -1,37 +1,56 @@ import React from 'react' import { useTranslation } from 'react-i18next' -import { useLoaderData, useNavigate } from 'react-router-dom' - -import * as Page from '@/ui/page' -import * as Table from '@/ui/table' +import { useNavigate } from 'react-router-dom' import { motion } from 'framer-motion' +import { Icon } from '@iconify/react' +import { GetSessions, GetSessionsStatistics } from '@cmd/CommandHandler' import type { model } from '@model' -import { Button } from '@/ui/button' -import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/ui/hover-card' -type DayGroup = Record -type MonthGroup = Record -type YearGroup = Record +import { useErrorPopup } from '@/main/error-popup' +import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/ui/hover-card' +import * as Page from '@/ui/page' +import { Button } from '@/ui/button' export function SessionsListPage() { - const sessions = (useLoaderData() ?? []) as model.Session[] const { i18n, t } = useTranslation() const navigate = useNavigate() + const setError = useErrorPopup() + + const [sessions, setSessions] = React.useState([]) + const [sessionStatistics, setSessionStatistics] = React.useState() + const [year, setYear] = React.useState('') + const [month, setMonth] = React.useState('01') + const [monthIndex, setMonthIndex] = React.useState(0) + + const months = sessionStatistics?.Months ?? [] - const groupedSessions: YearGroup = sessions.reduce((group, sesh) => { - const date = new Date(sesh.createdAt) - const year = date.getFullYear() - const month = date.getMonth() + 1 - const day = date.getDate() + React.useEffect(() => { + GetSessionsStatistics('').then(setSessionStatistics).catch(setError) + }, []) - group[year] = group[year] ?? {} - group[year][month] = group[year][month] ?? [] - group[year][month][day] = group[year][month][day] ?? [] - group[year][month][day].push(sesh) + React.useEffect(() => { + if (months.length > 0 && months[monthIndex]) { + const [month, year] = months[monthIndex].Date.split('-') + setMonth(month) + setYear(year) + } + }, [sessionStatistics, monthIndex]) - return group - }, {}) + React.useEffect(() => { + GetSessions('', month, 0, 0).then(setSessions).catch(setError) + }, [month]) + + const sessionsByDay = (sessions ?? []).reduce( + (group, session) => { + const date = new Date(session.createdAt) + const day = date.getDate() + group[day] = group[day] ?? [] + group[day].push(session) + return group + }, + {} as Record + ) return ( @@ -44,86 +63,96 @@ export function SessionsListPage() { transition={{ delay: 0.125 }} className='overflow-y-scroll' > - {Object.keys(groupedSessions) - .reverse() - .map(year => ( -
-

{year}

- {Object.keys(groupedSessions[year]) - .reverse() - .map(month => ( -
-

- {Intl.DateTimeFormat(i18n.resolvedLanguage, { - month: 'long' - }).format(new Date(`2024-${Number(month) < 10 ? '0' + month : month}-01`))} -

-
+ + +

+ {year} /{' '} + {Intl.DateTimeFormat(i18n.resolvedLanguage, { + month: 'long' + }).format(new Date(`2024-${month}-01`))} +

+ + +
+ {Object.keys(sessionsByDay).map(day => ( +
+ {day} + {sessionsByDay[day].reverse().map(s => ( + + + - - -
-
-
{t('wins')}
-
{s.matchesWon}
-
-
-
{t('losses')}
-
{s.matchesLost}
-
- {s.lpGain != 0 && s.mrGain != 0 && ( - <> -
-
{t('mrGain')}
-
{s.mrGain}
-
-
-
{t('lpGain')}
-
{s.lpGain}
-
- - )} -
-
-
- ))} -
- ))} -
-
- ))} -
+ + {Intl.DateTimeFormat(i18n.resolvedLanguage, { + hour: '2-digit', + minute: '2-digit' + }).format(new Date(s.createdAt))} + + {s.userName} + + + +
+
+
{t('wins')}
+
{s.matchesWon}
+
+
+
{t('losses')}
+
{s.matchesLost}
+
+ {s.lpGain != 0 && s.mrGain != 0 && ( + <> +
+
{t('mrGain')}
+
{s.mrGain}
+
+
+
{t('lpGain')}
+
{s.lpGain}
+
+ + )} +
+
+ + ))} + ))} +
) diff --git a/gui/src/ui/button.tsx b/gui/src/ui/button.tsx index 918f188..8931aa6 100644 --- a/gui/src/ui/button.tsx +++ b/gui/src/ui/button.tsx @@ -6,17 +6,23 @@ export const Button = React.forwardRef< HTMLButtonElement, React.PropsWithChildren> >((props, ref) => { - const { disabled, className, children, ...restProps } = props + const { disabled, className, children, onClick, ...restProps } = props return (