vkashti / app / admin / quiz / QuizProvider.tsx
QuizProvider.tsx
Raw
'use client';
import {
  createContext,
  useContext,
  useState,
  useEffect,
  ReactNode
} from 'react';
import { createClient } from '@/utils/supabase/client';
import { QuizAnswer } from '@/types/types';
import { getRound, groupByRound } from '@/utils/quizHelpers';

type QuizContextType = {
  answers: QuizAnswer[];
  groupedAnswers: {
    '1-10': QuizAnswer[];
    '11-20': QuizAnswer[];
    '21-30': QuizAnswer[];
    '31-35': QuizAnswer[];
  };
  allTeams: string[];
  teamTotals: Record<string, { round1: number; round2: number; round3: number; round4: number }>;
};

const QuizContext = createContext<QuizContextType | null>(null);

export function QuizProvider({ children, quizId }: { children: ReactNode; quizId: number }) {
  const supabase = createClient();
  const [answers, setAnswers] = useState<QuizAnswer[]>([]);

  // Fetch initial data
  useEffect(() => {
    const fetchAnswers = async () => {
      console.log('Fetching quiz answers for quiz_id:', quizId);
      
      // First, let's check if there are any answers for this quiz at all
      const { data: allAnswers, error: allAnswersError } = await supabase
        .from('quiz_answers')
        .select('*');
        
      if (allAnswersError) {
        console.error('Error fetching all quiz answers:', allAnswersError);
        return;
      }
      
      console.log('Total quiz answers in database:', allAnswers?.length);
      // Check for both number and string types of quiz_id
      const answersWithQuizId6 = allAnswers?.filter(a => {
        if (typeof a.quiz_id === 'number') return a.quiz_id === 6;
        if (typeof a.quiz_id === 'string') return a.quiz_id === '6';
        return false;
      });
      console.log('Quiz answers with quiz_id=6 (any type):', answersWithQuizId6?.length);
      
      // Now fetch the specific answers for this quiz
      const { data, error } = await supabase
        .from('quiz_answers')
        .select('*')
        .eq('quiz_id', quizId);

      if (error) {
        console.error('Error fetching quiz answers:', error);
        return;
      }

      console.log('Fetched quiz answers for quiz_id', quizId, ':', data?.length);
      
      // Try with string comparison as a fallback
      if (!data || data.length === 0) {
        console.log('Trying with string comparison...');
        // Use 'or' filter instead of eq with string to avoid type issues
        const { data: stringData, error: stringError } = await supabase
          .from('quiz_answers')
          .select('*')
          .or(`quiz_id.eq.${quizId},quiz_id.eq.${String(quizId)}`);
          
        if (stringError) {
          console.error('Error fetching quiz answers with string comparison:', stringError);
        } else {
          console.log('Fetched quiz answers with string comparison:', stringData?.length);
          if (stringData && stringData.length > 0) {
            // Type assertion to handle nullable fields from Supabase
            const typedAnswers = stringData.map(answer => ({
              ...answer,
              team_name: answer.team_name || '',
              answer: answer.answer || '',
              question_number: answer.question_number || 0,
              points: answer.points || 0,
              correct: answer.correct || false
            })) as QuizAnswer[];

            setAnswers(typedAnswers);
            return;
          }
        }
      }

      // Type assertion to handle nullable fields from Supabase
      const typedAnswers = (data || []).map(answer => ({
        ...answer,
        team_name: answer.team_name || '',
        answer: answer.answer || '',
        question_number: answer.question_number || 0,
        points: answer.points || 0,
        correct: answer.correct || false
      })) as QuizAnswer[];

      setAnswers(typedAnswers);
    };

    fetchAnswers();

    // Subscribe to real-time changes
    const channel = supabase
      .channel('quiz_answers_channel')
      .on(
        'postgres_changes',
        {
          event: '*',
          schema: 'public',
          table: 'quiz_answers',
          filter: `quiz_id=eq.${quizId}`
        },
        (payload) => {
          console.log('Real-time update received:', payload);
          if (payload.eventType === 'INSERT') {
            const newAnswer = {
              ...payload.new,
              team_name: payload.new.team_name || '',
              answer: payload.new.answer || '',
              question_number: payload.new.question_number || 0,
              points: payload.new.points || 0,
              correct: payload.new.correct || false
            } as QuizAnswer;
            setAnswers((prev) => [...prev, newAnswer]);
          } else if (payload.eventType === 'UPDATE') {
            setAnswers((prev) =>
              prev.map((answer) =>
                answer.id === payload.new.id
                  ? {
                      ...payload.new,
                      team_name: payload.new.team_name || '',
                      answer: payload.new.answer || '',
                      question_number: payload.new.question_number || 0,
                      points: payload.new.points || 0,
                      correct: payload.new.correct || false
                    } as QuizAnswer
                  : answer
              )
            );
          } else if (payload.eventType === 'DELETE') {
            setAnswers((prev) =>
              prev.filter((answer) => answer.id !== payload.old.id)
            );
          }
        }
      )
      .subscribe();

    return () => {
      supabase.removeChannel(channel);
    };
  }, [quizId, supabase]);

  // Compute derived state
  const groupedAnswers = groupByRound(answers);
  const allTeams = Array.from(new Set(answers.map((a) => a.team_name)));

  const teamTotals: Record<
    string,
    { round1: number; round2: number; round3: number; round4: number }
  > = {};

  allTeams.forEach((team) => {
    teamTotals[team] = { round1: 0, round2: 0, round3: 0, round4: 0 };
  });

  answers.forEach((answer) => {
    if (!answer.correct) return;
    const round = getRound(answer.question_number);
    teamTotals[answer.team_name][`round${round}` as keyof typeof teamTotals[string]] +=
      answer.points;
  });

  return (
    <QuizContext.Provider
      value={{
        answers,
        groupedAnswers,
        allTeams,
        teamTotals
      }}
    >
      {children}
    </QuizContext.Provider>
  );
}

export function useQuiz() {
  const context = useContext(QuizContext);
  if (!context) {
    throw new Error('useQuiz must be used within a QuizProvider');
  }
  return context;
}