[questions][ui] update create question encounter form

pull/411/head
Jeff Sieu 3 years ago
parent 8880e29b2d
commit 634a41a48a

@ -5,6 +5,7 @@ export type QuestionOverviewCardProps = Omit<
QuestionCardProps & { QuestionCardProps & {
showActionButton: false; showActionButton: false;
showAnswerStatistics: false; showAnswerStatistics: false;
showDeleteButton: false;
showReceivedStatistics: true; showReceivedStatistics: true;
showVoteButtons: true; showVoteButtons: true;
}, },
@ -24,6 +25,7 @@ export default function FullQuestionCard(props: QuestionOverviewCardProps) {
showAnswerStatistics={false} showAnswerStatistics={false}
showReceivedStatistics={true} showReceivedStatistics={true}
showVoteButtons={true} showVoteButtons={true}
truncateContent={false}
/> />
); );
} }

@ -1,6 +1,8 @@
import clsx from 'clsx';
import { useState } from 'react'; import { useState } from 'react';
import { import {
ChatBubbleBottomCenterTextIcon, ChatBubbleBottomCenterTextIcon,
CheckIcon,
EyeIcon, EyeIcon,
TrashIcon, TrashIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
@ -80,6 +82,7 @@ export type QuestionCardProps = ActionButtonProps &
role: string; role: string;
showHover?: boolean; showHover?: boolean;
timestamp: string; timestamp: string;
truncateContent?: boolean;
type: QuestionsQuestionType; type: QuestionsQuestionType;
}; };
@ -104,6 +107,7 @@ export default function QuestionCard({
onReceivedSubmit, onReceivedSubmit,
showDeleteButton, showDeleteButton,
onDelete, onDelete,
truncateContent = true,
}: QuestionCardProps) { }: QuestionCardProps) {
const [showReceivedForm, setShowReceivedForm] = useState(false); const [showReceivedForm, setShowReceivedForm] = useState(false);
const { handleDownvote, handleUpvote, vote } = useQuestionVote(questionId); const { handleDownvote, handleUpvote, vote } = useQuestionVote(questionId);
@ -147,7 +151,9 @@ export default function QuestionCard({
)} )}
</div> </div>
<div className="ml-2"> <div className="ml-2">
<p className="line-clamp-2 text-ellipsis ">{content}</p> <p className={clsx(truncateContent && 'line-clamp-2 text-ellipsis')}>
{content}
</p>
</div> </div>
{(showAnswerStatistics || showReceivedStatistics) && ( {(showAnswerStatistics || showReceivedStatistics) && (
<div className="flex gap-2"> <div className="flex gap-2">
@ -161,17 +167,26 @@ export default function QuestionCard({
/> />
)} )}
{showReceivedStatistics && ( {showReceivedStatistics && (
<>
<Button <Button
addonPosition="start" addonPosition="start"
icon={EyeIcon} icon={EyeIcon}
label={`${receivedCount} received this`} label={`${receivedCount} received this`}
size="sm" size="sm"
variant="tertiary" variant="tertiary"
/>
<Button
addonPosition="start"
icon={CheckIcon}
label="I received this too"
size="sm"
variant="tertiary"
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
setShowReceivedForm(true); setShowReceivedForm(true);
}} }}
/> />
</>
)} )}
</div> </div>
)} )}

@ -6,15 +6,15 @@ import QuestionCard from './QuestionCard';
export type QuestionListCardProps = Omit< export type QuestionListCardProps = Omit<
QuestionCardProps & { QuestionCardProps & {
showActionButton: false; showActionButton: false;
showAnswerStatistics: false;
showDeleteButton: true; showDeleteButton: true;
showUserStatistics: false;
showVoteButtons: false; showVoteButtons: false;
}, },
| 'actionButtonLabel' | 'actionButtonLabel'
| 'onActionButtonClick' | 'onActionButtonClick'
| 'showActionButton' | 'showActionButton'
| 'showAnswerStatistics'
| 'showDeleteButton' | 'showDeleteButton'
| 'showUserStatistics'
| 'showVoteButtons' | 'showVoteButtons'
>; >;
@ -23,9 +23,9 @@ function QuestionListCardWithoutHref(props: QuestionListCardProps) {
<QuestionCard <QuestionCard
{...props} {...props}
showActionButton={false} showActionButton={false}
showAnswerStatistics={false}
showDeleteButton={true} showDeleteButton={true}
showHover={true} showHover={true}
showUserStatistics={false}
showVoteButtons={false} showVoteButtons={false}
/> />
); );

