|
|
@ -14,6 +14,7 @@ import QuestionSearchBar from '~/components/questions/QuestionSearchBar';
|
|
|
|
import CompanyTypeahead from '~/components/questions/typeahead/CompanyTypeahead';
|
|
|
|
import CompanyTypeahead from '~/components/questions/typeahead/CompanyTypeahead';
|
|
|
|
import LocationTypeahead from '~/components/questions/typeahead/LocationTypeahead';
|
|
|
|
import LocationTypeahead from '~/components/questions/typeahead/LocationTypeahead';
|
|
|
|
import RoleTypeahead from '~/components/questions/typeahead/RoleTypeahead';
|
|
|
|
import RoleTypeahead from '~/components/questions/typeahead/RoleTypeahead';
|
|
|
|
|
|
|
|
import { JobTitleLabels } from '~/components/shared/JobTitles';
|
|
|
|
|
|
|
|
|
|
|
|
import type { QuestionAge } from '~/utils/questions/constants';
|
|
|
|
import type { QuestionAge } from '~/utils/questions/constants';
|
|
|
|
import { SORT_TYPES } from '~/utils/questions/constants';
|
|
|
|
import { SORT_TYPES } from '~/utils/questions/constants';
|
|
|
@ -21,6 +22,7 @@ import { SORT_ORDERS } from '~/utils/questions/constants';
|
|
|
|
import { APP_TITLE } from '~/utils/questions/constants';
|
|
|
|
import { APP_TITLE } from '~/utils/questions/constants';
|
|
|
|
import { QUESTION_AGES, QUESTION_TYPES } from '~/utils/questions/constants';
|
|
|
|
import { QUESTION_AGES, QUESTION_TYPES } from '~/utils/questions/constants';
|
|
|
|
import createSlug from '~/utils/questions/createSlug';
|
|
|
|
import createSlug from '~/utils/questions/createSlug';
|
|
|
|
|
|
|
|
import relabelQuestionAggregates from '~/utils/questions/relabelQuestionAggregates';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
useSearchParam,
|
|
|
|
useSearchParam,
|
|
|
|
useSearchParamSingle,
|
|
|
|
useSearchParamSingle,
|
|
|
@ -176,7 +178,7 @@ export default function QuestionsBrowsePage() {
|
|
|
|
return undefined;
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return questionsQueryData.pages.reduce(
|
|
|
|
return questionsQueryData.pages.reduce(
|
|
|
|
(acc, page) => acc + page.data.length,
|
|
|
|
(acc, page) => acc + (page.data.length as number),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}, [questionsQueryData]);
|
|
|
|
}, [questionsQueryData]);
|
|
|
@ -275,7 +277,7 @@ export default function QuestionsBrowsePage() {
|
|
|
|
return selectedRoles.map((role) => ({
|
|
|
|
return selectedRoles.map((role) => ({
|
|
|
|
checked: true,
|
|
|
|
checked: true,
|
|
|
|
id: role,
|
|
|
|
id: role,
|
|
|
|
label: role,
|
|
|
|
label: JobTitleLabels[role as keyof typeof JobTitleLabels],
|
|
|
|
value: role,
|
|
|
|
value: role,
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
}, [selectedRoles]);
|
|
|
|
}, [selectedRoles]);
|
|
|
@ -371,7 +373,7 @@ export default function QuestionsBrowsePage() {
|
|
|
|
setSelectedRoles([...selectedRoles, option.value]);
|
|
|
|
setSelectedRoles([...selectedRoles, option.value]);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
setSelectedRoles(
|
|
|
|
setSelectedRoles(
|
|
|
|
selectedCompanies.filter((role) => role !== option.value),
|
|
|
|
selectedRoles.filter((role) => role !== option.value),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
}}
|
|
|
@ -445,8 +447,7 @@ export default function QuestionsBrowsePage() {
|
|
|
|
<main className="flex flex-1 flex-col items-stretch">
|
|
|
|
<main className="flex flex-1 flex-col items-stretch">
|
|
|
|
<div className="flex h-full flex-1">
|
|
|
|
<div className="flex h-full flex-1">
|
|
|
|
<section className="flex min-h-0 flex-1 flex-col items-center overflow-auto">
|
|
|
|
<section className="flex min-h-0 flex-1 flex-col items-center overflow-auto">
|
|
|
|
<div className="flex min-h-0 max-w-3xl flex-1 p-4">
|
|
|
|
<div className="m-4 flex max-w-3xl flex-1 flex-col items-stretch justify-start gap-8">
|
|
|
|
<div className="flex flex-1 flex-col items-stretch justify-start gap-8">
|
|
|
|
|
|
|
|
<ContributeQuestionCard
|
|
|
|
<ContributeQuestionCard
|
|
|
|
onSubmit={(data) => {
|
|
|
|
onSubmit={(data) => {
|
|
|
|
createQuestion({
|
|
|
|
createQuestion({
|
|
|
@ -459,6 +460,7 @@ export default function QuestionsBrowsePage() {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div className="sticky top-0 border-b border-slate-300 bg-slate-50 py-4">
|
|
|
|
<QuestionSearchBar
|
|
|
|
<QuestionSearchBar
|
|
|
|
sortOrderOptions={SORT_ORDERS}
|
|
|
|
sortOrderOptions={SORT_ORDERS}
|
|
|
|
sortOrderValue={sortOrder}
|
|
|
|
sortOrderValue={sortOrder}
|
|
|
@ -470,28 +472,29 @@ export default function QuestionsBrowsePage() {
|
|
|
|
onSortOrderChange={setSortOrder}
|
|
|
|
onSortOrderChange={setSortOrder}
|
|
|
|
onSortTypeChange={setSortType}
|
|
|
|
onSortTypeChange={setSortType}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-2 pb-4">
|
|
|
|
<div className="flex flex-col gap-2 pb-4">
|
|
|
|
{(questionsQueryData?.pages ?? []).flatMap(
|
|
|
|
{(questionsQueryData?.pages ?? []).flatMap(
|
|
|
|
({ data: questions }) =>
|
|
|
|
({ data: questions }) =>
|
|
|
|
questions.map((question) => (
|
|
|
|
questions.map((question) => {
|
|
|
|
|
|
|
|
const { companyCounts, locationCounts, roleCounts } =
|
|
|
|
|
|
|
|
relabelQuestionAggregates(
|
|
|
|
|
|
|
|
question.aggregatedQuestionEncounters,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
<QuestionOverviewCard
|
|
|
|
<QuestionOverviewCard
|
|
|
|
key={question.id}
|
|
|
|
key={question.id}
|
|
|
|
answerCount={question.numAnswers}
|
|
|
|
answerCount={question.numAnswers}
|
|
|
|
companies={
|
|
|
|
companies={companyCounts}
|
|
|
|
question.aggregatedQuestionEncounters.companyCounts
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
content={question.content}
|
|
|
|
content={question.content}
|
|
|
|
href={`/questions/${question.id}/${createSlug(
|
|
|
|
href={`/questions/${question.id}/${createSlug(
|
|
|
|
question.content,
|
|
|
|
question.content,
|
|
|
|
)}`}
|
|
|
|
)}`}
|
|
|
|
locations={
|
|
|
|
locations={locationCounts}
|
|
|
|
question.aggregatedQuestionEncounters.locationCounts
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
questionId={question.id}
|
|
|
|
questionId={question.id}
|
|
|
|
receivedCount={question.receivedCount}
|
|
|
|
receivedCount={question.receivedCount}
|
|
|
|
roles={
|
|
|
|
roles={roleCounts}
|
|
|
|
question.aggregatedQuestionEncounters.roleCounts
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
timestamp={question.seenAt.toLocaleDateString(
|
|
|
|
timestamp={question.seenAt.toLocaleDateString(
|
|
|
|
undefined,
|
|
|
|
undefined,
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -502,7 +505,8 @@ export default function QuestionsBrowsePage() {
|
|
|
|
type={question.type}
|
|
|
|
type={question.type}
|
|
|
|
upvoteCount={question.numVotes}
|
|
|
|
upvoteCount={question.numVotes}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
)),
|
|
|
|
);
|
|
|
|
|
|
|
|
}),
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
<Button
|
|
|
|
<Button
|
|
|
|
disabled={!hasNextPage || isFetchingNextPage}
|
|
|
|
disabled={!hasNextPage || isFetchingNextPage}
|
|
|
@ -522,7 +526,6 @@ export default function QuestionsBrowsePage() {
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
<aside className="hidden w-[300px] overflow-y-auto border-l bg-white py-4 lg:block">
|
|
|
|
<aside className="hidden w-[300px] overflow-y-auto border-l bg-white py-4 lg:block">
|
|
|
|
<h2 className="px-4 text-xl font-semibold">Filter by</h2>
|
|
|
|
<h2 className="px-4 text-xl font-semibold">Filter by</h2>
|
|
|
|