Skip to content

Commit

Permalink
feat: Style refine.
Browse files Browse the repository at this point in the history
- add AddItem for all three input field (goal, microgoal, task)
- Collapse for animation when expanding macro and micro goals.
- Add animation for progress indicator. Also font size and color changes.
- Add new style for task check box.
- Refine styles for better mobile device experience.
  • Loading branch information
ZL-Asica committed Oct 29, 2024
1 parent baef5a1 commit 1bc48f7
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 123 deletions.
38 changes: 38 additions & 0 deletions src/components/Home/AddItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import AddIcon from '@mui/icons-material/Add';
import { IconButton, InputAdornment, TextField } from '@mui/material';
import { useState } from 'react';

const AddItem = ({ label, onAdd }) => {
const [inputValue, setInputValue] = useState('');

const handleAdd = async () => {
if (inputValue.trim()) {
await onAdd(inputValue);
setInputValue('');
}
};

return (
<TextField
variant="outlined"
label={label}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
fullWidth
onKeyDown={(e) => e.key === 'Enter' && handleAdd()}
slotProps={{
input: {
endAdornment: (
<InputAdornment position="end">
<IconButton color="primary" onClick={handleAdd} disabled={!inputValue.trim()}>
<AddIcon />
</IconButton>
</InputAdornment>
),
},
}}
/>
);
};

export default AddItem;
28 changes: 5 additions & 23 deletions src/components/Home/GoalTracker.jsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
import AddItem from '@components/Home/AddItem';
import MacroGoal from '@components/Home/MacroGoal';
import { useUser } from '@contexts/UserContext';
import useGoalsUpdater from '@hooks/useGoalsUpdater';
import { Box, Button, TextField } from '@mui/material';
import { useState } from 'react';
import { Box } from '@mui/material';

