From cf23f12075212a9f405525c449678036ac20b903 Mon Sep 17 00:00:00 2001
From: akshat
Date: Fri, 2 Feb 2024 15:23:35 +0530
Subject: [PATCH] feat: resend integrated feedback form
---
.env.example | 3 +-
package.json | 2 +
pnpm-lock.yaml | 215 +++++++++++++++++++++++
public/email-x.png | Bin 0 -> 12132 bytes
src/app/api/send/route.ts | 38 ++++
src/app/contact-us/page.tsx | 34 ++--
src/components/EmailTemplate.tsx | 171 ++++++++++++++++++
src/components/FeedbackForm.tsx | 133 +++++++-------
src/components/StudyMaterial.tsx | 38 ++--
src/components/modals/feedback-modal.tsx | 28 ++-
src/components/providers/providers.tsx | 2 +
src/components/ui/alert.tsx | 5 +-
src/components/ui/sonner.tsx | 30 ++++
src/hooks/use-feedback.ts | 4 -
src/lib/schemas.ts | 5 +-
15 files changed, 597 insertions(+), 111 deletions(-)
create mode 100644 public/email-x.png
create mode 100644 src/app/api/send/route.ts
create mode 100644 src/components/EmailTemplate.tsx
create mode 100644 src/components/ui/sonner.tsx
diff --git a/.env.example b/.env.example
index 7f05f9a..ece6080 100644
--- a/.env.example
+++ b/.env.example
@@ -1,2 +1,3 @@
CONTENTFUL_SPACE_ID=
-CONTENTFUL_ACCESS_TOKEN=
\ No newline at end of file
+CONTENTFUL_ACCESS_TOKEN=
+RESEND_API_KEY=
\ No newline at end of file
diff --git a/package.json b/package.json
index 12d5006..2f1da77 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7",
+ "@react-email/components": "^0.0.14",
"@tailwindcss/typography": "^0.5.10",
"@tanstack/query-sync-storage-persister": "^5.8.3",
"@tanstack/react-query": "^5.8.4",
@@ -65,6 +66,7 @@
"react-hook-form": "^7.49.3",
"react-textarea-autosize": "^8.5.3",
"resend": "^3.1.0",
+ "sonner": "^1.4.0",
"tailwind-merge": "^2.0.0",
"tailwindcss": "3.3.5",
"tailwindcss-animate": "^1.0.7",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f09f6bf..dd18e1e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -53,6 +53,9 @@ dependencies:
'@radix-ui/react-tooltip':
specifier: ^1.0.7
version: 1.0.7(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0)
+ '@react-email/components':
+ specifier: ^0.0.14
+ version: 0.0.14(@types/react@18.2.37)(react@18.2.0)
'@tailwindcss/typography':
specifier: ^0.5.10
version: 0.5.10(tailwindcss@3.3.5)
@@ -149,6 +152,9 @@ dependencies:
resend:
specifier: ^3.1.0
version: 3.1.0
+ sonner:
+ specifier: ^1.4.0
+ version: 1.4.0(react-dom@18.2.0)(react@18.2.0)
tailwind-merge:
specifier: ^2.0.0
version: 2.2.0
@@ -2170,6 +2176,164 @@ packages:
'@babel/runtime': 7.23.8
dev: false
+ /@react-email/body@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-vjJ5P1MUNWV0KNivaEWA6MGj/I3c764qQJMsKjCHlW6mkFJ4SXbm2OlQFtKAb++Bj8LDqBlnE6oW77bWcMc0NA==}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/button@0.0.13(react@18.2.0):
+ resolution: {integrity: sha512-e/y8u2odJ8fF83B+wvL2FXzVcbQSUh2Cn2JH2Ez4L6AuPELsh8s2JYo081IDsXc16IyFiYpObn0blOt7s/qp8g==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/code-block@0.0.2(react@18.2.0):
+ resolution: {integrity: sha512-bQApEmpsvIcVYXdPCXhJB9CGCyShhn/c1JdctE/6R1uIosLbWt40evvVfp2X9STdi02Dhsjxw/AcGuQE6zGZqw==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ prismjs: 1.29.0
+ react: 18.2.0
+ dev: false
+
+ /@react-email/code-inline@0.0.1(react@18.2.0):
+ resolution: {integrity: sha512-SeZKTB9Q4+TUafzeUm/8tGK3dFgywUHb1od/BrAiJCo/im65aT+oJfggJLjK2jCdSsus8odcK2kReeM3/FCNTQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/column@0.0.9(react@18.2.0):
+ resolution: {integrity: sha512-1ekqNBgmbS6m97/sUFOnVvQtLYljUWamw8Y44VId95v6SjiJ4ca+hMcdOteHWBH67xkRofEOWTvqDRea5SBV8w==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/components@0.0.14(@types/react@18.2.37)(react@18.2.0):
+ resolution: {integrity: sha512-t/sNj0R9Mx9Sx5degPQcSBeWotNs7eUwiv72KN8v6fxaf87XlnMo0CPcKI/1by2DHZr5S0258ZQOO7vEFrbcLw==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ '@react-email/body': 0.0.7(react@18.2.0)
+ '@react-email/button': 0.0.13(react@18.2.0)
+ '@react-email/code-block': 0.0.2(react@18.2.0)
+ '@react-email/code-inline': 0.0.1(react@18.2.0)
+ '@react-email/column': 0.0.9(react@18.2.0)
+ '@react-email/container': 0.0.11(react@18.2.0)
+ '@react-email/font': 0.0.5(react@18.2.0)
+ '@react-email/head': 0.0.7(react@18.2.0)
+ '@react-email/heading': 0.0.11(@types/react@18.2.37)(react@18.2.0)
+ '@react-email/hr': 0.0.7(react@18.2.0)
+ '@react-email/html': 0.0.7(react@18.2.0)
+ '@react-email/img': 0.0.7(react@18.2.0)
+ '@react-email/link': 0.0.7(react@18.2.0)
+ '@react-email/preview': 0.0.8(react@18.2.0)
+ '@react-email/render': 0.0.12
+ '@react-email/row': 0.0.7(react@18.2.0)
+ '@react-email/section': 0.0.11(react@18.2.0)
+ '@react-email/tailwind': 0.0.14(react@18.2.0)
+ '@react-email/text': 0.0.7(react@18.2.0)
+ react: 18.2.0
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: false
+
+ /@react-email/container@0.0.11(react@18.2.0):
+ resolution: {integrity: sha512-jzl/EHs0ClXIRFamfH+NR/cqv4GsJJscqRhdYtnWYuRAsWpKBM1muycrrPqIVhWvWi6sFHInWTt07jX+bDc3SQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/font@0.0.5(react@18.2.0):
+ resolution: {integrity: sha512-if/qKYmH3rJ2egQJoKbV8SfKCPavu+ikUq/naT/UkCr8Q0lkk309tRA0x7fXG/WeIrmcipjMzFRGTm2TxTecDw==}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/head@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-IcXL4jc0H1qzAXJCD9ajcRFBQdbUHkjKJyiUeogpaYSVZSq6cVDWQuGaI23TA9k+pI2TFeQimogUFb3Kgeeudw==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/heading@0.0.11(@types/react@18.2.37)(react@18.2.0):
+ resolution: {integrity: sha512-EF5ZtRCxhHPw3m+8iibKKg0RAvAeHj1AP68sjU7s6+J+kvRgllr/E972Wi5Y8UvcIGossCvpX1WrSMDzeB4puA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.2.37)(react@18.2.0)
+ react: 18.2.0
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: false
+
+ /@react-email/hr@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-8suK0M/deXHt0DBSeKhSC4bnCBCBm37xk6KJh9M0/FIKlvdltQBem52YUiuqVl1XLB87Y6v6tvspn3SZ9fuxEA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/html@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-oy7OoRtoOKApVI/5Lz1OZptMKmMYJu9Xn6+lOmdBQchAuSdQtWJqxhrSj/iI/mm8HZWo6MZEQ6SFpfOuf8/P6Q==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/img@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-up9tM2/dJ24u/CFjcvioKbyGuPw1yeJg605QA7VkrygEhd0CoQEjjgumfugpJ+VJgIt4ZjT9xMVCK5QWTIWoaA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/link@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-hXPChT3ZMyKnUSA60BLEMD2maEgyB2A37yg5bASbLMrXmsExHi6/IS1h2XiUPLDK4KqH5KFaFxi2cdNo1JOKwA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/preview@0.0.8(react@18.2.0):
+ resolution: {integrity: sha512-Jm0KUYBZQd2w0s2QRMQy0zfHdo3Ns+9bYSE1OybjknlvhANirjuZw9E5KfWgdzO7PyrRtB1OBOQD8//Obc4uIQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/@react-email/render@0.0.12:
resolution: {integrity: sha512-S8WRv/PqECEi6x0QJBj0asnAb5GFtJaHlnByxLETLkgJjc76cxMYDH4r9wdbuJ4sjkcbpwP3LPnVzwS+aIjT7g==}
engines: {node: '>=18.0.0'}
@@ -2180,6 +2344,42 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
+ /@react-email/row@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-h7pwrLVGk5CIx7Ai/oPxBgCCAGY7BEpCUQ7FCzi4+eThcs5IdjSwDPefLEkwaFS8KZc56UNwTAH92kNq5B7blg==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/section@0.0.11(react@18.2.0):
+ resolution: {integrity: sha512-3bZ/DuvX1julATI7oqYza6pOtWZgLJDBaa62LFFEvYjisyN+k6lrP2KOucPsDKu2DOkUzlQgK0FOm6VQJX+C0w==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/tailwind@0.0.14(react@18.2.0):
+ resolution: {integrity: sha512-SRRcm08zxrAR5XozaW0X+GAJlTJITakZe0UXBiFZDlSDBLwFMxjaGuQwccqNF0LxDnxmduxYB71mzEAqecgTZg==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /@react-email/text@0.0.7(react@18.2.0):
+ resolution: {integrity: sha512-eHCx0mdllGcgK9X7wiLKjNZCBRfxRVNjD3NNYRmOc3Icbl8M9JHriJIfxBuGCmGg2UAORK5P3KmaLQ8b99/pbA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: 18.2.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/@rushstack/eslint-patch@1.7.0:
resolution: {integrity: sha512-Jh4t/593gxs0lJZ/z3NnasKlplXT2f+4y/LZYuaKZW5KAaiVFL/fThhs+17EbUd53jUVJ0QudYCBGbN/psvaqg==}
dev: false
@@ -5395,6 +5595,11 @@ packages:
hasBin: true
dev: true
+ /prismjs@1.29.0:
+ resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
+ engines: {node: '>=6'}
+ dev: false
+
/prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
@@ -5838,6 +6043,16 @@ packages:
yargs: 15.4.1
dev: true
+ /sonner@1.4.0(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-nvkTsIuOmi9e5Wz5If8ldasJjZNVfwiXYijBi2dbijvTQnQppvMcXTFNxL/NUFWlI2yJ1JX7TREDsg+gYm9WyA==}
+ peerDependencies:
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
diff --git a/public/email-x.png b/public/email-x.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4666047a6c2fd0f9724d5fd27397a1a2c3f298c
GIT binary patch
literal 12132
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
a@&5q(a`Xh#bI->B0000",
+ to: ["iboard990@gmail.com"],
+ subject: "New response has arrived",
+ react: EmailAdminTemplate(
+ validatedFormFields
+ ) as React.ReactElement,
+ }),
+ resend.emails.send({
+ from: "SyllabusX ",
+ to: [validatedFormFields.email],
+ subject: "Thanks for the feedback",
+ react: EmailTemplate({
+ name: validatedFormFields.name,
+ }) as React.ReactElement,
+ }),
+ ]);
+ return Response.json(data);
+ } catch (error) {
+ return Response.json({ error });
+ }
+}
diff --git a/src/app/contact-us/page.tsx b/src/app/contact-us/page.tsx
index 0424d74..fd9db81 100644
--- a/src/app/contact-us/page.tsx
+++ b/src/app/contact-us/page.tsx
@@ -50,25 +50,23 @@ const Page: FC = ({}) => {
-
-
+
);
diff --git a/src/components/EmailTemplate.tsx b/src/components/EmailTemplate.tsx
new file mode 100644
index 0000000..213a87c
--- /dev/null
+++ b/src/components/EmailTemplate.tsx
@@ -0,0 +1,171 @@
+import { cn } from "@/lib/utils";
+import {
+ Body,
+ Container,
+ Head,
+ Heading,
+ Hr,
+ Html,
+ Img,
+ Link,
+ Preview,
+ Row,
+ Section,
+ Tailwind,
+ Text,
+} from "@react-email/components";
+import { GeistSans } from "geist/font/sans";
+import { FC } from "react";
+
+const baseUrl = process.env.VERCEL_URL
+ ? `https://${process.env.VERCEL_URL}`
+ : "";
+
+interface EmailTemplateProps {
+ name: string;
+}
+
+const EmailTemplate: FC
= ({ name }) => {
+ return (
+
+
+ Acknowledgment of Your Feedback on SyllabusX
+
+
+ We've received your feedback! Our team is on it.
+
+
+
+
+
+
+
+
+ Thanks for the feedback
+
+
+ Hello {name},
+
+
+ Thank you for taking the time to provide valuable
+ feedback to SyllabusX! Your input is important to
+ us, and we appreciate your effort in helping us
+ enhance our platform.
+
+
+ Please rest assured that your concerns or
+ suggestions will be carefully considered. We aim to
+ address and respond to your feedback promptly.
+
+
+ If you have any additional thoughts or questions,
+ please feel free to reach out to us at{" "}
+
+ iboard990@gmail.com
+
+ . We're here to assist you and ensure that
+ SyllabusX continues to meet your expectations.
+
+
+
+
+
+
+ );
+};
+
+export function EmailAdminTemplate({
+ name,
+ email,
+ college,
+ course,
+ semester,
+ branch,
+ query,
+}: {
+ name: string;
+ email: string;
+ college: string;
+ course: string;
+ semester: string;
+ branch: string;
+ query: string;
+}) {
+ return (
+
+
+ New form response
+
+ {name} submitted the feedback form
+
+
+
+
+
+
+
+ A new response has arrived.
+
+
+ Form submitted by {name}
+
+
+ Here's what {name} wrote
+
+
+ {query}
+
+
+
+
+
+ Email: {email}
+
+
+ College: {college}
+
+
+ Course: {course}
+
+
+ Semester: {semester}
+
+
+ Branch: {branch}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default EmailTemplate;
diff --git a/src/components/FeedbackForm.tsx b/src/components/FeedbackForm.tsx
index d22a49f..5d67133 100644
--- a/src/components/FeedbackForm.tsx
+++ b/src/components/FeedbackForm.tsx
@@ -4,8 +4,10 @@ import { useFeedback } from "@/hooks/use-feedback";
import { FeedbackSchema, TFeedbackSchema } from "@/lib/schemas";
import { cn } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
-import { CornerRightUp, UploadCloud } from "lucide-react";
+import axios from "axios";
+import { CornerRightUp, MessageSquare, UploadCloud } from "lucide-react";
import { useForm } from "react-hook-form";
+import { toast } from "sonner";
import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import { Button, buttonVariants } from "./ui/button";
import {
@@ -27,24 +29,26 @@ const FeedbackForm = ({}) => {
const form = useForm({
resolver: zodResolver(FeedbackSchema),
- defaultValues: {
- name: "",
- email: "",
- branch: "",
- semester: 1,
- college: "",
- course: "",
- query: feedback.query,
- },
});
- const onSubmit = (values: TFeedbackSchema) => {};
+ const onSubmit = async (values: TFeedbackSchema) => {
+ toast.promise(axios.post("/api/send", { values }), {
+ loading: "Submitting...",
+ success: () => {
+ return "Form submitted!";
+ },
+ error: "Something went wrong! Try again later",
+ });
+ };
return (
-
-
-
-
-
-
+
+
+ >
);
};
@@ -198,24 +218,9 @@ export function FeedbackFormTrigger() {
const feedback = useFeedback();
return (
-
-
-
+
);
}
diff --git a/src/components/StudyMaterial.tsx b/src/components/StudyMaterial.tsx
index ce0ed94..1539ad8 100644
--- a/src/components/StudyMaterial.tsx
+++ b/src/components/StudyMaterial.tsx
@@ -2,6 +2,7 @@
import { Tab } from "@/config";
import { useEmbed } from "@/hooks/use-embed";
+import { useFeedback } from "@/hooks/use-feedback";
import { getBcaStudyMaterial, getBtechStudyMaterial } from "@/lib/server";
import { cn } from "@/lib/utils";
import { useLocalStorage } from "@mantine/hooks";
@@ -11,8 +12,9 @@ import {
RefetchOptions,
useQuery,
} from "@tanstack/react-query";
-import { Check, Download, Frown, Heart, RotateCw } from "lucide-react";
+import { AlertCircle, Check, Download, Heart, RotateCw } from "lucide-react";
import React, { useState } from "react";
+import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import { Badge } from "./ui/badge";
import { Button, buttonVariants } from "./ui/button";
import { Skeleton } from "./ui/skeleton";
@@ -225,24 +227,26 @@ StudyMaterial.Skeleton = function StudyMaterialSkeleton() {
};
StudyMaterial.Error = function StudyMaterialError() {
+ const feedback = useFeedback();
+
return (
<>
-
+
+
+ No notes found!
+
+ Looks like this subject is feeling a bit lonely without
+ notes! Be the hero, upload some using our{" "}
+
+ !
+
+
>
);
};
diff --git a/src/components/modals/feedback-modal.tsx b/src/components/modals/feedback-modal.tsx
index 5a16151..aa577f4 100644
--- a/src/components/modals/feedback-modal.tsx
+++ b/src/components/modals/feedback-modal.tsx
@@ -1,21 +1,41 @@
"use client";
import { useFeedback } from "@/hooks/use-feedback";
+import { useMediaQuery } from "@mantine/hooks";
import { FC } from "react";
import FeedbackForm from "../FeedbackForm";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
+import { Drawer, DrawerContent, DrawerHeader, DrawerTitle } from "../ui/drawer";
interface FeedbackModalProps {}
const FeedbackModal: FC = ({}) => {
const feedback = useFeedback();
+ const isDesktop = useMediaQuery("(min-width: 768px)");
+
+ if (!isDesktop) {
+ return (
+
+
+
+ Feedback Form
+
+
+
+
+ );
+ }
return (
-