Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
import { CursorDataTable } from "@/components/data-table/cursor";
import type { Direction } from "@/components/data-table/pagination";
import { useSuspenseQuery } from "@apollo/client/react";
import type { VariablesOf } from "@graphql-typed-document-node/core";
import { useState } from "react";
import { columns, type Event } from "./data-table-columns";
import { EVENTS_TABLE_QUERY } from "./query";

export function EventsDataTable() {
const PAGE_SIZE = 10;
export function EventsDataTable({ query }: { query?: string }) {
const PAGE_SIZE = 20;
const [cursors, setCursors] = useState<(string | null)[]>([null]);
const [currentIndex, setCurrentIndex] = useState(0);

const after = cursors[currentIndex];
const variables = { first: PAGE_SIZE, after };

const variables = {
first: PAGE_SIZE,
after,
where: query ? { typeContains: query } : undefined,
} satisfies VariablesOf<typeof EVENTS_TABLE_QUERY>;

const { data } = useSuspenseQuery(EVENTS_TABLE_QUERY, {
variables,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";

import { Input } from "@/components/ui/input";

import { DataTableSkeleton } from "@/components/data-table/skeleton";
import { useDebouncedValue } from "foxact/use-debounced-value";
import { Suspense, useState } from "react";
import { EventsDataTable } from "./data-table";

export default function FilterableDataTable() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebouncedValue(query, 200);

return (
<div className="flex flex-col">
<div className="mb-4 flex items-center gap-4">
<Input
placeholder="搜尋事件類型"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
</div>

<Suspense fallback={<DataTableSkeleton />}>
<EventsDataTable query={debouncedQuery} />
</Suspense>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export const EVENTS_TABLE_QUERY = graphql(`
$after: Cursor
$last: Int
$before: Cursor
$where: EventWhereInput
) {
events(first: $first, after: $after, last: $last, before: $before, orderBy: { field: TRIGGERED_AT, direction: DESC }) {
events(first: $first, after: $after, last: $last, before: $before, where: $where, orderBy: { field: TRIGGERED_AT, direction: DESC }) {
edges {
node {
id
Expand Down
4 changes: 2 additions & 2 deletions app/(admin)/(activity-management)/events/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SiteHeader } from "@/components/site-header";
import type { Metadata } from "next";
import { EventsDataTable } from "./_components/data-table";
import FilterableDataTable from "./_components/filterable-data-table";

export const metadata: Metadata = {
title: "事件管理",
Expand All @@ -23,7 +23,7 @@ export default function Page() {
</div>
</div>
<div>
<EventsDataTable />
<FilterableDataTable />
</div>
</main>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
import { CursorDataTable } from "@/components/data-table/cursor";
import type { Direction } from "@/components/data-table/pagination";
import { useSuspenseQuery } from "@apollo/client/react";
import type { VariablesOf } from "@graphql-typed-document-node/core";
import { useState } from "react";
import { columns, type Point } from "./data-table-columns";
import { POINTS_TABLE_QUERY } from "./query";

export function PointsDataTable() {
const PAGE_SIZE = 10;
export function PointsDataTable({ query }: { query?: string }) {
const PAGE_SIZE = 20;
const [cursors, setCursors] = useState<(string | null)[]>([null]);
const [currentIndex, setCurrentIndex] = useState(0);

const after = cursors[currentIndex];
const variables = { first: PAGE_SIZE, after };

const variables = {
first: PAGE_SIZE,
after,
where: query ? { descriptionContains: query } : undefined,
} satisfies VariablesOf<typeof POINTS_TABLE_QUERY>;

const { data } = useSuspenseQuery(POINTS_TABLE_QUERY, {
variables,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";

import { Input } from "@/components/ui/input";

import { DataTableSkeleton } from "@/components/data-table/skeleton";
import { useDebouncedValue } from "foxact/use-debounced-value";
import { Suspense, useState } from "react";
import { PointsDataTable } from "./data-table";

export default function FilterableDataTable() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebouncedValue(query, 200);

return (
<div className="flex flex-col">
<div className="mb-4 flex items-center gap-4">
<Input
placeholder="搜尋描述"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
</div>

<Suspense fallback={<DataTableSkeleton />}>
<PointsDataTable query={debouncedQuery} />
</Suspense>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export const POINTS_TABLE_QUERY = graphql(`
$after: Cursor
$last: Int
$before: Cursor
$where: PointWhereInput
) {
points(first: $first, after: $after, last: $last, before: $before, orderBy: { field: GRANTED_AT, direction: DESC }) {
points(first: $first, after: $after, last: $last, before: $before, where: $where, orderBy: { field: GRANTED_AT, direction: DESC }) {
edges {
node {
id
Expand Down
4 changes: 2 additions & 2 deletions app/(admin)/(activity-management)/points/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SiteHeader } from "@/components/site-header";
import type { Metadata } from "next";
import { PointsDataTable } from "./_components/data-table";
import FilterableDataTable from "./_components/filterable-data-table";

export const metadata: Metadata = {
title: "積分管理",
Expand All @@ -23,7 +23,7 @@ export default function Page() {
</div>
</div>
<div>
<PointsDataTable />
<FilterableDataTable />
</div>
</main>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { columns, type Submission } from "./data-table-columns";
import { SUBMISSIONS_TABLE_QUERY } from "./query";

export function SubmissionsDataTable() {
const PAGE_SIZE = 10;
const PAGE_SIZE = 20;
const [cursors, setCursors] = useState<(string | null)[]>([null]);
const [currentIndex, setCurrentIndex] = useState(0);

Expand Down
6 changes: 5 additions & 1 deletion app/(admin)/(activity-management)/submissions/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { DataTableSkeleton } from "@/components/data-table/skeleton";
import { SiteHeader } from "@/components/site-header";
import type { Metadata } from "next";
import { Suspense } from "react";
import { SubmissionsDataTable } from "./_components/data-table";

export const metadata: Metadata = {
Expand All @@ -23,7 +25,9 @@ export default function Page() {
</div>
</div>
<div>
<SubmissionsDataTable />
<Suspense fallback={<DataTableSkeleton />}>
<SubmissionsDataTable />
</Suspense>
</div>
</main>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,35 @@ import { useSuspenseQuery } from "@apollo/client/react";
import { columns, type Database } from "./data-table-columns";
import { DATABASES_TABLE_QUERY } from "./query";

export function DatabaseDataTable() {
export function DatabaseDataTable({ query }: { query?: string }) {
const { data } = useSuspenseQuery(DATABASES_TABLE_QUERY);

const databaseList = data?.databases?.map((database) => ({
id: database.id,
slug: database.slug,
description: database.description,
schema: database.schema,
relationFigure: database.relationFigure,
} satisfies Database)) ?? [];
const databaseList = data?.databases
?.map(
(database) => ({
id: database.id,
slug: database.slug,
description: database.description,
schema: database.schema,
relationFigure: database.relationFigure,
} satisfies Database),
)
.filter((database) => {
if (query && database.slug.includes(query)) {
return true;
}

if (query && database.description?.includes(query)) {
return true;
}

// If no query is provided, return all databases
if (!query) {
return true;
}

return false;
}) ?? [];

return (
<GeneralDataTable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client";

import { Input } from "@/components/ui/input";

import { DataTableSkeleton } from "@/components/data-table/skeleton";
import { useDebouncedValue } from "foxact/use-debounced-value";
import { Suspense, useState } from "react";
import { DatabaseDataTable } from "./data-table";

export default function FilterableDataTable() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebouncedValue(query, 200);

return (
<div className="flex flex-col">
<div className="mb-4 flex items-center gap-4">
<Input
placeholder="搜尋資料庫 slug 或描述"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
</div>

<Suspense fallback={<DataTableSkeleton />}>
<DatabaseDataTable query={debouncedQuery} />
</Suspense>
</div>
);
}
4 changes: 2 additions & 2 deletions app/(admin)/(question-management)/database/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SiteHeader } from "@/components/site-header";
import type { Metadata } from "next";
import { CreateDatabaseTrigger } from "./_components/create";
import { DatabaseDataTable } from "./_components/data-table";
import FilterableDataTable from "./_components/filterable-data-table";

export const metadata: Metadata = {
title: "資料庫",
Expand All @@ -25,7 +25,7 @@ export default function Page() {
<CreateDatabaseTrigger />
</div>
<div>
<DatabaseDataTable />
<FilterableDataTable />
</div>
</main>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@

import { CursorDataTable } from "@/components/data-table/cursor";
import type { Direction } from "@/components/data-table/pagination";
import { QuestionDifficulty } from "@/gql/graphql";
import { useSuspenseQuery } from "@apollo/client/react";
import type { VariablesOf } from "@graphql-typed-document-node/core";
import { useState } from "react";
import { columns, type Question } from "./data-table-columns";
import { QUESTIONS_TABLE_QUERY } from "./query";

export function QuestionsDataTable() {
const PAGE_SIZE = 5;
export type DifficultyFilter = "all" | QuestionDifficulty;

export function QuestionsDataTable({ query, difficulty }: { query?: string; difficulty: DifficultyFilter }) {
const PAGE_SIZE = 20;
const [cursors, setCursors] = useState<(string | null)[]>([null]);
const [currentIndex, setCurrentIndex] = useState(0);

const after = cursors[currentIndex];
const variables = { first: PAGE_SIZE, after };
const variables = {
first: PAGE_SIZE,
after,
query,
difficulty: difficulty === "all" ? undefined : difficulty,
} satisfies VariablesOf<typeof QUESTIONS_TABLE_QUERY>;

const { data } = useSuspenseQuery(QUESTIONS_TABLE_QUERY, {
variables,
Expand Down Expand Up @@ -53,13 +62,15 @@ export function QuestionsDataTable() {
};

return (
<CursorDataTable
columns={columns}
data={questionList}
totalCount={data?.questions.totalCount ?? 0}
hasNextPage={!!pageInfo?.hasNextPage}
hasPreviousPage={currentIndex > 0}
onPageChange={handlePageChange}
/>
<>
<CursorDataTable
columns={columns}
data={questionList}
totalCount={data?.questions.totalCount ?? 0}
hasNextPage={!!pageInfo?.hasNextPage}
hasPreviousPage={currentIndex > 0}
onPageChange={handlePageChange}
/>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import { Input } from "@/components/ui/input";
import { SelectItem } from "@/components/ui/select";

import { DataTableSkeleton } from "@/components/data-table/skeleton";
import { Select, SelectContent, SelectTrigger, SelectValue } from "@/components/ui/select";
import { QuestionDifficulty } from "@/gql/graphql";
import { useDebouncedValue } from "foxact/use-debounced-value";
import { Suspense, useState } from "react";
import { type DifficultyFilter, QuestionsDataTable } from "./data-table";

export default function FilterableDataTable() {
const [query, setQuery] = useState("");
const [difficulty, setDifficulty] = useState<DifficultyFilter>("all");

const debouncedQuery = useDebouncedValue(query, 200);

return (
<div className="flex flex-col">
<div className="mb-4 flex items-center gap-4">
<Input
placeholder="搜尋題目的標題、分類和描述……"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<Select
value={difficulty}
onValueChange={(value) => setDifficulty(value as DifficultyFilter)}
>
<SelectTrigger>
<SelectValue placeholder="選擇難度" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">全部</SelectItem>
<SelectItem value={QuestionDifficulty.Easy}>簡單</SelectItem>
<SelectItem value={QuestionDifficulty.Medium}>中等</SelectItem>
<SelectItem value={QuestionDifficulty.Hard}>困難</SelectItem>
<SelectItem value={QuestionDifficulty.Unspecified}>
未指定
</SelectItem>
</SelectContent>
</Select>
</div>

<Suspense fallback={<DataTableSkeleton />}>
<QuestionsDataTable query={debouncedQuery} difficulty={difficulty} />
</Suspense>
</div>
);
}
Loading