Added UI for request

This commit is contained in:
sianida26 2024-02-16 02:09:07 +07:00
parent b86dd2a821
commit 5530b07769
9 changed files with 416 additions and 0 deletions

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}

BIN
bun.lockb

Binary file not shown.

View File

@ -11,6 +11,12 @@ export default async function roleSeed(prisma: PrismaClient) {
description: "Has full access to the system and can manage all features and settings",
isActive: true,
name: "Super Admin"
},
{
code: "reseller-office-365",
description: "Has ability to make request Office 365 links",
isActive: true,
name: "Reseller Office 365"
}
];

View File

@ -0,0 +1,28 @@
import getUserRoles from "@/modules/auth/utils/getUserRoles";
import checkMultiplePermissions from "@/modules/dashboard/services/checkMultiplePermissions";
import checkPermission from "@/modules/dashboard/services/checkPermission";
import RequestTable from "@/modules/resellerOffice365/tables/RequestTable/RequestTable";
import { Card, Stack, Title } from "@mantine/core";
import { notFound } from "next/navigation";
import React from "react";
export default async function RequestLinkPage() {
const permissions = await checkMultiplePermissions({
create: "office-365-link.create",
readAll: "office-365-link.readAll",
read: "office-365-link.read",
update: "office-365-link.update",
delete: "office-365-link.delete",
});
if (!permissions.readAll) notFound();
return (
<Stack>
<Title order={1}>Permohonan Link Office 365</Title>
<Card>
<RequestTable permissions={permissions} tableData={[]} />
</Card>
</Stack>
);
}

View File

@ -0,0 +1,5 @@
const resellerOffice365Config = {
activePeriods: ["1 Month", "1 Year", "2 Years"],
} as const;
export default resellerOffice365Config;

View File

