feat: update user activity filters to allow selection of last 7 days and improve UI layout
This commit is contained in:
@@ -368,7 +368,7 @@ const USER_FILTER = (history, userId) => {
|
|||||||
const UserActivites = () => {
|
const UserActivites = () => {
|
||||||
const { data: userProfile } = useUserProfile()
|
const { data: userProfile } = useUserProfile()
|
||||||
|
|
||||||
const [tabValue, setTabValue] = React.useState(30)
|
const [tabValue, setTabValue] = React.useState(7)
|
||||||
const [selectedHistory, setSelectedHistory] = React.useState([])
|
const [selectedHistory, setSelectedHistory] = React.useState([])
|
||||||
const [enrichedHistory, setEnrichedHistory] = React.useState([])
|
const [enrichedHistory, setEnrichedHistory] = React.useState([])
|
||||||
const [selectedChart, setSelectedChart] = React.useState('history')
|
const [selectedChart, setSelectedChart] = React.useState('history')
|
||||||
@@ -840,102 +840,53 @@ const UserActivites = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
{/* Main Content Area - Mobile: Stack vertically, Desktop: Side by side */}
|
|
||||||
<Box
|
{/* Filter Controls - Always visible */}
|
||||||
|
<Card
|
||||||
|
variant='outlined'
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
width: '100%',
|
||||||
flexDirection: { xs: 'column', lg: 'row' },
|
p: 2,
|
||||||
gap: 3,
|
mb: 3,
|
||||||
alignItems: 'flex-start',
|
borderRadius: 12,
|
||||||
|
background:
|
||||||
|
'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
||||||
|
backdropFilter: 'blur(10px)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Left Side - Timeline with Filters (Mobile: Full width, Desktop: Flexible) */}
|
<Stack spacing={2}>
|
||||||
<Box sx={{ flex: 1, minWidth: 0, width: '100%' }}>
|
<Typography level='title-sm' sx={{ color: 'text.secondary' }}>
|
||||||
{/* Improved Filter Bar - Now above timeline */}
|
Filter Activities
|
||||||
<Card
|
</Typography>
|
||||||
variant='outlined'
|
|
||||||
sx={{
|
|
||||||
width: '100%',
|
|
||||||
p: 2,
|
|
||||||
mb: 3,
|
|
||||||
borderRadius: 12,
|
|
||||||
background:
|
|
||||||
'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
|
||||||
backdropFilter: 'blur(10px)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack spacing={2}>
|
|
||||||
<Typography level='title-sm' sx={{ color: 'text.secondary' }}>
|
|
||||||
Filter Activities
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Stack
|
<Stack
|
||||||
direction={{ xs: 'column', sm: 'row' }}
|
direction={{ xs: 'column', sm: 'row' }}
|
||||||
spacing={2}
|
spacing={2}
|
||||||
alignItems={{ xs: 'stretch', sm: 'center' }}
|
alignItems={{ xs: 'stretch', sm: 'center' }}
|
||||||
>
|
>
|
||||||
{/* User Filter */}
|
{/* User Filter */}
|
||||||
<Box sx={{ flex: 1, minWidth: 200 }}>
|
<Box sx={{ flex: 1, minWidth: 200 }}>
|
||||||
<Typography level='body-sm' sx={{ mb: 1, fontWeight: 500 }}>
|
<Typography level='body-sm' sx={{ mb: 1, fontWeight: 500 }}>
|
||||||
Show activities for:
|
Show activities for:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Select
|
<Select
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
value={selectedUser}
|
value={selectedUser}
|
||||||
onChange={(e, selected) => {
|
onChange={(e, selected) => {
|
||||||
setSelectedUser(selected)
|
setSelectedUser(selected)
|
||||||
setSelectedHistory(
|
setSelectedHistory(
|
||||||
enrichedHistory.filter(h => USER_FILTER(h, selected)),
|
enrichedHistory.filter(h => USER_FILTER(h, selected)),
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
renderValue={() => {
|
renderValue={() => {
|
||||||
if (
|
if (
|
||||||
selectedUser === undefined ||
|
selectedUser === undefined ||
|
||||||
selectedUser === 'all'
|
selectedUser === 'all'
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Typography
|
|
||||||
startDecorator={
|
|
||||||
<Avatar color='primary' size='sm'>
|
|
||||||
<Group />
|
|
||||||
</Avatar>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
All Users
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Typography
|
|
||||||
startDecorator={
|
|
||||||
<Avatar
|
|
||||||
color='primary'
|
|
||||||
size='sm'
|
|
||||||
src={resolvePhotoURL(
|
|
||||||
circleUsers.find(
|
|
||||||
user => user.userId === selectedUser,
|
|
||||||
)?.image,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{circleUsers
|
|
||||||
.find(user => user.userId === selectedUser)
|
|
||||||
?.displayName?.charAt(0)}
|
|
||||||
</Avatar>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
circleUsers.find(
|
|
||||||
user => user.userId === selectedUser,
|
|
||||||
)?.displayName
|
|
||||||
}
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Option value='all'>
|
|
||||||
<Typography
|
<Typography
|
||||||
startDecorator={
|
startDecorator={
|
||||||
<Avatar color='primary' size='sm'>
|
<Avatar color='primary' size='sm'>
|
||||||
@@ -945,262 +896,366 @@ const UserActivites = () => {
|
|||||||
>
|
>
|
||||||
All Users
|
All Users
|
||||||
</Typography>
|
</Typography>
|
||||||
</Option>
|
)
|
||||||
{circleUsers.map(user => (
|
}
|
||||||
<Option key={user.userId} value={user.userId}>
|
return (
|
||||||
|
<Typography
|
||||||
|
startDecorator={
|
||||||
<Avatar
|
<Avatar
|
||||||
color='primary'
|
color='primary'
|
||||||
size='sm'
|
size='sm'
|
||||||
src={resolvePhotoURL(user.image)}
|
src={resolvePhotoURL(
|
||||||
|
circleUsers.find(
|
||||||
|
user => user.userId === selectedUser,
|
||||||
|
)?.image,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{user.displayName?.charAt(0)}
|
{circleUsers
|
||||||
|
.find(user => user.userId === selectedUser)
|
||||||
|
?.displayName?.charAt(0)}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<Typography>{user.displayName}</Typography>
|
}
|
||||||
<Chip
|
|
||||||
color='success'
|
|
||||||
size='sm'
|
|
||||||
variant='soft'
|
|
||||||
startDecorator={<Toll />}
|
|
||||||
>
|
|
||||||
{user.points - user.pointsRedeemed}
|
|
||||||
</Chip>
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
{/* Time Period Filter */}
|
|
||||||
<Box sx={{ flex: 1, minWidth: 200 }}>
|
|
||||||
<Typography level='body-sm' sx={{ mb: 1, fontWeight: 500 }}>
|
|
||||||
Time period:
|
|
||||||
</Typography>
|
|
||||||
<Tabs
|
|
||||||
onChange={(e, tabValue) => {
|
|
||||||
setTabValue(tabValue)
|
|
||||||
refetchHistory(tabValue)
|
|
||||||
}}
|
|
||||||
value={tabValue}
|
|
||||||
sx={{
|
|
||||||
borderRadius: 8,
|
|
||||||
backgroundColor: 'background.surface',
|
|
||||||
border: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TabList
|
|
||||||
disableUnderline
|
|
||||||
sx={{
|
|
||||||
borderRadius: 8,
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
p: 0.5,
|
|
||||||
gap: 0.5,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{[
|
{
|
||||||
{ label: '7 Days', value: 7 },
|
circleUsers.find(
|
||||||
{ label: '30 Days', value: 30 },
|
user => user.userId === selectedUser,
|
||||||
{ label: '90 Days', value: 90 },
|
)?.displayName
|
||||||
{ label: 'All Time', value: 365 },
|
}
|
||||||
].map((tab, index) => (
|
</Typography>
|
||||||
<Tab
|
)
|
||||||
key={index}
|
}}
|
||||||
sx={{
|
>
|
||||||
borderRadius: 6,
|
<Option value='all'>
|
||||||
minWidth: 'auto',
|
<Typography
|
||||||
px: 2,
|
startDecorator={
|
||||||
py: 1,
|
<Avatar color='primary' size='sm'>
|
||||||
fontSize: 'sm',
|
<Group />
|
||||||
fontWeight: 500,
|
</Avatar>
|
||||||
color: 'text.secondary',
|
}
|
||||||
'&.Mui-selected': {
|
>
|
||||||
color: 'primary.plainColor',
|
All Users
|
||||||
backgroundColor: 'primary.softBg',
|
</Typography>
|
||||||
fontWeight: 600,
|
</Option>
|
||||||
},
|
{circleUsers.map(user => (
|
||||||
'&:hover': {
|
<Option key={user.userId} value={user.userId}>
|
||||||
backgroundColor: 'neutral.softHoverBg',
|
<Avatar
|
||||||
},
|
color='primary'
|
||||||
}}
|
size='sm'
|
||||||
disableIndicator
|
src={resolvePhotoURL(user.image)}
|
||||||
value={tab.value}
|
>
|
||||||
>
|
{user.displayName?.charAt(0)}
|
||||||
{tab.label}
|
</Avatar>
|
||||||
</Tab>
|
<Typography>{user.displayName}</Typography>
|
||||||
))}
|
<Chip
|
||||||
</TabList>
|
color='success'
|
||||||
</Tabs>
|
size='sm'
|
||||||
</Box>
|
variant='soft'
|
||||||
</Stack>
|
startDecorator={<Toll />}
|
||||||
</Stack>
|
>
|
||||||
</Card>
|
{user.points - user.pointsRedeemed}
|
||||||
|
</Chip>
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Current Filter Summary */}
|
{/* Time Period Filter */}
|
||||||
<Box sx={{ mb: 3, textAlign: 'center' }}>
|
<Box sx={{ flex: 1, minWidth: 200 }}>
|
||||||
<Typography level='body-sm' sx={{ color: 'text.secondary' }}>
|
<Typography level='body-sm' sx={{ mb: 1, fontWeight: 500 }}>
|
||||||
Showing activities for{' '}
|
Time period:
|
||||||
<Typography
|
|
||||||
component='span'
|
|
||||||
sx={{ fontWeight: 600, color: 'primary.500' }}
|
|
||||||
>
|
|
||||||
{selectedUser === undefined || selectedUser === 'all'
|
|
||||||
? 'All Users'
|
|
||||||
: circleUsers.find(user => user.userId === selectedUser)
|
|
||||||
?.displayName || 'Unknown User'}
|
|
||||||
</Typography>{' '}
|
|
||||||
over the{' '}
|
|
||||||
<Typography
|
|
||||||
component='span'
|
|
||||||
sx={{ fontWeight: 600, color: 'primary.500' }}
|
|
||||||
>
|
|
||||||
{tabValue === 365 ? 'All Time' : `Last ${tabValue} Days`}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Typography>
|
<Tabs
|
||||||
</Box>
|
onChange={(e, tabValue) => {
|
||||||
|
setTabValue(tabValue)
|
||||||
|
refetchHistory(tabValue)
|
||||||
|
}}
|
||||||
|
value={tabValue}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: 'background.surface',
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TabList
|
||||||
|
disableUnderline
|
||||||
|
sx={{
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
p: 0.5,
|
||||||
|
gap: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
{ label: '7 Days', value: 7 },
|
||||||
|
{ label: '30 Days', value: 30 },
|
||||||
|
{ label: '90 Days', value: 90 },
|
||||||
|
{ label: 'All Time', value: 365 },
|
||||||
|
].map((tab, index) => (
|
||||||
|
<Tab
|
||||||
|
key={index}
|
||||||
|
sx={{
|
||||||
|
borderRadius: 6,
|
||||||
|
minWidth: 'auto',
|
||||||
|
px: 2,
|
||||||
|
py: 1,
|
||||||
|
fontSize: 'sm',
|
||||||
|
fontWeight: 500,
|
||||||
|
color: 'text.secondary',
|
||||||
|
'&.Mui-selected': {
|
||||||
|
color: 'primary.plainColor',
|
||||||
|
backgroundColor: 'primary.softBg',
|
||||||
|
fontWeight: 600,
|
||||||
|
},
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'neutral.softHoverBg',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
disableIndicator
|
||||||
|
value={tab.value}
|
||||||
|
>
|
||||||
|
{tab.label}
|
||||||
|
</Tab>
|
||||||
|
))}
|
||||||
|
</TabList>
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<ChoreHistoryTimeline history={selectedHistory} />
|
{/* Current Filter Summary */}
|
||||||
</Box>
|
<Box sx={{ mb: 3, textAlign: 'center' }}>
|
||||||
|
<Typography level='body-sm' sx={{ color: 'text.secondary' }}>
|
||||||
|
Showing activities for{' '}
|
||||||
|
<Typography
|
||||||
|
component='span'
|
||||||
|
sx={{ fontWeight: 600, color: 'primary.500' }}
|
||||||
|
>
|
||||||
|
{selectedUser === undefined || selectedUser === 'all'
|
||||||
|
? 'All Users'
|
||||||
|
: circleUsers.find(user => user.userId === selectedUser)
|
||||||
|
?.displayName || 'Unknown User'}
|
||||||
|
</Typography>{' '}
|
||||||
|
over the{' '}
|
||||||
|
<Typography
|
||||||
|
component='span'
|
||||||
|
sx={{ fontWeight: 600, color: 'primary.500' }}
|
||||||
|
>
|
||||||
|
{tabValue === 365 ? 'All Time' : `Last ${tabValue} Days`}
|
||||||
|
</Typography>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Right Sidebar - Charts (Mobile: Full width, Desktop: Fixed width + sticky) */}
|
{/* Conditional Content Based on Data Availability */}
|
||||||
<Box
|
{(!choresData.res?.length > 0 || !choresHistory?.length > 0) ? (
|
||||||
|
<Container
|
||||||
|
maxWidth='md'
|
||||||
sx={{
|
sx={{
|
||||||
width: { xs: '100%', lg: '350px' },
|
textAlign: 'center',
|
||||||
position: { xs: 'static', lg: 'sticky' },
|
display: 'flex',
|
||||||
top: { lg: '60px' },
|
alignItems: 'center',
|
||||||
alignSelf: { lg: 'flex-start' },
|
justifyContent: 'center',
|
||||||
maxHeight: { lg: 'calc(100vh - 40px)' },
|
flexDirection: 'column',
|
||||||
overflowY: { lg: 'auto' },
|
height: '50vh',
|
||||||
order: { xs: -1, lg: 1 }, // Show charts first on mobile, last on desktop
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Charts Container */}
|
<EventBusy
|
||||||
<Card
|
|
||||||
variant='plain'
|
|
||||||
sx={{
|
sx={{
|
||||||
p: 2,
|
fontSize: '6rem',
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
boxShadow: 'sm',
|
|
||||||
borderRadius: 20,
|
|
||||||
width: { xs: '100%', lg: '315px' },
|
|
||||||
mr: { xs: 0, lg: 10 },
|
|
||||||
mb: 1,
|
mb: 1,
|
||||||
}}
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Typography level='h3' gutterBottom>
|
||||||
|
No activities found
|
||||||
|
</Typography>
|
||||||
|
<Typography level='body1' sx={{ mb: 1 }}>
|
||||||
|
No activities found for{' '}
|
||||||
|
<Typography
|
||||||
|
component='span'
|
||||||
|
sx={{ fontWeight: 600, color: 'primary.500' }}
|
||||||
|
>
|
||||||
|
{selectedUser === undefined || selectedUser === 'all'
|
||||||
|
? 'All Users'
|
||||||
|
: circleUsers.find(user => user.userId === selectedUser)
|
||||||
|
?.displayName || 'Unknown User'}
|
||||||
|
</Typography>{' '}
|
||||||
|
in the{' '}
|
||||||
|
<Typography
|
||||||
|
component='span'
|
||||||
|
sx={{ fontWeight: 600, color: 'primary.500' }}
|
||||||
|
>
|
||||||
|
{tabValue === 365 ? 'All Time' : `Last ${tabValue} Days`}
|
||||||
|
</Typography>
|
||||||
|
.
|
||||||
|
</Typography>
|
||||||
|
<Typography level='body-sm' sx={{ color: 'text.secondary', mb: 2 }}>
|
||||||
|
Try selecting a different time period or user filter above.
|
||||||
|
</Typography>
|
||||||
|
<Button variant='soft' sx={{ mt: 2 }}>
|
||||||
|
<Link to='/chores'>Go back to chores</Link>
|
||||||
|
</Button>
|
||||||
|
</Container>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{/* Main Content Area - Mobile: Stack vertically, Desktop: Side by side */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', lg: 'row' },
|
||||||
|
gap: 3,
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Stack spacing={3}>
|
{/* Left Side - Timeline (Mobile: Full width, Desktop: Flexible) */}
|
||||||
{/* Main Chart */}
|
<Box sx={{ flex: 1, minWidth: 0, width: '100%' }}>
|
||||||
<Box
|
<ChoreHistoryTimeline history={selectedHistory} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Right Sidebar - Charts (Mobile: Full width, Desktop: Fixed width + sticky) */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: { xs: '100%', lg: '350px' },
|
||||||
|
position: { xs: 'static', lg: 'sticky' },
|
||||||
|
top: { lg: '60px' },
|
||||||
|
alignSelf: { lg: 'flex-start' },
|
||||||
|
maxHeight: { lg: 'calc(100vh - 40px)' },
|
||||||
|
overflowY: { lg: 'auto' },
|
||||||
|
order: { xs: -1, lg: 1 }, // Show charts first on mobile, last on desktop
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Charts Container */}
|
||||||
|
<Card
|
||||||
|
variant='plain'
|
||||||
sx={{
|
sx={{
|
||||||
|
p: 2,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'space-between',
|
||||||
textAlign: 'center',
|
boxShadow: 'sm',
|
||||||
minHeight: {
|
borderRadius: 20,
|
||||||
lg:
|
width: { xs: '100%', lg: '315px' },
|
||||||
chartData[selectedChart].data.length <= 3
|
mr: { xs: 0, lg: 10 },
|
||||||
? '350px'
|
mb: 1,
|
||||||
: '450px',
|
|
||||||
}, // Dynamic height based on legend needs
|
|
||||||
maxHeight: {
|
|
||||||
lg:
|
|
||||||
chartData[selectedChart].data.length <= 3
|
|
||||||
? '400px'
|
|
||||||
: '500px',
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography level='h4' textAlign='center' sx={{ mb: 1 }}>
|
<Stack spacing={3}>
|
||||||
{chartData[selectedChart].title}
|
{/* Main Chart */}
|
||||||
</Typography>
|
<Box
|
||||||
<Typography level='body-xs' textAlign='center' sx={{ mb: 2 }}>
|
sx={{
|
||||||
{chartData[selectedChart].description}
|
display: 'flex',
|
||||||
</Typography>
|
flexDirection: 'column',
|
||||||
<Box
|
alignItems: 'center',
|
||||||
sx={{
|
justifyContent: 'flex-start',
|
||||||
flex: 1,
|
textAlign: 'center',
|
||||||
display: 'flex',
|
minHeight: {
|
||||||
justifyContent: 'center',
|
lg:
|
||||||
alignItems: 'flex-start',
|
chartData[selectedChart].data.length <= 3
|
||||||
width: '100%',
|
? '350px'
|
||||||
}}
|
: '450px',
|
||||||
>
|
}, // Dynamic height based on legend needs
|
||||||
{renderPieChart(
|
maxHeight: {
|
||||||
chartData[selectedChart].data,
|
lg:
|
||||||
300, // Increased size for better chart container
|
chartData[selectedChart].data.length <= 3
|
||||||
true,
|
? '400px'
|
||||||
selectedChart,
|
: '500px',
|
||||||
)}
|
},
|
||||||
</Box>
|
}}
|
||||||
</Box>
|
>
|
||||||
|
<Typography level='h4' textAlign='center' sx={{ mb: 1 }}>
|
||||||
|
{chartData[selectedChart].title}
|
||||||
|
</Typography>
|
||||||
|
<Typography level='body-xs' textAlign='center' sx={{ mb: 2 }}>
|
||||||
|
{chartData[selectedChart].description}
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderPieChart(
|
||||||
|
chartData[selectedChart].data,
|
||||||
|
300, // Increased size for better chart container
|
||||||
|
true,
|
||||||
|
selectedChart,
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
{/* Chart Selection Grid */}
|
{/* Chart Selection Grid */}
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
{Object.entries(chartData)
|
{Object.entries(chartData)
|
||||||
.filter(([key]) => key !== selectedChart)
|
.filter(([key]) => key !== selectedChart)
|
||||||
.map(([key, { data, title }]) => (
|
.map(([key, { data, title }]) => (
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
key={key}
|
key={key}
|
||||||
xs={4}
|
xs={4}
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Card
|
|
||||||
onClick={() => setSelectedChart(key)}
|
|
||||||
variant='plain'
|
|
||||||
sx={{
|
|
||||||
cursor: 'pointer',
|
|
||||||
p: 1,
|
|
||||||
transition: 'all 0.2s ease-in-out',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
minHeight: 80,
|
|
||||||
maxWidth: 90,
|
|
||||||
'&:hover': {
|
|
||||||
transform: 'scale(1.02)',
|
|
||||||
boxShadow: 'sm',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
textAlign='center'
|
|
||||||
level='body-xs'
|
|
||||||
sx={{
|
|
||||||
mb: 0.5,
|
|
||||||
fontSize: '0.65rem',
|
|
||||||
lineHeight: 1.2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{renderPieChart(data, 70, false)}
|
<Card
|
||||||
</Box>
|
onClick={() => setSelectedChart(key)}
|
||||||
</Card>
|
variant='plain'
|
||||||
</Grid>
|
sx={{
|
||||||
))}
|
cursor: 'pointer',
|
||||||
</Grid>
|
p: 1,
|
||||||
</Box>
|
transition: 'all 0.2s ease-in-out',
|
||||||
</Stack>
|
display: 'flex',
|
||||||
</Card>
|
flexDirection: 'column',
|
||||||
</Box>
|
alignItems: 'center',
|
||||||
</Box>
|
justifyContent: 'center',
|
||||||
|
minHeight: 80,
|
||||||
|
maxWidth: 90,
|
||||||
|
'&:hover': {
|
||||||
|
transform: 'scale(1.02)',
|
||||||
|
boxShadow: 'sm',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
textAlign='center'
|
||||||
|
level='body-xs'
|
||||||
|
sx={{
|
||||||
|
mb: 0.5,
|
||||||
|
fontSize: '0.65rem',
|
||||||
|
lineHeight: 1.2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderPieChart(data, 70, false)}
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user