aboutsummaryrefslogtreecommitdiff
path: root/src/pages/Questions.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/Questions.tsx')
-rw-r--r--src/pages/Questions.tsx162
1 files changed, 118 insertions, 44 deletions
diff --git a/src/pages/Questions.tsx b/src/pages/Questions.tsx
index a6f0d7b..e9abe31 100644
--- a/src/pages/Questions.tsx
+++ b/src/pages/Questions.tsx
@@ -1,8 +1,14 @@
import React, {useMemo, useState} from 'react'
-import {UpkQuestion, UpkQuestionChoice} from "@/api";
-import {Card, CardContent, CardTitle, CardFooter, CardHeader} from "@/components/ui/card.tsx";
+import {
+ BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost,
+ ProfilingQuestionsApiFactory,
+ UpkQuestion,
+ UpkQuestionChoice,
+ UserQuestionAnswerIn
+} from "@/api";
+import {Card, CardContent, CardFooter, CardHeader, CardTitle} from "@/components/ui/card.tsx";
import {useAppDispatch, useAppSelector} from "@/hooks.ts";
-import {addAnswer, makeSelectChoicesByQuestion} from "@/models/answerSlice.ts";
+import answerSlice, {addAnswer, Answer,answerForQuestion, makeSelectChoicesByQuestion, saveAnswer} from "@/models/answerSlice.ts";
import {useSelector} from "react-redux";
import {Button} from "@/components/ui/button"
import {
@@ -12,41 +18,49 @@ import {
PaginationLink,
PaginationNext,
} from "@/components/ui/pagination"
-import { Input } from "@/components/ui/input"
+import {Input} from "@/components/ui/input"
import {Badge} from "@/components/ui/badge"
const TextEntry: React.FC<{ question: UpkQuestion }> = ({question}) => {
const dispatch = useAppDispatch()
const selectAnswer = useMemo(() => makeSelectChoicesByQuestion(question), [question]);
- const answer = useSelector(selectAnswer);
+ const answer: Answer = useSelector(selectAnswer);
+ const error: Boolean = answer.error_msg.length > 0
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
dispatch(addAnswer({question: question, val: event.target.value}))
};
- // console.log("TextEntry.answer", answer)
-
return (
- <Input type="text"
- id="text-entry-input"
- aria-describedby=""
- placeholder=""
- onKeyDown={handleInputChange}
- />
- // <small id="text-entry-msg">{answer.error_msg}</small>
+ <>
+ <Input type="text"
+ id="text-entry-input"
+ aria-describedby=""
+ defaultValue={answer.values.length ? answer.values[0] : ""}
+ onKeyUp={handleInputChange}
+ title={error ? answer.error_msg : ""}
+ className={error ? "border-red-500 focus-visible:ring-red-500" : ""}
+ />
+
+ {
+ error && <p className="text-sm text-red-500 mt-1">{answer.error_msg}</p>
+ }
+ </>
+
)
}
const MultiChoiceItem: React.FC<{ question: UpkQuestion, choice: UpkQuestionChoice }> = ({question, choice}) => {
const dispatch = useAppDispatch()
const selectAnswer = useMemo(() => makeSelectChoicesByQuestion(question), [question]);
- const answer = useSelector(selectAnswer);
+ const answer: Answer = useSelector(selectAnswer);
const selected: Boolean = answer.values.includes(choice.choice_id)
return (
<li key={choice.choice_id} style={{marginBottom: '0.5rem'}}>
<Button
onClick={() => dispatch(addAnswer({question: question, val: choice.choice_id}))}
+ className="cursor-pointer"
variant={selected ? "default" : "secondary"}
>
{choice.choice_text}
@@ -56,27 +70,40 @@ const MultiChoiceItem: React.FC<{ question: UpkQuestion, choice: UpkQuestionChoi
}
const MultipleChoice: React.FC<{ question: UpkQuestion }> = ({question}) => {
- // const selectAnswer = useMemo(() => makeSelectChoicesByQuestion(question), [question]);
- // const answer = useSelector(selectAnswer);
+ const selectAnswer = useMemo(() => makeSelectChoicesByQuestion(question), [question]);
+ const answer: Answer = useSelector(selectAnswer);
+ const error: Boolean = answer.error_msg.length > 0
return (
- // <small id="text-entry-msg">{answer.error_msg}</small>
- <ol style={{listStyle: 'none', padding: 0, margin: 0}}>
+ <>
{
- question.choices.map(c => {
- return <MultiChoiceItem
- key={`${question.question_id}-${c.choice_id}`}
- question={question}
- choice={c}/>
- })
+ error && <p className="text-sm text-red-500 mt-1">{answer.error_msg}</p>
}
- </ol>
+
+ <ol style={{listStyle: 'none', padding: 0, margin: 0}}>
+ {
+ question.choices.map(c => {
+ return <MultiChoiceItem
+ key={`${question.question_id}-${c.choice_id}`}
+ question={question}
+ choice={c}/>
+ })
+ }
+ </ol>
+ </>
)
}
const ProfileQuestionFull: React.FC<UpkQuestion> = ({question}) => {
+ const dispatch = useAppDispatch()
+ const selectAnswer = useMemo(() => makeSelectChoicesByQuestion(question), [question]);
+ const answer: Answer = useSelector(selectAnswer);
+ const app = useAppSelector(state => state.app)
+ const provided_answer = answer.values.length > 0
+ const error: Boolean = answer.error_msg.length > 0
+ const can_submit = provided_answer && !error && !answer.complete
const renderContent = () => {
switch (question.question_type) {
@@ -87,10 +114,38 @@ const ProfileQuestionFull: React.FC<UpkQuestion> = ({question}) => {
}
};
+ const submitAnswer = () => {
+ if (!can_submit) {
+ return;
+ }
+
+ if (answer.complete || answer.processing) {
+ return
+ }
+
+ let body: BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost = {
+ 'answers': [{
+ "question_id": question.question_id,
+ "answer": answer.values
+ } as UserQuestionAnswerIn
+ ]
+ }
+ console.log("submitAnswers", body)
+ new ProfilingQuestionsApiFactory().submitProfilingQuestionsProductIdProfilingQuestionsPost(app.bpid, app.bpuid, body)
+ .then(res => {
+ if (res.status == 200) {
+ dispatch(saveAnswer({question: question}))
+ } else {
+ // let error_msg = res.data.msg
+ }
+ })
+ .catch(err => console.log(err));
+ }
+
return (
<Card className="@container/card relative">
<Badge
- className="absolute top-2 right-2 h-5 min-w-5 rounded-full px-1 font-mono tabular-nums"
+ className="absolute top-2 right-2 h-5 min-w-5 rounded-full px-1 font-mono tabular-nums cursor-pointer"
variant="outline"
title={`Currently ${question.task_count.toLocaleString()} surveys use this profiling question`}
>
@@ -103,21 +158,51 @@ const ProfileQuestionFull: React.FC<UpkQuestion> = ({question}) => {
<CardContent>
{renderContent()}
</CardContent>
- <CardFooter className="flex-col gap-2">
- <Button type="submit" className="w-full">
+ <CardFooter className="flex justify-end">
+ <Button
+ type="submit"
+ className="w-1/3 cursor-pointer"
+ disabled={!can_submit}
+ onClick={submitAnswer}
+ >
Submit
</Button>
</CardFooter>
</Card>
)
}
+// type Props = {
+// onSetQuestionID: (name: string) => void
+// }
+
+const PaginationIcon: React.FC<{
+ question: UpkQuestion, activeQuestionID: string, idx: number, onSetQuestionID: () => void
+}> = ({question, activeQuestionID, idx, onSetQuestionID}) => {
+
+ const answers = useAppSelector(state => state.answers)
+ const answer = answers[question.question_id]
+
+ return (
+ <PaginationItem>
+ <PaginationLink
+ href="#"
+ title={question.question_text}
+ isActive={question.question_id === activeQuestionID}
+ aria-disabled={answer?.complete}
+
+ onClick={(e) => answer?.complete ? e.preventDefault() : onSetQuestionID(question.question_id)}
+ className={answer?.complete ? "pointer-events-none opacity-50 cursor-not-allowed" : ""}>
+ {idx + 1}
+ </PaginationLink>
+ </PaginationItem>
+ )
+}
const QuestionsPage = () => {
const questions = useAppSelector(state => state.questions)
- const [activeQuestionID, setQuestionID] = useState(() => questions[0].question_id);
+ const [activeQuestionID, setQuestionID] = useState(() => questions[0].question_id);
const question = questions.find(q => q.question_id === activeQuestionID);
- console.log("activeQuestionID:", activeQuestionID, question)
return (
<div>
@@ -129,18 +214,8 @@ const QuestionsPage = () => {
<PaginationContent>
{
questions.slice(0, 5).map((q, i) => {
- return (
- <PaginationItem>
- <PaginationLink
- href="#"
- title={q.question_text}
- onClick={() => setQuestionID(q.question_id)}
- isActive={q.question_id === activeQuestionID}
- >
- {i + 1}
- </PaginationLink>
- </PaginationItem>
- )
+ return <PaginationIcon key={q.question_id} question={q} idx={i}
+ onSetQuestionID={setQuestionID}/>
})
}
@@ -152,7 +227,6 @@ const QuestionsPage = () => {
</PaginationContent>
</Pagination>
-
<ProfileQuestionFull key={question.question_id} question={question} className="mt-4 mb-4"/>
</div>
)