export default function GoalTracker() {
const { user } = useUser();
const { addGoal } = useGoalsUpdater();
const [newGoalName, setNewGoalName] = useState('');

const handleAddGoal = async () => {
if (newGoalName.trim()) {
await addGoal(newGoalName);
setNewGoalName('');
}
};

return (
<Box sx={{ maxWidth: 800, margin: 'auto', pt: 4 }}>
<Box display="flex" mb={3}>
<TextField
variant="outlined"
label="New Goal"
value={newGoalName}
onChange={(e) => setNewGoalName(e.target.value)}
fullWidth
/>
<Button variant="contained" onClick={handleAddGoal} sx={{ ml: 2 }}>
Add Goal
</Button>
</Box>
<Box sx={{ maxWidth: 800, margin: 'auto', padding: 2 }}>
<AddItem label="New Goal" onAdd={addGoal} />
<Box sx={{ height: 16 }} />
{user.goals.map((macroGoal, index) => (
<MacroGoal key={index} macroGoal={macroGoal} macroGoalIndex={index} />
))}
Expand Down
78 changes: 23 additions & 55 deletions src/components/Home/MacroGoal.jsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,43 @@
import AddItem from '@components/Home/AddItem';
import MicroGoal from '@components/Home/MicroGoal';
import ProgressIndicator from '@components/Home/ProgressIndicator';
import useGoalsUpdater from '@hooks/useGoalsUpdater';
import { ExpandLess, ExpandMore } from '@mui/icons-material';
import {
Box,
Button,
Divider,
IconButton,
List,
Paper,
TextField,
Typography,
} from '@mui/material';
import { Box, Collapse, Divider, IconButton, List, Paper, Typography } from '@mui/material';
import { calculateProgress } from '@utils/calculateProgress';
import { useState } from 'react';

const MacroGoal = ({ macroGoal, macroGoalIndex }) => {
const { addMicrogoal, toggleGoalExpansion } = useGoalsUpdater();
const [newMicroGoalName, setNewMicroGoalName] = useState('');
const progress = calculateProgress(macroGoal.microgoals);

const handleAddMicroGoal = async () => {
if (newMicroGoalName.trim()) {
await addMicrogoal(macroGoalIndex, newMicroGoalName);
setNewMicroGoalName('');
}
};

return (
<Paper elevation={3} sx={{ p: 3, mb: 4, bgcolor: 'background.paper' }}>
<Box display="flex" alignItems="center" mb={2}>
<ProgressIndicator value={progress} size={48} thickness={4} />
<Typography variant="h5" sx={{ fontWeight: 'bold' }}>
<Paper elevation={2} sx={{ p: 2, mb: 3, borderRadius: 2 }}>
<Box display="flex" alignItems="center">
<ProgressIndicator value={progress} size={40} thickness={3} />
<Typography variant="h6" sx={{ flexGrow: 1, ml: 2 }}>
{macroGoal.name}
</Typography>
<IconButton
onClick={() => toggleGoalExpansion(macroGoalIndex)}
size="small"
sx={{ ml: 'auto' }}
>
<IconButton onClick={() => toggleGoalExpansion(macroGoalIndex)} size="small">
{macroGoal.expanded ? <ExpandLess /> : <ExpandMore />}
</IconButton>
</Box>
{macroGoal.expanded && (
<>
<Divider sx={{ mb: 2 }} />
<Box display="flex" mb={2}>
<TextField
variant="outlined"
label="New Microgoal"
value={newMicroGoalName}
onChange={(e) => setNewMicroGoalName(e.target.value)}
fullWidth
sx={{ mr: 1 }}
<Collapse in={macroGoal.expanded} timeout="auto" unmountOnExit>
<Divider sx={{ my: 1 }} />
<AddItem
label="New Microgoal"
onAdd={(microGoalName) => addMicrogoal(macroGoalIndex, microGoalName)}
/>
<List>
{macroGoal.microgoals.map((microGoal, microGoalIndex) => (
<MicroGoal
key={microGoalIndex}
microGoal={microGoal}
macroGoalIndex={macroGoalIndex}
microGoalIndex={microGoalIndex}
/>
<Button variant="contained" onClick={handleAddMicroGoal}>
Add Microgoal
</Button>
</Box>
<List sx={{ pl: 2 }}>
{macroGoal.microgoals.map((microGoal, microGoalIndex) => (
<MicroGoal
key={microGoalIndex}
microGoal={microGoal}
macroGoalIndex={macroGoalIndex}
microGoalIndex={microGoalIndex}
/>
))}
</List>
</>
)}
))}
</List>
</Collapse>
</Paper>
);
};
Expand Down
59 changes: 21 additions & 38 deletions src/components/Home/MicroGoal.jsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,44 @@
import AddItem from '@components/Home/AddItem';
import ProgressIndicator from '@components/Home/ProgressIndicator';
import Task from '@components/Home/Task';
import useGoalsUpdater from '@hooks/useGoalsUpdater';
import { ExpandLess, ExpandMore } from '@mui/icons-material';
import { Box, Button, IconButton, List, Paper, TextField, Typography } from '@mui/material';
import { Box, Collapse, IconButton, List, Paper, Typography } from '@mui/material';
import { calculateProgress } from '@utils/calculateProgress';
import { useState } from 'react';

const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => {
const { addTask, toggleMicroGoalExpansion, toggleTaskCompletion } = useGoalsUpdater();
const progress = calculateProgress([microGoal]);
const [newTaskName, setNewTaskName] = useState('');

const handleAddTask = async () => {
if (newTaskName.trim()) {
await addTask(macroGoalIndex, microGoalIndex, newTaskName);
setNewTaskName('');
}
};

return (
<Paper elevation={2} sx={{ p: 2, mb: 2, bgcolor: 'background.default' }}>
<Paper elevation={1} sx={{ p: 1, mb: 2, bgcolor: 'background.default', borderRadius: 1 }}>
<Box display="flex" alignItems="center">
<ProgressIndicator value={progress} size={32} thickness={3} />
<Typography variant="subtitle1">{microGoal.name}</Typography>
<ProgressIndicator value={progress} size={30} thickness={3} />
<Typography variant="subtitle1" sx={{ flexGrow: 1, ml: 1 }}>
{microGoal.name}
</Typography>
<IconButton
onClick={() => toggleMicroGoalExpansion(macroGoalIndex, microGoalIndex)}
size="small"
sx={{ ml: 'auto' }}
>
{microGoal.expanded ? <ExpandLess /> : <ExpandMore />}
</IconButton>
</Box>
{microGoal.expanded && (
<>
<List sx={{ mt: 1, pl: 4 }}>
{microGoal.tasks.map((task, taskIndex) => (
<Task
key={taskIndex}
task={task}
onToggle={() => toggleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex)}
/>
))}
</List>
<Box display="flex" mt={2}>
<TextField
variant="outlined"
label="New Task"
value={newTaskName}
onChange={(e) => setNewTaskName(e.target.value)}
fullWidth
<Collapse in={microGoal.expanded} timeout="auto" unmountOnExit>
<List sx={{ pl: 2 }}>
{microGoal.tasks.map((task, taskIndex) => (
<Task
key={taskIndex}
task={task}
onToggle={() => toggleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex)}
/>
<Button variant="contained" onClick={handleAddTask} sx={{ ml: 1 }}>
Add Task
</Button>
</Box>
</>
)}
))}
</List>
<AddItem
label="New Task"
onAdd={(taskName) => addTask(macroGoalIndex, microGoalIndex, taskName)}
/>
</Collapse>
</Paper>
);
};
Expand Down
26 changes: 23 additions & 3 deletions src/components/Home/ProgressIndicator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,40 @@ import { Box, CircularProgress, Typography } from '@mui/material';

