mirror of
https://github.com/Dvorinka/excalidraw-full.git
synced 2026-06-05 06:32:56 +00:00
init frontend
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { useEffect } from "react";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { User } from "../app-jotai";
|
||||
|
||||
export const useAuth = (setUser: (user: User | null) => void) => {
|
||||
useEffect(() => {
|
||||
// Check for token in URL params, which happens after GitHub login redirect.
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const token = searchParams.get("token");
|
||||
if (token) {
|
||||
localStorage.setItem("token", token);
|
||||
// Clean the token from the URL.
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
}
|
||||
|
||||
const storedToken = localStorage.getItem("token");
|
||||
if (storedToken) {
|
||||
try {
|
||||
const decodedToken: any = jwtDecode(storedToken);
|
||||
// Check if token is expired.
|
||||
if (decodedToken.exp * 1000 > Date.now()) {
|
||||
setUser({
|
||||
id: decodedToken.userId,
|
||||
githubId: decodedToken.githubId,
|
||||
login: decodedToken.login,
|
||||
avatarUrl: decodedToken.avatarUrl,
|
||||
name: decodedToken.name,
|
||||
});
|
||||
} else {
|
||||
// Token is expired, remove it.
|
||||
localStorage.removeItem("token");
|
||||
setUser(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Invalid token:", error);
|
||||
localStorage.removeItem("token");
|
||||
setUser(null);
|
||||
}
|
||||
}
|
||||
}, [setUser]);
|
||||
};
|
||||
@@ -0,0 +1,218 @@
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import {
|
||||
IStorageAdapter,
|
||||
CanvasMetadata,
|
||||
CanvasData,
|
||||
} from "../data/storage";
|
||||
import { AuthError } from "../data/storageAdapters/BackendStorageAdapter";
|
||||
import { ExcalidrawImperativeAPI } from "../../packages/excalidraw/types";
|
||||
import { User, currentCanvasIdAtom } from "../app-jotai";
|
||||
import { CREATIONS_SIDEBAR_NAME } from "../app_constants";
|
||||
|
||||
export const useCanvasManagement = ({
|
||||
storageAdapter,
|
||||
excalidrawAPI,
|
||||
user,
|
||||
setErrorMessage,
|
||||
resetSaveStatus,
|
||||
}: {
|
||||
storageAdapter: IStorageAdapter;
|
||||
excalidrawAPI: ExcalidrawImperativeAPI | null | undefined;
|
||||
user: User | null;
|
||||
setErrorMessage: (msg: string) => void;
|
||||
resetSaveStatus: () => void;
|
||||
}) => {
|
||||
const [canvases, setCanvases] = useState<CanvasMetadata[]>([]);
|
||||
const [currentCanvasId, setCurrentCanvasId] = useAtom(currentCanvasIdAtom);
|
||||
|
||||
const refreshCanvases = useCallback(async () => {
|
||||
try {
|
||||
const canvases = await storageAdapter.listCanvases();
|
||||
console.log("canvases", canvases);
|
||||
setCanvases(canvases);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setErrorMessage("Could not list your creations.");
|
||||
}
|
||||
}, [storageAdapter, setErrorMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshCanvases();
|
||||
}, [refreshCanvases]);
|
||||
|
||||
const openSidebar = excalidrawAPI?.getAppState().openSidebar;
|
||||
useEffect(() => {
|
||||
if (
|
||||
openSidebar?.name === "default" &&
|
||||
openSidebar?.tab === CREATIONS_SIDEBAR_NAME
|
||||
) {
|
||||
refreshCanvases();
|
||||
}
|
||||
}, [openSidebar, refreshCanvases]);
|
||||
|
||||
const handleCanvasSelect = useCallback(
|
||||
async (id: string) => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const canvasData = await storageAdapter.loadCanvas(id);
|
||||
if (canvasData) {
|
||||
excalidrawAPI.updateScene({ appState: { openSidebar: null } });
|
||||
excalidrawAPI.addFiles(Object.values(canvasData.files));
|
||||
excalidrawAPI.updateScene({
|
||||
elements: canvasData.elements,
|
||||
appState: canvasData.appState,
|
||||
commitToHistory: true,
|
||||
});
|
||||
setCurrentCanvasId(id);
|
||||
resetSaveStatus();
|
||||
}
|
||||
} catch (error) {
|
||||
setErrorMessage("Could not load the canvas.");
|
||||
}
|
||||
},
|
||||
[storageAdapter, excalidrawAPI, setErrorMessage, setCurrentCanvasId, resetSaveStatus],
|
||||
);
|
||||
|
||||
const handleCanvasDelete = useCallback(
|
||||
async (id: string) => {
|
||||
if (window.confirm("Are you sure you want to delete this canvas?")) {
|
||||
try {
|
||||
await storageAdapter.deleteCanvas(id);
|
||||
if (currentCanvasId === id) {
|
||||
setCurrentCanvasId(null);
|
||||
excalidrawAPI?.resetScene();
|
||||
resetSaveStatus();
|
||||
}
|
||||
await refreshCanvases();
|
||||
} catch (error: any) {
|
||||
if (error instanceof AuthError) {
|
||||
setErrorMessage("您需要登录才能删除此画布。");
|
||||
} else {
|
||||
setErrorMessage("Could not delete the canvas.");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
storageAdapter,
|
||||
refreshCanvases,
|
||||
setErrorMessage,
|
||||
currentCanvasId,
|
||||
setCurrentCanvasId,
|
||||
excalidrawAPI,
|
||||
resetSaveStatus,
|
||||
],
|
||||
);
|
||||
|
||||
const handleCanvasCreate = useCallback(
|
||||
async (newName: string) => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const appState = { ...excalidrawAPI.getAppState(), name: newName };
|
||||
const newCanvasData = {
|
||||
elements: [],
|
||||
appState,
|
||||
files: {},
|
||||
};
|
||||
const createdCanvas = await storageAdapter.createCanvas(
|
||||
newCanvasData as CanvasData,
|
||||
);
|
||||
await refreshCanvases();
|
||||
excalidrawAPI.resetScene();
|
||||
excalidrawAPI.updateScene({ appState: { name: newName } });
|
||||
setCurrentCanvasId(createdCanvas.id);
|
||||
} catch (error: any) {
|
||||
if (error instanceof AuthError) {
|
||||
setErrorMessage("您需要登录才能创建新画布。");
|
||||
} else {
|
||||
setErrorMessage("Could not create new canvas.");
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
excalidrawAPI,
|
||||
storageAdapter,
|
||||
refreshCanvases,
|
||||
setErrorMessage,
|
||||
setCurrentCanvasId,
|
||||
],
|
||||
);
|
||||
|
||||
const handleCanvasRename = useCallback(
|
||||
async (id: string, newName: string) => {
|
||||
try {
|
||||
await storageAdapter.renameCanvas(id, newName);
|
||||
await refreshCanvases();
|
||||
if (excalidrawAPI && currentCanvasId === id) {
|
||||
excalidrawAPI.updateScene({ appState: { name: newName } });
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error instanceof AuthError) {
|
||||
setErrorMessage("您需要登录才能重命名此画布。");
|
||||
} else {
|
||||
setErrorMessage("Could not rename the canvas.");
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
storageAdapter,
|
||||
refreshCanvases,
|
||||
setErrorMessage,
|
||||
excalidrawAPI,
|
||||
currentCanvasId,
|
||||
],
|
||||
);
|
||||
|
||||
const handleCanvasSaveAs = useCallback(
|
||||
async (newName: string) => {
|
||||
if (!excalidrawAPI) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const appState = { ...excalidrawAPI.getAppState(), name: newName };
|
||||
const elements = excalidrawAPI.getSceneElements();
|
||||
const files = excalidrawAPI.getFiles();
|
||||
|
||||
const newCanvasData = {
|
||||
elements,
|
||||
appState,
|
||||
files,
|
||||
};
|
||||
const createdCanvas = await storageAdapter.createCanvas(
|
||||
newCanvasData as CanvasData,
|
||||
);
|
||||
await refreshCanvases();
|
||||
// After saving as, we should switch to the new canvas
|
||||
setCurrentCanvasId(createdCanvas.id);
|
||||
} catch (error: any) {
|
||||
if (error instanceof AuthError) {
|
||||
setErrorMessage("您需要登录才能另存为新画布。");
|
||||
} else {
|
||||
setErrorMessage("Could not save as new canvas.");
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
excalidrawAPI,
|
||||
storageAdapter,
|
||||
refreshCanvases,
|
||||
setErrorMessage,
|
||||
setCurrentCanvasId,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
canvases,
|
||||
handleCanvasSelect,
|
||||
handleCanvasDelete,
|
||||
handleCanvasCreate,
|
||||
handleCanvasRename,
|
||||
handleCanvasSaveAs,
|
||||
refreshCanvases,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user