Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added apps/web/public/google.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/web/public/landing-placeholder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions apps/web/public/svg/blueCheck.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion apps/web/src/app/(pages)/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { auth } from "@cooper/auth";
import { CustomToaster } from "@cooper/ui";
import { redirect } from "next/navigation";

import HeaderLayout from "~/app/_components/header/header-layout";
import OnboardingWrapper from "~/app/_components/onboarding/onboarding-wrapper";

export default function RootLayout({
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
// Ensure user is authenticated
const session = await auth();

if (!session) {
redirect("/");
}

return (
<HeaderLayout>
<OnboardingWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@
);
const urlCompany = currentUrl.get("company");
const urlRole = currentUrl.get("role");
// Don't overwrite URL if it has a role but selectedItem is a company (would clear role)
if (urlRole && !isRole(selectedItem)) return;
// Skip URL update only when the URL already matches the selected item
if (urlCompany && urlRole && isRole(selectedItem)) {
const r = selectedItem as RoleType & {
Expand Down Expand Up @@ -305,6 +307,9 @@
const companySlug = roleItem.companySlug ?? createSlug(companyName);
const roleSlug = roleItem.slug;

// Don't push if we don't have a valid role slug (would clear role param)
if (!roleSlug) return;

// Preserve search param
const currentSearch = params.get("search");
params.delete("search");
Expand All @@ -318,7 +323,7 @@
params.set("search", currentSearch);
}

router.push(`/?${params.toString()}`);
router.push(`/roles/?${params.toString()}`);
} else {
// For companies, use the company parameter with the name
const companyItem = selectedItem as CompanyType & { slug?: string };
Expand All @@ -337,7 +342,7 @@
params.set("search", currentSearch);
}

router.push(`/?${params.toString()}`);
router.push(`/roles/?${params.toString()}`);
}
}
}, [
Expand Down Expand Up @@ -388,9 +393,9 @@

// Build new URL with only search param if it exists
if (searchParam) {
router.push(`/?search=${searchParam}`);
router.push(`/roles/?search=${searchParam}`);
} else {
router.push("/");
router.push("/roles");
}
};

Expand Down Expand Up @@ -491,7 +496,7 @@
if (selectedRole) {
roleInfoScrollRef.current?.scrollTo({ top: 0 });
}
}, [selectedRole?.id]);

Check warning on line 499 in apps/web/src/app/(pages)/(dashboard)/roles/page.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'selectedRole'. Either include it or remove the dependency array

return (
<div className="flex h-full w-full flex-col">
Expand Down
19 changes: 19 additions & 0 deletions apps/web/src/app/(pages)/(landing)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CustomToaster } from "@cooper/ui";

import HeaderLayout from "~/app/_components/header/header-layout";
import OnboardingWrapper from "~/app/_components/onboarding/onboarding-wrapper";

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<HeaderLayout>
<OnboardingWrapper>
{children}
<CustomToaster />
</OnboardingWrapper>
</HeaderLayout>
);
}
54 changes: 54 additions & 0 deletions apps/web/src/app/(pages)/(landing)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Image from "next/image";
import LoginButton from "~/app/_components/auth/login-button";

