merlyn/frontend/src/components/Sidebar/ActiveWorkspaces/index.jsx
Sean Hatfield 43e54a19dc
[FEAT] Workspace settings gear icon UX improvement (#1254)
take user back to workspace chat from gear icon
2024-05-01 16:22:10 -07:00

199 lines
7.6 KiB
JavaScript

import React, { useState, useEffect, useCallback } from "react";
import * as Skeleton from "react-loading-skeleton";
import "react-loading-skeleton/dist/skeleton.css";
import Workspace from "@/models/workspace";
import ManageWorkspace, {
useManageWorkspaceModal,
} from "../../Modals/MangeWorkspace";
import paths from "@/utils/paths";
import { useParams } from "react-router-dom";
import { GearSix, SquaresFour, UploadSimple } from "@phosphor-icons/react";
import truncate from "truncate";
import useUser from "@/hooks/useUser";
import ThreadContainer from "./ThreadContainer";
import { Link, useMatch } from "react-router-dom";
export default function ActiveWorkspaces() {
const { slug } = useParams();
const [loading, setLoading] = useState(true);
const [workspaces, setWorkspaces] = useState([]);
const [selectedWs, setSelectedWs] = useState(null);
const [hoverStates, setHoverStates] = useState({});
const [gearHover, setGearHover] = useState({});
const [uploadHover, setUploadHover] = useState({});
const { showing, showModal, hideModal } = useManageWorkspaceModal();
const { user } = useUser();
const isInWorkspaceSettings = !!useMatch("/workspace/:slug/settings/:tab");
useEffect(() => {
async function getWorkspaces() {
const workspaces = await Workspace.all();
setLoading(false);
setWorkspaces(workspaces);
}
getWorkspaces();
}, []);
const handleMouseEnter = useCallback((workspaceId) => {
setHoverStates((prev) => ({ ...prev, [workspaceId]: true }));
}, []);
const handleMouseLeave = useCallback((workspaceId) => {
setHoverStates((prev) => ({ ...prev, [workspaceId]: false }));
}, []);
const handleGearMouseEnter = useCallback((workspaceId) => {
setGearHover((prev) => ({ ...prev, [workspaceId]: true }));
}, []);
const handleGearMouseLeave = useCallback((workspaceId) => {
setGearHover((prev) => ({ ...prev, [workspaceId]: false }));
}, []);
const handleUploadMouseEnter = useCallback((workspaceId) => {
setUploadHover((prev) => ({ ...prev, [workspaceId]: true }));
}, []);
const handleUploadMouseLeave = useCallback((workspaceId) => {
setUploadHover((prev) => ({ ...prev, [workspaceId]: false }));
}, []);
if (loading) {
return (
<>
<Skeleton.default
height={36}
width="100%"
count={3}
baseColor="#292524"
highlightColor="#4c4948"
enableAnimation={true}
/>
</>
);
}
return (
<div role="list" aria-label="Workspaces" className="flex flex-col gap-y-2">
{workspaces.map((workspace) => {
const isActive = workspace.slug === slug;
const isHovered = hoverStates[workspace.id];
return (
<div
className="flex flex-col w-full"
onMouseEnter={() => handleMouseEnter(workspace.id)}
onMouseLeave={() => handleMouseLeave(workspace.id)}
key={workspace.id}
role="listitem"
>
<div
key={workspace.id}
className="flex gap-x-2 items-center justify-between"
>
<a
href={isActive ? null : paths.workspace.chat(workspace.slug)}
aria-current={isActive ? "page" : ""}
className={`
transition-all duration-[200ms]
flex flex-grow w-[75%] gap-x-2 py-[6px] px-[12px] rounded-[4px] text-white justify-start items-center
hover:bg-workspace-item-selected-gradient hover:font-bold border-2 border-outline
${
isActive
? "bg-workspace-item-selected-gradient font-bold"
: ""
}`}
>
<div className="flex flex-row justify-between w-full">
<div className="flex items-center space-x-2">
<SquaresFour
weight={isActive ? "fill" : "regular"}
className="flex-shrink-0"
size={24}
/>
<p
className={`text-[14px] leading-loose whitespace-nowrap overflow-hidden ${
isActive ? "text-white " : "text-zinc-200"
}`}
>
{isActive || isHovered
? truncate(workspace.name, 15)
: truncate(workspace.name, 20)}
</p>
</div>
{(isActive || isHovered || gearHover[workspace.id]) &&
user?.role !== "default" ? (
<div className="flex items-center gap-x-[2px]">
<div
className={`flex hover:bg-[#646768] p-[2px] rounded-[4px] text-[#A7A8A9] hover:text-white ${
uploadHover[workspace.id] ? "bg-[#646768]" : ""
}`}
>
<button
type="button"
onClick={(e) => {
e.preventDefault();
setSelectedWs(workspace);
showModal();
}}
onMouseEnter={() =>
handleUploadMouseEnter(workspace.id)
}
onMouseLeave={() =>
handleUploadMouseLeave(workspace.id)
}
className="rounded-md flex items-center justify-center ml-auto"
>
<UploadSimple
className="h-[20px] w-[20px]"
weight="bold"
/>
</button>
</div>
<Link
type="button"
to={
isInWorkspaceSettings
? paths.workspace.chat(workspace.slug)
: paths.workspace.settings.generalAppearance(
workspace.slug
)
}
onMouseEnter={() => handleGearMouseEnter(workspace.id)}
onMouseLeave={() => handleGearMouseLeave(workspace.id)}
className="rounded-md flex items-center justify-center text-[#A7A8A9] hover:text-white ml-auto"
aria-label="General appearance settings"
>
<div className="flex hover:bg-[#646768] p-[2px] rounded-[4px]">
<GearSix
color={
isInWorkspaceSettings && workspace.slug === slug
? "#46C8FF"
: gearHover[workspace.id]
? "#FFFFFF"
: "#A7A8A9"
}
weight="bold"
className="h-[20px] w-[20px]"
/>
</div>
</Link>
</div>
) : null}
</div>
</a>
</div>
{isActive && (
<ThreadContainer workspace={workspace} isActive={isActive} />
)}
</div>
);
})}
{showing && (
<ManageWorkspace
hideModal={hideModal}
providedSlug={selectedWs ? selectedWs.slug : null}
/>
)}
</div>
);
}