[ui][typeahead] refactor hooks into separate files

pull/516/head
Jeff Sieu 3 years ago
parent d873186209
commit cc96ba8acf

@ -3,11 +3,12 @@ import { useState } from 'react';
import { CheckIcon } from '@heroicons/react/20/solid';
import { Button } from '@tih/ui';
import { useCompanyOptions } from '~/components/shared/CompaniesTypeahead';
import { useJobTitleOptions } from '~/components/shared/JobTitlesTypeahead';
import type { Month } from '~/components/shared/MonthYearPicker';
import MonthYearPicker from '~/components/shared/MonthYearPicker';
import useCompanyOptions from '~/utils/shared/useCompanyOptions';
import useJobTitleOptions from '~/utils/shared/useJobTitleOptions';
import CompanyTypeahead from '../typeahead/CompanyTypeahead';
import LocationTypeahead, {
useLocationOptions,
@ -49,7 +50,7 @@ export default function CreateQuestionEncounterForm({
const { data: allCompanyOptions } = useCompanyOptions('');
const { data: allLocationOptions } = useLocationOptions('');
const allRoleOptions = useJobTitleOptions('');
const allRoleOptions = useJobTitleOptions('');
if (submitted) {
return (
@ -61,7 +62,7 @@ export default function CreateQuestionEncounterForm({
}
return (
<div className="flex items-center gap-2 flex-wrap">
<div className="flex flex-wrap items-center gap-2">
<p className="text-md text-slate-600">
I saw this question {step <= 1 ? 'at' : step === 2 ? 'for' : 'on'}
</p>

@ -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';

@ -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';

@ -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<typeof Typeahead>,
@ -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,

@ -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<typeof Typeahead>,
@ -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',

@ -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<typeof Typeahead>,
@ -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',

@ -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,
};
}

@ -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,
};
}

@ -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;
}
Loading…
Cancel
Save