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

View File

@@ -1,12 +1,20 @@
import { import {
Analytics, Type as ListType,
Checklist, SwipeableList,
EventBusy, SwipeableListItem,
Group, SwipeAction,
History, TrailingActions,
Star, } from '@meauxt/react-swipeable-list'
Timelapse, import '@meauxt/react-swipeable-list/dist/styles.css'
TrendingUp, import {
Analytics,
Checklist,
EventBusy,
Group,
History,
Star,
Timelapse,
TrendingUp,
} from '@mui/icons-material' } from '@mui/icons-material'
import DeleteIcon from '@mui/icons-material/Delete' import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit' 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 moment from 'moment'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Link, useParams } from 'react-router-dom' 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 useConfirmationModal from '../../hooks/useConfirmationModal'
import { import {
useChoreHistory, useChoreHistory,
useDeleteChoreHistory, useDeleteChoreHistory,
useUpdateChoreHistory, useUpdateChoreHistory,
} from '../../queries/ChoreQueries' } from '../../queries/ChoreQueries'
import { useCircleMembers } from '../../queries/UserQueries' import { useCircleMembers } from '../../queries/UserQueries'
import { ChoreHistoryStatus } from '../../utils/Chores' import { ChoreHistoryStatus } from '../../utils/Chores'

View File

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

View File

@@ -1,29 +1,29 @@
import DeleteIcon from '@mui/icons-material/Delete' import DeleteIcon from '@mui/icons-material/Delete'
import EditIcon from '@mui/icons-material/Edit' import EditIcon from '@mui/icons-material/Edit'
import { import {
Avatar, Avatar,
Box, Box,
Chip, Chip,
CircularProgress, CircularProgress,
Container, Container,
IconButton, IconButton,
Stack, Stack,
Typography, Typography,
} from '@mui/joy' } from '@mui/joy'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import ProjectModal from '../Modals/Inputs/ProjectModal' 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 { Add, Task } from '@mui/icons-material'
import { useQueryClient } from '@tanstack/react-query' 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 { useChores } from '../../queries/ChoreQueries'
import { useUserProfile } from '../../queries/UserQueries' import { useUserProfile } from '../../queries/UserQueries'
import { getTextColorFromBackgroundColor } from '../../utils/Colors' import { getTextColorFromBackgroundColor } from '../../utils/Colors'

View File

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

View File

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