From 0253b30d3957b8df3fc2ccfa8f2003c02e5a99cd Mon Sep 17 00:00:00 2001 From: Alex Phillips Date: Wed, 9 Feb 2022 20:22:36 -0500 Subject: [PATCH] ui overhaul --- frontend/src/App.js | 15 +- frontend/src/components/AccountDetails.js | 116 +++---- .../components/AccountTable/AccountTable.js | 21 +- .../AccountTable/BalanceCalculation.js | 115 +++++++ frontend/src/components/BudgetDetails.js | 270 ++++++---------- .../src/components/BudgetMonthNavigator.js | 139 +++++++++ .../BudgetTable/BudgetMonthCalculation.js | 122 ++++++++ .../src/components/BudgetTable/BudgetTable.js | 14 +- .../src/components/CategoryMonthActivity.js | 112 +++++++ frontend/src/components/Drawer.js | 288 ++++++++++++------ frontend/src/pages/Account.js | 34 ++- frontend/src/pages/Budget.js | 49 +-- frontend/src/redux/slices/App.js | 2 +- frontend/src/redux/slices/Categories.js | 10 +- 14 files changed, 908 insertions(+), 399 deletions(-) create mode 100644 frontend/src/components/AccountTable/BalanceCalculation.js create mode 100644 frontend/src/components/BudgetMonthNavigator.js create mode 100644 frontend/src/components/BudgetTable/BudgetMonthCalculation.js create mode 100644 frontend/src/components/CategoryMonthActivity.js diff --git a/frontend/src/App.js b/frontend/src/App.js index 2f44159..2dca27b 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -79,19 +79,19 @@ export default function App(props) { palette: { mode: 'light', background: { - drawer: '#333333', + drawer: '#3a3f51', header: '#536067', tableBody: '#ffffff', - tableHeader: '#333333', - details: '#333333', - detailsContent: '#333333', + tableHeader: '#3a3f51', + details: '#3a3f51', + detailsContent: '#3a3f51', }, action: { // disabledBackground: 'set color of background here', // disabled: '#616161', }, primary: { - main: '#333333', + main: '#3a3f51', }, secondary: { main: '#ffffff', @@ -110,7 +110,7 @@ export default function App(props) { MuiDrawer: { styleOverrides: { paper: { - backgroundColor: '#333333', + backgroundColor: '#3a3f51', color: 'white', }, }, @@ -140,7 +140,7 @@ export default function App(props) { return (
- + {!initComplete && } {initComplete && ( @@ -148,6 +148,7 @@ export default function App(props) { {/*
*/} setNewAccountDialogOpen(true)} /> + diff --git a/frontend/src/components/AccountDetails.js b/frontend/src/components/AccountDetails.js index d5f3e39..c7405ae 100644 --- a/frontend/src/components/AccountDetails.js +++ b/frontend/src/components/AccountDetails.js @@ -14,6 +14,8 @@ import { usePopupState, bindTrigger, bindPopover } from 'material-ui-popup-state import ReconcileForm from './ReconcileForm' import { createSelector } from '@reduxjs/toolkit' import Paper from '@mui/material/Paper' +import BalanceCalculation from './AccountTable/BalanceCalculation' +import EditIcon from '@mui/icons-material/Edit' export default function BudgetDetails({ accountId, name }) { const theme = useTheme() @@ -56,18 +58,28 @@ export default function BudgetDetails({ accountId, name }) { justifyContent="space-between" alignItems="center" spacing={2} - sx={{ p: 3, height: '100%' }} + sx={{ px: 2, pb: 2, height: '100%' }} > - - - + + - {account.name} - + + {account.name} + + + {/* */} + + - - - - - - + + + + + - - + + - Summary - - - - - Cleared - Uncleared ({pendingTransactions}) - Balance - - - - - {intlFormat(account.cleared)} - - - + - - - {intlFormat(account.uncleared)} - - - = - - - {intlFormat(account.balance)} - - + Pending Transactions + {pendingTransactions} diff --git a/frontend/src/components/AccountTable/AccountTable.js b/frontend/src/components/AccountTable/AccountTable.js index 1c47a0c..b4f0ecc 100644 --- a/frontend/src/components/AccountTable/AccountTable.js +++ b/frontend/src/components/AccountTable/AccountTable.js @@ -161,13 +161,6 @@ export default function Account(props) { const payeesMap = useSelector(selectPayeesMap) - let amountFieldFocused = null - let amountFieldModified = false - const focusAmountField = field => { - amountFieldFocused = field - amountFieldModified = false - } - const filter = createFilterOptions() const columns = [ { @@ -383,10 +376,6 @@ export default function Account(props) { ) }, editComponent: props => { - // if (amountFieldModified === true && amountFieldFocused !== 'outflow') { - // props.value.amount = 0 - // } - const value = dinero(props.value) return ( @@ -395,7 +384,6 @@ export default function Account(props) { variant="standard" value={toUnit(value, { digits: 2 })} onChange={value => { - amountFieldModified = true props.onChange(toSnapshot(inputToDinero(value))) }} // onFocus={focusOutflowField} @@ -712,7 +700,7 @@ export default function Account(props) { } return ( -
+ - - - - -
+
) } diff --git a/frontend/src/components/AccountTable/BalanceCalculation.js b/frontend/src/components/AccountTable/BalanceCalculation.js new file mode 100644 index 0000000..21f3e7f --- /dev/null +++ b/frontend/src/components/AccountTable/BalanceCalculation.js @@ -0,0 +1,115 @@ +import React, { useState, useEffect } from 'react' +import { useDispatch } from 'react-redux' +import { accountsSelectors, editAccount } from '../../redux/slices/Accounts' +import { FromAPI, getBalanceColor, intlFormat } from '../../utils/Currency' +import { usePopupState } from 'material-ui-popup-state/hooks' +import Stack from '@mui/material/Stack' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTheme } from '@mui/styles' +import { createSelector } from '@reduxjs/toolkit' + +export default function BalanceCalculation({ account }) { + const theme = useTheme() + + return ( + +
+ + + {intlFormat(account.cleared)} + + + Cleared + + +
+ + + + + + +
+ + + {intlFormat(account.uncleared)} + + + Uncleared + + +
+ + + = + + +
+ + + {intlFormat(account.balance)} + + + Working Balance + + +
+
+ ) +} diff --git a/frontend/src/components/BudgetDetails.js b/frontend/src/components/BudgetDetails.js index 4448f95..9c8acd4 100644 --- a/frontend/src/components/BudgetDetails.js +++ b/frontend/src/components/BudgetDetails.js @@ -1,26 +1,21 @@ import Box from '@mui/material/Box' import { useSelector, useDispatch } from 'react-redux' -import { getBalanceColor, inputToDinero, intlFormat, valueToDinero } from '../utils/Currency' -import Table from '@mui/material/Table' -import TableBody from '@mui/material/TableBody' -import TableCell from '@mui/material/TableCell' -import TableContainer from '@mui/material/TableContainer' -import TableRow from '@mui/material/TableRow' -import TableHead from '@mui/material/TableHead' +import { inputToDinero, intlFormat, valueToDinero, getBalanceColor } from '../utils/Currency' import { useTheme } from '@mui/styles' import Stack from '@mui/material/Stack' import { isPositive, isZero } from 'dinero.js' import Alert from '@mui/material/Alert' -import IconButton from '@mui/material/IconButton' -import { formatMonthFromDateString, getDateFromString } from '../utils/Date' -import BudgetMonthPicker from './BudgetMonthPicker' -import Button from '@mui/material/Button' import Typography from '@mui/material/Typography' -import { usePopupState, bindTrigger } from 'material-ui-popup-state/hooks' -import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIosNew' -import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos' -import { selectActiveBudget, setCurrentMonth } from '../redux/slices/Budgets' +import { selectActiveBudget } from '../redux/slices/Budgets' import Paper from '@mui/material/Paper' +import BudgetMonthCalculation from './BudgetTable/BudgetMonthCalculation' +import CategoryMonthActivity from './CategoryMonthActivity' +import BudgetMonthNavigator from './BudgetMonthNavigator' +import Card from '@mui/material/Card' +import CardActions from '@mui/material/CardActions' +import CardContent from '@mui/material/CardContent' +import Button from '@mui/material/Button' +import { setSelectedCategory } from '../redux/slices/Categories' export default function BudgetDetails(props) { const theme = useTheme() @@ -31,194 +26,117 @@ export default function BudgetDetails(props) { return state.budgetMonths.entities[month] || null }) - const income = budgetMonth ? valueToDinero(budgetMonth.income) : inputToDinero(0) - const activity = budgetMonth ? valueToDinero(budgetMonth.activity) : inputToDinero(0) - const budgeted = budgetMonth ? valueToDinero(budgetMonth.budgeted) : inputToDinero(0) const underfunded = budgetMonth ? valueToDinero(budgetMonth.underfunded) : inputToDinero(0) - - const availableMonths = useSelector(state => state.budgets.availableMonths) const budget = useSelector(selectActiveBudget) - const toBeBudgeted = budget ? valueToDinero(budget.toBeBudgeted) : inputToDinero(0) - const nextMonth = getDateFromString(month) - nextMonth.setMonth(nextMonth.getMonth() + 1) - const nextMonthDisabled = !availableMonths.includes(formatMonthFromDateString(nextMonth)) + const selectedCategory = useSelector(state => { + if (!state.categories.selected) { + return null + } - const prevMonth = getDateFromString(month) - prevMonth.setMonth(prevMonth.getMonth() - 1) - const prevMonthDisabled = !availableMonths.includes(formatMonthFromDateString(prevMonth)) - - const monthPickerPopupState = usePopupState({ - variant: 'popover', - popupId: 'monthPicker', + return state.categories.entities[state.categories.selected] }) - - const navigateMonth = direction => { - const monthDate = new Date(Date.UTC(...month.split('-'))) - monthDate.setDate(1) - monthDate.setMonth(monthDate.getMonth() + direction) - dispatch(setCurrentMonth({ month: formatMonthFromDateString(monthDate) })) + const clearSelectedCategory = () => { + dispatch(setSelectedCategory(null)) } - const isToday = month === formatMonthFromDateString(new Date()) - return ( - - - - - navigateMonth(-1)} - sx={{ - fontSize: theme.typography.h6.fontSize, - color: 'white', - }} - > - - + + + - - - - - - - navigateMonth(1)} - sx={{ - fontSize: theme.typography.h6.fontSize, - // [`.Mui-disabled`]: { color: theme.palette.grey[500] }, - color: 'white', - }} - > - - - - - - - - - - Available to Budget + Monthly Summary - - - + + - {intlFormat(toBeBudgeted)} - + Underfunded + {intlFormat(underfunded)} + + + + + {selectedCategory && ( + + + + + {selectedCategory.name} Activity + + + + + + + + + - - - - - - Monthly Breakdown - - - - Income - {intlFormat(income)} - - - - Activity - {intlFormat(activity)} - - - - Budgeted - {intlFormat(budgeted)} - - - - Underfunded - {intlFormat(underfunded)} - - - + )} + + diff --git a/frontend/src/components/BudgetMonthNavigator.js b/frontend/src/components/BudgetMonthNavigator.js new file mode 100644 index 0000000..2bc11ca --- /dev/null +++ b/frontend/src/components/BudgetMonthNavigator.js @@ -0,0 +1,139 @@ +import Box from '@mui/material/Box' +import { useSelector, useDispatch } from 'react-redux' +import { useTheme } from '@mui/styles' +import Stack from '@mui/material/Stack' +import IconButton from '@mui/material/IconButton' +import { formatMonthFromDateString, getDateFromString } from '../utils/Date' +import BudgetMonthPicker from './BudgetMonthPicker' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import { usePopupState, bindTrigger } from 'material-ui-popup-state/hooks' +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIosNew' +import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos' +import { selectActiveBudget, setCurrentMonth } from '../redux/slices/Budgets' +import EventIcon from '@mui/icons-material/Event' +import List from '@mui/material/List' +import ListItem from '@mui/material/ListItem' + +export default function BudgetMonthNavigator({ mini }) { + const theme = useTheme() + const dispatch = useDispatch() + + const month = useSelector(state => state.budgets.currentMonth) + const availableMonths = useSelector(state => state.budgets.availableMonths) + + const nextMonth = getDateFromString(month) + nextMonth.setMonth(nextMonth.getMonth() + 1) + const nextMonthDisabled = !availableMonths.includes(formatMonthFromDateString(nextMonth)) + + const prevMonth = getDateFromString(month) + prevMonth.setMonth(prevMonth.getMonth() - 1) + const prevMonthDisabled = !availableMonths.includes(formatMonthFromDateString(prevMonth)) + + const monthPickerPopupState = usePopupState({ + variant: 'popover', + popupId: 'monthPicker', + }) + + const navigateMonth = direction => { + const monthDate = new Date(Date.UTC(...month.split('-'))) + monthDate.setDate(1) + monthDate.setMonth(monthDate.getMonth() + direction) + dispatch(setCurrentMonth({ month: formatMonthFromDateString(monthDate) })) + } + + const isToday = month === formatMonthFromDateString(new Date()) + + if (mini === true) { + return ( + + + + + + + ) + } + + return ( + + + + navigateMonth(-1)} + sx={{ + fontSize: theme.typography.h6.fontSize, + color: 'white', + }} + > + + + + + + + + + + navigateMonth(1)} + sx={{ + fontSize: theme.typography.h6.fontSize, + // [`.Mui-disabled`]: { color: theme.palette.grey[500] }, + color: 'white', + }} + > + + + + + ) +} diff --git a/frontend/src/components/BudgetTable/BudgetMonthCalculation.js b/frontend/src/components/BudgetTable/BudgetMonthCalculation.js new file mode 100644 index 0000000..8c5543d --- /dev/null +++ b/frontend/src/components/BudgetTable/BudgetMonthCalculation.js @@ -0,0 +1,122 @@ +import React, { useState, useEffect } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import Stack from '@mui/material/Stack' +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTheme } from '@mui/styles' +import { getBalanceColor, inputToDinero, intlFormat, valueToDinero } from '../../utils/Currency' +import { selectActiveBudget } from '../../redux/slices/Budgets' +import { add } from 'dinero.js' + +export default function BudgetMonthCalculation({ account }) { + const theme = useTheme() + + const month = useSelector(state => state.budgets.currentMonth) + const budgetMonth = useSelector(state => { + return state.budgetMonths.entities[month] || null + }) + + const income = budgetMonth ? valueToDinero(budgetMonth.income) : inputToDinero(0) + const activity = budgetMonth ? valueToDinero(budgetMonth.activity) : inputToDinero(0) + + return ( + +
+ + + {intlFormat(income)} + + + Income + + +
+ + + + + + +
+ + + {intlFormat(activity)} + + + Spent + + +
+ + + = + + +
+ + + {intlFormat(add(income, activity))} + + + Net + + +
+
+ ) +} diff --git a/frontend/src/components/BudgetTable/BudgetTable.js b/frontend/src/components/BudgetTable/BudgetTable.js index 431449b..ffe859b 100644 --- a/frontend/src/components/BudgetTable/BudgetTable.js +++ b/frontend/src/components/BudgetTable/BudgetTable.js @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from 'react-redux' import { createSelector } from '@reduxjs/toolkit' import { refreshBudget } from '../../redux/slices/Budgets' import { updateCategoryMonth, refreshBudgetCategory } from '../../redux/slices/BudgetMonths' -import { updateCategory } from '../../redux/slices/Categories' +import { setSelectedCategory, updateCategory } from '../../redux/slices/Categories' import { updateCategoryGroup, fetchCategories, categoryGroupsSelectors } from '../../redux/slices/CategoryGroups' import { categoriesSelectors } from '../../redux/slices/Categories' import IconButton from '@mui/material/IconButton' @@ -502,6 +502,11 @@ export default function BudgetTable(props) { dispatch(refreshBudget()) } + const onCategoryRowClick = row => { + console.log(row) + dispatch(setSelectedCategory(row.original.categoryId)) + } + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable( { columns, @@ -526,8 +531,8 @@ export default function BudgetTable(props) { sx={{ backgroundColor: theme.palette.background.tableBody, display: 'grid', - gridTemplateColums: '1fr', - gridTemplateRows: 'auto 1fr auto', + // gridTemplateColums: '1fr', + // gridTemplateRows: 'auto 1fr auto', height: '100vh', }} > @@ -579,6 +584,9 @@ export default function BudgetTable(props) { prepareRow(row) return ( onCategoryRowClick(row)} {...row.getRowProps({ ...(!row.original.groupId && { sx: { backgroundColor: theme.palette.action.hover } }), })} diff --git a/frontend/src/components/CategoryMonthActivity.js b/frontend/src/components/CategoryMonthActivity.js new file mode 100644 index 0000000..9fa2fe7 --- /dev/null +++ b/frontend/src/components/CategoryMonthActivity.js @@ -0,0 +1,112 @@ +import React from 'react' +import { accountsSelectors } from '../redux/slices/Accounts' +import { useSelector } from 'react-redux' +import Box from '@mui/material/Box' +import Table from '@mui/material/Table' +import TableHead from '@mui/material/TableHead' +import TableBody from '@mui/material/TableBody' +import TableRow from '@mui/material/TableRow' +import TableCell from '@mui/material/TableCell' +import TableContainer from '@mui/material/TableContainer' +import Tooltip from '@mui/material/Tooltip' +import Typography from '@mui/material/Typography' +import { intlFormat, FromAPI } from '../utils/Currency' +import { formatMonthFromDateString } from '../utils/Date' +import { useTheme } from '@mui/styles' +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined' + +export default function CategoryMonthActivity(props) { + const theme = useTheme() + + const month = useSelector(state => new Date(state.budgets.currentMonth)) + const accounts = useSelector(accountsSelectors.selectAll) + const selectedCategory = useSelector(state => { + if (!state.categories.selected) { + return null + } + + return state.categories.entities[state.categories.selected] + }) + const payees = useSelector(state => state.payees.entities) + + if (!selectedCategory) { + return <>No category selected + } + + const transactions = accounts.reduce((total, account) => { + const filtered = Object.values(account.transactions.entities).filter(trx => { + const trxDate = new Date(trx.date) + if (trx.categoryId !== selectedCategory.id) { + return false + } + + if (trxDate.getMonth() === month.getMonth() && trxDate.getFullYear() === month.getFullYear()) { + return true + } + + return false + }) + + return total.concat(filtered) + }, []) + + if (transactions.length === 0) { + return No transactions for this month + } + + return ( + + + + + + + + Payee + + + Amount + + + + + + {transactions.map(transaction => { + transaction = FromAPI.transformTransaction(transaction) + return ( + + + + Date: {formatMonthFromDateString(transaction.date)} + + + Account: {accounts.find(acct => acct.id === transaction.accountId).name} + + + Memo: {transaction.memo}{' '} + + + } + > + + + + + {payees[transaction.payeeId].name} + {intlFormat(transaction.amount)} + + ) + })} + +
+
+
+ ) +} diff --git a/frontend/src/components/Drawer.js b/frontend/src/components/Drawer.js index 0344d14..2c4fee9 100644 --- a/frontend/src/components/Drawer.js +++ b/frontend/src/components/Drawer.js @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import Drawer from '@mui/material/Drawer' +import MuiDrawer from '@mui/material/Drawer' import List from '@mui/material/List' import Divider from '@mui/material/Divider' import ListItem from '@mui/material/ListItem' @@ -11,18 +11,13 @@ import ExpandMore from '@mui/icons-material/ExpandMore' import Collapse from '@mui/material/Collapse' import { useNavigate } from 'react-router-dom' import { useSelector, useDispatch } from 'react-redux' -import AccountBalanceIcon from '@mui/icons-material/AccountBalance' import { inputToDinero, intlFormat, valueToDinero } from '../utils/Currency' import LogoutIcon from '@mui/icons-material/Logout' import api from '../api' -import Grid from '@mui/material/Grid' import { add, isNegative } from 'dinero.js' -import { useTheme } from '@mui/styles' +import { styled, useTheme } from '@mui/styles' import AddCircleIcon from '@mui/icons-material/AddCircle' -import Menu from '@mui/material/Menu' -import MenuItem from '@mui/material/MenuItem' -import { usePopupState, bindTrigger, bindMenu } from 'material-ui-popup-state/hooks' -import ChevronRightIcon from '@mui/icons-material/ChevronRight' +import { usePopupState } from 'material-ui-popup-state/hooks' import { accountsSelectors, editAccount, fetchAccounts } from '../redux/slices/Accounts' import { setTheme } from '../redux/slices/App' import { selectActiveBudget } from '../redux/slices/Budgets' @@ -30,9 +25,51 @@ import Brightness4Icon from '@mui/icons-material/Brightness4' import Brightness7Icon from '@mui/icons-material/Brightness7' import Settings from './Settings/Settings' import SettingsIcon from '@mui/icons-material/Settings' -import MailOutlineIcon from '@mui/icons-material/MailOutline' +import Box from '@mui/material/Box' +import Stack from '@mui/material/Stack' +import Typography from '@mui/material/Typography' +import Avatar from '@mui/material/Avatar' +import ChevronLeftIcon from '@mui/icons-material/ChevronLeft' +import ChevronRightIcon from '@mui/icons-material/ChevronRight' +import AccountBalanceIcon from '@mui/icons-material/AccountBalance' -const drawerWidth = 350 +const drawerWidth = 300 + +const openedMixin = theme => ({ + width: drawerWidth, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen, + }), + overflowX: 'hidden', +}) + +const closedMixin = theme => ({ + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + overflowX: 'hidden', + width: `calc(${theme.spacing(9)} + 1px)`, + [theme.breakpoints.up('sm')]: { + width: `calc(${theme.spacing(9)} + 1px)`, + }, +}) + +const Drawer = styled(MuiDrawer, { shouldForwardProp: prop => prop !== 'open' })(({ theme, open }) => ({ + width: drawerWidth, + flexShrink: 0, + whiteSpace: 'nowrap', + boxSizing: 'border-box', + ...(open && { + ...openedMixin(theme), + '& .MuiDrawer-paper': openedMixin(theme), + }), + ...(!open && { + ...closedMixin(theme), + '& .MuiDrawer-paper': closedMixin(theme), + }), +})) export default function AppDrawer(props) { const dispatch = useDispatch() @@ -49,6 +86,7 @@ export default function AppDrawer(props) { /** * State block */ + const [drawerOpen, setDrawerOpen] = useState(true) const [accountsListOpen, setAccountsListOpen] = useState({ ACCOUNTS: true, OFF_BUDGET: true }) const [selectedItem, setSelectedItem] = useState('Budget') const [settingsOpen, setSettingsOpen] = useState(false) @@ -102,39 +140,46 @@ export default function AppDrawer(props) { return ( - listItemClicked(key)}> - -
- - - {accountsListOpen[key] ? ( - - ) : ( - - )} - - - -
- -
+ listItemClicked(key)}> + {drawerOpen && ( + <> + + {accountsListOpen[key] ? ( + + ) : ( + + )} + + {label} + + + {intlFormat(balance)} + + + } /> -
-
-
+ + )} + {!drawerOpen && ( + <> + } /> + + {accountsListOpen[key] ? ( + + ) : ( + + )} + + + )} + @@ -169,11 +214,16 @@ export default function AppDrawer(props) { props.onAddAccountClick() } + const toggleDrawer = () => { + setDrawerOpen(!drawerOpen) + } + const AccountItem = account => { const balance = valueToDinero(account.balance) const balanceColor = isNegative(balance) ? theme.palette.error.main : theme.palette.secondary.main return ( - listItemClicked(`account-${account.id}`, `/accounts/${account.id}`)} @@ -195,33 +245,43 @@ export default function AppDrawer(props) { DragState.dropAccount = -1 }} > - -
- -
+ {drawerOpen === false && ( + + {account.name[0]} + + )} + {drawerOpen === true && ( + +
+ +
-
- -
-
-
+
+ {/* {selectedItem === `account-${account.id}` && ( + + )} */} + +
+ + )} + ) } @@ -235,6 +295,7 @@ export default function AppDrawer(props) { - - - + + {drawerOpen && } + + {drawerOpen === false ? ( + + ) : ( + + )} + - - {/* - Settings - Add Account - */} + + + + {menuItems.map((menuItemConfig, index) => ( - listItemClicked(menuItemConfig.name, menuItemConfig.path)} selected={selectedItem === menuItemConfig.name} > - + {index % 2 === 0 ? : } - + ))} - + {/* */} {budgetAccounts.length > 0 && AccountList('ACCOUNTS', budgetAccounts)} @@ -281,21 +347,46 @@ export default function AppDrawer(props) { - - - - props.onAddAccountClick()} /> + {drawerOpen && ( + <> + + + + + + )} + {drawerOpen === false && ( + <> + + + + + )} - + + + + + + + + + + {currentTheme === 'dark' ? ( @@ -303,15 +394,16 @@ export default function AppDrawer(props) { )} - + + - + - + diff --git a/frontend/src/pages/Account.js b/frontend/src/pages/Account.js index 50e68f8..d681977 100644 --- a/frontend/src/pages/Account.js +++ b/frontend/src/pages/Account.js @@ -5,7 +5,7 @@ import AccountTable from '../components/AccountTable/AccountTable' import { useNavigate } from 'react-router-dom' import { accountsSelectors } from '../redux/slices/Accounts' import AccountDetails from '../components/AccountDetails' -import Grid from '@mui/material/Grid' +import Stack from '@mui/material/Stack' import Box from '@mui/material/Box' import { useTheme } from '@mui/styles' @@ -22,5 +22,35 @@ export default function Account(props) { } }, []) - return {account && } + return ( + + + + + + +
+ {account && } +
+
+
+ ) } diff --git a/frontend/src/pages/Budget.js b/frontend/src/pages/Budget.js index 1e5f93b..ef37391 100644 --- a/frontend/src/pages/Budget.js +++ b/frontend/src/pages/Budget.js @@ -1,32 +1,43 @@ import React from 'react' import BudgetTable from '../components/BudgetTable/BudgetTable' import BudgetDetails from '../components/BudgetDetails' -import Grid from '@mui/material/Grid' import Box from '@mui/material/Box' +import Stack from '@mui/material/Stack' import { useTheme } from '@mui/styles' -import BudgetTableHeader from '../components/BudgetTable/BudgetTableHeader' +import { useSelector } from 'react-redux' export default function Budget(props) { const theme = useTheme() return ( - - - - - + + + + - - - - - + + + + ) } diff --git a/frontend/src/redux/slices/App.js b/frontend/src/redux/slices/App.js index ccce4d2..f0253f7 100644 --- a/frontend/src/redux/slices/App.js +++ b/frontend/src/redux/slices/App.js @@ -4,7 +4,7 @@ const appSlice = createSlice({ name: 'app', initialState: { - theme: localStorage.getItem('theme') || 'light', + theme: localStorage.getItem('theme') || 'dark', }, reducers: { diff --git a/frontend/src/redux/slices/Categories.js b/frontend/src/redux/slices/Categories.js index e27bc4d..a35e4c9 100644 --- a/frontend/src/redux/slices/Categories.js +++ b/frontend/src/redux/slices/Categories.js @@ -23,12 +23,18 @@ const categoriesAdapter = createEntityAdapter() const categoriesSlice = createSlice({ name: 'categories', - initialState: categoriesAdapter.getInitialState(), + initialState: categoriesAdapter.getInitialState({ + selected: null, + }), reducers: { setCategories: (state, { payload }) => { categoriesAdapter.setAll(state, payload) }, + + setSelectedCategory: (state, { payload }) => { + state.selected = payload + }, }, extraReducers: builder => { @@ -42,7 +48,7 @@ const categoriesSlice = createSlice({ }, }) -export const { setCategories } = categoriesSlice.actions +export const { setCategories, setSelectedCategory } = categoriesSlice.actions export const categoriesSelectors = categoriesAdapter.getSelectors(state => state.categories) export const selectCategoryToGroupMap = createSelector(categoriesSelectors.selectAll, categories =>