const ProgressIndicator = ({ value, size = 40, thickness = 4 }) => (
<Box sx={{ position: 'relative', display: 'inline-flex', mr: 2 }}>
<CircularProgress variant="determinate" value={value} size={size} thickness={thickness} />
<CircularProgress
variant="determinate"
value={value}
size={size}
thickness={thickness}
sx={{
color: (theme) =>
value >= 100
? theme.palette.success.main
: `linear-gradient(to right, ${theme.palette.info.main}, ${theme.palette.warning.main})`,
transition: 'all 0.4s ease-in-out', // Smooth transition effect
}}
/>
<Box
sx={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Typography variant="caption" component="div" color="text.secondary">
<Typography
variant="caption"
component="div"
color={value >= 100 ? 'success.main' : 'text.secondary'}
sx={{
fontWeight: value >= 100 ? 'bold' : 'normal',
fontSize: value >= 100 ? '0.75rem' : 'inherit',
}}
>
{`${Math.round(value)}%`}
</Typography>
</Box>
Expand Down
31 changes: 28 additions & 3 deletions src/components/Home/Task.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
import { Checkbox, ListItem, ListItemText } from '@mui/material';

const Task = ({ task, onToggle }) => (
<ListItem dense>
<Checkbox edge="start" checked={task.completed} onChange={onToggle} />
<ListItemText primary={task.name} />
<ListItem
dense
sx={{
display: 'flex',
alignItems: 'center',
padding: 1,
bgcolor: task.completed ? 'action.hover' : 'background.paper',
borderRadius: 1,
mb: 1,
'&:hover': { bgcolor: 'action.hover' },
}}
>
<Checkbox
edge="start"
checked={task.completed}
onChange={onToggle}
size="medium"
sx={{ '& .MuiSvgIcon-root': { fontSize: 28 } }} // Enlarge the checkbox icon
/>
<ListItemText
primary={task.name}
primaryTypographyProps={{
sx: {
textDecoration: task.completed ? 'line-through' : 'none',
color: task.completed ? 'text.disabled' : 'text.primary',
},
}}
/>
</ListItem>
);

Expand Down
2 changes: 1 addition & 1 deletion src/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box } from '@mui/material';

const Home = () => {
return (
<Box sx={{ width: '90%', margin: 'auto' }}>
<Box sx={{ width: '95%', margin: 'auto' }}>
<GoalTracker />
</Box>
);
Expand Down

0 comments on commit 1bc48f7

Please sign in to comment.