From 0808532b494cda95815d95a8a9a754a5106a4fc2 Mon Sep 17 00:00:00 2001
From: David Luzar <5153846+dwelle@users.noreply.github.com>
Date: Mon, 18 Dec 2023 16:14:25 +0100
Subject: [PATCH] fix: follow mode collaborator status indicator (#7459)
---
.../excalidraw/actions/actionNavigate.tsx | 30 ++++++----
packages/excalidraw/components/App.tsx | 1 +
packages/excalidraw/components/LayerUI.tsx | 5 +-
packages/excalidraw/components/Tooltip.tsx | 5 ++
packages/excalidraw/components/UserList.scss | 7 +++
packages/excalidraw/components/UserList.tsx | 57 ++++++++++++-------
.../components/main-menu/MainMenu.tsx | 1 +
packages/excalidraw/locales/en.json | 3 +-
8 files changed, 75 insertions(+), 34 deletions(-)
diff --git a/packages/excalidraw/actions/actionNavigate.tsx b/packages/excalidraw/actions/actionNavigate.tsx
index 46492c73..1c55f104 100644
--- a/packages/excalidraw/actions/actionNavigate.tsx
+++ b/packages/excalidraw/actions/actionNavigate.tsx
@@ -1,5 +1,8 @@
import { getClientColor } from "../clients";
import { Avatar } from "../components/Avatar";
+import { GoToCollaboratorComponentProps } from "../components/UserList";
+import { eyeIcon } from "../components/icons";
+import { t } from "../i18n";
import { Collaborator } from "../types";
import { register } from "./register";
@@ -35,38 +38,43 @@ export const actionGoToCollaborator = register({
};
},
PanelComponent: ({ updateData, data, appState }) => {
- const [clientId, collaborator, withName] = data as [
- string,
- Collaborator,
- boolean,
- ];
+ const [socketId, collaborator, withName, isBeingFollowed] =
+ data as GoToCollaboratorComponentProps;
- const background = getClientColor(clientId);
+ const background = getClientColor(socketId);
return withName ? (
updateData({ ...collaborator, clientId })}
+ className="dropdown-menu-item dropdown-menu-item-base UserList__collaborator"
+ onClick={() => updateData({ ...collaborator, socketId })}
>
{}}
name={collaborator.username || ""}
src={collaborator.avatarUrl}
- isBeingFollowed={appState.userToFollow?.socketId === clientId}
+ isBeingFollowed={isBeingFollowed}
isCurrentUser={collaborator.isCurrentUser === true}
/>
{collaborator.username}
+
+ {eyeIcon}
+
) : (
{
- updateData({ ...collaborator, clientId });
+ updateData({ ...collaborator, socketId });
}}
name={collaborator.username || ""}
src={collaborator.avatarUrl}
- isBeingFollowed={appState.userToFollow?.socketId === clientId}
+ isBeingFollowed={isBeingFollowed}
isCurrentUser={collaborator.isCurrentUser === true}
/>
);
diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx
index 71d6ea82..5f3f8be2 100644
--- a/packages/excalidraw/components/App.tsx
+++ b/packages/excalidraw/components/App.tsx
@@ -3472,6 +3472,7 @@ class App extends React.Component {
};
private maybeUnfollowRemoteUser = () => {
+ console.warn("maybeUnfollowRemoteUser");
if (this.state.userToFollow) {
this.setState({ userToFollow: null });
}
diff --git a/packages/excalidraw/components/LayerUI.tsx b/packages/excalidraw/components/LayerUI.tsx
index c7866e7a..7dd36206 100644
--- a/packages/excalidraw/components/LayerUI.tsx
+++ b/packages/excalidraw/components/LayerUI.tsx
@@ -339,7 +339,10 @@ const LayerUI = ({
)}
>
{appState.collaborators.size > 0 && (
-
+
)}
{renderTopRightUI?.(device.editor.isMobile, appState)}
{!appState.viewModeEnabled &&
diff --git a/packages/excalidraw/components/Tooltip.tsx b/packages/excalidraw/components/Tooltip.tsx
index 220de283..38c04ef2 100644
--- a/packages/excalidraw/components/Tooltip.tsx
+++ b/packages/excalidraw/components/Tooltip.tsx
@@ -80,6 +80,7 @@ type TooltipProps = {
label: string;
long?: boolean;
style?: React.CSSProperties;
+ disabled?: boolean;
};
export const Tooltip = ({
@@ -87,11 +88,15 @@ export const Tooltip = ({
label,
long = false,
style,
+ disabled,
}: TooltipProps) => {
useEffect(() => {
return () =>
getTooltipDiv().classList.remove("excalidraw-tooltip--visible");
}, []);
+ if (disabled) {
+ return null;
+ }
return (
shouldWrap ? (
-
+
{children}
) : (
- {children}
+ {children}
);
const renderCollaborator = ({
actionManager,
collaborator,
- clientId,
+ socketId,
withName = false,
shouldWrapWithTooltip = false,
+ isBeingFollowed,
}: {
actionManager: ActionManager;
collaborator: Collaborator;
- clientId: string;
+ socketId: string;
withName?: boolean;
shouldWrapWithTooltip?: boolean;
+ isBeingFollowed: boolean;
}) => {
- const avatarJSX = actionManager.renderAction("goToCollaborator", [
- clientId,
+ const data: GoToCollaboratorComponentProps = [
+ socketId,
collaborator,
withName,
- ]);
+ isBeingFollowed,
+ ];
+ const avatarJSX = actionManager.renderAction("goToCollaborator", data);
return (
@@ -75,6 +86,7 @@ type UserListProps = {
className?: string;
mobile?: boolean;
collaborators: Map;
+ userToFollow: SocketId | null;
};
const collaboratorComparatorKeys = [
@@ -85,7 +97,7 @@ const collaboratorComparatorKeys = [
] as const;
export const UserList = React.memo(
- ({ className, mobile, collaborators }: UserListProps) => {
+ ({ className, mobile, collaborators, userToFollow }: UserListProps) => {
const actionManager = useExcalidrawActionManager();
const uniqueCollaboratorsMap = new Map();
@@ -98,7 +110,6 @@ export const UserList = React.memo(
);
});
- // const uniqueCollaboratorsMap = sampleCollaborators;
const uniqueCollaboratorsArray = Array.from(uniqueCollaboratorsMap).filter(
([_, collaborator]) => collaborator.username?.trim(),
);
@@ -123,23 +134,25 @@ export const UserList = React.memo(
);
const firstNAvatarsJSX = firstNCollaborators.map(
- ([clientId, collaborator]) =>
+ ([socketId, collaborator]) =>
renderCollaborator({
actionManager,
collaborator,
- clientId,
+ socketId,
shouldWrapWithTooltip: true,
+ isBeingFollowed: socketId === userToFollow,
}),
);
return mobile ? (
- {uniqueCollaboratorsArray.map(([clientId, collaborator]) =>
+ {uniqueCollaboratorsArray.map(([socketId, collaborator]) =>
renderCollaborator({
actionManager,
collaborator,
- clientId,
+ socketId,
shouldWrapWithTooltip: true,
+ isBeingFollowed: socketId === userToFollow,
}),
)}
@@ -161,7 +174,7 @@ export const UserList = React.memo(
{t("userList.hint.text")}
- {filteredCollaborators.map(([clientId, collaborator]) =>
+ {filteredCollaborators.map(([socketId, collaborator]) =>
renderCollaborator({
actionManager,
collaborator,
- clientId,
+ socketId,
withName: true,
+ isBeingFollowed: socketId === userToFollow,
}),
)}
@@ -212,7 +226,8 @@ export const UserList = React.memo(
if (
prev.collaborators.size !== next.collaborators.size ||
prev.mobile !== next.mobile ||
- prev.className !== next.className
+ prev.className !== next.className ||
+ prev.userToFollow !== next.userToFollow
) {
return false;
}
diff --git a/packages/excalidraw/components/main-menu/MainMenu.tsx b/packages/excalidraw/components/main-menu/MainMenu.tsx
index 37450ca5..07afd3c1 100644
--- a/packages/excalidraw/components/main-menu/MainMenu.tsx
+++ b/packages/excalidraw/components/main-menu/MainMenu.tsx
@@ -60,6 +60,7 @@ const MainMenu = Object.assign(
)}
diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json
index dc5e86f4..a57b823d 100644
--- a/packages/excalidraw/locales/en.json
+++ b/packages/excalidraw/locales/en.json
@@ -528,7 +528,8 @@
"empty": "No users found"
},
"hint": {
- "text": "Click on user to follow"
+ "text": "Click on user to follow",
+ "followStatus": "You're currently following this user"
}
}
}