Update styling for NavBar and ThingsView components

This commit is contained in:
Mo Tarbin 2025-02-02 01:27:37 -05:00
parent a57def2f92
commit 568f86acd0
4 changed files with 230 additions and 187 deletions

View file

@ -11,12 +11,12 @@ import {
PeopleAlt, PeopleAlt,
Person, Person,
SwitchAccessShortcut, SwitchAccessShortcut,
Timelapse,
} from '@mui/icons-material' } from '@mui/icons-material'
import { import {
Box, Box,
Button, Button,
Card, Card,
CardContent,
Checkbox, Checkbox,
Chip, Chip,
Container, Container,
@ -25,8 +25,6 @@ import {
Grid, Grid,
IconButton, IconButton,
Input, Input,
ListItem,
ListItemContent,
Menu, Menu,
MenuButton, MenuButton,
MenuItem, MenuItem,
@ -121,62 +119,43 @@ const ChoreView = () => {
{ {
size: 6, size: 6,
icon: <PeopleAlt />, icon: <PeopleAlt />,
text: 'Assigned To', title: 'Assignment',
subtext: performers.find(p => p.id === chore.assignedTo)?.displayName, text: `Assigned: ${
performers.find(p => p.id === chore.assignedTo)?.displayName || 'N/A'
}`,
subtext: ` Last: ${
chore.lastCompletedDate
? performers.find(p => p.id === chore.lastCompletedBy)?.displayName
: '--'
}`,
}, },
{ {
size: 6, size: 6,
icon: <CalendarMonth />, icon: <CalendarMonth />,
text: 'Due Date', title: 'Schedule',
subtext: chore.nextDueDate text: `Due: ${
? moment(chore.nextDueDate).fromNow() chore.nextDueDate ? moment(chore.nextDueDate).fromNow() : 'N/A'
: 'N/A', }`,
subtext: `Last: ${
chore.lastCompletedDate
? moment(chore.lastCompletedDate).fromNow()
: 'N/A'
}`,
}, },
// {
// icon: <TextFields />,
// text: 'Frequency',
// subtext:
// chore.frequencyType.charAt(0).toUpperCase() +
// chore.frequencyType.slice(1),
// },
{ {
size: 6, size: 6,
icon: <Checklist />, icon: <Checklist />,
text: 'Total Completed', title: 'Statistics',
subtext: `${chore.totalCompletedCount} times`, text: `Completed: ${chore.totalCompletedCount || 0} times`,
},
{
size: 6,
icon: <Timelapse />,
text: 'Last Completed',
subtext:
// chore.lastCompletedDate &&
// moment(chore.lastCompletedDate).format('MM/DD/YYYY hh:mm A'),
chore.lastCompletedDate && moment(chore.lastCompletedDate).fromNow(),
}, },
{ {
size: 6, size: 6,
icon: <Person />, icon: <Person />,
text: 'Last Performer', title: 'Details',
subtext: chore.lastCompletedDate subtext: `Created By: ${
? `${ performers.find(p => p.id === chore.createdBy)?.displayName || 'N/A'
performers.find(p => p.id === chore.lastCompletedBy)?.displayName }`,
}`
: '--',
}, },
{
size: 6,
icon: <Person />,
text: 'Created By',
subtext: performers.find(p => p.id === chore.createdBy)?.displayName,
},
// {
// size: 12,
// icon: <Note />,
// text: 'Recent Note',
// subtext: chore.notes || '--',
// },
] ]
setInfoCards(cards) setInfoCards(cards)
} }
@ -287,38 +266,70 @@ const ChoreView = () => {
</Chip> </Chip>
))} ))}
</Box> </Box>
<Box> <Box>
<Sheet <Grid
container
spacing={1}
sx={{ sx={{
mb: 1, mb: 1,
borderRadius: 'lg',
p: 2,
}} }}
variant='outlined'
> >
<Grid container spacing={1}> {infoCards.map((card, index) => (
{infoCards.map((detail, index) => ( <Grid item xs={6} sm={6} key={index}>
<Grid item xs={6} key={index}> <Card
{/* divider between the list items: */} variant='soft'
sx={{
borderRadius: 'md',
boxShadow: 1,
px: 2,
py: 1,
minHeight: 90,
// change from space-between to start:
justifyContent: 'start',
}}
>
<CardContent>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'start',
mb: 0.5,
}}
>
{card.icon}
<ListItem key={index}> <Typography
<ListItemContent> level='body-md'
<Typography level='body-xs' sx={{ fontWeight: 'md' }}> sx={{
{detail.text} ml: 1,
</Typography> fontWeight: '500',
<Chip color: 'text.primary',
color='primary' }}
size='md'
startDecorator={detail.icon}
> >
{detail.subtext ? detail.subtext : '--'} {card.title}
</Chip> </Typography>
</ListItemContent> </Box>
</ListItem> <Box>
</Grid> <Typography
))} level='body-sm'
</Grid> sx={{ color: 'text.secondary', lineHeight: 1.5 }}
</Sheet> >
{card.text}
</Typography>
<Typography
level='body-sm'
sx={{ color: 'text.secondary', lineHeight: 1.5 }}
>
{card.subtext}
</Typography>
</Box>
</CardContent>
</Card>
</Grid>
))}
</Grid>
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@ -345,6 +356,7 @@ const ChoreView = () => {
p: 1, p: 1,
}} }}
fullWidth fullWidth
variant='plain'
> >
{chorePriority ? chorePriority.icon : <LowPriority />} {chorePriority ? chorePriority.icon : <LowPriority />}
{chorePriority ? chorePriority.name : 'No Priority'} {chorePriority ? chorePriority.name : 'No Priority'}
@ -388,7 +400,7 @@ const ChoreView = () => {
<Button <Button
size='sm' size='sm'
color='neutral' color='neutral'
variant='outlined' variant='plain'
fullWidth fullWidth
onClick={() => { onClick={() => {
navigate(`/chores/${choreId}/history`) navigate(`/chores/${choreId}/history`)
@ -406,7 +418,7 @@ const ChoreView = () => {
<Button <Button
size='sm' size='sm'
color='neutral' color='neutral'
variant='outlined' variant='plain'
fullWidth fullWidth
sx={{ sx={{
// top right of the card: // top right of the card:
@ -431,7 +443,7 @@ const ChoreView = () => {
</Typography> </Typography>
<Sheet <Sheet
variant='outlined' variant='plain'
sx={{ sx={{
p: 2, p: 2,
borderRadius: 'lg', borderRadius: 'lg',
@ -471,7 +483,7 @@ const ChoreView = () => {
<Typography level='title-md' sx={{ mb: 1 }}> <Typography level='title-md' sx={{ mb: 1 }}>
Previous note: Previous note:
</Typography> </Typography>
<Sheet variant='outlined' sx={{ p: 2, borderRadius: 'lg' }}> <Sheet variant='plain' sx={{ p: 2, borderRadius: 'lg' }}>
<Typography level='body-md' sx={{ mb: 1 }}> <Typography level='body-md' sx={{ mb: 1 }}>
{chore.notes || '--'} {chore.notes || '--'}
</Typography> </Typography>
@ -479,11 +491,6 @@ const ChoreView = () => {
</> </>
)} )}
</Box> </Box>
{/* <Divider
sx={{
my: 2,
}}
/> */}
<Card <Card
sx={{ sx={{
@ -492,6 +499,7 @@ const ChoreView = () => {
boxShadow: 'sm', boxShadow: 'sm',
mt: 2, mt: 2,
}} }}
variant='soft'
> >
<Typography level='body-md' sx={{ mb: 1 }}> <Typography level='body-md' sx={{ mb: 1 }}>
Complete the task Complete the task
@ -511,16 +519,10 @@ const ChoreView = () => {
} }
}} }}
overlay overlay
sx={
{
// my: 1,
}
}
label={ label={
<Typography <Typography
level='body-sm' level='body-sm'
sx={{ sx={{
// center vertically
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
}} }}

View file

@ -13,6 +13,14 @@ import {
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 {
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts'
import { GetThingHistory } from '../../utils/Fetcher' import { GetThingHistory } from '../../utils/Fetcher'
const ThingsHistory = () => { const ThingsHistory = () => {
@ -67,7 +75,7 @@ const ThingsHistory = () => {
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}` return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
} }
if (errLoading || !thingsHistory) { if (errLoading || !thingsHistory || thingsHistory.length === 0) {
return ( return (
<Container <Container
maxWidth='md' maxWidth='md'
@ -107,6 +115,60 @@ const ThingsHistory = () => {
<Typography level='h3' mb={1.5}> <Typography level='h3' mb={1.5}>
History: History:
</Typography> </Typography>
{/* check if all the states are number the show it: */}
{thingsHistory.every(history => !isNaN(history.state)) &&
thingsHistory.length > 1 && (
<>
<Typography level='h4' gutterBottom>
Chart:
</Typography>
<Box sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md', mb: 2 }}>
<ResponsiveContainer width='100%' height={200}>
<LineChart
width={500}
height={300}
data={thingsHistory.toReversed()}
>
{/* <CartesianGrid strokeDasharray='3 3' /> */}
<XAxis
dataKey='updatedAt'
hide='true'
tick='false'
tickLine='false'
axisLine='false'
tickFormatter={tick =>
moment(tick).format('ddd MM/DD/yyyy HH:mm:ss')
}
/>
<YAxis
hide='true'
dataKey='state'
tick='false'
tickLine='true'
axisLine='false'
/>
<Tooltip
labelFormatter={label =>
moment(label).format('ddd MM/DD/yyyy HH:mm:ss')
}
/>
<Line
type='monotone'
dataKey='state'
stroke='#8884d8'
activeDot={{ r: 8 }}
dot={{ r: 4 }}
/>
</LineChart>
</ResponsiveContainer>
</Box>
</>
)}
<Typography level='h4' gutterBottom>
Change log:
</Typography>
<Box sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md' }}> <Box sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
<List sx={{ p: 0 }}> <List sx={{ p: 0 }}>
{thingsHistory.map((history, index) => ( {thingsHistory.map((history, index) => (

View file

@ -10,9 +10,8 @@ import {
} from '@mui/icons-material' } from '@mui/icons-material'
import { import {
Box, Box,
Card, Button,
Chip, Chip,
CircularProgress,
Container, Container,
Grid, Grid,
IconButton, IconButton,
@ -63,122 +62,102 @@ const ThingCard = ({
} }
return ( return (
<Card <Box
variant='plain' className='rounded-lg border border-zinc-200/80 p-4 shadow-sm'
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'space-between', justifyContent: 'space-between',
p: 2, p: 2,
boxShadow: 'sm',
borderRadius: 20,
mb: 2, mb: 2,
}} }}
> >
<Grid container> <Grid container alignItems='center'>
<Grid item xs={9}> <Grid
item
xs={12}
sm={8}
onClick={() => Navigate(`/things/${thing?.id}`)}
>
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center',
gap: 1, gap: 1,
cursor: 'pointer',
}} }}
onClick={() => { onClick={() => Navigate(`/things/${thing?.id}`)}
Navigate(`/things/${thing?.id}`)
}}
> >
<Typography level='title-lg' component='h2'> <Typography level='title-lg'>{thing?.name}</Typography>
{thing?.name} <Chip
</Typography> size='sm'
<Chip level='body-md' component='p'> sx={{
ml: 1,
}}
>
{thing?.type} {thing?.type}
</Chip> </Chip>
</Box> </Box>
<Box> State: <Chip size='md'>{thing?.state}</Chip>
<Typography level='body-sm' component='p'>
Current state:
<Chip level='title-md' component='span' size='sm'>
{thing?.state}
</Chip>
</Typography>
</Box>
</Grid> </Grid>
<Grid item xs={3}> <Grid
<Box display='flex' justifyContent='flex-end' alignItems='flex-end'> item
{/* <ButtonGroup> */} xs={12}
<div className='relative grid place-items-center'> sm={4}
<IconButton container
variant='solid' justifyContent='flex-end'
color='success' alignItems='center'
onClick={() => { >
handleRequestChange(thing) <Button
}} variant='soft'
sx={{ color='success'
borderRadius: '50%', onClick={() => {
width: 50, if (thing?.type === 'text') {
minWidth: 50,
height: 50,
zIndex: 1,
}}
disabled={isDisabled}
>
{getThingIcon(thing?.type)}
</IconButton>
{isDisabled && (
<CircularProgress
variant='solid'
color='success'
size='md'
sx={{
color: 'success.main',
position: 'absolute',
'--CircularProgress-size': '55px',
zIndex: 0,
}}
/>
)}
</div>
<IconButton
// sx={{ width: 15 }}
variant='soft'
color='success'
onClick={() => {
onEditClick(thing) onEditClick(thing)
}} } else {
sx={{ handleRequestChange(thing)
borderRadius: '50%', }
width: 25, }}
height: 25, disabled={isDisabled}
position: 'relative', startDecorator={getThingIcon(thing?.type)}
left: -10, >
}} {thing?.type === 'text'
> ? 'Change'
<Edit /> : thing?.type === 'number'
</IconButton> ? 'Increment'
{/* add delete icon: */} : 'Toggle'}
<IconButton </Button>
// sx={{ width: 15 }} <IconButton
color='primary'
color='danger' onClick={() => onEditClick(thing)}
variant='soft' sx={{
onClick={() => { borderRadius: '50%',
onDeleteClick(thing) width: 30,
}} height: 30,
sx={{ ml: 1,
borderRadius: '50%', transition: 'background-color 0.2s',
width: 25, '&:hover': { backgroundColor: 'action.hover' },
height: 25, }}
position: 'relative', >
left: -10, <Edit />
}} </IconButton>
> <IconButton
<Delete /> color='danger'
</IconButton> onClick={() => onDeleteClick(thing)}
</Box> sx={{
borderRadius: '50%',
width: 30,
height: 30,
ml: 1,
}}
>
<Delete fontSize='small' />
</IconButton>
</Grid> </Grid>
</Grid> </Grid>
</Card> </Box>
) )
} }

View file

@ -105,22 +105,22 @@ const NavBar = () => {
} }
return ( return (
<nav className='flex gap-2 p-3'> <nav className='flex gap-2 p-2'>
<IconButton size='sm' variant='plain' onClick={() => setDrawerOpen(true)}> <IconButton size='sm' variant='plain' onClick={() => setDrawerOpen(true)}>
<MenuRounded /> <MenuRounded />
</IconButton> </IconButton>
<Box <Box
className='flex items-center gap-2' className='flex items-center gap-1'
onClick={() => { onClick={() => {
navigate('/my/chores') navigate('/my/chores')
}} }}
> >
<img component='img' src={Logo} width='34' /> <img component='img' src={Logo} width='25' />
<Typography <Typography
level='title-lg' level='title-lg'
sx={{ sx={{
fontWeight: 700, fontWeight: 700,
fontSize: 24, fontSize: 20,
}} }}
> >
Done Done