Shareable Brains - 2 (#601)

* feat(brains): add fetching indicator

* feat: add brain share modal
This commit is contained in:
Mamadou DICKO 2023-07-11 14:45:18 +02:00 committed by GitHub
parent 22ea64e67c
commit 8749ffd0bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 93 additions and 20 deletions

View File

@ -1,17 +1,17 @@
import { useState } from "react";
import { FaBrain } from "react-icons/fa";
import { MdCheck, MdDelete } from "react-icons/md";
import { MdCheck } from "react-icons/md";
import Button from "@/lib/components/ui/Button";
import Field from "@/lib/components/ui/Field";
import Popover from "@/lib/components/ui/Popover";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { AddBrainModal } from "./AddBrainModal";
import { AddBrainModal } from "./components/AddBrainModal";
import { BrainActions } from "./components/BrainActions/BrainActions";
export const BrainsDropDown = (): JSX.Element => {
const [searchQuery, setSearchQuery] = useState("");
const { allBrains, setActiveBrain, currentBrain, deleteBrain } =
const { allBrains, isFetchingBrains, setActiveBrain, currentBrain } =
useBrainContext();
return (
@ -41,6 +41,11 @@ export const BrainsDropDown = (): JSX.Element => {
/>
<div className="overflow-auto scrollbar flex flex-col h-48 mt-5">
{/* List of brains */}
{isFetchingBrains && (
<div className="flex items-center justify-center h-full">
<p className="text-gray-500">Loading...</p>
</div>
)}
{allBrains.map((brain) => {
if (brain.name.includes(searchQuery)) {
return (
@ -68,13 +73,7 @@ export const BrainsDropDown = (): JSX.Element => {
</span>
<span className="flex-1">{brain.name}</span>
</button>
<Button
className="group-hover:visible invisible absolute right-0 hover:text-red-500 transition-[colors,opacity]"
onClick={() => void deleteBrain(brain.id)}
variant={"tertiary"}
>
<MdDelete className="text-xl" />
</Button>
<BrainActions brainId={brain.id} />
</div>
);
}

View File

@ -6,7 +6,7 @@ import Field from "@/lib/components/ui/Field";
import Modal from "@/lib/components/ui/Modal";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
const AddBrainModal = (): JSX.Element => {
export const AddBrainModal = (): JSX.Element => {
const [newBrainName, setNewBrainName] = useState("");
const [isPending, setIsPending] = useState(false);
@ -56,5 +56,3 @@ const AddBrainModal = (): JSX.Element => {
</Modal>
);
};
export { AddBrainModal };

View File

@ -0,0 +1,28 @@
import { UUID } from "crypto";
import { MdDelete } from "react-icons/md";
import Button from "@/lib/components/ui/Button";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { ShareBrain } from "./ShareBrain";
type BrainActionsProps = {
brainId: UUID;
};
export const BrainActions = ({ brainId }: BrainActionsProps): JSX.Element => {
const { deleteBrain } = useBrainContext();
return (
<div className="absolute right-0 flex flex-row">
<ShareBrain brainId={brainId} />
<Button
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
onClick={() => void deleteBrain(brainId)}
variant={"tertiary"}
>
<MdDelete className="text-xl" />
</Button>
</div>
);
};

View File

@ -0,0 +1,47 @@
import { UUID } from "crypto";
import { MdContentPaste, MdShare } from "react-icons/md";
import Button from "@/lib/components/ui/Button";
import Modal from "@/lib/components/ui/Modal";
import { useToast } from "@/lib/hooks";
type ShareBrainModalProps = {
brainId: UUID;
};
export const ShareBrain = ({ brainId }: ShareBrainModalProps): JSX.Element => {
const { publish } = useToast();
const baseUrl = window.location.origin;
const brainShareLink = `${baseUrl}/brain_subscription_invitation=${brainId}`;
const handleCopyInvitationLink = async () => {
await navigator.clipboard.writeText(brainShareLink);
publish({
variant: "success",
text: "Copied to clipboard",
});
};
return (
<Modal
Trigger={
<Button
className="group-hover:visible invisible hover:text-red-500 transition-[colors,opacity] p-1"
onClick={() => void 0}
variant={"tertiary"}
>
<MdShare className="text-xl" />
</Button>
}
title="Share brain"
>
<div className="flex flex-row align-center my-5">
<p>{brainShareLink}</p>
<Button onClick={() => void handleCopyInvitationLink()}>
<MdContentPaste />
</Button>
</div>
</Modal>
);
};

View File

@ -0,0 +1,2 @@
export * from "./AddBrainModal";
export * from "./BrainActions";

View File

@ -1,4 +1 @@
import { AddBrainModal } from "./AddBrainModal";
import { BrainsDropDown } from "./BrainsDropDown";
export { BrainsDropDown, AddBrainModal };
export * from "./BrainsDropDown";

View File

@ -12,6 +12,7 @@ interface ModalProps {
children?: ReactNode;
Trigger: ReactNode;
CloseTrigger?: ReactNode;
opened?: boolean;
}
const Modal = ({
@ -20,8 +21,9 @@ const Modal = ({
children,
Trigger,
CloseTrigger,
opened = false,
}: ModalProps): JSX.Element => {
const [open, setOpen] = useState(false);
const [open, setOpen] = useState(opened);
return (
<Dialog.Root onOpenChange={setOpen}>

View File

@ -103,6 +103,5 @@ export const useBrainProvider = () => {
setDefaultBrain,
fetchAndSetActiveBrain,
isFetchingBrains,
setIsFetchingBrains,
};
};