refactor: replace react-swipeable-list with @meauxt/react-swipeable-list across multiple views

This commit is contained in:
Mo Tarbin
2026-02-15 23:17:09 -05:00
parent bc274b2cf7
commit af401e7b27
7 changed files with 258 additions and 211 deletions

View File

@@ -1,3 +1,11 @@
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import {
Check,
Delete,
@@ -10,14 +18,6 @@ import {
} from '@mui/icons-material'
import { Box, Typography } from '@mui/joy'
import { useNavigate } from 'react-router-dom'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import ChoreCard from './ChoreCard'
import CompactChoreCard from './CompactChoreCard'

View File

@@ -1,3 +1,11 @@
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit'
import {
@@ -12,16 +20,15 @@ import {
} from '@mui/joy'
import { useEffect, useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import { Add, FilterAlt, Star, StarBorder, Task } from '@mui/icons-material'
import {
Add,
FilterAlt,
MoreVert,
Star,
StarBorder,
Task,
} from '@mui/icons-material'
import { useChores } from '../../queries/ChoreQueries'
import { useCircleMembers, useUserProfile } from '../../queries/UserQueries'
import { getFilterCount, getFilterOverdueCount } from '../../utils/FilterEngine'
@@ -39,7 +46,12 @@ import {
useUpdateFilter,
} from './FilterQueries'
const FilterCardContent = ({ filter, taskCount = 0, overdueCount = 0 }) => {
const FilterCardContent = ({
filter,
taskCount = 0,
overdueCount = 0,
onToggleActions,
}) => {
// Get condition labels for display
const getConditionSummary = () => {
if (!filter.conditions || filter.conditions.length === 0) {
@@ -212,6 +224,21 @@ const FilterCardContent = ({ filter, taskCount = 0, overdueCount = 0 }) => {
)}
</Box>
</Box>
<Box>
{onToggleActions && (
<IconButton
color='neutral'
variant='plain'
size='sm'
onClick={e => {
e.stopPropagation()
onToggleActions()
}}
>
<MoreVert sx={{ fontSize: 18 }} />
</IconButton>
)}
</Box>
</Box>
)
}
@@ -236,7 +263,7 @@ const FilterView = () => {
useState(false)
const [editingFilter, setEditingFilter] = useState(null)
const [confirmationModel, setConfirmationModel] = useState({})
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
// Sort filters: pinned first, then by usage count, then by last used
const savedFilters = useMemo(() => {
return [...filtersData].sort((a, b) => {
@@ -415,99 +442,119 @@ const FilterView = () => {
</Box>
) : (
<SwipeableList type={ListType.IOS} fullSwipe={false}>
{savedFilters.map(filter => (
<SwipeableListItem
onClick={() =>
navigate(`/chores?filterId=${encodeURIComponent(filter.id)}`)
}
key={filter.id}
trailingActions={
<TrailingActions>
<Box
sx={{
display: 'flex',
boxShadow: 'inset 2px 0 4px rgba(0,0,0,0.06)',
zIndex: 0,
}}
>
<SwipeAction onClick={() => handlePinFilter(filter.id)}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'warning.softBg',
color: 'warning.700',
px: 3,
height: '100%',
}}
>
{filter.isPinned ? (
<Star sx={{ fontSize: 20 }} />
) : (
<StarBorder sx={{ fontSize: 20 }} />
)}
<Typography level='body-xs' sx={{ mt: 0.5 }}>
{filter.isPinned ? 'Unpin' : 'Pin'}
</Typography>
</Box>
</SwipeAction>
<SwipeAction onClick={() => handleEditFilter(filter)}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'neutral.softBg',
color: 'neutral.700',
px: 3,
height: '100%',
}}
>
<EditIcon sx={{ fontSize: 20 }} />
<Typography level='body-xs' sx={{ mt: 0.5 }}>
Edit
</Typography>
</Box>
</SwipeAction>
<SwipeAction
onClick={() => handleDeleteClicked(filter.id)}
{savedFilters.map(filter => {
return (
<SwipeableListItem
swipeActionOpen={
showMoreInfoId === filter.id ? 'trailing' : null
}
onClick={() =>
navigate(
`/chores?filterId=${encodeURIComponent(filter.id)}`,
)
}
key={filter.id}
trailingActions={
<TrailingActions>
<Box
sx={{
display: 'flex',
boxShadow: 'inset 2px 0 4px rgba(0,0,0,0.06)',
zIndex: 0,
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'danger.softBg',
color: 'danger.700',
px: 3,
height: '100%',
}}
>
<DeleteIcon sx={{ fontSize: 20 }} color='danger' />
<Typography
level='body-xs'
sx={{ mt: 0.5 }}
color='danger'
<SwipeAction onClick={() => handlePinFilter(filter.id)}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'warning.softBg',
color: 'warning.700',
px: 3,
height: '100%',
}}
>
Delete
</Typography>
</Box>
</SwipeAction>
</Box>
</TrailingActions>
}
>
<FilterCardContent
filter={filter}
taskCount={filterCounts[filter.id]?.count || 0}
overdueCount={filterCounts[filter.id]?.overdueCount || 0}
/>
</SwipeableListItem>
))}
{filter.isPinned ? (
<Star sx={{ fontSize: 20 }} />
) : (
<StarBorder sx={{ fontSize: 20 }} />
)}
<Typography level='body-xs' sx={{ mt: 0.5 }}>
{filter.isPinned ? 'Unpin' : 'Pin'}
</Typography>
</Box>
</SwipeAction>
<SwipeAction onClick={() => handleEditFilter(filter)}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'neutral.softBg',
color: 'neutral.700',
px: 3,
height: '100%',
}}
>
<EditIcon sx={{ fontSize: 20 }} />
<Typography level='body-xs' sx={{ mt: 0.5 }}>
Edit
</Typography>
</Box>
</SwipeAction>
<SwipeAction
onClick={() => handleDeleteClicked(filter.id)}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'danger.softBg',
color: 'danger.700',
px: 3,
height: '100%',
}}
>
<DeleteIcon sx={{ fontSize: 20 }} color='danger' />
<Typography
level='body-xs'
sx={{ mt: 0.5 }}
color='danger'
>
Delete
</Typography>
</Box>
</SwipeAction>
</Box>
</TrailingActions>
}
>
<FilterCardContent
onToggleActions={() => {
console.log(
'Toggling actions for filter:',
filter.id,
showMoreInfoId,
)
if (showMoreInfoId === filter.id) {
setShowMoreInfoId(null)
} else {
setShowMoreInfoId(filter.id)
}
}}
filter={filter}
taskCount={filterCounts[filter.id]?.count || 0}
overdueCount={filterCounts[filter.id]?.overdueCount || 0}
/>
</SwipeableListItem>
)
})}
</SwipeableList>
)}
</Box>

