Skip to content

Commit 042f8bc

Browse files
authored
Merge pull request #25 from jmacuga/deleting-boards
Deleting boards fixed, added indexedDB garbage collection
2 parents 93c4984 + f811775 commit 042f8bc

File tree

36 files changed

+810
-381
lines changed

36 files changed

+810
-381
lines changed

components/board/components/object-edit-indicator.tsx

+1-13
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export const ObjectEditIndicator = ({
1818

1919
const { className, attrs } = shape;
2020

21-
// Handle className that can be either a string or an object with val property
2221
const getClassName = () => {
2322
if (typeof className === "string") {
2423
return className;
@@ -38,7 +37,6 @@ export const ObjectEditIndicator = ({
3837
radius = 0,
3938
points;
4039

41-
// Get transform attributes
4240
const scaleX = attrs.scaleX || 1;
4341
const scaleY = attrs.scaleY || 1;
4442
const rotation = attrs.rotation || 0;
@@ -65,30 +63,26 @@ export const ObjectEditIndicator = ({
6563
x = attrs.x;
6664
y = attrs.y;
6765
width = attrs.width * scaleX;
68-
height = 30 * scaleY; // Approximate text height
66+
height = 30 * scaleY;
6967
break;
7068

7169
case "Line":
7270
case "Arrow":
7371
points = attrs.points || [];
7472
if (points.length >= 4) {
75-
// Apply transformations to each point
7673
const transformedPoints = [];
7774
for (let i = 0; i < points.length; i += 2) {
7875
const px = points[i] * scaleX;
7976
const py = points[i + 1] * scaleY;
8077

81-
// Apply rotation if present
8278
if (rotation !== 0) {
8379
const radians = (rotation * Math.PI) / 180;
8480
const cos = Math.cos(radians);
8581
const sin = Math.sin(radians);
8682

87-
// Point position relative to the offset (rotation center)
8883
const rx = px - offsetX;
8984
const ry = py - offsetY;
9085

91-
// Rotated point
9286
const rotatedX = rx * cos - ry * sin + offsetX;
9387
const rotatedY = rx * sin + ry * cos + offsetY;
9488

@@ -98,7 +92,6 @@ export const ObjectEditIndicator = ({
9892
}
9993
}
10094

101-
// Calculate bounding box from transformed points
10295
const xPoints = transformedPoints.filter(
10396
(_: number, i: number) => i % 2 === 0
10497
);
@@ -139,23 +132,18 @@ export const ObjectEditIndicator = ({
139132

140133
const padding = 4;
141134

142-
// If the object is rotated, we need to apply the same rotation to the indicator
143135
const shouldRotate =
144136
rotation !== 0 && (shapeType === "Rect" || shapeType === "Text");
145137

146-
// Smart positioning for the label
147-
// Check if we're close to right edge of viewport and adjust position accordingly
148138
const BADGE_WIDTH = Math.min(150, editorNames.length * 7 + 20);
149139
const VIEWPORT_WIDTH =
150140
typeof window !== "undefined" ? window.innerWidth : 1000;
151141
const VIEWPORT_HEIGHT =
152142
typeof window !== "undefined" ? window.innerHeight : 800;
153143

154-
// Calculate if the label would go outside the viewport
155144
const isNearRightEdge = x + width + BADGE_WIDTH + 10 > VIEWPORT_WIDTH;
156145
const isNearBottomEdge = y + 30 > VIEWPORT_HEIGHT;
157146

158-
// Adjust label position based on viewport boundaries
159147
const labelX = isNearRightEdge ? x - BADGE_WIDTH - 5 : x + width + 5;
160148
const labelY = isNearBottomEdge ? y - 30 : y;
161149

components/board/hooks/use-active-users.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { AnyDocumentId } from "@automerge/automerge-repo";
1212
import { User } from "@/types/User";
1313
import { BoardContext } from "../context/board-context";
14+
import { UserStatusPayload } from "@/types/userStatusPayload";
1415

1516
export type ActiveUser = User & {
1617
editingObjects?: string[];
@@ -62,7 +63,7 @@ export const useActiveUsers = () => {
6263
useEffect(() => {
6364
if (!session?.user || !isOnline) return;
6465

65-
const currentUser = {
66+
const currentUser: UserStatusPayload = {
6667
user: {
6768
id: session.user.id as string,
6869
name: session.user.name || null,
@@ -149,7 +150,7 @@ export const useActiveUsers = () => {
149150

150151
useEffect(() => {
151152
if (!session?.user) return;
152-
const currentUser = {
153+
const currentUser: UserStatusPayload = {
153154
user: {
154155
id: session.user.id as string,
155156
name: session.user.name || null,

components/board/hooks/use-sync-mode.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ const useSyncMode = () => {
1212
const clientSyncService = useClientSync();
1313
const { isOnline, setIsOnline } = useContext(BoardContext);
1414
const { networkStatus } = useNetworkStatusContext();
15-
const { data: session } = useSession();
16-
const handle = useHandle<LayerSchema>(
17-
clientSyncService.getDocUrl() as AnyDocumentId
18-
);
1915

2016
useEffect(() => {
2117
if (networkStatus === "OFFLINE") {

components/boards/create-board-dialog.tsx

+47-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"use client";
2-
31
import { useState } from "react";
42
import { useRouter } from "next/router";
53
import { zodResolver } from "@hookform/resolvers/zod";
@@ -25,14 +23,20 @@ import {
2523
} from "@/components/ui/form";
2624
import { Input } from "@/components/ui/input";
2725
import { Plus } from "lucide-react";
28-
import { toast } from "sonner";
26+
import { toast } from "react-hot-toast";
2927

3028
type FormData = {
3129
name: string;
3230
};
3331

32+
interface ValidationError {
33+
path: string;
34+
message: string;
35+
}
36+
3437
export function CreateBoardDialog({ teamId }: { teamId: string }) {
3538
const [open, setOpen] = useState(false);
39+
const [isSubmitting, setIsSubmitting] = useState(false);
3640
const router = useRouter();
3741
const form = useForm<FormData>({
3842
resolver: zodResolver(schemaBoard),
@@ -43,6 +47,7 @@ export function CreateBoardDialog({ teamId }: { teamId: string }) {
4347

4448
const onSubmit = async (data: FormData) => {
4549
try {
50+
setIsSubmitting(true);
4651
const response = await fetch("/api/boards/create", {
4752
method: "POST",
4853
headers: {
@@ -52,43 +57,59 @@ export function CreateBoardDialog({ teamId }: { teamId: string }) {
5257
credentials: "include",
5358
});
5459

55-
const board = await response.json();
56-
console.log("Board:", board);
60+
const result = await response.json();
61+
5762
if (response.ok) {
63+
toast.success("Board created successfully");
64+
setOpen(false);
65+
form.reset();
5866
router.push(`/teams/${teamId}/boards/`);
59-
} else {
60-
throw new Error(board.message || "Failed to create board");
67+
return;
6168
}
6269

63-
toast.success("Board created successfully");
64-
setOpen(false);
65-
form.reset();
70+
if (!response.ok && result.errors) {
71+
const apiErrors = result.errors as ValidationError[];
72+
apiErrors.forEach((error) => {
73+
if (error.path === "name") {
74+
form.setError("name", {
75+
type: "server",
76+
message: error.message,
77+
});
78+
}
79+
});
80+
81+
throw new Error(result.message || "Failed to create board");
82+
} else {
83+
throw new Error(result.message || "Failed to create board");
84+
}
6685
} catch (error) {
6786
toast.error(
6887
error instanceof Error ? error.message : "Something went wrong"
6988
);
7089
console.error(error);
90+
} finally {
91+
setIsSubmitting(false);
7192
}
7293
};
7394

7495
return (
7596
<Dialog open={open} onOpenChange={setOpen}>
7697
<DialogTrigger asChild>
77-
<Button
78-
className="bg-burnt-sienna hover:bg-burnt-sienna-darker ms-10"
79-
aria-label="Create new board"
80-
>
81-
<Plus className="mr-2 h-4 w-4" />
98+
<Button className="flex gap-1 items-center">
99+
<Plus className="h-4 w-4" />
82100
Create Board
83101
</Button>
84102
</DialogTrigger>
85-
<DialogContent className="sm:max-w-[425px]">
103+
<DialogContent>
86104
<DialogHeader>
87-
<DialogTitle>Create New Board</DialogTitle>
105+
<DialogTitle className="text-xl font-bold">
106+
Create a New Board
107+
</DialogTitle>
88108
<DialogDescription>
89-
Create a new board to start collaborating with your team.
109+
Create a new board for your team to collaborate on
90110
</DialogDescription>
91111
</DialogHeader>
112+
92113
<Form {...form}>
93114
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
94115
<FormField
@@ -104,13 +125,17 @@ export function CreateBoardDialog({ teamId }: { teamId: string }) {
104125
</FormItem>
105126
)}
106127
/>
128+
107129
<DialogFooter>
108130
<Button
109-
type="submit"
110-
className="bg-burnt-sienna hover:bg-burnt-sienna-darker"
111-
disabled={form.formState.isSubmitting}
131+
type="button"
132+
variant="outline"
133+
onClick={() => setOpen(false)}
112134
>
113-
{form.formState.isSubmitting ? "Creating..." : "Create Board"}
135+
Cancel
136+
</Button>
137+
<Button type="submit" disabled={isSubmitting}>
138+
{isSubmitting ? "Creating..." : "Create Board"}
114139
</Button>
115140
</DialogFooter>
116141
</form>

0 commit comments

Comments
 (0)