[questions][ui] improve mobile back navigation

pull/517/head
Jeff Sieu 3 years ago
parent f12c36fc4b
commit 429115a9b9

@ -0,0 +1,30 @@
import type { PropsWithChildren } from 'react';
import { ArrowSmallLeftIcon } from '@heroicons/react/24/outline';
import { Button } from '@tih/ui';
export type BackButtonLayoutProps = PropsWithChildren<{
href: string;
}>;
export default function BackButtonLayout({
href,
children,
}: BackButtonLayoutProps) {
return (
<div className="flex w-full flex-1 flex-col items-stretch gap-4 p-4 lg:flex-row">
<div>
<Button
addonPosition="start"
display="inline"
href={href}
icon={ArrowSmallLeftIcon}
label="Back"
variant="secondary"
/>
</div>
<div className="flex w-full justify-center overflow-y-auto">
{children}
</div>
</div>
);
}

@ -2,12 +2,12 @@ import Head from 'next/head';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useState } from 'react'; import { useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { ArrowSmallLeftIcon } from '@heroicons/react/24/outline';
import { Button, TextArea } from '@tih/ui'; import { Button, TextArea } from '@tih/ui';
import AnswerCommentListItem from '~/components/questions/AnswerCommentListItem'; import AnswerCommentListItem from '~/components/questions/AnswerCommentListItem';
import FullAnswerCard from '~/components/questions/card/FullAnswerCard'; import FullAnswerCard from '~/components/questions/card/FullAnswerCard';
import FullScreenSpinner from '~/components/questions/FullScreenSpinner'; import FullScreenSpinner from '~/components/questions/FullScreenSpinner';
import BackButtonLayout from '~/components/questions/layout/BackButtonLayout';
import PaginationLoadMoreButton from '~/components/questions/PaginationLoadMoreButton'; import PaginationLoadMoreButton from '~/components/questions/PaginationLoadMoreButton';
import SortOptionsSelect from '~/components/questions/SortOptionsSelect'; import SortOptionsSelect from '~/components/questions/SortOptionsSelect';
@ -104,83 +104,72 @@ export default function QuestionPage() {
{answer.content} - {APP_TITLE} {answer.content} - {APP_TITLE}
</title> </title>
</Head> </Head>
<div className="flex w-full flex-1 items-stretch pb-4"> <BackButtonLayout
<div className="flex items-baseline gap-2 py-4 pl-4"> href={`/questions/${router.query.questionId}/${router.query.questionSlug}`}>
<Button <div className="flex max-w-7xl flex-1 flex-col gap-2">
addonPosition="start" <FullAnswerCard
display="inline" answerId={answer.id}
href={`/questions/${router.query.questionId}/${router.query.questionSlug}`} authorImageUrl={answer.userImage}
icon={ArrowSmallLeftIcon} authorName={answer.user}
label="Back" content={answer.content}
variant="secondary" createdAt={answer.createdAt}
upvoteCount={answer.numVotes}
/> />
</div> <div className="mx-2">
<div className="flex w-full justify-center overflow-y-auto py-4 px-5"> <form
<div className="flex max-w-7xl flex-1 flex-col gap-2"> className="mb-2"
<FullAnswerCard onSubmit={handleCommentSubmit(handleSubmitComment)}>
answerId={answer.id} <TextArea
authorImageUrl={answer.userImage} {...commentRegister('commentContent', {
authorName={answer.user} minLength: 1,
content={answer.content} required: true,
createdAt={answer.createdAt} })}
upvoteCount={answer.numVotes} label="Post a comment"
/> required={true}
<div className="mx-2"> resize="vertical"
<form rows={2}
className="mb-2" />
onSubmit={handleCommentSubmit(handleSubmitComment)}> <div className="my-3 flex justify-between">
<TextArea <Button
{...commentRegister('commentContent', { disabled={!isCommentDirty || !isCommentValid}
minLength: 1, label="Post"
required: true, type="submit"
})} variant="primary"
label="Post a comment"
required={true}
resize="vertical"
rows={2}
/> />
<div className="my-3 flex justify-between"> </div>
<Button </form>
disabled={!isCommentDirty || !isCommentValid} <div className="flex flex-col gap-2">
label="Post" <div className="flex items-center justify-between gap-2">
type="submit" <p className="text-lg">Comments</p>
variant="primary" <div className="flex items-end gap-2">
<SortOptionsSelect
sortOrderValue={commentSortOrder}
sortTypeValue={commentSortType}
onSortOrderChange={setCommentSortOrder}
onSortTypeChange={setCommentSortType}
/> />
</div> </div>
</form>
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between gap-2">
<p className="text-lg">Comments</p>
<div className="flex items-end gap-2">
<SortOptionsSelect
sortOrderValue={commentSortOrder}
sortTypeValue={commentSortType}
onSortOrderChange={setCommentSortOrder}
onSortTypeChange={setCommentSortType}
/>
</div>
</div>
{/* TODO: Allow to load more pages */}
{(answerCommentsData?.pages ?? []).flatMap(
({ processedQuestionAnswerCommentsData: comments }) =>
comments.map((comment) => (
<AnswerCommentListItem
key={comment.id}
answerCommentId={comment.id}
authorImageUrl={comment.userImage}
authorName={comment.user}
content={comment.content}
createdAt={comment.createdAt}
upvoteCount={comment.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={answerCommentInfiniteQuery} />
</div> </div>
{/* TODO: Allow to load more pages */}
{(answerCommentsData?.pages ?? []).flatMap(
({ processedQuestionAnswerCommentsData: comments }) =>
comments.map((comment) => (
<AnswerCommentListItem
key={comment.id}
answerCommentId={comment.id}
authorImageUrl={comment.userImage}
authorName={comment.user}
content={comment.content}
createdAt={comment.createdAt}
upvoteCount={comment.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={answerCommentInfiniteQuery} />
</div> </div>
</div> </div>
</div> </div>
</div> </BackButtonLayout>
</> </>
); );
} }

@ -2,13 +2,13 @@ import Head from 'next/head';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { ArrowSmallLeftIcon } from '@heroicons/react/24/outline';
import { Button, Collapsible, HorizontalDivider, TextArea } from '@tih/ui'; import { Button, Collapsible, HorizontalDivider, TextArea } from '@tih/ui';
import AnswerCommentListItem from '~/components/questions/AnswerCommentListItem'; import AnswerCommentListItem from '~/components/questions/AnswerCommentListItem';
import FullQuestionCard from '~/components/questions/card/question/FullQuestionCard'; import FullQuestionCard from '~/components/questions/card/question/FullQuestionCard';
import QuestionAnswerCard from '~/components/questions/card/QuestionAnswerCard'; import QuestionAnswerCard from '~/components/questions/card/QuestionAnswerCard';
import FullScreenSpinner from '~/components/questions/FullScreenSpinner'; import FullScreenSpinner from '~/components/questions/FullScreenSpinner';
import BackButtonLayout from '~/components/questions/layout/BackButtonLayout';
import PaginationLoadMoreButton from '~/components/questions/PaginationLoadMoreButton'; import PaginationLoadMoreButton from '~/components/questions/PaginationLoadMoreButton';
import SortOptionsSelect from '~/components/questions/SortOptionsSelect'; import SortOptionsSelect from '~/components/questions/SortOptionsSelect';
@ -182,168 +182,154 @@ export default function QuestionPage() {
{question.content} - {APP_TITLE} {question.content} - {APP_TITLE}
</title> </title>
</Head> </Head>
<div className="flex w-full flex-1 items-stretch pb-4"> <BackButtonLayout href="/questions/browse">
<div className="flex items-baseline gap-2 py-4 pl-4"> <div className="flex max-w-7xl flex-1 flex-col gap-2">
<Button <div className="flex flex-col gap-2 rounded-md border bg-white p-4">
addonPosition="start" <FullQuestionCard
display="inline" {...question}
href="/questions/browse" companies={relabeledAggregatedEncounters?.companyCounts ?? {}}
icon={ArrowSmallLeftIcon} countries={relabeledAggregatedEncounters?.countryCounts ?? {}}
label="Back" createEncounterButtonText="I received this too"
variant="secondary" questionId={question.id}
/> receivedCount={undefined}
</div> roles={relabeledAggregatedEncounters?.roleCounts ?? {}}
<div className="flex w-full justify-center overflow-y-auto py-4 px-5"> timestamp={question.seenAt.toLocaleDateString(undefined, {
<div className="flex max-w-7xl flex-1 flex-col gap-2"> month: 'short',
<div className="flex flex-col gap-2 rounded-md border bg-white p-4"> year: 'numeric',
<FullQuestionCard })}
{...question} upvoteCount={question.numVotes}
companies={relabeledAggregatedEncounters?.companyCounts ?? {}} onReceivedSubmit={async (data) => {
countries={relabeledAggregatedEncounters?.countryCounts ?? {}} await addEncounterAsync({
createEncounterButtonText="I received this too" cityId: data.cityId,
questionId={question.id} companyId: data.company,
receivedCount={undefined} countryId: data.countryId,
roles={relabeledAggregatedEncounters?.roleCounts ?? {}} questionId: questionId as string,
timestamp={question.seenAt.toLocaleDateString(undefined, { role: data.role,
month: 'short', seenAt: data.seenAt,
year: 'numeric', stateId: data.stateId,
})} });
upvoteCount={question.numVotes} }}
onReceivedSubmit={async (data) => { />
await addEncounterAsync({ <div className="ml-16 mr-2">
cityId: data.cityId, <Collapsible
companyId: data.company, defaultOpen={true}
countryId: data.countryId, label={
questionId: questionId as string, <div className="text-primary-700">{`${question.numComments} comment(s)`}</div>
role: data.role, }>
seenAt: data.seenAt, <div className="">
stateId: data.stateId, <div className="flex flex-col gap-2 text-black">
}); <div className="flex justify-end gap-2">
}} <div className="flex items-end gap-2">
/> <SortOptionsSelect
<div className="ml-16 mr-2"> sortOrderValue={commentSortOrder}
<Collapsible sortTypeValue={commentSortType}
defaultOpen={true} onSortOrderChange={setCommentSortOrder}
label={ onSortTypeChange={setCommentSortType}
<div className="text-primary-700">{`${question.numComments} comment(s)`}</div>
}>
<div className="">
<div className="flex flex-col gap-2 text-black">
<div className="flex justify-end gap-2">
<div className="flex items-end gap-2">
<SortOptionsSelect
sortOrderValue={commentSortOrder}
sortTypeValue={commentSortType}
onSortOrderChange={setCommentSortOrder}
onSortTypeChange={setCommentSortType}
/>
</div>
</div>
{(commentData?.pages ?? []).flatMap(
({ processedQuestionCommentsData: comments }) =>
comments.map((comment) => (
<AnswerCommentListItem
key={comment.id}
answerCommentId={comment.id}
authorImageUrl={comment.userImage}
authorName={comment.user}
content={comment.content}
createdAt={comment.createdAt}
upvoteCount={comment.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={commentInfiniteQuery} />
<form
className="mt-4"
onSubmit={handleCommentSubmitClick(
handleSubmitComment,
)}>
<TextArea
{...commentRegister('commentContent', {
minLength: 1,
required: true,
})}
label="Post a comment"
required={true}
resize="vertical"
rows={2}
/> />
<div className="my-3 flex justify-between"> </div>
<Button
disabled={!isCommentDirty || !isCommentValid}
label="Post"
type="submit"
variant="primary"
/>
</div>
</form>
</div> </div>
{(commentData?.pages ?? []).flatMap(
({ processedQuestionCommentsData: comments }) =>
comments.map((comment) => (
<AnswerCommentListItem
key={comment.id}
answerCommentId={comment.id}
authorImageUrl={comment.userImage}
authorName={comment.user}
content={comment.content}
createdAt={comment.createdAt}
upvoteCount={comment.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={commentInfiniteQuery} />
<form
className="mt-4"
onSubmit={handleCommentSubmitClick(handleSubmitComment)}>
<TextArea
{...commentRegister('commentContent', {
minLength: 1,
required: true,
})}
label="Post a comment"
required={true}
resize="vertical"
rows={2}
/>
<div className="my-3 flex justify-between">
<Button
disabled={!isCommentDirty || !isCommentValid}
label="Post"
type="submit"
variant="primary"
/>
</div>
</form>
</div> </div>
</Collapsible> </div>
</div> </Collapsible>
</div> </div>
<HorizontalDivider /> </div>
<form onSubmit={handleSubmit(handleSubmitAnswer)}> <HorizontalDivider />
<div className="flex flex-col gap-2"> <form onSubmit={handleSubmit(handleSubmitAnswer)}>
<p className="text-md font-semibold">Contribute your answer</p> <div className="flex flex-col gap-2">
<TextArea <p className="text-md font-semibold">Contribute your answer</p>
{...answerRegister('answerContent', { <TextArea
minLength: 1, {...answerRegister('answerContent', {
required: true, minLength: 1,
})} required: true,
isLabelHidden={true} })}
label="Contribute your answer" isLabelHidden={true}
required={true} label="Contribute your answer"
resize="vertical" required={true}
rows={5} resize="vertical"
/> rows={5}
</div> />
<div className="mt-3 mb-1 flex justify-between"> </div>
<Button <div className="mt-3 mb-1 flex justify-between">
disabled={!isDirty || !isValid} <Button
label="Contribute" disabled={!isDirty || !isValid}
type="submit" label="Contribute"
variant="primary" type="submit"
/> variant="primary"
</div> />
</form> </div>
<div className="flex items-center justify-between gap-2"> </form>
<p className="text-xl font-semibold"> <div className="flex items-center justify-between gap-2">
{question.numAnswers} answers <p className="text-xl font-semibold">
</p> {question.numAnswers} answers
<div className="flex items-end gap-2"> </p>
<SortOptionsSelect <div className="flex items-end gap-2">
sortOrderValue={answerSortOrder} <SortOptionsSelect
sortTypeValue={answerSortType} sortOrderValue={answerSortOrder}
onSortOrderChange={setAnswerSortOrder} sortTypeValue={answerSortType}
onSortTypeChange={setAnswerSortType} onSortOrderChange={setAnswerSortOrder}
/> onSortTypeChange={setAnswerSortType}
</div> />
</div> </div>
{/* TODO: Add button to load more */}
{(answerData?.pages ?? []).flatMap(
({ processedAnswersData: answers }) =>
answers.map((answer) => (
<QuestionAnswerCard
key={answer.id}
answerId={answer.id}
authorImageUrl={answer.userImage}
authorName={answer.user}
commentCount={answer.numComments}
content={answer.content}
createdAt={answer.createdAt}
href={`${router.asPath}/answer/${answer.id}/${createSlug(
answer.content,
)}`}
upvoteCount={answer.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={answerInfiniteQuery} />
</div> </div>
{/* TODO: Add button to load more */}
{(answerData?.pages ?? []).flatMap(
({ processedAnswersData: answers }) =>
answers.map((answer) => (
<QuestionAnswerCard
key={answer.id}
answerId={answer.id}
authorImageUrl={answer.userImage}
authorName={answer.user}
commentCount={answer.numComments}
content={answer.content}
createdAt={answer.createdAt}
href={`${router.asPath}/answer/${answer.id}/${createSlug(
answer.content,
)}`}
upvoteCount={answer.numVotes}
/>
)),
)}
<PaginationLoadMoreButton query={answerInfiniteQuery} />
</div> </div>
</div> </BackButtonLayout>
</> </>
); );
} }

Loading…
Cancel
Save