View File

@@ -1,12 +1,20 @@
import {
Analytics,
Checklist,
EventBusy,
Group,
History,
Star,
Timelapse,
TrendingUp,
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import {
Analytics,
Checklist,
EventBusy,
Group,
History,
Star,
Timelapse,
TrendingUp,
} from '@mui/icons-material'
import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit'
@@ -14,19 +22,11 @@ import { Box, Button, Card, Container, Grid, Sheet, Typography } from '@mui/joy'
import moment from 'moment'
import { useEffect, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import useConfirmationModal from '../../hooks/useConfirmationModal'
import {
useChoreHistory,
useDeleteChoreHistory,
useUpdateChoreHistory,
useChoreHistory,
useDeleteChoreHistory,
useUpdateChoreHistory,
} from '../../queries/ChoreQueries'
import { useCircleMembers } from '../../queries/UserQueries'
import { ChoreHistoryStatus } from '../../utils/Chores'

View File

@@ -13,16 +13,16 @@ import {
import { useEffect, useState } from 'react'
import LabelModal from '../Modals/Inputs/LabelModal'
import { Add } from '@mui/icons-material'
import { useQueryClient } from '@tanstack/react-query'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import { Add } from '@mui/icons-material'
import { useQueryClient } from '@tanstack/react-query'
import { useUserProfile } from '../../queries/UserQueries'
import { getTextColorFromBackgroundColor } from '../../utils/Colors'
import { DeleteLabel } from '../../utils/Fetcher'

View File

@@ -1,29 +1,29 @@
import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit'
import {
Avatar,
Box,
Chip,
CircularProgress,
Container,
IconButton,
Stack,
Typography,
Avatar,
Box,
Chip,
CircularProgress,
Container,
IconButton,
Stack,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import ProjectModal from '../Modals/Inputs/ProjectModal'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import { Add, Task } from '@mui/icons-material'
import { useQueryClient } from '@tanstack/react-query'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import { useChores } from '../../queries/ChoreQueries'
import { useUserProfile } from '../../queries/UserQueries'
import { getTextColorFromBackgroundColor } from '../../utils/Colors'

View File

@@ -1,39 +1,39 @@
import {
Add,
Delete,
Edit,
Flip,
PlusOne,
ToggleOff,
ToggleOn,
Widgets,
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import {
Add,
Delete,
Edit,
Flip,
PlusOne,
ToggleOff,
ToggleOn,
Widgets,
} from '@mui/icons-material'
import {
Avatar,
Box,
Chip,
Container,
IconButton,
Stack,
Typography,
Avatar,
Box,
Chip,
Container,
IconButton,
Stack,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import { useNotification } from '../../service/NotificationProvider'
import {
CreateThing,
DeleteThing,
GetThings,
SaveThing,
UpdateThingState,
CreateThing,
DeleteThing,
GetThings,
SaveThing,
UpdateThingState,
} from '../../utils/Fetcher'
import { getSafeBottomStyles } from '../../utils/SafeAreaUtils'
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'

View File

@@ -1,47 +1,47 @@
import {
AccessTime,
Add,
BrowseGallery,
Delete,
Edit,
PauseCircle,
Person,
PlayArrow,
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from '@meauxt/react-swipeable-list'
import '@meauxt/react-swipeable-list/dist/styles.css'
import {
AccessTime,
Add,
BrowseGallery,
Delete,
Edit,
PauseCircle,
Person,
PlayArrow,
} from '@mui/icons-material'
import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit'
import {
Alert,
Avatar,
Box,
Button,
Card,
CardContent,
Chip,
Container,
FormControl,
FormHelperText,
Grid,
IconButton,
Input,
Typography,
Alert,
Avatar,
Box,
Button,
Card,
CardContent,
Chip,
Container,
FormControl,
FormHelperText,
Grid,
IconButton,
Input,
Typography,
} from '@mui/joy'
import moment from 'moment'
import { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import {
Type as ListType,
SwipeableList,
SwipeableListItem,
SwipeAction,
TrailingActions,
} from 'react-swipeable-list'
import 'react-swipeable-list/dist/styles.css'
import {
useChoreTimer,
usePauseChore,
useStartChore,
useUpdateTimeSession,
useChoreTimer,
usePauseChore,
useStartChore,
useUpdateTimeSession,
} from '../../queries/TimeQueries'
import { useCircleMembers } from '../../queries/UserQueries'
import { useNotification } from '../../service/NotificationProvider'