feat: add finished screen for questions

pull/4459/head
Kamran Ahmed 1 year ago
parent 58dd3f2f41
commit 437d879af3
  1. 97
      src/components/Questions/QuestionFinished.tsx
  2. 26
      src/components/Questions/QuestionsList.tsx

@ -0,0 +1,97 @@
import type { ReactNode } from 'react';
import {
PartyPopper,
RefreshCcw,
SkipForward,
Sparkles,
ThumbsUp,
} from 'lucide-react';
import type { QuestionProgressType } from './QuestionsList';
type ProgressStatButtonProps = {
isDisabled?: boolean;
icon: ReactNode;
label: string;
count: number;
onClick: () => void;
};
function ProgressStatButton(props: ProgressStatButtonProps) {
const { icon, label, count, onClick, isDisabled = false } = props;
return (
<button
disabled={isDisabled}
onClick={onClick}
className="group relative flex flex-1 items-center overflow-hidden rounded-xl border border-gray-300 bg-white py-3 px-4 text-black disabled:pointer-events-none disabled:opacity-50"
>
{icon}
<span className="flex flex-grow justify-between">
<span>{label}</span>
<span>{count}</span>
</span>
<span className="absolute top-full left-0 right-0 flex h-full items-center justify-center border border-black bg-black text-white transition-all duration-200 group-hover:top-0">
Restart
</span>
</button>
);
}
type QuestionFinishedProps = {
knowCount: number;
didNotKnowCount: number;
skippedCount: number;
totalCount: number;
onReset: (type: QuestionProgressType | 'all') => void;
};
export function QuestionFinished(props: QuestionFinishedProps) {
const { knowCount, didNotKnowCount, skippedCount, totalCount, onReset } =
props;
return (
<div className="relative flex flex-grow flex-col items-center justify-center">
<PartyPopper className="mb-4 h-24 w-24 text-gray-300" />
<h1 className="text-2xl font-semibold text-gray-700">
Questions Finished
</h1>
<p className="mt-2 text-gray-500">
Click below revisit specific or all questions
</p>
<div className="mt-5 mb-5 flex w-full flex-col gap-3 px-2 sm:flex-row sm:px-16">
<ProgressStatButton
icon={<ThumbsUp className="mr-1 h-4" />}
label="Knew"
count={knowCount}
isDisabled={knowCount === 0}
onClick={() => onReset('know')}
/>
<ProgressStatButton
icon={<Sparkles className="mr-1 h-4" />}
label="Learned"
count={didNotKnowCount}
isDisabled={didNotKnowCount === 0}
onClick={() => onReset('dontKnow')}
/>
<ProgressStatButton
icon={<SkipForward className="mr-1 h-4" />}
label="Skipped"
count={skippedCount}
isDisabled={skippedCount === 0}
onClick={() => onReset('skip')}
/>
</div>
<div className="mt-2 text-sm">
<button
onClick={() => onReset('all')}
className="flex items-center gap-0.5 text-red-700 hover:text-black"
>
<RefreshCcw className="mr-1 h-4" />
Restart Asking
</button>
</div>
</div>
);
}

@ -8,6 +8,7 @@ import type { QuestionType } from '../../lib/question-group';
import { Confetti } from '../Confetti'; 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';
type UserQuestionProgress = { type UserQuestionProgress = {
know: string[]; know: string[];
@ -15,7 +16,7 @@ type UserQuestionProgress = {
skip: string[]; skip: string[];
}; };
type ProgressType = keyof UserQuestionProgress; export type QuestionProgressType = keyof UserQuestionProgress;
type QuestionsListProps = { type QuestionsListProps = {
groupId: string; groupId: string;
@ -90,7 +91,7 @@ export function QuestionsList(props: QuestionsListProps) {
setIsLoading(false); setIsLoading(false);
} }
async function resetProgress(type: ProgressType | 'all' = 'all') { async function resetProgress(type: QuestionProgressType | 'all' = 'all') {
let knownQuestions = userProgress?.know || []; let knownQuestions = userProgress?.know || [];
let didNotKnowQuestions = userProgress?.dontKnow || []; let didNotKnowQuestions = userProgress?.dontKnow || [];
let skipQuestions = userProgress?.skip || []; let skipQuestions = userProgress?.skip || [];
@ -146,7 +147,7 @@ export function QuestionsList(props: QuestionsListProps) {
} }
async function updateQuestionStatus( async function updateQuestionStatus(
status: ProgressType, status: QuestionProgressType,
questionId: string questionId: string
) { ) {
setIsLoading(true); setIsLoading(true);
@ -216,13 +217,24 @@ 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"> <div className="relative mb-4 flex min-h-[400px] w-full overflow-hidden rounded-lg border border-gray-300 bg-white">
{!isLoading && <QuestionCard question={currQuestion} />} {!isLoading && hasProgress && !currQuestion && (
<QuestionFinished
totalCount={unshuffledQuestions?.length || questions?.length || 0}
knowCount={knowCount}
didNotKnowCount={dontKnowCount}
skippedCount={skipCount}
onReset={(type: QuestionProgressType | 'all') => {
resetProgress(type).finally(() => null);
}}
/>
)}
{!isLoading && currQuestion && <QuestionCard question={currQuestion} />}
{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">
<button <button
disabled={isLoading} disabled={isLoading || !currQuestion}
ref={alreadyKnowRef} ref={alreadyKnowRef}
onClick={(e) => { onClick={(e) => {
showConfetti(alreadyKnowRef.current); showConfetti(alreadyKnowRef.current);
@ -241,7 +253,7 @@ export function QuestionsList(props: QuestionsListProps) {
() => null () => null
); );
}} }}
disabled={isLoading} disabled={isLoading || !currQuestion}
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"
> >
<Sparkles className="mr-1 h-4 text-current" /> <Sparkles className="mr-1 h-4 text-current" />
@ -251,7 +263,7 @@ export function QuestionsList(props: QuestionsListProps) {
onClick={() => { onClick={() => {
updateQuestionStatus('skip', currQuestion.id).finally(() => null); updateQuestionStatus('skip', currQuestion.id).finally(() => null);
}} }}
disabled={isLoading} disabled={isLoading || !currQuestion}
data-next-question="skip" data-next-question="skip"
className="flex flex-1 items-center rounded-xl border border-red-600 p-3 text-red-600 hover:bg-red-600 hover:text-white disabled:pointer-events-none disabled:opacity-50" className="flex flex-1 items-center rounded-xl border border-red-600 p-3 text-red-600 hover:bg-red-600 hover:text-white disabled:pointer-events-none disabled:opacity-50"
> >

Loading…
Cancel
Save