Skip to content

Commit

Permalink
feat(updateGoal): Enable update goal name and/or category after set (#29
Browse files Browse the repository at this point in the history
)

- **Added edit goal functionality**: Integrated an `Edit Goal` mode
within the `GoalDetails` page, allowing users to update the goal name
and category color directly from the goal header.

- **UI adjustments**:
- Added a dedicated `Edit` button to toggle the edit mode for the goal.
- Added hover color changes using `darken` for the `Edit` button,
providing visual feedback and aligning with the goal's theme color.
- Used `presetValue` and `presetCategory` props in the `AddItem`
component to prefill goal details during editing.

- **Code structure improvements**:
- Add the `updateGoal` function to update specific goal name and/or
category.
- Used `Collapse` to smoothly show/hide the `Edit Goal` input field on
toggle.

---------

Co-authored-by: ZL Asica <[email protected]>
  • Loading branch information
marycaserio and ZL-Asica authored Nov 8, 2024
1 parent 8599dcf commit 757341a
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 15 deletions.
29 changes: 22 additions & 7 deletions src/components/Home/AddItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,33 @@
import CategoryPicker from '@/components/Home/CategoryPicker'
import { DateTimePicker } from '@/components/Home/DateTimePickers'
import AddIcon from '@mui/icons-material/Add'
import CheckIcon from '@mui/icons-material/Check'
import { IconButton, InputAdornment, TextField } from '@mui/material'
import { useState } from 'react'
import { useEffect, useState } from 'react'