@ -8,7 +8,6 @@ import {
HorizontalDivider, HorizontalDivider,
Select, Select,
TextArea, TextArea,
Typeahead,
} from '@tih/ui'; } from '@tih/ui';
import { LOCATIONS, QUESTION_TYPES, ROLES } from '~/utils/questions/constants'; import { LOCATIONS, QUESTION_TYPES, ROLES } from '~/utils/questions/constants';

@ -8,6 +8,7 @@ import MonthYearPicker from '~/components/shared/MonthYearPicker';
import LocationTypeahead from '../typeahead/LocationTypeahead'; import LocationTypeahead from '../typeahead/LocationTypeahead';
import RoleTypeahead from '../typeahead/RoleTypeahead'; import RoleTypeahead from '../typeahead/RoleTypeahead';
import CompanyTypeahead from '../typeahead/CompanyTypeahead';
export type CreateQuestionEncounterData = { export type CreateQuestionEncounterData = {
company: string; company: string;
@ -25,6 +26,8 @@ export default function CreateQuestionEncounterForm({
onCancel, onCancel,
onSubmit, onSubmit,
}: CreateQuestionEncounterFormProps) { }: CreateQuestionEncounterFormProps) {
const [step, setStep] = useState(0);
const [selectedCompany, setSelectedCompany] = useState<string | null>(null); const [selectedCompany, setSelectedCompany] = useState<string | null>(null);
const [selectedLocation, setSelectedLocation] = useState<string | null>(null); const [selectedLocation, setSelectedLocation] = useState<string | null>(null);
const [selectedRole, setSelectedRole] = useState<string | null>(null); const [selectedRole, setSelectedRole] = useState<string | null>(null);
@ -43,18 +46,33 @@ export default function CreateQuestionEncounterForm({
}} }}
/> />
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<p className="font-md text-xl text-slate-600">I saw this question at</p> <p className="font-md text-md text-slate-600">I saw this question at</p>
{step === 0 && (
<div> <div>
<CompaniesTypeahead <CompanyTypeahead
placeholder="Other company"
suggestedCount={3}
onSuggestionClick={({ value: company }) => {
setSelectedCompany(company);
setStep(step + 1);
}}
isLabelHidden={true} isLabelHidden={true}
onSelect={({ value: company }) => { onSelect={({ value: company }) => {
setSelectedCompany(company); setSelectedCompany(company);
}} }}
/> />
</div> </div>
)}
{step === 1 && (
<div> <div>
<LocationTypeahead <LocationTypeahead
suggestedCount={3}
onSuggestionClick={({ value: location }) => {
setSelectedLocation(location);
setStep(step + 1);
}}
isLabelHidden={true} isLabelHidden={true}
placeholder="Other location"
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}} onQueryChange={() => {}}
onSelect={({ value: location }) => { onSelect={({ value: location }) => {
@ -62,10 +80,17 @@ export default function CreateQuestionEncounterForm({
}} }}
/> />
</div> </div>
<p className="font-md text-xl text-slate-600">for</p> )}
{step === 2 && (
<div> <div>
<RoleTypeahead <RoleTypeahead
isLabelHidden={true} isLabelHidden={true}
suggestedCount={3}
onSuggestionClick={({ value: role }) => {
setSelectedRole(role);
setStep(step + 1);
}}
placeholder="Other role"
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}} onQueryChange={() => {}}
onSelect={({ value: role }) => { onSelect={({ value: role }) => {
@ -73,8 +98,11 @@ export default function CreateQuestionEncounterForm({
}} }}
/> />
</div> </div>
<p className="font-md text-xl text-slate-600">for</p> )}
{step === 3 && (
<MonthYearPicker <MonthYearPicker
yearLabel={''}
monthLabel={''}
value={{ value={{
month: ((selectedDate?.getMonth() ?? 0) + 1) as Month, month: ((selectedDate?.getMonth() ?? 0) + 1) as Month,
year: selectedDate?.getFullYear() as number, year: selectedDate?.getFullYear() as number,
@ -85,6 +113,17 @@ export default function CreateQuestionEncounterForm({
); );
}} }}
/> />
)}
{step < 3 && (
<Button
label="Next"
variant="primary"
onClick={() => {
setStep(step + 1);
}}
/>
)}
{step === 3 && (
<Button <Button
label="Submit" label="Submit"
variant="primary" variant="primary"
@ -104,6 +143,7 @@ export default function CreateQuestionEncounterForm({
} }
}} }}
/> />
)}
</div> </div>
</div> </div>
); );

@ -0,0 +1,41 @@
import { useMemo, useState } from 'react';
import { trpc } from '~/utils/trpc';
import type { ExpandedTypeaheadProps } from './ExpandedTypeahead';
import ExpandedTypeahead from './ExpandedTypeahead';
export type CompanyTypeaheadProps = Omit<
ExpandedTypeaheadProps,
'label' | 'onQueryChange' | 'options'
>;
export default function CompanyTypeahead(props: CompanyTypeaheadProps) {
const [query, setQuery] = useState('');
const { data: companies } = trpc.useQuery([
'companies.list',
{
name: query,
},
]);
const companyOptions = useMemo(() => {
return (
companies?.map(({ id, name }) => ({
id,
label: name,
value: id,
})) ?? []
);
}, [companies]);
return (
<ExpandedTypeahead
{...(props as ExpandedTypeaheadProps)}
label="Company"
options={companyOptions}
onQueryChange={setQuery}
/>
);
}

@ -0,0 +1,37 @@
import type { ComponentProps } from 'react';
import { Button, Typeahead } from '@tih/ui';
type RequireAllOrNone<T> = T | { [K in keyof T]?: never };
type TypeaheadProps = ComponentProps<typeof Typeahead>;
type TypeaheadOption = TypeaheadProps['options'][number];
export type ExpandedTypeaheadProps = RequireAllOrNone<{
onSuggestionClick: (option: TypeaheadOption) => void;
suggestedCount: number;
}> &
TypeaheadProps;
export default function ExpandedTypeahead({
suggestedCount = 0,
onSuggestionClick,
...typeaheadProps
}: ExpandedTypeaheadProps) {
const suggestions = typeaheadProps.options.slice(0, suggestedCount);
return (
<div className="flex flex-wrap gap-x-2">
{suggestions.map((suggestion) => (
<Button
key={suggestion.id}
label={suggestion.label}
variant="tertiary"
onClick={() => {
onSuggestionClick?.(suggestion);
}}
/>
))}
<Typeahead {...typeaheadProps} />
</div>
);
}

@ -1,12 +1,19 @@
import type { ComponentProps } from 'react';
import { Typeahead } from '@tih/ui';
import { LOCATIONS } from '~/utils/questions/constants'; import { LOCATIONS } from '~/utils/questions/constants';
type TypeaheadProps = ComponentProps<typeof Typeahead>; import type { ExpandedTypeaheadProps } from './ExpandedTypeahead';
import ExpandedTypeahead from './ExpandedTypeahead';
export type LocationTypeaheadProps = Omit<TypeaheadProps, 'label' | 'options'>; export type LocationTypeaheadProps = Omit<
ExpandedTypeaheadProps,
'label' | 'options'
>;
export default function LocationTypeahead(props: LocationTypeaheadProps) { export default function LocationTypeahead(props: LocationTypeaheadProps) {
return <Typeahead label="Location" options={LOCATIONS} {...props} />; return (
<ExpandedTypeahead
{...(props as ExpandedTypeaheadProps)}
label="Location"
options={LOCATIONS}
/>
);
} }

@ -1,12 +1,19 @@
import type { ComponentProps } from 'react';
import { Typeahead } from '@tih/ui';
import { ROLES } from '~/utils/questions/constants'; import { ROLES } from '~/utils/questions/constants';
type TypeaheadProps = ComponentProps<typeof Typeahead>; import type { ExpandedTypeaheadProps } from './ExpandedTypeahead';
import ExpandedTypeahead from './ExpandedTypeahead';
export type RoleTypeaheadProps = Omit<TypeaheadProps, 'label' | 'options'>; export type RoleTypeaheadProps = Omit<
ExpandedTypeaheadProps,
'label' | 'options'
>;
export default function RoleTypeahead(props: RoleTypeaheadProps) { export default function RoleTypeahead(props: RoleTypeaheadProps) {
return <Typeahead label="Role" options={ROLES} {...props} />; return (
<ExpandedTypeahead
{...(props as ExpandedTypeaheadProps)}
label="Role"
options={ROLES}
/>
);
} }

Loading…
Cancel
Save