diff --git a/apps/portal/src/components/global/AppShell.tsx b/apps/portal/src/components/global/AppShell.tsx
index eeb2dfc9..0275dbb5 100644
--- a/apps/portal/src/components/global/AppShell.tsx
+++ b/apps/portal/src/components/global/AppShell.tsx
@@ -175,7 +175,7 @@ export default function AppShell({ children }: Props) {
/>
{/* Content area */}
-
+
+ );
+}
diff --git a/apps/portal/src/components/questions/ContributeQuestionCard.tsx b/apps/portal/src/components/questions/ContributeQuestionCard.tsx
index bd6c4d78..fa11f098 100644
--- a/apps/portal/src/components/questions/ContributeQuestionCard.tsx
+++ b/apps/portal/src/components/questions/ContributeQuestionCard.tsx
@@ -1,102 +1,83 @@
-import type { ComponentProps, ForwardedRef } from 'react';
import { useState } 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';
+import { TextInput } from '@tih/ui';
-import ContributeQuestionModal from './ContributeQuestionModal';
+import ContributeQuestionDialog from './ContributeQuestionDialog';
+import type { ContributeQuestionFormProps } from './ContributeQuestionForm';
-export type ContributeQuestionData = {
- company: string;
- date: Date;
- questionContent: string;
- questionType: string;
-};
-
-type TextInputProps = ComponentProps;
-
-type FormTextInputProps = Omit &
- Pick, 'onChange'>;
-
-function FormTextInputWithRef(
- props: FormTextInputProps,
- ref?: ForwardedRef,
-) {
- const { onChange, ...rest } = props;
- return (
- onChange(event)}
- />
- );
-}
-
-const FormTextInput = forwardRef(FormTextInputWithRef);
-
-export type ContributeQuestionCardProps = {
- onSubmit: (data: ContributeQuestionData) => void;
-};
+export type ContributeQuestionCardProps = Pick<
+ ContributeQuestionFormProps,
+ 'onSubmit'
+>;
export default function ContributeQuestionCard({
onSubmit,
}: ContributeQuestionCardProps) {
- const { register, handleSubmit } = useForm();
- const [isOpen, setOpen] = useState(false);
+ const [showDraftDialog, setShowDraftDialog] = useState(false);
+
+ const handleDraftDialogCancel = () => {
+ setShowDraftDialog(false);
+ };
+
+ const handleOpenContribute = () => {
+ setShowDraftDialog(true);
+ };
+
return (
- <>
-
-
-
- >
+
+
+
);
}
diff --git a/apps/portal/src/components/questions/ContributeQuestionDialog.tsx b/apps/portal/src/components/questions/ContributeQuestionDialog.tsx
new file mode 100644
index 00000000..e2ae8c8c
--- /dev/null
+++ b/apps/portal/src/components/questions/ContributeQuestionDialog.tsx
@@ -0,0 +1,100 @@
+import { Fragment, useState } from 'react';
+import { Dialog, Transition } from '@headlessui/react';
+
+import { HorizontalDivider } from '~/../../../packages/ui/dist';
+
+import type { ContributeQuestionFormProps } from './ContributeQuestionForm';
+import ContributeQuestionForm from './ContributeQuestionForm';
+import DiscardDraftDialog from './DiscardDraftDialog';
+
+export type ContributeQuestionDialogProps = Pick<
+ ContributeQuestionFormProps,
+ 'onSubmit'
+> & {
+ onCancel: () => void;
+ show: boolean;
+};
+
+export default function ContributeQuestionDialog({
+ show,
+ onSubmit,
+ onCancel,
+}: ContributeQuestionDialogProps) {
+ const [showDiscardDialog, setShowDiscardDialog] = useState(false);
+
+ const handleDraftDiscard = () => {
+ setShowDiscardDialog(false);
+ onCancel();
+ };
+
+ const handleDiscardCancel = () => {
+ setShowDiscardDialog(false);
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/apps/portal/src/components/questions/ContributeQuestionForm.tsx b/apps/portal/src/components/questions/ContributeQuestionForm.tsx
new file mode 100644
index 00000000..367f0d88
--- /dev/null
+++ b/apps/portal/src/components/questions/ContributeQuestionForm.tsx
@@ -0,0 +1,155 @@
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import {
+ BuildingOffice2Icon,
+ CalendarDaysIcon,
+ UserIcon,
+} from '@heroicons/react/24/outline';
+import type { QuestionsQuestionType } from '@prisma/client';
+import { Button, Collapsible, Select, TextArea, TextInput } from '@tih/ui';
+
+import { QUESTION_TYPES } from '~/utils/questions/constants';
+import {
+ useFormRegister,
+ useSelectRegister,
+} from '~/utils/questions/useFormRegister';
+
+import Checkbox from './ui-patch/Checkbox';
+
+export type ContributeQuestionData = {
+ company: string;
+ date: Date;
+ location: string;
+ position: string;
+ questionContent: string;
+ questionType: QuestionsQuestionType;
+ role: string;
+};
+
+export type ContributeQuestionFormProps = {
+ onDiscard: () => void;
+ onSubmit: (data: ContributeQuestionData) => void;
+};
+
+export default function ContributeQuestionForm({
+ onSubmit,
+ onDiscard,
+}: ContributeQuestionFormProps) {
+ const { register: formRegister, handleSubmit } =
+ useForm
();
+ const register = useFormRegister(formRegister);
+ const selectRegister = useSelectRegister(formRegister);
+
+ const [canSubmit, setCanSubmit] = useState(false);
+ const handleCheckSimilarQuestions = (checked: boolean) => {
+ setCanSubmit(checked);
+ };
+ return (
+
+ );
+}
diff --git a/apps/portal/src/components/questions/ContributeQuestionModal.tsx b/apps/portal/src/components/questions/ContributeQuestionModal.tsx
deleted file mode 100644
index 1da146e8..00000000
--- a/apps/portal/src/components/questions/ContributeQuestionModal.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import type { Dispatch, SetStateAction } from 'react';
-import { Fragment, useState } from 'react';
-import { Dialog, Transition } from '@headlessui/react';
-
-import Checkbox from './ui-patch/Checkbox';
-
-export type ContributeQuestionModalProps = {
- contributeState: boolean;
- setContributeState: Dispatch>;
-};
-
-export default function ContributeQuestionModal({
- contributeState,
- setContributeState,
-}: ContributeQuestionModalProps) {
- const [canSubmit, setCanSubmit] = useState(false);
-
- const handleCheckSimilarQuestions = (checked: boolean) => {
- setCanSubmit(checked);
- };
-
- return (
-
-
-
- );
-}
diff --git a/apps/portal/src/components/questions/DiscardDraftDialog.tsx b/apps/portal/src/components/questions/DiscardDraftDialog.tsx
new file mode 100644
index 00000000..85b56c4d
--- /dev/null
+++ b/apps/portal/src/components/questions/DiscardDraftDialog.tsx
@@ -0,0 +1,30 @@
+import { Button, Dialog } from '@tih/ui';
+
+export type DiscardDraftDialogProps = {
+ onCancel: () => void;
+ onDiscard: () => void;
+ show: boolean;
+};
+export default function DiscardDraftDialog({
+ show,
+ onCancel,
+ onDiscard,
+}: DiscardDraftDialogProps) {
+ return (
+
+ }
+ secondaryButton={
+
+ }
+ title="Discard draft"
+ onClose={onCancel}>
+
+ Are you sure you want to discard the current draft? This action cannot
+ be undone.
+
+
+ );
+}
diff --git a/apps/portal/src/components/questions/FullScreenSpinner.tsx b/apps/portal/src/components/questions/FullScreenSpinner.tsx
new file mode 100644
index 00000000..02e6e02f
--- /dev/null
+++ b/apps/portal/src/components/questions/FullScreenSpinner.tsx
@@ -0,0 +1,9 @@
+import { Spinner } from '@tih/ui';
+
+export default function FullScreenSpinner() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/portal/src/components/questions/LandingComponent.tsx b/apps/portal/src/components/questions/LandingComponent.tsx
new file mode 100644
index 00000000..b90323f5
--- /dev/null
+++ b/apps/portal/src/components/questions/LandingComponent.tsx
@@ -0,0 +1,108 @@
+import { 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';
+
+export type LandingQueryData = {
+ company: string;
+ location: string;
+ questionType: QuestionsQuestionType;
+};
+
+export type LandingComponentProps = {
+ onLanded: (data: LandingQueryData) => void;
+};
+
+export default function LandingComponent({
+ onLanded: handleLandingQuery,
+}: LandingComponentProps) {
+ const [landingQueryData, setLandingQueryData] = useState({
+ company: 'Google',
+ location: 'Singapore',
+ questionType: 'CODING',
+ });
+
+ const handleChangeCompany = (company: string) => {
+ setLandingQueryData((prev) => ({ ...prev, company }));
+ };
+
+ const handleChangeLocation = (location: string) => {
+ setLandingQueryData((prev) => ({ ...prev, location }));
+ };
+
+ const handleChangeType = (questionType: QuestionsQuestionType) => {
+ setLandingQueryData((prev) => ({ ...prev, questionType }));
+ };
+
+ return (
+
+
+
+
+

+
+ Tech Interview Question Bank
+
+
+
+ Get to know the latest SWE interview questions asked by top companies
+
+
+
+
Find
+
+
+
+
questions from
+
+
in
+
+
+
+
+
+
+
+
+ TODO questions Carousel
+
+
+
+
+ );
+}
diff --git a/apps/portal/src/components/questions/QuestionOverviewCard.tsx b/apps/portal/src/components/questions/QuestionOverviewCard.tsx
deleted file mode 100644
index 31435c04..00000000
--- a/apps/portal/src/components/questions/QuestionOverviewCard.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-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 (
-
-
-
-
-
-
- {timestamp} · {location} · {role}
-
-
-
{content}
-
-
-
-
-
-
- );
-}
diff --git a/apps/portal/src/components/questions/QuestionSearchBar.tsx b/apps/portal/src/components/questions/QuestionSearchBar.tsx
index 02ba0a89..d72ee69f 100644
--- a/apps/portal/src/components/questions/QuestionSearchBar.tsx
+++ b/apps/portal/src/components/questions/QuestionSearchBar.tsx
@@ -30,10 +30,13 @@ export default function QuestionSearchBar<
startAddOnType="icon"
/>
-