Skip to content

Commit

Permalink
Home / Search page (#45)
Browse files Browse the repository at this point in the history
* fix: fix company router errors when fetching companys that don't exist

#29

* refactor(form): move card to a separate component

* refactor(form): abstract form section

* refactor(form): abstract review section

* feat(form): add a radio group for coop cycle

* feat(form): add co-op cycle section

* feat(form): add a few company details questions

* feat(form): update review section

* fix(schema): modify schema

BREAKING CHANGE: modify schema

* fix(form): add numbers to heading

* feat(form): add benefits checklish

* fix(form): remove no benefits option

* refactor(form): clean up checklist code

* fix(trpc): modify review schema for endpoint

* feat(form): add a ratings section

* feat(form): add star component

* feat(form): add remaining star rating fields

* feat(form): improve star rating ux

* feat(form): add other benefits input box

* fix(form): change optional property of the form schema

* feat(form): add a reset button

* refactor(schema): sync form and schema field names

* fix(form): add a temporary fix to uncheck radio buttons on form reset

* docs: update readme

* feat(ui): improve responsiveness on smaller devices

* fix(form): add jsdoc, improve responsiveness, and add coop dates till 2000

* feat: added Colored Checkpoints to Header

* fix: compiled Changes for Push

* chore: prettier github action error

* style: responsive UI Updates

* feat: home page / Search Page + Filter

* chore: got rid of up

Got rid of yup, accidentally installed

* feat: homepage fixes, abstractions, code changes, tailwind changes

* fix: pR comment changes

* fix: fix BentonSans Font implementation, moved header components around

* style: format review-form.tsx

---------

Co-authored-by: Rishikesh Kanabar <rishikesh.kanabar@gmail.com>
  • Loading branch information
banushi-a and RishikeshNK authored Mar 17, 2024
1 parent a640a6d commit 3019fbe
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 51 deletions.
27 changes: 27 additions & 0 deletions public/svg/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/app/companies/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Header from "~/components/header";
import SearchFilter from "~/components/search-filter";

export default async function Companies() {
return (
<div className="flex h-full flex-col">
<Header />

<div className="mx-12 mt-16 flex flex-col">
<SearchFilter />
</div>
</div>
);
}
Binary file added src/app/fonts/BentonSansBold.otf
Binary file not shown.
Binary file added src/app/fonts/BentonSansBook.otf
Binary file not shown.
Binary file added src/app/fonts/BentonSansMedium.otf
Binary file not shown.
Binary file added src/app/fonts/BentonSansRegular.otf
Binary file not shown.
34 changes: 27 additions & 7 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import "~/styles/globals.css";

import { Inter as FontSans } from "next/font/google";

import { TRPCReactProvider } from "~/trpc/react";
import { Toaster } from "~/components/ui/sonner";
import { cn } from "~/lib/utils";

const fontSans = FontSans({
subsets: ["latin"],
variable: "--font-sans",
import localFont from "next/font/local";

// Font files can be colocated inside of `pages`
const myFont = localFont({
src: [
{
path: "./fonts/BentonSansBook.otf",
weight: "300",
style: "normal",
},
{
path: "./fonts/BentonSansRegular.otf",
weight: "500",
style: "normal",
},
{
path: "./fonts/BentonSansMedium.otf",
weight: "700",
style: "normal",
},
{
path: "./fonts/BentonSansBold.otf",
weight: "900",
style: "normal",
},
],
});

export const metadata = {
Expand All @@ -27,7 +47,7 @@ export default function RootLayout({
<body
className={cn(
"min-h-screen bg-background font-sans antialiased",
fontSans.variable,
myFont.className,
)}
>
<TRPCReactProvider>{children}</TRPCReactProvider>
Expand Down
52 changes: 9 additions & 43 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,16 @@
import { getServerAuthSession } from "~/server/auth";
import Header from "~/components/header";
import SearchFilter from "~/components/search-filter";

export default async function Home() {
const session = await getServerAuthSession();

if (!session) {
return (
<div className="flex h-screen flex-col items-center justify-center space-y-4">
<p className="text-3xl font-semibold text-red-500">
You are not signed in!
return (
<div className="flex h-[85vh] flex-col">
<Header />
<div className="flex h-full flex-col items-center justify-center">
<p className="mb-8 text-2xl font-semibold">
Search your dream co-op role!
</p>
<a
href="/api/auth/signin/google"
type="button"
className="mb-2 me-2 inline-flex items-center rounded-lg bg-[#4285F4] px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-[#4285F4]/90 focus:outline-none focus:ring-4 focus:ring-[#4285F4]/50 dark:focus:ring-[#4285F4]/55"
>
<svg
className="me-2 h-4 w-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 18 19"
>
<path
fillRule="evenodd"
d="M8.842 18.083a8.8 8.8 0 0 1-8.65-8.948 8.841 8.841 0 0 1 8.8-8.652h.153a8.464 8.464 0 0 1 5.7 2.257l-2.193 2.038A5.27 5.27 0 0 0 9.09 3.4a5.882 5.882 0 0 0-.2 11.76h.124a5.091 5.091 0 0 0 5.248-4.057L14.3 11H9V8h8.34c.066.543.095 1.09.088 1.636-.086 5.053-3.463 8.449-8.4 8.449l-.186-.002Z"
clipRule="evenodd"
/>
</svg>
Sign in with Google
</a>
<SearchFilter />
</div>
);
}

return (
<div className="flex h-screen flex-col items-center justify-center space-y-4">
<p className="text-3xl font-semibold text-emerald-500">
Welcome, {session.user.name}!
</p>
<a
href="/api/auth/signout"
type="button"
className="mb-2 me-2 rounded-lg bg-red-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
>
Sign Out
</a>
</div>
);
}
29 changes: 29 additions & 0 deletions src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Image from "next/image";
import Link from "next/link";

import LoginButton from "~/components/login-button";
import LogoutButton from "./logout-button";
import { getServerSession } from "next-auth";

export default async function Header() {
const session = await getServerSession();

return (
<header className="flex h-16 w-full items-center justify-between bg-cooper-blue-400 pr-2">
<div className="ml-[-1rem] flex items-center">
<div className="mt-2">
<Image
src="/svg/logo.svg"
width={100}
height={100}
alt="Logo Picture"
/>
</div>
<Link href="/">
<h1 className="text-3xl font-extrabold text-white">COOPER</h1>
</Link>
</div>
{session ? <LogoutButton /> : <LoginButton />}
</header>
);
}
16 changes: 16 additions & 0 deletions src/components/login-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import { Button } from "~/components/ui/button";
import { signIn } from "next-auth/react";

export default async function LoginButton() {
return (
<Button
type="button"
className="rounded-lg bg-red-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
onClick={() => signIn("google")}
>
Sign In
</Button>
);
}
18 changes: 18 additions & 0 deletions src/components/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import { Button } from "~/components/ui/button";
import { signOut } from "next-auth/react";

export default async function LogoutButton() {
return (
<Button
onClick={() => {
signOut({ callbackUrl: "/" });
}}
type="button"
className="rounded-lg bg-red-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
>
Sign Out
</Button>
);
}
4 changes: 3 additions & 1 deletion src/components/review-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ export function ReviewForm(props: ReviewFormProps) {
{currentStep == 0 && <CoopCycleSection />}
{currentStep == 1 && <RatingsSection />}
{currentStep == 2 && <ReviewSection />}
{currentStep == 3 && <CompanyDetailsSection companyName={props.company.name} />}
{currentStep == 3 && (
<CompanyDetailsSection companyName={props.company.name} />
)}
{currentStep >= 0 && currentStep <= steps.length - 1 && (
<div className="flex justify-between">
<Button
Expand Down
43 changes: 43 additions & 0 deletions src/components/search-bar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useFormContext } from "react-hook-form";
import { FormControl, FormField, FormItem } from "./ui/form";
import { Input } from "./ui/input";

export function SearchBar() {
const form = useFormContext();

return (
<FormField
control={form.control}
name="searchText"
render={({ field }) => (
<FormItem>
<FormControl>
<div className="relative w-96">
{/* SEARCH TEXT INPUT */}
<svg
xmlns="http://www.w3.org/2000/svg"
className="absolute bottom-0 left-3 top-0 my-auto h-6 w-6 text-gray-500"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>

<Input
{...field}
className="min-w-96 rounded-3xl border-none bg-cooper-blue-200 pl-12"
placeholder="Search"
/>
</div>
</FormControl>
</FormItem>
)}
/>
);
}
117 changes: 117 additions & 0 deletions src/components/search-filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { Form, FormControl, FormField, FormItem } from "~/components/ui/form";
import { Industry, WorkEnvironment, WorkTerm } from "@prisma/client";
import { Input } from "./ui/input";
import { cn } from "~/lib/utils";
import { buttonVariants } from "./ui/button";
import { TriangleDownIcon } from "@radix-ui/react-icons";
import { SearchBar } from "./search-bar";

const formSchema = z.object({
searchText: z.string(),
searchIndustry: z.nativeEnum(Industry).optional(),
searchWorkTerm: z.nativeEnum(WorkTerm).optional(),
searchWorkModel: z.nativeEnum(WorkEnvironment).optional(),
});

/**
* Used to abstract the dropdowns in the search bar.
*/
const searchDropdown: {
name: "searchIndustry" | "searchWorkTerm" | "searchWorkModel";
title: string;
enumObj: object;
}[] = [
{
name: "searchIndustry",
title: "Industry",
enumObj: Industry,
},
{
name: "searchWorkTerm",
title: "Work Term",
enumObj: WorkTerm,
},
{
name: "searchWorkModel",
title: "Work Model",
enumObj: WorkEnvironment,
},
];

export type SearchFilterFormType = typeof formSchema;

export default function SearchFilter() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
searchText: "",
searchIndustry: undefined,
searchWorkTerm: undefined,
searchWorkModel: undefined,
},
});

function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values);
}

return (
<div className="m-4 mt-0 flex h-24 min-w-[80vw] items-center justify-center rounded-2xl bg-cooper-blue-400 p-4">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-between mx-4 flex w-full flex-wrap items-center justify-between"
>
<SearchBar />
<div className="flex items-center justify-around space-x-3">
{searchDropdown.map(({ name, title, enumObj }) => {
return (
<FormField
key={`${name}-dropdown`}
control={form.control}
name={name}
render={({ field }) => (
<FormItem>
<div className="relative">
<FormControl>
<select
className={cn(
buttonVariants({ variant: "outline" }),
"w-36 appearance-none border-none bg-transparent pr-8 text-right text-white",
"hover:bg-transparent hover:text-secondary",
)}
{...field}
>
<option value={undefined}>{title}</option>
{(
Object.keys(enumObj) as Array<
keyof typeof Industry
>
).map((elem) => {
return (
<option key={elem} value={elem}>
{elem}
</option>
);
})}
</select>
</FormControl>
<TriangleDownIcon className="absolute right-2.5 top-2.5 h-5 w-5" />
</div>
</FormItem>
)}
/>
);
})}
</div>
</form>
</Form>
</div>
);
}
Loading

0 comments on commit 3019fbe

Please sign in to comment.