|
|
import React, { useState, useEffect } 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/ManageWorkspace"; |
|
|
import paths from "@/utils/paths"; |
|
|
import { useParams, useNavigate } from "react-router-dom"; |
|
|
import { GearSix, UploadSimple, DotsSixVertical } from "@phosphor-icons/react"; |
|
|
import useUser from "@/hooks/useUser"; |
|
|
import ThreadContainer from "./ThreadContainer"; |
|
|
import { useMatch } from "react-router-dom"; |
|
|
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; |
|
|
import showToast from "@/utils/toast"; |
|
|
|
|
|
export default function ActiveWorkspaces() { |
|
|
const navigate = useNavigate(); |
|
|
const { slug } = useParams(); |
|
|
const [loading, setLoading] = useState(true); |
|
|
const [workspaces, setWorkspaces] = useState([]); |
|
|
const [selectedWs, setSelectedWs] = useState(null); |
|
|
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(Workspace.orderWorkspaces(workspaces)); |
|
|
} |
|
|
getWorkspaces(); |
|
|
}, []); |
|
|
|
|
|
if (loading) { |
|
|
return ( |
|
|
<Skeleton.default |
|
|
height={40} |
|
|
width="100%" |
|
|
count={5} |
|
|
baseColor="var(--theme-sidebar-item-default)" |
|
|
highlightColor="var(--theme-sidebar-item-hover)" |
|
|
enableAnimation={true} |
|
|
className="my-1" |
|
|
/> |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function reorderWorkspaces(startIndex, endIndex) { |
|
|
const reorderedWorkspaces = Array.from(workspaces); |
|
|
const [removed] = reorderedWorkspaces.splice(startIndex, 1); |
|
|
reorderedWorkspaces.splice(endIndex, 0, removed); |
|
|
setWorkspaces(reorderedWorkspaces); |
|
|
const success = Workspace.storeWorkspaceOrder( |
|
|
reorderedWorkspaces.map((w) => w.id) |
|
|
); |
|
|
if (!success) { |
|
|
showToast("Failed to reorder workspaces", "error"); |
|
|
Workspace.all().then((workspaces) => setWorkspaces(workspaces)); |
|
|
} |
|
|
} |
|
|
|
|
|
const onDragEnd = (result) => { |
|
|
if (!result.destination) return; |
|
|
reorderWorkspaces(result.source.index, result.destination.index); |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<DragDropContext onDragEnd={onDragEnd}> |
|
|
<Droppable droppableId="workspaces"> |
|
|
{(provided) => ( |
|
|
<div |
|
|
role="list" |
|
|
aria-label="Workspaces" |
|
|
className="flex flex-col gap-y-2" |
|
|
ref={provided.innerRef} |
|
|
{...provided.droppableProps} |
|
|
> |
|
|
{workspaces.map((workspace, index) => { |
|
|
const isActive = workspace.slug === slug; |
|
|
return ( |
|
|
<Draggable |
|
|
key={workspace.id} |
|
|
draggableId={workspace.id.toString()} |
|
|
index={index} |
|
|
> |
|
|
{(provided, snapshot) => ( |
|
|
<div |
|
|
ref={provided.innerRef} |
|
|
{...provided.draggableProps} |
|
|
className={`flex flex-col w-full group ${ |
|
|
snapshot.isDragging ? "opacity-50" : "" |
|
|
}`} |
|
|
role="listitem" |
|
|
> |
|
|
<div 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] pl-[4px] pr-[6px] rounded-[4px] text-white justify-start items-center |
|
|
bg-theme-sidebar-item-default |
|
|
hover:bg-theme-sidebar-subitem-hover hover:font-bold |
|
|
${isActive ? "bg-theme-sidebar-item-selected font-bold light:outline-2 light:outline light:outline-blue-400 light:outline-offset-[-2px]" : ""} |
|
|
`} |
|
|
> |
|
|
<div className="flex flex-row justify-between w-full items-center"> |
|
|
<div |
|
|
{...provided.dragHandleProps} |
|
|
className="cursor-grab mr-[3px]" |
|
|
> |
|
|
<DotsSixVertical |
|
|
size={20} |
|
|
color="var(--theme-sidebar-item-workspace-active)" |
|
|
weight="bold" |
|
|
/> |
|
|
</div> |
|
|
<div className="flex items-center space-x-2 overflow-hidden flex-grow"> |
|
|
<div className="w-[130px] overflow-hidden"> |
|
|
<p |
|
|
className={` |
|
|
text-[14px] leading-loose whitespace-nowrap overflow-hidden text-white |
|
|
${isActive ? "font-bold" : "font-medium"} truncate |
|
|
w-full group-hover:w-[130px] group-hover:font-bold group-hover:duration-200 |
|
|
`} |
|
|
> |
|
|
{workspace.name} |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
{user?.role !== "default" && ( |
|
|
<div |
|
|
className={`flex items-center gap-x-[2px] transition-opacity duration-200 ${isActive ? "opacity-100" : "opacity-0 group-hover:opacity-100"}`} |
|
|
> |
|
|
<button |
|
|
type="button" |
|
|
onClick={(e) => { |
|
|
e.preventDefault(); |
|
|
setSelectedWs(workspace); |
|
|
showModal(); |
|
|
}} |
|
|
className="border-none rounded-md flex items-center justify-center ml-auto p-[2px] hover:bg-[#646768] text-[#A7A8A9] hover:text-white" |
|
|
> |
|
|
<UploadSimple className="h-[20px] w-[20px]" /> |
|
|
</button> |
|
|
<button |
|
|
onClick={(e) => { |
|
|
e.preventDefault(); |
|
|
e.stopPropagation(); |
|
|
navigate( |
|
|
isInWorkspaceSettings |
|
|
? paths.workspace.chat(workspace.slug) |
|
|
: paths.workspace.settings.generalAppearance( |
|
|
workspace.slug |
|
|
) |
|
|
); |
|
|
}} |
|
|
className="rounded-md flex items-center justify-center text-[#A7A8A9] hover:text-white ml-auto p-[2px] hover:bg-[#646768]" |
|
|
aria-label="General appearance settings" |
|
|
> |
|
|
<GearSix |
|
|
color={ |
|
|
isInWorkspaceSettings && |
|
|
workspace.slug === slug |
|
|
? "#46C8FF" |
|
|
: undefined |
|
|
} |
|
|
className="h-[20px] w-[20px]" |
|
|
/> |
|
|
</button> |
|
|
</div> |
|
|
)} |
|
|
</div> |
|
|
</a> |
|
|
</div> |
|
|
{isActive && ( |
|
|
<ThreadContainer |
|
|
workspace={workspace} |
|
|
isActive={isActive} |
|
|
/> |
|
|
)} |
|
|
</div> |
|
|
)} |
|
|
</Draggable> |
|
|
); |
|
|
})} |
|
|
{provided.placeholder} |
|
|
{showing && ( |
|
|
<ManageWorkspace |
|
|
hideModal={hideModal} |
|
|
providedSlug={selectedWs ? selectedWs.slug : null} |
|
|
/> |
|
|
)} |
|
|
</div> |
|
|
)} |
|
|
</Droppable> |
|
|
</DragDropContext> |
|
|
); |
|
|
} |
|
|
|