Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev michelleh 1629 #4

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions ui/.env
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# =========================================================================
NEXT_PUBLIC_BASE_URL=http://localhost:8080/uhgroupings
NEXT_PUBLIC_API_BASE_URL=http://localhost:8081/uhgroupingsapi
NEXT_PUBLIC_API_2_1_BASE_URL=http://localhost:8081/uhgroupingsapi/api/groupings/v2.1

# =========================================================================
Expand Down
7 changes: 6 additions & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@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",
"axios": "^1.6.7",
"axios-retry": "^4.0.0",
Expand All @@ -26,9 +28,12 @@
"next": "14.1.0",
"react": "^18",
"react-dom": "^18",
"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",
Expand Down
138 changes: 138 additions & 0 deletions ui/src/app/feedback/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"use client"
import React, {useState} 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 {sendFeedback} from "@/services/EmailService";
import {EmailResult, Feedback} from "@/services/EmailService";
import ErrorAlert from "@/components/layout/alerts/ErrorAlert";
import SuccessAlert from "@/components/layout/alerts/SuccessAlert";

const Feedback = () => {
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
const [showErrorAlert, setShowErrorAlert] = useState(false);

const formSchema = z.object({
type: z.string(),
name: 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: "[email protected]",
},
})

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 id="successAlert" hidden={!showSuccessAlert} className="container">
<SuccessAlert></SuccessAlert>
</div>
<div id="failAlert" hidden={!showErrorAlert} className="container">
<ErrorAlert></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">
<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-button 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>
</div>
</>
</Form>
)
}

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

export function ErrorAlert() {
return (
<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>
)}

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

export function SuccessAlert() {
return (
<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>
)}

export default SuccessAlert;
2 changes: 1 addition & 1 deletion ui/src/components/layout/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Footer = () => (
<div className="grid sm:grid-cols-12 md:grid-cols-12">
<div className="mx-auto mb-6 col-span-6 md:col-span-5 lg:col-span-4">
<Image
src="uhgroupings/uh-logo-system.svg"
src="/uhgroupings/uh-logo-system.svg"
alt="UH System logo"
width={235}
height={235} />
Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/layout/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const Navbar = async () => {
<div className="flex justify-between">
<Link href="/" className="lg:inline hidden">
<Image
src="uhgroupings/uh-groupings-logo.svg"
src="/uhgroupings/uh-groupings-logo.svg"
alt="UH Groupings Logo"
width={256}
height={256} />
Expand All @@ -24,7 +24,7 @@ const Navbar = async () => {
<MobileNavbar currentUser={currentUser} />
<Link href="/">
<Image
src="uhgroupings/uh-groupings-logo-large.svg"
src="/uhgroupings/uh-groupings-logo-large.svg"
alt="UH Groupings Logo"
width={56}
height={56} />
Expand Down
59 changes: 59 additions & 0 deletions ui/src/components/ui/alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from "react"
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",
{
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",
},
},
defaultVariants: {
variant: "default",
},
}
)

const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, ...props }, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
))
Alert.displayName = "Alert"

const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"

const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"

export { Alert, AlertTitle, AlertDescription }
72 changes: 36 additions & 36 deletions ui/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,54 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/components/ui/utils'

const buttonVariants = cva(
`inline-flex items-center justify-center whitespace-nowrap rounded-[0.25rem] text-base font-normal ring-offset-white
`inline-flex items-center justify-center whitespace-nowrap rounded-[0.25rem] text-base font-normal ring-offset-white
transition-colors ease-in-out duration-150 focus-visible:outline-none focus-visible:ring-2
focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50
dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300`,
{
variants: {
variant: {
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
{
variants: {
variant: {
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: `bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50
outline: `border border-green-blue bg-white hover:bg-green-blue hover:text-white text-uh-teal`,
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 rounded-md px-2',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
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 rounded-md px-2',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
)

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
asChild?: boolean
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : 'button'
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : 'button'
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = 'Button'

export { Button, buttonVariants }
export { Button, buttonVariants }
Loading
Loading