diff --git a/app/actions.ts b/app/actions.ts new file mode 100644 index 0000000..d2e31ab --- /dev/null +++ b/app/actions.ts @@ -0,0 +1,31 @@ +'use server'; + +const GOTIFY_URL = process.env.GOTIFY_URL; +const GOTIFY_APP_TOKEN = process.env.GOTIFY_APP_TOKEN; + +export async function sendGotifyNotification(attempts: number, status: 'won' | 'lost', puzzleId: number) { + try { + const title = `Hördle #${puzzleId} ${status === 'won' ? 'Solved!' : 'Failed'}`; + const message = status === 'won' + ? `Puzzle #${puzzleId} was solved in ${attempts} attempt(s).` + : `Puzzle #${puzzleId} was failed after ${attempts} attempt(s).`; + + const response = await fetch(`${GOTIFY_URL}/message?token=${GOTIFY_APP_TOKEN}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + title: title, + message: message, + priority: 5, + }), + }); + + if (!response.ok) { + console.error('Failed to send Gotify notification:', await response.text()); + } + } catch (error) { + console.error('Error sending Gotify notification:', error); + } +} diff --git a/components/AudioPlayer.tsx b/components/AudioPlayer.tsx index 2bff155..2a0c10e 100644 --- a/components/AudioPlayer.tsx +++ b/components/AudioPlayer.tsx @@ -6,9 +6,10 @@ interface AudioPlayerProps { src: string; unlockedSeconds: number; // 2, 4, 7, 11, 16, 30 (or full length) onPlay?: () => void; + autoPlay?: boolean; } -export default function AudioPlayer({ src, unlockedSeconds, onPlay }: AudioPlayerProps) { +export default function AudioPlayer({ src, unlockedSeconds, onPlay, autoPlay = false }: AudioPlayerProps) { const audioRef = useRef(null); const [isPlaying, setIsPlaying] = useState(false); const [progress, setProgress] = useState(0); @@ -19,8 +20,23 @@ export default function AudioPlayer({ src, unlockedSeconds, onPlay }: AudioPlaye audioRef.current.currentTime = 0; setIsPlaying(false); setProgress(0); + + if (autoPlay) { + const playPromise = audioRef.current.play(); + if (playPromise !== undefined) { + playPromise + .then(() => { + setIsPlaying(true); + onPlay?.(); + }) + .catch(error => { + console.log("Autoplay prevented:", error); + setIsPlaying(false); + }); + } + } } - }, [src, unlockedSeconds]); + }, [src, unlockedSeconds, autoPlay]); const togglePlay = () => { if (!audioRef.current) return; diff --git a/components/Game.tsx b/components/Game.tsx index ae0059e..27b190f 100644 --- a/components/Game.tsx +++ b/components/Game.tsx @@ -5,6 +5,7 @@ import AudioPlayer from './AudioPlayer'; import GuessInput from './GuessInput'; import Statistics from './Statistics'; import { useGameState } from '../lib/gameState'; +import { sendGotifyNotification } from '../app/actions'; interface GameProps { dailyPuzzle: { @@ -24,6 +25,7 @@ export default function Game({ dailyPuzzle }: GameProps) { const [hasWon, setHasWon] = useState(false); const [hasLost, setHasLost] = useState(false); const [shareText, setShareText] = useState('Share Result'); + const [lastAction, setLastAction] = useState<'GUESS' | 'SKIP' | null>(null); useEffect(() => { if (gameState && dailyPuzzle) { @@ -32,6 +34,10 @@ export default function Game({ dailyPuzzle }: GameProps) { } }, [gameState, dailyPuzzle]); + useEffect(() => { + setLastAction(null); + }, [dailyPuzzle?.id]); + if (!dailyPuzzle) return (

No Puzzle Available

@@ -43,17 +49,32 @@ export default function Game({ dailyPuzzle }: GameProps) { if (!gameState) return
Loading state...
; const handleGuess = (song: any) => { + setLastAction('GUESS'); if (song.id === dailyPuzzle.songId) { addGuess(song.title, true); setHasWon(true); + sendGotifyNotification(gameState.guesses.length + 1, 'won', dailyPuzzle.id); } else { addGuess(song.title, false); if (gameState.guesses.length + 1 >= 7) { setHasLost(true); + sendGotifyNotification(7, 'lost', dailyPuzzle.id); } } }; + const handleSkip = () => { + setLastAction('SKIP'); + addGuess("SKIPPED", false); + }; + + const handleGiveUp = () => { + setLastAction('SKIP'); + addGuess("SKIPPED", false); + setHasLost(true); + sendGotifyNotification(7, 'lost', dailyPuzzle.id); + }; + const unlockedSeconds = UNLOCK_STEPS[Math.min(gameState.guesses.length, 6)]; const handleShare = () => { @@ -116,6 +137,7 @@ export default function Game({ dailyPuzzle }: GameProps) {
@@ -138,17 +160,14 @@ export default function Game({ dailyPuzzle }: GameProps) { {gameState.guesses.length < 6 ? ( ) : (