feat: add create board modal (#131)

This commit is contained in:
Manuel
2024-02-18 15:44:49 +01:00
committed by GitHub
parent f1aa422614
commit e3e38e7f44
5 changed files with 110 additions and 12 deletions

View File

@@ -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 (
<Button onClick={onClick} loading={isPending}>
<Button
leftSection={<IconCategoryPlus size="1rem" />}
onClick={onClick}
loading={isPending}
>
{t("management.page.board.button.create")}
</Button>
);

View File

@@ -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 (
<>
<Title>{t("title")}</Title>
<CreateBoardButton />
<Group justify="space-between">
<Title mb="md">{t("title")}</Title>
<CreateBoardButton boardNames={boards.map((board) => board.name)} />
</Group>
<Grid>
{boards.map((board) => (
<GridCol span={{ xs: 12, md: 4 }} key={board.id}>
<Card>
<Text fw={500}>{board.name}</Text>
<Text fw="bolder" tt="uppercase">
{board.name}
</Text>
<Text size="sm" my="md" style={{ lineBreak: "anywhere" }}>
<Text
size="sm"
my="md"
c="dimmed"
style={{ lineBreak: "anywhere" }}
>
{JSON.stringify(board)}
</Text>

View File

@@ -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,
});

View File

@@ -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<void>;
}
export const AddBoardModal: ManagedModal<InnerProps> = ({
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 (
<form
onSubmit={form.onSubmit((values) => {
void innerProps.onSuccess(values);
actions.closeModal();
})}
>
<Stack>
<TextInput
label={t("management.page.board.modal.createBoard.field.name.label")}
data-autofocus
{...form.getInputProps("name")}
/>
<Group justify="right">
<Button onClick={actions.closeModal} variant="subtle" color="gray">
{t("common.action.cancel")}
</Button>
<Button disabled={form.isValid()} type="submit" color="teal">
{t("common.action.create")}
</Button>
</Group>
</Stack>
</form>
);
};

View File

@@ -384,6 +384,15 @@ export default {
create: "Create board",
delete: "Delete board",
},
modal: {
createBoard: {
field: {
name: {
label: 'Name'
}
}
}
}
},
},
},