mirror of
https://github.com/lukevella/rallly.git
synced 2025-06-01 18:21:52 +02:00
📢 Add a feedback form (#590)
This commit is contained in:
parent
ef1fd25a7c
commit
e8fd472ef6
10 changed files with 177 additions and 3 deletions
108
apps/web/src/components/feedback.tsx
Normal file
108
apps/web/src/components/feedback.tsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
import Link from "next/link";
|
||||
import { Trans, useTranslation } from "next-i18next";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { Button } from "@/components/button";
|
||||
import CheckCircle from "@/components/icons/check-circle.svg";
|
||||
import Speakerphone from "@/components/icons/speakerphone.svg";
|
||||
import { Logo } from "@/components/logo";
|
||||
import { useModalState } from "@/components/modal/use-modal";
|
||||
import Tooltip from "@/components/tooltip";
|
||||
import { trpc } from "@/utils/trpc";
|
||||
|
||||
const FeedbackForm = (props: { onClose: () => void }) => {
|
||||
const { t } = useTranslation("app");
|
||||
const sendFeedback = trpc.feedback.send.useMutation();
|
||||
const { handleSubmit, register, formState } = useForm<{ content: string }>();
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(async (data) => {
|
||||
await sendFeedback.mutateAsync(data);
|
||||
})}
|
||||
className="shadow-huge animate-popIn fixed bottom-8 right-8 z-20 w-[460px] max-w-full origin-bottom-right space-y-2 overflow-hidden rounded-md border bg-white p-3"
|
||||
>
|
||||
{formState.isSubmitted ? (
|
||||
<div className="absolute inset-0 flex h-full w-full items-center justify-center bg-white">
|
||||
<div className="space-y-3 text-center">
|
||||
<CheckCircle className="inline-block h-14 text-green-500" />
|
||||
<div>{t("feedbackSent")}</div>
|
||||
<div>
|
||||
<button onClick={props.onClose} className="text-link">
|
||||
{t("close")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="font-semibold text-slate-800">
|
||||
{t("feedbackFormTitle")}
|
||||
</div>
|
||||
<fieldset>
|
||||
<label className="mb-2" htmlFor="feedback">
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="feedbackFormLabel"
|
||||
components={{ appname: <Logo /> }}
|
||||
/>
|
||||
</label>
|
||||
<textarea
|
||||
id="feedback"
|
||||
autoFocus={true}
|
||||
placeholder={t("feedbackFormPlaceholder")}
|
||||
rows={4}
|
||||
className="w-full border bg-gray-50 p-2 text-slate-800"
|
||||
{...register("content", { required: true })}
|
||||
/>
|
||||
</fieldset>
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={props.onClose}>{t("cancel")}</Button>
|
||||
<Button
|
||||
loading={formState.isSubmitting}
|
||||
htmlType="submit"
|
||||
type="primary"
|
||||
>
|
||||
{t("send")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="feedbackFormFooter"
|
||||
components={{
|
||||
a: (
|
||||
<Link href="https://support.rallly.co" className="text-link" />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
const FeedbackButton = () => {
|
||||
const { t } = useTranslation("app");
|
||||
const [isVisible, show, close] = useModalState();
|
||||
if (isVisible) {
|
||||
return <FeedbackForm onClose={close} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
className="fixed bottom-8 right-8 z-20 hidden sm:block"
|
||||
content={t("sendFeedback")}
|
||||
placement="left"
|
||||
>
|
||||
<button
|
||||
onClick={show}
|
||||
className="shadow-huge inline-flex h-14 w-14 items-center justify-center rounded-full bg-slate-800"
|
||||
>
|
||||
<Speakerphone className="h-7 text-white" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeedbackButton;
|
Loading…
Add table
Add a link
Reference in a new issue