refactor: move modals to seperate package (#1135)

* refactor: move modals to seperate package

* fix: format issue

* fix: lint issues

* fix: format issue

* fix: only used as type
This commit is contained in:
Meier Lukas
2024-09-16 19:53:37 +02:00
committed by GitHub
parent 3ef478c53a
commit 6738296830
44 changed files with 1692 additions and 1389 deletions

View File

@@ -0,0 +1,2 @@
export { InviteCopyModal } from "./invite-copy-modal";
export { InviteCreateModal } from "./invite-create-modal";

View File

@@ -0,0 +1,57 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Button, CopyButton, Mark, Stack, Text } from "@mantine/core";
import type { RouterOutputs } from "@homarr/api";
import { createModal } from "@homarr/modals";
import { useScopedI18n } from "@homarr/translation/client";
export const InviteCopyModal = createModal<RouterOutputs["invite"]["createInvite"]>(({ actions, innerProps }) => {
const t = useScopedI18n("management.page.user.invite");
const inviteUrl = useInviteUrl(innerProps);
return (
<Stack>
<Text>{t("action.copy.description")}</Text>
{/* TODO: When next-international v2 is released the descriptions bold element can be implemented, see https://github.com/QuiiBz/next-international/pull/361 for progress */}
<Link href={createPath(innerProps)}>{t("action.copy.link")}</Link>
<Stack gap="xs">
<Text fw="bold">{t("field.id.label")}:</Text>
<Mark style={{ borderRadius: 4 }} color="gray" px={5}>
{innerProps.id}
</Mark>
<Text fw="bold">{t("field.token.label")}:</Text>
<Mark style={{ borderRadius: 4 }} color="gray" px={5}>
{innerProps.token}
</Mark>
</Stack>
<CopyButton value={inviteUrl}>
{({ copy }) => (
<Button
onClick={() => {
copy();
actions.closeModal();
}}
variant="default"
fullWidth
>
{t("action.copy.button")}
</Button>
)}
</CopyButton>
</Stack>
);
}).withOptions({
defaultTitle(t) {
return t("management.page.user.invite.action.copy.title");
},
});
const createPath = ({ id, token }: RouterOutputs["invite"]["createInvite"]) => `/auth/invite/${id}?token=${token}`;
const useInviteUrl = ({ id, token }: RouterOutputs["invite"]["createInvite"]) => {
const pathname = usePathname();
return window.location.href.replace(pathname, createPath({ id, token }));
};

View File

@@ -0,0 +1,77 @@
import React from "react";
import { Button, Group, Stack, Text } from "@mantine/core";
import { DateTimePicker } from "@mantine/dates";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { clientApi } from "@homarr/api/client";
import { useForm } from "@homarr/form";
import { createModal, useModalAction } from "@homarr/modals";
import { useI18n, useScopedI18n } from "@homarr/translation/client";
import { InviteCopyModal } from "./invite-copy-modal";
dayjs.extend(relativeTime);
interface FormType {
expirationDate: Date;
}
export const InviteCreateModal = createModal<void>(({ actions }) => {
const tInvite = useScopedI18n("management.page.user.invite");
const t = useI18n();
const { openModal } = useModalAction(InviteCopyModal);
const utils = clientApi.useUtils();
const { mutate, isPending } = clientApi.invite.createInvite.useMutation();
const minDate = dayjs().add(1, "hour").toDate();
const maxDate = dayjs().add(6, "months").toDate();
const form = useForm<FormType>({
initialValues: {
expirationDate: dayjs().add(4, "hours").toDate(),
},
});
const handleSubmit = (values: FormType) => {
mutate(values, {
onSuccess: (result) => {
void utils.invite.getAll.invalidate();
actions.closeModal();
openModal(result);
},
});
};
return (
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack>
<Text>{tInvite("action.new.description")}</Text>
<DateTimePicker
popoverProps={{ withinPortal: true }}
minDate={minDate}
maxDate={maxDate}
withAsterisk
valueFormat="DD MMM YYYY HH:mm"
label={tInvite("field.expirationDate.label")}
variant="filled"
{...form.getInputProps("expirationDate")}
/>
<Group justify="end">
<Button onClick={actions.closeModal} variant="subtle" color="gray">
{t("common.action.cancel")}
</Button>
<Button type="submit" loading={isPending} color="teal">
{t("common.action.create")}
</Button>
</Group>
</Stack>
</form>
);
}).withOptions({
defaultTitle(t) {
return t("management.page.user.invite.action.new.title");
},
});