I saw this question {step <= 1 ? 'at' : step === 2 ? 'for' : 'on'}
diff --git a/apps/portal/src/components/questions/typeahead/CompanyTypeahead.tsx b/apps/portal/src/components/questions/typeahead/CompanyTypeahead.tsx
index bf950a49..a00cd3c7 100644
--- a/apps/portal/src/components/questions/typeahead/CompanyTypeahead.tsx
+++ b/apps/portal/src/components/questions/typeahead/CompanyTypeahead.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
-import { useCompanyOptions } from '~/components/shared/CompaniesTypeahead';
+import useCompanyOptions from '~/utils/shared/useCompanyOptions';
import type { ExpandedTypeaheadProps } from './ExpandedTypeahead';
import ExpandedTypeahead from './ExpandedTypeahead';
diff --git a/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx b/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx
index 829c8ad2..c0bb2a8c 100644
--- a/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx
+++ b/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
-import { useJobTitleOptions } from '~/components/shared/JobTitlesTypeahead';
+import useJobTitleOptions from '~/utils/shared/useJobTitleOptions';
import type { ExpandedTypeaheadProps } from './ExpandedTypeahead';
import ExpandedTypeahead from './ExpandedTypeahead';
diff --git a/apps/portal/src/components/shared/CompaniesTypeahead.tsx b/apps/portal/src/components/shared/CompaniesTypeahead.tsx
index f51ba8d7..07d61669 100644
--- a/apps/portal/src/components/shared/CompaniesTypeahead.tsx
+++ b/apps/portal/src/components/shared/CompaniesTypeahead.tsx
@@ -3,7 +3,7 @@ import { useState } from 'react';
import type { TypeaheadOption } from '@tih/ui';
import { Typeahead } from '@tih/ui';
-import { trpc } from '~/utils/trpc';
+import useCompanyOptions from '~/utils/shared/useCompanyOptions';
type BaseProps = Pick<
ComponentProps
,
@@ -21,27 +21,6 @@ type Props = BaseProps &
value?: TypeaheadOption | null;
}>;
-export function useCompanyOptions(query: string) {
- const companies = trpc.useQuery([
- 'companies.list',
- {
- name: query,
- },
- ]);
-
- const { data, ...restQuery } = companies;
-
- return {
- data:
- data?.map(({ id, name }) => ({
- id,
- label: name,
- value: id,
- })) ?? [],
- ...restQuery,
- };
-}
-
export default function CompaniesTypeahead({
onSelect,
value,
diff --git a/apps/portal/src/components/shared/CountriesTypeahead.tsx b/apps/portal/src/components/shared/CountriesTypeahead.tsx
index 2c6b73d0..2f4bb2a0 100644
--- a/apps/portal/src/components/shared/CountriesTypeahead.tsx
+++ b/apps/portal/src/components/shared/CountriesTypeahead.tsx
@@ -1,10 +1,9 @@
import type { ComponentProps } from 'react';
import { useState } from 'react';
-import type { Country } from '@prisma/client';
import type { TypeaheadOption } from '@tih/ui';
import { Typeahead } from '@tih/ui';
-import { trpc } from '~/utils/trpc';
+import useCountryOptions from '~/utils/shared/useCountryOptions';
type BaseProps = Pick<
ComponentProps,
@@ -24,58 +23,6 @@ type Props = BaseProps &
value?: TypeaheadOption | null;
}>;
-function stringPositionComparator(a: string, b: string, query: string): number {
- const normalizedQueryString = query.trim().toLocaleLowerCase();
- const positionA = a.toLocaleLowerCase().indexOf(normalizedQueryString);
- const positionB = b.toLocaleLowerCase().indexOf(normalizedQueryString);
- return (
- (positionA === -1 ? 9999 : positionA) -
- (positionB === -1 ? 9999 : positionB)
- );
-}
-
-export function useCompareCountry(query: string) {
- return (a: Country, b: Country) => {
- const normalizedQueryString = query.trim().toLocaleLowerCase();
- if (
- a.code.toLocaleLowerCase() === normalizedQueryString ||
- b.code.toLocaleLowerCase() === normalizedQueryString
- ) {
- return stringPositionComparator(a.code, b.code, normalizedQueryString);
- }
-
- return stringPositionComparator(a.name, b.name, normalizedQueryString);
- };
-}
-
-export function useCountryOptions(query: string) {
- const countries = trpc.useQuery([
- 'locations.countries.list',
- {
- name: query,
- },
- ]);
-
- const { data, ...restQuery } = countries;
-
- const compareCountry = useCompareCountry(query);
-
- const countryOptions = (data ?? [])
- // Client-side sorting by position of query string appearing
- // in the country name since we can't do that in Prisma.
- .sort(compareCountry)
- .map(({ id, name }) => ({
- id,
- label: name,
- value: id,
- }));
-
- return {
- ...restQuery,
- data: countryOptions,
- };
-}
-
export default function CountriesTypeahead({
excludedValues,
label = 'Country',
diff --git a/apps/portal/src/components/shared/JobTitlesTypeahead.tsx b/apps/portal/src/components/shared/JobTitlesTypeahead.tsx
index 165d0077..131db3d0 100644
--- a/apps/portal/src/components/shared/JobTitlesTypeahead.tsx
+++ b/apps/portal/src/components/shared/JobTitlesTypeahead.tsx
@@ -3,7 +3,7 @@ import { useState } from 'react';
import type { TypeaheadOption } from '@tih/ui';
import { Typeahead } from '@tih/ui';
-import { JobTitleLabels } from './JobTitles';
+import useJobTitleOptions from '~/utils/shared/useJobTitleOptions';
type BaseProps = Pick<
ComponentProps,
@@ -24,23 +24,6 @@ type Props = BaseProps &
value?: TypeaheadOption | null;
}>;
-const sortedJobTitleOptions = Object.entries(JobTitleLabels)
- .map(([slug, { label, ranking }]) => ({
- id: slug,
- label,
- ranking,
- value: slug,
- }))
- .sort((a, b) => b.ranking - a.ranking);
-
-export function useJobTitleOptions(query: string) {
- const jobTitles = sortedJobTitleOptions.filter(({ label }) =>
- label.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()),
- );
-
- return jobTitles;
-}
-
export default function JobTitlesTypeahead({
excludedValues,
label: labelProp = 'Job Title',
diff --git a/apps/portal/src/utils/shared/useCompanyOptions.ts b/apps/portal/src/utils/shared/useCompanyOptions.ts
new file mode 100644
index 00000000..b9437f8d
--- /dev/null
+++ b/apps/portal/src/utils/shared/useCompanyOptions.ts
@@ -0,0 +1,22 @@
+import { trpc } from '../trpc';
+
+export default function useCompanyOptions(query: string) {
+ const companies = trpc.useQuery([
+ 'companies.list',
+ {
+ name: query,
+ },
+ ]);
+
+ const { data, ...restQuery } = companies;
+
+ return {
+ data:
+ data?.map(({ id, name }) => ({
+ id,
+ label: name,
+ value: id,
+ })) ?? [],
+ ...restQuery,
+ };
+}
diff --git a/apps/portal/src/utils/shared/useCountryOptions.ts b/apps/portal/src/utils/shared/useCountryOptions.ts
new file mode 100644
index 00000000..f5f1700c
--- /dev/null
+++ b/apps/portal/src/utils/shared/useCountryOptions.ts
@@ -0,0 +1,55 @@
+import type { Country } from '@prisma/client';
+
+import { trpc } from '../trpc';
+
+function stringPositionComparator(a: string, b: string, query: string): number {
+ const normalizedQueryString = query.trim().toLocaleLowerCase();
+ const positionA = a.toLocaleLowerCase().indexOf(normalizedQueryString);
+ const positionB = b.toLocaleLowerCase().indexOf(normalizedQueryString);
+ return (
+ (positionA === -1 ? 9999 : positionA) -
+ (positionB === -1 ? 9999 : positionB)
+ );
+}
+
+export function useCompareCountry(query: string) {
+ return (a: Country, b: Country) => {
+ const normalizedQueryString = query.trim().toLocaleLowerCase();
+ if (
+ a.code.toLocaleLowerCase() === normalizedQueryString ||
+ b.code.toLocaleLowerCase() === normalizedQueryString
+ ) {
+ return stringPositionComparator(a.code, b.code, normalizedQueryString);
+ }
+
+ return stringPositionComparator(a.name, b.name, normalizedQueryString);
+ };
+}
+
+export default function useCountryOptions(query: string) {
+ const countries = trpc.useQuery([
+ 'locations.countries.list',
+ {
+ name: query,
+ },
+ ]);
+
+ const { data, ...restQuery } = countries;
+
+ const compareCountry = useCompareCountry(query);
+
+ const countryOptions = (data ?? [])
+ // Client-side sorting by position of query string appearing
+ // in the country name since we can't do that in Prisma.
+ .sort(compareCountry)
+ .map(({ id, name }) => ({
+ id,
+ label: name,
+ value: id,
+ }));
+
+ return {
+ ...restQuery,
+ data: countryOptions,
+ };
+}
diff --git a/apps/portal/src/utils/shared/useJobTitleOptions.ts b/apps/portal/src/utils/shared/useJobTitleOptions.ts
new file mode 100644
index 00000000..8c8bda9b
--- /dev/null
+++ b/apps/portal/src/utils/shared/useJobTitleOptions.ts
@@ -0,0 +1,18 @@
+import { JobTitleLabels } from '~/components/shared/JobTitles';
+
+const sortedJobTitleOptions = Object.entries(JobTitleLabels)
+ .map(([slug, { label, ranking }]) => ({
+ id: slug,
+ label,
+ ranking,
+ value: slug,
+ }))
+ .sort((a, b) => b.ranking - a.ranking);
+
+export default function useJobTitleOptions(query: string) {
+ const jobTitles = sortedJobTitleOptions.filter(({ label }) =>
+ label.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()),
+ );
+
+ return jobTitles;
+}