Skip to content

Commit

Permalink
Merge pull request #1 from Zackaria-Slimane/edits
Browse files Browse the repository at this point in the history
Routing fixes
  • Loading branch information
slzakaria authored Jan 12, 2024
2 parents 4060004 + ce8aec9 commit ab3b8ff
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 47 deletions.
11 changes: 11 additions & 0 deletions cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
echo "cleaning up old files and cache >>>"
cd .
rm -rf ./node_modules
rm -rf ./build

echo "installing dependencies >>>"
npm ci

echo "starting project >>>"
npm run dev
3 changes: 0 additions & 3 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

import { Main, mainLoader } from "./layouts/Main";

import { deleteBudget } from "./actions/deleteBudget";
Expand Down Expand Up @@ -67,5 +66,3 @@ export function App() {
</div>
);
}


135 changes: 93 additions & 42 deletions src/components/BudgetItem.jsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,106 @@
import { useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { Form, Link } from "react-router-dom";
import { FaRegTrashCan, FaMoneyCheckDollar } from "react-icons/fa6";
import { EditBudget } from "../components/EditBudget";
import { FaRegTrashCan, FaMoneyCheckDollar, FaPen } from "react-icons/fa6";
import { calculateSpentByBudget, formatCurrency, formatPercentage } from "../helpers";

export function BudgetItem({ budget, showDelete = false }) {
const { id, name, amount } = budget;
const spent = calculateSpentByBudget(id);
const [showBudgetForm, setShowBudgetForm] = useState(false);

function toggleBudgetForm() {
console.log("toggleBudgetForm");
setShowBudgetForm(!showBudgetForm);
}

return (
<div className='budget mt-6 grid auto-cols-fr gap-6 border-fluo rounded-2xl p-4 border-2 text-alice'>
<div className='progress-text'>
<h3>{name}</h3>
<p>{formatCurrency(amount)} Budgeted</p>
</div>
<>
<Transition appear show={showBudgetForm} as={Fragment}>
<Dialog as='div' className='relative z-10 sm:w-[600px]' onClose={toggleBudgetForm}>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0'
enterTo='opacity-100'
leave='ease-in duration-200'
leaveFrom='opacity-100'
leaveTo='opacity-0'>
<div className='fixed inset-0 bg-black/25' />
</Transition.Child>

<progress max={amount} value={spent}>
{formatPercentage(spent / amount)}
</progress>
<div className='progress-text'>
<small>{formatCurrency(spent)} spent</small>
<small className={`${amount - spent < 0 ? "text-tomato" : "text-alice"}`}>
{formatCurrency(amount - spent)} remaining
</small>
</div>
{showDelete ? (
<div className='flex flex-wrap gap-4'>
<Form
method='post'
action='delete'
onSubmit={(event) => {
if (!confirm("Are you sure you want to permanently delete this budget?")) {
event.preventDefault();
}
}}>
<button
type='submit'
className='px-6 py-1 flex gap-2 bg-alice items-center rounded-md hover:bg-tomato transition-all duration-300 max-w-[230px]'>
<span className='text-lg text-navy'>Delete Budget</span>
<FaRegTrashCan className='w-5 h-5 text-navy' />
</button>
</Form>
<div className='fixed inset-0 overflow-y-auto'>
<div className='flex min-h-full items-center justify-center p-4 text-center'>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0 scale-95'
enterTo='opacity-100 scale-100'
leave='ease-in duration-200'
leaveFrom='opacity-100 scale-100'
leaveTo='opacity-0 scale-95'>
<Dialog.Panel className='w-full max-w-[600px] transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all'>
<EditBudget budgetId={id} />
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
<div className='budget mt-6 grid auto-cols-fr gap-6 border-fluo rounded-2xl p-4 border-2 text-alice'>
<div className='progress-text'>
<h3>{name}</h3>
<p>{formatCurrency(amount)} Budgeted</p>
</div>
) : (
<div className='flex flex-wrap gap-4'>
<Link
to={`/budget/${id}`}
className='px-6 py-1 flex gap-2 bg-alice items-center rounded-md hover:bg-fluo transition-all duration-300 max-w-[230px]'>
<span className='text-lg text-navy'>View Details</span>
<FaMoneyCheckDollar className='w-5 h-5 text-navy' />
</Link>

<progress max={amount} value={spent}>
{formatPercentage(spent / amount)}
</progress>
<div className='progress-text'>
<small>{formatCurrency(spent)} spent</small>
<small className={`${amount - spent < 0 ? "text-tomato" : "text-alice"}`}>
{formatCurrency(amount - spent)} remaining
</small>
</div>
)}
</div>
{showDelete ? (
<div className='flex flex-wrap gap-4'>
<Form
method='post'
action='delete'
onSubmit={(event) => {
if (!confirm("Are you sure you want to permanently delete this budget?")) {
event.preventDefault();
}
}}>
<button
type='submit'
className='px-6 py-1 flex gap-2 bg-alice items-center rounded-md hover:bg-tomato transition-all duration-300 max-w-[230px]'>
<span className='text-md text-navy'>Delete Budget</span>
<FaRegTrashCan className='w-5 h-5 text-navy' />
</button>
</Form>
<div>
<button
onClick={toggleBudgetForm}
type='button'
className='px-6 py-1 flex gap-2 bg-alice items-center rounded-md hover:bg-sunny transition-all duration-300 max-w-[230px]'>
<span className='text-md text-navy'>Edit Budget</span>
<FaPen className='w-4 h-4 text-navy' />
</button>
</div>
</div>
) : (
<div className='flex flex-wrap gap-4'>
<Link
to={`/budget/${id}`}
className='px-6 py-1 flex gap-2 bg-alice items-center rounded-md hover:bg-fluo transition-all duration-300 max-w-[230px]'>
<span className='text-lg text-navy'>View Details</span>
<FaMoneyCheckDollar className='w-5 h-5 text-navy' />
</Link>
</div>
)}
</div>
</>
);
}
82 changes: 82 additions & 0 deletions src/components/EditBudget.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useState, useEffect, useRef } from "react";
import { useFetcher } from "react-router-dom";
import { getAllMatchingItems } from "../helpers";

