Zammad docker and Link structure updates
This commit is contained in:
parent
2a37297ae1
commit
60b82f6fb4
39 changed files with 94 additions and 36 deletions
|
|
@ -0,0 +1,102 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useState } from "react";
|
||||
import {
|
||||
Grid,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useSWRConfig } from "swr";
|
||||
import { updateTicketMutation } from "@/app/_graphql/updateTicketMutation";
|
||||
|
||||
interface ArticleCreateDialogProps {
|
||||
ticketID: string;
|
||||
open: boolean;
|
||||
closeDialog: () => void;
|
||||
kind: "reply" | "note";
|
||||
}
|
||||
|
||||
export const ArticleCreateDialog: FC<ArticleCreateDialogProps> = ({
|
||||
ticketID,
|
||||
open,
|
||||
closeDialog,
|
||||
kind,
|
||||
}) => {
|
||||
const [body, setBody] = useState("");
|
||||
const backgroundColor = kind === "reply" ? "#1982FC" : "#FFB620";
|
||||
const color = kind === "reply" ? "white" : "black";
|
||||
const { fetcher } = useSWRConfig();
|
||||
const createArticle = async () => {
|
||||
await fetcher({
|
||||
document: updateTicketMutation,
|
||||
variables: {
|
||||
ticketId: `gid://zammad/Ticket/${ticketID}`,
|
||||
input: {
|
||||
article: {
|
||||
body,
|
||||
type: kind === "note" ? "note" : "phone",
|
||||
internal: kind === "note",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
closeDialog();
|
||||
setBody("");
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} maxWidth="sm" fullWidth>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
label={kind === "reply" ? "Write reply" : "Write internal note"}
|
||||
multiline
|
||||
rows={10}
|
||||
fullWidth
|
||||
value={body}
|
||||
onChange={(e: any) => setBody(e.target.value)}
|
||||
/>
|
||||
</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={createArticle}
|
||||
>
|
||||
{kind === "reply" ? "Send Reply" : "Save Note"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import { getTicketQuery } from "@/app/_graphql/getTicketQuery";
|
||||
import {
|
||||
Grid,
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
} from "@mui/material";
|
||||
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
|
||||
import {
|
||||
MainContainer,
|
||||
ChatContainer,
|
||||
MessageList,
|
||||
Message,
|
||||
ConversationHeader,
|
||||
} from "@chatscope/chat-ui-kit-react";
|
||||
import { ArticleCreateDialog } from "./ArticleCreateDialog";
|
||||
|
||||
interface TicketDetailProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const TicketDetail: FC<TicketDetailProps> = ({ id }) => {
|
||||
const { data: ticketData, error: ticketError }: any = useSWR(
|
||||
{
|
||||
document: getTicketQuery,
|
||||
variables: { ticketId: `gid://zammad/Ticket/${id}` },
|
||||
},
|
||||
{ refreshInterval: 100000 }
|
||||
);
|
||||
|
||||
console.log({ ticketData, ticketError });
|
||||
const ticket = ticketData?.ticket;
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [articleKind, setArticleKind] = useState<"reply" | "note">("reply");
|
||||
const closeDialog = () => setDialogOpen(false);
|
||||
|
||||
const shouldRender = ticketData && !ticketError;
|
||||
|
||||
return (
|
||||
shouldRender && (
|
||||
<>
|
||||
<MainContainer>
|
||||
<ChatContainer>
|
||||
<ConversationHeader>
|
||||
<ConversationHeader.Content>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{ fontFamily: "Poppins", fontWeight: 700 }}
|
||||
>
|
||||
{ticket.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ fontFamily: "Roboto", fontWeight: 400 }}
|
||||
>{`Ticket #${ticket.number} (created ${new Date(
|
||||
ticket.createdAt
|
||||
).toLocaleDateString()})`}</Typography>
|
||||
</Box>
|
||||
</ConversationHeader.Content>
|
||||
</ConversationHeader>
|
||||
<MessageList style={{ marginBottom: 80 }}>
|
||||
{ticket.articles.edges.map(({ node: article }: any) => (
|
||||
<Message
|
||||
key={article.id}
|
||||
className={
|
||||
article.internal
|
||||
? "internal-note"
|
||||
: article.sender.name === "Agent"
|
||||
? "outgoing-message"
|
||||
: "incoming-message"
|
||||
}
|
||||
model={{
|
||||
message: article.body.replace(/<div>*<br>*<div>/g, ""),
|
||||
sentTime: article.updated_at,
|
||||
sender: article.from,
|
||||
direction:
|
||||
article.sender === "Agent" ? "outgoing" : "incoming",
|
||||
position: "single",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</MessageList>
|
||||
</ChatContainer>
|
||||
<Box
|
||||
sx={{
|
||||
height: 80,
|
||||
background: "#eeeeee",
|
||||
borderTop: "1px solid #ddd",
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
width: "100%",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
spacing={4}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
alignContent="center"
|
||||
>
|
||||
<Grid item>
|
||||
<Button
|
||||
variant="contained"
|
||||
disableElevation
|
||||
sx={{
|
||||
fontFamily: "Poppins, sans-serif",
|
||||
fontWeight: 700,
|
||||
borderRadius: 2,
|
||||
textTransform: "none",
|
||||
backgroundColor: "#1982FC",
|
||||
padding: "6px 30px",
|
||||
margin: "20px 0px",
|
||||
whiteSpace: "nowrap",
|
||||
py: "10px",
|
||||
mt: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
setArticleKind("reply");
|
||||
setDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
Reply to ticket
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button
|
||||
variant="contained"
|
||||
disableElevation
|
||||
sx={{
|
||||
fontFamily: "Poppins, sans-serif",
|
||||
fontWeight: 700,
|
||||
borderRadius: 2,
|
||||
textTransform: "none",
|
||||
color: "black",
|
||||
backgroundColor: "#FFB620",
|
||||
padding: "6px 30px",
|
||||
margin: "20px 0px",
|
||||
whiteSpace: "nowrap",
|
||||
py: "10px",
|
||||
mt: 2,
|
||||
}}
|
||||
onClick={() => {
|
||||
setArticleKind("note");
|
||||
setDialogOpen(true);
|
||||
}}
|
||||
>
|
||||
Write note to agent
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</MainContainer>
|
||||
<ArticleCreateDialog
|
||||
ticketID={ticket.internalId}
|
||||
open={dialogOpen}
|
||||
closeDialog={closeDialog}
|
||||
kind={articleKind}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
11
apps/link/app/(main)/tickets/[id]/@detail/page.tsx
Normal file
11
apps/link/app/(main)/tickets/[id]/@detail/page.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { TicketDetail } from "./_components/TicketDetail";
|
||||
|
||||
type PageProps = {
|
||||
params: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
export default function Page({ params: { id } }: PageProps) {
|
||||
return <TicketDetail id={id} />;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue