[questions][ui] revamp landing page look

pull/411/head
Jeff Sieu 3 years ago
parent db8379bdc8
commit 1609355544

@ -1,13 +1,15 @@
import { useState } from 'react'; import { useEffect, useState } from 'react';
import { ArrowSmallRightIcon } from '@heroicons/react/24/outline'; import { ArrowSmallRightIcon } from '@heroicons/react/24/outline';
import type { QuestionsQuestionType } from '@prisma/client'; import type { QuestionsQuestionType } from '@prisma/client';
import { Button, Select } from '@tih/ui'; import { Button, Select } from '@tih/ui';
import { import { QUESTION_TYPES } from '~/utils/questions/constants';
COMPANIES, import useDefaultCompany from '~/utils/questions/useDefaultCompany';
LOCATIONS, import useDefaultLocation from '~/utils/questions/useDefaultLocation';
QUESTION_TYPES,
} from '~/utils/questions/constants'; import type { FilterChoice } from './filter/FilterSection';
import CompanyTypeahead from './typeahead/CompanyTypeahead';
import LocationTypeahead from './typeahead/LocationTypeahead';
export type LandingQueryData = { export type LandingQueryData = {
company: string; company: string;
@ -22,76 +24,109 @@ export type LandingComponentProps = {
export default function LandingComponent({ export default function LandingComponent({
onLanded: handleLandingQuery, onLanded: handleLandingQuery,
}: LandingComponentProps) { }: LandingComponentProps) {
const [landingQueryData, setLandingQueryData] = useState<LandingQueryData>({ const defaultCompany = useDefaultCompany();
company: 'Google', const defaultLocation = useDefaultLocation();
location: 'Singapore',
questionType: 'CODING', const [company, setCompany] = useState<FilterChoice | undefined>(
}); defaultCompany,
);
const [location, setLocation] = useState<FilterChoice | undefined>(
defaultLocation,
);
const [questionType, setQuestionType] =
useState<QuestionsQuestionType>('CODING');
const handleChangeCompany = (company: string) => { const handleChangeCompany = (newCompany: FilterChoice) => {
setLandingQueryData((prev) => ({ ...prev, company })); setCompany(newCompany);
}; };
const handleChangeLocation = (location: string) => { const handleChangeLocation = (newLocation: FilterChoice) => {
setLandingQueryData((prev) => ({ ...prev, location })); setCompany(newLocation);
}; };
const handleChangeType = (questionType: QuestionsQuestionType) => { const handleChangeType = (newQuestionType: QuestionsQuestionType) => {
setLandingQueryData((prev) => ({ ...prev, questionType })); setQuestionType(newQuestionType);
}; };
useEffect(() => {
if (company === undefined) {
setCompany(defaultCompany);
}
}, [defaultCompany, company]);
useEffect(() => {
if (location !== undefined) {
setLocation(defaultLocation);
}
}, [defaultLocation, location]);
return ( return (
<main className="flex flex-1 flex-col items-stretch overflow-y-auto bg-white"> <main className="flex flex-1 flex-col items-center overflow-y-auto bg-white">
<div className="pb-4"></div> <div className="flex flex-1 flex-col items-start justify-center gap-12 px-4">
<div className="flex flex-1 flex-col justify-center gap-3"> <header className="flex flex-col items-start">
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<img alt="app logo" className=" h-20 w-20" src="/logo.svg"></img> <h1 className="text-3xl font-semibold text-slate-900">
<h1 className="text-primary-600 p-4 text-center text-5xl font-bold">
Tech Interview Question Bank Tech Interview Question Bank
</h1> </h1>
<img alt="app logo" className="h-20 w-20" src="/logo.svg"></img>
</div> </div>
<p className="mx-auto max-w-lg p-6 text-center text-xl text-black sm:max-w-3xl"> <p className="mb-2 max-w-lg text-5xl font-semibold text-slate-900 sm:max-w-3xl">
Get to know the latest SWE interview questions asked by top companies Know the{' '}
<span className="text-primary-700">
latest SWE interview questions
</span>{' '}
asked by top companies.
</p> </p>
</header>
<div className="mx-auto flex max-w-lg items-baseline gap-3 p-4 text-center text-xl text-black sm:max-w-3xl"> <div className="flex flex-col items-start gap-3 text-xl font-semibold text-slate-900">
<p>Find</p> <p className="text-3xl">Find questions</p>
<div className=" space-x-2"> <div className="grid grid-cols-2">
<p className="text-slate-600">about</p>
<Select <Select
isLabelHidden={true} isLabelHidden={true}
label="Type" label="Type"
options={QUESTION_TYPES} options={QUESTION_TYPES}
value={landingQueryData.questionType} value={questionType}
onChange={(value) => { onChange={(value) => {
handleChangeType(value.toUpperCase() as QuestionsQuestionType); handleChangeType(value.toUpperCase() as QuestionsQuestionType);
}} }}
/> />
</div> <p className="text-slate-600">from</p>
<p>questions from</p> <CompanyTypeahead
<Select
isLabelHidden={true} isLabelHidden={true}
label="Company" value={company}
options={COMPANIES} onSelect={(value) => {
value={landingQueryData.company} handleChangeCompany(value);
onChange={handleChangeCompany} }}
/> />
<p>in</p> <p className="text-slate-600">in</p>
<Select <LocationTypeahead
isLabelHidden={true} isLabelHidden={true}
label="Location" value={location}
options={LOCATIONS} onSelect={(value) => {
value={landingQueryData.location} handleChangeLocation(value);
onChange={handleChangeLocation} }}
/> />
</div>
<Button <Button
addonPosition="end" addonPosition="end"
icon={ArrowSmallRightIcon} icon={ArrowSmallRightIcon}
label="Go" label="Go"
size="md" size="md"
variant="primary" variant="primary"
onClick={() => handleLandingQuery(landingQueryData)}></Button> onClick={() => {
if (company !== undefined && location !== undefined) {
return handleLandingQuery({
company: company.value,
location: location.value,
questionType,
});
}
}}
/>
</div> </div>
<div className="flex justify-center p-4"> <div className="flex justify-center">
<iframe <iframe
height={30} height={30}
src="https://ghbtns.com/github-btn.html?user=yangshun&amp;repo=tech-interview-handbook&amp;type=star&amp;count=true&amp;size=large" src="https://ghbtns.com/github-btn.html?user=yangshun&amp;repo=tech-interview-handbook&amp;type=star&amp;count=true&amp;size=large"

@ -3,15 +3,18 @@ import type { UseFormRegisterReturn } from 'react-hook-form';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { CheckboxInput, Collapsible, RadioList } from '@tih/ui'; import { CheckboxInput, Collapsible, RadioList } from '@tih/ui';
export type FilterOption<V extends string = string> = { export type FilterChoice<V extends string = string> = {
checked: boolean;
id: string; id: string;
label: string; label: string;
value: V; value: V;
}; };
export type FilterOption<V extends string = string> = FilterChoice<V> & {
checked: boolean;
};
export type FilterChoices<V extends string = string> = ReadonlyArray< export type FilterChoices<V extends string = string> = ReadonlyArray<
Omit<FilterOption<V>, 'checked'> FilterChoice<V>
>; >;
type FilterSectionType<FilterOptions extends Array<FilterOption>> = type FilterSectionType<FilterOptions extends Array<FilterOption>> =

@ -89,8 +89,6 @@ export default function ContributeQuestionForm({
render={({ field }) => ( render={({ field }) => (
<LocationTypeahead <LocationTypeahead
required={true} required={true}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={(option) => { onSelect={(option) => {
field.onChange(option.value); field.onChange(option.value);
}} }}
@ -143,8 +141,6 @@ export default function ContributeQuestionForm({
render={({ field }) => ( render={({ field }) => (
<RoleTypeahead <RoleTypeahead
required={true} required={true}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={(option) => { onSelect={(option) => {
field.onChange(option.value); field.onChange(option.value);
}} }}

@ -59,8 +59,6 @@ export default function CreateQuestionEncounterForm({
isLabelHidden={true} isLabelHidden={true}
placeholder="Other location" placeholder="Other location"
suggestedCount={3} suggestedCount={3}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: location }) => { onSelect={({ value: location }) => {
setSelectedLocation(location); setSelectedLocation(location);
}} }}
@ -77,8 +75,6 @@ export default function CreateQuestionEncounterForm({
isLabelHidden={true} isLabelHidden={true}
placeholder="Other role" placeholder="Other role"
suggestedCount={3} suggestedCount={3}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: role }) => { onSelect={({ value: role }) => {
setSelectedRole(role); setSelectedRole(role);
}} }}

@ -5,7 +5,7 @@ import ExpandedTypeahead from './ExpandedTypeahead';
export type LocationTypeaheadProps = Omit< export type LocationTypeaheadProps = Omit<
ExpandedTypeaheadProps, ExpandedTypeaheadProps,
'label' | 'options' 'label' | 'onQueryChange' | 'options'
>; >;
export default function LocationTypeahead(props: LocationTypeaheadProps) { export default function LocationTypeahead(props: LocationTypeaheadProps) {
@ -14,6 +14,8 @@ export default function LocationTypeahead(props: LocationTypeaheadProps) {
{...(props as ExpandedTypeaheadProps)} {...(props as ExpandedTypeaheadProps)}
label="Location" label="Location"
options={LOCATIONS} options={LOCATIONS}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
/> />
); );
} }

@ -5,7 +5,7 @@ import ExpandedTypeahead from './ExpandedTypeahead';
export type RoleTypeaheadProps = Omit< export type RoleTypeaheadProps = Omit<
ExpandedTypeaheadProps, ExpandedTypeaheadProps,
'label' | 'options' 'label' | 'onQueryChange' | 'options'
>; >;
export default function RoleTypeahead(props: RoleTypeaheadProps) { export default function RoleTypeahead(props: RoleTypeaheadProps) {
@ -14,6 +14,8 @@ export default function RoleTypeahead(props: RoleTypeaheadProps) {
{...(props as ExpandedTypeaheadProps)} {...(props as ExpandedTypeaheadProps)}
label="Role" label="Role"
options={ROLES} options={ROLES}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
/> />
); );
} }

@ -0,0 +1,22 @@
import type { FilterChoice } from '~/components/questions/filter/FilterSection';
import { trpc } from '../trpc';
export default function useDefaultCompany(): FilterChoice | undefined {
const { data: companies } = trpc.useQuery([
'companies.list',
{
name: '',
},
]);
const company = companies?.[0];
if (company === undefined) {
return company;
}
return {
id: company.id,
label: company.name,
value: company.id,
};
}

@ -0,0 +1,7 @@
import type { FilterChoice } from '~/components/questions/filter/FilterSection';
import { LOCATIONS } from './constants';
export default function useDefaultLocation(): FilterChoice | undefined {
return LOCATIONS[0];
}
Loading…
Cancel
Save