diff --git a/apps/portal/package.json b/apps/portal/package.json index f1bdb9e7..208b1940 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -15,6 +15,7 @@ "@headlessui/react": "^1.7.3", "@heroicons/react": "^2.0.11", "@next-auth/prisma-adapter": "^1.0.4", + "@popperjs/core": "^2.11.6", "@prisma/client": "^4.4.0", "@supabase/supabase-js": "^1.35.7", "@tih/ui": "*", @@ -33,6 +34,8 @@ "react-dropzone": "^14.2.3", "react-hook-form": "^7.36.1", "react-pdf": "^5.7.2", + "react-popper": "^2.3.0", + "react-popper-tooltip": "^4.4.2", "react-query": "^3.39.2", "superjson": "^1.10.0", "zod": "^3.18.0" diff --git a/apps/portal/src/components/questions/ContributeQuestionCard.tsx b/apps/portal/src/components/questions/ContributeQuestionCard.tsx index 73faba27..dc7d2836 100644 --- a/apps/portal/src/components/questions/ContributeQuestionCard.tsx +++ b/apps/portal/src/components/questions/ContributeQuestionCard.tsx @@ -7,7 +7,7 @@ import { import { TextInput } from '@tih/ui'; import ContributeQuestionDialog from './ContributeQuestionDialog'; -import type { ContributeQuestionFormProps } from './ContributeQuestionForm'; +import type { ContributeQuestionFormProps } from './forms/ContributeQuestionForm'; export type ContributeQuestionCardProps = Pick< ContributeQuestionFormProps, diff --git a/apps/portal/src/components/questions/ContributeQuestionDialog.tsx b/apps/portal/src/components/questions/ContributeQuestionDialog.tsx index b21b21dc..dd548d37 100644 --- a/apps/portal/src/components/questions/ContributeQuestionDialog.tsx +++ b/apps/portal/src/components/questions/ContributeQuestionDialog.tsx @@ -2,9 +2,9 @@ import { Fragment, useState } from 'react'; import { Dialog, Transition } from '@headlessui/react'; import { HorizontalDivider } from '@tih/ui'; -import type { ContributeQuestionFormProps } from './ContributeQuestionForm'; -import ContributeQuestionForm from './ContributeQuestionForm'; import DiscardDraftDialog from './DiscardDraftDialog'; +import type { ContributeQuestionFormProps } from './forms/ContributeQuestionForm'; +import ContributeQuestionForm from './forms/ContributeQuestionForm'; export type ContributeQuestionDialogProps = Pick< ContributeQuestionFormProps, @@ -60,14 +60,14 @@ export default function ContributeQuestionDialog({ leave="ease-in duration-200" leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"> - +
- Question Draft + Contribute question
diff --git a/apps/portal/src/components/questions/LandingComponent.tsx b/apps/portal/src/components/questions/LandingComponent.tsx index 7f3ffee4..1007f1e4 100644 --- a/apps/portal/src/components/questions/LandingComponent.tsx +++ b/apps/portal/src/components/questions/LandingComponent.tsx @@ -1,13 +1,15 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { ArrowSmallRightIcon } from '@heroicons/react/24/outline'; import type { QuestionsQuestionType } from '@prisma/client'; import { Button, Select } from '@tih/ui'; -import { - COMPANIES, - LOCATIONS, - QUESTION_TYPES, -} from '~/utils/questions/constants'; +import { QUESTION_TYPES } from '~/utils/questions/constants'; +import useDefaultCompany from '~/utils/questions/useDefaultCompany'; +import useDefaultLocation from '~/utils/questions/useDefaultLocation'; + +import type { FilterChoice } from './filter/FilterSection'; +import CompanyTypeahead from './typeahead/CompanyTypeahead'; +import LocationTypeahead from './typeahead/LocationTypeahead'; export type LandingQueryData = { company: string; @@ -22,76 +24,109 @@ export type LandingComponentProps = { export default function LandingComponent({ onLanded: handleLandingQuery, }: LandingComponentProps) { - const [landingQueryData, setLandingQueryData] = useState({ - company: 'Google', - location: 'Singapore', - questionType: 'CODING', - }); + const defaultCompany = useDefaultCompany(); + const defaultLocation = useDefaultLocation(); - const handleChangeCompany = (company: string) => { - setLandingQueryData((prev) => ({ ...prev, company })); + const [company, setCompany] = useState( + defaultCompany, + ); + const [location, setLocation] = useState( + defaultLocation, + ); + + const [questionType, setQuestionType] = + useState('CODING'); + + const handleChangeCompany = (newCompany: FilterChoice) => { + setCompany(newCompany); }; - const handleChangeLocation = (location: string) => { - setLandingQueryData((prev) => ({ ...prev, location })); + const handleChangeLocation = (newLocation: FilterChoice) => { + setLocation(newLocation); }; - const handleChangeType = (questionType: QuestionsQuestionType) => { - setLandingQueryData((prev) => ({ ...prev, questionType })); + const handleChangeType = (newQuestionType: QuestionsQuestionType) => { + setQuestionType(newQuestionType); }; + useEffect(() => { + if (company === undefined) { + setCompany(defaultCompany); + } + }, [defaultCompany, company]); + + useEffect(() => { + if (location === undefined) { + setLocation(defaultLocation); + } + }, [defaultLocation, location]); + return ( -
-
-
-
- app logo -

- Tech Interview Question Bank -

-
-

- Get to know the latest SWE interview questions asked by top companies -

- -
-

Find

-
+
+
+
+
+

+ Tech Interview Question Bank +

+ app logo +
+

+ Know the{' '} + + latest SWE interview questions + {' '} + asked by top companies. +

+
+
+

Find questions

+
+

about

-

in

- -
-
-
); diff --git a/apps/portal/src/components/questions/QuestionsNavigation.ts b/apps/portal/src/components/questions/QuestionsNavigation.ts index 457845bb..f46d2388 100644 --- a/apps/portal/src/components/questions/QuestionsNavigation.ts +++ b/apps/portal/src/components/questions/QuestionsNavigation.ts @@ -1,9 +1,10 @@ import type { ProductNavigationItems } from '~/components/global/ProductNavigation'; const navigation: ProductNavigationItems = [ - { href: '/questions', name: 'My Lists' }, - { href: '/questions', name: 'My Questions' }, - { href: '/questions', name: 'History' }, + { href: '/questions/browse', name: 'Browse' }, + { href: '/questions/lists', name: 'My Lists' }, + { href: '/questions/my-questions', name: 'My Questions' }, + { href: '/questions/history', name: 'History' }, ]; const config = { diff --git a/apps/portal/src/components/questions/card/AnswerCard.tsx b/apps/portal/src/components/questions/card/AnswerCard.tsx index 20818ee7..5407e95e 100644 --- a/apps/portal/src/components/questions/card/AnswerCard.tsx +++ b/apps/portal/src/components/questions/card/AnswerCard.tsx @@ -13,6 +13,7 @@ export type AnswerCardProps = { commentCount?: number; content: string; createdAt: Date; + showHover?: boolean; upvoteCount: number; votingButtonsSize: VotingButtonsProps['size']; }; @@ -26,10 +27,14 @@ export default function AnswerCard({ commentCount, votingButtonsSize, upvoteCount, + showHover, }: AnswerCardProps) { const { handleUpvote, handleDownvote, vote } = useAnswerVote(answerId); + const hoverClass = showHover ? 'hover:bg-slate-50' : ''; + return ( -
+
; - -export default function FullQuestionCard(props: QuestionOverviewCardProps) { - return ( - - ); -} diff --git a/apps/portal/src/components/questions/card/QuestionAnswerCard.tsx b/apps/portal/src/components/questions/card/QuestionAnswerCard.tsx index b508e5b4..ab573d7e 100644 --- a/apps/portal/src/components/questions/card/QuestionAnswerCard.tsx +++ b/apps/portal/src/components/questions/card/QuestionAnswerCard.tsx @@ -4,11 +4,11 @@ import type { AnswerCardProps } from './AnswerCard'; import AnswerCard from './AnswerCard'; export type QuestionAnswerCardProps = Required< - Omit + Omit >; function QuestionAnswerCardWithoutHref(props: QuestionAnswerCardProps) { - return ; + return ; } const QuestionAnswerCard = withHref(QuestionAnswerCardWithoutHref); diff --git a/apps/portal/src/components/questions/card/QuestionCard.tsx b/apps/portal/src/components/questions/card/QuestionCard.tsx deleted file mode 100644 index ba530f75..00000000 --- a/apps/portal/src/components/questions/card/QuestionCard.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { ChatBubbleBottomCenterTextIcon } from '@heroicons/react/24/outline'; -import type { QuestionsQuestionType } from '@prisma/client'; -import { Badge, Button } from '@tih/ui'; - -import { useQuestionVote } from '~/utils/questions/useVote'; - -import QuestionTypeBadge from '../QuestionTypeBadge'; -import VotingButtons from '../VotingButtons'; - -type UpvoteProps = - | { - showVoteButtons: true; - upvoteCount: number; - } - | { - showVoteButtons?: false; - upvoteCount?: never; - }; - -type StatisticsProps = - | { - answerCount: number; - showUserStatistics: true; - } - | { - answerCount?: never; - showUserStatistics?: false; - }; - -type ActionButtonProps = - | { - actionButtonLabel: string; - onActionButtonClick: () => void; - showActionButton: true; - } - | { - actionButtonLabel?: never; - onActionButtonClick?: never; - showActionButton?: false; - }; - -export type QuestionCardProps = ActionButtonProps & - StatisticsProps & - UpvoteProps & { - company: string; - content: string; - location: string; - questionId: string; - receivedCount: number; - role: string; - timestamp: string; - type: QuestionsQuestionType; - }; - -export default function QuestionCard({ - questionId, - company, - answerCount, - content, - // ReceivedCount, - type, - showVoteButtons, - showUserStatistics, - showActionButton, - actionButtonLabel, - onActionButtonClick, - upvoteCount, - timestamp, - role, - location, -}: QuestionCardProps) { - const { handleDownvote, handleUpvote, vote } = useQuestionVote(questionId); - - return ( -
- {showVoteButtons && ( - - )} -
-
-
- - -

- {timestamp} · {location} · {role} -

-
- {showActionButton && ( -
-
-

{content}

-
- {showUserStatistics && ( -
-
- )} -
-
- ); -} diff --git a/apps/portal/src/components/questions/card/QuestionOverviewCard.tsx b/apps/portal/src/components/questions/card/QuestionOverviewCard.tsx deleted file mode 100644 index fa786917..00000000 --- a/apps/portal/src/components/questions/card/QuestionOverviewCard.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import withHref from '~/utils/questions/withHref'; - -import type { QuestionCardProps } from './QuestionCard'; -import QuestionCard from './QuestionCard'; - -export type QuestionOverviewCardProps = Omit< - QuestionCardProps & { - showActionButton: false; - showUserStatistics: true; - showVoteButtons: true; - }, - | 'actionButtonLabel' - | 'onActionButtonClick' - | 'showActionButton' - | 'showUserStatistics' - | 'showVoteButtons' ->; - -function QuestionOverviewCardWithoutHref(props: QuestionOverviewCardProps) { - return ( - - ); -} - -const QuestionOverviewCard = withHref(QuestionOverviewCardWithoutHref); -export default QuestionOverviewCard; diff --git a/apps/portal/src/components/questions/card/SimilarQuestionCard.tsx b/apps/portal/src/components/questions/card/SimilarQuestionCard.tsx deleted file mode 100644 index 063bdf91..00000000 --- a/apps/portal/src/components/questions/card/SimilarQuestionCard.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type { QuestionCardProps } from './QuestionCard'; -import QuestionCard from './QuestionCard'; - -export type SimilarQuestionCardProps = Omit< - QuestionCardProps & { - showActionButton: true; - showUserStatistics: false; - showVoteButtons: false; - }, - | 'actionButtonLabel' - | 'answerCount' - | 'onActionButtonClick' - | 'showActionButton' - | 'showUserStatistics' - | 'showVoteButtons' - | 'upvoteCount' -> & { - onSimilarQuestionClick: () => void; -}; - -export default function SimilarQuestionCard(props: SimilarQuestionCardProps) { - const { onSimilarQuestionClick, ...rest } = props; - return ( - - ); -} diff --git a/apps/portal/src/components/questions/card/question/BaseQuestionCard.tsx b/apps/portal/src/components/questions/card/question/BaseQuestionCard.tsx new file mode 100644 index 00000000..3c54d58b --- /dev/null +++ b/apps/portal/src/components/questions/card/question/BaseQuestionCard.tsx @@ -0,0 +1,232 @@ +import clsx from 'clsx'; +import { useState } from 'react'; +import { + ChatBubbleBottomCenterTextIcon, + CheckIcon, + EyeIcon, + TrashIcon, +} from '@heroicons/react/24/outline'; +import type { QuestionsQuestionType } from '@prisma/client'; +import { Button } from '@tih/ui'; + +import { useQuestionVote } from '~/utils/questions/useVote'; + +import type { CreateQuestionEncounterData } from '../../forms/CreateQuestionEncounterForm'; +import CreateQuestionEncounterForm from '../../forms/CreateQuestionEncounterForm'; +import QuestionAggregateBadge from '../../QuestionAggregateBadge'; +import QuestionTypeBadge from '../../QuestionTypeBadge'; +import VotingButtons from '../../VotingButtons'; + +type UpvoteProps = + | { + showVoteButtons: true; + upvoteCount: number; + } + | { + showVoteButtons?: false; + upvoteCount?: never; + }; + +type DeleteProps = + | { + onDelete: () => void; + showDeleteButton: true; + } + | { + onDelete?: never; + showDeleteButton?: false; + }; + +type AnswerStatisticsProps = + | { + answerCount: number; + showAnswerStatistics: true; + } + | { + answerCount?: never; + showAnswerStatistics?: false; + }; + +type ActionButtonProps = + | { + actionButtonLabel: string; + onActionButtonClick: () => void; + showActionButton: true; + } + | { + actionButtonLabel?: never; + onActionButtonClick?: never; + showActionButton?: false; + }; + +type ReceivedStatisticsProps = + | { + receivedCount: number; + showReceivedStatistics: true; + } + | { + receivedCount?: never; + showReceivedStatistics?: false; + }; + +type CreateEncounterProps = + | { + onReceivedSubmit: (data: CreateQuestionEncounterData) => void; + showCreateEncounterButton: true; + } + | { + onReceivedSubmit?: never; + showCreateEncounterButton?: false; + }; + +export type BaseQuestionCardProps = ActionButtonProps & + AnswerStatisticsProps & + CreateEncounterProps & + DeleteProps & + ReceivedStatisticsProps & + UpvoteProps & { + companies: Record; + content: string; + locations: Record; + questionId: string; + roles: Record; + showHover?: boolean; + timestamp: string; + truncateContent?: boolean; + type: QuestionsQuestionType; + }; + +export default function BaseQuestionCard({ + questionId, + companies, + answerCount, + content, + receivedCount, + type, + showVoteButtons, + showAnswerStatistics, + showReceivedStatistics, + showCreateEncounterButton, + showActionButton, + actionButtonLabel, + onActionButtonClick, + upvoteCount, + timestamp, + roles, + locations, + showHover, + onReceivedSubmit, + showDeleteButton, + onDelete, + truncateContent = true, +}: BaseQuestionCardProps) { + const [showReceivedForm, setShowReceivedForm] = useState(false); + const { handleDownvote, handleUpvote, vote } = useQuestionVote(questionId); + const hoverClass = showHover ? 'hover:bg-slate-50' : ''; + const cardContent = ( + <> + {showVoteButtons && ( + + )} +
+
+
+ + + + +

{timestamp}

+
+ {showActionButton && ( +
+

+ {content} +

+ {!showReceivedForm && + (showAnswerStatistics || + showReceivedStatistics || + showCreateEncounterButton) && ( +
+ {showAnswerStatistics && ( +
+ )} + {showReceivedForm && ( + { + setShowReceivedForm(false); + }} + onSubmit={(data) => { + onReceivedSubmit?.(data); + setShowReceivedForm(false); + }} + /> + )} +
+ + ); + + return ( +
+ {cardContent} + {showDeleteButton && ( +
+
+ )} +
+ ); +} diff --git a/apps/portal/src/components/questions/card/question/FullQuestionCard.tsx b/apps/portal/src/components/questions/card/question/FullQuestionCard.tsx new file mode 100644 index 00000000..c99b4409 --- /dev/null +++ b/apps/portal/src/components/questions/card/question/FullQuestionCard.tsx @@ -0,0 +1,35 @@ +import type { BaseQuestionCardProps } from './BaseQuestionCard'; +import BaseQuestionCard from './BaseQuestionCard'; + +export type QuestionOverviewCardProps = Omit< + BaseQuestionCardProps & { + showActionButton: false; + showAnswerStatistics: false; + showCreateEncounterButton: true; + showDeleteButton: false; + showReceivedStatistics: false; + showVoteButtons: true; + }, + | 'actionButtonLabel' + | 'onActionButtonClick' + | 'showActionButton' + | 'showAnswerStatistics' + | 'showCreateEncounterButton' + | 'showDeleteButton' + | 'showReceivedStatistics' + | 'showVoteButtons' +>; + +export default function FullQuestionCard(props: QuestionOverviewCardProps) { + return ( + + ); +} diff --git a/apps/portal/src/components/questions/card/question/QuestionListCard.tsx b/apps/portal/src/components/questions/card/question/QuestionListCard.tsx new file mode 100644 index 00000000..b7b74cfa --- /dev/null +++ b/apps/portal/src/components/questions/card/question/QuestionListCard.tsx @@ -0,0 +1,36 @@ +import withHref from '~/utils/questions/withHref'; + +import type { BaseQuestionCardProps } from './BaseQuestionCard'; +import BaseQuestionCard from './BaseQuestionCard'; + +export type QuestionListCardProps = Omit< + BaseQuestionCardProps & { + showActionButton: false; + showAnswerStatistics: false; + showDeleteButton: true; + showVoteButtons: false; + }, + | 'actionButtonLabel' + | 'onActionButtonClick' + | 'showActionButton' + | 'showAnswerStatistics' + | 'showDeleteButton' + | 'showVoteButtons' +>; + +function QuestionListCardWithoutHref(props: QuestionListCardProps) { + return ( + + ); +} + +const QuestionListCard = withHref(QuestionListCardWithoutHref); +export default QuestionListCard; diff --git a/apps/portal/src/components/questions/card/question/QuestionOverviewCard.tsx b/apps/portal/src/components/questions/card/question/QuestionOverviewCard.tsx new file mode 100644 index 00000000..77ae5efa --- /dev/null +++ b/apps/portal/src/components/questions/card/question/QuestionOverviewCard.tsx @@ -0,0 +1,42 @@ +import withHref from '~/utils/questions/withHref'; + +import type { BaseQuestionCardProps } from './BaseQuestionCard'; +import BaseQuestionCard from './BaseQuestionCard'; + +export type QuestionOverviewCardProps = Omit< + BaseQuestionCardProps & { + showActionButton: false; + showAnswerStatistics: true; + showCreateEncounterButton: false; + showDeleteButton: false; + showReceivedStatistics: true; + showVoteButtons: true; + }, + | 'actionButtonLabel' + | 'onActionButtonClick' + | 'onDelete' + | 'showActionButton' + | 'showAnswerStatistics' + | 'showCreateEncounterButton' + | 'showDeleteButton' + | 'showReceivedStatistics' + | 'showVoteButtons' +>; + +function QuestionOverviewCardWithoutHref(props: QuestionOverviewCardProps) { + return ( + + ); +} + +const QuestionOverviewCard = withHref(QuestionOverviewCardWithoutHref); +export default QuestionOverviewCard; diff --git a/apps/portal/src/components/questions/card/question/SimilarQuestionCard.tsx b/apps/portal/src/components/questions/card/question/SimilarQuestionCard.tsx new file mode 100644 index 00000000..846a57e4 --- /dev/null +++ b/apps/portal/src/components/questions/card/question/SimilarQuestionCard.tsx @@ -0,0 +1,44 @@ +import type { BaseQuestionCardProps } from './BaseQuestionCard'; +import BaseQuestionCard from './BaseQuestionCard'; + +export type SimilarQuestionCardProps = Omit< + BaseQuestionCardProps & { + showActionButton: true; + showAnswerStatistics: true; + showCreateEncounterButton: false; + showDeleteButton: false; + showHover: true; + showReceivedStatistics: false; + showVoteButtons: false; + }, + | 'actionButtonLabel' + | 'onActionButtonClick' + | 'showActionButton' + | 'showAnswerStatistics' + | 'showCreateEncounterButton' + | 'showDeleteButton' + | 'showHover' + | 'showReceivedStatistics' + | 'showVoteButtons' +> & { + onSimilarQuestionClick: () => void; +}; + +export default function SimilarQuestionCard(props: SimilarQuestionCardProps) { + const { onSimilarQuestionClick, ...rest } = props; + return ( + + ); +} diff --git a/apps/portal/src/components/questions/filter/FilterSection.tsx b/apps/portal/src/components/questions/filter/FilterSection.tsx index 312122c3..b72bc7ff 100644 --- a/apps/portal/src/components/questions/filter/FilterSection.tsx +++ b/apps/portal/src/components/questions/filter/FilterSection.tsx @@ -1,14 +1,20 @@ -import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; -import { CheckboxInput, Collapsible, RadioList, TextInput } from '@tih/ui'; +import { useMemo } from 'react'; +import type { UseFormRegisterReturn } from 'react-hook-form'; +import { useForm } from 'react-hook-form'; +import { CheckboxInput, Collapsible, RadioList } from '@tih/ui'; -export type FilterOption = { - checked: boolean; +export type FilterChoice = { + id: string; label: string; value: V; }; +export type FilterOption = FilterChoice & { + checked: boolean; +}; + export type FilterChoices = ReadonlyArray< - Omit, 'checked'> + FilterChoice >; type FilterSectionType> = @@ -30,42 +36,87 @@ export type FilterSectionProps> = options: FilterOptions; } & ( | { - searchPlaceholder: string; + renderInput: (props: { + field: UseFormRegisterReturn<'search'>; + onOptionChange: FilterSectionType['onOptionChange']; + options: FilterOptions; + }) => React.ReactNode; showAll?: never; } | { - searchPlaceholder?: never; + renderInput?: never; showAll: true; } ); +export type FilterSectionFormData = { + search: string; +}; + export default function FilterSection< FilterOptions extends Array, >({ label, options, - searchPlaceholder, showAll, onOptionChange, isSingleSelect, + renderInput, }: FilterSectionProps) { + const { register, reset } = useForm(); + + const registerSearch = register('search'); + + const field: UseFormRegisterReturn<'search'> = { + ...registerSearch, + onChange: async (event) => { + await registerSearch.onChange(event); + reset(); + }, + }; + + const autocompleteOptions = useMemo(() => { + return options.filter((option) => !option.checked) as FilterOptions; + }, [options]); + + const selectedCount = useMemo(() => { + return options.filter((option) => option.checked).length; + }, [options]); + + const collapsibleLabel = useMemo(() => { + if (isSingleSelect) { + return label; + } + if (selectedCount === 0) { + return `${label} (all)`; + } + + return `${label} (${selectedCount})`; + }, [label, selectedCount, isSingleSelect]); + return ( -
- +
+
{!showAll && ( - +
+ {renderInput({ + field, + onOptionChange: async ( + optionValue: FilterOptions[number]['value'], + ) => { + reset(); + return onOptionChange(optionValue, true); + }, + options: autocompleteOptions, + })} +
)} {isSingleSelect ? (
option.checked)?.value} onChange={(value) => { onOptionChange(value); @@ -81,16 +132,18 @@ export default function FilterSection<
) : (
- {options.map((option) => ( - { - onOptionChange(option.value, checked); - }} - /> - ))} + {options + .filter((option) => showAll || option.checked) + .map((option) => ( + { + onOptionChange(option.value, checked); + }} + /> + ))}
)}
diff --git a/apps/portal/src/components/questions/ContributeQuestionForm.tsx b/apps/portal/src/components/questions/forms/ContributeQuestionForm.tsx similarity index 59% rename from apps/portal/src/components/questions/ContributeQuestionForm.tsx rename to apps/portal/src/components/questions/forms/ContributeQuestionForm.tsx index a0e4d0b6..a4daa3c6 100644 --- a/apps/portal/src/components/questions/ContributeQuestionForm.tsx +++ b/apps/portal/src/components/questions/forms/ContributeQuestionForm.tsx @@ -1,26 +1,26 @@ import { startOfMonth } from 'date-fns'; import { useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; -import { CalendarDaysIcon, UserIcon } from '@heroicons/react/24/outline'; import type { QuestionsQuestionType } from '@prisma/client'; import { Button, CheckboxInput, - Collapsible, + HorizontalDivider, Select, TextArea, - TextInput, } from '@tih/ui'; -import { QUESTION_TYPES } from '~/utils/questions/constants'; +import { LOCATIONS, QUESTION_TYPES, ROLES } from '~/utils/questions/constants'; import { useFormRegister, useSelectRegister, } from '~/utils/questions/useFormRegister'; -import CompaniesTypeahead from '../shared/CompaniesTypeahead'; -import type { Month } from '../shared/MonthYearPicker'; -import MonthYearPicker from '../shared/MonthYearPicker'; +import CompanyTypeahead from '../typeahead/CompanyTypeahead'; +import LocationTypeahead from '../typeahead/LocationTypeahead'; +import RoleTypeahead from '../typeahead/RoleTypeahead'; +import type { Month } from '../../shared/MonthYearPicker'; +import MonthYearPicker from '../../shared/MonthYearPicker'; export type ContributeQuestionData = { company: string; @@ -59,8 +59,17 @@ export default function ContributeQuestionForm({ }; return (
+
+