Sidebar and edit updates

This commit is contained in:
Darren Clarke 2023-10-16 09:20:40 +02:00
parent d73b194d1f
commit f13530f043
32 changed files with 3057 additions and 1114 deletions

View file

@ -0,0 +1,139 @@
"use client";
import { FC, useState } from "react";
import {
Grid,
Button,
Dialog,
DialogActions,
DialogContent,
TextField,
Autocomplete
} from "@mui/material";
import { useSWRConfig } from "swr";
import { createTicketMutation } from "app/_graphql/createTicketMutation";
interface TicketCreateDialogProps {
open: boolean;
closeDialog: () => void;
}
export const TicketCreateDialog: FC<TicketCreateDialogProps> = ({
open,
closeDialog,
}) => {
const [kind, setKind] = useState("note");
const [customerID, setCustomerID] = useState("");
const [groupID, setGroupID] = useState("");
const [ownerID, setOwnerID] = useState("");
const [priorityID, setPriorityID] = useState("");
const [stateID, setStateID] = useState("");
const [tags, setTags] = useState([]);
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
const backgroundColor = kind === "note" ? "#FFB620" : "#1982FC";
const color = kind === "note" ? "black" : "white";
const { fetcher } = useSWRConfig();
const ticket = {
customerId: customerID,
groupId: groupID,
ownerId: ownerID,
priorityId: priorityID,
stateId: stateID,
tags,
title,
article: {
body,
type: kind,
internal: kind === "note",
}
};
const createTicket = async () => {
await fetcher({
document: createTicketMutation,
variables: {
input: {
ticket
},
},
});
closeDialog();
setBody("");
};
return (
<Dialog open={open} maxWidth="md" fullWidth>
<DialogContent>
<Grid container direction="column" spacing={2}>
<Grid item>
<TextField
label={"Title"}
fullWidth
value={title}
onChange={(e: any) => setTitle(e.target.value)}
/>
</Grid>
<Grid item>
<Autocomplete
disablePortal
options={[{ label: "Test One", id: 1 }, { label: "Test Two", id: 2 }]}
sx={{ width: 300 }}
onChange={(e: any) => setCustomerID(e.target.value)}
renderInput={(params) => <TextField {...params} label="Customer" />}
/>
</Grid>
<Grid item>
<TextField
label={"Details"}
multiline
rows={10}
fullWidth
value={body}
onChange={(e: any) => setBody(e.target.value)}
/>
</Grid>
</Grid>
</DialogContent>
<DialogActions sx={{ px: 3, pt: 0, pb: 3 }}>
<Grid container justifyContent="space-between">
<Grid item>
<Button
sx={{
backgroundColor: "white",
color: "#666",
fontFamily: "Poppins, sans-serif",
fontWeight: 700,
borderRadius: 2,
textTransform: "none",
}}
onClick={() => {
setBody("");
closeDialog();
}}
>
Cancel
</Button>
</Grid>
<Grid item>
<Button
sx={{
backgroundColor,
color,
fontFamily: "Poppins, sans-serif",
fontWeight: 700,
borderRadius: 2,
textTransform: "none",
px: 3,
}}
onClick={createTicket}
>
{kind === "note" ? "Save Note" : "Send Reply"}
</Button>
</Grid>
</Grid>
</DialogActions>
</Dialog>
);
};

View file

