[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 & {
showActionButton: false;
showAnswerStatistics: false;
showDeleteButton: false;
showReceivedStatistics: true;
showVoteButtons: true;
},
@ -24,6 +25,7 @@ export default function FullQuestionCard(props: QuestionOverviewCardProps) {
showAnswerStatistics={false}
showReceivedStatistics={true}
showVoteButtons={true}
truncateContent={false}
/>
);
}

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

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

@ -8,7 +8,6 @@ import {
HorizontalDivider,
Select,
TextArea,
Typeahead,
} from '@tih/ui';
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 RoleTypeahead from '../typeahead/RoleTypeahead';
import CompanyTypeahead from '../typeahead/CompanyTypeahead';
export type CreateQuestionEncounterData = {
company: string;
@ -25,6 +26,8 @@ export default function CreateQuestionEncounterForm({
onCancel,
onSubmit,
}: CreateQuestionEncounterFormProps) {
const [step, setStep] = useState(0);
const [selectedCompany, setSelectedCompany] = useState<string | null>(null);
const [selectedLocation, setSelectedLocation] = useState<string | null>(null);
const [selectedRole, setSelectedRole] = useState<string | null>(null);
@ -43,67 +46,104 @@ export default function CreateQuestionEncounterForm({
}}
/>
<div className="flex items-center gap-2">
<p className="font-md text-xl text-slate-600">I saw this question at</p>
<div>
<CompaniesTypeahead
isLabelHidden={true}
onSelect={({ value: company }) => {
setSelectedCompany(company);
<p className="font-md text-md text-slate-600">I saw this question at</p>
{step === 0 && (
<div>
<CompanyTypeahead
placeholder="Other company"
suggestedCount={3}
onSuggestionClick={({ value: company }) => {
setSelectedCompany(company);
setStep(step + 1);
}}
isLabelHidden={true}
onSelect={({ value: company }) => {
setSelectedCompany(company);
}}
/>
</div>
)}
{step === 1 && (
<div>
<LocationTypeahead
suggestedCount={3}
onSuggestionClick={({ value: location }) => {
setSelectedLocation(location);
setStep(step + 1);
}}
isLabelHidden={true}
placeholder="Other location"
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: location }) => {
setSelectedLocation(location);
}}
/>
</div>
)}
{step === 2 && (
<div>
<RoleTypeahead
isLabelHidden={true}
suggestedCount={3}
onSuggestionClick={({ value: role }) => {
setSelectedRole(role);
setStep(step + 1);
}}
placeholder="Other role"
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: role }) => {
setSelectedRole(role);
}}
/>
</div>
)}
{step === 3 && (
<MonthYearPicker
yearLabel={''}
monthLabel={''}
value={{
month: ((selectedDate?.getMonth() ?? 0) + 1) as Month,
year: selectedDate?.getFullYear() as number,
}}
onChange={(value) => {
setSelectedDate(
startOfMonth(new Date(value.year, value.month - 1)),
);
}}
/>
</div>
<div>
<LocationTypeahead
isLabelHidden={true}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: location }) => {
setSelectedLocation(location);
)}
{step < 3 && (
<Button
label="Next"
variant="primary"
onClick={() => {
setStep(step + 1);
}}
/>
</div>
<p className="font-md text-xl text-slate-600">for</p>
<div>
<RoleTypeahead
isLabelHidden={true}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value: role }) => {
setSelectedRole(role);
)}
{step === 3 && (
<Button
label="Submit"
variant="primary"
onClick={() => {
if (
selectedCompany &&
selectedLocation &&
selectedRole &&
selectedDate
) {
onSubmit({
company: selectedCompany,
location: selectedLocation,
role: selectedRole,
seenAt: selectedDate,
});
}
}}
/>
</div>
<p className="font-md text-xl text-slate-600">for</p>
<MonthYearPicker
value={{
month: ((selectedDate?.getMonth() ?? 0) + 1) as Month,
year: selectedDate?.getFullYear() as number,
}}
onChange={(value) => {
setSelectedDate(
startOfMonth(new Date(value.year, value.month - 1)),
);
}}
/>
<Button
label="Submit"
variant="primary"
onClick={() => {
if (
selectedCompany &&
selectedLocation &&
selectedRole &&
selectedDate
) {
onSubmit({
company: selectedCompany,
location: selectedLocation,
role: selectedRole,
seenAt: selectedDate,
});
}
}}
/>
)}
</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';
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) {
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';
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) {
return <Typeahead label="Role" options={ROLES} {...props} />;
return (
<ExpandedTypeahead
{...(props as ExpandedTypeaheadProps)}
label="Role"
options={ROLES}
/>
);
}

Loading…
Cancel
Save