diff options
| author | Sebastien Castiel <sebastien@castiel.me> | 2024-01-19 11:28:25 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-19 11:28:25 -0500 |
| commit | 23524cb94314fd50476ccffe654841d980c713d7 (patch) | |
| tree | 6546d4d8675c1e4bc9d30f6bf526e08eef9b4eaf /src/components | |
| parent | f9040f8beda10b3969572cf8764e49f9b24b222a (diff) | |
Clean project from marketing content (#50)
* Clean project from marketing content
* Remove some dependencies
Diffstat (limited to 'src/components')
4 files changed, 0 insertions, 333 deletions
diff --git a/src/components/feedback-button/feedback-button-actions.tsx b/src/components/feedback-button/feedback-button-actions.tsx deleted file mode 100644 index 00c8748..0000000 --- a/src/components/feedback-button/feedback-button-actions.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use server' -import { formSchema } from '@/components/feedback-button/feedback-button-common' -import { FeedbackButtonEmail } from '@/components/feedback-button/feedback-button-email' -import { getResend } from '@/lib/resend' -import { env } from 'process' - -export async function sendFeedback(values: unknown) { - 'use server' - const { email, message } = formSchema.parse(values) - const resend = getResend() - if (!resend || !env.FEEDBACK_EMAIL_FROM || !env.FEEDBACK_EMAIL_TO) { - console.warn( - 'Resend is not properly configured. Feedback email won’t be sent.', - ) - return - } - await resend.emails.send({ - from: env.FEEDBACK_EMAIL_FROM, - to: env.FEEDBACK_EMAIL_TO, - subject: `Spliit: new feedback from ${email || 'anonymous user'}`, - react: <FeedbackButtonEmail email={email} message={message} />, - }) -} diff --git a/src/components/feedback-button/feedback-button-common.tsx b/src/components/feedback-button/feedback-button-common.tsx deleted file mode 100644 index 04567ef..0000000 --- a/src/components/feedback-button/feedback-button-common.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from 'zod' - -export const formSchema = z.object({ - email: z.union([ - z.string().email('Please enter a valid email address.'), - z.string().max(0), - ]), - message: z.string().min(10, 'Please enter at least 10 characters.').max(5000), -}) diff --git a/src/components/feedback-button/feedback-button-email.tsx b/src/components/feedback-button/feedback-button-email.tsx deleted file mode 100644 index ecb8c7d..0000000 --- a/src/components/feedback-button/feedback-button-email.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Heading } from '@react-email/heading' -import { Html } from '@react-email/html' -import { Preview } from '@react-email/preview' -import { Text } from '@react-email/text' - -type Props = { - email?: string - message: string -} - -export function FeedbackButtonEmail({ email, message }: Props) { - return ( - <Html> - <Preview>New feedback from {email || 'anonymous user'}</Preview> - <Heading>New feedback on Spliit</Heading> - <Text> - Email address: <strong>{email || 'not provided'}</strong> - </Text> - <pre style={{ padding: 16, borderLeft: '2px solid lightgray' }}> - {message} - </pre> - </Html> - ) -} diff --git a/src/components/feedback-button/feedback-button.tsx b/src/components/feedback-button/feedback-button.tsx deleted file mode 100644 index b1b6ae2..0000000 --- a/src/components/feedback-button/feedback-button.tsx +++ /dev/null @@ -1,277 +0,0 @@ -'use client' -import { sendFeedback } from '@/components/feedback-button/feedback-button-actions' -import { formSchema } from '@/components/feedback-button/feedback-button-common' -import { Button, ButtonProps } from '@/components/ui/button' -import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' -import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer' -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form' -import { Input } from '@/components/ui/input' -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Textarea } from '@/components/ui/textarea' -import { useToast } from '@/components/ui/use-toast' -import { useMediaQuery } from '@/lib/hooks' -import { zodResolver } from '@hookform/resolvers/zod' -import { Heart, HeartIcon, Loader2, MessageCircle } from 'lucide-react' -import { PropsWithChildren, ReactNode, SetStateAction, useState } from 'react' -import { useForm } from 'react-hook-form' -import * as z from 'zod' - -type FormValues = z.infer<typeof formSchema> - -type Props = { - donationUrl: string - defaultTab?: 'feedback' | 'support' -} - -export function FeedbackModal({ - donationUrl, - defaultTab = 'feedback', - children, -}: PropsWithChildren<Props>) { - const { toast } = useToast() - const isDesktop = useMediaQuery('(min-width: 640px)') - const [open, setOpen] = useState(false) - - async function onSubmit(values: FormValues) { - await sendFeedback(values) - toast({ - title: 'Thank you for your feedback!', - description: - 'We will have a look at it as soon as possible, and will get back to you if needed.', - }) - } - - const Wrapper = isDesktop ? FeedbackDialog : FeedbackDrawer - - return ( - <Wrapper open={open} setOpen={setOpen} button={children}> - <FeedbackContent - onSubmit={async (values) => { - await onSubmit(values) - setOpen(false) - }} - donationUrl={donationUrl} - defaultTab={defaultTab} - /> - </Wrapper> - ) -} - -function FeedbackDrawer({ - children, - open, - setOpen, - button, -}: PropsWithChildren<{ - open: boolean - setOpen: (open: SetStateAction<boolean>) => void - button: ReactNode -}>) { - return ( - <Drawer open={open} onOpenChange={setOpen}> - <DrawerTrigger asChild>{button}</DrawerTrigger> - <DrawerContent> - <div className="p-4">{children}</div> - </DrawerContent> - </Drawer> - ) -} - -function FeedbackDialog({ - children, - open, - setOpen, - button, -}: PropsWithChildren<{ - open: boolean - setOpen: (open: SetStateAction<boolean>) => void - button: ReactNode -}>) { - return ( - <Dialog open={open} onOpenChange={setOpen}> - <DialogTrigger asChild>{button}</DialogTrigger> - <DialogContent> - <div className="pt-4">{children}</div> - </DialogContent> - </Dialog> - ) -} - -function FeedbackContent({ - onSubmit, - donationUrl, - defaultTab, -}: { - onSubmit: (values: FormValues) => Promise<void> - donationUrl: string - defaultTab: 'feedback' | 'support' -}) { - return ( - <Tabs defaultValue={defaultTab}> - <div className="mt-2 mb-6"> - <TabsList className="grid w-full grid-cols-2"> - <TabsTrigger value="feedback">Give feedback</TabsTrigger> - <TabsTrigger value="support">Support us</TabsTrigger> - </TabsList> - </div> - <TabsContent value="feedback"> - <FeedbackForm onSubmit={onSubmit} /> - </TabsContent> - <TabsContent value="support"> - <DonationForm donationUrl={donationUrl} /> - </TabsContent> - </Tabs> - ) -} - -function FeedbackForm({ - onSubmit, -}: { - onSubmit: (values: FormValues) => Promise<void> -}) { - const form = useForm<FormValues>({ - resolver: zodResolver(formSchema), - defaultValues: { email: '', message: '' }, - }) - - const isSubmitting = form.formState.isSubmitting - return ( - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)} className="grid gap-4"> - <div> - <h2 className="text-lg font-semibold leading-none tracking-tight pb-1.5"> - Give us your feedback - </h2> - <p className="text-sm text-muted-foreground"> - We are always working to improve the user experience, and your - feedback helps us a lot. - </p> - </div> - <div className="grid gap-4"> - <FormField - control={form.control} - name="email" - render={({ field }) => ( - <FormItem> - <FormLabel>Your email address</FormLabel> - <FormControl> - <Input - placeholder="your@email.com" - className="text-base" - {...field} - /> - </FormControl> - <FormDescription> - Optional. Provide it if you want us to get back to you. - </FormDescription> - <FormMessage /> - </FormItem> - )} - /> - <FormField - control={form.control} - name="message" - render={({ field }) => ( - <FormItem> - <FormLabel>Your feedback</FormLabel> - <FormControl> - <Textarea - placeholder="Enter your feedback" - className="text-base" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - </div> - <div className="text-center mt-1"> - <Button type="submit" disabled={isSubmitting}> - {isSubmitting ? ( - <> - <Loader2 className="w-4 h-4 mr-2 animate-spin" /> Submitting… - </> - ) : ( - <> - <MessageCircle className="w-4 h-4 mr-2" /> Send - </> - )} - </Button> - </div> - </form> - </Form> - ) -} - -function DonationForm({ donationUrl }: { donationUrl: string }) { - return ( - <div className="flex flex-col gap-4"> - <div> - <h2 className="text-lg font-semibold leading-none tracking-tight pb-1.5"> - Support us - </h2> - <p className="text-sm text-muted-foreground"> - Help keep <strong>Spliit</strong> free and without ads! - </p> - </div> - <div className="prose prose-sm dark:prose-invert"> - <p> - Spliit is offered for free, but costs money and energy. If you like - the app, you can choose to support it by buying me (Sebastien) a - coffee with a one-time small donation. - </p> - <p>By supporting Spliit:</p> - <ul> - <li> - You contribute to the <strong>hosting costs</strong> for the app - (currently ~$150/year). - </li> - <li> - You help us keeping the application{' '} - <strong>free and without ads</strong>. - </li> - <li> - You give me energy to build <strong>new features</strong> and - improve the application. - </li> - </ul> - <p> - You will be redirected to <strong>Stripe</strong>, our payment - provider, where you can choose an amount to donate and complete the - payment. - </p> - </div> - <div className="text-center"> - <Button - asChild - className="bg-pink-700 hover:bg-pink-600 dark:bg-pink-500 dark:hover:bg-pink-600" - > - <a href={donationUrl} target="_blank"> - <Heart className="w-4 h-4 mr-2" /> Support us - </a> - </Button> - </div> - </div> - ) -} - -export function FeedbackButton({ ...props }: ButtonProps) { - return ( - <Button - className="bg-pink-700 hover:bg-pink-600 dark:bg-pink-500 dark:hover:bg-pink-600 fixed right-0 bottom-4 rounded-r-none gap-2" - {...props} - > - <MessageCircle className="w-4 h-4" /> - <HeartIcon className="w-4 h-4" /> - </Button> - ) -} |
