[offers][refactor] improve offers table responsiveness

pull/492/head
Yangshun Tay 2 years ago
parent ab7f064734
commit 55e93102de

@ -7,7 +7,7 @@ import OffersTablePagination from '~/components/offers/table/OffersTablePaginati
import { import {
OfferTableFilterOptions, OfferTableFilterOptions,
OfferTableSortBy, OfferTableSortBy,
OfferTableTabOptions, OfferTableYoeOptions,
YOE_CATEGORY, YOE_CATEGORY,
} from '~/components/offers/table/types'; } from '~/components/offers/table/types';
@ -29,7 +29,7 @@ export default function OffersTable({
jobTitleFilter, jobTitleFilter,
}: OffersTableProps) { }: OffersTableProps) {
const [currency, setCurrency] = useState(Currency.SGD.toString()); // TODO: Detect location const [currency, setCurrency] = useState(Currency.SGD.toString()); // TODO: Detect location
const [selectedTab, setSelectedTab] = useState(YOE_CATEGORY.ENTRY); const [selectedYoe, setSelectedYoe] = useState(YOE_CATEGORY.ENTRY);
const [pagination, setPagination] = useState<Paging>({ const [pagination, setPagination] = useState<Paging>({
currentPage: 0, currentPage: 0,
numOfItems: 0, numOfItems: 0,
@ -48,7 +48,7 @@ export default function OffersTable({
numOfPages: 0, numOfPages: 0,
totalItems: 0, totalItems: 0,
}); });
}, [selectedTab, currency]); }, [selectedYoe, currency]);
const offersQuery = trpc.useQuery( const offersQuery = trpc.useQuery(
[ [
'offers.list', 'offers.list',
@ -60,7 +60,7 @@ export default function OffersTable({
offset: pagination.currentPage, offset: pagination.currentPage,
sortBy: OfferTableSortBy[selectedFilter] ?? '-monthYearReceived', sortBy: OfferTableSortBy[selectedFilter] ?? '-monthYearReceived',
title: jobTitleFilter, title: jobTitleFilter,
yoeCategory: selectedTab, yoeCategory: selectedYoe,
}, },
], ],
{ {
@ -76,22 +76,15 @@ export default function OffersTable({
function renderFilters() { function renderFilters() {
return ( return (
<div className="m-4 flex grid grid-cols-1 items-center justify-between gap-6 sm:grid-cols-4"> <div className="flex items-center justify-between p-4 text-sm sm:grid-cols-4 md:text-base">
<DropdownMenu <DropdownMenu align="start" label="Filters" size="inherit">
align="start" {OfferTableYoeOptions.map(({ label: itemLabel, value }) => (
label={
OfferTableTabOptions.filter(
({ value: itemValue }) => itemValue === selectedTab,
)[0].label
}
size="inherit">
{OfferTableTabOptions.map(({ label: itemLabel, value }) => (
<DropdownMenu.Item <DropdownMenu.Item
key={value} key={value}
isSelected={value === selectedTab} isSelected={value === selectedYoe}
label={itemLabel} label={itemLabel}
onClick={() => { onClick={() => {
setSelectedTab(value); setSelectedYoe(value);
gaEvent({ gaEvent({
action: `offers.table_filter_yoe_category_${value}`, action: `offers.table_filter_yoe_category_${value}`,
category: 'engagement', category: 'engagement',
@ -103,7 +96,9 @@ export default function OffersTable({
</DropdownMenu> </DropdownMenu>
<div className="divide-x-slate-200 col-span-3 flex items-center justify-end space-x-4 divide-x"> <div className="divide-x-slate-200 col-span-3 flex items-center justify-end space-x-4 divide-x">
<div className="justify-left flex items-center space-x-2"> <div className="justify-left flex items-center space-x-2">
<span>View all offers in</span> <span className="sr-only sm:not-sr-only sm:inline">
View all offers in
</span>
<CurrencySelector <CurrencySelector
handleCurrencyChange={(value: string) => setCurrency(value)} handleCurrencyChange={(value: string) => setCurrency(value)}
selectedCurrency={currency} selectedCurrency={currency}
@ -140,7 +135,7 @@ export default function OffersTable({
'Company', 'Company',
'Title', 'Title',
'YOE', 'YOE',
selectedTab === YOE_CATEGORY.INTERN ? 'Monthly Salary' : 'Annual TC', selectedYoe === YOE_CATEGORY.INTERN ? 'Monthly Salary' : 'Annual TC',
'Date Offered', 'Date Offered',
'Actions', 'Actions',
]; ];
@ -172,34 +167,32 @@ export default function OffersTable({
}; };
return ( return (
<div className="w-5/6"> <div className="relative w-full border border-slate-200">
<div className="relative w-full border border-slate-200"> {renderFilters()}
{renderFilters()} {offersQuery.isLoading ? (
{offersQuery.isLoading ? ( <div className="col-span-10 pt-4">
<div className="col-span-10 pt-4"> <Spinner display="block" size="lg" />
<Spinner display="block" size="lg" /> </div>
</div> ) : (
) : ( <div className="overflow-x-auto">
<div className="overflow-x-auto"> <table className="w-full divide-y divide-slate-200 border-y border-slate-200 text-left text-slate-600">
<table className="w-full divide-y divide-slate-200 border-y border-slate-200 text-left text-slate-600"> {renderHeader()}
{renderHeader()} <tbody>
<tbody> {offers.map((offer) => (
{offers.map((offer) => ( <OffersRow key={offer.id} row={offer} />
<OffersRow key={offer.id} row={offer} /> ))}
))} </tbody>
</tbody> </table>
</table> </div>
</div> )}
)} <OffersTablePagination
<OffersTablePagination endNumber={
endNumber={ pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + offers.length
pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + offers.length }
} handlePageChange={handlePageChange}
handlePageChange={handlePageChange} pagination={pagination}
pagination={pagination} startNumber={pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + 1}
startNumber={pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + 1} />
/>
</div>
</div> </div>
); );
} }

@ -6,7 +6,7 @@ export enum YOE_CATEGORY {
SENIOR = 3, SENIOR = 3,
} }
export const OfferTableTabOptions = [ export const OfferTableYoeOptions = [
{ {
label: 'Fresh Grad (0-2 YOE)', label: 'Fresh Grad (0-2 YOE)',
value: YOE_CATEGORY.ENTRY, value: YOE_CATEGORY.ENTRY,

@ -0,0 +1,26 @@
import clsx from 'clsx';
import React from 'react';
type Props = Readonly<{
children: React.ReactNode;
className?: string;
variant?: 'narrow' | 'normal';
}>;
export default function Container({
children,
className,
variant = 'normal',
}: Props) {
return (
<div
className={clsx(
'mx-auto px-4 sm:px-6 lg:px-8',
variant === 'normal' && 'max-w-7xl',
variant === 'narrow' && 'max-w-6xl',
className,
)}>
{children}
</div>
);
}

@ -5,10 +5,14 @@ import { Banner } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
import OffersTable from '~/components/offers/table/OffersTable'; import OffersTable from '~/components/offers/table/OffersTable';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead'; import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import Container from '~/components/shared/Container';
import type { JobTitleType } from '~/components/shared/JobTitles';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead'; import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
export default function OffersHomePage() { export default function OffersHomePage() {
const [jobTitleFilter, setjobTitleFilter] = useState('software-engineer'); const [jobTitleFilter, setJobTitleFilter] = useState<JobTitleType | ''>(
'software-engineer',
);
const [companyFilter, setCompanyFilter] = useState(''); const [companyFilter, setCompanyFilter] = useState('');
const { event: gaEvent } = useGoogleAnalytics(); const { event: gaEvent } = useGoogleAnalytics();
@ -42,14 +46,14 @@ export default function OffersHomePage() {
textSize="inherit" textSize="inherit"
onSelect={(option) => { onSelect={(option) => {
if (option) { if (option) {
setjobTitleFilter(option.value); setJobTitleFilter(option.value as JobTitleType);
gaEvent({ gaEvent({
action: `offers.table_filter_job_title_${option.value}`, action: `offers.table_filter_job_title_${option.value}`,
category: 'engagement', category: 'engagement',
label: 'Filter by job title', label: 'Filter by job title',
}); });
} else { } else {
setjobTitleFilter(''); setJobTitleFilter('');
} }
}} }}
/> />
@ -74,12 +78,12 @@ export default function OffersHomePage() {
</div> </div>
</div> </div>
</div> </div>
<div className="flex justify-center bg-white pb-20 pt-10"> <Container className="pb-20 pt-10">
<OffersTable <OffersTable
companyFilter={companyFilter} companyFilter={companyFilter}
jobTitleFilter={jobTitleFilter} jobTitleFilter={jobTitleFilter}
/> />
</div> </Container>
</main> </main>
); );
} }

@ -19,7 +19,8 @@ export default function Banner({ children, size = 'md', onHide }: Props) {
size === 'xs' && 'text-xs', size === 'xs' && 'text-xs',
)}> )}>
<div className="mx-auto max-w-7xl py-2 px-3 sm:px-6 lg:px-8"> <div className="mx-auto max-w-7xl py-2 px-3 sm:px-6 lg:px-8">
<div className="pr-16 sm:px-16 sm:text-center"> <div
className={clsx('text-center sm:px-16', onHide != null && 'pr-16')}>
<p className="font-medium text-white">{children}</p> <p className="font-medium text-white">{children}</p>
</div> </div>
{onHide != null && ( {onHide != null && (

Loading…
Cancel
Save