feat: public boards

This commit is contained in:
Henry
2025-01-11 15:22:49 +00:00
parent d98df1d2c6
commit 2df54f03bb
30 changed files with 487 additions and 100 deletions

View File

@@ -1,9 +1,8 @@
import { api } from "~/utils/api";
import Button from "~/components/Button";
import { useBoard } from "~/providers/board";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import Button from "~/components/Button";
import { api } from "~/utils/api";
interface DeleteListConfirmationProps {
listPublicId: string;
@@ -38,6 +37,7 @@ export function DeleteListConfirmation({
showPopup({
header: "Unable to delete list",
message: "Please try again later, or contact customer support.",
icon: "error",
});
},
});

View File

@@ -1,14 +1,16 @@
import { IoFilterOutline } from "react-icons/io5";
import {
HiOutlineUserCircle,
HiOutlineTag,
HiMiniXMark,
} from "react-icons/hi2";
import { useRouter } from "next/router";
import {
HiMiniXMark,
HiOutlineTag,
HiOutlineUserCircle,
} from "react-icons/hi2";
import { IoFilterOutline } from "react-icons/io5";
import type { GetBoardByIdOutput } from "@kan/api/types";
import Button from "~/components/Button";
import CheckboxDropdown from "~/components/CheckboxDropdown";
import { formatToArray } from "~/utils/helpers";
import { useBoard } from "~/providers/board";
const LabelIcon = ({ colourCode }: { colourCode: string | null }) => (
<svg
@@ -25,15 +27,20 @@ const Avatar = ({ name }: { name: string }) => (
<span className="inline-flex h-4 w-4 items-center justify-center rounded-full bg-gray-400 ring-1 ring-light-200 dark:ring-dark-500">
<span className="text-[8px] font-medium leading-none text-white">
{name
?.split(" ")
.split(" ")
.map((namePart) => namePart.charAt(0).toUpperCase())
.join("")}
</span>
</span>
);
const Filters = () => {
const { boardData } = useBoard();
const Filters = ({
position = "right",
boardData,
}: {
position?: "left" | "right";
boardData: GetBoardByIdOutput;
}) => {
const router = useRouter();
const clearFilters = async (e: React.MouseEvent<HTMLButtonElement>) => {
@@ -51,7 +58,7 @@ const Filters = () => {
};
const formattedMembers =
boardData?.workspace?.members?.map((member) => ({
boardData?.workspace?.members.map((member) => ({
key: member.publicId,
value: member.user?.name ?? "",
selected: !!router.query.members?.includes(member.publicId),
@@ -116,21 +123,24 @@ const Filters = () => {
groups={groups}
handleSelect={handleSelect}
menuSpacing="md"
position={position}
>
<Button variant="secondary" iconLeft={<IoFilterOutline />}>
Filter
{numOfFilters > 0 && (
<button
onClick={clearFilters}
className="group absolute -right-[18px] -top-[15px] flex h-5 w-5 items-center justify-center rounded-full border-2 border-light-100 bg-light-1000 text-[8px] font-[700] text-light-600 dark:border-dark-50 dark:bg-dark-1000 dark:text-dark-600 dark:text-dark-600"
>
<span className="group-hover:hidden">{numOfFilters}</span>
<span className="hidden text-light-50 group-hover:inline dark:text-dark-50">
<HiMiniXMark size={12} />
</span>
</button>
)}
</Button>
{numOfFilters > 0 && (
<button
type="button"
onClick={clearFilters}
aria-label="Clear filters"
className="group absolute -right-[8px] -top-[8px] flex h-5 w-5 items-center justify-center rounded-full border-2 border-light-100 bg-light-1000 text-[8px] font-[700] text-light-600 dark:border-dark-50 dark:bg-dark-1000 dark:text-dark-600"
>
<span className="group-hover:hidden">{numOfFilters}</span>
<span className="hidden text-light-50 group-hover:inline dark:text-dark-50">
<HiMiniXMark size={12} />
</span>
</button>
)}
</CheckboxDropdown>
</div>
);

View File

@@ -6,7 +6,7 @@ import {
HiXMark,
} from "react-icons/hi2";
import { type NewCardInput } from "@kan/api/types";
import type { NewCardInput } from "@kan/api/types";
import Button from "~/components/Button";
import CheckboxDropdown from "~/components/CheckboxDropdown";
@@ -58,13 +58,14 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
showPopup({
header: "Unable to create card",
message: "Please try again later, or contact customer support.",
icon: "error",
});
},
});
useEffect(() => {
const titleElement: HTMLElement | null =
document?.querySelector<HTMLElement>("#title");
document.querySelector<HTMLElement>("#title");
if (titleElement) titleElement.focus();
}, []);
@@ -83,7 +84,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
})) ?? [];
const formattedMembers =
boardData?.workspace?.members?.map((member) => ({
boardData?.workspace?.members.map((member) => ({
key: member.publicId,
value: member.user?.name ?? "",
selected: memberPublicIds.includes(member.publicId),
@@ -207,7 +208,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
>
<span className="text-[8px] font-medium leading-none text-white">
{member?.value
?.split(" ")
.split(" ")
.map((namePart) =>
namePart.charAt(0).toUpperCase(),
)

View File

@@ -2,7 +2,7 @@ import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { HiXMark } from "react-icons/hi2";
import { type NewListInput } from "@kan/api/types";
import type { NewListInput } from "@kan/api/types";
import Button from "~/components/Button";
import Input from "~/components/Input";
@@ -42,13 +42,14 @@ export function NewListForm({ boardPublicId }: { boardPublicId: string }) {
showPopup({
header: "Unable to create list",
message: "Please try again later, or contact customer support.",
icon: "error",
});
},
});
useEffect(() => {
const nameElement: HTMLElement | null =
document?.querySelector<HTMLElement>("#list-name");
document.querySelector<HTMLElement>("#list-name");
if (nameElement) nameElement.focus();
}, []);

View File

@@ -60,6 +60,7 @@ export function UpdateBoardSlugForm({
showPopup({
header: "Unable to update board URL",
message: "Please try again later, or contact customer support.",
icon: "error",
});
},
});