import {
Add,
CancelRounded,
EditCalendar,
ExpandCircleDown,
Grain,
PriorityHigh,
Search,
Sort,
Style,
Unarchive,
} from '@mui/icons-material'
import {
Accordion,
AccordionDetails,
AccordionGroup,
Box,
Button,
Chip,
Container,
Divider,
IconButton,
Input,
List,
Menu,
MenuItem,
Snackbar,
Typography,
} from '@mui/joy'
import Fuse from 'fuse.js'
import { useContext, useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { UserContext } from '../../contexts/UserContext'
import { useChores } from '../../queries/ChoreQueries'
import {
GetAllUsers,
GetArchivedChores,
GetChores,
GetUserProfile,
} from '../../utils/Fetcher'
import Priorities from '../../utils/Priorities'
import LoadingComponent from '../components/Loading'
import { useLabels } from '../Labels/LabelQueries'
import ChoreCard from './ChoreCard'
import IconButtonWithMenu from './IconButtonWithMenu'
import { ChoreFilters, ChoresGrouper, ChoreSorter } from '../../utils/Chores'
import TaskInput from '../components/AddTaskModal'
import {
canScheduleNotification,
scheduleChoreNotification,
} from './LocalNotificationScheduler'
import NotificationAccessSnackbar from './NotificationAccessSnackbar'
import Sidepanel from './Sidepanel'
import SortAndGrouping from './SortAndGrouping'
const MyChores = () => {
const { userProfile, setUserProfile } = useContext(UserContext)
const [isSnackbarOpen, setIsSnackbarOpen] = useState(false)
const [snackBarMessage, setSnackBarMessage] = useState(null)
const [chores, setChores] = useState([])
const [archivedChores, setArchivedChores] = useState(null)
const [filteredChores, setFilteredChores] = useState([])
const [searchFilter, setSearchFilter] = useState('All')
const [choreSections, setChoreSections] = useState([])
const [activeTextField, setActiveTextField] = useState('task')
const [taskInputFocus, setTaskInputFocus] = useState(0)
const searchInputRef = useRef()
const [searchInputFocus, setSearchInputFocus] = useState(0)
const [selectedChoreSection, setSelectedChoreSection] = useState(
localStorage.getItem('selectedChoreSection') || 'due_date',
)
const [openChoreSections, setOpenChoreSections] = useState(
JSON.parse(localStorage.getItem('openChoreSections')) || {},
)
const [selectedChoreFilter, setSelectedChoreFilter] = useState(
JSON.parse(localStorage.getItem('selectedChoreFilter')) || 'anyone',
)
const [searchTerm, setSearchTerm] = useState('')
const [performers, setPerformers] = useState([])
const [anchorEl, setAnchorEl] = useState(null)
const menuRef = useRef(null)
const Navigate = useNavigate()
const { data: userLabels, isLoading: userLabelsLoading } = useLabels()
const { data: choresData, isLoading: choresLoading } = useChores()
useEffect(() => {
Promise.all([GetChores(), GetAllUsers(), GetUserProfile()]).then(
responses => {
const [choresResponse, usersResponse, userProfileResponse] = responses
if (!choresResponse.ok) {
throw new Error(choresResponse.statusText)
}
if (!usersResponse.ok) {
throw new Error(usersResponse.statusText)
}
if (!userProfileResponse.ok) {
throw new Error(userProfileResponse.statusText)
}
Promise.all([
choresResponse.json(),
usersResponse.json(),
userProfileResponse.json(),
]).then(data => {
const [choresData, usersData, userProfileData] = data
setUserProfile(userProfileData.res)
choresData.res.sort(ChoreSorter)
setChores(choresData.res)
setFilteredChores(choresData.res)
setPerformers(usersData.res)
if (canScheduleNotification()) {
scheduleChoreNotification(
choresData.res,
userProfileData.res,
usersData.res,
)
}
})
},
)
// GetAllUsers()
// .then(response => response.json())
// .then(data => {
// setPerformers(data.res)
// })
// GetUserProfile().then(response => response.json()).then(data => {
// setUserProfile(data.res)
// })
// const currentUser = JSON.parse(localStorage.getItem('user'))
// if (currentUser !== null) {
// setActiveUserId(currentUser.id)
// }
}, [])
useEffect(() => {
if (choresData) {
const sortedChores = choresData.res.sort(ChoreSorter)
setChores(sortedChores)
setFilteredChores(sortedChores)
const sections = ChoresGrouper(selectedChoreSection, sortedChores)
setChoreSections(sections)
if (localStorage.getItem('openChoreSections') === null) {
setSelectedChoreSectionWithCache(selectedChoreSection)
setOpenChoreSections(
Object.keys(sections).reduce((acc, key) => {
acc[key] = true
return acc
}, {}),
)
}
}
}, [choresData, choresLoading])
useEffect(() => {
document.addEventListener('mousedown', handleMenuOutsideClick)
return () => {
document.removeEventListener('mousedown', handleMenuOutsideClick)
}
}, [anchorEl])
useEffect(() => {
if (searchInputFocus > 0 && searchInputRef.current) {
searchInputRef.current.focus()
searchInputRef.current.selectionStart =
searchInputRef.current.value?.length
searchInputRef.current.selectionEnd = searchInputRef.current.value?.length
}
}, [searchInputFocus])
const setSelectedChoreSectionWithCache = value => {
setSelectedChoreSection(value)
localStorage.setItem('selectedChoreSection', value)
}
const setOpenChoreSectionsWithCache = value => {
setOpenChoreSections(value)
localStorage.setItem('openChoreSections', JSON.stringify(value))
}
const setSelectedChoreFilterWithCache = value => {
setSelectedChoreFilter(value)
localStorage.setItem('selectedChoreFilter', JSON.stringify(value))
}
const updateChores = newChore => {
const newChores = chores
newChores.push(newChore)
setChores(newChores)
setFilteredChores(newChores)
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
setSearchFilter('All')
}
const handleMenuOutsideClick = event => {
if (
anchorEl &&
!anchorEl.contains(event.target) &&
!menuRef.current.contains(event.target)
) {
handleFilterMenuClose()
}
}
const handleFilterMenuOpen = event => {
event.preventDefault()
setAnchorEl(event.currentTarget)
}
const handleFilterMenuClose = () => {
setAnchorEl(null)
}
const handleLabelFiltering = chipClicked => {
if (chipClicked.label) {
const label = chipClicked.label
const labelFiltered = [...chores].filter(chore =>
chore.labelsV2.some(
l => l.id === label.id && l.created_by === label.created_by,
),
)
setFilteredChores(labelFiltered)
setSearchFilter('Label: ' + label.name)
} else if (chipClicked.priority) {
const priority = chipClicked.priority
const priorityFiltered = chores.filter(
chore => chore.priority === priority,
)
setFilteredChores(priorityFiltered)
setSearchFilter('Priority: ' + priority)
}
}
const handleChoreUpdated = (updatedChore, event) => {
var newChores = chores.map(chore => {
if (chore.id === updatedChore.id) {
return updatedChore
}
return chore
})
var newFilteredChores = filteredChores.map(chore => {
if (chore.id === updatedChore.id) {
return updatedChore
}
return chore
})
if (
event === 'archive' ||
(event === 'completed' && updatedChore.frequencyType === 'once')
) {
newChores = newChores.filter(chore => chore.id !== updatedChore.id)
newFilteredChores = newFilteredChores.filter(
chore => chore.id !== updatedChore.id,
)
if (archivedChores !== null) {
setArchivedChores([...archivedChores, updatedChore])
}
}
if (event === 'unarchive') {
newChores.push(updatedChore)
newFilteredChores.push(updatedChore)
setArchivedChores(
archivedChores.filter(chore => chore.id !== updatedChore.id),
)
}
setChores(newChores)
setFilteredChores(newFilteredChores)
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
switch (event) {
case 'completed':
setSnackBarMessage('Completed')
break
case 'skipped':
setSnackBarMessage('Skipped')
break
case 'rescheduled':
setSnackBarMessage('Rescheduled')
break
case 'unarchive':
setSnackBarMessage('Unarchive')
break
case 'archive':
setSnackBarMessage('Archived')
break
default:
setSnackBarMessage('Updated')
}
setIsSnackbarOpen(true)
}
const handleChoreDeleted = deletedChore => {
const newChores = chores.filter(chore => chore.id !== deletedChore.id)
const newFilteredChores = filteredChores.filter(
chore => chore.id !== deletedChore.id,
)
setChores(newChores)
setFilteredChores(newFilteredChores)
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
}
const searchOptions = {
// keys to search in
keys: ['name', 'raw_label'],
includeScore: true, // Optional: if you want to see how well each result matched the search term
isCaseSensitive: false,
findAllMatches: true,
}
const fuse = new Fuse(
chores.map(c => ({
...c,
raw_label: c.labelsV2.map(c => c.name).join(' '),
})),
searchOptions,
)
const handleSearchChange = e => {
if (searchFilter !== 'All') {
setSearchFilter('All')
}
const search = e.target.value
if (search === '') {
setFilteredChores(chores)
setSearchTerm('')
return
}
const term = search.toLowerCase()
setSearchTerm(term)
setFilteredChores(fuse.search(term).map(result => result.item))
}
if (
userProfile === null ||
userLabelsLoading ||
performers.length === 0 ||
choresLoading
) {
return