@ -0,0 +1,194 @@
import {
Button,
Divider,
Fieldset,
Flex,
Group,
Modal,
NumberInput,
ScrollArea,
Select,
Stack,
TextInput,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import React, { useState } from "react";
import {
TbAt,
TbCalendarTime,
TbDeviceFloppy,
TbLink,
TbUser,
TbUsers,
} from "react-icons/tb";
import resellerOffice365Config from "../config";
export interface ModalProps {
title: string;
opened: boolean;
readonly: boolean;
onClose?: () => void;
}
interface FormType {
numberOfLinks: number;
details: {
email: string;
activePeriod: (typeof resellerOffice365Config.activePeriods)[number];
endUserQty: number;
}[];
}
export default function RequestModal(props: ModalProps) {
const [isSubmitting, setSubmitting] = useState(false);
const [formState, setFormState] = useState<
"idle" | "submitting" | "waiting"
>("idle");
const closeModal = () => {
props.onClose ? props.onClose() : "";
};
const form = useForm<FormType>({
initialValues: {
numberOfLinks: 1,
details: [
{
email: "",
activePeriod: "2 Years",
endUserQty: 1,
},
],
},
onValuesChange: (values, prev) => {
// Check if numberOfLinks has changed
if (values.numberOfLinks !== prev.numberOfLinks) {
const currentDetails = values.details;
const targetLength = values.numberOfLinks;
// Add new detail objects if numberOfLinks has increased
while (currentDetails.length < targetLength) {
currentDetails.push({
email: "",
activePeriod: "2 Years",
endUserQty: 1,
});
}
// Remove extra detail objects if numberOfLinks has decreased
if (currentDetails.length > targetLength) {
currentDetails.length = targetLength; // Adjusts the array length
}
// Update the form values with the adjusted details array
form.setValues({
...values,
details: currentDetails,
});
}
},
});
const disableChange = formState !== "idle";
const handleSubmit = (values: FormType) => {
const submitableState = ["idle"];
if (!submitableState.includes(formState)) return; //prevent submit
setFormState("submitting");
};
return (
<Modal
size="sm"
opened={props.opened}
title={props.title}
onClose={closeModal}
scrollAreaComponent={ScrollArea.Autosize}
>
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack gap="md">
<NumberInput
label="Please input the number of links you request"
min={1}
max={3}
allowDecimal={false}
clampBehavior="strict"
leftSection={<TbLink />}
disabled={disableChange}
{...form.getInputProps("numberOfLinks")}
/>
<Divider
label="End User Information"
labelPosition="center"
/>
<Stack>
{form.values.details.map((item, i) => (
<Fieldset key={i} legend={`Information ${i + 1}`}>
<TextInput
leftSection={<TbAt />}
label="Email"
disabled={disableChange}
{...form.getInputProps(
`details.${i}.email`
)}
/>
<Flex gap="md">
<Select
data={
resellerOffice365Config.activePeriods
}
label="Active Period"
disabled={disableChange}
leftSection={<TbCalendarTime />}
{...form.getInputProps(
`details.${i}.activePeriod`
)}
/>
<NumberInput
label="End User Quantity"
leftSection={<TbUsers />}
min={1}
max={5}
disabled={disableChange}
allowDecimal={false}
clampBehavior="strict"
{...form.getInputProps(
`details.${i}.endUserQty`
)}
/>
</Flex>
</Fieldset>
))}
</Stack>
{/* Buttons */}
<Flex justify="flex-end" align="center" gap="lg" mt="lg">
<Button
variant="outline"
onClick={closeModal}
disabled={["submitting"].includes(formState)}
>
Close
</Button>
{(!props.readonly || formState === "waiting") && (
<Button
variant="filled"
leftSection={<TbDeviceFloppy size={20} />}
type="submit"
loading={["submitting", "waiting"].includes(
formState
)}
>
Make Request
</Button>
)}
</Flex>
</Stack>
</form>
</Modal>
);
}

View File

@ -0,0 +1,76 @@
"use client";
import DashboardTable from "@/modules/dashboard/components/DashboardTable";
import { Button, Flex, Text } from "@mantine/core";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import React, { ReactNode, useState } from "react";
import { TbPlus } from "react-icons/tb";
import createColumns from "./columns";
import CrudPermissions from "@/modules/dashboard/types/CrudPermissions";
import RequestLink from "../../types/RequestLink";
import RequestModal, { ModalProps } from "../../modals/RequestModal";
interface Props {
permissions: Partial<CrudPermissions>;
tableData: RequestLink[];
}
export default function RequestTable(props: Props) {
// const [modalProps, setModalProps] = useState<ModalProps>({
// opened: false,
// title: "",
// readonly: false,
// });
const [openModal, setOpenModal] = useState(false);
const table = useReactTable({
data: props.tableData,
columns: createColumns({
permissions: props.permissions,
actions: {
detail: (id) => {console.log(id)}
}
}),
getCoreRowModel: getCoreRowModel(),
defaultColumn: {
cell: (props) => <Text>{props.getValue() as ReactNode}</Text>,
},
});
const openFormModall = () => {
// setModalProps({
// opened: true,
// title: "Request new link",
// readonly: false,
// });
// console.log('hai')
setOpenModal(true);
};
const closeModal = () => {
// setModalProps({
// opened: false,
// title: "",
// readonly: false,
// });
setOpenModal(false)
};
return (
<>
<Flex justify="flex-end">
{
<Button
leftSection={<TbPlus />}
onClick={() => openFormModall()}
>
New Link Request
</Button>
}
</Flex>
<DashboardTable table={table} />
<RequestModal opened={openModal} readonly={false} title="Create new Link Request" onClose={closeModal} />
</>
);
}

View File

@ -0,0 +1,86 @@
import { createColumnHelper } from "@tanstack/react-table";
import { Badge, Flex } from "@mantine/core";
import { TbEye, TbPencil, TbTrash } from "react-icons/tb";
import CrudPermissions from "@/modules/dashboard/types/CrudPermissions";
import createActionButtons from "@/modules/dashboard/utils/createActionButton";
export interface RequestLinkRow {
id: string;
requestDate: Date,
userCount: number,
status: string
}
interface ColumnOptions {
permissions: Partial<CrudPermissions>;
actions: {
detail: (id: string) => void;
// edit: (id: string) => void;
// delete: (id: string) => void;
};
}
const createColumns = (options: ColumnOptions) => {
const columnHelper = createColumnHelper<RequestLinkRow>();
const columns = [
columnHelper.accessor("id", {
id: "sequence",
header: "#",
cell: (props) => props.row.index + 1,
}),
columnHelper.accessor("requestDate", {
header: "Request Date",
}),
columnHelper.accessor("userCount", {
header: "User Count",
}),
columnHelper.accessor("status", {
header: "Status",
}),
columnHelper.display({
id: "Actions",
header: "Actions",
cell: (props) => (
<Flex gap="xs">
{createActionButtons([
{
label: "Detail",
permission: options.permissions.read,
action: () =>
options.actions.detail(props.row.original.id),
color: "green",
icon: <TbEye />,
},
{
label: "Edit",
permission: options.permissions.update,
// action: () =>
// options.actions.edit(props.row.original.id),
color: "yellow",
icon: <TbPencil />,
},
{
label: "Delete",
permission: options.permissions.delete,
// action: () =>
// options.actions.delete(
// props.row.original.id
// ),
color: "red",
icon: <TbTrash />,
},
])}
</Flex>
),
}),
];
return columns;
};
export default createColumns;

View File

@ -0,0 +1,6 @@
export default interface RequestLink {
id: string;
requestDate: Date,
userCount: number,
status: string
}