diff --git a/src/components/AddExpenseForm.js b/src/components/AddExpenseForm.js new file mode 100644 index 0000000..29081f3 --- /dev/null +++ b/src/components/AddExpenseForm.js @@ -0,0 +1,65 @@ +import React, { useContext, useState } from 'react'; +import { AppContext } from '../context/AppContext'; +import { v4 as uuidv4 } from 'uuid'; + +const AddExpenseForm = (props) => { + const { dispatch } = useContext(AppContext); + + const [name, setName] = useState(''); + const [cost, setCost] = useState(''); + + const onSubmit = (event) => { + event.preventDefault(); + const expense = { + id: uuidv4(), + name, + cost: parseInt(cost), + }; + + dispatch({ + type: 'ADD_EXPENSE', + payload: expense, + }); + + setName(''); + setCost(''); + }; + + return ( +
+
+
+ + setName(event.target.value)} + /> +
+
+ + setCost(event.target.value)} + /> +
+
+
+
+ +
+
+
+ ); +}; + +export default AddExpenseForm; diff --git a/src/components/AddNewBill.css b/src/components/AddNewBill.css deleted file mode 100644 index 81ac5ff..0000000 --- a/src/components/AddNewBill.css +++ /dev/null @@ -1,58 +0,0 @@ -.add_bill_widget { - background-color: rgb(223, 245, 229); - max-height: 50%; - } -.widget_header { - margin: 0px; - margin-bottom: 20px; -} -input { - max-width: 50%; -} -button { - margin-left: 20%; - margin-right: auto; -} -.buttons{ -} -/* Style The Dropdown Button */ -.dropbtn { - cursor: pointer; - } - - /* The container
- needed to position the dropdown content */ - .dropdown { - position: relative; - display: inline-block; - } - - /* Dropdown Content (Hidden by Default) */ - .dropdown-content { - display: none; - position: absolute; - background-color: #f9f9f9; - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 1; - } - - /* Links inside the dropdown */ - .dropdown-content a { - color: black; - padding: 12px 16px; - text-decoration: none; - display: block; - } - - /* Change color of dropdown links on hover */ - .dropdown-content a:hover {background-color: #f1f1f1} - - /* Show the dropdown menu on hover */ - .dropdown:hover .dropdown-content { - display: block; - } - - /* Change the background color of the dropdown button when the dropdown content is shown */ - .dropdown:hover .dropbtn { - background-color: #3e8e41; - } \ No newline at end of file diff --git a/src/components/AddNewBill.js b/src/components/AddNewBill.js deleted file mode 100644 index 5cd260f..0000000 --- a/src/components/AddNewBill.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import './AddNewBill.css' - -export default function AddNewBill() { - return ( - <> -
-

Add New Bill

- -
- - -
- -
- - - ) -} \ No newline at end of file diff --git a/src/components/CurrentBalance.css b/src/components/CurrentBalance.css deleted file mode 100644 index d9529f9..0000000 --- a/src/components/CurrentBalance.css +++ /dev/null @@ -1,23 +0,0 @@ -.current_balance_widget { - background-color: rgb(223, 245, 229); -} -.widget_header { -} - -img { - float: left; - height: 40px; - margin-left: 5%; -} - -.current_balance_widget h1 { - float: left; - margin: 0; - margin-left: 10%; -} -.current_balance_widget h6 { - color: green; - float: left; - margin: 0; - margin-left: 33%; -} diff --git a/src/components/CurrentBalance.js b/src/components/CurrentBalance.js deleted file mode 100644 index 9123602..0000000 --- a/src/components/CurrentBalance.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' -import './CurrentBalance.css' -import logo from '../assets/widget_logos/current_balance_logo.png'; - -export default function CurrentBalance() { - return ( - <> -
-

Current Balance

- -

$1238.56