export function EditBudget({ budgetId }) {
const fetcher = useFetcher();
const isSubmitting = fetcher.state === "submitting";
const formRef = useRef();
const focusRef = useRef();
const [budget, setBudget] = useState({});

useEffect(() => {
console.log("budgetId", budgetId);
async function getBudget() {
let result = await getAllMatchingItems({
category: "budgets",
key: "id",
value: budgetId,
})[0];
console.log("budget", budget);
setBudget(result);
}
getBudget();
}, []);

useEffect(() => {
if (!isSubmitting) {
formRef.current.reset();
focusRef.current.focus();
}
}, [isSubmitting]);

return (
<div className='font-jetBrain max-w-[600px] p-6 bg-white rounded-2xl flex-1'>
<h2 className='text-navy text-2xl'>Edit budget</h2>
<fetcher.Form method='post' className='grid gap-4 p-4' ref={formRef}>
<div className='grid gap-4'>
<label className='text-navy text-lg' htmlFor='newBudget'>
Budget Name
</label>
<input
className='text-navy rounded-lg ring-2 ring-navy py-2 px-4'
type='text'
name='newBudget'
id='newBudget'
placeholder={budget.name}
required
ref={focusRef}
/>
</div>
<div className='grid gap-4'>
<label className='text-navy text-lg' htmlFor='newBudgetAmount'>
Amount
</label>
<input
className='text-navy rounded-lg ring-2 ring-navy py-2 px-4'
type='number'
step='0.01'
name='newBudgetAmount'
id='newBudgetAmount'
placeholder={budget.amount}
required
inputMode='decimal'
/>
</div>
<input type='hidden' name='_action' value='editBudget' />
<button
type='submit'
className='px-6 py-2 mt-2 flex gap-2 bg-fluo items-center rounded-md hover:bg-fluo/80 transition-all duration-300 max-w-[230px]'
disabled={isSubmitting}>
{isSubmitting ? (
<span className='text-lg'>Submitting…</span>
) : (
<>
<span className='w-full text-md text-navy'>Edit budget</span>
</>
)}
</button>
</fetcher.Form>
</div>
);
}
27 changes: 27 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ export const createBudget = ({ name, amount }) => {
return localStorage.setItem("budgets", JSON.stringify([...existingBudgets, newItem]));
};

export const updateBudget = ({ id, name, amount }) => {
const existingBudgets = fetchData("budgets") ?? [];
const updatedBudgets = existingBudgets.map((budget) => {
if (budget.id !== id) return budget;
return {
...budget,
name: name,
amount: +amount,
};
});
return localStorage.setItem("budgets", JSON.stringify(updatedBudgets));
};

export const createExpense = ({ name, amount, budgetId }) => {
const budgetName = getAllMatchingItems({ category: "budgets", key: "id", value: budgetId })[0]
.name;
Expand All @@ -62,6 +75,20 @@ export const createExpense = ({ name, amount, budgetId }) => {
return localStorage.setItem("expenses", JSON.stringify([...existingExpenses, newItem]));
};

export const updateExpense = ({ id, name, amount, budgetId }) => {
const existingExpenses = fetchData("expenses") ?? [];
const updatedExpenses = existingExpenses.map((expense) => {
if (expense.id !== id) return expense;
return {
...expense,
name: name,
amount: +amount,
budgetId: budgetId,
};
});
return localStorage.setItem("expenses", JSON.stringify(updatedExpenses));
};

export const calculateSpentByBudget = (budgetId) => {
const expenses = fetchData("expenses") ?? [];
const budgetSpent = expenses.reduce((acc, expense) => {
Expand Down
1 change: 1 addition & 0 deletions src/pages/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export function Dashboard() {
<span>Add Expense</span> <BsCartCheck />
</button>
</div>

<Transition appear show={modalOpen} as={Fragment}>
<Dialog as='div' className='relative z-10' onClose={closeModal}>
<Transition.Child
Expand Down
5 changes: 3 additions & 2 deletions src/pages/Error.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { useRouteError, Link, useNavigate } from "react-router-dom";
export function Error() {
const error = useRouteError();
const navigate = useNavigate();
console.log("ERROR PAGE CAUSED BY ======>", error);

return (
<div className='error h-screen'>
<h1 className='text-alice text-xl'>Uh oh! We’ve got a problem.</h1>
<p className='text-tomato'>{error.message || error.statusText}</p>
<h1 className='text-alice text-xl'>Uh oh! Sorry We’ve got a problem.</h1>
<p className='text-tomato'>{error?.message || error?.statusText}</p>
<div className='flex gap-6'>
<button className='' onClick={() => navigate(-1)}>
<span className='bg-tomato text-alice px-4 py-1 rounded-lg text-lg'>Go Back</span>
Expand Down

0 comments on commit ab3b8ff

Please sign in to comment.