import Head from 'next/head'; import { useRouter } from 'next/router'; import { useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Button, Collapsible, HorizontalDivider, TextArea } from '~/ui'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import FullQuestionCard from '~/components/questions/card/question/FullQuestionCard'; import QuestionAnswerCard from '~/components/questions/card/QuestionAnswerCard'; import QuestionCommentListItem from '~/components/questions/comments/QuestionCommentListItem'; import FullScreenSpinner from '~/components/questions/FullScreenSpinner'; import BackButtonLayout from '~/components/questions/layout/BackButtonLayout'; import PaginationLoadMoreButton from '~/components/questions/PaginationLoadMoreButton'; import SortOptionsSelect from '~/components/questions/SortOptionsSelect'; import { APP_TITLE } from '~/utils/questions/constants'; import createSlug from '~/utils/questions/createSlug'; import relabelQuestionAggregates from '~/utils/questions/relabelQuestionAggregates'; import { useFormRegister } from '~/utils/questions/useFormRegister'; import { useProtectedCallback } from '~/utils/questions/useProtectedCallback'; import { trpc } from '~/utils/trpc'; import { SortOrder, SortType } from '~/types/questions.d'; export type AnswerQuestionData = { answerContent: string; }; export type QuestionCommentData = { commentContent: string; }; export default function QuestionPage() { const router = useRouter(); const { event } = useGoogleAnalytics(); const [answerSortOrder, setAnswerSortOrder] = useState( SortOrder.DESC, ); const [answerSortType, setAnswerSortType] = useState(SortType.NEW); const [commentSortOrder, setCommentSortOrder] = useState( SortOrder.DESC, ); const [commentSortType, setCommentSortType] = useState( SortType.NEW, ); const { register: ansRegister, handleSubmit, reset: resetAnswer, formState: { isDirty, isValid }, } = useForm({ mode: 'onChange' }); const answerRegister = useFormRegister(ansRegister); const { register: comRegister, handleSubmit: handleCommentSubmitClick, reset: resetComment, formState: { isDirty: isCommentDirty, isValid: isCommentValid }, } = useForm({ mode: 'onChange' }); const commentRegister = useFormRegister(comRegister); const { questionId } = router.query; const { data: question } = trpc.useQuery([ 'questions.questions.getQuestionById', { id: questionId as string }, ]); const { data: aggregatedEncounters } = trpc.useQuery([ 'questions.questions.encounters.getAggregatedEncounters', { questionId: questionId as string }, ]); const relabeledAggregatedEncounters = useMemo(() => { if (!aggregatedEncounters) { return aggregatedEncounters; } return relabelQuestionAggregates(aggregatedEncounters); }, [aggregatedEncounters]); const utils = trpc.useContext(); const commentInfiniteQuery = trpc.useInfiniteQuery( [ 'questions.questions.comments.getQuestionComments', { limit: 5, questionId: questionId as string, sortOrder: commentSortOrder, sortType: commentSortType, }, ], { getNextPageParam: (lastPage) => lastPage.nextCursor, keepPreviousData: true, }, ); const { data: commentData } = commentInfiniteQuery; const { mutate: addComment } = trpc.useMutation( 'questions.questions.comments.user.create', { onSuccess: () => { utils.invalidateQueries( 'questions.questions.comments.getQuestionComments', ); const previousData = utils.getQueryData([ 'questions.questions.getQuestionById', { id: questionId as string }, ]); if (previousData === undefined) { return; } utils.setQueryData( ['questions.questions.getQuestionById', { id: questionId as string }], { ...previousData, numComments: previousData.numComments + 1, }, ); event({ action: 'questions.comment', category: 'engagement', label: 'comment on question', }); }, }, ); const answerInfiniteQuery = trpc.useInfiniteQuery( [ 'questions.answers.getAnswers', { limit: 5, questionId: questionId as string, sortOrder: answerSortOrder, sortType: answerSortType, }, ], { getNextPageParam: (lastPage) => lastPage.nextCursor, keepPreviousData: true, }, ); const { data: answerData } = answerInfiniteQuery; const { mutate: addAnswer } = trpc.useMutation( 'questions.answers.user.create', { onSuccess: () => { utils.invalidateQueries('questions.answers.getAnswers'); const previousData = utils.getQueryData([ 'questions.questions.getQuestionById', { id: questionId as string }, ]); if (previousData === undefined) { return; } utils.setQueryData( ['questions.questions.getQuestionById', { id: questionId as string }], { ...previousData, numAnswers: previousData.numAnswers + 1, }, ); event({ action: 'questions.answer', category: 'engagement', label: 'add answer to question', }); }, }, ); const { mutateAsync: addEncounterAsync } = trpc.useMutation( 'questions.questions.encounters.user.create', { onSuccess: () => { utils.invalidateQueries( 'questions.questions.encounters.getAggregatedEncounters', ); utils.invalidateQueries('questions.questions.getQuestionById'); event({ action: 'questions.create_question', category: 'engagement', label: 'create question encounter', }); }, }, ); const handleSubmitAnswer = useProtectedCallback( (data: AnswerQuestionData) => { addAnswer({ content: data.answerContent, questionId: questionId as string, }); resetAnswer(); }, ); const handleSubmitComment = useProtectedCallback( (data: QuestionCommentData) => { addComment({ content: data.commentContent, questionId: questionId as string, }); resetComment(); }, ); if (!question) { return ; } return ( <> {question.content} - {APP_TITLE}
{ await addEncounterAsync({ cityId: data.cityId, companyId: data.company, countryId: data.countryId, questionId: questionId as string, role: data.role, seenAt: data.seenAt, stateId: data.stateId, }); }} />
{question.numComments}{' '} {question.numComments === 1 ? 'comment' : 'comments'}
}>
{(commentData?.pages ?? []).flatMap(({ data: comments }) => comments.map((comment) => ( )), )}