drawDB/src/pages/survey.jsx

335 lines
9.9 KiB
React
Raw Normal View History

2023-10-13 04:17:23 +08:00
import React, { useEffect, useState, useCallback, useMemo } from "react";
import logo_light from "../assets/logo_light_46.png";
import logo_dark from "../assets/logo_dark_46.png";
import {
Banner,
Button,
Toast,
Spin,
Slider,
Radio,
RadioGroup,
Select,
TextArea,
} from "@douyinfe/semi-ui";
import { IconSun, IconMoon } from "@douyinfe/semi-icons";
import RichEditor from "../components/RichEditor";
2023-10-13 04:17:23 +08:00
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";
function SurveyForm({ theme }) {
const [editor] = useLexicalComposerContext();
const questions = useMemo(
() => ({
satisfaction: "How satisfied are you with drawDB?",
ease: "How easy was it to get started with drawDB?",
wouldRecommend: "How likely are you to recommend drawDB?",
hadDifficulty:
"Did you encounter any difficulties when navigating drawDB?",
difficulty: "What were the difficulties you faced?",
triedOtherApps: "Have you tried apps like drawDB?",
comparison: "How did you find drawDB as compared to other apps?",
occupation: "What is your occupation?",
}),
[]
);
const [form, setForm] = useState({
satisfaction: 5,
ease: 5,
wouldRecommend: 5,
hadDifficulty: "",
difficulty: "",
triedOtherApps: "",
comparison: "",
occupation: "",
});
const [loading, setLoading] = useState(false);
const resetForm = () => {
2023-10-14 21:43:22 +08:00
setForm({
satisfaction: 5,
ease: 5,
wouldRecommend: 5,
hadDifficulty: "",
difficulty: "",
triedOtherApps: "",
comparison: "",
occupation: "",
});
2023-10-13 04:17:23 +08:00
setLoading(false);
};
const onSubmit = useCallback(
(e) => {
setLoading(true);
editor.update(() => {
const sendMail = async () => {
await axios
2023-10-14 22:02:45 +08:00
.post(`${process.env.REACT_APP_BACKEND_URL}/send_email`, {
2023-10-13 04:17:23 +08:00
subject: `[SURVEY]: ${new Date().toDateString()}`,
2023-10-14 21:43:22 +08:00
message: `${Object.keys(form).map(
2023-10-13 04:17:23 +08:00
(k) => `<div>${questions[k]}</div><div>${form[k]}</div>`
2023-11-30 21:02:13 +08:00
)}<div>How can we make drawDB a better experience for you?</div>${$generateHtmlFromNodes(
editor
)}`,
2023-10-13 04:17:23 +08:00
})
.then((res) => {
Toast.success("Thanks for the feedback!");
editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
resetForm();
})
.catch((err) => {
Toast.error("Oops! Something went wrong.");
setLoading(false);
});
};
sendMail();
});
},
[editor, form, questions]
);
return (
<div className="py-5 px-8 mt-6 card-theme rounded-md">
<div className="my-3">
<div className="font-semibold ms-1 mb-2">{questions.satisfaction}</div>
<Slider
field="satisfaction"
min={0}
max={10}
value={form.satisfaction}
onChange={(v) => {
setForm((prev) => ({ ...prev, satisfaction: v }));
}}
/>
<div className="text-sm flex justify-between opacity-80">
<div>Not at all</div>
<div>Extremely</div>
</div>
</div>
<div className="my-3">
<div className="font-semibold ms-1 mb-2">{questions.ease}</div>
<Slider
field="ease"
min={0}
max={10}
value={form.ease}
onChange={(v) => {
setForm((prev) => ({ ...prev, ease: v }));
}}
/>
<div className="text-sm flex justify-between opacity-80">
<div>Not at all</div>
<div>Extremely</div>
</div>
</div>
<div className="my-3">
<div className="font-semibold ms-1 mb-2">
{questions.wouldRecommend}
</div>
<Slider
field="ease"
min={0}
max={10}
value={form.wouldRecommend}
onChange={(v) => {
setForm((prev) => ({ ...prev, wouldRecommend: v }));
}}
/>
<div className="text-sm flex justify-between opacity-80">
<div>Not at all</div>
<div>Extremely</div>
</div>
</div>
<div className="my-3">
<div className="font-semibold ms-1 mb-3">{questions.hadDifficulty}</div>
<RadioGroup
direction="vertical"
2023-10-14 21:43:22 +08:00
value={form.hadDifficulty}
2023-10-13 04:17:23 +08:00
onChange={(e) =>
setForm((prev) => ({ ...prev, hadDifficulty: e.target.value }))
}
>
<Radio value={"yes"}>Yes</Radio>
<Radio value={"no"}>No</Radio>
</RadioGroup>
</div>
{form.hadDifficulty === "yes" && (
<div className="my-3">
<div className="font-semibold ms-1 mb-3">{questions.difficulty}</div>
<TextArea
rows={2}
2023-10-14 21:43:22 +08:00
placeholder="Tell us more"
value={form.difficulty}
2023-10-13 04:17:23 +08:00
onChange={(v) => setForm((prev) => ({ ...prev, difficulty: v }))}
/>
</div>
)}
<div className="my-3">
<div className="font-semibold ms-1 mb-3">
{questions.triedOtherApps}
</div>
<RadioGroup
direction="vertical"
2023-10-14 21:43:22 +08:00
value={form.triedOtherApps}
2023-10-13 04:17:23 +08:00
onChange={(e) =>
setForm((prev) => ({ ...prev, triedOtherApps: e.target.value }))
}
>
<Radio value={"yes"}>Yes</Radio>
<Radio value={"no"}>No</Radio>
</RadioGroup>
</div>
{form.triedOtherApps === "yes" && (
<div className="my-3">
<div className="font-semibold ms-1 mb-3">{questions.comparison}</div>
<TextArea
rows={2}
2023-10-14 21:43:22 +08:00
placeholder="Tell us more"
value={form.comparison}
2023-10-13 04:17:23 +08:00
onChange={(v) => setForm((prev) => ({ ...prev, comparison: v }))}
/>
</div>
)}
<div className="my-3">
<div className="font-semibold ms-1 mb-3">{questions.occupation}</div>
<Select
optionList={[
{ value: "Student", label: "Student" },
{ value: "Teacher", label: "Teacher" },
{ value: "Developer", label: "Developer" },
]}
className="w-full"
placeholder="Occupation"
2023-10-14 21:43:22 +08:00
value={form.occupation}
2023-10-13 04:17:23 +08:00
onSelect={(v) => setForm((prev) => ({ ...prev, occupation: v }))}
/>
</div>
<div className="ms-1 font-semibold">
How can we make drawDB a better experience for you?
</div>
<RichEditor theme={theme} />
<div className="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 32px" }}
disabled={loading}
>
Submit
</Button>
<div className={loading ? "ms-2" : "hidden"}>
<Spin />
</div>
</div>
</div>
</div>
);
}
2023-09-19 20:51:40 +08:00
export default function Survey() {
2023-10-13 04:17:23 +08:00
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 = "Share you feedback | 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 (
<>
2023-11-30 21:02:13 +08:00
<div className="sm:py-3 py-5 md:px-8 px-20 flex justify-between items-center">
2023-10-13 04:17:23 +08:00
<div className="flex items-center justify-start">
<img
src={theme === "dark" ? logo_dark : logo_light}
alt="logo"
className="me-2 sm:h-[28px] md:h-[46px]"
/>
<div className="ms-4 sm:text-sm xl:text-lg font-semibold">
Share your feedback
</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="md:w-[90%] w-[74%] mx-auto my-8">
<Banner
fullMode={false}
type="info"
icon={null}
closeIcon={null}
description={
<div>
Thanks for taking this survey! We highly value your feedback and
strive to make drawDB fit your needs better.
</div>
}
/>
<LexicalComposer initialConfig={editorConfig}>
<SurveyForm theme={theme} />
</LexicalComposer>
</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>
</>
);
2023-09-19 20:51:40 +08:00
}