Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/match table #158

Merged
merged 3 commits into from
Jun 23, 2024
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@ supabase studio url: http://localhost:54323
| match | 成績表 |
| game | 半荘 |
| score | ポイント |
| points | 点数|
| points | 点数 |
| result | 収支 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use client";

import { Button, ButtonProps } from "@/components/Button";
import { useChipInputModal } from "../ChipInputModal/hooks";

export function ChipInputButton(props: Omit<ButtonProps, "onClick">) {
const { onOpen } = useChipInputModal();
return <Button {...props} onClick={onOpen} />;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"use server";

import { revalidatePath } from "next/cache";
import { z } from "zod";
import { serverServices } from "@/lib/services/server";
import { schema } from "@/lib/utils/schema";

type AddChipState = {
export type AddChipState = {
success?: boolean;
errors?: {
base?: string[];
Expand Down Expand Up @@ -72,6 +73,8 @@ export async function addChip(
});
});

revalidatePath(`/matches/${matchId}`);

return {
success: true,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function GameInputForm({ match }: { match: Match }) {
return (
<SortableItem key={field.id} id={field.id}>
{({ attributes, listeners }) => (
<div className="flex items-center gap-1">
<div className="flex touch-none items-center gap-1">
<Controller
control={control}
name={`players.${index}.id`}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ export function AddGameButton({ isDisabled }: { isDisabled: boolean }) {
return (
<Button
fullWidth
size="lg"
onClick={gameInputModal.onOpen}
isDisabled={isDisabled}
startContent={<Icon className="size-6" name="add" />}
startContent={<Icon className="size-5" name="edit" />}
variant="ghost"
>
結果を入力する
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use client";

import { useChipInputModal } from "../../../ChipInputModal/hooks";

export function ChipInputButton(
props: React.ComponentPropsWithoutRef<"button">,
) {
const gameInputModal = useChipInputModal();

return <button onClick={gameInputModal.onOpen} {...props}></button>;
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
import classNames from "classnames";
import {
Table,
TableBody,
TableCell,
TableColumn,
TableFooter,
TableFooterCell,
TableFooterRow,
TableHeader,
TableRow,
} from "@/components/Table";
import { serverServices } from "@/lib/services/server";
import { AddChipButton } from "./(components)/AddChipButton";
import { MatchPlayer } from "@/lib/type";
import { AddGameButton } from "./(components)/AddGameButton";
import { ChipInputButton } from "./(components)/ChipInputButton";
import styles from "./styles.module.css";

type Column = {
id: string;
janrecoId: string | null;
name: string | null;
type: "index" | "player" | "empty";
};
} & MatchPlayer;

type Row = {
[playerId: Column["id"]]: number;
};

export async function MatchTable({ matchId }: { matchId: string }) {
export async function MatchTable({
matchId,
className,
}: {
matchId: string;
className?: string;
}) {
const { getMatch } = serverServices();
const [match] = await Promise.all([getMatch({ matchId })]);
const { rule, players } = match;
Expand All @@ -49,6 +46,11 @@ export async function MatchTable({ matchId }: { matchId: string }) {
janrecoId: "",
name: "",
type: "empty",
rankCounts: [0] as number[],
averageRank: 0,
totalScore: 0,
chipCount: null,
result: 0,
}) as const,
),
];
Expand All @@ -60,91 +62,126 @@ export async function MatchTable({ matchId }: { matchId: string }) {
),
) ?? [];

const totalPointsRow: Row = Object.fromEntries(
players.map((player) => [
player.id,
gameRows.reduce((acc, gameRow) => acc + gameRow[player.id], 0),
]),
);

const chipsRow: Row = Object.fromEntries(
players.map((player) => [player.id, player.chipCount ?? 0]),
);

return (
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableColumn className="">
<span />
</TableColumn>
{columns.map((column) => (
<TableColumn key={column?.id} className="px-1">
<div className="relative min-w-[60px] ">
<div className="absolute inset-0 flex items-center justify-center">
{column.type === "player" && (
<span className="truncate">{column.name}</span>
)}
</div>
<div className={classNames(className, "flex flex-col")}>
<div
className={classNames(
styles["row"],
"flex items-center rounded-lg bg-default-100 text-foreground-500",
)}
>
<div
className={classNames(
styles["col"],
styles["col--header"],
styles["col--index"],
)}
/>
{columns.map((column) => (
<div
key={column?.id}
className={classNames(styles["col--header"], styles["col"])}
>
{column.type === "player" && (
<span className="truncate">{column.name}</span>
)}
</div>
))}
</div>
<div className="grow">
{gameRows.map((item, index) => (
<div
className={classNames(styles["row"], "flex items-center py-1")}
key={index}
>
<div
className={classNames(
styles["col"],
styles["col--index"],
styles["col--body"],
)}
>
{index + 1}
</div>
{columns.map((column) => (
<div
key={column.id}
className={classNames(styles["col"], styles["col--body"], {
"text-danger": item[column.id] < 0,
})}
>
{item[column.id]}
</div>
</TableColumn>
))}
</div>
))}
<div>
{/* TODO: disabledやめる */}
<AddGameButton isDisabled={isPlayersShort} />
{/* <AddChipButton isDisabled={isPlayersShort} /> */}
</div>
</div>
<div className="rounded-lg bg-default-100 text-foreground-500">
<div className={classNames(styles["row"])}>
<div
className={classNames(
styles["col"],
styles["col--index"],
styles["col--footer"],
)}
>
合計
</div>
{columns.map((column) => (
<div
className={classNames(styles["col"], styles["col--footer"], {
"text-danger": column.totalScore < 0,
})}
key={column.id}
>
{column.totalScore}
</div>
))}
</TableHeader>
<TableBody>
{gameRows.map((item, index) => (
<TableRow key={index}>
<TableCell className="text-center text-default-500">
{index + 1}
</TableCell>
{columns.map((column) => (
<TableCell
key={column.id}
className={classNames("text-center", {
"text-danger": item[column.id] < 0,
})}
>
{item[column.id]}
</TableCell>
))}
</TableRow>
</div>
<ChipInputButton className={classNames(styles["row"], "w-full")}>
<div
className={classNames(
styles["col"],
styles["col--index"],
styles["col--footer"],
)}
>
チップ
</div>
{columns.map((column) => (
<div
className={classNames(styles["col"], styles["col--footer"])}
key={column.id}
>
{column.chipCount}
</div>
))}
<tr aria-hidden="true" className="mx-1 block size-px"></tr>
<tr>
<td colSpan={columns.length + 1}>
<div className="flex flex-col gap-1">
<AddGameButton isDisabled={isPlayersShort} />
<AddChipButton isDisabled={isPlayersShort} />
</div>
</td>
</tr>
</TableBody>
<TableFooter>
<TableFooterRow>
<TableFooterCell className="text-center">合計</TableFooterCell>
{columns.map((column) => (
<TableFooterCell className="text-center" key={column.id}>
{totalPointsRow[column.id]}
</TableFooterCell>
))}
</TableFooterRow>
<TableFooterRow>
<TableFooterCell className="text-center">チップ</TableFooterCell>
{columns.map((column) => (
<TableFooterCell className="text-center" key={column.id}>
{chipsRow[column.id]}
</TableFooterCell>
))}
</TableFooterRow>
<TableFooterRow>
<TableFooterCell className="text-center">収支</TableFooterCell>
{columns.map((column) => (
<TableFooterCell className="text-center" key={column.id}>
{totalPointsRow[column.id]}
</TableFooterCell>
))}
</TableFooterRow>
</TableFooter>
</Table>
</ChipInputButton>
<div className={classNames(styles["row"])}>
<div
className={classNames(
styles["col"],
styles["col--index"],
styles["col--footer"],
)}
>
収支
</div>
{columns.map((column) => (
<div
className={classNames(styles["col"], styles["col--footer"])}
key={column.id}
>
{column.result}
</div>
))}
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.row {
@apply flex;
}

.col {
@apply flex-1 flex items-center justify-center;
}

.col--index {
@apply basis-[46px] grow-0 shrink-0 text-default-500;
}

.col--header {
@apply h-10 whitespace-nowrap px-1 text-left align-middle text-tiny font-semibold;
}

.col--body {
@apply px-1 py-2 align-middle text-small font-normal;
}

.col--footer {
@apply h-10 whitespace-nowrap px-1 align-middle text-tiny font-semibold;
}
Loading
Loading