const textOptions = [
"Insights on interviews, pay, and job experience",
"Side-by-side comparison view of up to three jobs",
"Anonymous reviews to protect identities",
];
export default function Landing() {
return (
<div className="flex w-full flex-col bg-cooper-cream-100 lg:flex-row overflow-auto lg:overflow-hidden h-full flex-1">
<div className="lg:w-[43%] flex flex-col pl-16 pr-28 justify-center pt-2 lg:pt-0">
<div className="flex w-fit flex-row items-center gap-2">
<div className="text-cooper-blue-800 text-[40px] leading-[48px] font-semibold">
<div>Real reviews of </div>
<span className="font-black italic">real co-op experiences</span>
</div>
</div>
<div className="w-fit pt-8">
<LoginButton />
<div className="text-cooper-gray-600 text-md pb-6 pt-4 w-fit">
Log in with husky.neu.edu email to access reviews
</div>
<hr />
</div>

<div className="pt-6 text-cooper-gray-550 font-lg flex flex-col gap-3">
{textOptions.map((option) => {
return (
<div className="flex flex-row gap-2">
<Image
src="/svg/blueCheck.svg"
width={11}
height={9}
alt="Blue check"
/>
<div>{option}</div>
</div>
);
})}
</div>
</div>
<div className="flex-1 flex justify-end">
<Image
src="/landing-placeholder.png"
width={880}
height={600}
alt="Landing picture"
className="pt-20"
/>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion apps/web/src/app/(pages)/(protected)/review-form/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default function ReviewForm() {

const mutation = api.review.create.useMutation({
onSuccess: () => {
router.push("/");
router.push("/roles");
},
onError: (error) => {
toast.error(error.message || "Something went wrong. Please try again.");
Expand Down
16 changes: 13 additions & 3 deletions apps/web/src/app/_components/auth/login-button.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { signIn } from "@cooper/auth";
import { Button } from "@cooper/ui/button";
import Image from "next/image";

export default function LoginButton() {
return (
<form>
<Button
className="h-9 rounded-lg border-none border-cooper-yellow-500 bg-cooper-yellow-500 px-3 py-2 text-sm font-semibold text-white hover:border-cooper-yellow-700 hover:bg-cooper-yellow-700"
className="relative flex h-10 w-full justify-start gap-3 rounded-lg border border-[#E6E3DE] bg-[#fffefc] py-2.5 pl-3 text-lg font-semibold text-[#201E19]"
formAction={async () => {
"use server";
await signIn("google", { redirectTo: "/" });
await signIn("google", { redirectTo: "/roles" });
}}
>
Log in
<Image
src="/google.png"
width={20}
height={20}
alt="Google logo"
className="p-0 ml-0 shrink-0"
/>
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
Log in with Husky email
</div>
</Button>
</form>
);
Expand Down
6 changes: 4 additions & 2 deletions apps/web/src/app/_components/companies/all-company-roles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ export default function RenderAllRoles({
<div
key={role.id}
className="p-2"
onClick={() => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onClose?.();
router.push(
`/?company=${company?.slug ?? ""}&role=${role.slug}&type=roles`,
`/roles/?company=${company?.slug ?? ""}&type=roles&role=${role.slug}`,
);
}}
>
Expand Down
9 changes: 2 additions & 7 deletions apps/web/src/app/_components/header/header-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { ReactNode } from "react";
import { auth } from "@cooper/auth";

import Header from "~/app/_components/header/header";
import LoginButton from "../auth/login-button";
import ProfileButton from "../profile/profile-button";

/**
Expand All @@ -17,16 +16,12 @@ export default async function HeaderLayout({
children: ReactNode;
}) {
const session = await auth();
const button = session ? (
<ProfileButton session={session} />
) : (
<LoginButton />
);
const button = session ? <ProfileButton session={session} /> : "";

return (
<div className="flex h-screen flex-col overflow-y-auto">
<div className="top-0 z-50 w-full bg-white">
<Header auth={button} />
<Header auth={button} loggedIn={session} />
</div>
<article className="flex min-h-0 flex-1 flex-col items-center justify-start overflow-hidden">
{children}
Expand Down
20 changes: 11 additions & 9 deletions apps/web/src/app/_components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@
import { handleSignOut } from "../auth/actions";
import CooperLogo from "../cooper-logo";
import MobileHeaderButton from "./mobile-header-button";
import { Session } from "@cooper/auth";

Check warning on line 20 in apps/web/src/app/_components/header/header.tsx

View workflow job for this annotation

GitHub Actions / lint

All imports in the declaration are only used as types. Use `import type`

interface HeaderProps {
auth: React.ReactNode;
loggedIn: Session | null;
}

/**
* This is the header component. (Probably) should use header-layout instead
* @returns The header component for the website
*/
export default function Header({ auth }: HeaderProps) {
export default function Header({ auth, loggedIn }: HeaderProps) {
const [isOpen, setIsOpen] = useState(false);
const session = api.auth.getSession.useQuery();
const utils = api.useUtils();
Expand All @@ -36,10 +38,10 @@
<header className="bg-cooper-cream-100 z-50 flex min-h-[14rem] w-full flex-col justify-start outline outline-[1px]">
<div className="z-10 ml-3 mr-4 flex h-[8dvh] min-h-10 items-center justify-between gap-4">
<Link
href="/"
href="/roles"
onClick={(e) => {
e.preventDefault();
window.location.href = "/";
window.location.href = "/roles";
}}
>
<h1 className="text-2xl font-bold text-cooper-blue-800">Cooper</h1>
Expand All @@ -57,7 +59,7 @@

<div className="flex translate-y-8 justify-evenly">
<MobileHeaderButton
href="/"
href="/roles"
iconSrc="/svg/apartment.svg"
label="Jobs"
onClick={() => setIsOpen(false)}
Expand Down Expand Up @@ -91,9 +93,9 @@
<button
type="button"
onClick={async () => {
await handleSignOut();
await utils.auth.getSession.invalidate();
utils.auth.getSession.setData(undefined, null);
setIsOpen(false);
await handleSignOut();
}}
>
Log Out
Expand All @@ -114,10 +116,10 @@
return (
<header className="bg-cooper-cream-100 outline-cooper-gray-150 z-10 flex w-full items-center justify-between px-6 py-4 outline outline-[1px]">
<Link
href="/"
href="/roles"
onClick={(e) => {
e.preventDefault();
window.location.href = "/";
window.location.href = "/roles";
}}
className={"flex items-center justify-center gap-3"}
>
Expand All @@ -134,7 +136,7 @@
>
Submit Feedback or Bug Reports
</Link>
{session.data && (
{session.data && loggedIn && (
<div className="flex items-center gap-8">
<Link href="/review-form">
<Button className="hover:border-cooper-yellow-700 hover:bg-cooper-yellow-700 h-9 rounded-lg border-none border-cooper-yellow-500 bg-cooper-yellow-500 px-3 py-2 text-sm font-semibold text-white">
Expand Down
6 changes: 5 additions & 1 deletion apps/web/src/app/_components/reviews/role-card-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ export function RoleCardPreview({
)}
</CardHeader>
</div>
{showFavorite && <FavoriteButton objId={roleObj.id} objType="role" />}
{showFavorite && (
<div onClick={(e) => e.stopPropagation()}>
<FavoriteButton objId={roleObj.id} objType="role" />
</div>
)}
</div>
</Card>
);
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const metadata: Metadata = {
};

export default function RootLayout(props: { children: React.ReactNode }) {
// Ensure user is authenticated

return (
<html
className={hankenGroteskFont.variable}
Expand Down
Loading