Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/layouts/buttons/AddFeedbackButton.tsx
T

91 lines
3.8 KiB
TypeScript

import { useFetcher, useLocation, useParams } from "react-router";
import { Fragment, useEffect, useState } from "react";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
import ButtonPrimary from "~/components/ui/buttons/ButtonPrimary";
import StarsIconFilled from "~/components/ui/icons/StarsIconFilled";
import InputText from "~/components/ui/input/InputText";
import Modal from "~/components/ui/modals/Modal";
import { appPath } from "~/utils/app/CanonicalUrlUtils";
import { useAppOrAdminData } from "~/utils/data/useAppOrAdminData";
import { useRootData } from "~/utils/data/useRootData";
export default function AddFeedbackButton() {
const [isOpen, setIsOpen] = useState(false);
const { t } = useTranslation();
return (
<Fragment>
<div className="relative hidden sm:inline-flex">
<div className="relative">
<div className="inline-flex divide-x divide-gray-300 rounded-sm shadow-none">
<div className="relative z-0 inline-flex rounded-full text-sm shadow-none">
<button
onClick={() => setIsOpen(!isOpen)}
type="button"
className="text-muted-foreground bg-secondary hover:bg-secondary/90 border-border relative inline-flex items-center rounded-full border p-2 font-medium shadow-inner focus:z-10 focus:outline-hidden focus:ring-2 focus:ring-offset-2"
aria-haspopup="listbox"
aria-expanded="true"
aria-label={t("feedback.title")}
>
<span className="sr-only">{t("feedback.title")}</span>
<StarsIconFilled className="h-5 w-5 p-0.5" />
</button>
</div>
</div>
</div>
</div>
<Modal open={isOpen} setOpen={setIsOpen} size="sm">
<FeedbackForm onClose={() => setIsOpen(false)} />
</Modal>
</Fragment>
);
}
function FeedbackForm({ onClose }: { onClose: () => void }) {
const { t } = useTranslation();
const params = useParams();
const appOrAdminData = useAppOrAdminData();
const { csrf } = useRootData();
const fetcher = useFetcher<{ success?: string; error?: string }>();
const location = useLocation();
useEffect(() => {
if (fetcher.data?.success) {
toast.success(fetcher.data.success);
onClose();
} else if (fetcher.data?.error) {
toast.error(fetcher.data.error);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetcher.data]);
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
fetcher.submit(e.currentTarget, {
method: "post",
action: appPath({ tenantSlug: params.tenant ?? "", mode: "host-aware" }),
});
// onClose();
};
return (
<fetcher.Form onSubmit={onSubmit} method="post">
<input type="hidden" name="action" value="add-feedback" readOnly hidden />
<input type="hidden" name="csrf" value={csrf ?? ""} readOnly hidden />
<input type="hidden" name="tenantId" value={appOrAdminData.currentTenant?.id} readOnly hidden />
<input type="hidden" name="fromUrl" value={location.pathname} readOnly hidden />
<div className="space-y-3">
<h3 className="text-lg font-medium leading-6">{t("feedback.title")}</h3>
<p className="text-muted-foreground text-sm">{t("feedback.description")}</p>
<InputText name="message" title="feedback.message" withLabel={false} defaultValue="" required rows={5} placeholder={t("feedback.placeholder")} />
<div className="flex justify-between">
<button type="button" onClick={onClose} className="text-muted-foreground text-sm hover:underline">
{t("shared.cancel")}
</button>
<ButtonPrimary type="submit">{t("feedback.send")}</ButtonPrimary>
</div>
</div>
</fetcher.Form>
);
}