@ -1,12 +1,13 @@
"use client";
import { FC } from "react";
import { FC, useState } from "react";
import { Grid, Box } from "@mui/material";
import { GridColDef } from "@mui/x-data-grid-pro";
import { StyledDataGrid } from "../../../_components/StyledDataGrid";
import { Button } from "../../../../_components/Button";
import { typography } from "../../../../_styles/theme";
import { useRouter } from "next/navigation";
import { TicketCreateDialog } from "./TicketCreateDialog";
interface TicketListProps {
title: string;
@ -14,72 +15,96 @@ interface TicketListProps {
}
export const TicketList: FC<TicketListProps> = ({ title, tickets }) => {
const [dialogOpen, setDialogOpen] = useState(false);
const router = useRouter();
let gridColumns: GridColDef[] = [
{
field: "number",
headerName: "Number",
flex: 0.3,
flex: 1,
},
{
field: "title",
headerName: "Title",
flex: 1.5,
flex: 5,
},
{
field: "customer",
headerName: "Sender",
valueGetter: (params) => params.row?.customer?.fullname,
flex: 0.6,
flex: 2,
},
{
field: "createdAt",
headerName: "Created At",
valueGetter: (params) => new Date(params.row?.createdAt).toLocaleString(),
flex: 1,
},
{
field: "updatedAt",
headerName: "Updated At",
valueGetter: (params) => new Date(params.row?.updatedAt).toLocaleString(),
flex: 1,
},
{
field: "group",
headerName: "Group",
valueGetter: (params) => params.row?.group?.name,
flex: 0.3,
flex: 1,
},
];
console.log({ tickets });
const rowClick = ({ row }) => {
router.push(`/tickets/${row.internalId}`);
};
return (
<Box sx={{ height: "100vh", backgroundColor: "#ddd", p: 3 }}>
<Grid container direction="column">
<Grid
item
container
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Grid item>
<Box
sx={{
backgroundColor: "#ddd",
px: "8px",
pb: "16px",
...typography.h4,
fontSize: 24,
}}
>
{title}
</Box>
<>
<Box sx={{ height: "100vh", backgroundColor: "#ddd", p: 3 }}>
<Grid container direction="column">
<Grid
item
container
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Grid item>
<Box
sx={{
backgroundColor: "#ddd",
px: "8px",
pb: "16px",
...typography.h4,
fontSize: 24,
}}
>
{title}
</Box>
</Grid>
<Grid item>
<Button
href={""}
onClick={() => setDialogOpen(true)}
text="Create"
color="#1982FC"
/>
</Grid>
</Grid>
<Grid item>
<Button href="/tickets/create" text="Create" color="#1982FC" />
<StyledDataGrid
name={title}
columns={gridColumns}
rows={tickets}
onRowClick={rowClick}
/>
</Grid>
</Grid>
<Grid item>
<StyledDataGrid
name={title}
columns={gridColumns}
rows={tickets}
onRowClick={rowClick}
/>
</Grid>
</Grid>
</Box>
</Box>
<TicketCreateDialog
open={dialogOpen}
closeDialog={() => setDialogOpen(false)}
/>
</>
);
};

View file

@ -1,6 +1,6 @@
"use client";
import { FC } from "react";
import { FC, useEffect, useState } from "react";
import useSWR from "swr";
import { TicketList } from "./TicketList";
import { getTicketsByOverviewQuery } from "../../../../_graphql/getTicketsByOverviewQuery";
@ -11,6 +11,8 @@ type ZammadOverviewProps = {
};
export const ZammadOverview: FC<ZammadOverviewProps> = ({ name, id }) => {
const [tickets, setTickets] = useState([]);
const [error, setError] = useState(null);
const { data: ticketData, error: ticketError }: any = useSWR(
{
document: getTicketsByOverviewQuery,
@ -19,24 +21,57 @@ export const ZammadOverview: FC<ZammadOverviewProps> = ({ name, id }) => {
{ refreshInterval: 10000 },
);
const shouldRender = !ticketError && ticketData;
const tickets =
ticketData?.ticketsByOverview?.edges.map((edge: any) => edge.node) || [];
const restFetcher = (url: string) => fetch(url).then((r) => r.json());
const { data: recent } = useSWR("/api/v1/recent_view", restFetcher);
const sortedTickets = tickets.sort((a: any, b: any) => {
if (a.internalId < b.internalId) {
return 1;
}
if (a.internalId > b.internalId) {
return -1;
}
return 0;
});
const sortTickets = (tickets: any) => {
return tickets.sort((a: any, b: any) => {
if (a.internalId < b.internalId) {
return 1;
}
if (a.internalId > b.internalId) {
return -1;
}
return 0;
});
};
return (
<>
{shouldRender && <TicketList title={name} tickets={sortedTickets} />}
{/*ticketError && <div>{ticketError.toString()}</div>*/}
</>
);
useEffect(() => {
if (name != "Recent") {
const edges = ticketData?.ticketsByOverview?.edges;
if (edges) {
const nodes = edges.map((edge: any) => edge.node);
setTickets(sortTickets(nodes));
}
if (ticketError) {
setError(ticketError);
}
}
}, [ticketData, ticketError]);
useEffect(() => {
const fetchRecentTickets = async () => {
if (name === "Recent" && recent) {
let allTickets = [];
for (const rec of recent) {
const res = await fetch(`/api/v1/tickets/${rec.o_id}`);
const tkt = await res.json();
allTickets.push({
...tkt,
internalId: tkt.id,
createdAt: tkt.created_at,
updatedAt: tkt.updated_at,
});
}
setTickets(sortTickets(allTickets));
console.log({ allTickets });
}
};
fetchRecentTickets();
}, [name]);
const shouldRender = tickets && !error;
return shouldRender && <TicketList title={name} tickets={tickets} />;
};