diff --git a/src/views/Chores/MyChores.jsx b/src/views/Chores/MyChores.jsx
index cbb689b..3554091 100644
--- a/src/views/Chores/MyChores.jsx
+++ b/src/views/Chores/MyChores.jsx
@@ -2,15 +2,10 @@ import {
Add,
Bolt,
CalendarMonth,
- CheckBox,
- CheckBoxOutlineBlank,
EditCalendar,
ExpandCircleDown,
PriorityHigh,
- Sort,
Style,
- ViewAgenda,
- ViewModule,
} from '@mui/icons-material'
import {
Accordion,
@@ -37,7 +32,6 @@ import IconButtonWithMenu from './IconButtonWithMenu'
import { useMediaQuery } from '@mui/material'
import { useQueryClient } from '@tanstack/react-query'
-import FilterBar from '../../components/common/FilterBar'
import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint'
import { useFilter } from '../../hooks/useFilter'
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
@@ -52,15 +46,13 @@ import { getSafeBottom } from '../../utils/SafeAreaUtils.js'
import TaskInput from '../components/AddTaskModal'
import CalendarDual from '../components/CalendarDual'
import CalendarMonthly from '../components/CalendarMonthly.jsx'
-import ProjectSelector from '../components/ProjectSelector'
import AdvancedFilterBuilder from '../Modals/Inputs/AdvancedFilterBuilder'
import { useProjects } from '../Projects/ProjectQueries.js'
import ChoreListView from './ChoreListView.jsx'
+import ChoreToolbar from './components/ChoreToolbarPrototype'
import ChoreModals from './components/ChoreModals'
-import FilterSection from './components/FilterSection'
import MultiSelectToolbar from './components/MultiSelectToolbar'
import MyChoreHeader from './components/MyChoreHeader'
-import SearchBar from './components/SearchBar'
import { useChoreActions } from './hooks/useChoreActions'
import { useChoreFilters } from './hooks/useChoreFilters'
import { useChoreModals } from './hooks/useChoreModals'
@@ -75,7 +67,6 @@ import {
import NotificationAccessSnackbar from './NotificationAccessSnackbar'
import Sidepanel from './Sidepanel'
import { INSIGHT_FILTER_DEFS } from './SmartInsightsCard'
-import SortAndGrouping from './SortAndGrouping'
const MyChores = () => {
const { data: userProfile, isLoading: isUserProfileLoading } =
@@ -790,14 +781,13 @@ const MyChores = () => {
localStorage.setItem('openChoreSections', JSON.stringify(value))
}
- const toggleViewMode = () => {
- const modes = ['default', 'compact', 'calendar']
- const currentIndex = modes.indexOf(viewMode)
- const nextIndex = (currentIndex + 1) % modes.length
- const newMode = modes[nextIndex]
+ const toggleViewMode = value => {
+ const newMode = value ?? (() => {
+ const modes = ['default', 'compact', 'calendar']
+ return modes[(modes.indexOf(viewMode) + 1) % modes.length]
+ })()
setViewMode(newMode)
localStorage.setItem('choreCardViewMode', newMode)
-
if (newMode !== 'calendar') {
setSelectedCalendarDate(null)
}
@@ -957,126 +947,7 @@ const MyChores = () => {
tempFilter={tempFilter}
tempFilterMeta={tempFilterMeta}
/>
-
-
-
- }
- selectedItem={selectedChoreSection}
- selectedFilter={selectedChoreFilter}
- setFilter={filter => {
- setSelectedChoreFilterWithCache(filter)
- // Clear active custom filter when quick filter is applied
- if (activeFilterId) {
- clearActiveFilter()
- updateFilterUrl(null, null)
- }
- }}
- onItemSelect={selected => {
- setSelectedChoreSectionWithCache(selected.value)
- setFilteredChores(chores)
- clearQuickFilters()
- }}
- onCreateNewFilter={() => {
- setShowAdvancedFilterBuilder(true)
- setEditingFilter(null)
- }}
- mouseClickHandler={handleMenuOutsideClick}
- />
-
- {/* Project Selector - Hidden when active filter has project conditions */}
- {projectsWithDefault.length > 1 &&
- !hasProjectConditions &&
- !hasFilterApplied && (
- {
- setSelectedProjectWithCache(project)
- clearActiveFilter()
- }}
- showKeyboardShortcuts={showKeyboardShortcuts}
- />
- )}
-
- {/* View Mode Toggle Button */}
-
- {viewMode === 'default' ? (
-
- ) : viewMode === 'compact' ? (
-
- ) : (
-
- )}
-
-
- {/* Multi-select Toggle Button */}
-
-
- {isMultiSelectMode ? : }
-
-
-
-
-
- {/* Quick Filters */}
- {
@@ -1084,21 +955,40 @@ const MyChores = () => {
setQuickFilter(id, value)
setSelectedCalendarDate(null)
}}
- onClearAll={() => {
+ onClearAllFilters={() => {
clearQuickFilters()
+ clearActiveFilter()
+ setSelectedChoreFilterWithCache('anyone')
+ setSelectedProjectWithCache(projectsWithDefault.find(p => p.id === 'default') || null)
updateFilterUrl(null, null)
}}
- resultCount={hasQuickFilters ? getFilteredChores.length : undefined}
- totalCount={hasQuickFilters ? projectFilteredChores.length : undefined}
- />
-
- {/* Custom Filters Section */}
- {
+ setSelectedProjectWithCache(project)
+ clearActiveFilter()
+ }}
+ selectedAssigneeFilter={selectedChoreFilter}
+ onAssigneeFilterChange={filter => {
+ setSelectedChoreFilterWithCache(filter)
+ if (activeFilterId) {
+ clearActiveFilter()
+ updateFilterUrl(null, null)
+ }
+ }}
savedFilters={savedFilters}
activeFilterId={activeFilterId}
- activeFilter={activeFilter}
- hasProjectConditions={hasProjectConditions}
- onFilterClick={filterId => {
+ onSavedFilterClick={filterId => {
if (activeFilterId === filterId) {
clearActiveFilter()
updateFilterUrl(null, null)
@@ -1106,31 +996,42 @@ const MyChores = () => {
clearQuickFilters()
setSearchTerm('')
setFilteredChores([])
-
- // Reset quick filter to 'anyone' when custom filter is applied
if (selectedChoreFilter !== 'anyone') {
setSelectedChoreFilterWithCache('anyone')
}
-
- // Clear project selection if the filter has project conditions
const filter = savedFilters.find(f => f.id === filterId)
if (filter?.conditions?.some(c => c.type === 'project')) {
setSelectedProjectWithCache(null)
}
-
applyCustomFilter(filterId)
updateFilterUrl('filterId', filterId)
}
}}
- onFilterDelete={deleteFilter}
- onFilterPin={pinFilter}
- onFilterEdit={filter => {
+ onSavedFilterEdit={filter => {
setEditingFilter(filter)
setShowAdvancedFilterBuilder(true)
}}
- onClearActiveFilter={clearActiveFilter}
- onCreateAdvancedFilter={() => setShowAdvancedFilterBuilder(true)}
- updateFilterUrl={updateFilterUrl}
+ onSavedFilterDelete={deleteFilter}
+ onSavedFilterPin={pinFilter}
+ onCreateAdvancedFilter={() => {
+ setShowAdvancedFilterBuilder(true)
+ setEditingFilter(null)
+ }}
+ selectedGroupBy={selectedChoreSection}
+ onGroupBySelect={value => {
+ setSelectedChoreSectionWithCache(value)
+ setFilteredChores(chores)
+ clearQuickFilters()
+ }}
+ viewMode={viewMode}
+ onToggleViewMode={toggleViewMode}
+ isMultiSelectMode={isMultiSelectMode}
+ onToggleMultiSelect={toggleMultiSelectMode}
+ searchTerm={searchTerm}
+ onSearchChange={handleSearchChange}
+ onSearchClose={handleSearchClose}
+ searchInputRef={searchInputRef}
+ showKeyboardShortcuts={showKeyboardShortcuts}
/>
toolbar block
+ * and the two rows below it (FilterBar + FilterSection) with:
+ *
+ */
+
+import {
+ Add,
+ CalendarMonth,
+ Check,
+ CheckBox,
+ CheckBoxOutlineBlank,
+ Close,
+ FilterList,
+ FolderOpen,
+ PriorityHigh,
+ Settings,
+ Sort,
+ Style,
+ Tune,
+ ViewAgenda,
+ ViewComfy,
+ ViewModule,
+} from '@mui/icons-material'
+import {
+ Badge,
+ Box,
+ Button,
+ Chip,
+ Divider,
+ IconButton,
+ Typography,
+} from '@mui/joy'
+import { useState } from 'react'
+import BottomSheetModal from '../../../components/common/BottomSheetModal'
+import KeyboardShortcutHint from '../../../components/common/KeyboardShortcutHint'
+import SearchBar from './SearchBar'
+
+// ─── helpers ─────────────────────────────────────────────────────────────────
+
+const chipLabel = (def, value) => {
+ if (!value || (Array.isArray(value) && value.length === 0)) return null
+ if (def.type === 'single-select')
+ return def.options?.find(o => o.value === value)?.label ?? null
+ if (def.type === 'multi-select' && Array.isArray(value)) {
+ if (value.length === 1)
+ return def.options?.find(o => o.value === value[0])?.label ?? def.label
+ return `${def.label} (${value.length})`
+ }
+ return null
+}
+
+// ─── sub-components ──────────────────────────────────────────────────────────
+
+const SectionHeader = ({ icon, label, badge }) => (
+
+ {icon && (
+
+ {icon}
+
+ )}
+
+ {label}
+
+ {badge != null && (
+
+ {badge}
+
+ )}
+
+)
+
+const OptionChips = ({ options, selected, multi, onToggle }) => (
+
+ {options.map(opt => {
+ const isSelected = multi
+ ? (selected || []).includes(opt.value)
+ : selected === opt.value
+ return (
+
+ : opt.icon
+ : undefined
+ }
+ onClick={() => onToggle(opt.value)}
+ sx={{
+ py: 0.64,
+ cursor: 'pointer',
+ transition: 'all 0.15s ease',
+ userSelect: 'none',
+ '&:hover': { opacity: 0.85 },
+ }}
+ >
+ {opt.label}
+
+ )
+ })}
+
+)
+
+// ─── main component ───────────────────────────────────────────────────────────
+
+/**
+ * Props:
+ * filterDefs – same shape as FilterBar: [{ id, label, type, icon, options, filterFn }]
+ * PLUS two new built-in sections handled here: 'project' and 'assignee'
+ * activeFilters – { [id]: value }
+ * onSetFilter – (id, value | null) => void
+ * onClearAllFilters – () => void
+ * resultCount / totalCount
+ *
+ * projects – [{ id, name }] — drives the Project section
+ * selectedProject – current project object
+ * onProjectSelect – (project) => void
+ *
+ * selectedAssigneeFilter – 'anyone' | 'assigned_to_me' | 'available_for_me' | 'assigned_to_others'
+ * onAssigneeFilterChange – (key) => void
+ *
+ * savedFilters – [{ id, name, color, count, isPinned }]
+ * activeFilterId – number | null
+ * onSavedFilterClick – (id) => void
+ * onSavedFilterEdit – (filter) => void
+ * onSavedFilterDelete– (id) => void
+ * onSavedFilterPin – (id) => void
+ * onCreateAdvancedFilter – () => void
+ *
+ * selectedGroupBy – 'default' | 'due_date' | 'priority' | 'labels'
+ * onGroupBySelect – (value) => void
+ *
+ * viewMode – 'default' | 'compact' | 'calendar'
+ * onToggleViewMode – () => void
+ *
+ * isMultiSelectMode – bool
+ * onToggleMultiSelect – () => void
+ *
+ * searchTerm / onSearchChange / onSearchClose / searchInputRef
+ * showKeyboardShortcuts
+ */
+const ChoreToolbar = ({
+ // quick filters
+ filterDefs = [],
+ activeFilters = {},
+ onSetFilter,
+ onClearAllFilters,
+ resultCount,
+ totalCount,
+ // project
+ projects = [],
+ selectedProject,
+ onProjectSelect,
+ // assignee
+ selectedAssigneeFilter = 'anyone',
+ onAssigneeFilterChange,
+ // saved / custom
+ savedFilters = [],
+ activeFilterId,
+ onSavedFilterClick,
+ onSavedFilterEdit,
+ onSavedFilterDelete,
+ onSavedFilterPin,
+ onCreateAdvancedFilter,
+ // grouping
+ selectedGroupBy = 'default',
+ onGroupBySelect,
+ // view + multiselect
+ viewMode = 'default',
+ onToggleViewMode,
+ isMultiSelectMode,
+ onToggleMultiSelect,
+ // search
+ searchTerm,
+ onSearchChange,
+ onSearchClose,
+ searchInputRef,
+ showKeyboardShortcuts,
+}) => {
+ const [filterSheetOpen, setFilterSheetOpen] = useState(false)
+ const [displaySheetOpen, setDisplaySheetOpen] = useState(false)
+
+ // ── count active filters for badge ──────────────────────────────────────────
+
+ const quickFilterCount = filterDefs.filter(def => {
+ const v = activeFilters[def.id]
+ return v != null && !(Array.isArray(v) && v.length === 0)
+ }).length
+
+ const projectActive =
+ selectedProject && selectedProject.id !== 'default' ? 1 : 0
+ const assigneeActive = selectedAssigneeFilter !== 'anyone' ? 1 : 0
+ const savedFilterActive = activeFilterId != null ? 1 : 0
+
+ const totalActiveCount = quickFilterCount + savedFilterActive
+ const hasAnyActive = totalActiveCount > 0
+
+ // ── inline chip strip (max 2 visible + overflow) ─────────────────────────────
+
+ const inlineChips = []
+
+ if (savedFilterActive) {
+ const sf = savedFilters.find(f => f.id === activeFilterId)
+ if (sf)
+ inlineChips.push({
+ key: '__saved',
+ label: sf.name,
+ onClear: () => onSavedFilterClick?.(activeFilterId),
+ })
+ }
+
+ filterDefs.forEach(def => {
+ const label = chipLabel(def, activeFilters[def.id])
+ if (label) inlineChips.push({ key: def.id, label, onClear: () => onSetFilter(def.id, null) })
+ })
+
+ const MAX_CHIPS = 2
+ const visibleChips = inlineChips.slice(0, MAX_CHIPS)
+ const overflow = inlineChips.length - MAX_CHIPS
+
+ // ── groupby options ──────────────────────────────────────────────────────────
+
+ const groupByOptions = [
+ { value: 'default', label: 'Smart' },
+ { value: 'due_date', label: 'Due Date' },
+ { value: 'priority', label: 'Priority' },
+ { value: 'labels', label: 'Labels' },
+ ]
+
+ // ── assignee options ─────────────────────────────────────────────────────────
+
+ const assigneeOptions = [
+ { value: 'anyone', label: 'Everyone' },
+ { value: 'assigned_to_me', label: 'Mine' },
+ { value: 'available_for_me', label: 'Available to me' },
+ { value: 'assigned_to_others', label: 'Others' },
+ ]
+
+ // ── project options (show only if more than just Default) ───────────────────
+
+ const showProjectSection = projects.filter(p => p.id !== 'default').length > 0
+
+ // ── pinned saved filters ─────────────────────────────────────────────────────
+
+ const pinnedFilters = savedFilters.filter(f => f.isPinned)
+
+ // ── display active state (highlight button when non-default) ─────────────────
+
+ const displayActive =
+ selectedGroupBy !== 'default' ||
+ viewMode !== 'default' ||
+ projectActive > 0 ||
+ assigneeActive > 0
+
+ const viewOptions = [
+ { value: 'default', label: 'Cards', icon: },
+ { value: 'compact', label: 'Compact', icon: },
+ { value: 'calendar', label: 'Calendar', icon: },
+ ]
+
+ return (
+ <>
+ {/* ── Row 1: main toolbar ─────────────────────────────────────────────── */}
+
+ {/* Search takes available space */}
+
+
+ {/* Filter button */}
+
+ setFilterSheetOpen(true)}
+ title='Filters'
+ >
+
+
+
+
+ {/* Display button — View + Group combined */}
+ setDisplaySheetOpen(true)}
+ title='View & Group'
+ >
+ {viewMode === 'calendar' ? (
+
+ ) : viewMode === 'compact' ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Multiselect */}
+
+
+ {isMultiSelectMode ? : }
+
+
+
+
+
+ {/* ── Row 2: active filter chips (only when something is active) ─────── */}
+ {hasAnyActive && (
+
+ {visibleChips.map(({ key, label, onClear }) => (
+ {
+ e.stopPropagation()
+ onClear()
+ }}
+ />
+ }
+ onClick={() => setFilterSheetOpen(true)}
+ sx={{ cursor: 'pointer', flexShrink: 0 }}
+ >
+ {label}
+
+ ))}
+
+ {overflow > 0 && (
+ setFilterSheetOpen(true)}
+ sx={{ cursor: 'pointer', flexShrink: 0 }}
+ >
+ +{overflow} more
+
+ )}
+
+ {resultCount != null && totalCount != null && (
+
+ {resultCount} / {totalCount}
+
+ )}
+
+
+
+ )}
+
+ {/* ── Unified Filter bottom sheet ─────────────────────────────────────── */}
+ setFilterSheetOpen(false)}
+ title={
+
+
+ Filters
+ {hasAnyActive && (
+
+ {totalActiveCount}
+
+ )}
+
+ }
+ footer={
+
+
+
+
+ }
+ >
+
+
+ {/* ── Quick filter sections (Due Date / Priority / Labels etc.) ────── */}
+ {filterDefs.map(def => (
+
+
+
+ {
+ if (def.type === 'multi-select') {
+ const curr = activeFilters[def.id] || []
+ const next = curr.includes(val)
+ ? curr.filter(v => v !== val)
+ : [...curr, val]
+ onSetFilter(def.id, next.length > 0 ? next : null)
+ } else {
+ onSetFilter(def.id, activeFilters[def.id] === val ? null : val)
+ }
+ }}
+ />
+
+ ))}
+
+ {/* ── Saved / custom filters ──────────────────────────────────────── */}
+ {(pinnedFilters.length > 0 || savedFilters.length > 0) && (
+ <>
+
+
+
+ Saved Filters
+
+ {
+ setFilterSheetOpen(false)
+ // navigate to /filters or open settings
+ }}
+ >
+
+
+
+
+ {savedFilters.map(filter => {
+ const isActive = activeFilterId === filter.id
+ return (
+
+ ) : (
+
+ {filter.count ?? 0}
+
+ )
+ }
+ onClick={() => {
+ onSavedFilterClick?.(filter.id)
+ setFilterSheetOpen(false)
+ }}
+ sx={{
+ cursor: 'pointer',
+ transition: 'all 0.15s ease',
+ userSelect: 'none',
+ '&:hover': { opacity: 0.85 },
+ ...(filter.color && !isActive
+ ? { borderColor: filter.color }
+ : {}),
+ }}
+ >
+ {filter.name}
+
+ )
+ })}
+
+
+ }
+ onClick={() => {
+ setFilterSheetOpen(false)
+ onCreateAdvancedFilter?.()
+ }}
+ sx={{ mt: 1.5, alignSelf: 'flex-start', px: 0 }}
+ >
+ Create advanced filter
+
+ >
+ )}
+
+ {/* Edge case: no saved filters yet → still show "Create" CTA */}
+ {savedFilters.length === 0 && (
+ <>
+
+ }
+ onClick={() => {
+ setFilterSheetOpen(false)
+ onCreateAdvancedFilter?.()
+ }}
+ sx={{ alignSelf: 'flex-start', px: 0 }}
+ >
+ Create advanced filter
+
+ >
+ )}
+
+
+
+ {/* ── Display bottom sheet (View + Group combined) ───────────────────── */}
+ setDisplaySheetOpen(false)}
+ title={
+
+
+ Display
+
+ }
+ footer={
+
+ }
+ >
+
+ {/* View section */}
+
+
+ {viewOptions.map(opt => (
+ : opt.icon}
+ onClick={() => onToggleViewMode?.(opt.value)}
+ sx={{
+ py: 0.64,
+ cursor: 'pointer',
+ transition: 'all 0.15s ease',
+ userSelect: 'none',
+ '&:hover': { opacity: 0.85 },
+ }}
+ >
+ {opt.label}
+
+ ))}
+
+
+
+
+ {/* Group by section */}
+ }
+ label='Group by'
+ badge={
+ selectedGroupBy !== 'default'
+ ? groupByOptions.find(o => o.value === selectedGroupBy)?.label
+ : null
+ }
+ />
+
+ {groupByOptions.map(opt => (
+ onGroupBySelect?.(opt.value)}
+ sx={{
+ py: 0.64,
+ cursor: 'pointer',
+ transition: 'all 0.15s ease',
+ userSelect: 'none',
+ '&:hover': { opacity: 0.85 },
+ }}
+ >
+ {opt.label}
+
+ ))}
+
+
+ {/* Show tasks for section */}
+
+ }
+ label='Show tasks for'
+ badge={
+ selectedAssigneeFilter !== 'anyone'
+ ? assigneeOptions.find(o => o.value === selectedAssigneeFilter)?.label
+ : null
+ }
+ />
+ onAssigneeFilterChange?.(v)}
+ />
+
+ {/* Project section */}
+ {showProjectSection && (
+ <>
+
+ }
+ label='Project'
+ badge={projectActive ? selectedProject.name : null}
+ />
+ ({ value: p.id, label: p.name }))}
+ selected={selectedProject?.id ?? 'default'}
+ multi={false}
+ onToggle={id => {
+ const p = projects.find(x => x.id === id)
+ if (p) onProjectSelect?.(p)
+ }}
+ />
+ >
+ )}
+
+
+ >
+ )
+}
+
+export default ChoreToolbar
diff --git a/src/views/History/ChoreHistory.jsx b/src/views/History/ChoreHistory.jsx
index 17ed410..458b1f1 100644
--- a/src/views/History/ChoreHistory.jsx
+++ b/src/views/History/ChoreHistory.jsx
@@ -8,11 +8,21 @@ import {
import '@meauxt/react-swipeable-list/dist/styles.css'
import {
Analytics,
+ CalendarMonth,
+ Check,
Checklist,
EventBusy,
+ EventNote,
+ FilterList,
Group,
History,
+ HourglassEmpty,
+ Person,
+ Redo,
+ RunningWithErrors,
+ Schedule,
Star,
+ ThumbDown,
Timelapse,
TrendingUp,
} from '@mui/icons-material'
@@ -20,10 +30,12 @@ import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit'
import { Box, Button, Card, Container, Grid, Sheet, Typography } from '@mui/joy'
import moment from 'moment'
-import { useEffect, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
+import FilterBar from '../../components/common/FilterBar'
import { useLocalization } from '../../contexts/LocalizationContext'
import useConfirmationModal from '../../hooks/useConfirmationModal'
+import { useFilter } from '../../hooks/useFilter'
import {
useChoreHistory,
useDeleteChoreHistory,
@@ -34,6 +46,7 @@ import { useNotification } from '../../service/NotificationProvider'
import { ChoreHistoryStatus } from '../../utils/Chores'
import LoadingComponent from '../components/Loading'
import EditHistoryModal from '../Modals/EditHistoryModal'
+import HistoryDetailModal from '../Modals/HistoryDetailModal'
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
import NoteViewerModal from '../Modals/Inputs/NoteViewerModal'
import HistoryCard from './HistoryCard'
@@ -48,6 +61,7 @@ const ChoreHistory = () => {
const { fmt } = useLocalization()
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
const [noteViewerConfig, setNoteViewerConfig] = useState({ isOpen: false })
+ const [detailModalConfig, setDetailModalConfig] = useState({ isOpen: false })
const { showSuccess, showError } = useNotification()
// React Query hooks
const { data: choreHistoryData, isLoading } = useChoreHistory(choreId)
@@ -58,6 +72,61 @@ const ChoreHistory = () => {
const choreHistory = choreHistoryData?.res || []
const performers = circleMembersData?.res || []
+ const filterDefs = useMemo(
+ () => [
+ {
+ id: 'status',
+ label: 'Status',
+ type: 'multi-select',
+ icon: ,
+ options: [
+ { value: ChoreHistoryStatus.COMPLETED, label: 'Completed', color: 'success', icon: },
+ { value: ChoreHistoryStatus.SKIPPED, label: 'Skipped', color: 'warning', icon: },
+ { value: ChoreHistoryStatus.PENDING_APPROVAL, label: 'Pending', color: 'neutral', icon: },
+ { value: ChoreHistoryStatus.REJECTED, label: 'Rejected', color: 'danger', icon: },
+ { value: 5, label: 'Missed', color: 'danger', icon: },
+ { value: 6, label: 'Rescheduled', color: 'warning', icon: },
+ ],
+ filterFn: (item, values) => values.includes(item.status),
+ },
+ {
+ id: 'hasNotes',
+ label: 'Has Notes',
+ type: 'boolean',
+ icon: ,
+ filterFn: item => !!item.notes,
+ },
+ {
+ id: 'completedBy',
+ label: 'Completed By',
+ type: 'multi-select',
+ icon: ,
+ options: performers.map(p => ({
+ value: p.userId,
+ label: p.displayName,
+ avatar: p.image,
+ })),
+ filterFn: (item, values) => values.includes(item.completedBy),
+ },
+ {
+ id: 'dateRange',
+ label: 'Completed At',
+ type: 'date-range',
+ icon: ,
+ filterFn: (item, value) => {
+ const performed = new Date(item.performedAt || item.updatedAt)
+ if (value.from && performed < new Date(value.from)) return false
+ if (value.to && performed > new Date(value.to)) return false
+ return true
+ },
+ },
+ ],
+ [performers],
+ )
+
+ const { filteredData: filteredHistory, activeFilters, setFilter, clearAll, activeFilterCount } =
+ useFilter(choreHistory, filterDefs)
+
const handleDelete = historyEntry => {
showConfirmation(
`Are you sure you want to delete this history record?`,
@@ -205,9 +274,10 @@ const ChoreHistory = () => {
}
return (
-
+
{/* Enhanced Header Section */}
-
+
+ {/* */}
{/* Statistics Cards Grid - Compact Design */}
@@ -285,7 +355,9 @@ const ChoreHistory = () => {
{/* History Section Header */}
-
+
+
+
{
Task Activity
+
+
+
+
+ {filteredHistory.length === 0 && activeFilterCount > 0 && (
+
+
+
+ No results match your filters
+
+
+ Try adjusting or clearing the active filters.
+
+
+
+ )}
+
+ {filteredHistory.length > 0 && (
{/* Chore History List (Updated Style) */}
- {choreHistory.map((historyEntry, index) => (
+ {filteredHistory.map((historyEntry, index) => (
{
performers={performers}
allHistory={choreHistory}
index={index}
+ onViewDetails={() => {
+ setDetailModalConfig({
+ isOpen: true,
+ entry: historyEntry,
+ performers,
+ onClose: () => setDetailModalConfig({ isOpen: false }),
+ })
+ }}
onViewNote={notes => {
setNoteViewerConfig({
isOpen: true,
@@ -387,6 +503,7 @@ const ChoreHistory = () => {
))}
+ )}
{
/>
-
+
+
)
}