-
+ $179.97 (17%) last month
-
- - - ) -} \ No newline at end of file diff --git a/src/components/EditBudget.js b/src/components/EditBudget.js new file mode 100644 index 0000000..eff7336 --- /dev/null +++ b/src/components/EditBudget.js @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; + +const EditBudget = (props) => { + const [value, setValue] = useState(props.budget); + return ( + <> + setValue(event.target.value)} + /> + + + ); +}; + +export default EditBudget; diff --git a/src/components/ExpenseItem.js b/src/components/ExpenseItem.js new file mode 100644 index 0000000..5088ede --- /dev/null +++ b/src/components/ExpenseItem.js @@ -0,0 +1,24 @@ +import React, { useContext } from 'react'; +import { AppContext } from '../context/AppContext'; + +const ExpenseItem = (props) => { + const { dispatch } = useContext(AppContext); + + const handleDeleteExpense = () => { + dispatch({ + type: 'DELETE_EXPENSE', + payload: props.id, + }); + }; + + return ( +
  • + {props.name} +
    + ${props.cost} +
    +
  • + ); +}; + +export default ExpenseItem; diff --git a/src/components/ExpenseList.js b/src/components/ExpenseList.js new file mode 100644 index 0000000..91bae9d --- /dev/null +++ b/src/components/ExpenseList.js @@ -0,0 +1,42 @@ +import React, { useContext, useState, useEffect } from 'react'; +import ExpenseItem from './ExpenseItem'; +import { AppContext } from '../context/AppContext'; + +const ExpenseList = () => { + const { expenses } = useContext(AppContext); + + const [filteredExpenses, setfilteredExpenses] = useState(expenses || []); + + useEffect(() => { + setfilteredExpenses(expenses); + }, [expenses]); + + const handleChange = (event) => { + const searchResults = expenses.filter((filteredExpense) => + filteredExpense.name.toLowerCase().includes(event.target.value) + ); + setfilteredExpenses(searchResults); + }; + + return ( + <> + + + + ); +}; + +export default ExpenseList; diff --git a/src/components/ExpenseTotal.js b/src/components/ExpenseTotal.js new file mode 100644 index 0000000..3cdd3e7 --- /dev/null +++ b/src/components/ExpenseTotal.js @@ -0,0 +1,18 @@ +import React, { useContext } from 'react'; +import { AppContext } from '../context/AppContext'; + +const ExpenseTotal = () => { + const { expenses } = useContext(AppContext); + + const total = expenses.reduce((total, item) => { + return (total += item.cost); + }, 0); + + return ( +
    + This Month's Expenses: ${total} +
    + ); +}; + +export default ExpenseTotal; diff --git a/src/components/Expenses.css b/src/components/Expenses.css deleted file mode 100644 index 27c7098..0000000 --- a/src/components/Expenses.css +++ /dev/null @@ -1,20 +0,0 @@ -.expenses_widget { - background-color: rgb(223, 245, 229); -} -.widget_header { -} - -img { - height: 40px; -} - -.expenses_widget h1 { - float: left; - margin: 0; - margin-left: 10%; -} -.expenses_widget h6 { - color: red; - float: right; - margin: 0; -} diff --git a/src/components/Expenses.js b/src/components/Expenses.js deleted file mode 100644 index 086b6dd..0000000 --- a/src/components/Expenses.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' -import './Expenses.css' -import logo from '../assets/widget_logos/expenses_logo.png'; - -export default function Expenses() { - return ( - <> -
    -

    This Month's Expenses

    - -

    $456.78

    -
    + $359.97 (26%) last month (17%)
    -
    - - - ) -} \ No newline at end of file diff --git a/src/components/Income.css b/src/components/Income.css deleted file mode 100644 index a571360..0000000 --- a/src/components/Income.css +++ /dev/null @@ -1,20 +0,0 @@ -.income_widget { - background-color: rgb(223, 245, 229); -} -.widget_header { -} - -img { - height: 40px; -} - -.income_widget h1 { - float: left; - margin: 0; - margin-left: 10%; -} -.income_widget h6 { - color: green; - margin: 0; - float: right; -} diff --git a/src/components/Income.js b/src/components/Income.js deleted file mode 100644 index c1c2112..0000000 --- a/src/components/Income.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' -import './Income.css' -import logo from '../assets/widget_logos/income_logo.png'; - -export default function Income() { - return ( - <> -
    -

    This Month's Income

    - -

    $1,525.00

    -
    + $1,037.51 (42%) last month
    -
    - - - ) -} \ No newline at end of file diff --git a/src/components/RecentTransaction.css b/src/components/RecentTransaction.css deleted file mode 100644 index 51027a8..0000000 --- a/src/components/RecentTransaction.css +++ /dev/null @@ -1,15 +0,0 @@ -.transactions_widget { - background-color: rgb(223, 245, 229); -} - -.transaction_table { - display: grid; - grid-template-columns: repeat(3, 1fr); - grid-template-rows: 30px 30px 30px 30px; - box-sizing: border-box; -} - -.transaction_table p { - margin: 0; - float: left; -} \ No newline at end of file diff --git a/src/components/RecentTransactions.js b/src/components/RecentTransactions.js deleted file mode 100644 index 49fd46d..0000000 --- a/src/components/RecentTransactions.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react' -import './RecentTransaction.css' - -export default function RecentTransactions() { - return ( - <> -
    -

    Recent Transactions

    -
    -

    Bill

    -

    $35.00

    -

    2/15/23

    -

    Food

    -

    $29.95

    -

    2/11/23

    -

    Wage

    -

    $723.40

    -

    2/10/23

    -

    Pet

    -

    $56.98

    -

    2/5/23

    -

    Leisure

    -

    $60.04

    -

    2/03/23

    -
    -
    - - - ) -} \ No newline at end of file diff --git a/src/components/Remaining.js b/src/components/Remaining.js new file mode 100644 index 0000000..66486c3 --- /dev/null +++ b/src/components/Remaining.js @@ -0,0 +1,20 @@ +import React, { useContext } from 'react'; +import { AppContext } from '../context/AppContext'; + +const RemainingBudget = () => { + const { expenses, budget } = useContext(AppContext); + + const totalExpenses = expenses.reduce((total, item) => { + return (total += item.cost); + }, 0); + + const alertType = totalExpenses > budget ? 'alert-danger' : 'alert-success'; + + return ( +
    + Budget Remaining: ${budget - totalExpenses} +
    + ); +}; + +export default RemainingBudget; diff --git a/src/components/SideNav.css b/src/components/SideNav.css index ab42973..e637b76 100644 --- a/src/components/SideNav.css +++ b/src/components/SideNav.css @@ -1,7 +1,3 @@ -.sidebar { - padding: 0 12px; -} - .sidebar-header { display: flex; align-items: center; diff --git a/src/components/SideNav.js b/src/components/SideNav.js index ee2142a..72feec3 100644 --- a/src/components/SideNav.js +++ b/src/components/SideNav.js @@ -12,7 +12,7 @@ import './SideNav.css' export default function SideNav() { return( - +
    diff --git a/src/components/ViewBudget.js b/src/components/ViewBudget.js new file mode 100644 index 0000000..05f0639 --- /dev/null +++ b/src/components/ViewBudget.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const ViewBudget = (props) => { + return ( + <> + Current Balance: ${props.budget} + + + ); +}; + +export default ViewBudget; diff --git a/src/components/budget.css b/src/components/budget.css deleted file mode 100644 index e381257..0000000 --- a/src/components/budget.css +++ /dev/null @@ -1,23 +0,0 @@ -.budget_widget { - background-color: rgb(223, 245, 229); -} -.widget_header { -} - -img { - float: left; - height: 40px; - margin-left: 5%; -} - -.budget_widget h1 { - float: left; - margin: 0; - margin-left: 10%; -} -.budget_widget h6 { - color: green; - float: left; - margin: 0; - margin-left: 37%; -} diff --git a/src/components/budget.js b/src/components/budget.js index 4efc95b..834b2a2 100644 --- a/src/components/budget.js +++ b/src/components/budget.js @@ -1,17 +1,33 @@ -import React from 'react' -import './budget.css' -import logo from '../assets/widget_logos/budget_logo.png'; +import React, { useState, useContext } from 'react'; +import ViewBudget from './ViewBudget'; +import EditBudget from './EditBudget'; +import { AppContext } from '../context/AppContext'; -export default function Budget() { - return ( - <> -
    -

    Budget Remaining

    - -

    $456.78

    -
    Still on budget
    -
    - - - ) -} \ No newline at end of file +const Budget = () => { + const { budget, dispatch } = useContext(AppContext); + const [isEditing, setIsEditing] = useState(false); + + const handleEditClick = () => { + setIsEditing(true); + }; + + const handleSaveClick = (value) => { + dispatch({ + type: 'SET_BUDGET', + payload: value, + }); + setIsEditing(false); + }; + + return ( +
    + {isEditing ? ( + + ) : ( + + )} +
    + ); +}; + +export default Budget; diff --git a/src/context/AppContext.js b/src/context/AppContext.js new file mode 100644 index 0000000..b90fc7c --- /dev/null +++ b/src/context/AppContext.js @@ -0,0 +1,56 @@ +import React, { createContext, useReducer } from 'react'; +import { v4 as uuidv4 } from 'uuid'; + +export const AppReducer = (state, action) => { + switch (action.type) { + case 'ADD_EXPENSE': + return { + ...state, + expenses: [...state.expenses, action.payload], + }; + case 'DELETE_EXPENSE': + return { + ...state, + expenses: state.expenses.filter( + (expense) => expense.id !== action.payload + ), + }; + case 'SET_BUDGET': + return { + ...state, + budget: action.payload, + }; + + default: + return state; + } +}; + +const initialState = { + budget: 2000, + expenses: [ + { id: uuidv4(), name: 'Groceries', cost: 50 }, + { id: uuidv4(), name: 'Leisure', cost: 300 }, + { id: uuidv4(), name: 'Pet', cost: 70 }, + { id: uuidv4(), name: 'Gas', cost: 40 }, + { id: uuidv4(), name: 'Rent', cost: 500 }, + ], +}; + +export const AppContext = createContext(); + +export const AppProvider = (props) => { + const [state, dispatch] = useReducer(AppReducer, initialState); + + return ( + + {props.children} + + ); +}; diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index f166210..3a3418d 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -1,19 +1,42 @@ - import AddNewBill from '../components/AddNewBill' - import CurrentBalance from '../components/CurrentBalance' - import Expenses from '../components/Expenses' - import Income from '../components/Income' - import Budget from '../components/budget' -import RecentTransactions from '../components/RecentTransactions' - - export default function Dashboard() { - return ( - <> - - - - - - - - ) +import React from 'react'; +import 'bootstrap/dist/css/bootstrap.min.css'; + +import { AppProvider } from '../context/AppContext'; +import Budget from '../components/Budget'; +import ExpenseTotal from '../components/ExpenseTotal'; +import ExpenseList from '../components/ExpenseList'; +import AddExpenseForm from '../components/AddExpenseForm'; +import RemainingBudget from '../components/Remaining'; + +export default function Dashboard() { + return ( + +
    +

    My Budget Planner

    +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Expenses

    +
    +
    + +
    +
    +

    Add Expense

    +
    +
    + +
    +
    +
    +
    + ); } \ No newline at end of file diff --git a/src/styles.css b/src/styles.css index cd41d76..180297c 100644 --- a/src/styles.css +++ b/src/styles.css @@ -24,12 +24,12 @@ code { border-radius: 20px; padding: 20px 30px; width: 100vw; - display: grid; + /*display: grid; COMMENTED OUT BY CHRIS FOR PUSH ON WIDGETS, not sure if need for welcome page or not, do not need anymore for widgets grid-template-columns: repeat(4, 1fr); grid-template-rows: 125px 250px 100px 100px; gap: 10px; padding: 10px; - box-sizing: border-box; + box-sizing: border-box; */ } .page-display div {