Added UI for request
This commit is contained in:
parent
b86dd2a821
commit
5530b07769
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal 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}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
28
src/app/dashboard/reseller-office-365/request/page.tsx
Normal file
28
src/app/dashboard/reseller-office-365/request/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
5
src/modules/resellerOffice365/config.ts
Normal file
5
src/modules/resellerOffice365/config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const resellerOffice365Config = {
|
||||
activePeriods: ["1 Month", "1 Year", "2 Years"],
|
||||
} as const;
|
||||
|
||||
export default resellerOffice365Config;
|
||||
194
src/modules/resellerOffice365/modals/RequestModal.tsx
Normal file
194
src/modules/resellerOffice365/modals/RequestModal.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
6
src/modules/resellerOffice365/types/RequestLink.d.ts
vendored
Normal file
6
src/modules/resellerOffice365/types/RequestLink.d.ts
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export default interface RequestLink {
|
||||
id: string;
|
||||
requestDate: Date,
|
||||
userCount: number,
|
||||
status: string
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user