Skip to content

Commit

Permalink
Bc 6342 hide user indicator (#48)
Browse files Browse the repository at this point in the history
* BC-4709-create-authorizatiopn-service

* Fixed errorMessage

* fix error handling

* Check redirect

* redirect

* redirect

* Add button

* Add logout redirect

* fix

* Add handling errors

* Add check

* fix dependencies

* Add 4404 error

* add check

* Delete console.log

* Fix

* rewrite create-react-app to vite and refactor

* Delete .idea directory

* update Dockerfile

* fix modal showing on refresh

* fix favicon

* fix zoom

* add timeout

* fix line separators

* change tsconfig extensions option

* move redirect method to utils

* remove default room name

* remove comment

* remove console log on localhost

* fix line endings

* add custom cursors and refactor

* fix error handling

* add error handling and refactor

* add file storage support

* add notifications

* Revert "Merge branch 'main' into vite-tldraw-storage"

This reverts commit 27e1a41, reversing
changes made to e4a6ce8.

* fix dependency review

* fix allowed assets condition

* adjust cursor position

* add error notifications and minor fixes

* clear error data on start

* remove unused package

* fix users count hook

* fix multiplayer state

* move method inside useEffect

* refactor html remover hook

* set default tldraw state in setup

* set default tldraw state in setup

* configure vitest and add tests

* fix notifications and error messages

* move and add some comments

* change page title

* rename function

* fix import order

* change user displayname to full name

* fix user name display

* update vite

* Change parent type in file endpoint

* change file api url

* Hide the user indicator when focus mode is on

* Fix tests

* fix merge conflicts

* Small fix

---------

Co-authored-by: Viktoriia <1>
Co-authored-by: davwas <[email protected]>
Co-authored-by: blazejpass <[email protected]>
  • Loading branch information
3 people authored Feb 1, 2024
1 parent 5778c5f commit 8efa399
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 101 deletions.
10 changes: 8 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import { useTldrawSettings } from "./hooks/useTldrawSettings";

function App() {
useJwtHandler();
const { isDarkMode, handleDarkModeChange } = useTldrawSettings();
const {
isDarkMode,
isFocusMode,
handleDarkModeChange,
handleFocusModeChange,
} = useTldrawSettings();

return (
<div>
<div className="tldraw-content">
<UsersInfo />
<UsersInfo isFocusMode={isFocusMode} />
<div className="tldraw">
<Editor
roomId={roomId}
darkModeHandler={handleDarkModeChange}
focusModeHandler={handleFocusModeChange}
/>
</div>
</div>
Expand Down
8 changes: 7 additions & 1 deletion src/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ import { useTldrawSettings } from "../hooks/useTldrawSettings";
function Editor({
roomId,
darkModeHandler,
focusModeHandler,
}: {
roomId: string;
darkModeHandler: (isDarkMode: boolean) => void;
focusModeHandler: (isFocusMode: boolean) => void;
}) {
const { onSaveProjectAs, onSaveProject, onOpenMedia } = useFileSystem();
const { onMount, onOpen, onAssetCreate, onAssetDelete, onPatch, ...events } =
useMultiplayerState(roomId, darkModeHandler);
useMultiplayerState({
roomId,
setIsDarkMode: darkModeHandler,
setIsFocusMode: focusModeHandler,
});
const containerRef = useRef<HTMLDivElement | null>(null);
useTldrawUiSanitizer(containerRef);
const { isDarkMode } = useTldrawSettings();
Expand Down
6 changes: 5 additions & 1 deletion src/components/UsersInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import Icon from "@mdi/react";
import { mdiAccountMultipleOutline } from "@mdi/js";
import { useUsersCount } from "../hooks/useUsersCount";

function UsersInfo() {
function UsersInfo({ isFocusMode }: { isFocusMode: boolean }) {
const usersCount = useUsersCount();

if (isFocusMode) {
return null;
}

return (
<div className="user-display">
<div className="user-count">
Expand Down
51 changes: 34 additions & 17 deletions src/hooks/useMultiplayerState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ describe("useMultiplayerState hook", () => {
const mockOpenDialog = vi.fn();
const mockOpenProject = vi.fn();

const setIsDarkMode = vi.fn();
const setIsFocusMode = vi.fn();

const useFileSystemSpy = vi.spyOn(Tldraw, "useFileSystem").mockReturnValue({
onOpenProject: mockOpenProject,
onNewProject: vi.fn(),
Expand All @@ -128,15 +131,21 @@ describe("useMultiplayerState hook", () => {
user,
useFileSystemSpy,
mockOpenDialog,
setIsDarkMode,
setIsFocusMode,
mockOpenProject,
};
};

const multiPlayerProps = {
roomId: "testRoom",
setIsDarkMode: vi.fn(),
setIsFocusMode: vi.fn(),
};

it("should handle onMount correctly", () => {
const { app, loadRoomSpy, pauseSpy } = setup();
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
);
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));

act(() => {
result.current.onMount(app);
Expand All @@ -146,11 +155,27 @@ describe("useMultiplayerState hook", () => {
expect(pauseSpy).toHaveBeenCalled();
});

it("should handle onUndo correctly", () => {
it("should handle setIsDarkMode and setIsFocusMode correctly", () => {
const { app, setIsDarkMode, setIsFocusMode } = setup();
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
useMultiplayerState({
...multiPlayerProps,
setIsDarkMode,
setIsFocusMode,
}),
);

act(() => {
result.current.onPatch(app, {}, "settings");

expect(setIsDarkMode).toHaveBeenCalledWith(app.settings.isDarkMode);
expect(setIsFocusMode).toHaveBeenCalledWith(app.settings.isFocusMode);
});
});

it("should handle onUndo correctly", () => {
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));

act(() => {
result.current.onUndo();
});
Expand All @@ -159,9 +184,7 @@ describe("useMultiplayerState hook", () => {
});

it("should handle onRedo correctly", () => {
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
);
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));

act(() => {
result.current.onRedo();
Expand All @@ -172,9 +195,7 @@ describe("useMultiplayerState hook", () => {

it("should handle onChangePage correctly", () => {
const { app } = setup();
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
);
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));
const shapes: Record<string, TDShape | undefined> = {
shape1: undefined,
};
Expand All @@ -194,9 +215,7 @@ describe("useMultiplayerState hook", () => {

it("should handle onChangePresence correctly", () => {
const { app, user } = setup();
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
);
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));

act(() => {
app.loadRoom("testRoom");
Expand All @@ -210,9 +229,7 @@ describe("useMultiplayerState hook", () => {

it("should handle onOpen correctly", () => {
const { app, mockOpenDialog, mockOpenProject } = setup();
const { result } = renderHook(() =>
useMultiplayerState("testRoom", () => {}),
);
const { result } = renderHook(() => useMultiplayerState(multiPlayerProps));

act(() => {
result.current.onOpen(app, mockOpenDialog);
Expand Down
168 changes: 88 additions & 80 deletions src/hooks/useMultiplayerState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,90 +29,21 @@ import { UserPresence } from "../types/UserPresence";

declare const window: Window & { app: TldrawApp };

export function useMultiplayerState(
roomId: string,
setIsDarkMode: (isDarkMode: boolean) => void,
) {
interface MultiplayerStateProps {
roomId: string;
setIsDarkMode: (isDarkMode: boolean) => void;
setIsFocusMode: (isFocusMode: boolean) => void;
}

export function useMultiplayerState({
roomId,
setIsDarkMode,
setIsFocusMode,
}: MultiplayerStateProps) {
const [app, setApp] = useState<TldrawApp>();
const [loading, setLoading] = useState(true);
const { onOpenProject } = useFileSystem();

const openFromFileSystem = async (): Promise<null | {
fileHandle: FileSystemFileHandle | null;
document: TDDocument;
}> => {
// Get the blob
const blob = await fileOpen({
description: "Tldraw File",
extensions: [".tldr"],
multiple: false,
});

if (!blob) return null;

// Get JSON from blob
const json: string = await new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => {
if (reader.readyState === FileReader.DONE) {
resolve(reader.result as string);
}
};
reader.readAsText(blob, "utf8");
});

// Parse
const file: TDFile = JSON.parse(json);
if ("tldrawFileFormatVersion" in file) {
console.error(
"This file was created in a newer version of tldraw and it cannot be opened",
);
toast.info(
"This file was created in a newer version of tldraw and it cannot be opened",
);
return null;
}

const fileHandle = blob.handle ?? null;

return {
fileHandle,
document: file.document,
};
};

const updateDoc = (
shapes: Record<string, TDShape | undefined>,
bindings: Record<string, TDBinding | undefined>,
assets: Record<string, TDAsset | undefined>,
) => {
doc.transact(() => {
Object.entries(shapes).forEach(([id, shape]) => {
if (!shape) {
yShapes.delete(id);
} else {
yShapes.set(shape.id, shape);
}
});

Object.entries(bindings).forEach(([id, binding]) => {
if (!binding) {
yBindings.delete(id);
} else {
yBindings.set(binding.id, binding);
}
});

Object.entries(assets).forEach(([id, asset]) => {
if (!asset) {
yAssets.delete(id);
} else {
yAssets.set(asset.id, asset);
}
});
});
};

// Callbacks --------------

const onOpen = useCallback(
Expand Down Expand Up @@ -254,6 +185,7 @@ export function useMultiplayerState(
);

setIsDarkMode(app.settings.isDarkMode);
setIsFocusMode(app.settings.isFocusMode);
}
},
[setIsDarkMode],
Expand Down Expand Up @@ -403,3 +335,79 @@ export function useMultiplayerState(
onAssetDelete,
};
}

const openFromFileSystem = async (): Promise<null | {
fileHandle: FileSystemFileHandle | null;
document: TDDocument;
}> => {
// Get the blob
const blob = await fileOpen({
description: "Tldraw File",
extensions: [".tldr"],
multiple: false,
});

if (!blob) return null;

// Get JSON from blob
const json: string = await new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => {
if (reader.readyState === FileReader.DONE) {
resolve(reader.result as string);
}
};
reader.readAsText(blob, "utf8");
});

// Parse
const file: TDFile = JSON.parse(json);
if ("tldrawFileFormatVersion" in file) {
console.error(
"This file was created in a newer version of tldraw and it cannot be opened",
);
toast.info(
"This file was created in a newer version of tldraw and it cannot be opened",
);
return null;
}

const fileHandle = blob.handle ?? null;

return {
fileHandle,
document: file.document,
};
};

const updateDoc = (
shapes: Record<string, TDShape | undefined>,
bindings: Record<string, TDBinding | undefined>,
assets: Record<string, TDAsset | undefined>,
) => {
doc.transact(() => {
Object.entries(shapes).forEach(([id, shape]) => {
if (!shape) {
yShapes.delete(id);
} else {
yShapes.set(shape.id, shape);
}
});

Object.entries(bindings).forEach(([id, binding]) => {
if (!binding) {
yBindings.delete(id);
} else {
yBindings.set(binding.id, binding);
}
});

Object.entries(assets).forEach(([id, asset]) => {
if (!asset) {
yAssets.delete(id);
} else {
yAssets.set(asset.id, asset);
}
});
});
};

0 comments on commit 8efa399

Please sign in to comment.