From e3e38e7f4496989a761657d9e79c317e26738c46 Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Sun, 18 Feb 2024 15:44:49 +0100 Subject: [PATCH] feat: add create board modal (#131) --- .../_components/create-board-button.tsx | 33 +++++++++-- .../src/app/[locale]/manage/boards/page.tsx | 20 +++++-- apps/nextjs/src/app/[locale]/modals.tsx | 2 + .../manage/boards/add-board-modal.tsx | 58 +++++++++++++++++++ packages/translation/src/lang/en.ts | 9 +++ 5 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 apps/nextjs/src/components/manage/boards/add-board-modal.tsx diff --git a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx index 339ae07d8..71c373cab 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx @@ -4,24 +4,45 @@ import React from "react"; import { clientApi } from "@homarr/api/client"; import { useI18n } from "@homarr/translation/client"; -import { Button } from "@homarr/ui"; +import { Button, IconCategoryPlus } from "@homarr/ui"; +import { modalEvents } from "~/app/[locale]/modals"; import { revalidatePathAction } from "~/app/revalidatePathAction"; -export const CreateBoardButton = () => { +interface CreateBoardButtonProps { + boardNames: string[]; +} + +export const CreateBoardButton = ({ boardNames }: CreateBoardButtonProps) => { const t = useI18n(); + const { mutateAsync, isPending } = clientApi.board.create.useMutation({ onSettled: async () => { await revalidatePathAction("/manage/boards"); }, }); - const onClick = React.useCallback(async () => { - await mutateAsync({ name: "default" }); - }, [mutateAsync]); + const onClick = React.useCallback(() => { + modalEvents.openManagedModal({ + modal: "addBoardModal", + title: t("management.page.board.button.create"), + innerProps: { + onSuccess: async (values) => { + await mutateAsync({ + name: values.name, + }); + }, + boardNames, + }, + }); + }, [mutateAsync, t, boardNames]); return ( - ); diff --git a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx index 2437439af..4d1c68402 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx @@ -1,7 +1,7 @@ import React from "react"; import { getScopedI18n } from "@homarr/translation/server"; -import { Card, Grid, GridCol, Text, Title } from "@homarr/ui"; +import { Card, Grid, GridCol, Group, Text, Title } from "@homarr/ui"; import { api } from "~/trpc/server"; import { CreateBoardButton } from "./_components/create-board-button"; @@ -14,17 +14,25 @@ export default async function ManageBoardsPage() { return ( <> - {t("title")} - - + + {t("title")} + board.name)} /> + {boards.map((board) => ( - {board.name} + + {board.name} + - + {JSON.stringify(board)} diff --git a/apps/nextjs/src/app/[locale]/modals.tsx b/apps/nextjs/src/app/[locale]/modals.tsx index 7ac3e15a5..f3e700b7c 100644 --- a/apps/nextjs/src/app/[locale]/modals.tsx +++ b/apps/nextjs/src/app/[locale]/modals.tsx @@ -6,9 +6,11 @@ import { WidgetEditModal } from "@homarr/widgets"; import { ItemSelectModal } from "~/components/board/items/item-select-modal"; import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal"; +import { AddBoardModal } from "~/components/manage/boards/add-board-modal"; export const [ModalsManager, modalEvents] = createModalManager({ categoryEditModal: CategoryEditModal, widgetEditModal: WidgetEditModal, itemSelectModal: ItemSelectModal, + addBoardModal: AddBoardModal, }); diff --git a/apps/nextjs/src/components/manage/boards/add-board-modal.tsx b/apps/nextjs/src/components/manage/boards/add-board-modal.tsx new file mode 100644 index 000000000..86940cf9f --- /dev/null +++ b/apps/nextjs/src/components/manage/boards/add-board-modal.tsx @@ -0,0 +1,58 @@ +import type { ManagedModal } from "mantine-modal-manager"; +import { boardSchemas } from "node_modules/@homarr/validation/src/board"; + +import { useForm, zodResolver } from "@homarr/form"; +import { useI18n } from "@homarr/translation/client"; +import { Button, Group, Stack, TextInput } from "@homarr/ui"; +import { z } from "@homarr/validation"; + +interface InnerProps { + boardNames: string[]; + onSuccess: ({ name }: { name: string }) => Promise; +} + +export const AddBoardModal: ManagedModal = ({ + actions, + innerProps, +}) => { + const t = useI18n(); + const form = useForm({ + initialValues: { + name: "", + }, + validate: zodResolver( + z.object({ + name: boardSchemas.byName.shape.name.refine( + (value) => !innerProps.boardNames.includes(value), + ), + }), + ), + validateInputOnBlur: true, + validateInputOnChange: true, + }); + + return ( +
{ + void innerProps.onSuccess(values); + actions.closeModal(); + })} + > + + + + + + + +
+ ); +}; diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts index 9ed6c20e9..880781b54 100644 --- a/packages/translation/src/lang/en.ts +++ b/packages/translation/src/lang/en.ts @@ -384,6 +384,15 @@ export default { create: "Create board", delete: "Delete board", }, + modal: { + createBoard: { + field: { + name: { + label: 'Name' + } + } + } + } }, }, },