Updating workspace structure
This commit is contained in:
+22
-91
@@ -1,98 +1,29 @@
|
||||
import { SidebarEntity } from "@/components/sidebar/Entity";
|
||||
import { SetState, Task } from "@/lib/types";
|
||||
import { OutputData } from "@editorjs/editorjs";
|
||||
import { Entity, EntityId, Workspace } from "@/lib/types";
|
||||
import {
|
||||
loadWorkspaceFromLocalStorage,
|
||||
saveWorkspaceToLocalStorage,
|
||||
} from "@/lib/workspace";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export type Entity =
|
||||
| {
|
||||
name: string;
|
||||
kind: "todo";
|
||||
tasks: Task[];
|
||||
setTasks: SetState<Task[]>;
|
||||
}
|
||||
| {
|
||||
name: string;
|
||||
kind: "doc";
|
||||
doc: OutputData;
|
||||
setDoc: SetState<OutputData>;
|
||||
};
|
||||
export function useWorkspace(workspaceId: string) {
|
||||
const [workspace, setWorkspace] = useState<Workspace>(() =>
|
||||
loadWorkspaceFromLocalStorage(workspaceId),
|
||||
);
|
||||
|
||||
export interface Workspace {
|
||||
name: string;
|
||||
entityLayout: SidebarEntity[];
|
||||
entities: Record<string, Entity>;
|
||||
|
||||
route: string;
|
||||
setRoute: SetState<string>;
|
||||
}
|
||||
|
||||
export default function useWorkspace(): Workspace {
|
||||
const [route, setRoute] = useState("alpha_tasks");
|
||||
const [tasks, setTasks] = useState<Task[]>([]);
|
||||
const [doc, setDoc] = useState<OutputData>({
|
||||
blocks: [],
|
||||
});
|
||||
const [doc2, setDoc2] = useState<OutputData>({
|
||||
blocks: [],
|
||||
});
|
||||
const updateEntity = (entityId: EntityId, updater: (e: Entity) => Entity) => {
|
||||
setWorkspace((prev) => ({
|
||||
...prev,
|
||||
entities: {
|
||||
...prev.entities,
|
||||
[entityId]: updater(prev.entities[entityId]),
|
||||
},
|
||||
updatedAt: Date.now(),
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setTasks([
|
||||
{ id: "1", title: "Buy groceries", status: "todo" },
|
||||
{ id: "2", title: "Plan sprint", status: "todo" },
|
||||
{
|
||||
id: "3",
|
||||
title: "Build App",
|
||||
description: "A simple description",
|
||||
tags: ["website", "api", "app"],
|
||||
status: "inprogress",
|
||||
},
|
||||
]);
|
||||
}, []);
|
||||
saveWorkspaceToLocalStorage(workspace);
|
||||
}, [workspace]);
|
||||
|
||||
return {
|
||||
name: "Personal Workspace",
|
||||
entities: {
|
||||
alpha_tasks: {
|
||||
name: "Alpha tasks",
|
||||
kind: "todo",
|
||||
tasks,
|
||||
setTasks,
|
||||
},
|
||||
beta_tasks: {
|
||||
name: "Beta tasks",
|
||||
kind: "todo",
|
||||
tasks,
|
||||
setTasks,
|
||||
},
|
||||
|
||||
alpha_doc: {
|
||||
name: "Alpha docs",
|
||||
kind: "doc",
|
||||
doc: doc,
|
||||
setDoc: setDoc,
|
||||
},
|
||||
beta_doc: {
|
||||
name: "Beta docs",
|
||||
kind: "doc",
|
||||
doc: doc2,
|
||||
setDoc: setDoc2,
|
||||
},
|
||||
},
|
||||
entityLayout: [
|
||||
{
|
||||
kind: "group",
|
||||
name: "Project alpha",
|
||||
children: [{ id: "alpha_tasks" }, { id: "alpha_doc" }],
|
||||
},
|
||||
{
|
||||
kind: "group",
|
||||
name: "Project beta",
|
||||
children: [{ id: "beta_tasks" }, { id: "beta_doc" }],
|
||||
},
|
||||
],
|
||||
|
||||
route,
|
||||
setRoute,
|
||||
};
|
||||
return { workspace, updateEntity };
|
||||
}
|
||||
|
||||
+81
-9
@@ -1,11 +1,83 @@
|
||||
import { Color } from "./ui/color";
|
||||
|
||||
export type Task = {
|
||||
id: string;
|
||||
title: string;
|
||||
status: string;
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
};
|
||||
import { OutputData } from "@editorjs/editorjs";
|
||||
|
||||
export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
|
||||
|
||||
export type EntityId = string;
|
||||
export type TagId = string;
|
||||
export type TaskId = string;
|
||||
|
||||
export interface Workspace {
|
||||
id: string;
|
||||
name: string;
|
||||
|
||||
entities: Record<EntityId, Entity>;
|
||||
layout: LayoutNode[];
|
||||
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export type LayoutNode = {
|
||||
type: "group";
|
||||
id: string;
|
||||
name: string;
|
||||
children: LayoutItem[];
|
||||
};
|
||||
|
||||
export type LayoutItem = {
|
||||
entityId: EntityId;
|
||||
};
|
||||
|
||||
export type Entity = TodoEntity | DocEntity;
|
||||
|
||||
export interface TodoEntity {
|
||||
id: EntityId;
|
||||
type: "todo";
|
||||
name: string;
|
||||
|
||||
config: {
|
||||
statuses: Status[];
|
||||
};
|
||||
|
||||
tags: Record<TagId, Tag>;
|
||||
tasks: Record<TaskId, Task>;
|
||||
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export interface Status {
|
||||
id: string;
|
||||
name: string;
|
||||
color?: string;
|
||||
order: number;
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
id: TagId;
|
||||
name: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
id: TaskId;
|
||||
title: string;
|
||||
description?: string;
|
||||
|
||||
statusId: string;
|
||||
tagIds: TagId[];
|
||||
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export interface DocEntity {
|
||||
id: EntityId;
|
||||
type: "doc";
|
||||
name: string;
|
||||
|
||||
content: OutputData;
|
||||
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Workspace } from "./types";
|
||||
|
||||
export function createDefaultWorkspace(): Workspace {
|
||||
const now = Date.now();
|
||||
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
name: "New Workspace",
|
||||
entities: {},
|
||||
layout: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
}
|
||||
|
||||
export function loadWorkspaceFromLocalStorage(id: string): Workspace {
|
||||
try {
|
||||
const raw = localStorage.getItem(id);
|
||||
|
||||
if (!raw) {
|
||||
return createDefaultWorkspace();
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
// Basic shape validation
|
||||
if (
|
||||
typeof parsed !== "object" ||
|
||||
parsed === null ||
|
||||
typeof parsed.version !== "number"
|
||||
) {
|
||||
console.warn("Invalid workspace shape. Resetting.");
|
||||
return createDefaultWorkspace();
|
||||
}
|
||||
|
||||
return parsed as Workspace;
|
||||
} catch (err) {
|
||||
console.error("Failed to load workspace:", err);
|
||||
return createDefaultWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
export function saveWorkspaceToLocalStorage(workspace: Workspace): void {
|
||||
try {
|
||||
const serialized = JSON.stringify(workspace);
|
||||
localStorage.setItem(workspace.id, serialized);
|
||||
} catch (err) {
|
||||
console.error("Failed to save workspace:", err);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user