diff options
| author | Max Nanis | 2025-06-07 04:17:19 +0700 |
|---|---|---|
| committer | Max Nanis | 2025-06-07 04:17:19 +0700 |
| commit | 51b1003d1e0ce43aa6c30f461d710cb09cdfc29f (patch) | |
| tree | 85a33808ae2e01a3a46ffbbf4e0255b0c27caa7e /src/pages | |
| parent | 257bc2f85b71a8564e95a8e6ba39ab0b00e022df (diff) | |
| download | panel-ui-51b1003d1e0ce43aa6c30f461d710cb09cdfc29f.tar.gz panel-ui-51b1003d1e0ce43aa6c30f461d710cb09cdfc29f.zip | |
Passing in onClick for FullProfileQuestion so that Profile Question and SoftPair are different. Using API models to POST to Softpair submission (with offerwall_id saved). Updating from Conditional to Ineligible buckets. Availability Count to app state. Using / exploring sidebar to show filtered questions for specific Bucket.
Diffstat (limited to 'src/pages')
| -rw-r--r-- | src/pages/Offerwall.tsx | 89 | ||||
| -rw-r--r-- | src/pages/Questions.tsx | 67 |
2 files changed, 121 insertions, 35 deletions
diff --git a/src/pages/Offerwall.tsx b/src/pages/Offerwall.tsx index acce696..178e762 100644 --- a/src/pages/Offerwall.tsx +++ b/src/pages/Offerwall.tsx @@ -1,12 +1,25 @@ import React from 'react' import {Separator} from "@/components/ui/separator" import {Link} from '@mui/material'; +import {useSelector} from "react-redux"; import {Card, CardContent, CardFooter, CardHeader, CardTitle} from "@/components/ui/card.tsx"; import {ScrollArea} from "@/components/ui/scroll-area.tsx"; +import {makeSelectQuestionsByIds, setNextQuestion, setQuestions} from "@/models/questionSlice.ts" import {CheckIcon, MessageCircleQuestionIcon, XIcon} from "lucide-react" -import {SoftPairBucket} from "@/api/models/soft-pair-bucket.ts" -import {useAppSelector} from '@/hooks' +import { + BodyOfferwallSoftpairPostProductIdOfferwall37d1da64OfferwallIdPost, + OfferwallApi, + SoftPairBucket, + UserQuestionAnswerIn +} from "@/api" +import {useAppDispatch, useAppSelector} from '@/hooks' +import {Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger,} from "@/components/ui/sheet" +import {ProfileQuestionFull} from "@/pages/Questions.tsx" +import {Answer, saveAnswer, selectAnswerForQuestion, submitAnswer} from "@/models/answerSlice.ts"; +import {assert} from "@/lib/utils.ts"; +import {setAvailabilityCount, setOfferwallId} from "@/models/appSlice.ts"; +import {setBuckets} from "@/models/bucketSlice.ts"; const BucketStatus: React.FC<SoftPairBucket> = ({bucket}) => { switch (bucket.eligibility) { @@ -19,6 +32,74 @@ const BucketStatus: React.FC<SoftPairBucket> = ({bucket}) => { } } +const ConditionalQuestions: React.FC<SoftPairBucket> = ({bucket}) => { + const dispatch = useAppDispatch() + + const questions = useSelector(makeSelectQuestionsByIds(bucket.missing_questions)) + const question = questions[0] + const answer: Answer | undefined = useSelector(selectAnswerForQuestion(question)); + const app = useAppSelector(state => state.app) + + console.log("Conditional bucket:", questions, question, answer) + + const submitEvt = () => { + dispatch(submitAnswer({question: question})) + + assert(!answer?.complete, "Can't submit completed Answer") + assert(!answer?.processing, "Can't submit processing Answer") + assert(answer?.error_msg.length == 0, "Can't submit Answer with error message") + + let body: BodyOfferwallSoftpairPostProductIdOfferwall37d1da64OfferwallIdPost = { + 'answers': [{ + "question_id": question.question_id, + "answer": answer.values + } as UserQuestionAnswerIn + ] + } + + new OfferwallApi().offerwallSoftpairPostProductIdOfferwall37d1da64OfferwallIdPost(app.bpid, app.offerwall_id, app.bpuid, body) + .then(res => { + if (res.status == 200) { + dispatch(setAvailabilityCount(res.data.offerwall.availability_count)) + dispatch(setOfferwallId(res.data.offerwall.id)) + dispatch(setBuckets(res.data.offerwall.buckets)) + } else { + // let error_msg = res.data.msg + } + }) + .catch(err => console.log(err)); + } + + return ( + <Sheet> + <SheetTrigger>Open</SheetTrigger> + <SheetContent + side="right" + className="md:w-[900px], lg:w-[1000px]"> + + <SheetHeader> + <SheetTitle>Bucket Questions</SheetTitle> + <SheetDescription> + This survey has some unanswered questions. Answer these to determine if you're + eligible for the Survey Bucket + </SheetDescription> + </SheetHeader> + + { + questions.map(q => { + return <ProfileQuestionFull + key={q.question_id} + question={q} + submitAnswerEvt={submitEvt} + className="mt-4 m-2"/> + }) + } + + </SheetContent> + </Sheet> + ) +} + const CallToAction: React.FC<SoftPairBucket> = ({bucket}) => { switch (bucket.eligibility) { case "eligible": @@ -28,9 +109,7 @@ const CallToAction: React.FC<SoftPairBucket> = ({bucket}) => { </button> </Link>; case "conditional": - return <button type="button"> - Unlock Survey - </button>; + return <ConditionalQuestions bucket={bucket}/> case "ineligible": return <button type="button"> diff --git a/src/pages/Questions.tsx b/src/pages/Questions.tsx index 3cd6f71..06374b2 100644 --- a/src/pages/Questions.tsx +++ b/src/pages/Questions.tsx @@ -110,9 +110,9 @@ const MultipleChoice: React.FC<{ question: ProfileQuestion }> = ({question}) => } -const ProfileQuestionFull: React.FC<{ - question: ProfileQuestion, -}> = ({question}) => { +export const ProfileQuestionFull: React.FC<{ + question: ProfileQuestion, submitAnswerEvt: () => void +}> = ({question, submitAnswerEvt}) => { const dispatch = useAppDispatch() @@ -134,31 +134,6 @@ const ProfileQuestionFull: React.FC<{ } }; - const submitAnswerEvt = () => { - dispatch(submitAnswer({question: question})) - - assert(!answer?.complete, "Can't submit completed Answer") - assert(!answer?.processing, "Can't submit processing Answer") - assert(answer?.error_msg.length == 0, "Can't submit Answer with error message") - - let body: BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost = { - 'answers': [{ - "question_id": question.question_id, - "answer": answer.values - } as UserQuestionAnswerIn - ] - } - new ProfilingQuestionsApiFactory().submitProfilingQuestionsProductIdProfilingQuestionsPost(app.bpid, app.bpuid, body) - .then(res => { - if (res.status == 200) { - dispatch(saveAnswer({question: question})) - dispatch(setNextQuestion()) - } else { - // let error_msg = res.data.msg - } - }) - .catch(err => console.log(err)); - } return ( <Card className="@container/card relative overflow-hidden"> @@ -175,9 +150,9 @@ const ProfileQuestionFull: React.FC<{ <Badge 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`} + title={`Currently ${(question.task_count ?? 0).toLocaleString()} surveys use this profiling question`} > - {question.task_count.toLocaleString()} + {(question.task_count ?? 0).toLocaleString()} </Badge> <CardHeader> @@ -249,6 +224,9 @@ const QuestionsPage = () => { // cannot be done within the click handler. const nextQuestion = useSelector(selectNextAvailableQuestion) + const answer: Answer | undefined = useSelector(selectAnswerForQuestion(question)); + const app = useAppSelector(state => state.app) + const clickNext = () => { // TODO: if nextQuestion was already submitted, skip it! if (nextQuestion) { @@ -285,6 +263,34 @@ const QuestionsPage = () => { return items.slice(start, end) } + + const submitAnswerEvt = () => { + dispatch(submitAnswer({question: question})) + + assert(!answer?.complete, "Can't submit completed Answer") + assert(!answer?.processing, "Can't submit processing Answer") + assert(answer?.error_msg.length == 0, "Can't submit Answer with error message") + + let body: BodySubmitProfilingQuestionsProductIdProfilingQuestionsPost = { + 'answers': [{ + "question_id": question.question_id, + "answer": answer.values + } as UserQuestionAnswerIn + ] + } + new ProfilingQuestionsApiFactory().submitProfilingQuestionsProductIdProfilingQuestionsPost(app.bpid, app.bpuid, body) + .then(res => { + if (res.status == 200) { + dispatch(saveAnswer({question: question})) + dispatch(setNextQuestion()) + } else { + // let error_msg = res.data.msg + } + }) + .catch(err => console.log(err)); + } + + return ( <> <Pagination className="mt-4 mb-4"> @@ -311,6 +317,7 @@ const QuestionsPage = () => { <ProfileQuestionFull key={question.question_id} question={question} + submitAnswerEvt={submitAnswerEvt} className="mt-4 mb-4"/> </> ) |
