feat: add MoreVert icon button for toggle actions in multiple components
This commit is contained in:
@@ -14,11 +14,19 @@ import {
|
|||||||
History,
|
History,
|
||||||
Star,
|
Star,
|
||||||
Timelapse,
|
Timelapse,
|
||||||
TrendingUp,
|
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'
|
||||||
import { Box, Button, Card, Container, Grid, Sheet, Typography } from '@mui/joy'
|
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'
|
||||||
@@ -42,6 +50,7 @@ const ChoreHistory = () => {
|
|||||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
|
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
|
||||||
const [editHistory, setEditHistory] = useState({})
|
const [editHistory, setEditHistory] = useState({})
|
||||||
const { confirmModalConfig, showConfirmation } = useConfirmationModal()
|
const { confirmModalConfig, showConfirmation } = useConfirmationModal()
|
||||||
|
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
|
||||||
|
|
||||||
// React Query hooks
|
// React Query hooks
|
||||||
const { data: choreHistoryData, isLoading } = useChoreHistory(choreId)
|
const { data: choreHistoryData, isLoading } = useChoreHistory(choreId)
|
||||||
@@ -298,6 +307,11 @@ const ChoreHistory = () => {
|
|||||||
{choreHistory.map((historyEntry, index) => (
|
{choreHistory.map((historyEntry, index) => (
|
||||||
<SwipeableListItem
|
<SwipeableListItem
|
||||||
key={historyEntry.id || index}
|
key={historyEntry.id || index}
|
||||||
|
swipeActionOpen={
|
||||||
|
showMoreInfoId === (historyEntry.id || index)
|
||||||
|
? 'trailing'
|
||||||
|
: null
|
||||||
|
}
|
||||||
trailingActions={
|
trailingActions={
|
||||||
<TrailingActions>
|
<TrailingActions>
|
||||||
<Box
|
<Box
|
||||||
@@ -355,6 +369,14 @@ const ChoreHistory = () => {
|
|||||||
performers={performers}
|
performers={performers}
|
||||||
allHistory={choreHistory}
|
allHistory={choreHistory}
|
||||||
index={index}
|
index={index}
|
||||||
|
onToggleActions={() => {
|
||||||
|
const id = historyEntry.id || index
|
||||||
|
if (showMoreInfoId === id) {
|
||||||
|
setShowMoreInfoId(null)
|
||||||
|
} else {
|
||||||
|
setShowMoreInfoId(id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</SwipeableListItem>
|
</SwipeableListItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import {
|
|||||||
CheckCircle,
|
CheckCircle,
|
||||||
EventNote,
|
EventNote,
|
||||||
HourglassEmpty,
|
HourglassEmpty,
|
||||||
|
MoreVert,
|
||||||
Person,
|
Person,
|
||||||
Redo,
|
Redo,
|
||||||
ThumbDown,
|
ThumbDown,
|
||||||
Timelapse,
|
Timelapse,
|
||||||
Toll,
|
Toll,
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import { Avatar, Box, Chip, Grid, Typography } from '@mui/joy'
|
import { Avatar, Box, Chip, Grid, IconButton, Typography } from '@mui/joy'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { TASK_COLOR } from '../../utils/Colors.jsx'
|
import { TASK_COLOR } from '../../utils/Colors.jsx'
|
||||||
|
|
||||||
@@ -85,7 +86,13 @@ const formatTime = seconds => {
|
|||||||
/**
|
/**
|
||||||
* Compact HistoryCard component - content only
|
* Compact HistoryCard component - content only
|
||||||
*/
|
*/
|
||||||
const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
|
const HistoryCard = ({
|
||||||
|
allHistory,
|
||||||
|
performers,
|
||||||
|
historyEntry,
|
||||||
|
index,
|
||||||
|
onToggleActions,
|
||||||
|
}) => {
|
||||||
const performer = performers.find(p => p.userId === historyEntry.completedBy)
|
const performer = performers.find(p => p.userId === historyEntry.completedBy)
|
||||||
const assignedTo = performers.find(p => p.userId === historyEntry.assignedTo)
|
const assignedTo = performers.find(p => p.userId === historyEntry.assignedTo)
|
||||||
|
|
||||||
@@ -149,7 +156,7 @@ const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
|
|||||||
borderColor: 'divider',
|
borderColor: 'divider',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ flex: 1 }}>
|
<Box sx={{ flex: 1, minWidth: 0 }}>
|
||||||
<Grid container spacing={1} alignItems='center'>
|
<Grid container spacing={1} alignItems='center'>
|
||||||
{/* First Row/Column: Status and Time Info */}
|
{/* First Row/Column: Status and Time Info */}
|
||||||
<Grid xs={12} sm={8}>
|
<Grid xs={12} sm={8}>
|
||||||
@@ -282,6 +289,21 @@ const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{onToggleActions && (
|
||||||
|
<IconButton
|
||||||
|
color='neutral'
|
||||||
|
variant='plain'
|
||||||
|
size='sm'
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
onToggleActions()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVert sx={{ fontSize: 18 }} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
TrailingActions,
|
TrailingActions,
|
||||||
} from '@meauxt/react-swipeable-list'
|
} from '@meauxt/react-swipeable-list'
|
||||||
import '@meauxt/react-swipeable-list/dist/styles.css'
|
import '@meauxt/react-swipeable-list/dist/styles.css'
|
||||||
import { Add } from '@mui/icons-material'
|
import { Add, MoreVert } from '@mui/icons-material'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
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'
|
||||||
@@ -30,7 +30,7 @@ import { getSafeBottomStyles } from '../../utils/SafeAreaUtils'
|
|||||||
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
||||||
import { useLabels } from './LabelQueries'
|
import { useLabels } from './LabelQueries'
|
||||||
|
|
||||||
const LabelCardContent = ({ label, currentUserId }) => {
|
const LabelCardContent = ({ label, currentUserId, onToggleActions }) => {
|
||||||
// Check if current user owns this label
|
// Check if current user owns this label
|
||||||
const isOwnedByCurrentUser = label.created_by === currentUserId
|
const isOwnedByCurrentUser = label.created_by === currentUserId
|
||||||
|
|
||||||
@@ -128,6 +128,21 @@ const LabelCardContent = ({ label, currentUserId }) => {
|
|||||||
)}
|
)}
|
||||||
</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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -142,6 +157,7 @@ const LabelView = () => {
|
|||||||
const [currentLabel, setCurrentLabel] = useState(null)
|
const [currentLabel, setCurrentLabel] = useState(null)
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [confirmationModel, setConfirmationModel] = useState({})
|
const [confirmationModel, setConfirmationModel] = useState({})
|
||||||
|
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
|
||||||
|
|
||||||
const handleAddLabel = () => {
|
const handleAddLabel = () => {
|
||||||
setCurrentLabel(null)
|
setCurrentLabel(null)
|
||||||
@@ -260,6 +276,7 @@ const LabelView = () => {
|
|||||||
{userLabels.map(label => (
|
{userLabels.map(label => (
|
||||||
<SwipeableListItem
|
<SwipeableListItem
|
||||||
key={label.id}
|
key={label.id}
|
||||||
|
swipeActionOpen={showMoreInfoId === label.id ? 'trailing' : null}
|
||||||
trailingActions={
|
trailingActions={
|
||||||
<TrailingActions>
|
<TrailingActions>
|
||||||
<Box
|
<Box
|
||||||
@@ -311,7 +328,17 @@ const LabelView = () => {
|
|||||||
</TrailingActions>
|
</TrailingActions>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<LabelCardContent label={label} currentUserId={userProfile?.id} />
|
<LabelCardContent
|
||||||
|
label={label}
|
||||||
|
currentUserId={userProfile?.id}
|
||||||
|
onToggleActions={() => {
|
||||||
|
if (showMoreInfoId === label.id) {
|
||||||
|
setShowMoreInfoId(null)
|
||||||
|
} else {
|
||||||
|
setShowMoreInfoId(label.id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</SwipeableListItem>
|
</SwipeableListItem>
|
||||||
))}
|
))}
|
||||||
</SwipeableList>
|
</SwipeableList>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
TrailingActions,
|
TrailingActions,
|
||||||
} from '@meauxt/react-swipeable-list'
|
} from '@meauxt/react-swipeable-list'
|
||||||
import '@meauxt/react-swipeable-list/dist/styles.css'
|
import '@meauxt/react-swipeable-list/dist/styles.css'
|
||||||
import { Add, Task } from '@mui/icons-material'
|
import { Add, MoreVert, Task } from '@mui/icons-material'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import { useChores } from '../../queries/ChoreQueries'
|
import { useChores } from '../../queries/ChoreQueries'
|
||||||
import { useUserProfile } from '../../queries/UserQueries'
|
import { useUserProfile } from '../../queries/UserQueries'
|
||||||
@@ -38,6 +38,7 @@ const ProjectCardContent = ({
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
taskCounts = {},
|
taskCounts = {},
|
||||||
onCardClick,
|
onCardClick,
|
||||||
|
onToggleActions,
|
||||||
}) => {
|
}) => {
|
||||||
// Check if current user owns this project
|
// Check if current user owns this project
|
||||||
const isOwnedByCurrentUser = project.created_by === currentUserId
|
const isOwnedByCurrentUser = project.created_by === currentUserId
|
||||||
@@ -197,6 +198,21 @@ const ProjectCardContent = ({
|
|||||||
)}
|
)}
|
||||||
</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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -215,6 +231,7 @@ const ProjectView = () => {
|
|||||||
const [taskCounts, setTaskCounts] = useState({})
|
const [taskCounts, setTaskCounts] = useState({})
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [confirmationModel, setConfirmationModel] = useState({})
|
const [confirmationModel, setConfirmationModel] = useState({})
|
||||||
|
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
|
||||||
|
|
||||||
const handleAddProject = () => {
|
const handleAddProject = () => {
|
||||||
setCurrentProject(null)
|
setCurrentProject(null)
|
||||||
@@ -373,6 +390,9 @@ const ProjectView = () => {
|
|||||||
<SwipeableListItem
|
<SwipeableListItem
|
||||||
onClick={() => handleCardClick(project)}
|
onClick={() => handleCardClick(project)}
|
||||||
key={project.id}
|
key={project.id}
|
||||||
|
swipeActionOpen={
|
||||||
|
showMoreInfoId === project.id ? 'trailing' : null
|
||||||
|
}
|
||||||
trailingActions={
|
trailingActions={
|
||||||
<TrailingActions>
|
<TrailingActions>
|
||||||
<Box
|
<Box
|
||||||
@@ -430,7 +450,13 @@ const ProjectView = () => {
|
|||||||
project={project}
|
project={project}
|
||||||
currentUserId={userProfile?.id}
|
currentUserId={userProfile?.id}
|
||||||
taskCounts={taskCounts}
|
taskCounts={taskCounts}
|
||||||
// onCardClick={}
|
onToggleActions={() => {
|
||||||
|
if (showMoreInfoId === project.id) {
|
||||||
|
setShowMoreInfoId(null)
|
||||||
|
} else {
|
||||||
|
setShowMoreInfoId(project.id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</SwipeableListItem>
|
</SwipeableListItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Delete,
|
Delete,
|
||||||
Edit,
|
Edit,
|
||||||
Flip,
|
Flip,
|
||||||
|
MoreVert,
|
||||||
PlusOne,
|
PlusOne,
|
||||||
ToggleOff,
|
ToggleOff,
|
||||||
ToggleOn,
|
ToggleOn,
|
||||||
@@ -40,7 +41,7 @@ import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
|||||||
import CreateThingModal from '../Modals/Inputs/CreateThingModal'
|
import CreateThingModal from '../Modals/Inputs/CreateThingModal'
|
||||||
import EditThingStateModal from '../Modals/Inputs/EditThingState'
|
import EditThingStateModal from '../Modals/Inputs/EditThingState'
|
||||||
|
|
||||||
const ThingCardContent = ({ thing, onCardClick }) => {
|
const ThingCardContent = ({ thing, onCardClick, onToggleActions }) => {
|
||||||
const getThingIcon = type => {
|
const getThingIcon = type => {
|
||||||
if (type === 'text') {
|
if (type === 'text') {
|
||||||
return <Flip />
|
return <Flip />
|
||||||
@@ -183,6 +184,21 @@ const ThingCardContent = ({ thing, onCardClick }) => {
|
|||||||
</Chip>
|
</Chip>
|
||||||
</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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -194,6 +210,7 @@ const ThingsView = () => {
|
|||||||
const [isShowEditThingStateModal, setIsShowEditStateModal] = useState(false)
|
const [isShowEditThingStateModal, setIsShowEditStateModal] = useState(false)
|
||||||
const [createModalThing, setCreateModalThing] = useState(null)
|
const [createModalThing, setCreateModalThing] = useState(null)
|
||||||
const [confirmModelConfig, setConfirmModelConfig] = useState({})
|
const [confirmModelConfig, setConfirmModelConfig] = useState({})
|
||||||
|
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
|
||||||
const { showError, showNotification } = useNotification()
|
const { showError, showNotification } = useNotification()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -388,6 +405,7 @@ const ThingsView = () => {
|
|||||||
<SwipeableListItem
|
<SwipeableListItem
|
||||||
onClick={() => navigate(`/things/${thing?.id}`)}
|
onClick={() => navigate(`/things/${thing?.id}`)}
|
||||||
key={thing.id}
|
key={thing.id}
|
||||||
|
swipeActionOpen={showMoreInfoId === thing.id ? 'trailing' : null}
|
||||||
trailingActions={
|
trailingActions={
|
||||||
<TrailingActions>
|
<TrailingActions>
|
||||||
<Box
|
<Box
|
||||||
@@ -474,7 +492,16 @@ const ThingsView = () => {
|
|||||||
</TrailingActions>
|
</TrailingActions>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ThingCardContent thing={thing} />
|
<ThingCardContent
|
||||||
|
thing={thing}
|
||||||
|
onToggleActions={() => {
|
||||||
|
if (showMoreInfoId === thing.id) {
|
||||||
|
setShowMoreInfoId(null)
|
||||||
|
} else {
|
||||||
|
setShowMoreInfoId(thing.id)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</SwipeableListItem>
|
</SwipeableListItem>
|
||||||
))}
|
))}
|
||||||
</SwipeableList>
|
</SwipeableList>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
BrowseGallery,
|
BrowseGallery,
|
||||||
Delete,
|
Delete,
|
||||||
Edit,
|
Edit,
|
||||||
|
MoreVert,
|
||||||
PauseCircle,
|
PauseCircle,
|
||||||
Person,
|
Person,
|
||||||
PlayArrow,
|
PlayArrow,
|
||||||
@@ -56,6 +57,7 @@ const TimerDetails = () => {
|
|||||||
const [editingSessions, setEditingSessions] = useState({})
|
const [editingSessions, setEditingSessions] = useState({})
|
||||||
const [currentTime, setCurrentTime] = useState(new Date())
|
const [currentTime, setCurrentTime] = useState(new Date())
|
||||||
const [timerActionLoading, setTimerActionLoading] = useState(false)
|
const [timerActionLoading, setTimerActionLoading] = useState(false)
|
||||||
|
const [showMoreInfoId, setShowMoreInfoId] = useState(null)
|
||||||
const { showError, showSuccess } = useNotification()
|
const { showError, showSuccess } = useNotification()
|
||||||
|
|
||||||
// Fetch circle members data
|
// Fetch circle members data
|
||||||
@@ -940,6 +942,11 @@ const TimerDetails = () => {
|
|||||||
return (
|
return (
|
||||||
<SwipeableListItem
|
<SwipeableListItem
|
||||||
key={pauseIndex}
|
key={pauseIndex}
|
||||||
|
swipeActionOpen={
|
||||||
|
showMoreInfoId === pauseIndex
|
||||||
|
? 'trailing'
|
||||||
|
: null
|
||||||
|
}
|
||||||
trailingActions={
|
trailingActions={
|
||||||
<TrailingActions>
|
<TrailingActions>
|
||||||
<Box
|
<Box
|
||||||
@@ -1131,6 +1138,22 @@ const TimerDetails = () => {
|
|||||||
{endTime ? `→ ${endTime}` : '→ ongoing'}
|
{endTime ? `→ ${endTime}` : '→ ongoing'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
color='neutral'
|
||||||
|
variant='plain'
|
||||||
|
size='sm'
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
if (showMoreInfoId === pauseIndex) {
|
||||||
|
setShowMoreInfoId(null)
|
||||||
|
} else {
|
||||||
|
setShowMoreInfoId(pauseIndex)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreVert sx={{ fontSize: 18 }} />
|
||||||
|
</IconButton>
|
||||||
</Card>
|
</Card>
|
||||||
</SwipeableListItem>
|
</SwipeableListItem>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user