feat : 2 team per row
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState, useTransition, type ReactNode } from "react";
|
||||
import { useEffect, useMemo, useState, useTransition, type ReactNode } from "react";
|
||||
import {
|
||||
GripVerticalIcon,
|
||||
PlusIcon,
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import { toast } from "sonner";
|
||||
@@ -747,14 +746,14 @@ function SortableTeam({
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({ id });
|
||||
} = useSortable({ id, animateLayoutChanges: () => false });
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
style={{ transform: CSS.Transform.toString(transform), transition }}
|
||||
className={cn(isDragging && "relative z-10 opacity-60")}
|
||||
className={cn("min-w-0", isDragging && "relative z-10 opacity-60")}
|
||||
>
|
||||
<div className="flex flex-col gap-2 rounded-lg border bg-muted/20 p-2">
|
||||
<div className="flex h-full flex-col gap-2 rounded-lg border bg-muted/20 p-2">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-sm font-medium">Team {position + 1}</span>
|
||||
<Button
|
||||
@@ -799,10 +798,10 @@ function BossRecommendationEditor({
|
||||
const groups = recommendations.filter(
|
||||
(group) => group.level === level && group.bossPosition === boss.position,
|
||||
);
|
||||
const [teams, setTeams] = useState<StygianRecommendationItemInput[][]>(() =>
|
||||
const [teams, setTeams] = useState<{ id: string; items: StygianRecommendationItemInput[] }[]>(() =>
|
||||
groups
|
||||
.filter((group) => group.kind === "team")
|
||||
.map((group) => group.items.flatMap((item) => toInput(item) ?? [])),
|
||||
.map((group) => ({ id: group.id, items: group.items.flatMap((item) => toInput(item) ?? []) })),
|
||||
);
|
||||
const [units, setUnits] = useState<StygianRecommendationItemInput[]>(() =>
|
||||
groups
|
||||
@@ -815,13 +814,13 @@ function BossRecommendationEditor({
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
}),
|
||||
);
|
||||
const teamIds = teams.map((_, index) => `team-${index}`);
|
||||
const fingerprint = JSON.stringify({ teams, units });
|
||||
const teamIds = useMemo(() => teams.map((team) => team.id), [teams]);
|
||||
const fingerprint = JSON.stringify({ teams: teams.map((team) => team.items), units });
|
||||
const valid = teams.every(
|
||||
(team) =>
|
||||
team.length >= 1 &&
|
||||
team.length <= 4 &&
|
||||
team.every((item) => item.kind === "character"),
|
||||
team.items.length >= 1 &&
|
||||
team.items.length <= 4 &&
|
||||
team.items.every((item) => item.kind === "character"),
|
||||
);
|
||||
const [savedFingerprint, setSavedFingerprint] = useState(fingerprint);
|
||||
const [failedFingerprint, setFailedFingerprint] = useState<string | null>(
|
||||
@@ -896,37 +895,36 @@ function BossRecommendationEditor({
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={({ active, over }) => {
|
||||
if (!over || active.id === over.id) return;
|
||||
const from = teamIds.indexOf(String(active.id));
|
||||
const to = teamIds.indexOf(String(over.id));
|
||||
if (from >= 0 && to >= 0)
|
||||
setTeams((current) => arrayMove(current, from, to));
|
||||
setTeams((current) => {
|
||||
const from = current.findIndex((team) => team.id === active.id);
|
||||
const to = current.findIndex((team) => team.id === over.id);
|
||||
return from === -1 || to === -1 ? current : arrayMove(current, from, to);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<SortableContext
|
||||
items={teamIds}
|
||||
strategy={verticalListSortingStrategy}
|
||||
strategy={rectSortingStrategy}
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="grid grid-cols-1 gap-3 xl:grid-cols-2">
|
||||
{teams.map((team, teamIndex) => (
|
||||
<SortableTeam
|
||||
key={teamIds[teamIndex]}
|
||||
id={teamIds[teamIndex]}
|
||||
key={team.id}
|
||||
id={team.id}
|
||||
position={teamIndex}
|
||||
>
|
||||
<VisualRecommendationGrid
|
||||
items={team}
|
||||
items={team.items}
|
||||
limit={4}
|
||||
teamLayout
|
||||
characters={characters}
|
||||
weapons={weapons}
|
||||
artifacts={artifacts}
|
||||
onChange={(items) =>
|
||||
setTeams(
|
||||
teams
|
||||
.map((entry, index) =>
|
||||
index === teamIndex ? items : entry,
|
||||
)
|
||||
.filter((entry) => entry.length),
|
||||
setTeams((current) =>
|
||||
current
|
||||
.map((entry) => entry.id === team.id ? { ...entry, items } : entry)
|
||||
.filter((entry) => entry.items.length),
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -944,9 +942,7 @@ function BossRecommendationEditor({
|
||||
description="This team and all of its character recommendations will be removed."
|
||||
confirmLabel="Remove team"
|
||||
onConfirm={() =>
|
||||
setTeams(
|
||||
teams.filter((_, index) => index !== teamIndex),
|
||||
)
|
||||
setTeams((current) => current.filter((entry) => entry.id !== team.id))
|
||||
}
|
||||
>
|
||||
<Trash2Icon data-icon="inline-start" />
|
||||
@@ -961,7 +957,7 @@ function BossRecommendationEditor({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="self-start"
|
||||
onClick={() => setTeams([...teams, []])}
|
||||
onClick={() => setTeams((current) => [...current, { id: crypto.randomUUID(), items: [] }])}
|
||||
>
|
||||
<PlusIcon data-icon="inline-start" />
|
||||
Add team
|
||||
|
||||
Reference in New Issue
Block a user