Spaces:
Sleeping
Sleeping
| "use client"; | |
| import React, { createContext, useContext, useState, ReactNode, useEffect } from "react"; | |
| import GameAlert from "../ui/GameAlert"; | |
| import { Player } from "@/types"; | |
| import { useSound } from "@/hooks/useSound"; | |
| type AlertType = 'error' | 'info' | 'success' | 'voting'; | |
| interface AlertData { | |
| id: number; | |
| message: React.ReactNode; | |
| type: AlertType; | |
| title: string; | |
| image?: string; | |
| votes?: Record<string, number>; | |
| players?: Player[]; | |
| sound?: string; | |
| } | |
| interface AlertContextType { | |
| showAlert: (message: React.ReactNode, type?: AlertType, title?: string, image?: string, votes?: Record<string, number>, players?: Player[], sound?: string) => void; | |
| } | |
| const AlertContext = createContext<AlertContextType | undefined>(undefined); | |
| export function AlertProvider({ children }: { children: ReactNode }) { | |
| const [queue, setQueue] = useState<AlertData[]>([]); | |
| const [currentAlert, setCurrentAlert] = useState<AlertData | null>(null); | |
| const { playSound } = useSound(); | |
| const showAlert = (msg: React.ReactNode, alertType: AlertType = 'info', alertTitle?: string, alertImage?: string, voteData?: Record<string, number>, playerData?: Player[], sound?: string) => { | |
| // Spam Prevention: Check if the last queued alert or current alert is identical | |
| const lastInQueue = queue[queue.length - 1]; | |
| const isDuplicateOfCurrent = currentAlert && currentAlert.message === msg && currentAlert.title === alertTitle; | |
| const isDuplicateOfQueue = lastInQueue && lastInQueue.message === msg && lastInQueue.title === alertTitle; | |
| if (isDuplicateOfCurrent || isDuplicateOfQueue) { | |
| return; // Ignore duplicate | |
| } | |
| const newAlert: AlertData = { | |
| id: Date.now() + Math.random(), | |
| message: msg, | |
| type: alertType, | |
| title: alertTitle || (alertType === 'error' ? 'ERROR' : alertType === 'voting' ? 'PENENTUAN' : 'NOTICE'), | |
| image: alertImage, | |
| votes: voteData, | |
| players: playerData, | |
| sound: sound | |
| }; | |
| setQueue((prev) => [...prev, newAlert]); | |
| }; | |
| useEffect(() => { | |
| if (!currentAlert && queue.length > 0) { | |
| const nextAlert = queue[0]; | |
| setCurrentAlert(nextAlert); | |
| setQueue((prev) => prev.slice(1)); | |
| if (nextAlert.sound) { | |
| playSound(nextAlert.sound); | |
| } | |
| } | |
| }, [queue, currentAlert, playSound]); | |
| const closeAlert = () => { | |
| setCurrentAlert(null); | |
| }; | |
| return ( | |
| <AlertContext.Provider value={{ showAlert }}> | |
| {children} | |
| <GameAlert | |
| isOpen={!!currentAlert} | |
| message={currentAlert?.message || ""} | |
| title={currentAlert?.title} | |
| type={currentAlert?.type || 'info'} | |
| image={currentAlert?.image} | |
| votes={currentAlert?.votes} | |
| players={currentAlert?.players} | |
| onClose={closeAlert} | |
| /> | |
| </AlertContext.Provider> | |
| ); | |
| } | |
| export function useAlert() { | |
| const context = useContext(AlertContext); | |
| if (context === undefined) { | |
| throw new Error("useAlert must be used within an AlertProvider"); | |
| } | |
| return context; | |
| } |