Skip to content

Commit

Permalink
Create Feedback page
Browse files Browse the repository at this point in the history
  • Loading branch information
michho8 committed May 11, 2024
1 parent f167a29 commit 81a0806
Show file tree
Hide file tree
Showing 14 changed files with 536 additions and 15 deletions.
8 changes: 7 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
},
"dependencies": {
"@radix-ui/react-alert-dialog": "^1.0.5",
"@hookform/resolvers": "^3.3.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"camaro": "^6.2.2",
Expand All @@ -27,15 +29,19 @@
"react": "^18",
"react-dom": "^18",
"react-idle-timer": "^5.7.2",
"react-hook-form": "^7.50.1",
"react-router-dom": "^6.22.1",
"tailwind-merge": "^2.2.1",
"tailwindcss-animate": "^1.0.7",
"uniqid": "^5.4.0"
"uniqid": "^5.4.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@stylistic/eslint-plugin": "^1.6.1",
"@swc/core": "^1.3.106",
"@testing-library/jest-dom": "^6.3.0",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.11",
"@types/node": "^20",
"@types/react": "^18",
Expand Down
123 changes: 123 additions & 0 deletions ui/src/app/feedback/components/FeedbackForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use client'
import React from 'react';
import {Input} from '@/components/ui/input';
import {Button} from '@/components/ui/button'
import {Form, FormControl, FormField, FormItem, FormLabel, FormMessage,} from '@/components/ui/form'
import {z} from 'zod'
import {zodResolver} from '@hookform/resolvers/zod'
import {useForm} from 'react-hook-form'
import {EmailResult, Feedback, sendFeedback} from '@/services/EmailService';

const FeedbackForm = ({ currUser, setShowSuccessAlert, setShowErrorAlert } :
{ currUser:string, setShowSuccessAlert:any, setShowErrorAlert:any }) => {

const formSchema = z.object({
type: z.string(),
name: z.optional(z.string()),
email: z.string().email(),
message: z.string().min(15),
})

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
type: 'General',
email: currUser + '@hawaii.edu'
}
});

async function onSubmit(values: z.infer<typeof formSchema>) {
const input: Feedback = {
type: values.type,
name: values.name,
email: values.email,
message: values.message,
exceptionMessage: 'test exception message'
};
const results = await sendFeedback(input);
const emailResult: EmailResult = {
resultCode: results.resultCode,
recipient: results.recipient,
from: results.from,
subject: results.subject,
text: results.text
};

(emailResult.resultCode == 'SUCCESS') ? setShowSuccessAlert(true) : setShowErrorAlert(true);

if (emailResult.resultCode == 'SUCCESS') {
setShowSuccessAlert(true);
} else {
setShowErrorAlert(true);
}

//will break without curly braces
form.reset({});
}

