feat: set board visibility
This commit is contained in:
@@ -5,9 +5,9 @@ const LoadingSpinner = ({ size = "md" }: { size?: "sm" | "md" | "lg" }) => {
|
||||
<svg
|
||||
className={twMerge(
|
||||
"animate-spin",
|
||||
size === "sm" && "h-4 w-4",
|
||||
size === "md" && "h-5 w-5",
|
||||
size === "lg" && "h-6 w-6",
|
||||
size === "sm" && "h-3 w-3",
|
||||
size === "md" && "h-4 w-4",
|
||||
size === "lg" && "h-5 w-5",
|
||||
)}
|
||||
viewBox="0 0 100 100"
|
||||
>
|
||||
|
||||
61
apps/web/src/views/board/components/VisibilityButton.tsx
Normal file
61
apps/web/src/views/board/components/VisibilityButton.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { HiOutlineEye, HiOutlineEyeSlash } from "react-icons/hi2";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { useBoard } from "~/providers/board";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
const VisibilityButton = ({
|
||||
visibility,
|
||||
boardPublicId,
|
||||
}: {
|
||||
visibility: "public" | "private";
|
||||
boardPublicId: string;
|
||||
}) => {
|
||||
const { refetchBoard } = useBoard();
|
||||
const { showPopup } = usePopup();
|
||||
const [stateVisibility, setStateVisibility] = useState<"public" | "private">(
|
||||
visibility,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setStateVisibility(visibility);
|
||||
}, [visibility]);
|
||||
|
||||
const isPublic = stateVisibility === "public";
|
||||
|
||||
const updateBoardVisibility = api.board.update.useMutation({
|
||||
onSuccess: async () => {
|
||||
await refetchBoard();
|
||||
setStateVisibility(isPublic ? "private" : "public");
|
||||
},
|
||||
onError: () => {
|
||||
showPopup({
|
||||
header: "Unable to update board visibility",
|
||||
message: "Please try again later, or contact customer support.",
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleUpdateBoardVisibility = () => {
|
||||
updateBoardVisibility.mutate({
|
||||
visibility: isPublic ? "private" : "public",
|
||||
boardPublicId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={handleUpdateBoardVisibility}
|
||||
iconLeft={isPublic ? <HiOutlineEye /> : <HiOutlineEyeSlash />}
|
||||
isLoading={updateBoardVisibility.isPending}
|
||||
>
|
||||
{isPublic ? "Public" : "Private"}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default VisibilityButton;
|
||||
@@ -9,6 +9,7 @@ import { HiOutlinePlusSmall } from "react-icons/hi2";
|
||||
|
||||
import type { UpdateBoardInput } from "@kan/api/types";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import Modal from "~/components/modal";
|
||||
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
|
||||
import { PageHead } from "~/components/PageHead";
|
||||
@@ -27,6 +28,7 @@ import List from "./components/List";
|
||||
import { NewCardForm } from "./components/NewCardForm";
|
||||
import { NewListForm } from "./components/NewListForm";
|
||||
import { UpdateBoardSlugForm } from "./components/UpdateBoardSlugForm";
|
||||
import VisibilityButton from "./components/VisibilityButton";
|
||||
|
||||
type PublicListId = string;
|
||||
|
||||
@@ -161,18 +163,22 @@ export default function BoardPage() {
|
||||
)}
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<VisibilityButton
|
||||
visibility={boardData.visibility}
|
||||
boardPublicId={boardId}
|
||||
/>
|
||||
<Filters boardData={boardData} position="left" />
|
||||
<button
|
||||
type="button"
|
||||
className="mr-2 inline-flex items-center gap-x-1.5 rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 dark:bg-dark-1000 dark:text-dark-50"
|
||||
<Button
|
||||
iconLeft={
|
||||
<HiOutlinePlusSmall
|
||||
className="-mr-0.5 h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
}
|
||||
onClick={() => openNewListForm(boardId)}
|
||||
>
|
||||
<HiOutlinePlusSmall
|
||||
className="-mr-0.5 h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
New list
|
||||
</button>
|
||||
</Button>
|
||||
<BoardDropdown />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -188,6 +188,7 @@ export const boardRouter = createTRPCRouter({
|
||||
.max(60)
|
||||
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/)
|
||||
.optional(),
|
||||
visibility: z.enum(["public", "private"]).optional(),
|
||||
}),
|
||||
)
|
||||
.output(z.custom<Awaited<ReturnType<typeof boardRepo.update>>>())
|
||||
@@ -196,6 +197,7 @@ export const boardRouter = createTRPCRouter({
|
||||
name: input.name,
|
||||
slug: input.slug,
|
||||
boardPublicId: input.boardPublicId,
|
||||
visibility: input.visibility,
|
||||
});
|
||||
|
||||
if (!result)
|
||||
|
||||
@@ -31,6 +31,7 @@ export const getByPublicId = async (
|
||||
publicId,
|
||||
name,
|
||||
slug,
|
||||
visibility,
|
||||
workspace (
|
||||
publicId,
|
||||
members:workspace_members (
|
||||
@@ -222,12 +223,18 @@ export const update = async (
|
||||
boardInput: {
|
||||
name: string | undefined;
|
||||
slug: string | undefined;
|
||||
visibility: "public" | "private" | undefined;
|
||||
boardPublicId: string;
|
||||
},
|
||||
) => {
|
||||
const { data } = await db
|
||||
.from("board")
|
||||
.update({ name: boardInput.name, slug: boardInput.slug })
|
||||
.update({
|
||||
name: boardInput.name,
|
||||
slug: boardInput.slug,
|
||||
visibility: boardInput.visibility,
|
||||
updatedAt: new Date().toISOString(),
|
||||
})
|
||||
.eq("publicId", boardInput.boardPublicId)
|
||||
.select(`publicId, name`)
|
||||
.limit(1)
|
||||
|
||||
Reference in New Issue
Block a user