parent
6c91ec2077
commit
3992504a0c
@ -0,0 +1,79 @@
|
|||||||
|
import type { ComponentProps, Ref } from 'react';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import type { UseFormRegisterReturn } from 'react-hook-form';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import {
|
||||||
|
BuildingOffice2Icon,
|
||||||
|
CalendarDaysIcon,
|
||||||
|
QuestionMarkCircleIcon,
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
|
import { Button, TextInput } from '@tih/ui';
|
||||||
|
|
||||||
|
export type ContributeQuestionData = {
|
||||||
|
company: string;
|
||||||
|
date: Date;
|
||||||
|
questionContent: string;
|
||||||
|
questionType: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type FormTextInputProps = Omit<ComponentProps<typeof TextInput>, 'onChange'> &
|
||||||
|
Pick<UseFormRegisterReturn<never>, 'onChange'>;
|
||||||
|
|
||||||
|
function FormTextInputWithRef(
|
||||||
|
props: FormTextInputProps,
|
||||||
|
ref?: Ref<HTMLInputElement>,
|
||||||
|
) {
|
||||||
|
const { onChange, ...rest } = props;
|
||||||
|
return (
|
||||||
|
<TextInput onChange={(_, event) => onChange(event)} {...rest} ref={ref} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormTextInput = forwardRef(FormTextInputWithRef);
|
||||||
|
|
||||||
|
export type ContributeQuestionCardProps = {
|
||||||
|
onSubmit: (data: ContributeQuestionData) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ContributeQuestionCard({
|
||||||
|
onSubmit,
|
||||||
|
}: ContributeQuestionCardProps) {
|
||||||
|
const { register, handleSubmit } = useForm<ContributeQuestionData>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="flex flex-col items-stretch justify-center gap-2 rounded-md border border-slate-300 p-4"
|
||||||
|
onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<FormTextInput
|
||||||
|
isLabelHidden={true}
|
||||||
|
label="Question"
|
||||||
|
placeholder="Contribute a question"
|
||||||
|
{...register('questionContent')}
|
||||||
|
/>
|
||||||
|
<div className="flex items-end justify-center gap-x-2">
|
||||||
|
<div className="flex-1">
|
||||||
|
<FormTextInput
|
||||||
|
label="Company"
|
||||||
|
startIcon={BuildingOffice2Icon}
|
||||||
|
{...register('company')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<FormTextInput
|
||||||
|
label="Question type"
|
||||||
|
startIcon={QuestionMarkCircleIcon}
|
||||||
|
{...register('questionType')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<FormTextInput
|
||||||
|
label="Date"
|
||||||
|
startIcon={CalendarDaysIcon}
|
||||||
|
{...register('date')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button label="Contribute" type="submit" variant="primary" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
import {
|
||||||
|
ChatBubbleBottomCenterTextIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronUpIcon,
|
||||||
|
EyeIcon,
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
|
import { Badge, Button } from '@tih/ui';
|
||||||
|
|
||||||
|
export type QuestionOverviewCardProps = {
|
||||||
|
answerCount: number;
|
||||||
|
content: string;
|
||||||
|
location: string;
|
||||||
|
role: string;
|
||||||
|
similarCount: number;
|
||||||
|
timestamp: string;
|
||||||
|
upvoteCount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function QuestionOverviewCard({
|
||||||
|
answerCount,
|
||||||
|
content,
|
||||||
|
similarCount,
|
||||||
|
upvoteCount,
|
||||||
|
timestamp,
|
||||||
|
role,
|
||||||
|
location,
|
||||||
|
}: QuestionOverviewCardProps) {
|
||||||
|
return (
|
||||||
|
<article className="flex gap-2 rounded-md border border-slate-300 p-4">
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<Button
|
||||||
|
icon={ChevronUpIcon}
|
||||||
|
isLabelHidden={true}
|
||||||
|
label="Upvote"
|
||||||
|
variant="tertiary"
|
||||||
|
/>
|
||||||
|
<p>{upvoteCount}</p>
|
||||||
|
<Button
|
||||||
|
icon={ChevronDownIcon}
|
||||||
|
isLabelHidden={true}
|
||||||
|
label="Downvote"
|
||||||
|
variant="tertiary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<div className="flex items-center gap-2 text-slate-500">
|
||||||
|
<Badge label="Technical" variant="primary" />
|
||||||
|
<p className="text-xs">
|
||||||
|
{timestamp} · {location} · {role}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p className="line-clamp-2 text-ellipsis">{content}</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
addonPosition="start"
|
||||||
|
icon={ChatBubbleBottomCenterTextIcon}
|
||||||
|
label={`${answerCount} answers`}
|
||||||
|
size="sm"
|
||||||
|
variant="tertiary"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
addonPosition="start"
|
||||||
|
icon={EyeIcon}
|
||||||
|
label={`${similarCount} received this`}
|
||||||
|
size="sm"
|
||||||
|
variant="tertiary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
|
||||||
|
import { Select, TextInput } from '@tih/ui';
|
||||||
|
|
||||||
|
export type SortOption = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionSearchBarProps<SortOptions extends Array<SortOption>> = {
|
||||||
|
onSortChange?: (sortValue: SortOptions[number]['value']) => void;
|
||||||
|
sortOptions: SortOptions;
|
||||||
|
sortValue: SortOptions[number]['value'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function QuestionSearchBar<
|
||||||
|
SortOptions extends Array<SortOption>,
|
||||||
|
>({
|
||||||
|
onSortChange,
|
||||||
|
sortOptions,
|
||||||
|
sortValue,
|
||||||
|
}: QuestionSearchBarProps<SortOptions>) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-end gap-2">
|
||||||
|
<div className="flex-1">
|
||||||
|
<TextInput
|
||||||
|
isLabelHidden={true}
|
||||||
|
label="Search by content"
|
||||||
|
placeholder="Search by content"
|
||||||
|
startIcon={MagnifyingGlassIcon}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
display="inline"
|
||||||
|
label="Sort by"
|
||||||
|
options={sortOptions}
|
||||||
|
value={sortValue}
|
||||||
|
onChange={onSortChange}></Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in new issue