mirror of
https://github.com/QuivrHQ/quivr.git
synced 2024-08-16 18:00:23 +03:00
feat: add brain management people page
This commit is contained in:
parent
37f904122c
commit
cff94e3249
@ -1,14 +1,18 @@
|
||||
import { Content, List, Root } from "@radix-ui/react-tabs";
|
||||
|
||||
import { BrainTabTrigger } from "./components";
|
||||
import { BrainTabTrigger, PeopleTab } from "./components";
|
||||
import { useBrainManagementTabs } from "./hooks/useBrainManagementTabs";
|
||||
|
||||
export const BrainManagementTabs = (): JSX.Element => {
|
||||
const { selectedTab, setSelectedTab } = useBrainManagementTabs();
|
||||
const { selectedTab, setSelectedTab, brainId } = useBrainManagementTabs();
|
||||
|
||||
if (brainId === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Root
|
||||
className="shadow-md min-h-[50%] dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl overflow-hidden bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4"
|
||||
className="shadow-md min-h-[50%] dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl overflow-hidden bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4 pt-10"
|
||||
defaultValue="settings"
|
||||
>
|
||||
<List className="flex justify-between" aria-label="Manage your brain">
|
||||
@ -31,9 +35,15 @@ export const BrainManagementTabs = (): JSX.Element => {
|
||||
onChange={setSelectedTab}
|
||||
/>
|
||||
</List>
|
||||
<Content value="settings">
|
||||
<p>coming soon</p>
|
||||
</Content>
|
||||
|
||||
<div className="p-20 pt-5">
|
||||
<Content value="settings">
|
||||
<p>coming soon</p>
|
||||
</Content>
|
||||
<Content value="people">
|
||||
<PeopleTab brainId={brainId} />
|
||||
</Content>
|
||||
</div>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,93 @@
|
||||
/* eslint-disable max-lines */
|
||||
"use client";
|
||||
|
||||
import { UUID } from "crypto";
|
||||
import { ImUserPlus } from "react-icons/im";
|
||||
import { MdContentPaste, MdLink } from "react-icons/md";
|
||||
|
||||
import { BrainUsers } from "@/lib/components/BrainUsers/BrainUsers";
|
||||
import { UserToInvite } from "@/lib/components/UserToInvite";
|
||||
import Button from "@/lib/components/ui/Button";
|
||||
import { useShareBrain } from "@/lib/hooks/useShareBrain";
|
||||
|
||||
type ShareBrainModalProps = {
|
||||
brainId: UUID;
|
||||
};
|
||||
|
||||
export const PeopleTab = ({ brainId }: ShareBrainModalProps): JSX.Element => {
|
||||
const {
|
||||
roleAssignations,
|
||||
handleCopyInvitationLink,
|
||||
updateRoleAssignation,
|
||||
removeRoleAssignation,
|
||||
inviteUsers,
|
||||
addNewRoleAssignationRole,
|
||||
sendingInvitation,
|
||||
canAddNewRow,
|
||||
} = useShareBrain(brainId);
|
||||
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
void inviteUsers();
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-row align-center my-5">
|
||||
<div
|
||||
onClick={() => void handleCopyInvitationLink()}
|
||||
className="cursor-pointer flex bg-gray-100 p-0 flex-1 flex-row border-gray-200 dark:border-gray-700 justify-space-between align-center rounded-md border-2"
|
||||
>
|
||||
<div className="px-8 py-3 text-sm disabled:opacity-80 text-center font-medium rounded-md focus:ring ring-primary/10 outline-none flex items-center justify-center gap-2 transition-opacity bg-transparent border-2 border-gray border-l-0 border-t-0 border-b-0 rounded-l-none">
|
||||
<MdLink size="20" color="gray" />
|
||||
</div>
|
||||
<div className="flex flex-row flex-1 items-center justify-center">
|
||||
<span className="color-gray">
|
||||
Click to copy link to share your brain
|
||||
</span>
|
||||
</div>
|
||||
<Button type="button">
|
||||
<MdContentPaste />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-100 h-0.5 my-10 border-gray-200 dark:border-gray-700" />
|
||||
<p className="text-lg font-bold">Add new users</p>
|
||||
|
||||
{roleAssignations.map((roleAssignation, index) => (
|
||||
<UserToInvite
|
||||
key={roleAssignation.id}
|
||||
onChange={updateRoleAssignation(index)}
|
||||
removeCurrentInvitation={removeRoleAssignation(index)}
|
||||
roleAssignation={roleAssignation}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
className="my-5"
|
||||
onClick={addNewRoleAssignationRole}
|
||||
disabled={sendingInvitation || !canAddNewRow}
|
||||
data-testid="add-new-row-role-button"
|
||||
>
|
||||
<ImUserPlus />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mb-3 flex flex-row justify-end">
|
||||
<Button
|
||||
isLoading={sendingInvitation}
|
||||
disabled={roleAssignations.length === 0}
|
||||
type="submit"
|
||||
>
|
||||
Share
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="bg-gray-100 h-0.5 my-10 border-gray-200 dark:border-gray-700" />
|
||||
<p className="text-lg font-bold">Users with access</p>
|
||||
<BrainUsers brainId={brainId} />
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from "./PeopleTab";
|
@ -1 +1,2 @@
|
||||
export * from "./BrainTabTrigger";
|
||||
export * from "./PeopleTab";
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { UUID } from "crypto";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
import { BrainManagementTab } from "../types";
|
||||
@ -7,8 +9,13 @@ export const useBrainManagementTabs = () => {
|
||||
const [selectedTab, setSelectedTab] =
|
||||
useState<BrainManagementTab>("settings");
|
||||
|
||||
const params = useParams();
|
||||
|
||||
const brainId = params?.brainId as UUID | undefined;
|
||||
|
||||
return {
|
||||
selectedTab,
|
||||
setSelectedTab,
|
||||
brainId,
|
||||
};
|
||||
};
|
||||
|
@ -1,3 +1,4 @@
|
||||
export * from "./BrainListItem";
|
||||
export * from "./BrainManagementTabs";
|
||||
export * from "./BrainSearchBar";
|
||||
export * from "./BrainsList";
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { UUID } from "crypto";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
import { BrainManagementTabs } from "./components/BrainManagementTabs/BrainManagementTabs";
|
||||
import { BrainManagementTabs } from "./components";
|
||||
|
||||
const BrainsManagement = (): JSX.Element => {
|
||||
const params = useParams();
|
||||
@ -21,7 +21,7 @@ const BrainsManagement = (): JSX.Element => {
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex flex-col w-full pt-20 px-20">
|
||||
<main className="flex flex-col w-full pt-20 px-20 mb-10">
|
||||
<BrainManagementTabs />
|
||||
</main>
|
||||
);
|
||||
|
@ -6,8 +6,8 @@ import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainConte
|
||||
|
||||
import { RemoveAccessIcon } from "./components/RemoveAccessIcon";
|
||||
import { useBrainUser } from "./hooks/useBrainUser";
|
||||
import { BrainRoleType } from "../../../../../../types";
|
||||
import { availableRoles } from "../../../../types";
|
||||
import { availableRoles } from "../../../NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/types";
|
||||
import { BrainRoleType } from "../../../NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types";
|
||||
|
||||
type BrainUserProps = {
|
||||
email: string;
|
@ -5,7 +5,7 @@ import { useBrainApi } from "@/lib/api/brain/useBrainApi";
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
import { useToast } from "@/lib/hooks";
|
||||
|
||||
import { BrainRoleType } from "../../../../../../../types";
|
||||
import { BrainRoleType } from "../../../../NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types";
|
||||
|
||||
type UseBrainUserProps = {
|
||||
fetchBrainUsers: () => Promise<void>;
|
@ -5,12 +5,11 @@ import { UUID } from "crypto";
|
||||
import { ImUserPlus } from "react-icons/im";
|
||||
import { MdContentPaste, MdShare } from "react-icons/md";
|
||||
|
||||
import { BrainUsers } from "@/lib/components/BrainUsers/BrainUsers";
|
||||
import { UserToInvite } from "@/lib/components/UserToInvite";
|
||||
import Button from "@/lib/components/ui/Button";
|
||||
import { Modal } from "@/lib/components/ui/Modal";
|
||||
|
||||
import { BrainUsers } from "./components/BrainUsers/BrainUsers";
|
||||
import { UserToInvite } from "./components/UserToInvite";
|
||||
import { useShareBrain } from "./hooks/useShareBrain";
|
||||
import { useShareBrain } from "@/lib/hooks/useShareBrain";
|
||||
|
||||
type ShareBrainModalProps = {
|
||||
brainId: UUID;
|
||||
@ -32,13 +31,9 @@ export const ShareBrain = ({
|
||||
sendingInvitation,
|
||||
setIsShareModalOpen,
|
||||
isShareModalOpen,
|
||||
canAddNewRow,
|
||||
} = useShareBrain(brainId);
|
||||
|
||||
const canAddNewRow =
|
||||
roleAssignations.length === 0 ||
|
||||
roleAssignations.filter((invitingUser) => invitingUser.email === "")
|
||||
.length === 0;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
Trigger={
|
||||
|
@ -1,2 +0,0 @@
|
||||
export * from "./BrainUsers/components/BrainUser/BrainUser";
|
||||
export * from "./UserToInvite";
|
@ -5,8 +5,11 @@ import Field from "@/lib/components/ui/Field";
|
||||
import { Select } from "@/lib/components/ui/Select";
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
|
||||
import { BrainRoleAssignation, BrainRoleType } from "../../../types";
|
||||
import { userRoleToAssignableRoles } from "../types";
|
||||
import { userRoleToAssignableRoles } from "./NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/types";
|
||||
import {
|
||||
BrainRoleAssignation,
|
||||
BrainRoleType,
|
||||
} from "./NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types";
|
||||
|
||||
type UserToInviteProps = {
|
||||
onChange: (newRole: BrainRoleAssignation) => void;
|
||||
@ -25,10 +28,6 @@ export const UserToInvite = ({
|
||||
const [email, setEmail] = useState(roleAssignation.email);
|
||||
const { currentBrain } = useBrainContext();
|
||||
|
||||
if (currentBrain === undefined) {
|
||||
throw new Error("Brain is undefined");
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
onChange({
|
||||
...roleAssignation,
|
||||
@ -37,6 +36,10 @@ export const UserToInvite = ({
|
||||
});
|
||||
}, [email, selectedRole]);
|
||||
|
||||
if (currentBrain === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="assignation-row"
|
@ -6,8 +6,8 @@ import { Subscription } from "@/lib/api/brain/brain";
|
||||
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
|
||||
import { useToast } from "@/lib/hooks";
|
||||
|
||||
import { BrainRoleAssignation } from "../../../types";
|
||||
import { generateBrainAssignation } from "../utils/generateBrainAssignation";
|
||||
import { generateBrainAssignation } from "../components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/utils/generateBrainAssignation";
|
||||
import { BrainRoleAssignation } from "../components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const useShareBrain = (brainId: string) => {
|
||||
@ -102,6 +102,10 @@ export const useShareBrain = (brainId: string) => {
|
||||
const addNewRoleAssignationRole = () => {
|
||||
setRoleAssignation([...roleAssignations, generateBrainAssignation()]);
|
||||
};
|
||||
const canAddNewRow =
|
||||
roleAssignations.length === 0 ||
|
||||
roleAssignations.filter((invitingUser) => invitingUser.email === "")
|
||||
.length === 0;
|
||||
|
||||
return {
|
||||
roleAssignations,
|
||||
@ -114,5 +118,6 @@ export const useShareBrain = (brainId: string) => {
|
||||
sendingInvitation,
|
||||
setIsShareModalOpen,
|
||||
isShareModalOpen,
|
||||
canAddNewRow,
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user