[resumes][fix] fix merge conflicts

pull/506/head
Keane Chan 3 years ago
parent 80dbfe39a1
commit 87f85c1ff8
No known key found for this signature in database
GPG Key ID: 32718398E1E9F87C

@ -43,7 +43,6 @@
"react-query": "^3.39.2", "react-query": "^3.39.2",
"read-excel-file": "^5.5.3", "read-excel-file": "^5.5.3",
"superjson": "^1.10.0", "superjson": "^1.10.0",
"xlsx": "^0.18.5",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"xlsx": "^0.18.5", "xlsx": "^0.18.5",
"zod": "^3.18.0" "zod": "^3.18.0"

@ -15,7 +15,6 @@ import {
PencilSquareIcon, PencilSquareIcon,
StarIcon, StarIcon,
} from '@heroicons/react/20/solid'; } from '@heroicons/react/20/solid';
import type { TypeaheadOption } from '@tih/ui';
import { Button, Spinner } from '@tih/ui'; import { Button, Spinner } from '@tih/ui';
import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';
@ -27,11 +26,9 @@ import loginPageHref from '~/components/shared/loginPageHref';
import { import {
BROWSE_TABS_VALUES, BROWSE_TABS_VALUES,
EXPERIENCES,
getFilterLabel, getFilterLabel,
getTypeaheadOption,
INITIAL_FILTER_STATE, INITIAL_FILTER_STATE,
LOCATIONS,
ROLES,
} from '~/utils/resumes/resumeFilters'; } from '~/utils/resumes/resumeFilters';
import { trpc } from '~/utils/trpc'; import { trpc } from '~/utils/trpc';
@ -121,27 +118,24 @@ export default function ResumeReviewPage() {
}; };
const onInfoTagClick = ({ const onInfoTagClick = ({
locationLabel, locationName,
experienceLabel, locationValue,
roleLabel, experienceValue,
roleValue,
}: { }: {
experienceLabel?: string; experienceValue?: string;
locationLabel?: string; locationName?: string;
roleLabel?: string; locationValue?: string;
roleValue?: string;
}) => { }) => {
const getFilterValue = (
label: string,
filterOptions: Array<TypeaheadOption>,
) => filterOptions.find((option) => option.label === label)?.value;
router.push({ router.push({
pathname: '/resumes', pathname: '/resumes',
query: { query: {
currentPage: JSON.stringify(1), currentPage: JSON.stringify(1),
isFiltersOpen: JSON.stringify({ isFiltersOpen: JSON.stringify({
experience: experienceLabel !== undefined, experience: experienceValue !== undefined,
location: locationLabel !== undefined, location: locationValue !== undefined,
role: roleLabel !== undefined, role: roleValue !== undefined,
}), }),
searchValue: JSON.stringify(''), searchValue: JSON.stringify(''),
shortcutSelected: JSON.stringify('all'), shortcutSelected: JSON.stringify('all'),
@ -149,14 +143,16 @@ export default function ResumeReviewPage() {
tabsValue: JSON.stringify(BROWSE_TABS_VALUES.ALL), tabsValue: JSON.stringify(BROWSE_TABS_VALUES.ALL),
userFilters: JSON.stringify({ userFilters: JSON.stringify({
...INITIAL_FILTER_STATE, ...INITIAL_FILTER_STATE,
...(locationLabel && { ...(locationValue && {
location: [getFilterValue(locationLabel, LOCATIONS)], location: [
getTypeaheadOption('location', locationValue, locationName),
],
}), }),
...(roleLabel && { ...(roleValue && {
role: [getFilterValue(roleLabel, ROLES)], role: [getTypeaheadOption('role', roleValue)],
}), }),
...(experienceLabel && { ...(experienceValue && {
experience: [getFilterValue(experienceLabel, EXPERIENCES)], experience: [getTypeaheadOption('experience', experienceValue)],
}), }),
}), }),
}, },
@ -318,92 +314,71 @@ export default function ResumeReviewPage() {
<div className="hidden xl:block">{renderReviewButton()}</div> <div className="hidden xl:block">{renderReviewButton()}</div>
</div> </div>
</div> </div>
</div> <div className="space-y-2">
<div className="flex flex-col lg:mt-0 lg:flex-row lg:flex-wrap lg:space-x-8"> <div className="grid grid-cols-2 gap-2 lg:flex lg:flex-wrap lg:space-x-8">
<div className="mt-2 flex items-center text-sm text-slate-600 xl:mt-1"> <div className="col-span-1 flex items-center text-xs text-slate-600 sm:text-sm">
<BriefcaseIcon <BriefcaseIcon
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400"
/> />
<button <button
className="hover:text-primary-800 underline" className="hover:text-primary-800 underline"
type="button" type="button"
onClick={() => onClick={() =>
onInfoTagClick({ onInfoTagClick({
roleLabel: detailsQuery.data?.role, roleValue: detailsQuery.data?.role,
}) })
}> }>
{getFilterLabel('role', detailsQuery.data.role)} {getFilterLabel('role', detailsQuery.data.role)}
</button> </button>
</div> </div>
<div className="flex items-center pt-2 text-sm text-slate-600 xl:pt-1"> <div className="col-span-1 flex items-center text-xs text-slate-600 sm:text-sm">
<MapPinIcon <MapPinIcon
aria-hidden="true" aria-hidden="true"
className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400" className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400"
/> />
<button <button
className="hover:text-primary-800 underline" className="hover:text-primary-800 underline"
type="button" type="button"
onClick={() => onClick={() =>
onInfoTagClick({ onInfoTagClick({
locationLabel: detailsQuery.data?.locationId, locationName: detailsQuery.data?.location.name,
}) locationValue: detailsQuery.data?.locationId,
}> })
{detailsQuery.data?.location.name} }>
</button> {detailsQuery.data?.location.name}
</div> </button>
<div className="flex items-center pt-2 text-sm text-slate-600 xl:pt-1"> </div>
<AcademicCapIcon <div className="col-span-1 flex items-center text-xs text-slate-600 sm:text-sm">
aria-hidden="true" <AcademicCapIcon
className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400" aria-hidden="true"
/> className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400"
<button />
className="hover:text-primary-800 underline" <button
type="button" className="hover:text-primary-800 underline"
onClick={() => type="button"
onInfoTagClick({ onClick={() =>
experienceLabel: detailsQuery.data?.experience, onInfoTagClick({
}) experienceValue: detailsQuery.data?.experience,
}> })
{getFilterLabel('experience', detailsQuery.data.experience)} }>
</button> {getFilterLabel(
</div> 'experience',
<div className="flex items-center pt-2 text-sm text-slate-600 xl:pt-1"> detailsQuery.data.experience,
<CalendarIcon )}
aria-hidden="true" </button>
className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400" </div>
/> <div className="col-span-1 flex items-center text-xs text-slate-600 sm:text-sm">
{`Uploaded ${formatDistanceToNow(detailsQuery.data.createdAt, { <CalendarIcon
addSuffix: true, aria-hidden="true"
})} by ${detailsQuery.data.user.name}`} className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400"
</div> />
</div> {`Uploaded ${formatDistanceToNow(
{detailsQuery.data.additionalInfo && ( detailsQuery.data.createdAt,
<div className="flex items-start whitespace-pre-wrap pt-2 text-sm text-slate-600 xl:pt-1"> {
<InformationCircleIcon addSuffix: true,
aria-hidden="true" },
className="mr-1.5 h-5 w-5 flex-shrink-0 text-indigo-400" )} by ${detailsQuery.data.user.name}`}
/>
<ResumeExpandableText
key={detailsQuery.data.additionalInfo}
text={detailsQuery.data.additionalInfo}
/>
</div>
)}
<div className="flex w-full flex-col gap-6 py-4 xl:flex-row xl:py-0">
<div className="w-full xl:w-1/2">
<ResumePdf url={detailsQuery.data.url} />
</div>
<div className="grow">
<div className="mb-6 space-y-4 xl:hidden">
{renderReviewButton()}
<div className="flex items-center space-x-2">
<hr className="flex-grow border-slate-300" />
<span className="bg-slate-50 px-3 text-lg font-medium text-slate-900">
Reviews
</span>
<hr className="flex-grow border-slate-300" />
</div> </div>
</div> </div>
{detailsQuery.data.additionalInfo && ( {detailsQuery.data.additionalInfo && (

@ -30,21 +30,12 @@ import ResumeRoleTypeahead from '~/components/resumes/shared/ResumeRoleTypeahead
import ResumeSignInButton from '~/components/resumes/shared/ResumeSignInButton'; import ResumeSignInButton from '~/components/resumes/shared/ResumeSignInButton';
import loginPageHref from '~/components/shared/loginPageHref'; import loginPageHref from '~/components/shared/loginPageHref';
import type { import type { Filter, FilterId, Shortcut } from '~/utils/resumes/resumeFilters';
Filter, import type { SortOrder } from '~/utils/resumes/resumeFilters';
FilterId,
FilterLabel,
Shortcut,
} from '~/utils/resumes/resumeFilters';
import type { FilterState, SortOrder } from '~/utils/resumes/resumeFilters';
import { import {
BROWSE_TABS_VALUES, BROWSE_TABS_VALUES,
EXPERIENCES,
getFilterLabel, getFilterLabel,
INITIAL_FILTER_STATE, INITIAL_FILTER_STATE,
isInitialFilterState,
LOCATIONS,
ROLES,
SHORTCUTS, SHORTCUTS,
SORT_OPTIONS, SORT_OPTIONS,
} from '~/utils/resumes/resumeFilters'; } from '~/utils/resumes/resumeFilters';
@ -59,17 +50,14 @@ const filters: Array<Filter> = [
{ {
id: 'role', id: 'role',
label: 'Role', label: 'Role',
options: ROLES,
}, },
{ {
id: 'experience', id: 'experience',
label: 'Experience', label: 'Experience',
options: EXPERIENCES,
}, },
{ {
id: 'location', id: 'location',
label: 'Location', label: 'Location',
options: LOCATIONS,
}, },
]; ];
@ -84,20 +72,14 @@ const getLoggedOutText = (tabsValue: string) => {
} }
}; };
const getEmptyDataText = ( const getEmptyDataText = (tabsValue: string, searchValue: string) => {
tabsValue: string,
searchValue: string,
userFilters: FilterState,
) => {
if (searchValue.length > 0) { if (searchValue.length > 0) {
return 'Try tweaking your search text to see more resumes.'; return 'Try tweaking your search text to see more resumes.';
} }
if (!isInitialFilterState(userFilters)) {
return 'Try tweaking your filters to see more resumes.';
}
switch (tabsValue) { switch (tabsValue) {
case BROWSE_TABS_VALUES.ALL: case BROWSE_TABS_VALUES.ALL:
return "There's nothing to see here..."; return 'Oops, there is no resumes to see here. Maybe try tweaking your filters to see more.';
case BROWSE_TABS_VALUES.STARRED: case BROWSE_TABS_VALUES.STARRED:
return 'You have not starred any resumes. Star one to see it here!'; return 'You have not starred any resumes. Star one to see it here!';
case BROWSE_TABS_VALUES.MY: case BROWSE_TABS_VALUES.MY:
@ -387,12 +369,16 @@ export default function ResumeHomePage() {
} }
}; };
const getFilterCount = (filter: FilterLabel, value: string) => { const getFilterCount = (filterId: FilterId, value: string) => {
const filterCountsData = getTabFilterCounts(); const filterCountsData = getTabFilterCounts();
if (!filterCountsData) { if (
filterCountsData === undefined ||
filterCountsData[filterId] === undefined ||
filterCountsData[filterId][value] === undefined
) {
return 0; return 0;
} }
return filterCountsData[filter][value]; return filterCountsData[filterId][value];
}; };
return ( return (
@ -498,7 +484,7 @@ export default function ResumeHomePage() {
{userFilters[filter.id].map((option) => ( {userFilters[filter.id].map((option) => (
<div <div
key={option.value} key={option.value}
className="[&>div>div:nth-child(1)>input]:text-primary-600 [&>div>div:nth-child(1)>input]:ring-primary-500 flex items-center px-1 text-sm [&>div>div:nth-child(2)>label]:font-normal"> className="flex items-center px-1 text-sm">
<CheckboxInput <CheckboxInput
label={option.label} label={option.label}
value={true} value={true}
@ -515,11 +501,7 @@ export default function ResumeHomePage() {
} }
/> />
<span className="ml-1 text-slate-500"> <span className="ml-1 text-slate-500">
( ({getFilterCount(filter.id, option.value)}
{getFilterCount(
filter.label,
option.label,
)}
) )
</span> </span>
</div> </div>
@ -615,7 +597,7 @@ export default function ResumeHomePage() {
{userFilters[filter.id].map((option) => ( {userFilters[filter.id].map((option) => (
<div <div
key={option.value} key={option.value}
className="[&>div>div:nth-child(1)>input]:text-primary-600 [&>div>div:nth-child(1)>input]:ring-primary-500 flex items-center px-1 text-sm [&>div>div:nth-child(2)>label]:font-normal"> className="flex items-center px-1 text-sm">
<CheckboxInput <CheckboxInput
label={option.label} label={option.label}
value={true} value={true}
@ -631,9 +613,7 @@ export default function ResumeHomePage() {
} }
/> />
<span className="ml-1 text-slate-500"> <span className="ml-1 text-slate-500">
( ({getFilterCount(filter.id, option.value)})
{getFilterCount(filter.label, option.label)}
)
</span> </span>
</div> </div>
))} ))}
@ -740,7 +720,7 @@ export default function ResumeHomePage() {
height={196} height={196}
width={196} width={196}
/> />
{getEmptyDataText(tabsValue, searchValue, userFilters)} {getEmptyDataText(tabsValue, searchValue)}
</div> </div>
) : ( ) : (
<div> <div>

@ -1,8 +1,6 @@
import { z } from 'zod'; import { z } from 'zod';
import { Vote } from '@prisma/client'; import { Vote } from '@prisma/client';
import { EXPERIENCES, LOCATIONS, ROLES } from '~/utils/resumes/resumeFilters';
import { createRouter } from '../context'; import { createRouter } from '../context';
import type { Resume } from '~/types/resume'; import type { Resume } from '~/types/resume';
@ -98,6 +96,7 @@ export const resumesRouter = createRouter()
isResolved: r.isResolved, isResolved: r.isResolved,
isStarredByUser: r.stars.length > 0, isStarredByUser: r.stars.length > 0,
location: r.location.name, location: r.location.name,
locationId: r.locationId,
numComments: r._count.comments, numComments: r._count.comments,
numStars: r._count.stars, numStars: r._count.stars,
role: r.role, role: r.role,
@ -127,20 +126,6 @@ export const resumesRouter = createRouter()
roleCounts.map((rc) => [rc.role, rc._count._all]), roleCounts.map((rc) => [rc.role, rc._count._all]),
); );
// Filter out roles with zero counts and map to object where key = role and value = 0
const zeroRoleCounts = Object.fromEntries(
ROLES.filter((r) => !(r.value in mappedRoleCounts)).map((r) => [
r.value,
0,
]),
);
// Combine to form singular role counts object
const processedRoleCounts = {
...mappedRoleCounts,
...zeroRoleCounts,
};
const experienceCounts = await ctx.prisma.resumesResume.groupBy({ const experienceCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
_all: true, _all: true,
@ -156,15 +141,6 @@ export const resumesRouter = createRouter()
const mappedExperienceCounts = Object.fromEntries( const mappedExperienceCounts = Object.fromEntries(
experienceCounts.map((ec) => [ec.experience, ec._count._all]), experienceCounts.map((ec) => [ec.experience, ec._count._all]),
); );
const zeroExperienceCounts = Object.fromEntries(
EXPERIENCES.filter((e) => !(e.value in mappedExperienceCounts)).map(
(e) => [e.value, 0],
),
);
const processedExperienceCounts = {
...mappedExperienceCounts,
...zeroExperienceCounts,
};
const locationCounts = await ctx.prisma.resumesResume.groupBy({ const locationCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
@ -181,21 +157,11 @@ export const resumesRouter = createRouter()
const mappedLocationCounts = Object.fromEntries( const mappedLocationCounts = Object.fromEntries(
locationCounts.map((lc) => [lc.locationId, lc._count._all]), locationCounts.map((lc) => [lc.locationId, lc._count._all]),
); );
const zeroLocationCounts = Object.fromEntries(
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
l.value,
0,
]),
);
const processedLocationCounts = {
...mappedLocationCounts,
...zeroLocationCounts,
};
const filterCounts = { const filterCounts = {
Experience: processedExperienceCounts, experience: mappedExperienceCounts,
Location: processedLocationCounts, location: mappedLocationCounts,
Role: processedRoleCounts, role: mappedRoleCounts,
}; };
return { return {

@ -1,7 +1,5 @@
import { z } from 'zod'; import { z } from 'zod';
import { EXPERIENCES, LOCATIONS, ROLES } from '~/utils/resumes/resumeFilters';
import { createProtectedRouter } from '../context'; import { createProtectedRouter } from '../context';
import type { Resume } from '~/types/resume'; import type { Resume } from '~/types/resume';
@ -165,6 +163,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
isResolved: rs.resume.isResolved, isResolved: rs.resume.isResolved,
isStarredByUser: true, isStarredByUser: true,
location: rs.resume.location.name, location: rs.resume.location.name,
locationId: rs.resume.locationId,
numComments: rs.resume._count.comments, numComments: rs.resume._count.comments,
numStars: rs.resume._count.stars, numStars: rs.resume._count.stars,
role: rs.resume.role, role: rs.resume.role,
@ -195,16 +194,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedRoleCounts = Object.fromEntries( const mappedRoleCounts = Object.fromEntries(
roleCounts.map((rc) => [rc.role, rc._count._all]), roleCounts.map((rc) => [rc.role, rc._count._all]),
); );
const zeroRoleCounts = Object.fromEntries(
ROLES.filter((r) => !(r.value in mappedRoleCounts)).map((r) => [
r.value,
0,
]),
);
const processedRoleCounts = {
...mappedRoleCounts,
...zeroRoleCounts,
};
const experienceCounts = await ctx.prisma.resumesResume.groupBy({ const experienceCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
@ -226,15 +215,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedExperienceCounts = Object.fromEntries( const mappedExperienceCounts = Object.fromEntries(
experienceCounts.map((ec) => [ec.experience, ec._count._all]), experienceCounts.map((ec) => [ec.experience, ec._count._all]),
); );
const zeroExperienceCounts = Object.fromEntries(
EXPERIENCES.filter((e) => !(e.value in mappedExperienceCounts)).map(
(e) => [e.value, 0],
),
);
const processedExperienceCounts = {
...mappedExperienceCounts,
...zeroExperienceCounts,
};
const locationCounts = await ctx.prisma.resumesResume.groupBy({ const locationCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
@ -256,21 +236,11 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedLocationCounts = Object.fromEntries( const mappedLocationCounts = Object.fromEntries(
locationCounts.map((lc) => [lc.locationId, lc._count._all]), locationCounts.map((lc) => [lc.locationId, lc._count._all]),
); );
const zeroLocationCounts = Object.fromEntries(
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
l.value,
0,
]),
);
const processedLocationCounts = {
...mappedLocationCounts,
...zeroLocationCounts,
};
const filterCounts = { const filterCounts = {
Experience: processedExperienceCounts, experience: mappedExperienceCounts,
Location: processedLocationCounts, location: mappedLocationCounts,
Role: processedRoleCounts, role: mappedRoleCounts,
}; };
return { filterCounts, mappedResumeData, totalRecords }; return { filterCounts, mappedResumeData, totalRecords };
@ -365,6 +335,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
isResolved: r.isResolved, isResolved: r.isResolved,
isStarredByUser: r.stars.length > 0, isStarredByUser: r.stars.length > 0,
location: r.location.name, location: r.location.name,
locationId: r.locationId,
numComments: r._count.comments, numComments: r._count.comments,
numStars: r._count.stars, numStars: r._count.stars,
role: r.role, role: r.role,
@ -391,16 +362,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedRoleCounts = Object.fromEntries( const mappedRoleCounts = Object.fromEntries(
roleCounts.map((rc) => [rc.role, rc._count._all]), roleCounts.map((rc) => [rc.role, rc._count._all]),
); );
const zeroRoleCounts = Object.fromEntries(
ROLES.filter((r) => !(r.value in mappedRoleCounts)).map((r) => [
r.value,
0,
]),
);
const processedRoleCounts = {
...mappedRoleCounts,
...zeroRoleCounts,
};
const experienceCounts = await ctx.prisma.resumesResume.groupBy({ const experienceCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
@ -418,15 +379,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedExperienceCounts = Object.fromEntries( const mappedExperienceCounts = Object.fromEntries(
experienceCounts.map((ec) => [ec.experience, ec._count._all]), experienceCounts.map((ec) => [ec.experience, ec._count._all]),
); );
const zeroExperienceCounts = Object.fromEntries(
EXPERIENCES.filter((e) => !(e.value in mappedExperienceCounts)).map(
(e) => [e.value, 0],
),
);
const processedExperienceCounts = {
...mappedExperienceCounts,
...zeroExperienceCounts,
};
const locationCounts = await ctx.prisma.resumesResume.groupBy({ const locationCounts = await ctx.prisma.resumesResume.groupBy({
_count: { _count: {
@ -444,21 +396,11 @@ export const resumesResumeUserRouter = createProtectedRouter()
const mappedLocationCounts = Object.fromEntries( const mappedLocationCounts = Object.fromEntries(
locationCounts.map((lc) => [lc.locationId, lc._count._all]), locationCounts.map((lc) => [lc.locationId, lc._count._all]),
); );
const zeroLocationCounts = Object.fromEntries(
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
l.value,
0,
]),
);
const processedLocationCounts = {
...mappedLocationCounts,
...zeroLocationCounts,
};
const filterCounts = { const filterCounts = {
Experience: processedExperienceCounts, experience: mappedExperienceCounts,
Location: processedLocationCounts, location: mappedLocationCounts,
Role: processedRoleCounts, role: mappedRoleCounts,
}; };
return { filterCounts, mappedResumeData, totalRecords }; return { filterCounts, mappedResumeData, totalRecords };

@ -6,6 +6,7 @@ export type Resume = {
isResolved: boolean; isResolved: boolean;
isStarredByUser: boolean; isStarredByUser: boolean;
location: string; location: string;
locationId: string;
numComments: number; numComments: number;
numStars: number; numStars: number;
role: string; role: string;

@ -4,7 +4,6 @@ import type { JobTitleType } from '~/components/shared/JobTitles';
import { JobTitleLabels } from '~/components/shared/JobTitles'; import { JobTitleLabels } from '~/components/shared/JobTitles';
export type FilterId = 'experience' | 'location' | 'role'; export type FilterId = 'experience' | 'location' | 'role';
export type FilterLabel = 'Experience' | 'Location' | 'Role';
export type CustomFilter = { export type CustomFilter = {
isUnreviewed: boolean; isUnreviewed: boolean;
@ -17,8 +16,7 @@ export type FilterOption<T> = {
export type Filter = { export type Filter = {
id: FilterId; id: FilterId;
label: FilterLabel; label: string;
options: Array<TypeaheadOption>;
}; };
export type FilterState = CustomFilter & export type FilterState = CustomFilter &
@ -33,6 +31,31 @@ export type Shortcut = {
sortOrder: SortOrder; sortOrder: SortOrder;
}; };
export const getTypeaheadOption = (
filterId: FilterId,
filterValue: string,
locationName?: string,
) => {
switch (filterId) {
case 'experience':
return EXPERIENCES.find(({ value }) => value === filterValue);
case 'role':
return {
id: filterValue,
label: JobTitleLabels[filterValue as keyof typeof JobTitleLabels],
value: filterValue,
};
case 'location':
return {
id: filterValue,
label: locationName ?? '',
value: filterValue,
};
default:
break;
}
};
export const BROWSE_TABS_VALUES = { export const BROWSE_TABS_VALUES = {
ALL: 'all', ALL: 'all',
MY: 'my', MY: 'my',
@ -54,12 +77,20 @@ const INITIAL_ROLES_VALUES: Array<JobTitleType> = [
'android-engineer', 'android-engineer',
'data-engineer', 'data-engineer',
]; ];
export const INITIAL_ROLES: Array<TypeaheadOption> = INITIAL_ROLES_VALUES.map(
(value) =>
getTypeaheadOption('role', value) ?? {
id: value,
label: value,
value,
},
);
export const EXPERIENCES: Array<TypeaheadOption> = [ export const EXPERIENCES: Array<TypeaheadOption> = [
{ {
id: 'internship', id: 'internship',
label: 'Internship', label: 'Internship',
value: 'Internship', value: 'internship',
}, },
{ {
id: 'entry-level', id: 'entry-level',
@ -69,21 +100,26 @@ export const EXPERIENCES: Array<TypeaheadOption> = [
{ {
id: 'mid-level', id: 'mid-level',
label: 'Mid Level (3 - 5 years)', label: 'Mid Level (3 - 5 years)',
value: 'Mid Level (3 - 5 years)', value: 'mid-level',
}, },
{ {
id: 'Senior Level (5+ years)', id: 'senior-level',
label: 'Senior Level (5+ years)', label: 'Senior Level (5+ years)',
value: 'Senior Level (5+ years)', value: 'senior-level',
}, },
]; ];
export const LOCATIONS: Array<TypeaheadOption> = [ export const INITIAL_LOCATIONS: Array<TypeaheadOption> = [
{ {
id: '196', id: '196',
label: 'Singapore', label: 'Singapore',
value: '196', value: '196',
}, },
{
id: '101',
label: 'India',
value: '101',
},
{ {
id: '231', id: '231',
label: 'United States', label: 'United States',
@ -109,8 +145,8 @@ export const LOCATIONS: Array<TypeaheadOption> = [
export const INITIAL_FILTER_STATE: FilterState = { export const INITIAL_FILTER_STATE: FilterState = {
experience: EXPERIENCES, experience: EXPERIENCES,
isUnreviewed: true, isUnreviewed: true,
location: LOCATIONS, location: INITIAL_LOCATIONS,
role: ROLES, role: INITIAL_ROLES,
}; };
export const SHORTCUTS: Array<Shortcut> = [ export const SHORTCUTS: Array<Shortcut> = [
@ -119,7 +155,7 @@ export const SHORTCUTS: Array<Shortcut> = [
...INITIAL_FILTER_STATE, ...INITIAL_FILTER_STATE,
isUnreviewed: false, isUnreviewed: false,
}, },
name: 'All', name: 'General',
sortOrder: 'latest', sortOrder: 'latest',
}, },
{ {
@ -133,7 +169,13 @@ export const SHORTCUTS: Array<Shortcut> = [
{ {
filters: { filters: {
...INITIAL_FILTER_STATE, ...INITIAL_FILTER_STATE,
experience: [], experience: [
{
id: 'entry-level',
label: 'Entry Level (0 - 2 years)',
value: 'entry-level',
},
],
isUnreviewed: false, isUnreviewed: false,
}, },
name: 'Fresh Grad', name: 'Fresh Grad',
@ -151,25 +193,22 @@ export const SHORTCUTS: Array<Shortcut> = [
filters: { filters: {
...INITIAL_FILTER_STATE, ...INITIAL_FILTER_STATE,
isUnreviewed: false, isUnreviewed: false,
location: [], location: [
{
id: '231',
label: 'United States',
value: '231',
},
],
}, },
name: 'US Only', name: 'US Only',
sortOrder: 'latest', sortOrder: 'latest',
}, },
]; ];
export const isInitialFilterState = (filters: FilterState) => // We omit 'location' as its label should be fetched from the Country table.
Object.keys(filters).every((filter) => {
if (!['experience', 'location', 'role'].includes(filter)) {
return true;
}
return INITIAL_FILTER_STATE[filter as FilterId].every((value) =>
filters[filter as FilterId].includes(value),
);
});
export const getFilterLabel = ( export const getFilterLabel = (
filterId: FilterId | 'sort', filterId: Omit<FilterId | 'sort', 'location'>,
filterValue: SortOrder | string, filterValue: SortOrder | string,
): string | undefined => { ): string | undefined => {
if (filterId === 'location') { if (filterId === 'location') {

Loading…
Cancel
Save