diff --git a/package-lock.json b/package-lock.json index 7dac78c..6deb902 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "firebase": "^11.0.1", "react": "^18.3.1", "react-calendar": "^5.1.0", + "react-confetti": "^6.1.0", "react-dom": "^18.3.0", "react-router-dom": "^6.27.0" }, @@ -6609,6 +6610,21 @@ } } }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "license": "MIT", + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -7467,6 +7483,12 @@ "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", "license": "0BSD" }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "license": "BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index d579c37..0fd50c5 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "firebase": "^11.0.1", "react": "^18.3.1", "react-calendar": "^5.1.0", + "react-confetti": "^6.1.0", "react-dom": "^18.3.0", "react-router-dom": "^6.27.0" }, diff --git a/public/treee.mov b/public/treee.mov new file mode 100644 index 0000000..9dd1a7b Binary files /dev/null and b/public/treee.mov differ diff --git a/src/components/Home/MicroGoal.jsx b/src/components/Home/MicroGoal.jsx index dfb3e4b..ee8adb3 100644 --- a/src/components/Home/MicroGoal.jsx +++ b/src/components/Home/MicroGoal.jsx @@ -2,6 +2,8 @@ import AddItem from '@/components/Home/AddItem' import DeleteItem from '@/components/Home/DeleteItem' import ProgressIndicator from '@/components/Home/ProgressIndicator' import Task from '@/components/Home/Task' +import TaskCompletionModal from '@/components/Home/TaskCompletionModal' +import { useUser } from '@/contexts/UserContext' import useGoalsUpdater from '@/hooks/useGoalsUpdater' import { calculateProgress } from '@/utils/calculateProgress' import { ExpandLess, ExpandMore } from '@mui/icons-material' @@ -14,10 +16,21 @@ import { Paper, Typography, } from '@mui/material' +import { useState } from 'react' const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => { const { addTask, toggleExpansion, toggleTaskCompletion } = useGoalsUpdater() const progress = calculateProgress([microGoal]) + const [modalOpen, setModalOpen] = useState(false) + const { user } = useUser() + + // Access today's task completion count + const todayCount = user?.streak?.todayCount || 0 + + const handleTaskCompletion = (macroGoalIndex, microGoalIndex, taskIndex) => { + toggleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex) + setModalOpen(true) // Open the modal after each task completion + } return ( { microGoalIndex={microGoalIndex} taskIndex={taskIndex} onToggle={() => - toggleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex) + handleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex) } /> ))} @@ -63,6 +76,13 @@ const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => { } /> + + {/* TaskCompletionModal */} + setModalOpen(false)} + count={todayCount} // Pass today's task completion count to the modal + /> ) } diff --git a/src/components/Home/TaskCompletionModal.jsx b/src/components/Home/TaskCompletionModal.jsx new file mode 100644 index 0000000..2e4d102 --- /dev/null +++ b/src/components/Home/TaskCompletionModal.jsx @@ -0,0 +1,116 @@ +import { useUser } from '@/contexts/UserContext' // Import useUser hook +import { Box, Button, Modal, Typography, useTheme } from '@mui/material' +import { useEffect, useRef, useState } from 'react' +import Confetti from 'react-confetti' + +const TaskCompletionModal = ({ open, handleClose }) => { + const { user } = useUser() + const theme = useTheme() // Access the theme for colors + const todayCount = user?.streak?.todayCount || 0 // Get the daily task completion count + + const [confetti, setConfetti] = useState(false) + const videoRef = useRef(null) // Reference to the video element + + // Define the start and end times for each stage in seconds + const timeRanges = [ + { start: 0, end: 2.5 }, + { start: 2.5, end: 4 }, + { start: 4, end: 6 }, + { start: 6, end: 8 }, + { start: 6.5, end: 11 }, + ] + + // Show confetti when exactly 5 tasks are completed + useEffect(() => { + if (todayCount === 5) { + setConfetti(true) + setTimeout(() => setConfetti(false), 5000) + } + }, [todayCount]) + + // Control video playback based on `todayCount` + useEffect(() => { + const video = videoRef.current + if (open && video && todayCount <= 5) { + const { start, end } = timeRanges[todayCount - 1] || { start: 0, end: 0 } // Get time range based on task count + video.currentTime = start // Set video start time + video.play() + + // Stop video at the specified end time + const handleTimeUpdate = () => { + if (video.currentTime >= end) { + video.pause() + } + } + + video.addEventListener('timeupdate', handleTimeUpdate) + + // Clean up event listener when the component unmounts or task count changes + return () => { + video.removeEventListener('timeupdate', handleTimeUpdate) + } + } + }, [open, todayCount]) + + // Only render the modal content if todayCount is 5 or fewer + if (todayCount === 6 && todayCount > 5) { + return null // Prevent modal from rendering if more than 5 tasks are completed + } + + return ( + + + {/* Full-screen confetti with purple and white colors */} + {confetti && ( + + )} + + + + + {todayCount === 4 + ? 'Just one more task to go, you got this!!' + : todayCount < 5 + ? `Complete ${5 - todayCount} more tasks to grow your tree today!` // General message for counts less than 5 + : 'Congratulations! You Completed 5 tasks today!'} + + + + + + ) +} + +export default TaskCompletionModal