diff --git a/src/actions/chuni/playlog.ts b/src/actions/chuni/playlog.ts
index 76123f4..3751a00 100644
--- a/src/actions/chuni/playlog.ts
+++ b/src/actions/chuni/playlog.ts
@@ -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',
diff --git a/src/components/login-card.tsx b/src/app/(centered)/auth/login/login-card.tsx
similarity index 100%
rename from src/components/login-card.tsx
rename to src/app/(centered)/auth/login/login-card.tsx
diff --git a/src/app/(centered)/auth/login/page.tsx b/src/app/(centered)/auth/login/page.tsx
index 6b2832a..faa729b 100644
--- a/src/app/(centered)/auth/login/page.tsx
+++ b/src/app/(centered)/auth/login/page.tsx
@@ -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');
diff --git a/src/app/(centered)/auth/register/page.tsx b/src/app/(centered)/auth/register/page.tsx
index e87152f..1b14cb0 100644
--- a/src/app/(centered)/auth/register/page.tsx
+++ b/src/app/(centered)/auth/register/page.tsx
@@ -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 ()
diff --git a/src/components/register-card.tsx b/src/app/(centered)/auth/register/register-card.tsx
similarity index 100%
rename from src/components/register-card.tsx
rename to src/app/(centered)/auth/register/register-card.tsx
diff --git a/src/components/admin-user-list.tsx b/src/app/(with-header)/admin/users/admin-user-list.tsx
similarity index 95%
rename from src/components/admin-user-list.tsx
rename to src/app/(with-header)/admin/users/admin-user-list.tsx
index 9124458..6442965 100644
--- a/src/components/admin-user-list.tsx
+++ b/src/app/(with-header)/admin/users/admin-user-list.tsx
@@ -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],
diff --git a/src/app/(with-header)/admin/users/page.tsx b/src/app/(with-header)/admin/users/page.tsx
index e0e5675..15d6d3d 100644
--- a/src/app/(with-header)/admin/users/page.tsx
+++ b/src/app/(with-header)/admin/users/page.tsx
@@ -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() {
diff --git a/src/components/arcade.tsx b/src/app/(with-header)/arcade/[arcadeId]/arcade.tsx
similarity index 96%
rename from src/components/arcade.tsx
rename to src/app/(with-header)/arcade/[arcadeId]/arcade.tsx
index dd68b91..4b3a490 100644
--- a/src/components/arcade.tsx
+++ b/src/app/(with-header)/arcade/[arcadeId]/arcade.tsx
@@ -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,
diff --git a/src/components/cab.tsx b/src/app/(with-header)/arcade/[arcadeId]/cab.tsx
similarity index 100%
rename from src/components/cab.tsx
rename to src/app/(with-header)/arcade/[arcadeId]/cab.tsx
diff --git a/src/app/(with-header)/arcade/[arcadeId]/page.tsx b/src/app/(with-header)/arcade/[arcadeId]/page.tsx
index b67c054..ca8ff99 100644
--- a/src/app/(with-header)/arcade/[arcadeId]/page.tsx
+++ b/src/app/(with-header)/arcade/[arcadeId]/page.tsx
@@ -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 }}) {
diff --git a/src/components/create-arcade-button.tsx b/src/app/(with-header)/arcade/create-arcade-button.tsx
similarity index 100%
rename from src/components/create-arcade-button.tsx
rename to src/app/(with-header)/arcade/create-arcade-button.tsx
diff --git a/src/app/(with-header)/arcade/page.tsx b/src/app/(with-header)/arcade/page.tsx
index e5e152a..b74b45e 100644
--- a/src/app/(with-header)/arcade/page.tsx
+++ b/src/app/(with-header)/arcade/page.tsx
@@ -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) => {
diff --git a/src/app/(with-header)/chuni/dashboard/page.tsx b/src/app/(with-header)/chuni/dashboard/page.tsx
index 7bfbffa..6db718c 100644
--- a/src/app/(with-header)/chuni/dashboard/page.tsx
+++ b/src/app/(with-header)/chuni/dashboard/page.tsx
@@ -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';
diff --git a/src/components/chuni/top-rating-sidebar.tsx b/src/app/(with-header)/chuni/dashboard/top-rating-sidebar.tsx
similarity index 98%
rename from src/components/chuni/top-rating-sidebar.tsx
rename to src/app/(with-header)/chuni/dashboard/top-rating-sidebar.tsx
index 7bcac71..28e8729 100644
--- a/src/components/chuni/top-rating-sidebar.tsx
+++ b/src/app/(with-header)/chuni/dashboard/top-rating-sidebar.tsx
@@ -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';
diff --git a/src/components/chuni/top-rating.tsx b/src/app/(with-header)/chuni/dashboard/top-rating.tsx
similarity index 100%
rename from src/components/chuni/top-rating.tsx
rename to src/app/(with-header)/chuni/dashboard/top-rating.tsx
diff --git a/src/components/chuni/music-detail.tsx b/src/app/(with-header)/chuni/music/[musicId]/music-detail.tsx
similarity index 96%
rename from src/components/chuni/music-detail.tsx
rename to src/app/(with-header)/chuni/music/[musicId]/music-detail.tsx
index a406a08..6f52673 100644
--- a/src/components/chuni/music-detail.tsx
+++ b/src/app/(with-header)/chuni/music/[musicId]/music-detail.tsx
@@ -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';
diff --git a/src/components/chuni/music-playlog.tsx b/src/app/(with-header)/chuni/music/[musicId]/music-playlog.tsx
similarity index 100%
rename from src/components/chuni/music-playlog.tsx
rename to src/app/(with-header)/chuni/music/[musicId]/music-playlog.tsx
diff --git a/src/app/(with-header)/chuni/music/[musicId]/page.tsx b/src/app/(with-header)/chuni/music/[musicId]/page.tsx
index 613c940..3645cfc 100644
--- a/src/app/(with-header)/chuni/music/[musicId]/page.tsx
+++ b/src/app/(with-header)/chuni/music/[musicId]/page.tsx
@@ -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);
diff --git a/src/components/chuni/music-list.tsx b/src/app/(with-header)/chuni/music/music-list.tsx
similarity index 100%
rename from src/components/chuni/music-list.tsx
rename to src/app/(with-header)/chuni/music/music-list.tsx
diff --git a/src/app/(with-header)/chuni/music/page.tsx b/src/app/(with-header)/chuni/music/page.tsx
index 1060538..4850d18 100644
--- a/src/app/(with-header)/chuni/music/page.tsx
+++ b/src/app/(with-header)/chuni/music/page.tsx
@@ -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() {
diff --git a/src/app/(with-header)/chuni/playlog/page.tsx b/src/app/(with-header)/chuni/playlog/page.tsx
index a27af93..f1fb7cc 100644
--- a/src/app/(with-header)/chuni/playlog/page.tsx
+++ b/src/app/(with-header)/chuni/playlog/page.tsx
@@ -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 ();
-}
+const FILTERERS = ([
+ CHUNI_FILTER_DIFFICULTY,
+ CHUNI_FILTER_GENRE,
+ {
+ ...CHUNI_FILTER_LAMP,
+ props: {
+ children: [
+ All Justice,
+ Full Combo,
+ Clear,
+ ],
+ 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),
+ {
+ ...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 (
+ {item =>
+
+
}
+ );
+};
+
+export default function ChuniPlaylogList() {
+ return ( => {
+ 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) =>
+
+
}
+ );
+};
diff --git a/src/app/(with-header)/chuni/userbox/page.tsx b/src/app/(with-header)/chuni/userbox/page.tsx
index 32ad1bb..59e9c10 100644
--- a/src/app/(with-header)/chuni/userbox/page.tsx
+++ b/src/app/(with-header)/chuni/userbox/page.tsx
@@ -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 = {
diff --git a/src/components/chuni/userbox.tsx b/src/app/(with-header)/chuni/userbox/userbox.tsx
similarity index 100%
rename from src/components/chuni/userbox.tsx
rename to src/app/(with-header)/chuni/userbox/userbox.tsx
diff --git a/src/components/header-sidebar.tsx b/src/app/(with-header)/header-sidebar.tsx
similarity index 97%
rename from src/components/header-sidebar.tsx
rename to src/app/(with-header)/header-sidebar.tsx
index 48290a5..f2c0a30 100644
--- a/src/components/header-sidebar.tsx
+++ b/src/app/(with-header)/header-sidebar.tsx
@@ -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 = {
diff --git a/src/app/(with-header)/layout.tsx b/src/app/(with-header)/layout.tsx
index 5e9a1ee..b86aa07 100644
--- a/src/app/(with-header)/layout.tsx
+++ b/src/app/(with-header)/layout.tsx
@@ -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 (
diff --git a/src/app/(with-header)/settings/page.tsx b/src/app/(with-header)/settings/page.tsx
index 8ca5d99..2f49d92 100644
--- a/src/app/(with-header)/settings/page.tsx
+++ b/src/app/(with-header)/settings/page.tsx
@@ -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();
diff --git a/src/components/user-settings.tsx b/src/app/(with-header)/settings/user-settings.tsx
similarity index 97%
rename from src/components/user-settings.tsx
rename to src/app/(with-header)/settings/user-settings.tsx
index ae11981..bb9e863 100644
--- a/src/components/user-settings.tsx
+++ b/src/app/(with-header)/settings/user-settings.tsx
@@ -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 });
diff --git a/src/app/(with-header)/team/[teamId]/page.tsx b/src/app/(with-header)/team/[teamId]/page.tsx
index ad85ae1..b439ac1 100644
--- a/src/app/(with-header)/team/[teamId]/page.tsx
+++ b/src/app/(with-header)/team/[teamId]/page.tsx
@@ -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();
diff --git a/src/components/team.tsx b/src/app/(with-header)/team/[teamId]/team.tsx
similarity index 96%
rename from src/components/team.tsx
rename to src/app/(with-header)/team/[teamId]/team.tsx
index 942c0b7..12abba9 100644
--- a/src/components/team.tsx
+++ b/src/app/(with-header)/team/[teamId]/team.tsx
@@ -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';
diff --git a/src/components/create-team-button.tsx b/src/app/(with-header)/team/create-team-button.tsx
similarity index 86%
rename from src/components/create-team-button.tsx
rename to src/app/(with-header)/team/create-team-button.tsx
index 860f01d..1754e28 100644
--- a/src/components/create-team-button.tsx
+++ b/src/app/(with-header)/team/create-team-button.tsx
@@ -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';
diff --git a/src/app/(with-header)/team/page.tsx b/src/app/(with-header)/team/page.tsx
index 506130c..34c45d1 100644
--- a/src/app/(with-header)/team/page.tsx
+++ b/src/app/(with-header)/team/page.tsx
@@ -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';
diff --git a/src/components/chuni/playlog-list.tsx b/src/components/chuni/playlog-list.tsx
deleted file mode 100644
index 49901a2..0000000
--- a/src/components/chuni/playlog-list.tsx
+++ /dev/null
@@ -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: [
- All Justice,
- Full Combo,
- Clear,
- ],
- 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),
- { ...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 (
- {item =>
-
-
}
- );
-};
-
-export const ChuniPlaylogList = () => {
- return ( => {
- 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) =>
-
-
}
- );
-};