|
|
@ -5,10 +5,10 @@ import { QuestionCard } from './QuestionCard'; |
|
|
|
import { QuestionLoader } from './QuestionLoader'; |
|
|
|
import { QuestionLoader } from './QuestionLoader'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import type { QuestionType } from '../../lib/question-group'; |
|
|
|
import type { QuestionType } from '../../lib/question-group'; |
|
|
|
import { Confetti } from '../Confetti'; |
|
|
|
|
|
|
|
import { httpGet, httpPut } from '../../lib/http'; |
|
|
|
import { httpGet, httpPut } from '../../lib/http'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { QuestionFinished } from './QuestionFinished'; |
|
|
|
import { QuestionFinished } from './QuestionFinished'; |
|
|
|
|
|
|
|
import { Confetti } from '../Confetti'; |
|
|
|
|
|
|
|
|
|
|
|
type UserQuestionProgress = { |
|
|
|
type UserQuestionProgress = { |
|
|
|
know: string[]; |
|
|
|
know: string[]; |
|
|
@ -29,25 +29,12 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
const toast = useToast(); |
|
|
|
const toast = useToast(); |
|
|
|
|
|
|
|
|
|
|
|
const [isLoading, setIsLoading] = useState(true); |
|
|
|
const [isLoading, setIsLoading] = useState(true); |
|
|
|
const [confettiEl, setConfettiEl] = useState<HTMLElement | null>(null); |
|
|
|
const [showConfetti, setShowConfetti] = useState(false); |
|
|
|
|
|
|
|
|
|
|
|
const [questions, setQuestions] = useState<QuestionType[]>(); |
|
|
|
const [questions, setQuestions] = useState<QuestionType[]>(); |
|
|
|
const [pendingQuestions, setPendingQuestions] = useState<QuestionType[]>([]); |
|
|
|
const [pendingQuestions, setPendingQuestions] = useState<QuestionType[]>([]); |
|
|
|
|
|
|
|
|
|
|
|
const [userProgress, setUserProgress] = useState<UserQuestionProgress>(); |
|
|
|
const [userProgress, setUserProgress] = useState<UserQuestionProgress>(); |
|
|
|
const alreadyKnowRef = useRef<HTMLButtonElement>(null); |
|
|
|
const containerRef = useRef<HTMLDivElement>(null); |
|
|
|
const didNotKnowRef = useRef<HTMLButtonElement>(null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function showConfetti(el: HTMLElement | null) { |
|
|
|
|
|
|
|
// If confetti is already showing, remove that first
|
|
|
|
|
|
|
|
if (confettiEl) { |
|
|
|
|
|
|
|
setConfettiEl(null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.setTimeout(() => { |
|
|
|
|
|
|
|
setConfettiEl(el); |
|
|
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function fetchUserProgress(): Promise< |
|
|
|
async function fetchUserProgress(): Promise< |
|
|
|
UserQuestionProgress | undefined |
|
|
|
UserQuestionProgress | undefined |
|
|
@ -57,7 +44,9 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { response, error } = await httpGet<UserQuestionProgress>( |
|
|
|
const { response, error } = await httpGet<UserQuestionProgress>( |
|
|
|
`/v1-get-user-question-progress/${groupId}` |
|
|
|
`${ |
|
|
|
|
|
|
|
import.meta.env.PUBLIC_API_URL |
|
|
|
|
|
|
|
}/v1-get-user-question-progress/${groupId}` |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (error) { |
|
|
|
if (error) { |
|
|
@ -112,7 +101,9 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
setIsLoading(true); |
|
|
|
setIsLoading(true); |
|
|
|
|
|
|
|
|
|
|
|
const { response, error } = await httpPut<UserQuestionProgress>( |
|
|
|
const { response, error } = await httpPut<UserQuestionProgress>( |
|
|
|
`/v1-reset-question-progress/${groupId}`, |
|
|
|
`${ |
|
|
|
|
|
|
|
import.meta.env.PUBLIC_API_URL |
|
|
|
|
|
|
|
}/v1-reset-question-progress/${groupId}`,
|
|
|
|
{ |
|
|
|
{ |
|
|
|
type, |
|
|
|
type, |
|
|
|
} |
|
|
|
} |
|
|
@ -163,7 +154,9 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
const { response, error } = await httpPut<UserQuestionProgress>( |
|
|
|
const { response, error } = await httpPut<UserQuestionProgress>( |
|
|
|
`/v1-update-question-status/${groupId}`, |
|
|
|
`${ |
|
|
|
|
|
|
|
import.meta.env.PUBLIC_API_URL |
|
|
|
|
|
|
|
}/v1-update-question-status/${groupId}`,
|
|
|
|
{ |
|
|
|
{ |
|
|
|
status, |
|
|
|
status, |
|
|
|
questionId, |
|
|
|
questionId, |
|
|
@ -179,9 +172,17 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
newProgress = response; |
|
|
|
newProgress = response; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const updatedQuestionList = pendingQuestions.filter( |
|
|
|
|
|
|
|
(q) => q.id !== questionId |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
setUserProgress(newProgress); |
|
|
|
setUserProgress(newProgress); |
|
|
|
setPendingQuestions(pendingQuestions.filter((q) => q.id !== questionId)); |
|
|
|
setPendingQuestions(updatedQuestionList); |
|
|
|
setIsLoading(false); |
|
|
|
setIsLoading(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (updatedQuestionList.length === 0) { |
|
|
|
|
|
|
|
setShowConfetti(true); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
@ -194,16 +195,10 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
const hasProgress = knowCount > 0 || dontKnowCount > 0 || skipCount > 0; |
|
|
|
const hasProgress = knowCount > 0 || dontKnowCount > 0 || skipCount > 0; |
|
|
|
|
|
|
|
|
|
|
|
const currQuestion = pendingQuestions[0]; |
|
|
|
const currQuestion = pendingQuestions[0]; |
|
|
|
|
|
|
|
const hasFinished = !isLoading && hasProgress && !currQuestion; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div className="mb-40 gap-3 text-center"> |
|
|
|
<div className="mb-40 gap-3 text-center"> |
|
|
|
<Confetti |
|
|
|
|
|
|
|
element={confettiEl} |
|
|
|
|
|
|
|
onDone={() => { |
|
|
|
|
|
|
|
setConfettiEl(null); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<QuestionsProgress |
|
|
|
<QuestionsProgress |
|
|
|
knowCount={knowCount} |
|
|
|
knowCount={knowCount} |
|
|
|
didNotKnowCount={dontKnowCount} |
|
|
|
didNotKnowCount={dontKnowCount} |
|
|
@ -216,8 +211,21 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
}} |
|
|
|
}} |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<div className="relative mb-4 flex min-h-[400px] w-full overflow-hidden rounded-lg border border-gray-300 bg-white"> |
|
|
|
{showConfetti && containerRef.current && ( |
|
|
|
{!isLoading && hasProgress && !currQuestion && ( |
|
|
|
<Confetti |
|
|
|
|
|
|
|
pieces={100} |
|
|
|
|
|
|
|
element={containerRef.current} |
|
|
|
|
|
|
|
onDone={() => { |
|
|
|
|
|
|
|
setShowConfetti(false); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div |
|
|
|
|
|
|
|
ref={containerRef} |
|
|
|
|
|
|
|
className="relative mb-4 flex min-h-[400px] w-full overflow-hidden rounded-lg border border-gray-300 bg-white" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
{hasFinished && ( |
|
|
|
<QuestionFinished |
|
|
|
<QuestionFinished |
|
|
|
totalCount={unshuffledQuestions?.length || questions?.length || 0} |
|
|
|
totalCount={unshuffledQuestions?.length || questions?.length || 0} |
|
|
|
knowCount={knowCount} |
|
|
|
knowCount={knowCount} |
|
|
@ -232,12 +240,14 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
{isLoading && <QuestionLoader />} |
|
|
|
{isLoading && <QuestionLoader />} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-3 sm:flex-row"> |
|
|
|
<div |
|
|
|
|
|
|
|
className={`flex flex-col gap-3 sm:flex-row ${ |
|
|
|
|
|
|
|
hasFinished ? 'invisible' : 'visible' |
|
|
|
|
|
|
|
}`}
|
|
|
|
|
|
|
|
> |
|
|
|
<button |
|
|
|
<button |
|
|
|
disabled={isLoading || !currQuestion} |
|
|
|
disabled={isLoading || !currQuestion} |
|
|
|
ref={alreadyKnowRef} |
|
|
|
|
|
|
|
onClick={(e) => { |
|
|
|
onClick={(e) => { |
|
|
|
showConfetti(alreadyKnowRef.current); |
|
|
|
|
|
|
|
updateQuestionStatus('know', currQuestion.id).finally(() => null); |
|
|
|
updateQuestionStatus('know', currQuestion.id).finally(() => null); |
|
|
|
}} |
|
|
|
}} |
|
|
|
className="flex flex-1 items-center rounded-xl border border-gray-300 bg-white py-3 px-4 text-black transition-colors hover:border-black hover:bg-black hover:text-white disabled:pointer-events-none disabled:opacity-50" |
|
|
|
className="flex flex-1 items-center rounded-xl border border-gray-300 bg-white py-3 px-4 text-black transition-colors hover:border-black hover:bg-black hover:text-white disabled:pointer-events-none disabled:opacity-50" |
|
|
@ -246,9 +256,7 @@ export function QuestionsList(props: QuestionsListProps) { |
|
|
|
Already Know that |
|
|
|
Already Know that |
|
|
|
</button> |
|
|
|
</button> |
|
|
|
<button |
|
|
|
<button |
|
|
|
ref={didNotKnowRef} |
|
|
|
|
|
|
|
onClick={() => { |
|
|
|
onClick={() => { |
|
|
|
showConfetti(didNotKnowRef.current); |
|
|
|
|
|
|
|
updateQuestionStatus('dontKnow', currQuestion.id).finally( |
|
|
|
updateQuestionStatus('dontKnow', currQuestion.id).finally( |
|
|
|
() => null |
|
|
|
() => null |
|
|
|
); |
|
|
|
); |
|
|
|