forked from sk1982/actaeon
refactor: colocate page-specific components
This commit is contained in:
parent
f26ff35643
commit
c66055def1
@ -1,11 +1,11 @@
|
||||
'use server';
|
||||
|
||||
import { requireUser } from '@/actions/auth';
|
||||
import { PlaylogFilterState } from '@/app/(with-header)/chuni/playlog/page';
|
||||
import { db } from '@/db';
|
||||
import { CHUNI_MUSIC_PROPERTIES } from '@/helpers/chuni/music';
|
||||
import { chuniRating } from '@/helpers/chuni/rating';
|
||||
import { sql } from 'kysely';
|
||||
import { PlaylogFilterState } from '@/components/chuni/playlog-list';
|
||||
|
||||
const SORT_KEYS = {
|
||||
Date: 'id',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { PageProps } from '@/types/page';
|
||||
import { headers } from 'next/headers';
|
||||
import { LoginCard } from '@/components/login-card';
|
||||
import { LoginCard } from './login-card';
|
||||
|
||||
export default async function LoginPage({ searchParams }: PageProps) {
|
||||
const referer = headers().get('referer');
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PageProps } from '@/types/page';
|
||||
import { RegisterCard } from '@/components/register-card';
|
||||
import { RegisterCard } from './register-card';
|
||||
|
||||
export default async function RegisterPage({ searchParams }: PageProps) {
|
||||
return (<RegisterCard callback={searchParams?.['callbackUrl']?.toString()} />)
|
||||
|
@ -1,23 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { createUserWithAccessCode, deleteUser, setUserPermissions } from '@/actions/user';
|
||||
import { PermissionEditModal } from './permission-edit-modal';
|
||||
import { PermissionEditModal } from '@/components/permission-edit-modal';
|
||||
import { useState } from 'react';
|
||||
import { USER_PERMISSION_NAMES, UserPermissions } from '@/types/permissions';
|
||||
import { Button, Divider, Tooltip, Input, Accordion, AccordionItem, Link, Spacer } from '@nextui-org/react';
|
||||
import { ChevronDownIcon, CreditCardIcon, PencilSquareIcon, PlusIcon } from '@heroicons/react/24/outline';
|
||||
import { usePromptModal } from './prompt-modal';
|
||||
import { usePromptModal } from '@/components/prompt-modal';
|
||||
import { ArrowPathIcon } from '@heroicons/react/24/outline';
|
||||
import { generateAccessCode } from '@/helpers/access-code';
|
||||
import { useUser } from '@/helpers/use-user';
|
||||
import { TbBrandAppleArcade, TbCrown, TbFileSettings, TbUserShield } from 'react-icons/tb';
|
||||
import { hasPermission } from '@/helpers/permissions';
|
||||
import { AimeCard } from './aime-card';
|
||||
import { useErrorModal } from './error-modal';
|
||||
import { AimeCard } from '@/components/aime-card';
|
||||
import { useErrorModal } from '@/components/error-modal';
|
||||
import { AdminUser } from '@/data/user';
|
||||
import { adminAddCardToUser } from '@/actions/card';
|
||||
import { TrashIcon } from '@heroicons/react/24/outline';
|
||||
import { useConfirmModal } from './confirm-modal';
|
||||
import { useConfirmModal } from '@/components/confirm-modal';
|
||||
|
||||
const PERMISSION_ICONS = new Map([
|
||||
[UserPermissions.USERMOD, TbUserShield],
|
@ -1,6 +1,6 @@
|
||||
import { requireUser } from '@/actions/auth';
|
||||
import { UserPermissions } from '@/types/permissions';
|
||||
import { AdminUserList } from '@/components/admin-user-list';
|
||||
import { AdminUserList } from './admin-user-list';
|
||||
import { getUsers } from '@/data/user';
|
||||
|
||||
export default async function AdminUsersPage() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Arcade, ArcadeCab, ArcadeLink, ArcadeUser } from '@/data/arcade';
|
||||
import { JoinPrivacy, Visibility } from '@/types/privacy-visibility';
|
||||
import { Autocomplete, AutocompleteItem, Button, Divider, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Input, Select, SelectItem, Tooltip } from '@nextui-org/react';
|
||||
import { ChevronDownIcon, GlobeAltIcon, LinkIcon, LockClosedIcon, PencilIcon, PencilSquareIcon, PlusIcon, UserMinusIcon, UserPlusIcon } from '@heroicons/react/24/outline';
|
||||
import { JoinPrivacy } from '@/types/privacy-visibility';
|
||||
import { Autocomplete, AutocompleteItem, Button, Divider, Input, Select, SelectItem, Tooltip } from '@nextui-org/react';
|
||||
import { LinkIcon, PencilIcon, PencilSquareIcon, PlusIcon, UserMinusIcon, UserPlusIcon } from '@heroicons/react/24/outline';
|
||||
import { useRef, useState } from 'react';
|
||||
import { useUser } from '@/helpers/use-user';
|
||||
import { hasArcadePermission, hasPermission } from '@/helpers/permissions';
|
||||
@ -13,15 +13,14 @@ import { COUNTRY_CODES } from '@/types/country';
|
||||
import { ArcadeUpdate, createArcadeLink, deleteArcade, deleteArcadeLink, joinPublicArcade, removeUserFromArcade, setUserArcadePermissions, updateArcade } from '@/actions/arcade';
|
||||
import { useErrorModal } from '@/components/error-modal';
|
||||
import { Entries } from 'type-fest';
|
||||
import { Cab } from '@/components/cab';
|
||||
import { Cab } from './cab';
|
||||
import Link from 'next/link';
|
||||
import { useConfirmModal } from '@/components/confirm-modal';
|
||||
import { XMarkIcon } from '@heroicons/react/20/solid';
|
||||
import { JoinLinksModal } from '@/components/join-links-modal';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { PermissionEditModal, PermissionEditModalUser } from '@/components/permission-edit-modal';
|
||||
import { VisibilityIcon } from './visibility-icon';
|
||||
import { VisibilityDropdown } from './visibility-dropdown';
|
||||
import { VisibilityDropdown } from '@/components/visibility-dropdown';
|
||||
|
||||
export type ArcadeProps = {
|
||||
arcade: Arcade,
|
@ -1,7 +1,7 @@
|
||||
import { getUser } from '@/actions/auth';
|
||||
import { getArcadeCabs, getArcadeInviteLinks, getArcades, getArcadeUsers } from '@/data/arcade';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { ArcadeDetail } from '@/components/arcade';
|
||||
import { ArcadeDetail } from './arcade';
|
||||
import { PrivateVisibilityError } from '@/components/private-visibility-error';
|
||||
|
||||
export default async function ArcadeDetailPage({ params }: { params: { arcadeId: string }}) {
|
||||
|
@ -3,7 +3,7 @@ import { getUser } from '@/actions/auth';
|
||||
import { Divider, Tooltip } from '@nextui-org/react';
|
||||
import { UserGroupIcon } from '@heroicons/react/24/outline';
|
||||
import Link from 'next/link';
|
||||
import { CreateArcadeButton } from '@/components/create-arcade-button';
|
||||
import { CreateArcadeButton } from './create-arcade-button';
|
||||
import { VisibilityIcon } from '@/components/visibility-icon';
|
||||
|
||||
const getLocation = (arcade: Arcade) => {
|
||||
|
@ -4,7 +4,7 @@ import { ChuniPlaylogCard } from '@/components/chuni/playlog-card';
|
||||
import { getUserData, getUserRating } from '@/actions/chuni/profile';
|
||||
import { requireUser } from '@/actions/auth';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { ChuniTopRatingSidebar } from '@/components/chuni/top-rating-sidebar';
|
||||
import { ChuniTopRatingSidebar } from './top-rating-sidebar';
|
||||
import { Button } from '@nextui-org/react';
|
||||
import Link from 'next/link';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { ChuniTopRating } from '@/components/chuni/top-rating';
|
||||
import { ChuniTopRating } from './top-rating';
|
||||
import { getUserRating } from '@/actions/chuni/profile';
|
||||
import { useState } from 'react';
|
||||
import { Button, ButtonGroup } from '@nextui-org/react';
|
@ -5,7 +5,7 @@ import { ChuniPlaylog } from '@/actions/chuni/playlog';
|
||||
import { MusicPlayer } from '@/components/music-player';
|
||||
import { getJacketUrl, getMusicUrl } from '@/helpers/assets';
|
||||
import { Ticker } from '@/components/ticker';
|
||||
import { ChuniMusicPlaylog } from '@/components/chuni/music-playlog';
|
||||
import { ChuniMusicPlaylog } from './music-playlog';
|
||||
import { Button } from '@nextui-org/react';
|
||||
import { HeartIcon as SolidHeartIcon } from '@heroicons/react/24/solid';
|
||||
import { HeartIcon as OutlineHeartIcon } from '@heroicons/react/24/outline';
|
@ -2,7 +2,7 @@ import { getMusic } from '@/actions/chuni/music';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { getPlaylog } from '@/actions/chuni/playlog';
|
||||
|
||||
import { ChuniMusicDetail } from '@/components/chuni/music-detail';
|
||||
import { ChuniMusicDetail } from './music-detail';
|
||||
|
||||
export default async function ChuniMusicDetailPage({ params }: { params: { musicId: string } }) {
|
||||
const musicId = parseInt(params.musicId);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { getMusic } from '@/actions/chuni/music';
|
||||
import { ChuniMusicList } from '@/components/chuni/music-list';
|
||||
import { ChuniMusicList } from './music-list';
|
||||
|
||||
|
||||
export default async function ChuniMusicPage() {
|
||||
|
@ -1,6 +1,115 @@
|
||||
import { ChuniPlaylogList } from '@/components/chuni/playlog-list';
|
||||
'use client';
|
||||
|
||||
import { CHUNI_FILTER_DIFFICULTY, CHUNI_FILTER_GENRE, CHUNI_FILTER_LAMP, CHUNI_FILTER_LEVEL, CHUNI_FILTER_RATING, CHUNI_FILTER_SCORE, CHUNI_FILTER_WORLDS_END_STARS, CHUNI_FILTER_WORLDS_END_TAG, getLevelValFromStop } from '@/helpers/chuni/filter';
|
||||
import { FilterField, FilterSorter } from '@/components/filter-sorter';
|
||||
import { SelectItem } from '@nextui-org/react';
|
||||
import { ChuniMusic } from '@/actions/chuni/music';
|
||||
import { ArrayIndices } from 'type-fest';
|
||||
import { ChuniPlaylog, getPlaylog } from '@/actions/chuni/playlog';
|
||||
import { WindowScrollerGrid } from '@/components/window-scroller-grid';
|
||||
import { ChuniPlaylogCard } from '@/components/chuni/playlog-card';
|
||||
import { useBreakpoint } from '@/helpers/use-breakpoint';
|
||||
|
||||
export default function ChuniPlaylogPage() {
|
||||
return (<ChuniPlaylogList />);
|
||||
const FILTERERS = ([
|
||||
CHUNI_FILTER_DIFFICULTY,
|
||||
CHUNI_FILTER_GENRE,
|
||||
{
|
||||
...CHUNI_FILTER_LAMP,
|
||||
props: {
|
||||
children: [
|
||||
<SelectItem key="aj" value="aj">All Justice</SelectItem>,
|
||||
<SelectItem key="fc" value="fc">Full Combo</SelectItem>,
|
||||
<SelectItem key="clear" value="clear">Clear</SelectItem>,
|
||||
],
|
||||
selectionMode: 'multiple'
|
||||
}
|
||||
},
|
||||
CHUNI_FILTER_WORLDS_END_TAG,
|
||||
{
|
||||
...CHUNI_FILTER_SCORE,
|
||||
className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1'
|
||||
},
|
||||
// CHUNI_FILTER_FAVORITE,
|
||||
({
|
||||
type: 'dateSelect',
|
||||
name: 'dateRange',
|
||||
label: 'Date Range',
|
||||
value: undefined,
|
||||
className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1',
|
||||
filter: () => false
|
||||
} as FilterField<ChuniMusic, 'dateSelect', 'dateRange'>),
|
||||
{
|
||||
...CHUNI_FILTER_WORLDS_END_STARS,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
},
|
||||
{
|
||||
...CHUNI_FILTER_LEVEL,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
},
|
||||
{
|
||||
...CHUNI_FILTER_RATING,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
}
|
||||
] as const);
|
||||
|
||||
export type PlaylogFilterState = {
|
||||
[K in ArrayIndices<(typeof FILTERERS)> as (typeof FILTERERS)[K]['name']]: (typeof FILTERERS[K])['value']
|
||||
};
|
||||
|
||||
const SORTERS = [{
|
||||
name: 'Date'
|
||||
}, {
|
||||
name: 'Rating'
|
||||
}, {
|
||||
name: 'Level'
|
||||
}, {
|
||||
name: 'Score'
|
||||
}] as const;
|
||||
|
||||
const PER_PAGE = [25, 50, 100, 250];
|
||||
|
||||
const REMOTE_FILTERERS = FILTERERS.map(({ filter, ...x }) => x);
|
||||
|
||||
const ChuniPlaylogGrid = ({ items }: { items: ChuniPlaylog['data']; }) => {
|
||||
const breakpoint = useBreakpoint();
|
||||
let colSize = 1000;
|
||||
let rowSize = 275;
|
||||
|
||||
if (breakpoint !== 'sm' && breakpoint !== undefined) {
|
||||
colSize = 550;
|
||||
rowSize = 200;
|
||||
}
|
||||
|
||||
return (<WindowScrollerGrid rowSize={rowSize} colSize={colSize} items={items}>
|
||||
{item => <div className="p-1 w-full h-full max-w-full">
|
||||
<ChuniPlaylogCard playlog={item} showDetails
|
||||
badgeClass="h-4 sm:h-5 md:-mt-3"
|
||||
className="w-full h-full max-w-full" />
|
||||
</div>}
|
||||
</WindowScrollerGrid>);
|
||||
};
|
||||
|
||||
export default function ChuniPlaylogList() {
|
||||
return (<FilterSorter className="flex-grow"
|
||||
filterers={REMOTE_FILTERERS}
|
||||
defaultAscending={false}
|
||||
data={({ filters: f, pageSize, currentPage, search, sort, ascending }): Promise<ChuniPlaylog> => {
|
||||
const filterState = {
|
||||
...f, level: [...f.level],
|
||||
dateRange: f.dateRange ? { ...f.dateRange } : undefined
|
||||
} as PlaylogFilterState;
|
||||
filterState.level[0] = getLevelValFromStop(filterState.level[0]);
|
||||
filterState.level[1] = getLevelValFromStop(filterState.level[1]);
|
||||
if (filterState.dateRange?.to) {
|
||||
filterState.dateRange.to = new Date(filterState.dateRange.to);
|
||||
filterState.dateRange.to.setHours(23, 59, 59, 999);
|
||||
}
|
||||
|
||||
return getPlaylog({ ...filterState, sort, limit: pageSize, offset: pageSize * (currentPage - 1), search, ascending });
|
||||
}}
|
||||
sorters={SORTERS} pageSizes={PER_PAGE}>
|
||||
{(_, d) => <div className="w-full max-w-full flex-grow my-2">
|
||||
<ChuniPlaylogGrid items={d} />
|
||||
</div>}
|
||||
</FilterSorter>);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { requireUser } from '@/actions/auth';
|
||||
import { getUserData } from '@/actions/chuni/profile';
|
||||
import { getUserboxItems } from '@/actions/chuni/userbox';
|
||||
import { ChuniUserbox } from '@/components/chuni/userbox';
|
||||
import { ChuniUserbox } from './userbox';
|
||||
import { Viewport } from 'next';
|
||||
|
||||
export const viewport: Viewport = {
|
||||
|
@ -8,13 +8,10 @@ import { ThemeSwitcherDropdown, ThemeSwitcherSwitch } from '@/components/theme-s
|
||||
import { AdjustmentsHorizontalIcon } from '@heroicons/react/24/solid';
|
||||
import { login, logout } from '@/actions/auth';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { UserPayload } from '@/types/user';
|
||||
import { MAIN_ROUTES, ROUTES, Subroute, UserOnly, filterRoute } from '@/routes';
|
||||
import { useUser } from '@/helpers/use-user';
|
||||
import { useBreakpoint } from '@/helpers/use-breakpoint';
|
||||
import { useCookies } from 'next-client-cookies';
|
||||
import { UserPermissions } from '@/types/permissions';
|
||||
import { hasPermission } from '@/helpers/permissions';
|
||||
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
export type HeaderSidebarProps = {
|
@ -1,6 +1,6 @@
|
||||
import { LayoutProps } from '@/types/layout';
|
||||
import { ClientProviders } from '@/components/client-providers';
|
||||
import { HeaderSidebar } from '@/components/header-sidebar';
|
||||
import { HeaderSidebar } from './header-sidebar';
|
||||
|
||||
export default async function HeaderLayout({children}: LayoutProps) {
|
||||
return (<ClientProviders>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { getCards } from '@/actions/card';
|
||||
import { Divider } from '@nextui-org/react';
|
||||
import { AimeCard } from '@/components/aime-card';
|
||||
import { UserSettings } from '@/components/user-settings';
|
||||
import { UserSettings } from './user-settings';
|
||||
|
||||
export default async function SettingsPage() {
|
||||
const card = await getCards();
|
||||
|
@ -6,7 +6,7 @@ import { getValidHomepageRoutes } from '@/routes';
|
||||
import { USER_VISIBILITY_NAMES, UserVisibility } from '@/types/user';
|
||||
import { Button, Checkbox, CheckboxGroup, Divider, Select, SelectItem, SelectSection } from '@nextui-org/react';
|
||||
import { useState } from 'react';
|
||||
import { useErrorModal } from './error-modal';
|
||||
import { useErrorModal } from '@/components/error-modal';
|
||||
|
||||
export const UserSettings = () => {
|
||||
const user = useUser({ required: true });
|
@ -2,7 +2,7 @@ import { getUser } from '@/actions/auth';
|
||||
import { getTeamInviteLinks, getTeams, getTeamUsers } from '@/data/team';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { PrivateVisibilityError } from '@/components/private-visibility-error';
|
||||
import { TeamDetail } from '@/components/team';
|
||||
import { TeamDetail } from './team';
|
||||
|
||||
export default async function TeamDetailPage({ params }: { params: { teamId: string }}) {
|
||||
const user = await getUser();
|
||||
|
@ -2,18 +2,18 @@
|
||||
|
||||
import { useRef, useState } from 'react';
|
||||
import { Team, TeamUser } from '@/data/team';
|
||||
import { VisibilityDropdown } from './visibility-dropdown';
|
||||
import { VisibilityDropdown } from '@/components/visibility-dropdown';
|
||||
import { Button, Divider, Input, Select, SelectItem, Tooltip } from '@nextui-org/react';
|
||||
import { JoinPrivacy } from '@/types/privacy-visibility';
|
||||
import { LinkIcon, PencilIcon, UserMinusIcon, UserPlusIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
||||
import { useUser } from '@/helpers/use-user';
|
||||
import { createTeamLink, deleteTeam, deleteTeamLink, joinPublicTeam, modifyTeam, removeUserFromTeam } from '@/actions/team';
|
||||
import { useErrorModal } from './error-modal';
|
||||
import { useErrorModal } from '@/components/error-modal';
|
||||
import { UserPermissions } from '@/types/permissions';
|
||||
import { hasPermission } from '@/helpers/permissions';
|
||||
import { useConfirmModal } from './confirm-modal';
|
||||
import { useConfirmModal } from '@/components/confirm-modal';
|
||||
import { DB } from '@/types/db';
|
||||
import { JoinLinksModal } from './join-links-modal';
|
||||
import { JoinLinksModal } from '@/components/join-links-modal';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
@ -1,8 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import { Button, Tooltip } from '@nextui-org/react';
|
||||
import { usePromptModal } from './prompt-modal';
|
||||
import { useErrorModal } from './error-modal';
|
||||
import { usePromptModal } from '@/components/prompt-modal';
|
||||
import { useErrorModal } from '@/components/error-modal';
|
||||
import { PlusIcon } from '@heroicons/react/24/outline';
|
||||
import { useUser } from '@/helpers/use-user';
|
||||
import { createTeam } from '@/actions/team';
|
@ -1,5 +1,5 @@
|
||||
import { getUser } from '@/actions/auth';
|
||||
import { CreateTeamButton } from '@/components/create-team-button';
|
||||
import { CreateTeamButton } from './create-team-button';
|
||||
import { VisibilityIcon } from '@/components/visibility-icon';
|
||||
import { getTeams } from '@/data/team';
|
||||
import { UserGroupIcon } from '@heroicons/react/24/outline';
|
||||
|
@ -1,108 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { CHUNI_FILTER_DIFFICULTY, CHUNI_FILTER_GENRE, CHUNI_FILTER_LAMP, CHUNI_FILTER_LEVEL, CHUNI_FILTER_RATING, CHUNI_FILTER_SCORE, CHUNI_FILTER_WORLDS_END_STARS, CHUNI_FILTER_WORLDS_END_TAG, getLevelValFromStop } from '@/helpers/chuni/filter';
|
||||
import { FilterField, FilterSorter } from '@/components/filter-sorter';
|
||||
import { SelectItem } from '@nextui-org/react';
|
||||
import { ChuniMusic } from '@/actions/chuni/music';
|
||||
import { ArrayIndices } from 'type-fest';
|
||||
import { ChuniPlaylog, getPlaylog } from '@/actions/chuni/playlog';
|
||||
import { WindowScrollerGrid } from '@/components/window-scroller-grid';
|
||||
import { ChuniPlaylogCard } from '@/components/chuni/playlog-card';
|
||||
import { useBreakpoint } from '@/helpers/use-breakpoint';
|
||||
|
||||
const FILTERERS = ([
|
||||
CHUNI_FILTER_DIFFICULTY,
|
||||
CHUNI_FILTER_GENRE,
|
||||
{ ...CHUNI_FILTER_LAMP,
|
||||
props: {
|
||||
children: [
|
||||
<SelectItem key="aj" value="aj">All Justice</SelectItem>,
|
||||
<SelectItem key="fc" value="fc">Full Combo</SelectItem>,
|
||||
<SelectItem key="clear" value="clear">Clear</SelectItem>,
|
||||
],
|
||||
selectionMode: 'multiple'
|
||||
}
|
||||
},
|
||||
CHUNI_FILTER_WORLDS_END_TAG,
|
||||
{ ...CHUNI_FILTER_SCORE,
|
||||
className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1'
|
||||
},
|
||||
// CHUNI_FILTER_FAVORITE,
|
||||
({
|
||||
type: 'dateSelect',
|
||||
name: 'dateRange',
|
||||
label: 'Date Range',
|
||||
value: undefined,
|
||||
className: 'col-span-6 md:col-span-3 lg:col-span-2 5xl:col-span-1',
|
||||
filter: () => false
|
||||
} as FilterField<ChuniMusic, 'dateSelect', 'dateRange'>),
|
||||
{ ...CHUNI_FILTER_WORLDS_END_STARS,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
},
|
||||
{ ...CHUNI_FILTER_LEVEL,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
},
|
||||
{ ...CHUNI_FILTER_RATING,
|
||||
className: 'col-span-full md:col-span-6 lg:col-span-4 5xl:col-span-2'
|
||||
}
|
||||
] as const)
|
||||
|
||||
export type PlaylogFilterState = {
|
||||
[K in ArrayIndices<(typeof FILTERERS)> as (typeof FILTERERS)[K]['name']]: (typeof FILTERERS[K])['value']
|
||||
};
|
||||
|
||||
const SORTERS = [{
|
||||
name: 'Date'
|
||||
}, {
|
||||
name: 'Rating'
|
||||
}, {
|
||||
name: 'Level'
|
||||
}, {
|
||||
name: 'Score'
|
||||
}] as const;
|
||||
|
||||
const PER_PAGE = [25, 50, 100, 250];
|
||||
|
||||
const REMOTE_FILTERERS = FILTERERS.map(({ filter, ...x }) => x);
|
||||
|
||||
const ChuniPlaylogGrid = ({ items }: { items: ChuniPlaylog['data'] }) => {
|
||||
const breakpoint = useBreakpoint();
|
||||
let colSize = 1000;
|
||||
let rowSize = 275;
|
||||
|
||||
if (breakpoint !== 'sm' && breakpoint !== undefined) {
|
||||
colSize = 550;
|
||||
rowSize = 200;
|
||||
}
|
||||
|
||||
return (<WindowScrollerGrid rowSize={rowSize} colSize={colSize} items={items}>
|
||||
{item => <div className="p-1 w-full h-full max-w-full">
|
||||
<ChuniPlaylogCard playlog={item} showDetails
|
||||
badgeClass="h-4 sm:h-5 md:-mt-3"
|
||||
className="w-full h-full max-w-full" />
|
||||
</div>}
|
||||
</WindowScrollerGrid>);
|
||||
};
|
||||
|
||||
export const ChuniPlaylogList = () => {
|
||||
return (<FilterSorter className="flex-grow"
|
||||
filterers={REMOTE_FILTERERS}
|
||||
defaultAscending={false}
|
||||
data={({ filters: f, pageSize, currentPage, search, sort, ascending }): Promise<ChuniPlaylog> => {
|
||||
const filterState = { ...f, level: [...f.level],
|
||||
dateRange: f.dateRange ? { ...f.dateRange } : undefined } as PlaylogFilterState;
|
||||
filterState.level[0] = getLevelValFromStop(filterState.level[0]);
|
||||
filterState.level[1] = getLevelValFromStop(filterState.level[1]);
|
||||
if (filterState.dateRange?.to) {
|
||||
filterState.dateRange.to = new Date(filterState.dateRange.to);
|
||||
filterState.dateRange.to.setHours(23, 59, 59, 999);
|
||||
}
|
||||
|
||||
return getPlaylog({ ...filterState, sort, limit: pageSize, offset: pageSize * (currentPage - 1), search, ascending });
|
||||
}}
|
||||
sorters={SORTERS} pageSizes={PER_PAGE}>
|
||||
{(_, d) => <div className="w-full max-w-full flex-grow my-2">
|
||||
<ChuniPlaylogGrid items={d} />
|
||||
</div>}
|
||||
</FilterSorter>);
|
||||
};
|
Loading…
Reference in New Issue
Block a user