const AddItem = ({ label, onAdd }) => {
const [inputValue, setInputValue] = useState('')
const [selectedCategory, setSelectedCategory] = useState('#000000') // For 'New Goal'
const AddItem = ({
label,
onAdd,
presetValue = '',
presetCategory = '#000000',
sx = {},
}) => {
const [inputValue, setInputValue] = useState(presetValue)
const [selectedCategory, setSelectedCategory] = useState(presetCategory) // For 'New Goal'
const [dueDate, setDueDate] = useState(null) // For 'New Task'

useEffect(() => {
if (presetValue) {
setInputValue(presetValue)
setSelectedCategory(presetCategory)
}
}, [presetValue, presetCategory])

const handleAdd = async () => {
if (inputValue.trim()) {
let attributes = null

if (label === 'New Goal') {
if (label === 'New Goal' || label === 'Edit Goal') {
attributes = selectedCategory
} else if (label === 'New Task') {
attributes = dueDate
Expand All @@ -30,7 +44,7 @@ const AddItem = ({ label, onAdd }) => {

// Conditionally render the category picker
const getStartAdornment = () => {
if (label === 'New Goal') {
if (label === 'New Goal' || label === 'Edit Goal') {
return (
<CategoryPicker
selectedCategory={selectedCategory}
Expand All @@ -49,6 +63,7 @@ const AddItem = ({ label, onAdd }) => {
display: 'flex',
alignItems: 'center',
gap: 2,
...sx,
}}
variant='outlined'
label={label}
Expand All @@ -67,7 +82,7 @@ const AddItem = ({ label, onAdd }) => {
onClick={handleAdd}
disabled={!inputValue.trim()}
>
<AddIcon />
{label === 'Edit Goal' ? <CheckIcon /> : <AddIcon />}
</IconButton>
</InputAdornment>
),
Expand Down
15 changes: 15 additions & 0 deletions src/hooks/useGoalsUpdater/addOperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,18 @@ export const addTask = async (
'Task added successfully.'
)
}

export const updateGoal = async (userContext, goalIndex, name, category) => {
const updatedGoals = [...userContext.user.goals]
updatedGoals[goalIndex] = {
...updatedGoals[goalIndex],
name,
category,
}

await updateGoalsAndStreak(
userContext,
updatedGoals,
'Goal category updated successfully.'
)
}
16 changes: 13 additions & 3 deletions src/hooks/useGoalsUpdater/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-check

import { useUser } from '@/contexts/UserContext'
import { addGoal, addMicrogoal, addTask } from './addOperations'
import { addGoal, addMicrogoal, addTask, updateGoal } from './addOperations'
import { deleteItem } from './deleteOperations'
import { toggleExpansion, toggleTaskCompletion } from './toggleOperations'

Expand All @@ -20,7 +20,7 @@ const useGoalsUpdater = () => {

/**
* Adds a new microgoal under a specified goal.
* @param {number} goalIndex - Index of the goal to add the microgoal to.
* @param {string} goalIndex - Index of the goal to add the microgoal to.
* @param {string} microGoalName - Name of the microgoal.
* @returns {Promise<void>}
*/
Expand All @@ -29,7 +29,7 @@ const useGoalsUpdater = () => {

/**
* Adds a new task under a specified microgoal.
* @param {number} goalIndex - Index of the goal.
* @param {string} goalIndex - Index of the goal.
* @param {number} microGoalIndex - Index of the microgoal.
* @param {string} taskName - Name of the task.
* @param {Date} dueDate - Due date for the task.
Expand All @@ -38,6 +38,16 @@ const useGoalsUpdater = () => {
addTask: (goalIndex, microGoalIndex, taskName, dueDate) =>
addTask(userContext, goalIndex, microGoalIndex, taskName, dueDate),

/**
* Updates the category color for a specified goal.
* @param {string} goalIndex - Index of the goal.
* @param {string} name - New name for the goal.
* @param {string} category - New category color for the goal.
* @returns {Promise<void>}
*/
updateGoal: (goalIndex, name, category) =>
updateGoal(userContext, goalIndex, name, category),

/**
* Deletes a specified goal, microgoal, or task.
* @param {{ goalIndex: number, microGoalIndex?: number, taskIndex?: number }} indices - Indices of items to delete.
Expand Down
50 changes: 45 additions & 5 deletions src/pages/GoalDetails.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
// @ts-check

import AddItem from '@/components/Home/AddItem'
import MicroGoal from '@/components/Home/MicroGoal'
import ProgressIndicator from '@/components/Home/ProgressIndicator'
import { useUser } from '@/contexts/UserContext'
import useGoalsUpdater from '@/hooks/useGoalsUpdater'
import { calculateProgress } from '@/utils/calculateProgress'
import { Box, List, Paper, Typography } from '@mui/material'
import EditIcon from '@mui/icons-material/Edit'
import {
Box,
Collapse,
darken,
IconButton,
List,
Paper,
Typography,
} from '@mui/material'
import { useState } from 'react'
import { useParams } from 'react-router-dom'

const GoalDetails = () => {
const [editGoalInput, setEditGoalInput] = useState(false)
const { macroGoalIndex } = useParams()
const { user } = useUser()
const { addMicrogoal } = useGoalsUpdater()
const { addMicrogoal, updateGoal } = useGoalsUpdater()

const macroGoal = user.goals[macroGoalIndex]
const categoryColor = macroGoal.category || '#000'

// @ts-ignore
const progress = calculateProgress(macroGoal.microgoals)

return (
Expand All @@ -24,15 +40,38 @@ const GoalDetails = () => {
mb: 3,
borderRadius: 2,
border: '2px solid',
borderColor: macroGoal.category ? macroGoal.category : '#000',
borderColor: categoryColor,
}}
>
<Box display='flex' alignItems='center'>
<Box
display='flex'
alignItems='center'
onClick={() => setEditGoalInput(!editGoalInput)} // Click to edit goal name
>
<ProgressIndicator value={progress} size={50} thickness={4} />
<Typography variant='h5' sx={{ ml: 2 }}>
<Typography variant='h5' sx={{ ml: 2, flexGrow: 1 }}>
{macroGoal.name}
</Typography>
<IconButton
aria-label='Edit Goal'
onClick={() => setEditGoalInput(!editGoalInput)}
sx={{ color: darken(categoryColor, 0.3) }}
>
<EditIcon />
</IconButton>
</Box>
<Collapse in={editGoalInput} timeout='auto' unmountOnExit>
<AddItem
label='Edit Goal'
onAdd={(name, category) => {
updateGoal(macroGoalIndex, name, category)
setEditGoalInput(false)
}}
presetValue={macroGoal.name}
presetCategory={categoryColor}
sx={{ mt: 2 }}
/>
</Collapse>
</Paper>

<AddItem
Expand All @@ -41,6 +80,7 @@ const GoalDetails = () => {
/>

<List sx={{ mt: 3 }}>
{/* @ts-ignore */}
{macroGoal.microgoals.map((microGoal, microGoalIndex) => (
<MicroGoal
key={microGoalIndex}
Expand Down

0 comments on commit 757341a

Please sign in to comment.