mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2026-04-03 10:57:52 +08:00
[offers][feat] add header for pages (#526)
* [offers][feat] add header for pages * [offers][fix] fix pronoun for toast * [offers][feat] fix index page description
This commit is contained in:
@@ -8,7 +8,7 @@ const navigation: ProductNavigationItems = [
|
||||
|
||||
const navigationAuthenticated: ProductNavigationItems = [
|
||||
{ href: '/offers/submit', name: 'Analyze your offers' },
|
||||
{ href: '/offers/dashboard', name: 'Your dashboard' },
|
||||
{ href: '/offers/dashboard', name: 'My dashboard' },
|
||||
{ href: '/offers/features', name: 'Features' },
|
||||
{ href: '/offers/about', name: 'About' },
|
||||
];
|
||||
|
||||
@@ -12,7 +12,7 @@ const features = [
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Maiores impedit perferendis suscipit eaque, iste dolor cupiditate blanditiis ratione.',
|
||||
'Reveal stories behind offers. Help job seekers benchmark and analyse their anonymous offers with more context. Encourage discussions around offer profiles.',
|
||||
href: '/offers',
|
||||
img: '/logos/offers-logo.svg',
|
||||
name: 'Tech Offers',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
import Container from '~/components/shared/Container';
|
||||
|
||||
const people = [
|
||||
@@ -29,75 +31,80 @@ const people = [
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<div className="lg:py-18 bg-white py-12">
|
||||
<Container variant="xs">
|
||||
<div className="space-y-12">
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
About Tech Offers Repo
|
||||
</h1>
|
||||
<p className="text-lg text-slate-500">
|
||||
Tech Offers Repo, a project under the series of Tech Interview
|
||||
Handbook (TIH), reveals the stories behind offers by focusing on
|
||||
the profiles of the offer receivers. It helps job seekers
|
||||
benchmark and analyse their anonymous offers with more context and
|
||||
encourages discussions around offer profiles.
|
||||
</p>
|
||||
</div>
|
||||
{/* Feedback */}
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">
|
||||
Feedback to Us
|
||||
</h2>
|
||||
<>
|
||||
<Head>
|
||||
<title>About us - Tech Offers Repo</title>
|
||||
</Head>
|
||||
<div className="lg:py-18 bg-white py-12">
|
||||
<Container variant="xs">
|
||||
<div className="space-y-12">
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
About Tech Offers Repo
|
||||
</h1>
|
||||
<p className="text-lg text-slate-500">
|
||||
Tech Offers Repo, a project under the series of Tech Interview
|
||||
Handbook (TIH), reveals the stories behind offers by focusing on
|
||||
the profiles of the offer receivers. It helps job seekers
|
||||
benchmark and analyse their anonymous offers with more context
|
||||
and encourages discussions around offer profiles.
|
||||
</p>
|
||||
</div>
|
||||
{/* Feedback */}
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">
|
||||
Feedback to Us
|
||||
</h2>
|
||||
|
||||
<p className="text-lg text-slate-500">
|
||||
Thank you for using our platform! Feel free to submit your
|
||||
feedback / feature request / bug report
|
||||
<a
|
||||
className="text-primary-600 hover:text-primary-500 ml-1"
|
||||
href="https://forms.gle/6zV5yimPyiByKqDy8"
|
||||
rel="noreferrer"
|
||||
target="_blank">
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">
|
||||
Meet the Team
|
||||
</h2>
|
||||
<ul
|
||||
className="grid grid-cols-2 items-start gap-8 md:grid-cols-1 md:items-start md:space-y-0"
|
||||
role="list">
|
||||
{people.map((person) => (
|
||||
<li key={person.name}>
|
||||
<div className="space-y-4 sm:grid sm:grid-cols-4 sm:gap-6 sm:space-y-0 lg:gap-8">
|
||||
<div className="aspect-w-2 aspect-h-2 h-0">
|
||||
<img
|
||||
alt={person.name}
|
||||
className="rounded-lg object-cover shadow-lg"
|
||||
src={person.imageUrl}
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-3">
|
||||
<div className="space-y-4">
|
||||
<div className="text-md space-y-1 font-medium leading-6 sm:text-lg">
|
||||
<h3>{person.name}</h3>
|
||||
<p className="text-primary-600">{person.role}</p>
|
||||
</div>
|
||||
<div className="text-sm sm:text-lg">
|
||||
<p className="text-slate-500">{person.bio}</p>
|
||||
<p className="text-lg text-slate-500">
|
||||
Thank you for using our platform! Feel free to submit your
|
||||
feedback / feature request / bug report
|
||||
<a
|
||||
className="text-primary-600 hover:text-primary-500 ml-1"
|
||||
href="https://forms.gle/6zV5yimPyiByKqDy8"
|
||||
rel="noreferrer"
|
||||
target="_blank">
|
||||
here
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">
|
||||
Meet the Team
|
||||
</h2>
|
||||
<ul
|
||||
className="grid grid-cols-2 items-start gap-8 md:grid-cols-1 md:items-start md:space-y-0"
|
||||
role="list">
|
||||
{people.map((person) => (
|
||||
<li key={person.name}>
|
||||
<div className="space-y-4 sm:grid sm:grid-cols-4 sm:gap-6 sm:space-y-0 lg:gap-8">
|
||||
<div className="aspect-w-2 aspect-h-2 h-0">
|
||||
<img
|
||||
alt={person.name}
|
||||
className="rounded-lg object-cover shadow-lg"
|
||||
src={person.imageUrl}
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-3">
|
||||
<div className="space-y-4">
|
||||
<div className="text-md space-y-1 font-medium leading-6 sm:text-lg">
|
||||
<h3>{person.name}</h3>
|
||||
<p className="text-primary-600">{person.role}</p>
|
||||
</div>
|
||||
<div className="text-sm sm:text-lg">
|
||||
<p className="text-slate-500">{person.bio}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { signIn, useSession } from 'next-auth/react';
|
||||
import { useState } from 'react';
|
||||
@@ -45,53 +46,63 @@ export default function ProfilesDashboard() {
|
||||
|
||||
if (userProfiles.length === 0) {
|
||||
return (
|
||||
<div className="flex w-full">
|
||||
<div className="w-full justify-center space-y-8 py-16 text-xl">
|
||||
<div className="flex w-full flex-row justify-center">
|
||||
<h2>You have not saved any offer profiles yet.</h2>
|
||||
</div>
|
||||
<div className="flex flex-row justify-center">
|
||||
<Button
|
||||
label="Submit your offers now!"
|
||||
size="lg"
|
||||
variant="primary"
|
||||
onClick={() => router.push('/offers/submit')}
|
||||
/>
|
||||
<>
|
||||
<Head>
|
||||
<title>My Dashboard - Tech Offers Repo</title>
|
||||
</Head>
|
||||
<div className="flex w-full">
|
||||
<div className="w-full justify-center space-y-8 py-16 text-xl">
|
||||
<div className="flex w-full flex-row justify-center">
|
||||
<h2>You have not saved any offer profiles yet.</h2>
|
||||
</div>
|
||||
<div className="flex flex-row justify-center">
|
||||
<Button
|
||||
label="Submit your offers now!"
|
||||
size="lg"
|
||||
variant="primary"
|
||||
onClick={() => router.push('/offers/submit')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container variant="xs">
|
||||
{userProfilesQuery.isLoading && (
|
||||
<div className="flex h-screen">
|
||||
<div className="m-auto mx-auto w-full justify-center">
|
||||
<Spinner className="m-10" display="block" size="lg" />
|
||||
<>
|
||||
<Head>
|
||||
<title>My Dashboard - Tech Offers Repo</title>
|
||||
</Head>
|
||||
<Container variant="xs">
|
||||
{userProfilesQuery.isLoading && (
|
||||
<div className="flex h-screen">
|
||||
<div className="m-auto mx-auto w-full justify-center">
|
||||
<Spinner className="m-10" display="block" size="lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!userProfilesQuery.isLoading && (
|
||||
<div className="overflow-y-auto py-8">
|
||||
<h1 className="mx-auto mb-4 text-start text-4xl font-bold text-slate-900">
|
||||
Your dashboard
|
||||
</h1>
|
||||
<p className="mt-4 text-xl leading-8 text-slate-500">
|
||||
Save your offer profiles to your dashboard to easily access and edit
|
||||
them later.
|
||||
</p>
|
||||
<div className="mt-8 flex justify-center">
|
||||
<ul className="w-full space-y-4" role="list">
|
||||
{userProfiles?.map((profile) => (
|
||||
<li key={profile.id}>
|
||||
<DashboardProfileCard key={profile.id} profile={profile} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{!userProfilesQuery.isLoading && (
|
||||
<div className="overflow-y-auto py-8">
|
||||
<h1 className="mx-auto mb-4 text-start text-4xl font-bold text-slate-900">
|
||||
My dashboard
|
||||
</h1>
|
||||
<p className="mt-4 text-xl leading-8 text-slate-500">
|
||||
Save your offer profiles to your dashboard to easily access and
|
||||
edit them later.
|
||||
</p>
|
||||
<div className="mt-8 flex justify-center">
|
||||
<ul className="w-full space-y-4" role="list">
|
||||
{userProfiles?.map((profile) => (
|
||||
<li key={profile.id}>
|
||||
<DashboardProfileCard key={profile.id} profile={profile} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Head from 'next/head';
|
||||
import type { SVGProps } from 'react';
|
||||
import {
|
||||
BookmarkSquareIcon,
|
||||
@@ -82,176 +83,182 @@ const footerNavigation = {
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<div className="mx-auto w-full overflow-y-auto bg-white">
|
||||
<main>
|
||||
{/* Hero section */}
|
||||
<div className="relative h-full">
|
||||
<div className="relative px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8">
|
||||
<img
|
||||
alt="Tech Offers Repo"
|
||||
className="mx-auto mb-8 w-auto"
|
||||
src="/logos/offers-logo.svg"
|
||||
/>
|
||||
<h1 className="text-center text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
|
||||
<span>Choosing offers </span>
|
||||
<span className="from-primary-600 -mb-1 mr-2 bg-gradient-to-r to-purple-500 bg-clip-text pb-1 pr-4 italic text-transparent">
|
||||
made easier
|
||||
</span>
|
||||
</h1>
|
||||
<p className="mx-auto mt-6 max-w-lg text-center text-xl sm:max-w-3xl">
|
||||
Analyze your offers using profiles from fellow software engineers.
|
||||
</p>
|
||||
<div className="mx-auto mt-10 max-w-sm sm:flex sm:max-w-none sm:justify-center">
|
||||
<div className="space-y-4 sm:mx-auto sm:inline-grid sm:grid-cols-1 sm:gap-5 sm:space-y-0">
|
||||
<a
|
||||
className="border-grey-600 flex items-center justify-center rounded-md border bg-white px-4 py-3 text-base font-medium text-indigo-700 shadow-sm hover:bg-indigo-50 sm:px-8"
|
||||
href={HOME_URL}>
|
||||
Get started
|
||||
</a>
|
||||
{/* <a
|
||||
<>
|
||||
<Head>
|
||||
<title>Features - Tech Offers Repo</title>
|
||||
</Head>
|
||||
<div className="mx-auto w-full overflow-y-auto bg-white">
|
||||
<main>
|
||||
{/* Hero section */}
|
||||
<div className="relative h-full">
|
||||
<div className="relative px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8">
|
||||
<img
|
||||
alt="Tech Offers Repo"
|
||||
className="mx-auto mb-8 w-auto"
|
||||
src="/logos/offers-logo.svg"
|
||||
/>
|
||||
<h1 className="text-center text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
|
||||
<span>Choosing offers </span>
|
||||
<span className="from-primary-600 -mb-1 mr-2 bg-gradient-to-r to-purple-500 bg-clip-text pb-1 pr-4 italic text-transparent">
|
||||
made easier
|
||||
</span>
|
||||
</h1>
|
||||
<p className="mx-auto mt-6 max-w-lg text-center text-xl sm:max-w-3xl">
|
||||
Analyze your offers using profiles from fellow software
|
||||
engineers.
|
||||
</p>
|
||||
<div className="mx-auto mt-10 max-w-sm sm:flex sm:max-w-none sm:justify-center">
|
||||
<div className="space-y-4 sm:mx-auto sm:inline-grid sm:grid-cols-1 sm:gap-5 sm:space-y-0">
|
||||
<a
|
||||
className="border-grey-600 flex items-center justify-center rounded-md border bg-white px-4 py-3 text-base font-medium text-indigo-700 shadow-sm hover:bg-indigo-50 sm:px-8"
|
||||
href={HOME_URL}>
|
||||
Get started
|
||||
</a>
|
||||
{/* <a
|
||||
className="bg-primary-500 flex items-center justify-center rounded-md border border-transparent px-4 py-3 text-base font-medium text-white shadow-sm hover:bg-opacity-70 sm:px-8"
|
||||
href="#">
|
||||
Live demo
|
||||
</a> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alternating Feature Sections */}
|
||||
<div className="relative overflow-hidden pt-16 pb-32">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 top-0 h-48 bg-gradient-to-b from-gray-100"
|
||||
/>
|
||||
<div className="relative">
|
||||
<LeftTextCard
|
||||
buttonLabel="View offers"
|
||||
description="Filter relevant offers by job title, company, submission date, salary and more."
|
||||
icon={
|
||||
<TableCellsIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Browse page"
|
||||
imageSrc={offersBrowse}
|
||||
title="Stay informed of recent offers"
|
||||
url={HOME_URL}
|
||||
{/* Alternating Feature Sections */}
|
||||
<div className="relative overflow-hidden pt-16 pb-32">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 top-0 h-48 bg-gradient-to-b from-gray-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-36">
|
||||
<RightTextCard
|
||||
buttonLabel="Analyse offers"
|
||||
description="With our offer engine analysis, you can benchmark your offers against other offers on the market and make an informed decision."
|
||||
icon={
|
||||
<ChartBarSquareIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Offers analysis page"
|
||||
imageSrc={offersAnalysis}
|
||||
title="Better understand your offers"
|
||||
url={OFFERS_SUBMIT_URL}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-36">
|
||||
<LeftTextCard
|
||||
buttonLabel="View offer profiles"
|
||||
description="An offer profile includes not only offers that a person received in their application cycle, but also background information such as education and work experience. Use offer profiles to help you better contextualize offers."
|
||||
icon={
|
||||
<InformationCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Offer profile page"
|
||||
imageSrc={offersProfile}
|
||||
title="Choosing an offer needs context"
|
||||
url={HOME_URL}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Gradient Feature Section */}
|
||||
<div className="to-primary-600 bg-gradient-to-r from-purple-800">
|
||||
<div className="mx-auto max-w-4xl px-4 py-16 sm:px-6 sm:pt-20 sm:pb-24 lg:max-w-7xl lg:px-8 lg:pt-24">
|
||||
<h2 className="flex justify-center text-4xl font-bold tracking-tight text-white">
|
||||
Your privacy is our priority.
|
||||
</h2>
|
||||
<p className="text-primary-100 mt-4 flex flex-row justify-center text-lg">
|
||||
All offer profiles are anonymized and we do not store information
|
||||
about your personal identity.
|
||||
</p>
|
||||
<div className="mt-12 grid grid-cols-1 gap-x-6 gap-y-12 sm:grid-cols-2 lg:mt-16 lg:grid-cols-3 lg:gap-x-8 lg:gap-y-16">
|
||||
{features.map((feature) => (
|
||||
<div key={feature.name}>
|
||||
<div>
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-md bg-white bg-opacity-10">
|
||||
<feature.icon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<h3 className="text-lg font-medium text-white">
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="text-primary-100 mt-2 text-base">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="relative">
|
||||
<LeftTextCard
|
||||
buttonLabel="View offers"
|
||||
description="Filter relevant offers by job title, company, submission date, salary and more."
|
||||
icon={
|
||||
<TableCellsIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Browse page"
|
||||
imageSrc={offersBrowse}
|
||||
title="Stay informed of recent offers"
|
||||
url={HOME_URL}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-36">
|
||||
<RightTextCard
|
||||
buttonLabel="Analyse offers"
|
||||
description="With our offer engine analysis, you can benchmark your offers against other offers on the market and make an informed decision."
|
||||
icon={
|
||||
<ChartBarSquareIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Offers analysis page"
|
||||
imageSrc={offersAnalysis}
|
||||
title="Better understand your offers"
|
||||
url={OFFERS_SUBMIT_URL}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-36">
|
||||
<LeftTextCard
|
||||
buttonLabel="View offer profiles"
|
||||
description="An offer profile includes not only offers that a person received in their application cycle, but also background information such as education and work experience. Use offer profiles to help you better contextualize offers."
|
||||
icon={
|
||||
<InformationCircleIcon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
}
|
||||
imageAlt="Offer profile page"
|
||||
imageSrc={offersProfile}
|
||||
title="Choosing an offer needs context"
|
||||
url={HOME_URL}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA Section */}
|
||||
<div className="bg-white">
|
||||
<div className="mx-auto max-w-4xl py-16 px-4 sm:px-6 sm:py-24 lg:flex lg:max-w-7xl lg:items-center lg:justify-between lg:px-8">
|
||||
<h2 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-4xl">
|
||||
<span className="block">Ready to get started?</span>
|
||||
<span className="to-primary-600 -mb-1 block bg-gradient-to-r from-purple-600 bg-clip-text pb-1 text-transparent">
|
||||
Create your own offer profile today.
|
||||
</span>
|
||||
</h2>
|
||||
<div className="mt-6 space-y-4 sm:flex sm:space-y-0 sm:space-x-5">
|
||||
<a
|
||||
className="to-primary-500 flex items-center justify-center rounded-md border border-transparent bg-gradient-to-r from-purple-600 bg-origin-border px-4 py-3 text-base font-medium text-white shadow-sm hover:from-purple-700 hover:to-indigo-700"
|
||||
href={OFFERS_SUBMIT_URL}>
|
||||
Get Started
|
||||
</a>
|
||||
{/* Gradient Feature Section */}
|
||||
<div className="to-primary-600 bg-gradient-to-r from-purple-800">
|
||||
<div className="mx-auto max-w-4xl px-4 py-16 sm:px-6 sm:pt-20 sm:pb-24 lg:max-w-7xl lg:px-8 lg:pt-24">
|
||||
<h2 className="flex justify-center text-4xl font-bold tracking-tight text-white">
|
||||
Your privacy is our priority.
|
||||
</h2>
|
||||
<p className="text-primary-100 mt-4 flex flex-row justify-center text-lg">
|
||||
All offer profiles are anonymized and we do not store
|
||||
information about your personal identity.
|
||||
</p>
|
||||
<div className="mt-12 grid grid-cols-1 gap-x-6 gap-y-12 sm:grid-cols-2 lg:mt-16 lg:grid-cols-3 lg:gap-x-8 lg:gap-y-16">
|
||||
{features.map((feature) => (
|
||||
<div key={feature.name}>
|
||||
<div>
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-md bg-white bg-opacity-10">
|
||||
<feature.icon
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<h3 className="text-lg font-medium text-white">
|
||||
{feature.name}
|
||||
</h3>
|
||||
<p className="text-primary-100 mt-2 text-base">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer aria-labelledby="footer-heading" className="bg-gray-50">
|
||||
<h2 className="sr-only" id="footer-heading">
|
||||
Footer
|
||||
</h2>
|
||||
<div className="mx-auto max-w-7xl px-4 pt-0 pb-8 sm:px-6 lg:px-8">
|
||||
<div className="mt-12 border-t border-gray-200 pt-8 md:flex md:items-center md:justify-between lg:mt-16">
|
||||
<div className="flex space-x-6 md:order-2">
|
||||
{footerNavigation.social.map((item) => (
|
||||
{/* CTA Section */}
|
||||
<div className="bg-white">
|
||||
<div className="mx-auto max-w-4xl py-16 px-4 sm:px-6 sm:py-24 lg:flex lg:max-w-7xl lg:items-center lg:justify-between lg:px-8">
|
||||
<h2 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-4xl">
|
||||
<span className="block">Ready to get started?</span>
|
||||
<span className="to-primary-600 -mb-1 block bg-gradient-to-r from-purple-600 bg-clip-text pb-1 text-transparent">
|
||||
Create your own offer profile today.
|
||||
</span>
|
||||
</h2>
|
||||
<div className="mt-6 space-y-4 sm:flex sm:space-y-0 sm:space-x-5">
|
||||
<a
|
||||
key={item.name}
|
||||
className="text-gray-400 hover:text-gray-500"
|
||||
href={item.href}>
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon aria-hidden="true" className="h-6 w-6" />
|
||||
className="to-primary-500 flex items-center justify-center rounded-md border border-transparent bg-gradient-to-r from-purple-600 bg-origin-border px-4 py-3 text-base font-medium text-white shadow-sm hover:from-purple-700 hover:to-indigo-700"
|
||||
href={OFFERS_SUBMIT_URL}>
|
||||
Get Started
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-8 text-base text-gray-400 md:order-1 md:mt-0">
|
||||
© 2022 Tech Offers Repo. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer aria-labelledby="footer-heading" className="bg-gray-50">
|
||||
<h2 className="sr-only" id="footer-heading">
|
||||
Footer
|
||||
</h2>
|
||||
<div className="mx-auto max-w-7xl px-4 pt-0 pb-8 sm:px-6 lg:px-8">
|
||||
<div className="mt-12 border-t border-gray-200 pt-8 md:flex md:items-center md:justify-between lg:mt-16">
|
||||
<div className="flex space-x-6 md:order-2">
|
||||
{footerNavigation.social.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
className="text-gray-400 hover:text-gray-500"
|
||||
href={item.href}>
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon aria-hidden="true" className="h-6 w-6" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-8 text-base text-gray-400 md:order-1 md:mt-0">
|
||||
© 2022 Tech Offers Repo. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Head from 'next/head';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { MapPinIcon } from '@heroicons/react/24/outline';
|
||||
@@ -27,118 +28,123 @@ export default function OffersHomePage() {
|
||||
useSearchParamSingle<JobTitleType | null>('jobTitleId');
|
||||
|
||||
return (
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<Banner size="sm">
|
||||
⭐ Check if your offer is competitive by submitting it{' '}
|
||||
<Link className="underline" href="/offers/submit">
|
||||
here
|
||||
</Link>
|
||||
. ⭐
|
||||
</Banner>
|
||||
<div className="text-primary-600 flex items-center justify-end space-x-1 bg-slate-100 px-4 pt-4 sm:text-lg">
|
||||
<span>
|
||||
<MapPinIcon className="flex h-7 w-7" />
|
||||
</span>
|
||||
<CountriesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Countries"
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setCountryFilter(option.value);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_country_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by country',
|
||||
});
|
||||
} else {
|
||||
setCountryFilter('');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-slate-100 py-16 px-4">
|
||||
<div>
|
||||
<>
|
||||
<Head>
|
||||
<title>Home - Tech Offers Repo</title>
|
||||
</Head>
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<Banner size="sm">
|
||||
⭐ Check if your offer is competitive by submitting it{' '}
|
||||
<Link className="underline" href="/offers/submit">
|
||||
here
|
||||
</Link>
|
||||
. ⭐
|
||||
</Banner>
|
||||
<div className="text-primary-600 flex items-center justify-end space-x-1 bg-slate-100 px-4 pt-4 sm:text-lg">
|
||||
<span>
|
||||
<MapPinIcon className="flex h-7 w-7" />
|
||||
</span>
|
||||
<CountriesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Countries"
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setCountryFilter(option.value);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_country_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by country',
|
||||
});
|
||||
} else {
|
||||
setCountryFilter('');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-slate-100 py-16 px-4">
|
||||
<div>
|
||||
<h1 className="text-primary-600 text-center text-4xl font-bold sm:text-5xl">
|
||||
Tech Offers Repo
|
||||
</h1>
|
||||
<div>
|
||||
<h1 className="text-primary-600 text-center text-4xl font-bold sm:text-5xl">
|
||||
Tech Offers Repo
|
||||
</h1>
|
||||
</div>
|
||||
<div className="mt-4 text-center text-lg text-slate-600 sm:text-2xl">
|
||||
Find out how good your offer is. Discover how others got their
|
||||
offers.
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 text-center text-lg text-slate-600 sm:text-2xl">
|
||||
Find out how good your offer is. Discover how others got their
|
||||
offers.
|
||||
<div className="mt-6 flex flex-col items-center justify-center space-y-2 text-sm text-slate-700 sm:mt-10 sm:flex-row sm:space-y-0 sm:space-x-4 sm:text-lg">
|
||||
<span>Viewing offers for</span>
|
||||
<div className="flex items-center space-x-4">
|
||||
<JobTitlesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Job Titles"
|
||||
textSize="inherit"
|
||||
value={
|
||||
selectedJobTitleId
|
||||
? {
|
||||
id: selectedJobTitleId,
|
||||
label: getLabelForJobTitleType(
|
||||
selectedJobTitleId as JobTitleType,
|
||||
),
|
||||
value: selectedJobTitleId,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setSelectedJobTitleId(option.id as JobTitleType);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_job_title_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by job title',
|
||||
});
|
||||
} else {
|
||||
setSelectedJobTitleId(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>in</span>
|
||||
<CompaniesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Companies"
|
||||
textSize="inherit"
|
||||
value={
|
||||
selectedCompanyName
|
||||
? {
|
||||
id: selectedCompanyId,
|
||||
label: selectedCompanyName,
|
||||
value: selectedCompanyId,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setSelectedCompanyId(option.id);
|
||||
setSelectedCompanyName(option.label);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_company_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by company',
|
||||
});
|
||||
} else {
|
||||
setSelectedCompanyId('');
|
||||
setSelectedCompanyName('');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 flex flex-col items-center justify-center space-y-2 text-sm text-slate-700 sm:mt-10 sm:flex-row sm:space-y-0 sm:space-x-4 sm:text-lg">
|
||||
<span>Viewing offers for</span>
|
||||
<div className="flex items-center space-x-4">
|
||||
<JobTitlesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Job Titles"
|
||||
textSize="inherit"
|
||||
value={
|
||||
selectedJobTitleId
|
||||
? {
|
||||
id: selectedJobTitleId,
|
||||
label: getLabelForJobTitleType(
|
||||
selectedJobTitleId as JobTitleType,
|
||||
),
|
||||
value: selectedJobTitleId,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setSelectedJobTitleId(option.id as JobTitleType);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_job_title_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by job title',
|
||||
});
|
||||
} else {
|
||||
setSelectedJobTitleId(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span>in</span>
|
||||
<CompaniesTypeahead
|
||||
isLabelHidden={true}
|
||||
placeholder="All Companies"
|
||||
textSize="inherit"
|
||||
value={
|
||||
selectedCompanyName
|
||||
? {
|
||||
id: selectedCompanyId,
|
||||
label: selectedCompanyName,
|
||||
value: selectedCompanyId,
|
||||
}
|
||||
: null
|
||||
}
|
||||
onSelect={(option) => {
|
||||
if (option) {
|
||||
setSelectedCompanyId(option.id);
|
||||
setSelectedCompanyName(option.label);
|
||||
gaEvent({
|
||||
action: `offers.table_filter_company_${option.value}`,
|
||||
category: 'engagement',
|
||||
label: 'Filter by company',
|
||||
});
|
||||
} else {
|
||||
setSelectedCompanyId('');
|
||||
setSelectedCompanyName('');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Container className="pb-20 pt-10">
|
||||
<OffersTable
|
||||
companyFilter={selectedCompanyId}
|
||||
companyName={selectedCompanyName}
|
||||
countryFilter={countryFilter}
|
||||
jobTitleFilter={selectedJobTitleId ?? ''}
|
||||
/>
|
||||
</Container>
|
||||
</main>
|
||||
<Container className="pb-20 pt-10">
|
||||
<OffersTable
|
||||
companyFilter={selectedCompanyId}
|
||||
companyName={selectedCompanyName}
|
||||
countryFilter={countryFilter}
|
||||
jobTitleFilter={selectedJobTitleId ?? ''}
|
||||
/>
|
||||
</Container>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Error from 'next/error';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useState } from 'react';
|
||||
@@ -201,42 +202,49 @@ export default function OfferProfile() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full divide-x lg:flex">
|
||||
<div className="divide-y lg:w-2/3">
|
||||
<div className="h-fit">
|
||||
<ProfileHeader
|
||||
background={background}
|
||||
handleDelete={handleDelete}
|
||||
isEditable={isEditable}
|
||||
isLoading={getProfileQuery.isLoading}
|
||||
selectedTab={selectedTab}
|
||||
setSelectedTab={setSelectedTab}
|
||||
/>
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
{background?.profileName ? background.profileName : 'View profile'}
|
||||
</title>
|
||||
</Head>
|
||||
<div className="w-full divide-x lg:flex">
|
||||
<div className="divide-y lg:w-2/3">
|
||||
<div className="h-fit">
|
||||
<ProfileHeader
|
||||
background={background}
|
||||
handleDelete={handleDelete}
|
||||
isEditable={isEditable}
|
||||
isLoading={getProfileQuery.isLoading}
|
||||
selectedTab={selectedTab}
|
||||
setSelectedTab={setSelectedTab}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<ProfileDetails
|
||||
analysis={analysis}
|
||||
background={background}
|
||||
isEditable={isEditable}
|
||||
isLoading={getProfileQuery.isLoading}
|
||||
offers={offers}
|
||||
profileId={offerProfileId as string}
|
||||
selectedTab={selectedTab}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ProfileDetails
|
||||
analysis={analysis}
|
||||
background={background}
|
||||
<div
|
||||
className="bg-white lg:fixed lg:right-0 lg:bottom-0 lg:w-1/3"
|
||||
style={{ top: 64 }}>
|
||||
<ProfileComments
|
||||
isDisabled={deleteMutation.isLoading}
|
||||
isEditable={isEditable}
|
||||
isLoading={getProfileQuery.isLoading}
|
||||
offers={offers}
|
||||
profileId={offerProfileId as string}
|
||||
selectedTab={selectedTab}
|
||||
profileName={background?.profileName}
|
||||
token={token as string}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="bg-white lg:fixed lg:right-0 lg:bottom-0 lg:w-1/3"
|
||||
style={{ top: 64 }}>
|
||||
<ProfileComments
|
||||
isDisabled={deleteMutation.isLoading}
|
||||
isEditable={isEditable}
|
||||
isLoading={getProfileQuery.isLoading}
|
||||
profileId={offerProfileId as string}
|
||||
profileName={background?.profileName}
|
||||
token={token as string}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Error from 'next/error';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import { JobType } from '@prisma/client';
|
||||
@@ -88,6 +89,9 @@ export default function OffersEditPage() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Edit profile</title>
|
||||
</Head>
|
||||
{getProfileResult.isError && (
|
||||
<div className="flex w-full justify-center">
|
||||
<Error statusCode={404} title="Requested profile does not exist" />
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
import OffersSubmissionForm from '~/components/offers/offersSubmission/OffersSubmissionForm';
|
||||
|
||||
export default function OffersSubmissionPage() {
|
||||
return <OffersSubmissionForm />;
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Analyze your offers</title>
|
||||
</Head>
|
||||
<OffersSubmissionForm />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import Head from 'next/head';
|
||||
|
||||
import OffersSubmissionForm from '~/components/offers/offersSubmission/OffersSubmissionForm';
|
||||
|
||||
export default function OffersSubmissionPage() {
|
||||
return <OffersSubmissionForm />;
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Analyze your offers</title>
|
||||
</Head>
|
||||
<OffersSubmissionForm />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Error from 'next/error';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
@@ -92,52 +93,57 @@ export default function OffersSubmissionResult() {
|
||||
title="You do not have permissions to access this page"
|
||||
/>
|
||||
) : (
|
||||
<div ref={pageRef} className="w-full">
|
||||
<div className="flex justify-center">
|
||||
<div className="block w-full max-w-screen-md overflow-hidden rounded-lg sm:shadow-lg md:my-10">
|
||||
<div className="flex justify-center bg-slate-100 px-4 py-4 sm:px-6 lg:px-8">
|
||||
<Breadcrumbs
|
||||
currentStep={step}
|
||||
setStep={setStep}
|
||||
steps={breadcrumbSteps}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-white p-6 sm:p-10">
|
||||
{steps[step]}
|
||||
{step === 0 && (
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
disabled={false}
|
||||
icon={ArrowRightIcon}
|
||||
label="Next"
|
||||
variant="primary"
|
||||
onClick={() => setStep(step + 1)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{step === 1 && (
|
||||
<div className="flex items-center justify-between">
|
||||
<Button
|
||||
addonPosition="start"
|
||||
icon={ArrowLeftIcon}
|
||||
label="Previous"
|
||||
variant="secondary"
|
||||
onClick={() => setStep(step - 1)}
|
||||
/>
|
||||
<Button
|
||||
href={getProfilePath(
|
||||
offerProfileId as string,
|
||||
token as string,
|
||||
)}
|
||||
icon={EyeIcon}
|
||||
label="View your profile"
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<>
|
||||
<Head>
|
||||
<title>View the result</title>
|
||||
</Head>
|
||||
<div ref={pageRef} className="w-full">
|
||||
<div className="flex justify-center">
|
||||
<div className="block w-full max-w-screen-md overflow-hidden rounded-lg sm:shadow-lg md:my-10">
|
||||
<div className="flex justify-center bg-slate-100 px-4 py-4 sm:px-6 lg:px-8">
|
||||
<Breadcrumbs
|
||||
currentStep={step}
|
||||
setStep={setStep}
|
||||
steps={breadcrumbSteps}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-white p-6 sm:p-10">
|
||||
{steps[step]}
|
||||
{step === 0 && (
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
disabled={false}
|
||||
icon={ArrowRightIcon}
|
||||
label="Next"
|
||||
variant="primary"
|
||||
onClick={() => setStep(step + 1)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{step === 1 && (
|
||||
<div className="flex items-center justify-between">
|
||||
<Button
|
||||
addonPosition="start"
|
||||
icon={ArrowLeftIcon}
|
||||
label="Previous"
|
||||
variant="secondary"
|
||||
onClick={() => setStep(step - 1)}
|
||||
/>
|
||||
<Button
|
||||
href={getProfilePath(
|
||||
offerProfileId as string,
|
||||
token as string,
|
||||
)}
|
||||
icon={EyeIcon}
|
||||
label="View your profile"
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user