drawDB/src/pages/BugReport.jsx
2024-02-28 16:53:59 +02:00

303 lines
9.3 KiB
JavaScript

import { useEffect, useState, useCallback, useRef } from "react";
import logo_light from "../assets/logo_light_160.png";
import logo_dark from "../assets/logo_dark_160.png";
import { Banner, Button, Input, Upload, Toast, Spin } from "@douyinfe/semi-ui";
import {
IconSun,
IconMoon,
IconGithubLogo,
IconPaperclip,
} from "@douyinfe/semi-icons";
import RichEditor from "../components/RichEditor";
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { editorConfig } from "../data/editor_config";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { $generateHtmlFromNodes } from "@lexical/html";
import { CLEAR_EDITOR_COMMAND } from "lexical";
import axios from "axios";
import { Link } from "react-router-dom";
function Form({ theme }) {
const [editor] = useLexicalComposerContext();
const [data, setData] = useState({
title: "",
attachments: [],
});
const [loading, setLoading] = useState(false);
const uploadRef = useRef();
const resetForm = () => {
setData({
title: "",
attachments: [],
});
setLoading(false);
if (uploadRef.current) {
uploadRef.current.clear();
}
};
const onFileChange = (fileList) => {
const attachments = [];
const processFile = (index) => {
const reader = new FileReader();
reader.onload = (event) => {
const dataUri = event.target.result;
attachments.push({ path: dataUri, filename: fileList[index].name });
};
reader.readAsDataURL(fileList[index].fileInstance);
};
fileList.forEach((_, i) => processFile(i));
setData((prev) => ({
...prev,
attachments: attachments,
}));
};
const onSubmit = useCallback(() => {
setLoading(true);
editor.update(() => {
const sendMail = async () => {
await axios
.post(`${import.meta.env.VITE_API_BACKEND_URL}/send_email`, {
subject: `[BUG REPORT]: ${data.title}`,
message: $generateHtmlFromNodes(editor),
attachments: data.attachments,
})
.then(() => {
Toast.success("Bug reported!");
editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
resetForm();
})
.catch(() => {
Toast.error("Oops! Something went wrong.");
setLoading(false);
});
};
sendMail();
});
}, [editor, data]);
return (
<div className="p-5 mt-6 card-theme rounded-md">
<Input
placeholder="Title"
value={data.title}
onChange={(v) => setData((prev) => ({ ...prev, title: v }))}
/>
<RichEditor theme={theme} placeholder={"Describe the bug"} />
<Upload
action="#"
ref={uploadRef}
onChange={(info) => onFileChange(info.fileList)}
beforeUpload={({ file }) => {
return {
autoRemove: false,
fileInstance: file.fileInstance,
status: "success",
shouldUpload: false,
};
}}
draggable={true}
dragMainText="Click to upload the file or drag and drop the file here"
dragSubText="Upload up to 3 images"
accept="image/*"
limit={3}
></Upload>
<div className="pt-4 flex justify-between items-center">
<div className="text-sm opacity-80">
<i className="fa-brands fa-markdown me-1"></i>Styling with markdown is
supported
</div>
<div className="flex items-center">
<Button
onClick={onSubmit}
style={{ padding: "16px 24px" }}
disabled={loading || data.title === "" || !data.title}
>
Submit
</Button>
<div className={loading ? "ms-2" : "hidden"}>
<Spin />
</div>
</div>
</div>
</div>
);
}
export default function BugReport() {
const [theme, setTheme] = useState("");
useEffect(() => {
const t = localStorage.getItem("theme");
setTheme(t);
if (t === "dark") {
const body = document.body;
if (body.hasAttribute("theme-mode")) {
body.setAttribute("theme-mode", "dark");
}
} else {
const body = document.body;
if (body.hasAttribute("theme-mode")) {
body.setAttribute("theme-mode", "light");
}
}
document.title = "Report a bug | drawDB";
document.body.setAttribute("class", "theme");
}, [setTheme]);
const changeTheme = () => {
const body = document.body;
const t = body.getAttribute("theme-mode");
if (t === "dark") {
if (body.hasAttribute("theme-mode")) {
body.setAttribute("theme-mode", "light");
setTheme("light");
}
} else {
if (body.hasAttribute("theme-mode")) {
body.setAttribute("theme-mode", "dark");
setTheme("dark");
}
}
};
return (
<>
<div className="sm:py-3 py-5 px-20 sm:px-6 flex justify-between items-center">
<div className="flex items-center justify-start">
<Link to="/">
<img
src={theme === "dark" ? logo_dark : logo_light}
alt="logo"
className="me-2 sm:h-[28px] md:h-[46px] h-[48px]"
/>
</Link>
<div className="ms-4 sm:text-sm xl:text-lg font-semibold">
Report a bug
</div>
</div>
<div className="flex items-center">
<Button
icon={
theme === "dark" ? (
<IconSun size="extra-large" />
) : (
<IconMoon size="extra-large" />
)
}
theme="borderless"
onClick={changeTheme}
></Button>
</div>
</div>
<hr
className={`${
theme === "dark" ? "border-zinc-700" : "border-zinc-300"
} my-1`}
/>
<div className="grid grid-cols-12 gap-8 my-6 mx-20 sm:mx-6">
<div className="col-span-4 md:col-span-12 lg:col-span-4">
<div className="card-theme p-6 rounded-md">
<div className="flex items-center">
<IconPaperclip />
<div className="font-bold ms-1">Describe the bug </div>
</div>
<div className="text-sm mt-1">
Please provide a clear and concise description of what the bug is.
</div>
<div className="flex items-center mt-3">
<IconPaperclip />
<div className="font-bold ms-1">Steps to reproduce the bug </div>
</div>
<div className="text-sm mt-1">
Please provide the steps of how to reproduce the bug.
</div>
<div className="flex items-center mt-3">
<IconPaperclip />
<div className="font-bold ms-1">Expected behaviour</div>
</div>
<div className="text-sm mt-1">
Tell us what you expected to see vs what you saw.
</div>
<div className="flex items-center mt-3">
<IconPaperclip />
<div className="font-bold ms-1">Your browser and device</div>
</div>
<div className="text-sm mt-1">
What web browser and device did you encounter the bug on.
</div>
<div className="flex items-center mt-3">
<IconPaperclip />
<div className="font-bold ms-1">Screenshots</div>
</div>
<div className="text-sm mt-1">
Add any relevant images if possible.
</div>
<div className="flex items-center justify-center my-2">
<hr
className={`${
theme === "dark" ? "border-zinc-700" : "border-zinc-300"
} flex-grow`}
/>
<div className="text-sm font-semibold m-2">Alternatively</div>
<hr
className={`${
theme === "dark" ? "border-zinc-700" : "border-zinc-300"
} flex-grow`}
/>
</div>
<Button
block
icon={<IconGithubLogo />}
style={{ backgroundColor: "#239144", color: "white" }}
onClick={() => {
window.open(
"https://github.com/drawdb-io/drawdb-issues/issues",
"_self"
);
}}
>
Add an issue
</Button>
</div>
</div>
<div className="col-span-8 md:col-span-12 lg:col-span-8">
<Banner
fullMode={false}
type="info"
icon={null}
closeIcon={null}
description={
<div>
We value your feedback! If you&apos;ve encountered a bug or
issue while using our platform, please help us improve by
reporting it. Your input is invaluable in making our service
better.
</div>
}
/>
<LexicalComposer initialConfig={editorConfig}>
<Form theme={theme} />
</LexicalComposer>
</div>
</div>
<hr
className={`${
theme === "dark" ? "border-zinc-700" : "border-zinc-300"
} my-1`}
/>
<div className="text-center text-sm py-3">
&copy; 2024 <strong>drawDB</strong> - All right reserved.
</div>
</>
);
}