[portal][feat] add ranking to job titles typeahead

pull/519/head
Yangshun Tay 2 years ago
parent ac215dcbff
commit 79500b8a35

@ -3,7 +3,7 @@ import { useFormContext, useWatch } from 'react-hook-form';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypeahead';
type Props = Omit<
ComponentProps<typeof JobTitlesTypeahead>,
@ -21,11 +21,15 @@ export default function FormJobTitlesTypeahead({ name, ...props }: Props) {
return (
<JobTitlesTypeahead
{...props}
value={{
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}}
value={
watchJobTitle
? {
id: watchJobTitle,
label: getLabelForJobTitleType(watchJobTitle as JobTitleType),
value: watchJobTitle,
}
: null
}
onSelect={(option) => {
setValue(name, option?.value);
}}

@ -12,7 +12,7 @@ export type RoleTypeaheadProps = Omit<
>;
const ROLES: FilterChoices = Object.entries(JobTitleLabels).map(
([slug, label]) => ({
([slug, { label }]) => ({
id: slug,
label,
value: slug,

@ -30,7 +30,7 @@ export default function ResumeRoleTypeahead({
}: Props) {
const [query, setQuery] = useState('');
const options = Object.entries(JobTitleLabels)
.map(([slug, label]) => ({
.map(([slug, { label }]) => ({
id: slug,
label,
value: slug,

@ -1,56 +1,82 @@
export const JobTitleLabels = {
'ai-engineer': 'Artificial Intelligence (AI) Engineer',
'algorithms-engineer': 'Algorithms Engineer',
'android-engineer': 'Android Software Engineer',
'applications-engineer': 'Applications Engineer',
'back-end-engineer': 'Back End Engineer',
'business-analyst': 'Business Analyst',
'business-engineer': 'Business Engineer',
'capacity-engineer': 'Capacity Engineer',
'customer-engineer': 'Customer Engineer',
'data-analyst': 'Data Analyst',
'data-engineer': 'Data Engineer',
'data-scientist': 'Data Scientist',
'devops-engineer': 'DevOps Engineer',
'engineering-director': 'Engineering Director',
'engineering-manager': 'Engineering Manager',
'enterprise-engineer': 'Enterprise Engineer',
'forward-deployed-engineer': 'Forward Deployed Engineer',
'front-end-engineer': 'Front End Engineer',
'full-stack-engineer': 'Full Stack Engineer',
'gameplay-engineer': 'Gameplay Engineer',
'hardware-engineer': 'Hardware Engineer',
'infrastructure-engineer': 'Infrastructure Engineer',
'ios-engineer': 'iOS Software Engineer',
'machine-learning-engineer': 'Machine Learning (ML) Engineer',
'machine-learning-researcher': 'Machine Learning (ML) Researcher',
'mobile-engineer': 'Mobile Software Engineer (iOS + Android)',
'networks-engineer': 'Networks Engineer',
'partner-engineer': 'Partner Engineer',
'product-engineer': 'Product Engineer',
'product-manager': 'Product Manager',
'production-engineer': 'Production Engineer',
'project-manager': 'Project Manager',
'release-engineer': 'Release Engineer',
'research-engineer': 'Research Engineer',
'research-scientist': 'Research Scientist',
'rotational-engineer': 'Rotational Engineer',
'sales-engineer': 'Sales Engineer',
'security-engineer': 'Security Engineer',
'site-reliability-engineer': 'Site Reliability Engineer (SRE)',
'software-engineer': 'Software Engineer',
'solutions-architect': 'Solutions Architect',
'solutions-engineer': 'Solutions Engineer',
'systems-analyst': 'Systems Analyst',
'systems-engineer': 'Systems Engineer',
'tech-ops-engineer': 'Tech Ops Engineer',
'technical-program-manager': 'Technical Program Manager',
'test-engineer': 'QA/Test Engineer (SDET)',
'ux-engineer': 'User Experience (UX) Engineer',
type JobTitleData = Record<
string,
Readonly<{
label: string;
ranking: number;
}>
>;
export const JobTitleLabels: JobTitleData = {
'ai-engineer': { label: 'Artificial Intelligence (AI) Engineer', ranking: 5 },
'algorithms-engineer': { label: 'Algorithms Engineer', ranking: 0 },
'android-engineer': { label: 'Android Software Engineer', ranking: 8 },
'applications-engineer': { label: 'Applications Engineer', ranking: 0 },
'back-end-engineer': { label: 'Back End Engineer', ranking: 9 },
'business-analyst': { label: 'Business Analyst', ranking: 0 },
'business-engineer': { label: 'Business Engineer', ranking: 5 },
'capacity-engineer': { label: 'Capacity Engineer', ranking: 0 },
'customer-engineer': { label: 'Customer Engineer', ranking: 0 },
'data-analyst': { label: 'Data Analyst', ranking: 0 },
'data-engineer': { label: 'Data Engineer', ranking: 0 },
'data-scientist': { label: 'Data Scientist', ranking: 5 },
'devops-engineer': { label: 'DevOps Engineer', ranking: 0 },
'engineering-director': { label: 'Engineering Director', ranking: 0 },
'engineering-manager': { label: 'Engineering Manager', ranking: 0 },
'enterprise-engineer': { label: 'Enterprise Engineer', ranking: 0 },
'forward-deployed-engineer': {
label: 'Forward Deployed Engineer (FDE)',
ranking: 0,
},
'front-end-engineer': { label: 'Front End Engineer', ranking: 9 },
'full-stack-engineer': { label: 'Full Stack Engineer', ranking: 9 },
'gameplay-engineer': { label: 'Gameplay Engineer', ranking: 0 },
'hardware-engineer': { label: 'Hardware Engineer', ranking: 0 },
'infrastructure-engineer': { label: 'Infrastructure Engineer', ranking: 0 },
'ios-engineer': { label: 'iOS Software Engineer', ranking: 0 },
'machine-learning-engineer': {
label: 'Machine Learning (ML) Engineer',
ranking: 5,
},
'machine-learning-researcher': {
label: 'Machine Learning (ML) Researcher',
ranking: 0,
},
'mobile-engineer': {
label: 'Mobile Software Engineer (iOS + Android)',
ranking: 8,
},
'networks-engineer': { label: 'Networks Engineer', ranking: 0 },
'partner-engineer': { label: 'Partner Engineer', ranking: 0 },
'product-engineer': { label: 'Product Engineer', ranking: 7 },
'product-manager': { label: 'Product Manager', ranking: 0 },
'production-engineer': { label: 'Production Engineer', ranking: 8 },
'project-manager': { label: 'Project Manager', ranking: 0 },
'release-engineer': { label: 'Release Engineer', ranking: 0 },
'research-engineer': { label: 'Research Engineer', ranking: 6 },
'research-scientist': { label: 'Research Scientist', ranking: 7 },
'rotational-engineer': { label: 'Rotational Engineer', ranking: 0 },
'sales-engineer': { label: 'Sales Engineer', ranking: 0 },
'security-engineer': { label: 'Security Engineer', ranking: 7 },
'site-reliability-engineer': {
label: 'Site Reliability Engineer (SRE)',
ranking: 8,
},
'software-engineer': { label: 'Software Engineer', ranking: 10 },
'solutions-architect': { label: 'Solutions Architect', ranking: 0 },
'solutions-engineer': { label: 'Solutions Engineer', ranking: 0 },
'systems-analyst': { label: 'Systems Analyst', ranking: 0 },
'systems-engineer': { label: 'Systems Engineer', ranking: 0 },
'tech-ops-engineer': { label: 'Tech Ops Engineer', ranking: 0 },
'technical-program-manager': {
label: 'Technical Program Manager',
ranking: 0,
},
'test-engineer': { label: 'QA/Test Engineer (SDET)', ranking: 6 },
'ux-engineer': { label: 'User Experience (UX) Engineer', ranking: 0 },
};
export type JobTitleType = keyof typeof JobTitleLabels;
export function getLabelForJobTitleType(jobTitle: JobTitleType): string {
return JobTitleLabels[jobTitle];
return JobTitleLabels[jobTitle].label;
}

@ -28,11 +28,13 @@ export default function JobTitlesTypeahead({
}: Props) {
const [query, setQuery] = useState('');
const options = Object.entries(JobTitleLabels)
.map(([slug, label]) => ({
.map(([slug, { label, ranking }]) => ({
id: slug,
label,
ranking,
value: slug,
}))
.sort((a, b) => b.ranking - a.ranking)
.filter(
({ label }) =>
label.toLocaleLowerCase().indexOf(query.toLocaleLowerCase()) > -1,

@ -9,8 +9,8 @@ import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import Container from '~/components/shared/Container';
import CountriesTypeahead from '~/components/shared/CountriesTypeahead';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { JobTitleLabels } from '~/components/shared/JobTitles';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypeahead';
import { useSearchParamSingle } from '~/utils/offers/useSearchParam';
@ -79,7 +79,9 @@ export default function OffersHomePage() {
selectedJobTitleId
? {
id: selectedJobTitleId,
label: JobTitleLabels[selectedJobTitleId as JobTitleType],
label: getLabelForJobTitleType(
selectedJobTitleId as JobTitleType,
),
value: selectedJobTitleId,
}
: null

@ -17,7 +17,8 @@ import QuestionSearchBar from '~/components/questions/QuestionSearchBar';
import CompanyTypeahead from '~/components/questions/typeahead/CompanyTypeahead';
import LocationTypeahead from '~/components/questions/typeahead/LocationTypeahead';
import RoleTypeahead from '~/components/questions/typeahead/RoleTypeahead';
import { JobTitleLabels } from '~/components/shared/JobTitles';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
import type { QuestionAge } from '~/utils/questions/constants';
import { QUESTION_SORT_TYPES } from '~/utils/questions/constants';
@ -316,7 +317,7 @@ export default function QuestionsBrowsePage() {
return selectedRoles.map((role) => ({
checked: true,
id: role,
label: JobTitleLabels[role as keyof typeof JobTitleLabels],
label: getLabelForJobTitleType(role as JobTitleType),
value: role,
}));
}, [selectedRoles]);

@ -7,7 +7,7 @@ import { HorizontalDivider } from '@tih/ui';
import CitiesTypeahead from '~/components/shared/CitiesTypeahead';
import CompaniesTypeahead from '~/components/shared/CompaniesTypeahead';
import CountriesTypeahead from '~/components/shared/CountriesTypeahead';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypahead';
import JobTitlesTypeahead from '~/components/shared/JobTitlesTypeahead';
import type {
Month,
MonthYearOptional,

@ -1,4 +1,5 @@
import { JobTitleLabels } from '~/components/shared/JobTitles';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
import type { AggregatedQuestionEncounter } from '~/types/questions';
@ -8,7 +9,7 @@ export default function relabelQuestionAggregates({
}: AggregatedQuestionEncounter) {
const newRoleCounts = Object.fromEntries(
Object.entries(roleCounts).map(([roleId, count]) => [
JobTitleLabels[roleId as keyof typeof JobTitleLabels],
getLabelForJobTitleType(roleId as JobTitleType),
count,
]),
);

@ -1,6 +1,7 @@
import type { TypeaheadOption } from '@tih/ui';
import type { JobTitleType } from '~/components/shared/JobTitles';
import { getLabelForJobTitleType } from '~/components/shared/JobTitles';
import { JobTitleLabels } from '~/components/shared/JobTitles';
export type FilterId = 'experience' | 'location' | 'role';
@ -42,7 +43,7 @@ export const getTypeaheadOption = (
case 'role':
return {
id: filterValue,
label: JobTitleLabels[filterValue as keyof typeof JobTitleLabels],
label: getLabelForJobTitleType(filterValue as JobTitleType),
value: filterValue,
};
case 'location':
@ -222,7 +223,7 @@ export const getFilterLabel = (
filters = EXPERIENCES;
break;
case 'role':
filters = Object.entries(JobTitleLabels).map(([slug, label]) => ({
filters = Object.entries(JobTitleLabels).map(([slug, { label }]) => ({
id: slug,
label,
value: slug,

Loading…
Cancel
Save