return (
<Form {...form}>
<>
<div className='col-span-7 pl-5 pt-5'>
<form id='feedbackForm' onSubmit={form.handleSubmit(onSubmit)} className='space-y-8'>
<FormField control={form.control} name='type'
render={({field}) => (
<FormItem>
<FormLabel htmlFor='type' className='text-base'>Feedback Type:
<span className='text-red-500'>*</span></FormLabel>
<FormControl>
<select id='type' className='w-full px-3 py-1 border border-gray-300 rounded-md focus:accent-blue-500 focus:border-blue-500' {...field}>
<option value='General' defaultValue='true'>General</option>
<option value='Problem'>Problem</option>
<option value='Feature'>Feature</option>
<option value='Question'>Question</option>
</select>
</FormControl>
</FormItem>
)}
/>
<FormField control={form.control} name='name'
render={({field}) => (
<FormItem>
<FormLabel htmlFor='name' className='text-base'>Your Name (Optional):</FormLabel>
<FormControl>
<Input id='name' className='text-base' placeholder='John Doe' {...field} />
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<FormField control={form.control} name='email'
render={({field}) => (
<FormItem>
<FormLabel htmlFor='email' className='text-base'>Email Address:
<span className='text-red-500'>*</span></FormLabel>
<FormControl>
<Input id='email' className='text-base' placeholder='Enter your email here' {...field} />
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<FormField control={form.control} name='message'
render={({field}) => (
<FormItem>
<FormLabel htmlFor='message' className='text-base'>Your Feedback:
<span className='text-red-500'>*</span></FormLabel>
<FormControl>
<textarea id='message' className='w-full px-3 py-1 border border-gray-300 rounded-md' rows={6} {...field} />
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<Button className='text-white bg-uh-teal hover:bg-green-blue focus:ring-4 focus:ring-blue-300 rounded-md text-base dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 shadow-2xl'
type='submit'>Submit</Button>
</form>
</div>
</>
</Form>
)
}

export default FeedbackForm;
41 changes: 41 additions & 0 deletions ui/src/app/feedback/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client'
import React, {useState} from 'react';
import ErrorAlert from '@/components/layout/alerts/ErrorAlert';
import SuccessAlert from '@/components/layout/alerts/SuccessAlert';
import FeedbackForm from '@/app/feedback/components/FeedbackForm';
import {getCurrentUser} from '@/access/AuthenticationService';

async function getUser() {
return await getCurrentUser();
}
const Feedback = () => {
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
const [showErrorAlert, setShowErrorAlert] = useState(false);

const [userUid, setUserUid] = useState<string>('something first');

// Calling an async function to get the user's uid
getUser().then(res => setUserUid(res.uid))

return (
<>
<div id="successAlert" hidden={!showSuccessAlert} className="container">
<SuccessAlert isActive={showSuccessAlert}></SuccessAlert>
</div>
<div id="errorAlert" hidden={!showErrorAlert} className="container">
<ErrorAlert isActive={showErrorAlert}></ErrorAlert>
</div>
<div className="container grid grid-cols-12 pt-5 pb-4">
<div className="col-span-5 pt-5">
<h1 className="text-md-left text-3xl font-bold">Feedback</h1>
<p className="text-md-left text-xl mt-3">Helps us to understand where improvements are needed. Please let us know.</p>
</div>
<div className="col-span-7 pl-5 pt-5">
<FeedbackForm currUser={userUid} setShowSuccessAlert={setShowSuccessAlert} setShowErrorAlert={setShowErrorAlert} ></FeedbackForm>
</div>
</div>
</>
)
}

export default Feedback;
24 changes: 24 additions & 0 deletions ui/src/components/layout/alerts/ErrorAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
Alert,
AlertDescription,
AlertTitle,
} from '@/components/ui/alert'
import {XCircle} from 'lucide-react';
import React from 'react';

export const ErrorAlert = ({ isActive } : { isActive:any }) => {
return (
<section className="errorAlert">
{isActive ? (
<Alert variant="destructive" className="bg-red-100">
<XCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription className="text-base text-red-500">
Email feedback was unsuccessful. Please try again.
</AlertDescription>
</Alert>
) : null }
</section>
)}

export default ErrorAlert;
26 changes: 26 additions & 0 deletions ui/src/components/layout/alerts/SuccessAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
Alert,
AlertDescription,
AlertTitle,
} from '@/components/ui/alert'
import {CheckCircle2} from 'lucide-react';
import React from 'react';

export const SuccessAlert = ({ isActive } : { isActive:any }) => {
return (
<section className="successAlert">
{isActive ? (
<Alert variant="default" className="bg-green-100">
<CheckCircle2 className="h-4 w-4" />
<AlertTitle>Thank you!</AlertTitle>
<AlertDescription>
<div className="text-base alert-success-test-color">
Your feedback has successfully been submitted.
</div>
</AlertDescription>
</Alert>
) : null }
</section>
)}

export default SuccessAlert;
8 changes: 2 additions & 6 deletions ui/src/components/ui/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/components/ui/utils'

const alertVariants = cva(

`relative w-full rounded-lg border border-slate-200 p-4
[&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute
[&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-slate-950 dark:border-slate-800 dark:[&>svg]:text-slate-50`,
'relative w-full rounded-lg border border-slate-200 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-slate-950 dark:border-slate-800 dark:[&>svg]:text-slate-50',
{
variants: {
variant: {
default: 'bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50',
destructive:
`border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50
dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900`,
'border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900',
},
},
defaultVariants: {
Expand Down
11 changes: 5 additions & 6 deletions ui/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ const buttonVariants = cva(
{
variants: {
variant: {
default: `bg-[#6fa9be] border-transparent text-slate-50 [text-shadow:_0_1px_1px_#444] bg-gradient-to-b
from-[#7db1c4] to-[#5a9cb4] border hover:from-green-blue hover:to-green-blue
border-x-black/[.0.1] border-t-black/[.0.1] border-b-black/[.0.25]`,
default: `bg-[#5a9cb4] hover:bg-green-blue [text-shadow:_0_1px_1px_#444] text-slate-50`,
destructive: `bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50
dark:hover:bg-red-900/90`,
outline: `border border-green-blue bg-white hover:bg-green-blue hover:text-white text-uh-teal`,
secondary: `border border-transparent bg-[#f8f9fa] text-[#212529] hover:bg-uh-blue4 hover:text-white`,
secondary: `bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50
dark:hover:bg-slate-800/80`,
ghost: `hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50`,
link: `text-slate-900 underline-offset-4 hover:underline dark:text-slate-50`,
},
size: {
default: 'h-10 px-2.5 py-2',
sm: 'h-9 px-2',
lg: 'h-12 px-4 text-xl',
sm: 'h-9 rounded-md px-2',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
},
},
Expand Down
Loading

0 comments on commit 81a0806

Please sign in to comment.