mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: add feedback button
This commit is contained in:
parent
122c802c62
commit
fd36a8ac45
4 changed files with 126 additions and 15 deletions
|
|
@ -1,16 +1,30 @@
|
|||
'use client';
|
||||
import React from "react";
|
||||
import React, { use, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import { getUriWithOrg } from "@services/config/config";
|
||||
import { getAPIUrl, getUriWithOrg } from "@services/config/config";
|
||||
import { getOrganizationContextInfo, getOrganizationContextInfoWithoutCredentials } from "@services/organizations/orgs";
|
||||
import ClientComponentSkeleton from "@components/Utils/ClientComp";
|
||||
import { HeaderProfileBox } from "@components/Security/HeaderProfileBox";
|
||||
import MenuLinks from "./MenuLinks";
|
||||
import { getOrgLogoMediaDirectory } from "@services/media/media";
|
||||
import { MessageSquareIcon } from "lucide-react";
|
||||
import { Tooltip } from "@radix-ui/react-tooltip";
|
||||
import ToolTip from "@components/StyledElements/Tooltip/Tooltip";
|
||||
import Modal from "@components/StyledElements/Modal/Modal";
|
||||
import FeedbackModal from "../Modals/Feedback/Feedback";
|
||||
import useSWR from "swr";
|
||||
import { swrFetcher } from "@services/utils/ts/requests";
|
||||
|
||||
export const Menu = async (props: any) => {
|
||||
export const Menu = (props: any) => {
|
||||
const orgslug = props.orgslug;
|
||||
const org = await getOrganizationContextInfoWithoutCredentials(orgslug, { revalidate: 0, tags: ['organizations'] });
|
||||
const [feedbackModal, setFeedbackModal] = React.useState(false);
|
||||
const { data: org, error: error, isLoading } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, swrFetcher);
|
||||
|
||||
function closeFeedbackModal() {
|
||||
setFeedbackModal(false);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="backdrop-blur-lg h-[60px] blur-3xl z-10" style={{
|
||||
|
|
@ -25,7 +39,7 @@ export const Menu = async (props: any) => {
|
|||
<div className="logo flex ">
|
||||
<Link href={getUriWithOrg(orgslug, "/")}>
|
||||
<div className="flex w-auto h-9 rounded-md items-center m-auto py-1 justify-center" >
|
||||
{org.logo ? (
|
||||
{org?.logo ? (
|
||||
<img
|
||||
src={`${getOrgLogoMediaDirectory(org.org_id, org?.logo)}`}
|
||||
alt="Learnhouse"
|
||||
|
|
@ -39,15 +53,24 @@ export const Menu = async (props: any) => {
|
|||
</Link>
|
||||
</div>
|
||||
<div className="links flex grow">
|
||||
<ClientComponentSkeleton>
|
||||
<MenuLinks orgslug={orgslug} />
|
||||
</ClientComponentSkeleton>
|
||||
|
||||
<MenuLinks orgslug={orgslug} />
|
||||
</div>
|
||||
<div className="profile flex">
|
||||
<ClientComponentSkeleton>
|
||||
<HeaderProfileBox />
|
||||
</ClientComponentSkeleton>
|
||||
<div className="profile flex items-center space-x-2">
|
||||
|
||||
<Modal
|
||||
isDialogOpen={feedbackModal}
|
||||
onOpenChange={setFeedbackModal}
|
||||
minHeight="sm"
|
||||
dialogContent={<FeedbackModal></FeedbackModal>}
|
||||
dialogTitle="Feedback"
|
||||
dialogDescription="An issue? A suggestion? a bug ? Let us know!"
|
||||
dialogTrigger={
|
||||
<div className="feedback cursor-pointer block items-center h-fit p-2 rounded-2xl bg-orange-800 hover:bg-orange-900 text-orange-300 shadow">
|
||||
<MessageSquareIcon size={12} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<HeaderProfileBox />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
88
front/components/Objects/Modals/Feedback/Feedback.tsx
Normal file
88
front/components/Objects/Modals/Feedback/Feedback.tsx
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input, Textarea } from "@components/StyledElements/Form/Form"
|
||||
import { BarLoader } from "react-spinners"
|
||||
import * as Form from '@radix-ui/react-form'
|
||||
import React, { useState } from "react";
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { CheckCircleIcon } from "lucide-react";
|
||||
import { AuthContext } from "@components/Security/AuthProvider";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
export const FeedbackModal = (user: any) => {
|
||||
const auth: any = React.useContext(AuthContext);
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [view, setView] = useState<"feedbackForm" | "success">("feedbackForm")
|
||||
const [feedbackMessage, setFeedbackMessage] = useState("");
|
||||
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
const user = auth.userInfo.user_object ? auth.userInfo.user_object : null;
|
||||
const eventId = Sentry.captureMessage(`Feedback from ${user ? user.email : 'Anonymous'} - ${feedbackMessage}`);
|
||||
|
||||
const userFeedback = {
|
||||
event_id: eventId,
|
||||
name: user ? user.full_name : 'Anonymous',
|
||||
email: user ? user.email : 'Anonymous',
|
||||
comments: feedbackMessage,
|
||||
}
|
||||
Sentry.captureUserFeedback(userFeedback);
|
||||
setIsSubmitting(false);
|
||||
setView("success");
|
||||
};
|
||||
|
||||
const handleFeedbackMessage = (event: React.ChangeEvent<any>) => {
|
||||
setFeedbackMessage(event.target.value)
|
||||
};
|
||||
|
||||
if (view == "feedbackForm") {
|
||||
return (
|
||||
<FormLayout onSubmit={handleSubmit}>
|
||||
<FormField name="feedback-message">
|
||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||
<FormLabel>Feedback message</FormLabel>
|
||||
<FormMessage match="valueMissing">Please provide learning elements, separated by comma (,)</FormMessage>
|
||||
</Flex>
|
||||
<Form.Control asChild>
|
||||
<Textarea style={{ height: 150, }} onChange={handleFeedbackMessage} required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
|
||||
<Form.Submit asChild>
|
||||
<ButtonBlack type="submit" css={{ marginTop: 10 }}>
|
||||
{isSubmitting ? <BarLoader cssOverride={{ borderRadius: 60, }} width={60} color="#ffffff" />
|
||||
: "Submit Feedback"}
|
||||
</ButtonBlack>
|
||||
</Form.Submit>
|
||||
</Flex>
|
||||
</FormLayout>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-5">
|
||||
<div className="flex flex-col items-center space-y-5 pt-10">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="text-9xl text-green-500">
|
||||
<CheckCircleIcon></CheckCircleIcon>
|
||||
</div>
|
||||
<div className="text-3xl text-green-500">
|
||||
<div>Thank you for your feedback!</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xl text-gray-500">
|
||||
<div>We will take it into account.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<ButtonBlack onClick={() => setView("feedbackForm")}>Send another feedback</ButtonBlack>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FeedbackModal
|
||||
|
|
@ -28,7 +28,7 @@ const Modal = (params: ModalParams) => (
|
|||
<Dialog.Portal>
|
||||
<DialogOverlay />
|
||||
<DialogContent minHeight={params.minHeight}>
|
||||
<DialogTopBar>
|
||||
<DialogTopBar className='-space-y-1'>
|
||||
<DialogTitle>{params.dialogTitle}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{params.dialogDescription}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue