[offers][fix] improve table UX

pull/535/head
Yangshun Tay 2 years ago
parent b0c7006a2d
commit a225b9ba93

@ -61,7 +61,7 @@ function ProfileJewel() {
<Menu.Button className="focus:ring-primary-500 flex rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-offset-2">
<span className="sr-only">Open user menu</span>
{session?.user?.image == null ? (
<span>Render some icon</span>
<span>TODO: Render some icon</span>
) : (
<img
alt={session?.user?.email ?? session?.user?.name ?? ''}

@ -35,7 +35,7 @@ export default function OfferTableRow({
<tr key={id} className="divide-x divide-slate-200 border-b bg-white">
<td className="space-y-0.5 py-4 px-4" scope="row">
<div className="font-medium">{company.name}</div>
<div className="text-xs text-slate-400">
<div className="text-xs text-slate-500">
{location.cityName} ({location.countryCode})
</div>
</td>

@ -1,6 +1,6 @@
import clsx from 'clsx';
import { useRouter } from 'next/router';
import { useEffect, useMemo, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { JobType } from '@prisma/client';
import { DropdownMenu, Spinner, useToast } from '@tih/ui';
@ -23,13 +23,15 @@ import OffersRow from './OffersRow';
import type { DashboardOffer, GetOffersResponse, Paging } from '~/types/offers';
const NUMBER_OF_OFFERS_IN_PAGE = 10;
const NUMBER_OF_OFFERS_PER_PAGE = 20;
export type OffersTableProps = Readonly<{
companyFilter: string;
companyName?: string;
countryFilter: string;
jobTitleFilter: string;
}>;
export default function OffersTable({
countryFilter,
companyName,
@ -101,15 +103,16 @@ export default function OffersTable({
pathname,
]);
const topRef = useRef<HTMLDivElement>(null);
const { showToast } = useToast();
trpc.useQuery(
const { isLoading: isResultsLoading } = trpc.useQuery(
[
'offers.list',
{
companyId: companyFilter,
countryId: countryFilter,
currency,
limit: NUMBER_OF_OFFERS_IN_PAGE,
limit: NUMBER_OF_OFFERS_PER_PAGE,
offset: pagination.currentPage,
sortBy: selectedSortBy ?? '-monthYearReceived',
title: jobTitleFilter,
@ -257,17 +260,27 @@ export default function OffersTable({
};
return (
<div className="relative w-full border border-slate-200">
{renderFilters()}
<div className="relative w-full divide-y divide-slate-200 border border-slate-200 bg-white">
<div ref={topRef}>{renderFilters()}</div>
<OffersTablePagination
endNumber={
pagination.currentPage * NUMBER_OF_OFFERS_PER_PAGE + offers.length
}
handlePageChange={handlePageChange}
isInitialFetch={isLoading}
isLoading={isResultsLoading}
pagination={pagination}
startNumber={pagination.currentPage * NUMBER_OF_OFFERS_PER_PAGE + 1}
/>
{isLoading ? (
<div className="col-span-10 py-32">
<Spinner display="block" size="lg" />
</div>
) : (
<div className="overflow-x-auto text-slate-600">
<table className="w-full divide-y divide-slate-200 border-y border-slate-200 text-left text-xs text-slate-700 sm:text-sm md:text-base">
<table className="w-full divide-y divide-slate-200 text-left text-xs text-slate-700 sm:text-sm">
{renderHeader()}
<tbody>
<tbody className="divide-y divide-slate-200">
{offers.map((offer) => (
<OffersRow key={offer.id} jobType={jobType} row={offer} />
))}
@ -283,11 +296,18 @@ export default function OffersTable({
)}
<OffersTablePagination
endNumber={
pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + offers.length
pagination.currentPage * NUMBER_OF_OFFERS_PER_PAGE + offers.length
}
handlePageChange={handlePageChange}
handlePageChange={(number) => {
topRef?.current?.scrollIntoView({
block: 'start',
});
handlePageChange(number);
}}
isInitialFetch={isLoading}
isLoading={isResultsLoading}
pagination={pagination}
startNumber={pagination.currentPage * NUMBER_OF_OFFERS_IN_PAGE + 1}
startNumber={pagination.currentPage * NUMBER_OF_OFFERS_PER_PAGE + 1}
/>
</div>
);

@ -1,37 +1,51 @@
import { useEffect, useState } from 'react';
import { Pagination } from '@tih/ui';
import { Pagination, Spinner } from '@tih/ui';
import type { Paging } from '~/types/offers';
type OffersTablePaginationProps = Readonly<{
endNumber: number;
handlePageChange: (page: number) => void;
isInitialFetch?: boolean;
isLoading?: boolean;
pagination: Paging;
startNumber: number;
}>;
export default function OffersTablePagination({
isInitialFetch,
isLoading,
endNumber,
pagination,
startNumber,
handlePageChange,
}: OffersTablePaginationProps) {
const [screenWidth, setScreenWidth] = useState(0);
useEffect(() => {
setScreenWidth(window.innerWidth);
}, []);
return (
<nav aria-label="Table navigation" className="p-4">
<div className="flex grid grid-cols-1 items-center md:grid-cols-2">
<div className="mb-2 text-sm font-normal text-slate-500 md:mb-0">
Showing
<span className="font-semibold text-slate-900">
{` ${endNumber > 0 ? startNumber : 0} - ${endNumber} `}
</span>
{`of `}
<span className="font-semibold text-slate-900">
{pagination.totalItems}
</span>
<nav aria-label="Offers Pagination" className="py-3 px-4">
<div className="grid grid-cols-1 items-center gap-2 md:grid-cols-2">
<div>
{!isInitialFetch && (
<div className="flex items-center space-x-2">
<div className="text-sm text-slate-500">
Showing
<span className="font-semibold text-slate-900">
{` ${endNumber > 0 ? startNumber : 0} - ${endNumber} `}
</span>
{`of `}
<span className="font-semibold text-slate-900">
{pagination.totalItems}
</span>{' '}
results
</div>
{isLoading && <Spinner size="xs" />}
</div>
)}
</div>
<div className="flex md:justify-end">
<Pagination

Loading…
Cancel
Save