From 007b23783aee08ef7ae489d0a91d1a91a61e67d5 Mon Sep 17 00:00:00 2001 From: Polaris Date: Wed, 21 Aug 2024 13:34:23 -0400 Subject: [PATCH] added fuzzy search for table --- app/(sharing)/[token]/[id]/actions.ts | 155 +++++++++++---------- components/navigationbar/navigationbar.tsx | 11 +- components/scoreplaylog/DebouncedInput.tsx | 37 +++++ components/scoreplaylog/action.ts | 87 ++++++++++++ components/scoreplaylog/data-table.tsx | 32 +++-- 5 files changed, 226 insertions(+), 96 deletions(-) create mode 100644 components/scoreplaylog/DebouncedInput.tsx create mode 100644 components/scoreplaylog/action.ts diff --git a/app/(sharing)/[token]/[id]/actions.ts b/app/(sharing)/[token]/[id]/actions.ts index a7b67fd..be96891 100644 --- a/app/(sharing)/[token]/[id]/actions.ts +++ b/app/(sharing)/[token]/[id]/actions.ts @@ -1,21 +1,19 @@ - "use server"; - import { artemis, daphnis } from "@/lib/prisma"; import type * as Prisma from "@prisma/client"; - type ChuniScorePlaylog = Prisma.PrismaClient; - type ChuniStaticMusic = Prisma.PrismaClient; +type ChuniScorePlaylog = Prisma.PrismaClient; +type ChuniStaticMusic = Prisma.PrismaClient; type LinkSharingToken = { - playlogId: number; - }; - + playlogId: number; +}; export async function getSongsWithTitles(userId: number) { - try { - const songs: ChuniScorePlaylog[] = await artemis.chuni_score_playlog.findMany({ + try { + const songs: ChuniScorePlaylog[] = + await artemis.chuni_score_playlog.findMany({ where: { user: userId, }, @@ -63,12 +61,13 @@ export async function getSongsWithTitles(userId: number) { ticketId: true, }, }); - - const chuniScorePlaylogMusicId = songs - .map((song) => song.musicId) - .filter((id): id is number => id !== null); - - const staticMusicInfo: ChuniStaticMusic[] = await artemis.chuni_static_music.findMany({ + + const chuniScorePlaylogMusicId = songs + .map((song) => song.musicId) + .filter((id): id is number => id !== null); + + const staticMusicInfo: ChuniStaticMusic[] = + await artemis.chuni_static_music.findMany({ where: { songId: { in: chuniScorePlaylogMusicId, @@ -82,74 +81,76 @@ export async function getSongsWithTitles(userId: number) { level: true, genre: true, worldsEndTag: true, - jacketPath: true, + jacketPath: true, }, }); - - const playCounts = await artemis.chuni_score_playlog.groupBy({ - by: ['musicId'], - _count: { - musicId: true, + + const playCounts = await artemis.chuni_score_playlog.groupBy({ + by: ["musicId"], + _count: { + musicId: true, + }, + where: { + user: userId, + musicId: { + in: chuniScorePlaylogMusicId, }, - where: { - user: userId, - musicId: { - in: chuniScorePlaylogMusicId, - }, - }, - }); - - const playCountMap = playCounts.reduce((map, item) => { + }, + }); + + const playCountMap = playCounts.reduce( + (map, item) => { if (item.musicId !== null) { map[item.musicId] = item._count.musicId; } return map; - }, {} as Record); - - const songsWithTitles = songs.map((song) => { - const staticInfo = staticMusicInfo.find( - (chuniStaticMusic) => - chuniStaticMusic.songId === song.musicId && - chuniStaticMusic.chartId === song.level - ); - - return { - ...song, - title: staticInfo?.title || "Unknown Title", - artist: staticInfo?.artist || "Unknown Artist", - genre: staticInfo?.genre || "Unknown Genre", - chartId: staticInfo?.chartId || "Unknown chartId", - level: staticInfo?.level || "Unknown Level", - chartlevel: song.level || "Unknown Level", - playCount: song.musicId !== null ? playCountMap[song.musicId] || 0 : 0, - jacketPath: staticInfo?.jacketPath || "", - }; - }); - - return songsWithTitles; - } catch (error) { - console.error("Error fetching songs with titles:", error); - throw error; - } - } + }, + {} as Record, + ); + + const songsWithTitles = songs.map((song) => { + const staticInfo = staticMusicInfo.find( + (chuniStaticMusic) => + chuniStaticMusic.songId === song.musicId && + chuniStaticMusic.chartId === song.level, + ); + + return { + ...song, + title: staticInfo?.title || "Unknown Title", + artist: staticInfo?.artist || "Unknown Artist", + genre: staticInfo?.genre || "Unknown Genre", + chartId: staticInfo?.chartId || "Unknown chartId", + level: staticInfo?.level || "Unknown Level", + chartlevel: song.level || "Unknown Level", + playCount: song.musicId !== null ? playCountMap[song.musicId] || 0 : 0, + jacketPath: staticInfo?.jacketPath || "", + }; + }); + + return songsWithTitles; + } catch (error) { + console.error("Error fetching songs with titles:", error); + throw error; + } +} - export async function generatePlaylogId(playlogid: number) { - try { - const tokens = (await daphnis.linkSharingToken.findMany({ - where: { - playlogId: playlogid, - }, - select: { - playlogId: true, - }, - })) as LinkSharingToken[]; - - const playlogIds: number[] = tokens.map((token) => token.playlogId); - - return playlogIds; - } catch (error) { - console.error("Error fetching playlogIds:", error); - throw error; - } - } \ No newline at end of file + try { + const tokens = (await daphnis.linkSharingToken.findMany({ + where: { + playlogId: playlogid, + }, + select: { + playlogId: true, + }, + })) as LinkSharingToken[]; + + const playlogIds: number[] = tokens.map((token) => token.playlogId); + + return playlogIds; + } catch (error) { + console.error("Error fetching playlogIds:", error); + throw error; + } +} diff --git a/components/navigationbar/navigationbar.tsx b/components/navigationbar/navigationbar.tsx index 610f2b8..ea55646 100644 --- a/components/navigationbar/navigationbar.tsx +++ b/components/navigationbar/navigationbar.tsx @@ -41,16 +41,7 @@ const HeaderNavigation = async () => {
-
- {/*
- - -
*/} -
+
diff --git a/components/scoreplaylog/DebouncedInput.tsx b/components/scoreplaylog/DebouncedInput.tsx new file mode 100644 index 0000000..6624c8b --- /dev/null +++ b/components/scoreplaylog/DebouncedInput.tsx @@ -0,0 +1,37 @@ +import React, { useEffect, useState } from "react"; +import { Input } from "../ui/input"; + +export default function DebouncedInput({ + value: initialValue, + onChange, + debounce = 500, + ...props +}: { + value: string | number; + onChange: (value: string | number) => void; + debounce?: number; +} & Omit, "onChange">) { + const [value, setValue] = useState(initialValue); + + useEffect(() => { + setValue(initialValue); + }, [initialValue]); + + useEffect(() => { + const timeout = setTimeout(() => { + onChange(value); + }, debounce); + + return () => clearTimeout(timeout); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]); + + return ( + setValue(e.target.value)} + /> + ); +} diff --git a/components/scoreplaylog/action.ts b/components/scoreplaylog/action.ts new file mode 100644 index 0000000..4880ae8 --- /dev/null +++ b/components/scoreplaylog/action.ts @@ -0,0 +1,87 @@ +"use server"; + +import { artemis } from "@/lib/prisma"; +import type * as Prisma from "@prisma/client"; + +type ChuniScorePlaylog = Prisma.PrismaClient; +type ChuniStaticMusic = Prisma.PrismaClient; + +export async function searchSongWithTitle( + userId: number, + searchQuery: string = "", +) { + try { + const songs: ChuniScorePlaylog[] = + await artemis.chuni_score_playlog.findMany({ + where: { + user: userId, + }, + orderBy: { + userPlayDate: "desc", + }, + select: { + id: true, + }, + }); + + const chuniScorePlaylogMusicId = songs + .map((song) => song.musicId) + .filter((id): id is number => id !== null); + + const staticMusicInfo: ChuniStaticMusic[] = + await artemis.chuni_static_music.findMany({ + where: { + songId: { + in: chuniScorePlaylogMusicId, + }, + title: { + contains: searchQuery, + }, + }, + select: { + title: true, + }, + }); + + const playCounts = await artemis.chuni_score_playlog.groupBy({ + by: ["musicId"], + _count: { + musicId: true, + }, + where: { + user: userId, + musicId: { + in: chuniScorePlaylogMusicId, + }, + }, + }); + + const playCountMap = playCounts.reduce( + (map, item) => { + if (item.musicId !== null) { + map[item.musicId] = item._count.musicId; + } + return map; + }, + {} as Record, + ); + + const songsWithTitles = songs.map((song) => { + const staticInfo = staticMusicInfo.find( + (chuniStaticMusic) => + chuniStaticMusic.songId === song.musicId && + chuniStaticMusic.chartId === song.level, + ); + + return { + ...song, + title: staticInfo?.title || "Unknown Title", + }; + }); + + return songsWithTitles; + } catch (error) { + console.error("Error fetching songs with titles:", error); + throw error; + } +} diff --git a/components/scoreplaylog/data-table.tsx b/components/scoreplaylog/data-table.tsx index ffbc15c..bd23e66 100644 --- a/components/scoreplaylog/data-table.tsx +++ b/components/scoreplaylog/data-table.tsx @@ -1,10 +1,14 @@ "use client"; +// https://github.com/dracor-org/einakter/blob/466ca1663098a16cc1141129a6ba22628135b04c/src/components/Table.tsx#L26 +// used the above for reference on how to fuzzy search +import { useState } from "react"; import { Button } from "@/components/ui/button"; import { ColumnDef, SortingState, getSortedRowModel, flexRender, + getFilteredRowModel, getCoreRowModel, getPaginationRowModel, useReactTable, @@ -18,8 +22,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; -import { useState } from "react"; - +import DebouncedInput from "./DebouncedInput"; interface DataTableProps { columns: ColumnDef[]; data: TData[]; @@ -30,21 +33,32 @@ export function DataTable({ data, }: DataTableProps) { const [sorting, setSorting] = useState([]); + const [globalFilter, setGlobalFilter] = useState(""); const table = useReactTable({ data, columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), state: { sorting, + globalFilter, }, + onSortingChange: setSorting, + onGlobalFilterChange: setGlobalFilter, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), }); return ( -
+
+
+ setGlobalFilter(String(value))} + placeholder={`Search`} + /> +
{table.getHeaderGroups().map((headerGroup) => ( @@ -55,7 +69,7 @@ export function DataTable({ ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -85,7 +99,7 @@ export function DataTable({ )}
-
+