From 389862feb35b6c7fd27261d6a8c8bf8a3507702d Mon Sep 17 00:00:00 2001 From: Jeff Sieu Date: Sun, 30 Oct 2022 19:32:33 +0800 Subject: [PATCH] [questions][ui] update roles typeahead, add sticky search bar (#451) --- .../questions/ContributeQuestionCard.tsx | 88 ++++++++------- .../questions/typeahead/RoleTypeahead.tsx | 10 +- .../[questionId]/[questionSlug]/index.tsx | 16 ++- apps/portal/src/pages/questions/browse.tsx | 101 +++++++++--------- apps/portal/src/pages/questions/lists.tsx | 64 +++++------ .../questions/relabelQuestionAggregates.ts | 26 +++++ 6 files changed, 176 insertions(+), 129 deletions(-) create mode 100644 apps/portal/src/utils/questions/relabelQuestionAggregates.ts diff --git a/apps/portal/src/components/questions/ContributeQuestionCard.tsx b/apps/portal/src/components/questions/ContributeQuestionCard.tsx index fa25d9f1..e9bf5c44 100644 --- a/apps/portal/src/components/questions/ContributeQuestionCard.tsx +++ b/apps/portal/src/components/questions/ContributeQuestionCard.tsx @@ -28,56 +28,54 @@ export default function ContributeQuestionCard({ }; return ( -
- +
+ +
+
+ +
+

+ Contribute +

+
- + ); } diff --git a/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx b/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx index d40d6678..60dd3ffa 100644 --- a/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx +++ b/apps/portal/src/components/questions/typeahead/RoleTypeahead.tsx @@ -1,13 +1,21 @@ -import { ROLES } from '~/utils/questions/constants'; +import { JobTitleLabels } from '~/components/shared/JobTitles'; import type { ExpandedTypeaheadProps } from './ExpandedTypeahead'; import ExpandedTypeahead from './ExpandedTypeahead'; +import type { FilterChoices } from '../filter/FilterSection'; export type RoleTypeaheadProps = Omit< ExpandedTypeaheadProps, 'label' | 'onQueryChange' | 'options' >; +const ROLES: FilterChoices = Object.entries(JobTitleLabels).map( + ([slug, label]) => ({ + id: slug, + label, + value: slug, + }), +); export default function RoleTypeahead(props: RoleTypeaheadProps) { return ( { + if (!aggregatedEncounters) { + return aggregatedEncounters; + } + + return relabelQuestionAggregates(aggregatedEncounters); + }, [aggregatedEncounters]); + const utils = trpc.useContext(); const { data: comments } = trpc.useQuery([ @@ -138,11 +148,11 @@ export default function QuestionPage() {
acc + page.data.length, + (acc, page) => acc + (page.data.length as number), 0, ); }, [questionsQueryData]); @@ -275,7 +277,7 @@ export default function QuestionsBrowsePage() { return selectedRoles.map((role) => ({ checked: true, id: role, - label: role, + label: JobTitleLabels[role as keyof typeof JobTitleLabels], value: role, })); }, [selectedRoles]); @@ -371,7 +373,7 @@ export default function QuestionsBrowsePage() { setSelectedRoles([...selectedRoles, option.value]); } else { setSelectedRoles( - selectedCompanies.filter((role) => role !== option.value), + selectedRoles.filter((role) => role !== option.value), ); } }} @@ -445,20 +447,20 @@ export default function QuestionsBrowsePage() {
-
-
- { - createQuestion({ - companyId: data.company, - content: data.questionContent, - location: data.location, - questionType: data.questionType, - role: data.role, - seenAt: data.date, - }); - }} - /> +
+ { + createQuestion({ + companyId: data.company, + content: data.questionContent, + location: data.location, + questionType: data.questionType, + role: data.role, + seenAt: data.date, + }); + }} + /> +
-
- {(questionsQueryData?.pages ?? []).flatMap( - ({ data: questions }) => - questions.map((question) => ( +
+
+ {(questionsQueryData?.pages ?? []).flatMap( + ({ data: questions }) => + questions.map((question) => { + const { companyCounts, locationCounts, roleCounts } = + relabelQuestionAggregates( + question.aggregatedQuestionEncounters, + ); + + return ( - )), - )} -
+ ); + }), + )} +
diff --git a/apps/portal/src/pages/questions/lists.tsx b/apps/portal/src/pages/questions/lists.tsx index ea4009f8..cbf1b276 100644 --- a/apps/portal/src/pages/questions/lists.tsx +++ b/apps/portal/src/pages/questions/lists.tsx @@ -15,6 +15,7 @@ import DeleteListDialog from '~/components/questions/DeleteListDialog'; import { Button } from '~/../../../packages/ui/dist'; import { APP_TITLE } from '~/utils/questions/constants'; import createSlug from '~/utils/questions/createSlug'; +import relabelQuestionAggregates from '~/utils/questions/relabelQuestionAggregates'; import { trpc } from '~/utils/trpc'; export default function ListPage() { @@ -172,37 +173,38 @@ export default function ListPage() { {lists?.[selectedListIndex] && (
{lists[selectedListIndex].questionEntries.map( - ({ question, id: entryId }) => ( - { - deleteQuestionEntry({ id: entryId }); - }} - /> - ), + ({ question, id: entryId }) => { + const { companyCounts, locationCounts, roleCounts } = + relabelQuestionAggregates( + question.aggregatedQuestionEncounters, + ); + + return ( + { + deleteQuestionEntry({ id: entryId }); + }} + /> + ); + }, )} {lists[selectedListIndex].questionEntries?.length === 0 && (
diff --git a/apps/portal/src/utils/questions/relabelQuestionAggregates.ts b/apps/portal/src/utils/questions/relabelQuestionAggregates.ts new file mode 100644 index 00000000..50a2a5dd --- /dev/null +++ b/apps/portal/src/utils/questions/relabelQuestionAggregates.ts @@ -0,0 +1,26 @@ +import { JobTitleLabels } from '~/components/shared/JobTitles'; + +import type { AggregatedQuestionEncounter } from '~/types/questions'; + +export default function relabelQuestionAggregates({ + locationCounts, + companyCounts, + roleCounts, + latestSeenAt, +}: AggregatedQuestionEncounter) { + const newRoleCounts = Object.fromEntries( + Object.entries(roleCounts).map(([roleId, count]) => [ + JobTitleLabels[roleId as keyof typeof JobTitleLabels], + count, + ]), + ); + + const relabeledAggregate: AggregatedQuestionEncounter = { + companyCounts, + latestSeenAt, + locationCounts, + roleCounts: newRoleCounts, + }; + + return relabeledAggregate; +}