" project commit "

new_01
sonali 2024-10-02 14:10:16 +05:30
commit d8c91e08d9
72 changed files with 25349 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

70
README.md Normal file
View File

@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

20476
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

51
package.json Normal file
View File

@ -0,0 +1,51 @@
{
"name": "mini-pos",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@lottiefiles/react-lottie-player": "^3.5.4",
"@mui/icons-material": "^6.1.1",
"@mui/material": "^6.1.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.7.7",
"express": "^4.21.0",
"jwt-decode": "^4.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-lottie-player": "^2.1.0",
"react-router-dom": "^6.26.2",
"react-scripts": "5.0.1",
"react-toastify": "^10.0.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

3
public/entries.json Normal file
View File

@ -0,0 +1,3 @@
[
]

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

46
public/index.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
public/manifest.json Normal file
View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

38
src/App.css Normal file
View File

@ -0,0 +1,38 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

64
src/App.js Normal file
View File

@ -0,0 +1,64 @@
import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Home from "./components/pages/Income/Home";
import IncomePage from "./components/pages/Income/Income/IncomePage";
import AmountPage from "./components/pages/Income/Amount/AmountPage";
import Category from "./components/pages/Income/Category/Category";
import Layout from "./components/pages/Income/Common/Layout";
import TotalSuccessfully from "./components/pages/Income/Common/TotalSuccessfully";
import Records from "./components/pages/Income/Records/Records";
import IncomeEdit from "./components/pages/Income/Common/IncomeEdit";
import IncomeSuccessfully from "./components/pages/Income/Income/IncomeSuccessfully";
import Footer from "./components/pages/Income/Common/Footer";
import ExpensePage from "./components/pages/Expense/ExpensePage/ExpensePage";
import ExpenseAmount from "./components/pages/Expense/ExpenseAmount/ExpenseAmount"
import ExpenseCategory from "./components/pages/Expense/ExpenseCategory/ExpenseCategory"
import ExpenseLayout from "./components/pages/Expense/Common/ExpenseLayout";
import TotalExpenseSuccessfully from "./components/pages/Expense/Common/TotalExpenseSuccessfully";
import ExpenseEditPage from "./components/pages/Expense/Common/ExpenseEditPage"
import ExpenseRecords from "./components/pages/Expense/ExpenseRecords/ExpenseRecords";
import ExpenseSuccessfully from "./components/pages/Expense/ExpenseSuccessfully/ExpenseSuccessfully";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/totalsuccessfully" element={<TotalSuccessfully />} />
<Route path="/editPage" element={<IncomeEdit />} />
<Route path="/successPage" element={<IncomeSuccessfully />} />
<Route path="/records" element={<Records />} />
<Route element={<Layout />}>
<Route path="/income" element={<IncomePage />} />
<Route path="/amount" element={<AmountPage />} />
<Route path="/category" element={<Category />} />
</Route>
{/* Expense Components*/}
<Route path="/expense-totalsuccessfully" element={<TotalExpenseSuccessfully />} />
<Route path="/expense-editPage" element={<ExpenseEditPage/>}/>
<Route path="/expense-records" element={<ExpenseRecords/>}/>
<Route path="/expense-successfully" element={<ExpenseSuccessfully/>}/>
<Route element={<ExpenseLayout />}>
<Route path="/expense" element={<ExpensePage/>}/>
<Route path="/expenseAmount" element={<ExpenseAmount/>}/>
<Route path="/expenseCategory" element={<ExpenseCategory/>}/>
</Route>
</Routes>
<Footer />
</Router>
);
}
export default App;

8
src/App.test.js Normal file
View File

@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

BIN
src/assets/Rupees.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
src/assets/amount.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/assets/category.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/assets/expenses.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,119 @@
.incomeedit-containers {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
font-family: 'Montserrat', sans-serif;
}
.backIcon {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon {
font-size: 24px;
cursor: pointer;
}
.edit-content {
padding: 20px;
border-radius: 8px;
/* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); */
width: 100%;
max-width: 400px;
}
.edit-titles h1 {
color: #fff;
font-size: 30px;
margin: 0px 0;
text-align: center;
}
.edit-datetime {
color: #fff;
font-size: 18px;
text-align: center;
margin-bottom: 10px;
}
.edit-fields {
color: #fff;
margin-bottom: 15px;
width: 93%;
}
.edit-fields label {
display: block;
margin-bottom: 9px;
}
.edit-fields input {
width: 100%;
padding: 10px;
border: 1px solid #555;
border-radius: 4px;
background-color: #3A3A3A;
color: #fff;
font-size: 16px;
}
.edit-buttons {
display: flex;
justify-content: center;
margin-top: 30px;
width: 100%;
}
.edit-btn {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.edit-btn-2 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
@media (max-width: 768px) {
.edit-titles h1 {
font-size: 24px;
}
.edit-datetime {
font-size: 16px;
}
.edit-buttons div {
font-size: 14px;
}
}

View File

@ -0,0 +1,102 @@
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import "../Common/ExpenseEditPage.css"
function ExpenseEditPage() {
const location = useLocation();
const navigate = useNavigate();
const [currentDateTime, setCurrentDateTime] = useState("");
const [amount, setAmount] = useState(location.state?.amount || "");
const [category, setCategory] = useState(location.state?.category || "");
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
}, []);
const handleBackClick = () => {
navigate("/expense-records");
};
const handleSave = () => {
setIsLoading(true);
setError(null);
const updatedEntry = {
id: location.state?.id,
amount: amount,
dateTime: currentDateTime,
category: category,
};
const storedEntries = JSON.parse(localStorage.getItem("entries")) || [];
const updatedEntries = storedEntries.map((entry) =>
entry.id === updatedEntry.id ? updatedEntry : entry
);
localStorage.setItem("entries", JSON.stringify(updatedEntries));
console.log("Entry updated in local storage:", updatedEntry);
navigate("/expense-successfully");
setIsLoading(false);
};
return (
<div className="incomeedit-containers">
<div className="backIcon">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<div className="edit-content">
<div className="edit-titles">
<h1>Edit Expense</h1>
<div className="edit-datetime">
<p>{currentDateTime}</p>
</div>
</div>
{error && <p className="error-message">{error}</p>}
<div className="edit-fields">
<label>Amount:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
</div>
<div className="edit-fields">
<label>Category:</label>
<input
type="text"
value={category}
onChange={(e) => setCategory(e.target.value)}
/>
</div>
<div className="edit-buttons">
<div className="edit-btn" onClick={handleBackClick}>
Cancel
</div>
<div className="edit-btn-2" onClick={handleSave}>
{isLoading ? "Saving..." : "Save"}
</div>
</div>
</div>
</div>
);
}
export default ExpenseEditPage;

View File

@ -0,0 +1,10 @@
.layout-container {
display: flex;
flex-direction: column;
min-height: 100vh;
font-family: 'Montserrat', sans-serif;
}

View File

@ -0,0 +1,23 @@
import React, { useState } from 'react';
import { Outlet } from 'react-router-dom';
import '../Common/ExpenseLayout.css';
import TotalExpenseAmount from '../ExpenseAmount/TotalExpenseAmount';
const ExpenseLayout = () => {
const [totalAmount, setTotalAmount] = useState(0);
const [category, setCategory] = useState('');
return (
<div className="layout-container">
<div className="page-content">
<Outlet context={[totalAmount, setTotalAmount, category, setCategory]} />
</div>
<TotalExpenseAmount totalAmount={totalAmount} category={category} setCategory={setCategory} />
</div>
);
};
export default ExpenseLayout;

View File

@ -0,0 +1,117 @@
.Succesfully-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
}
.arrows {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon-1 {
font-size: 24px;
cursor: pointer;
}
.success-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.success-animation {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
.success-title h1 {
color: #fff;
font-size: 30px;
margin-top: 10px;
text-align: center;
}
.success-message h2 {
color: #fff;
font-size: 24px;
text-align: center;
margin-bottom: 10px;
}
/* Buttons styling */
.success-button {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn-view {
position: relative;
width: 120px;
height: 40px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.btn-back {
position: relative;
width: 120px;
height: 40px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.success-date-time{
color: #fff;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.btn-view, .btn-back {
padding: 12px 20px;
font-size: 16px;
}
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.success-message h2 {
font-size: 20px;
}
.success-title h1 {
font-size: 24px;
}
}

View File

@ -0,0 +1,85 @@
import React, { useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { Player } from "@lottiefiles/react-lottie-player";
import successAnimation from "./Animation - 1727464749500.json";
import "../Common/TotalExpenseSuccessfully.css";
function TotalExpenseSuccessfully() {
const navigate = useNavigate();
const location = useLocation();
const [currentDateTime, setCurrentDateTime] = useState("");
// Extract entryId from location state
const { entryId } = location.state || {}; // This will be undefined if not passed
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
const dataToStore = {
incomeRecord: {
dateTime: formattedDateTime,
entryId: entryId || "Not provided", // Fallback in case entryId is undefined
},
};
console.log(JSON.stringify(dataToStore));
}, [entryId]);
const handleBackClick = () => {
navigate("/");
};
const handleViewRecordsClick = () => {
// Pass entryId to the /records route when navigating
navigate("/expense-records", { state: { entryId } });
console.log(entryId);
};
return (
<div className="Succesfully-container">
<div className="arrows">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon-1"
onClick={handleBackClick}
/>
</div>
<div className="success-title">
<h1>Expense</h1>
<div className="success-date-time">
<p>{currentDateTime}</p>
</div>
</div>
<div className="success-content">
<div className="success-animation">
<Player
autoplay
loop={false}
src={successAnimation}
style={{ height: "300px", width: "300px" }}
/>
</div>
<div className="success-message">
<h2>Was successfully recorded!</h2>
</div>
<div className="success-button">
<div className="btn-back" onClick={handleBackClick}>
Home
</div>
<div className="btn-view" onClick={handleViewRecordsClick}>
Records
</div>
</div>
</div>
</div>
);
}
export default TotalExpenseSuccessfully;

View File

@ -0,0 +1,191 @@
.amount-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
margin: 0 auto;
max-width: 500px;
background-color: #1e1e1e;
border-radius: 10px;
text-align: center;
}
.backarrow {
position: relative;
width: 100%;
text-align: center;
margin-bottom: 50px;
}
.arrowbtn {
position: absolute;
left: 0;
top: 50%;
margin: 30px 10px;
/* transform: translateY(-50%); */
font-size: 24px;
color: #333;
cursor: pointer;
}
.amount-titles {
font-size: 24px;
width: 100px;
color: #fff;
margin: 0 auto;
text-align: center;
flex-grow: 1;
}
.amount-display {
display: flex;
align-items: center;
justify-content: center;
background: #1E1E1E;
box-shadow: 0px 0px 22.3px #E335DC, 0px 0px 2.9px #FFFFFF, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
padding: 10px;
border-radius: 8px;
margin-bottom: 20px;
}
.total-amount {
font-size: 36px;
color: #fff;
margin-right: 10px;
}
.Rupeesicon {
width: 30px;
height: 30px;
}
.rupess_section {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin-top: 20px;
}
.coin {
width: 50px;
height: 50px;
background: #E335DC;
box-shadow: -10px -10px 12px rgba(50, 50, 51, 0.66), 10px 10px 16px #040404, inset -2px -2px 2px rgba(111, 0, 121, 0.64), inset 2px 2px 2px rgba(102, 0, 98, 0.56);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.3s ease;
/* border: 2px solid #fff; */
}
.coin-value {
font-size: 24px;
font-weight: bold;
color: #fff;
}
@media (max-width: 600px) {
.amount-container {
padding: 10px;
max-width: 100%;
}
.backarrow {
justify-content: space-between;
}
.arrowbtn {
position: absolute;
left: 0;
top: 50%;
margin: 30px 10px;
/* transform: translateX(-20%); */
font-size: 24px;
color: #333;
cursor: pointer;
}
.amount-titles {
font-size: 20px;
}
.rupess_section {
gap: 10px;
}
.coin {
width: 50px;
height: 50px;
padding: 15px;
}
.coin-value {
font-size: 26px;
}
.Rupeesicon {
width: 20px;
height: 20px;
}
.total-amount {
font-size: 28px;
}
.coin:hover {
background-color: #4caf50;
}
}
@media (min-width: 1024px) {
.amount-container {
max-width: 800px;
padding: 20px;
}
.coin {
width: 100px;
height: 100px;
}
.coin-value {
font-size: 20px;
}
.Rupeesicon {
width: 30px;
height: 30px;
padding: 10px;
}
.total-amount {
font-size: 40px;
}
}

View File

@ -0,0 +1,70 @@
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { useNavigate, useOutletContext ,useLocation } from "react-router-dom";
import rupeeIcon from "../../../../assets/Rupees.png";
import "../ExpenseAmount/ExpenseAmount.css";
function ExpenseAmount() {
const navigate = useNavigate();
const location = useLocation();
const { entryType } = location.state || {};
const [totalAmount, setTotalAmount] = useOutletContext();
const handleCoinClick = (amount) => {
setTotalAmount((prevAmount) => prevAmount + amount);
};
const handleBackClick = () => {
console.log(entryType);
navigate("/expense", { state: { entryType } });
};
return (
<div className="amount-container">
<div className="backarrow">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrowbtn"
onClick={handleBackClick}
/>
</div>
<div className="amount-display">
<h3 className="amount-titles">Amount</h3>
<img src={rupeeIcon} alt="Rupee Icon" className="Rupeesicon" />
</div>
<section className="rupess_section">
<div className="coin" onClick={() => handleCoinClick(50)}>
<div className="coin-value">50</div>
</div>
<div className="coin" onClick={() => handleCoinClick(100)}>
<div className="coin-value">100</div>
</div>
<div className="coin" onClick={() => handleCoinClick(200)}>
<div className="coin-value">200</div>
</div>
<div className="coin" onClick={() => handleCoinClick(500)}>
<div className="coin-value">500</div>
</div>
<div className="coin" onClick={() => handleCoinClick(1000)}>
<div className="coin-value">1000</div>
</div>
</section>
</div>
);
}
export default ExpenseAmount;

View File

@ -0,0 +1,122 @@
.total-amount-container {
flex-direction: column;
position: absolute;
width: 80%;
max-width: 500px;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: 'Montserrat', sans-serif;
background: #1e1e1e;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404,
inset -2px -2px 2px rgba(255, 255, 255, 0.64),
inset 2px 2px 2px rgba(39, 39, 44, 0.56);
padding: 20px;
box-sizing: border-box;
}
.input-group {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
margin-top: 20px;
width: 100%;
}
.amount-input,
.category-input {
flex: 1 1 30%;
margin: 10px;
color: white;
min-width: 200px;
}
label {
margin-bottom: 5px;
}
input {
padding: 10px;
background-color: #1e1e1e;
border: none;
border-bottom: 1px solid #fafafa;
outline: none;
color: #ffffff;
width: 90%;
}
input:focus {
border-bottom: 1px solid #0056b3;
}
.button-group {
display: flex;
justify-content: space-between;
width: 80%;
margin: 20px auto;
}
.add-entry-1,
.add-entry-2 {
width: 150px;
height: 50px;
color: #fff;
background: #1e1e1e;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66),
8px 8px 16px #040404,
inset -2px -2px 2px rgba(4, 4, 4, 0.64),
inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.error-message{
color: red;
}
@media (max-width: 768px) {
.total-amount-container {
width: 90%;
top: 60%;
}
.input-group {
flex-direction: column;
}
.amount-input,
.category-input {
width: 100%;
margin: 10px 0;
}
.button-group {
flex-direction: column;
align-items: center;
}
.add-entry-1,
.add-entry-2 {
width: 100%;
margin: 10px 0;
}
}
@media (max-width: 480px) {
.total-amount-container {
/* padding: 15px; */
margin: 40px 0px ;
}
.add-entry-1,
.add-entry-2 {
font-size: 14px;
height: 40px;
}
}

View File

@ -0,0 +1,124 @@
import React, { useState, useEffect } from 'react';
import { useNavigate , useLocation } from 'react-router-dom';
import '../ExpenseAmount/TotalExpenseAmount.css';
function TotalExpenseAmount({ totalAmount, category, setCategory }) {
const [amount, setAmount] = useState(totalAmount || '');
const location = useLocation();
const { entryType } = location.state || {};
const [entries, setEntries] = useState([]);
const [categoryError, setCategoryError] = useState('');
const [categories, setCategories] = useState(["Hair", "Clothing", "Food", "Books", "Electronics", "Other"]);
const navigate = useNavigate();
useEffect(() => {
if (totalAmount !== undefined) {
setAmount(totalAmount);
}
}, [totalAmount]);
useEffect(() => {
const storedEntries = JSON.parse(localStorage.getItem('entries')) || [];
setEntries(storedEntries);
}, []);
const handleAddEntry = () => {
setCategoryError('');
if (amount <= 0) {
alert('Amount is required and must be greater than zero');
return null;
}
if (!category) {
setCategoryError('Category is required');
return null;
}
const now = new Date();
const formattedDateTime = now.toLocaleString();
const newEntry = {
id: Date.now(),
amount: parseFloat(amount),
category,
dateTime: formattedDateTime,
type: entryType
};
console.log(entryType)
if (!categories.includes(category)) {
setCategories([...categories, category]);
}
const updatedEntries = [...entries, newEntry];
if (updatedEntries.length > 5) {
updatedEntries.shift();
}
setEntries(updatedEntries);
localStorage.setItem('entries', JSON.stringify(updatedEntries));
setCategory('');
setAmount('');
return formattedDateTime;
};
const handleSaveEntry = () => {
const timestamp = handleAddEntry();
if (timestamp) {
navigate('/expense-totalsuccessfully', { state: { timestamp } });
}
};
const handleSaveAndAddEntry = () => {
const timestamp = handleAddEntry();
if (timestamp) {
navigate('/expense');
}
};
return (
<div className="total-amount-container">
<div className="input-group">
<div className="amount-input">
<label>Total:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter Amount"
/>
</div>
<div className="category-input">
<label>Category:</label>
<input
type="text"
value={category}
onChange={(e) => setCategory(e.target.value)}
placeholder="Add Category"
/>
{categoryError && <span className="error-message">{categoryError}</span>}
</div>
</div>
<div className="button-group">
<div className="add-entry-2" onClick={handleSaveEntry}>Save</div>
<div className="add-entry-1" onClick={handleSaveAndAddEntry}>Save & Add</div>
</div>
</div>
);
}
export default TotalExpenseAmount;

View File

@ -0,0 +1,158 @@
.category-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #1e1e1e;
color: white;
width: 100%;
padding: 10px;
}
.arrow {
position: absolute;
top: 10px;
left: 30px;
}
.arrow-icon {
font-size: 24px;
}
/*
.category-header {
display: flex;
align-items: center;
justify-content: center;
margin: 20px 0;
width: 100%;
text-align: center;
} */
.category-display {
margin: 30px;
width: 150px;
height: 30px;
/* left: calc(50% - 207px / 2 - 0.5px); */
top: 90px;
background: #1E1E1E;
box-shadow: 0px 0px 22.3px #00D092, 0px 0px 2.9px #FFFFFF, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
border-radius: 8px;
}
.category-titles {
font-size: 24px;
margin-right: 4px;
}
.category-icon {
width: 30px;
/* top: 10px; */
justify-content: center;
align-items: center;
/* margin: 2px; */
height: 30px;
}
.category-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
margin-top: 20px;
}
.cat-item {
background-color: #2a2a2a;
border-radius: 10px;
padding: 15px;
margin: 10px;
min-width: 120px;
text-align: center;
font-size: 18px;
transition: background-color 0.3s ease;
cursor: pointer;
}
.cat-item.selected {
background-color: #007BFF;
color: white;
border-radius: 5px;
}
.cat-item.selected {
background-color: #007bff;
color: #fff;
}
.texts {
width: 50%;
padding: 10px;
margin: 20px 0;
font-size: 16px;
border-bottom: 1px solid #fafafa;
outline: none;
color: #ffffff;
border-radius: 8px;
transition: border-color 0.3s ease, background-color 0.3s ease;
}
@media (max-width: 768px) {
.category-titles {
font-size: 20px;
}
.category-icon {
width: 35px;
margin: 10px;
height: 35px;
}
.cat-item {
min-width: 100px;
font-size: 16px;
}
}
@media (max-width: 480px) {
.arrow {
top: 40px;
left: 40px;
}
.category-titles {
font-size: 18px;
}
.category-icon {
width: 30px;
margin: 7px;
height: 30px;
}
.cat-item {
min-width: 80px;
font-size: 14px;
padding: 10px;
margin: 8px;
}
.category-container {
padding: 0px;
}
}

View File

@ -0,0 +1,109 @@
import React, { useEffect, useState } from 'react';
import { useOutletContext, useNavigate , useLocation} from 'react-router-dom';
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import categoryImage from '../../../../assets/category.png';
import '../ExpenseCategory/ExpenseCategory.css';
function ExpenseCategory() {
const navigate = useNavigate();
const [totalAmount, setTotalAmount, category, setCategory] = useOutletContext();
const [categories, setCategories] = useState(["Hair", "Clothing", "Food", "Books", "Electronics", "Other"]);
const [selectedCategories, setSelectedCategories] = useState([]);
const [customCategoryCount, setCustomCategoryCount] = useState(0);
const location = useLocation();
const entryType = location.state?.entryType;
const handleBackClick = () => {
navigate("/expense", { state: { entryType } });
console.log(entryType);
}
const handleCategorySelect = (selectedCategory) => {
if (selectedCategories.includes(selectedCategory)) {
const newSelectedCategories = selectedCategories.filter(cat => cat !== selectedCategory);
setSelectedCategories(newSelectedCategories);
setCategory(newSelectedCategories);
} else {
const newSelectedCategories = [...selectedCategories, selectedCategory];
setSelectedCategories(newSelectedCategories);
setCategory(newSelectedCategories);
}
};
const handleAddCategory = (newCategory) => {
if (!categories.includes(newCategory)) {
if (customCategoryCount < 3) {
const updatedCategories = [...categories, newCategory];
setCategories(updatedCategories);
setCustomCategoryCount(customCategoryCount + 1);
localStorage.setItem('categories', JSON.stringify(updatedCategories));
alert(`Category "${newCategory}" added!`);
} else {
alert('You can only add up to three custom categories!');
}
} else {
alert('Category already exists!');
}
};
useEffect(() => {
const savedCategories = JSON.parse(localStorage.getItem('categories'));
if (savedCategories) {
setCategories(savedCategories);
setCustomCategoryCount(savedCategories.filter(cat => !["Hair", "Clothing", "Food", "Books", "Electronics", "Other"].includes(cat)).length);
}
}, []);
return (
<div className='category-container'>
<div className="arrow">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<div className='category-display'>
<h3 className="category-titles">Categories</h3>
<img src={categoryImage} alt="categoryIcon" className="category-icon" />
</div>
<section className='category-list'>
{categories.map((cat, index) => (
<div
key={index}
className={`cat-item ${selectedCategories.includes(cat) ? 'selected' : ''}`}
onClick={() => handleCategorySelect(cat)}
>
{cat}
</div>
))}
</section>
{customCategoryCount < 3 && (
<input className='texts'
type="text"
placeholder="Add New Category"
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleAddCategory(e.target.value);
e.target.value = '';
}
}}
/>
)}
</div>
);
}
export default ExpenseCategory;

View File

@ -0,0 +1,160 @@
.expense-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
justify-content: center;
border-radius: 10px;
/* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */
text-align: center;
}
.arrow-container {
position: relative;
width: 100%;
text-align: center;
margin-bottom: 20px;
}
.arrow-icon {
position: absolute;
left: 0;
top: 50%;
margin: 40px 5px;
transform: translateY(-50%);
font-size: 24px;
color: #333;
cursor: pointer;
}
.expense-title {
font-size: 24px;
color: #fff;
margin: 0;
text-align: center;
margin-top: 10px;
}
.expense-date {
font-size: 14px;
color: #fff;
text-align: center;
margin: 10px;
}
.button-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
.amount-btn{
width: 37%;
/* max-width: 200px; */
padding: 15px;
font-weight: bold;
color: #fff;
border: none;
font-size: 18px;
border-radius: 8px;
margin: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.category-btn {
width: 37%;
/* max-width: 200px; */
padding: 15px;
font-weight: bold;
color: #fff;
border: none;
font-size: 18px;
border-radius: 8px;
margin: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.amount-btn {
background: #e335dc;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(139, 0, 134, 0.64),
inset 2px 2px 2px #e335dc;
}
.category-btn {
background-color: #00d092;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(35, 145, 35, 0.64),
inset 2px 2px 2px #4CAF50;
}
.category-icon {
width: 30px;
height: 30px;
margin-bottom: 10px;
}
@media (max-width: 600px) {
.arrow-icon {
font-size: 15px;
}
.expense-title {
font-size: 20px;
}
.expense-date {
font-size: 12px;
}
.button-container {
flex-direction: row;
align-items: center;
}
.amount-btn, .category-btn {
width: 80%;
max-width: none;
font-size: 15px;
padding: 10px;
}
.amount-icon, .category-icon {
width: 40px;
height: 40px;
margin: 2px;
}
}
@media (max-width: 1024px) {
.expense-container {
max-width: 100%;
}
.amount-btn,
.category-btn {
font-size: 18px;
}
}

View File

@ -0,0 +1,69 @@
import React, { useState, useEffect } from 'react';
import { useNavigate , useLocation} from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import '../ExpensePage/ExpensePage.css';
import amount from '../../../../assets/amount.png';
import category from '../../../../assets/category.png';
function ExpensePage() {
const navigate = useNavigate();
const location = useLocation();
const entryType = location.state?.entryType;
const handleAmountClick = () => {
navigate("/expenseAmount", { state: { entryType } });
};
const handleBackClick = () => {
navigate("/", { state: { entryType } });
};
const handleCategoryClick = () => {
navigate("/expenseCategory", { state: { entryType } });
};
const [currentDate, setCurrentDate] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setCurrentDate(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const options = { hour: '2-digit', minute: '2-digit', hour12: true };
const formattedDate = `on ${currentDate.toLocaleDateString()} - ${currentDate.toLocaleTimeString([], options)}`;
return (
<div className="income-container">
<div className="arrow-container">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<h4 className="income-title">Expense</h4>
<p className="income-date">{formattedDate}</p>
<div className="button-container">
<button className="amount-btn" onClick={handleAmountClick}>
<img src={amount} alt="Amount Icon" className="amount-icon" />
Amount
</button>
<button className="category-btn" onClick={handleCategoryClick}>
<img src={category} alt="Category Icon" className="category-icon" />
Category
</button>
</div>
</div>
);
}
export default ExpensePage;

View File

@ -0,0 +1,141 @@
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
color: white;
position: relative;
}
.back_arrows {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon {
font-size: 24px;
cursor: pointer;
}
.success-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.success-titles h1 {
color: #fff;
font-size: 30px;
margin: 10px 0;
text-align: center;
}
.success-datetime {
color: #fff;
font-size: 18px;
text-align: center;
}
.total-amount {
text-align: center;
font-size: 24px;
color: #4CAF50;
margin: 10px 0;
}
.categories {
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.categories h3 {
font-size: 15px;
color: #9e9696;
/* margin: 0px 0px 0px 0px; */
/* padding: 5px; */
}
.categories ul {
list-style-type: none;
padding: 5px;
}
.categories li {
font-size: 16px;
color: #deb1b1;
border-bottom: 1px solid #e0e0e0;
padding: 8px 0;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.success-titles h1 {
font-size: 24px;
}
.success-datetime {
font-size: 16px;
}
}
.total-amount {
color: #fff;
font-size: 12px;
margin: 20px 0;
}
.categories {
color: #fff;
font-size: 10px;
margin: 10px 0;
}
.success-buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn-home {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.btn-edit {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}

View File

@ -0,0 +1,104 @@
import React, { useEffect, useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import '../ExpenseRecords/ExpenseRecords.css';
function ExpenseRecords() {
const navigate = useNavigate();
const location = useLocation();
const [currentDateTime, setCurrentDateTime] = useState("");
const [totalAmount, setTotalAmount] = useState(0);
const [categories, setCategories] = useState([]);
const [entry, setEntry] = useState(null);
const [lastEntry, setLastEntry] = useState(null);
const { entryId } = location.state || {};
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
const storedEntries = JSON.parse(localStorage.getItem('entries')) || [];
if (entryId) {
const foundEntry = storedEntries.find((e) => e.id === entryId);
setEntry(foundEntry);
}
const lastEntryData = storedEntries[storedEntries.length - 1];
if (lastEntryData) {
setLastEntry(lastEntryData);
}
}, [entryId]);
useEffect(() => {
if (entry) {
setTotalAmount(parseFloat(entry.amount));
setCategories([entry.category]);
} else if (lastEntry) {
setTotalAmount(parseFloat(lastEntry.amount));
setCategories([lastEntry.category]);
}
}, [entry, lastEntry]);
const handleBackClick = () => {
navigate("/");
};
const handleEditClick = () => {
const idToEdit = entryId || (lastEntry ? lastEntry.id : null);
if (idToEdit) {
navigate("/expense-editPage", {
state: {
id: idToEdit,
amount: entry ? entry.amount : lastEntry.amount,
category: entry ? entry.category : lastEntry.category,
},
});
} else {
console.error("No entry found to edit.");
}
};
return (
<div className="container">
<div className="back_arrows">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<h1>Expense</h1>
<div className="success-datetime">
<p>{currentDateTime}</p>
</div>
<div className="total-amount">
<h2>Amount: {totalAmount.toFixed(2)}</h2>
<div className="categories">
<h3>Selected Categories:</h3>
<ul>
{categories.map((category, index) => (
<li key={index}>{category}</li>
))}
</ul>
</div>
</div>
<div className="success-buttons">
<div className="btn-home" onClick={handleBackClick}>Home</div>
<div className="btn-edit" onClick={handleEditClick}>Edit</div>
</div>
</div>
);
}
export default ExpenseRecords;

View File

@ -0,0 +1,187 @@
body {
background-color: #1E1E1E;
margin: 20px;
padding: 0;
font-family: Arial, sans-serif;
}
.Payment-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
}
.arrow {
font-size: 24px;
cursor: pointer;
}
.arr {
position: absolute;
top: 20px;
left: 20px;
}
.income-date {
color: #fff;
font-size: 18px;
text-align: center;
margin-bottom: 10px;
}
.payment-title {
text-align: center;
margin-bottom: 10px;
}
.payment-title h1 {
color: #fff;
font-size: 30px;
margin: 10px 0;
text-align: center;
}
.payment-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.payment-animation {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
.payment-message h2 {
color: #fff;
font-size: 24px;
text-align: center;
margin-bottom: 20px;
}
.payment-buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn1 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.bt_11 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
@media (max-width: 600px) {
.payment-title h1 {
font-size: 24px;
}
.income-date {
font-size: 16px;
}
.payment-message h2 {
font-size: 20px;
}
.btn1, .bt_11 {
width: 120px;
height: 50px;
font-size: 16px;
}
.arr {
top: 10px;
left: 10px;
}
}
@media (max-width: 1024px) {
.payment-title h1 {
font-size: 28px;
}
.income-date {
font-size: 16px;
}
.payment-message h2 {
font-size: 22px;
}
.btn1, .bt_11 {
width: 140px;
height: 55px;
font-size: 18px;
}
.arr {
top: 15px;
left: 15px;
}
}
@media (min-width: 1025px) {
.btn1, .bt_11 {
width: 160px;
height: 60px;
font-size: 18px;
}
.payment-title h1 {
font-size: 30px;
}
.payment-message h2 {
font-size: 24px;
}
}

View File

@ -0,0 +1,81 @@
import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { useNavigate } from "react-router-dom";
import { Player } from "@lottiefiles/react-lottie-player";
import successAnimation from "../Common/Animation - 1727464749500.json";
import "../ExpenseSuccessfully/ExpenseSuccessfully.css"
function ExpenseSuccessfully() {
const [currentDate, setCurrentDate] = useState(new Date());
const navigate = useNavigate();
useEffect(() => {
const timer = setInterval(() => {
setCurrentDate(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const handleBackClick = () => {
navigate("/expense-edit");
};
const handleBackToHome = () => {
navigate("/");
};
const handleBackToRecord = () => {
navigate("/expense-records")
}
const options = { hour: "2-digit", minute: "2-digit", hour12: true };
const formattedDate = `on ${currentDate.toLocaleDateString()} - ${currentDate.toLocaleTimeString(
[],
options
)}`;
return (
<div className="Payment-container">
<div className="payment-title">
<h1>Expense</h1>
<p className="income-date">{formattedDate}</p>
<div className="arr">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow"
onClick={handleBackClick}
/>
</div>
<div className="payment-content">
<div className="payment-animation">
<Player
autoplay
loop={false}
src={successAnimation}
style={{ height: "300px", width: "300px" }}
/>
</div>
<div className="payment-message">
<h2>Was successfully edited & recorded!</h2>
</div>
<div className="payment-buttons">
<div className="btn1" onClick={handleBackToHome}>
Home
</div>
<div className="bt_11" onClick={handleBackToRecord}>
Records
</div>
</div>
</div>
</div>
</div>
);
}
export default ExpenseSuccessfully;

View File

@ -0,0 +1,190 @@
.amount-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
margin: 0 auto;
font-family: 'Montserrat', sans-serif;
max-width: 500px;
background-color: #1e1e1e;
border-radius: 10px;
text-align: center;
}
.backarrow {
position: relative;
width: 100%;
text-align: center;
margin-bottom: 50px;
}
.arrowbtn {
position: absolute;
left: 0;
top: 50%;
margin: 30px 10px;
/* transform: translateY(-50%); */
font-size: 24px;
color: #333;
cursor: pointer;
}
.amount-titles {
font-size: 24px;
width: 100px;
color: #fff;
margin: 0 auto;
text-align: center;
flex-grow: 1;
}
.amount-display {
display: flex;
align-items: center;
justify-content: center;
background: #1E1E1E;
box-shadow: 0px 0px 22.3px #E335DC, 0px 0px 2.9px #FFFFFF, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
padding: 10px;
border-radius: 8px;
margin-bottom: 20px;
}
.total-amount {
font-size: 36px;
color: #fff;
margin-right: 10px;
}
.Rupeesicon {
width: 30px;
height: 30px;
}
.rupess_section {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin-top: 20px;
}
.coin {
width: 50px;
height: 50px;
background: #E335DC;
box-shadow: -10px -10px 12px rgba(50, 50, 51, 0.66), 10px 10px 16px #040404, inset -2px -2px 2px rgba(111, 0, 121, 0.64), inset 2px 2px 2px rgba(102, 0, 98, 0.56);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.3s ease;
/* border: 2px solid #fff; */
}
.coin-value {
font-size: 24px;
font-weight: bold;
color: #fff;
}
@media (max-width: 600px) {
.amount-container {
padding: 10px;
max-width: 100%;
}
.backarrow {
justify-content: space-between;
}
.arrowbtn {
position: absolute;
left: 0;
top: 50%;
margin: 33px 10px;
/* transform: translateX(-20%); */
font-size: 24px;
color: #333;
cursor: pointer;
}
.amount-titles {
font-size: 20px;
}
.rupess_section {
gap: 10px;
}
.coin {
width: 50px;
height: 50px;
padding: 25px;
}
.coin-value {
font-size: 26px;
}
.Rupeesicon {
width: 20px;
height: 20px;
}
.total-amount {
font-size: 28px;
}
.coin:hover {
background-color: #4caf50;
}
}
@media (min-width: 1024px) {
.amount-container {
max-width: 800px;
padding: 20px;
}
.coin {
width: 100px;
height: 100px;
}
.coin-value {
font-size: 20px;
}
.Rupeesicon {
width: 30px;
height: 30px;
padding: 10px;
}
.total-amount {
font-size: 40px;
}
}

View File

@ -0,0 +1,61 @@
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { useNavigate, useLocation , useOutletContext} from "react-router-dom";
import rupeeIcon from "../../../../assets/amount.png";
import "../Amount/AmountPage.css";
function AmountPage() {
const navigate = useNavigate();
const location = useLocation();
const { entryType } = location.state || {};
const [totalAmount, setTotalAmount] = useOutletContext();
const handleCoinClick = (amount) => {
setTotalAmount((prevAmount) => prevAmount + amount);
};
const handleBackClick = () => {
console.log(entryType);
navigate("/income", { state: { entryType } });
};
return (
<div className="amount-container">
<div className="backarrow">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrowbtn"
onClick={handleBackClick}
/>
</div>
<div className="amount-display">
<h3 className="amount-titles">Amount</h3>
<img src={rupeeIcon} alt="Rupee Icon" className="Rupeesicon" />
</div>
<section className="rupess_section">
<div className="coin" onClick={() => handleCoinClick(50)}>
<div className="coin-value">50</div>
</div>
<div className="coin" onClick={() => handleCoinClick(100)}>
<div className="coin-value">100</div>
</div>
<div className="coin" onClick={() => handleCoinClick(200)}>
<div className="coin-value">200</div>
</div>
<div className="coin" onClick={() => handleCoinClick(500)}>
<div className="coin-value">500</div>
</div>
<div className="coin" onClick={() => handleCoinClick(1000)}>
<div className="coin-value">1000</div>
</div>
</section>
</div>
);
}
export default AmountPage;

View File

@ -0,0 +1,92 @@
.entries-list-container {
background: #1e1e1e;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66),
8px 8px 16px #040404,
inset -2px -2px 2px rgba(4, 4, 4, 0.64),
inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
padding: 30px;
max-width: 1000px;
color: #fff;
margin: 20px auto;
}
.entries-list-container h3 {
font-size: medium;
font-weight: bolder;
font-family: 'Montserrat', sans-serif;
}
.entry-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 0;
border-bottom: 1px solid #ddd;
}
.entry-amount {
margin-left: 10px;
color: #4caf50;
font-weight: bold;
flex: 1;
text-align: left;
}
.entry-category {
margin-left: 10px;
font-weight: bolder;
flex: 1;
font-family: 'Montserrat', sans-serif;
color: #fff;
text-align: left;
}
.entry-input {
/* background-color: #333; */
/* border: 1px solid #ddd; */
border-bottom: 1px solid #ddd;
color: #fff;
padding: 5px;
border-radius: 5px;
margin-right: 10px;
flex: 1;
}
/* Entry icons container */
.entry-icons {
display: flex;
align-items: center;
}
.entry-repeat-icon,
.entry-edit-icon,
.entry-save-icon,
.entry-cancel-icon {
color: #fff;
margin-left: 10px;
cursor: pointer;
transition: color 0.3s ease;
}
.entry-repeat-icon:hover {
color: #4caf50;
}
.entry-edit-icon:hover {
color: #ff9800;
}
.entry-save-icon:hover {
color: #4caf50;
}
.entry-cancel-icon:hover {
color: #ff4d4d;
}

View File

@ -0,0 +1,138 @@
import React, { useState, useEffect } from "react";
import "./EntriesList.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faRedoAlt, faEdit, faSave, faTimes } from "@fortawesome/free-solid-svg-icons";
import { useNavigate } from "react-router-dom";
import Modal from '../Common/Model';
function EntriesList() {
const navigate = useNavigate();
const [entries, setEntries] = useState([]);
const [editingEntryId, setEditingEntryId] = useState(null);
const [editedAmount, setEditedAmount] = useState("");
const [editedCategory, setEditedCategory] = useState("");
const [repeatEntry, setRepeatEntry] = useState(null);
const [isDialogOpen, setIsDialogOpen] = useState(false);
useEffect(() => {
const storedEntries = JSON.parse(localStorage.getItem("entries")) || [];
setEntries(storedEntries.slice(-5));
}, []);
const handleRedoClick = (entry) => {
setRepeatEntry(entry);
setIsDialogOpen(true);
};
const handleEditClick = (entry) => {
setEditingEntryId(entry.id);
setEditedAmount(entry.amount);
setEditedCategory(entry.category);
};
const handleSaveClick = (entry) => {
const updatedEntries = entries.map((e) =>
e.id === entry.id ? { ...e, amount: editedAmount, category: editedCategory } : e
);
setEntries(updatedEntries);
localStorage.setItem("entries", JSON.stringify(updatedEntries));
setEditingEntryId(null);
};
const handleCancelClick = () => {
setEditingEntryId(null);
};
const handleDialogClose = (confirmed) => {
setIsDialogOpen(false);
if (confirmed && repeatEntry) {
const newEntry = {
id: new Date().getTime(),
amount: repeatEntry.amount,
category: repeatEntry.category,
type: repeatEntry.type, // Ensure type is included
};
const updatedEntries = [...entries, newEntry];
setEntries(updatedEntries);
localStorage.setItem("entries", JSON.stringify(updatedEntries));
// Navigate based on entry type
if (repeatEntry.type === "income") {
navigate("/totalsuccessfully", { state: { entryId: newEntry.id } });
} else {
navigate("/expense-totalsuccessfully", { state: { entryId: newEntry.id } });
}
} else {
navigate("/");
}
setRepeatEntry(null);
};
return (
<div className="entries-list-container">
<h4>Previous Last Five Transactions:</h4>
{entries.length === 0 ? (
<p>No transaction data available</p>
) : (
entries.map((entry, index) => (
<div key={index} className="entry-item">
<span>{index + 1}.</span>
{editingEntryId === entry.id ? (
<>
<input
type="text"
value={editedAmount}
onChange={(e) => setEditedAmount(e.target.value)}
className="entry-input"
/>
<input
type="text"
value={editedCategory}
onChange={(e) => setEditedCategory(e.target.value)}
className="entry-input"
/>
<FontAwesomeIcon
icon={faSave}
className="entry-save-icon"
onClick={() => handleSaveClick(entry)}
/>
<FontAwesomeIcon
icon={faTimes}
className="entry-cancel-icon"
onClick={handleCancelClick}
/>
</>
) : (
<>
<span className="entry-amount">{entry.amount}</span>
<span className="entry-category">{entry.category}</span>
<div className="entry-icons">
<FontAwesomeIcon
icon={faRedoAlt}
className="entry-repeat-icon"
onClick={() => handleRedoClick(entry)}
/>
<FontAwesomeIcon
icon={faEdit}
className="entry-edit-icon"
onClick={() => handleEditClick(entry)}
/>
</div>
</>
)}
</div>
))
)}
<Modal
isOpen={isDialogOpen}
onClose={() => handleDialogClose(false)}
onConfirm={() => handleDialogClose(true)}
/>
</div>
);
}
export default EntriesList;

View File

@ -0,0 +1,121 @@
.total-amount-container {
flex-direction: column;
position: absolute;
width: 80%;
max-width: 500px;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: 'Montserrat', sans-serif;
background: #1e1e1e;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404,
inset -2px -2px 2px rgba(255, 255, 255, 0.64),
inset 2px 2px 2px rgba(39, 39, 44, 0.56);
padding: 20px;
box-sizing: border-box;
}
.input-group {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
margin-top: 20px;
width: 100%;
}
.amount-input,
.category-input {
flex: 1 1 30%;
margin: 10px;
color: white;
min-width: 200px;
}
label {
margin-bottom: 5px;
}
input {
padding: 10px;
background-color: #1e1e1e;
border: none;
border-bottom: 1px solid #fafafa;
outline: none;
color: #ffffff;
width: 90%;
}
input:focus {
border-bottom: 1px solid #0056b3;
}
.button-group {
display: flex;
justify-content: space-between;
width: 80%;
margin: 20px auto;
}
.add-entry-1,
.add-entry-2 {
width: 150px;
height: 50px;
color: #fff;
background: #1e1e1e;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66),
8px 8px 16px #040404,
inset -2px -2px 2px rgba(4, 4, 4, 0.64),
inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.error-message{
color: red;
}
@media (max-width: 768px) {
.total-amount-container {
width: 90%;
top: 60%;
}
.input-group {
flex-direction: column;
}
.amount-input,
.category-input {
width: 100%;
margin: 10px 0;
}
.button-group {
flex-direction: column;
align-items: center;
}
.add-entry-1,
.add-entry-2 {
width: 100%;
margin: 10px 0;
}
}
@media (max-width: 480px) {
.total-amount-container {
/* padding: 15px; */
margin: 40px 0px ;
}
.add-entry-1,
.add-entry-2 {
font-size: 14px;
height: 40px;
}
}

View File

@ -0,0 +1,120 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import './TotalAmount.css';
function TotalAmount({ totalAmount, category, setCategory }) {
const [amount, setAmount] = useState(totalAmount || '');
const location = useLocation();
const { entryType } = location.state || {};
const [entries, setEntries] = useState([]);
const [categoryError, setCategoryError] = useState('');
const [categories, setCategories] = useState(["Hair", "Clothing", "Food", "Books", "Electronics", "Other"]);
const navigate = useNavigate();
useEffect(() => {
if (totalAmount !== undefined) {
setAmount(totalAmount);
}
}, [totalAmount]);
useEffect(() => {
const storedEntries = JSON.parse(localStorage.getItem('entries')) || [];
setEntries(storedEntries);
}, []);
const handleAddEntry = () => {
setCategoryError('');
if (amount <= 0) {
alert('Amount is required and must be greater than zero');
return null;
}
if (!category) {
setCategoryError('Category is required');
return null;
}
const now = new Date();
const formattedDateTime = now.toLocaleString();
const newEntry = {
id: Date.now(),
amount: parseFloat(amount),
category,
dateTime: formattedDateTime,
type: entryType
};
console.log(entryType)
if (!categories.includes(category)) {
setCategories([...categories, category]);
}
const updatedEntries = [...entries, newEntry];
if (updatedEntries.length > 5) {
updatedEntries.shift();
}
setEntries(updatedEntries);
localStorage.setItem('entries', JSON.stringify(updatedEntries));
// Reset input fields
setCategory('');
setAmount('');
return formattedDateTime;
};
const handleSaveEntry = () => {
const timestamp = handleAddEntry();
if (timestamp) {
navigate('/totalsuccessfully', { state: { timestamp } });
}
};
const handleSaveAndAddEntry = () => {
const timestamp = handleAddEntry();
if (timestamp) {
navigate('/income');
}
};
return (
<div className="total-amount-container">
<div className="input-group">
<div className="amount-input">
<label>Total:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter Amount"
/>
</div>
<div className="category-input">
<label>Category:</label>
<input
type="text"
value={category}
onChange={(e) => setCategory(e.target.value)}
placeholder="Add Category"
/>
{categoryError && <span className="error-message">{categoryError}</span>}
</div>
</div>
<div className="button-group">
<div className="add-entry-2" onClick={handleSaveEntry}>Save</div>
<div className="add-entry-1" onClick={handleSaveAndAddEntry}>Save & Add</div>
</div>
</div>
);
}
export default TotalAmount;

View File

@ -0,0 +1,166 @@
.category-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #1e1e1e;
color: white;
width: 100%;
font-family: 'Montserrat', sans-serif;
padding: 10px;
}
.arrow {
position: absolute;
top: 10px;
left: 30px;
}
.arrow-icon {
font-size: 24px;
right: 85px;
bottom: 40px;
}
/*
.category-header {
display: flex;
align-items: center;
justify-content: center;
margin: 20px 0;
width: 100%;
text-align: center;
} */
.category-display {
margin: 40px;
width: 10px;
height: 30px;
/* left: calc(50% - 207px / 2 - 0.5px); */
top: 90px;
background: #1E1E1E;
box-shadow: 0px 0px 22.3px #00D092, 0px 0px 2.9px #FFFFFF, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
border-radius: 8px;
}
.category-titles {
font-size: 24px;
color: #fff;
margin-right: 4px;
}
.category-icon {
width: 30px;
/* top: 10px; */
justify-content: center;
align-items: center;
/* margin: 2px; */
height: 30px;
}
.category-list {
display: flex;
flex-wrap: wrap;
justify-content: center;
width: 100%;
margin-top: 20px;
}
.cat-item {
background-color: #2a2a2a;
border-radius: 10px;
padding: 15px;
margin: 10px;
min-width: 120px;
text-align: center;
font-size: 18px;
transition: background-color 0.3s ease;
cursor: pointer;
}
.cat-item.selected {
background-color: #007BFF;
color: white;
border-radius: 5px;
}
.cat-item.selected {
background-color: #007bff;
color: #fff;
}
.texts {
width: 50%;
padding: 10px;
margin: 20px 0;
font-size: 16px;
border-bottom: 1px solid #fafafa;
outline: none;
color: #ffffff;
border-radius: 8px;
transition: border-color 0.3s ease, background-color 0.3s ease;
}
/* Mobile responsiveness */
@media (max-width: 768px) {
.category-titles {
font-size: 20px;
}
.category-container {
margin: 10px;
}
.category-icon {
width: 35px;
margin: 10px;
height: 35px;
}
.cat-item {
min-width: 100px;
font-size: 16px;
}
}
@media (max-width: 480px) {
.arrow {
top: 30px;
left: 10px;
}
.category-titles {
font-size: 18px;
}
.category-icon {
width: 30px;
margin: 7px;
height: 30px;
}
.cat-item {
min-width: 80px;
font-size: 14px;
padding: 10px;
margin: 8px;
}
.category-container {
padding: 0px;
}
}

View File

@ -0,0 +1,105 @@
import React, { useEffect, useState } from 'react';
import { useOutletContext, useNavigate, useLocation } from 'react-router-dom';
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import categoryImage from '../../../../assets/category.png';
import '../Category/Category.css';
function Category() {
const navigate = useNavigate();
const [totalAmount, setTotalAmount, category, setCategory] = useOutletContext();
const [categories, setCategories] = useState(["Hair", "Clothing", "Food", "Books", "Electronics", "Other"]);
const [selectedCategories, setSelectedCategories] = useState([]);
const [customCategoryCount, setCustomCategoryCount] = useState(0);
const location = useLocation();
const entryType = location.state?.entryType;
const handleBackClick = () => {
navigate("/income", { state: { entryType } });
console.log(entryType);
}
const handleCategorySelect = (selectedCategory) => {
if (selectedCategories.includes(selectedCategory)) {
const newSelectedCategories = selectedCategories.filter(cat => cat !== selectedCategory);
setSelectedCategories(newSelectedCategories);
setCategory(newSelectedCategories);
} else {
const newSelectedCategories = [...selectedCategories, selectedCategory];
setSelectedCategories(newSelectedCategories);
setCategory(newSelectedCategories);
}
};
const handleAddCategory = (newCategory) => {
if (!categories.includes(newCategory)) {
if (customCategoryCount < 3) {
const updatedCategories = [...categories, newCategory];
setCategories(updatedCategories);
setCustomCategoryCount(customCategoryCount + 1);
localStorage.setItem('categories', JSON.stringify(updatedCategories));
alert(`Category "${newCategory}" added!`);
} else {
alert('You can only add up to three custom categories!');
}
} else {
alert('Category already exists!');
}
};
useEffect(() => {
const savedCategories = JSON.parse(localStorage.getItem('categories'));
if (savedCategories) {
setCategories(savedCategories);
setCustomCategoryCount(savedCategories.filter(cat => !["Hair", "Clothing", "Food", "Books", "Electronics", "Other"].includes(cat)).length);
}
}, []);
return (
<div className='category-container'>
<div className="arrow">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<div className='category-display'>
<h3 className="category-titles">Categories</h3>
<img src={categoryImage} alt="categoryIcon" className="category-icon" />
</div>
<section className='category-list'>
{categories.map((cat, index) => (
<div
key={index}
className={`cat-item ${selectedCategories.includes(cat) ? 'selected' : ''}`}
onClick={() => handleCategorySelect(cat)}
>
{cat}
</div>
))}
</section>
{customCategoryCount < 3 && (
<input className='texts'
type="text"
placeholder="Add New Category"
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleAddCategory(e.target.value);
e.target.value = '';
}
}}
/>
)}
</div>
);
}
export default Category;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,30 @@
.footer {
position: fixed; /* Keep the footer at the bottom */
bottom: 0;
left: 0;
font-family: 'Montserrat', sans-serif;
width: 100%;
background-color: #1e1e1e; /* Match the background color */
color: white;
text-align: center;
padding: 10px 0; /* Space around the text */
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.5);
}
.footer-content {
max-width: 1200px; /* Limit the width on larger screens */
margin: 0 auto; /* Center the footer content */
}
.footer p {
margin: 0; /* Remove default margins */
font-size: 1rem; /* Adjust font size as needed */
}
/* Responsive styling */
@media (max-width: 768px) {
.footer p {
font-size: 0.9rem; /* Smaller font size for mobile */
}
}

View File

@ -0,0 +1,14 @@
import React from 'react';
import './Footer.css';
function Footer() {
return (
<footer className="footer">
<div className="footer-content">
<p> Humbingo Consultancy Services LLP All rights reserved.</p>
</div>
</footer>
);
}
export default Footer;

View File

@ -0,0 +1,124 @@
.incomeedit-containers {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
font-family: 'Montserrat', sans-serif;
}
.backIcon {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon {
font-size: 24px;
cursor: pointer;
}
.edit-content {
padding: 20px;
border-radius: 8px;
/* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); */
width: 100%;
max-width: 400px;
}
.edit-titles h1 {
color: #fff;
font-size: 30px;
margin: 0px 0;
text-align: center;
}
.edit-datetime {
color: #fff;
font-size: 18px;
text-align: center;
margin-bottom: 10px;
}
.edit-fields {
color: #fff;
margin-bottom: 15px;
width: 93%;
}
.edit-fields label {
display: block;
margin-bottom: 9px;
}
.edit-fields input {
width: 100%;
padding: 10px;
border: 1px solid #555;
border-radius: 4px;
background-color: #3A3A3A;
color: #fff;
font-size: 16px;
}
/* Button styling */
.edit-buttons {
display: flex;
justify-content: center;
margin-top: 30px;
width: 100%;
}
.edit-btn {
/* item */
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.edit-btn-2 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
@media (max-width: 768px) {
.edit-titles h1 {
font-size: 24px;
}
.edit-datetime {
font-size: 16px;
}
.edit-buttons div {
font-size: 14px;
}
}

View File

@ -0,0 +1,102 @@
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import "../Common/IncomeEdit.css";
function IncomeEdit() {
const location = useLocation();
const navigate = useNavigate();
const [currentDateTime, setCurrentDateTime] = useState("");
const [amount, setAmount] = useState(location.state?.amount || "");
const [category, setCategory] = useState(location.state?.category || "");
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
}, []);
const handleBackClick = () => {
navigate("/records");
};
const handleSave = () => {
setIsLoading(true);
setError(null);
const updatedEntry = {
id: location.state?.id,
amount: amount,
dateTime: currentDateTime,
category: category,
};
const storedEntries = JSON.parse(localStorage.getItem("entries")) || [];
const updatedEntries = storedEntries.map((entry) =>
entry.id === updatedEntry.id ? updatedEntry : entry
);
localStorage.setItem("entries", JSON.stringify(updatedEntries));
// Optionally, you can navigate to a success page or display a message here
console.log("Entry updated in local storage:", updatedEntry);
navigate("/successPage");
setIsLoading(false); // End loading
};
return (
<div className="incomeedit-containers">
<div className="backIcon">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<div className="edit-content">
<div className="edit-titles">
<h1>Edit Income</h1>
<div className="edit-datetime">
<p>{currentDateTime}</p>
</div>
</div>
{error && <p className="error-message">{error}</p>}
<div className="edit-fields">
<label>Amount:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
</div>
<div className="edit-fields">
<label>Category:</label>
<input
type="text"
value={category}
onChange={(e) => setCategory(e.target.value)}
/>
</div>
<div className="edit-buttons">
<div className="edit-btn" onClick={handleBackClick}>
Cancel
</div>
<div className="edit-btn-2" onClick={handleSave}>
{isLoading ? "Saving..." : "Save"}
</div>
</div>
</div>
</div>
);
}
export default IncomeEdit;

View File

@ -0,0 +1,10 @@
.layout-container {
display: flex;
flex-direction: column;
min-height: 100vh;
font-family: 'Montserrat', sans-serif;
}

View File

@ -0,0 +1,22 @@
import React, { useState } from 'react';
import { Outlet } from 'react-router-dom';
import TotalAmount from '../Amount/TotalAmount';
import './Layout.css';
const Layout = () => {
const [totalAmount, setTotalAmount] = useState(0);
const [category, setCategory] = useState('');
return (
<div className="layout-container">
<div className="page-content">
<Outlet context={[totalAmount, setTotalAmount, category, setCategory]} />
</div>
<TotalAmount totalAmount={totalAmount} category={category} setCategory={setCategory} />
</div>
);
};
export default Layout;

View File

@ -0,0 +1,67 @@
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
font-family: 'Montserrat', sans-serif;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
font-family: 'Montserrat', sans-serif;
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
text-align: center;
max-width: 400px;
width: 90%;
}
h3 {
color: #218838;
}
.modal-actions {
margin-top: 20px;
}
.modal-button {
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
padding: 10px 20px;
margin: 0 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.modal-button:hover {
background-color: #0056b3;
}
.modal-button.confirm {
background-color: #28a745;
}
.modal-button.confirm:hover {
background-color: #218838;
}
@media (max-width: 600px) {
.modal-content {
width: 250px;
max-width: 90%;
}
}

View File

@ -0,0 +1,20 @@
import React from 'react';
import '../Common/Model.css';
const Modal = ({ isOpen, onClose, onConfirm }) => {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal-content">
<h3>Are you sure you want to repeat this transaction?</h3>
<div className="modal-actions">
<button className="modal-button" onClick={onClose}>No</button>
<button className="modal-button confirm" onClick={onConfirm}>Yes</button>
</div>
</div>
</div>
);
};
export default Modal;

View File

@ -0,0 +1,117 @@
.Succesfully-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Montserrat', sans-serif;
position: relative;
}
.arrows {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon-1 {
font-size: 24px;
cursor: pointer;
}
.success-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.success-animation {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
.success-title h1 {
color: #fff;
font-size: 30px;
margin-top: 10px;
text-align: center;
}
.success-message h2 {
color: #fff;
font-size: 24px;
text-align: center;
margin-bottom: 10px;
}
.success-button {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn-view {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.btn-back {
position: relative;
width: 120px;
height: 40px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.success-date-time {
color: #fff;
}
@media (max-width: 768px) {
.btn-view,
.btn-back {
padding: 12px 20px;
font-size: 16px;
}
}
@media (max-width: 768px) {
.success-message h2 {
font-size: 20px;
}
.success-title h1 {
font-size: 24px;
}
}

View File

@ -0,0 +1,85 @@
import React, { useEffect, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { Player } from "@lottiefiles/react-lottie-player";
import successAnimation from "./Animation - 1727464749500.json";
import "./TotalSuccessfully.css";
function TotalSuccessfully() {
const navigate = useNavigate();
const location = useLocation();
const [currentDateTime, setCurrentDateTime] = useState("");
const { entryId } = location.state || {};
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
const dataToStore = {
incomeRecord: {
dateTime: formattedDateTime,
entryId: entryId || "Not provided",
},
};
console.log(JSON.stringify(dataToStore));
}, [entryId]);
const handleBackClick = () => {
navigate("/");
};
const handleViewRecordsClick = () => {
navigate("/records", { state: { entryId } });
console.log(entryId);
};
return (
<div className="Succesfully-container">
<div className="arrows">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon-1"
onClick={handleBackClick}
/>
</div>
<div className="success-title">
<h1>Income</h1>
<div className="success-date-time">
<p>{currentDateTime}</p>
</div>
</div>
<div className="success-content">
<div className="success-animation">
<Player
autoplay
loop={false}
src={successAnimation}
style={{ height: "300px", width: "300px" }}
/>
</div>
<div className="success-message">
<h2>Was successfully recorded!</h2>
</div>
<div className="success-button">
<div className="btn-back" onClick={handleBackClick}>
Home
</div>
<div className="btn-view" onClick={handleViewRecordsClick}>
Records
</div>
</div>
</div>
</div>
);
}
export default TotalSuccessfully;

View File

@ -0,0 +1,132 @@
.main-container {
max-width: 700px;
margin: 0 auto;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.title {
font-size: 24px;
margin-bottom: 20px;
font-family: 'Montserrat', sans-serif;
color: #fff;
}
.buttons {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 600px;
margin-bottom: 30px;
}
.expense-btn, .income-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 48%;
padding: 15px;
font-family: 'Montserrat', sans-serif;
font-size: 18px;
font-weight: bold;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.expense-btn {
background: #e335dc;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(139, 0, 134, 0.64),
inset 2px 2px 2px #e335dc;
}
.income-btn {
background-color: #00d092;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(35, 145, 35, 0.64),
inset 2px 2px 2px #4CAF50;
}
.expense-icon, .economic-crisis-icon {
width: 40px;
height: 40px;
margin-bottom: 10px;
}
@media (max-width: 600px) {
.main-container {
padding: 15px;
}
.title {
font-size: 20px;
}
.buttons {
flex-direction: row;
align-items: center;
/* justify-content: space-between; */
gap: 14px;
}
.expense-btn {
width: 100%;
margin-bottom: 15px;
padding: 10px;
font-size: 16px; background: #e335dc;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(139, 0, 134, 0.64),
inset 2px 2px 2px #e335dc;
}
.income-btn{
width: 100%;
margin-bottom: 15px;
padding: 10px;
background-color: #00d092;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(35, 145, 35, 0.64),
inset 2px 2px 2px #4CAF50;
}
.expense-icon, .economic-crisis-icon {
width: 40px;
height: 40px;
}
}
@media (max-width: 1024px) {
.main-container {
max-width: 100%;
padding: 0px;
/* change padding */
}
.buttons {
max-width: 100%;
}
.expense-btn, .income-btn {
font-size: 18px;
}
}

View File

@ -0,0 +1,50 @@
// Home.js
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import '../Income/Home.css';
import expense from '../../../assets/expenses.png';
import economic from '../../../assets/economic-crisis.png';
import EntriesList from '../Income/Amount/EntriesList';
function Home() {
const navigate = useNavigate();
const [entries, setEntries] = useState([]);
const [entryType, setEntryType] = useState('');
useEffect(() => {
const storedEntries = JSON.parse(localStorage.getItem('entries')) || [];
setEntries(storedEntries);
}, []);
const handleIncomeClick = () => {
setEntryType('income');
console.log(entryType)
navigate('/income', { state: { entryType: 'income' } });
};
const handleExpenseClick = () => {
setEntryType('expense');
console.log(entryType)
navigate('/expense', { state: { entryType: 'expense' } });
}
return (
<div className="main-container">
<h4 className="title">Add Transaction</h4>
<div className="buttons">
<button className="expense-btn" onClick={handleExpenseClick}>
<img src={expense} alt="Expense Icon" className="expense-icon" />
Expense
</button>
<button className="income-btn" onClick={handleIncomeClick}>
<img src={economic} alt="Economic Crisis Icon" className="economic-crisis-icon" />
Income
</button>
</div>
<EntriesList entries={entries} />
</div>
);
}
export default Home;

View File

@ -0,0 +1,168 @@
/* IncomePage.css */
/* Main container */
.income-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
justify-content: center;
border-radius: 10px;
/* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */
text-align: center;
}
.arrow-container {
position: relative;
width: 100%;
text-align: center; /* Center the title and date */
margin-bottom: 20px;
}
/* Arrow icon */
.arrow-icon {
position: absolute;
left: 0; /* Place the arrow on the left */
top: 50%;
margin: 40px 5px;
transform: translateY(-50%);
font-size: 24px;
color: #333;
cursor: pointer;
}
/* Title */
.income-title {
font-size: 24px;
color: #fff;
margin: 0;
font-family: 'Montserrat', sans-serif;
text-align: center;
margin-top: 10px;
}
/* Date and time */
.income-date {
font-size: 14px;
color: #fff;
font-family: 'Montserrat', sans-serif;
text-align: center; /* Center the date */
margin: 10px;
}
/* Button container */
.button-container {
display: flex;
font-family: 'Montserrat', sans-serif;
justify-content: center;
margin-top: 20px;
}
.amount-btn{
width: 37%;
/* max-width: 200px; */
padding: 15px;
font-weight: bold;
color: #fff;
border: none;
font-size: 18px;
border-radius: 8px;
margin: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
display: flex;
font-family: 'Montserrat', sans-serif;
flex-direction: column;
align-items: center;
justify-content: center;
}
.category-btn {
width: 37%;
/* max-width: 200px; */
padding: 15px;
font-weight: bold;
color: #fff;
border: none;
font-family: 'Montserrat', sans-serif;
font-size: 18px;
border-radius: 8px;
margin: 10px;
cursor: pointer;
transition: background-color 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.amount-btn {
background: #e335dc;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(139, 0, 134, 0.64),
inset 2px 2px 2px #e335dc;
}
.category-btn {
background-color: #00d092;
box-shadow: -8px -8px 12px rgba(39, 39, 44, 0.48),
8px 8px 16px rgba(4, 4, 4, 0.8),
inset -2px -2px 2px rgba(35, 145, 35, 0.64),
inset 2px 2px 2px #4CAF50;
}
/* Icons in buttons */
.category-icon {
width: 30px;
height: 30px;
margin-bottom: 10px;
}
/* Responsive styling */
/* Mobile-specific styles */
@media (max-width: 600px) {
.arrow-icon {
font-size: 15px;
}
.expense-title {
font-size: 20px;
}
.expense-date {
font-size: 12px;
}
.button-container {
flex-direction: row;
align-items: center;
}
.amount-btn, .category-btn {
width: 80%;
max-width: none;
font-size: 15px;
padding: 10px;
}
.amount-icon, .category-icon {
width: 40px;
height: 40px;
margin: 2px;
}
}
/* Tablet-specific styles */
@media (max-width: 1024px) {
.expense-container {
max-width: 100%;
}
.amount-btn,
.category-btn {
font-size: 18px;
}
}

View File

@ -0,0 +1,67 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import './IncomePage.css';
import amount from '../../../../assets/amount.png';
import category from '../../../../assets/category.png';
function IncomePage() {
const navigate = useNavigate();
const location = useLocation();
const entryType = location.state?.entryType;
const handleAmountClick = () => {
navigate("/amount", { state: { entryType } });
};
const handleBackClick = () => {
navigate("/", { state: { entryType } });
}
const handleCategoryClick = () => {
navigate("/category", { state: { entryType } });
};
const [currentDate, setCurrentDate] = useState(new Date());
useEffect(() => {
const timer = setInterval(() => {
setCurrentDate(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const options = { hour: '2-digit', minute: '2-digit', hour12: true };
const formattedDate = `on ${currentDate.toLocaleDateString()} - ${currentDate.toLocaleTimeString([], options)}`;
return (
<div className="income-container">
<div className="arrow-container">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<h4 className="income-title">Income</h4>
<p className="income-date">{formattedDate}</p>
<div className="button-container">
<button className="amount-btn" onClick={handleAmountClick}>
<img src={amount} alt="Amount Icon" className="amount-icon" />
Amount
</button>
<button className="category-btn" onClick={handleCategoryClick}>
<img src={category} alt="Category Icon" className="category-icon" />
Category
</button>
</div>
</div>
);
}
export default IncomePage;

View File

@ -0,0 +1,187 @@
body {
background-color: #1E1E1E;
margin: 20px;
padding: 0;
font-family: Arial, sans-serif;
}
.Payment-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
position: relative;
}
.arrow {
font-size: 24px;
cursor: pointer;
}
.arr {
position: absolute;
top: 20px;
left: 20px;
}
.income-date {
color: #fff;
font-size: 18px;
text-align: center;
margin-bottom: 10px;
}
.payment-title {
text-align: center;
margin-bottom: 10px;
}
.payment-title h1 {
color: #fff;
font-size: 30px;
margin: 10px 0;
text-align: center;
}
.payment-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.payment-animation {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10px;
}
.payment-message h2 {
color: #fff;
font-size: 24px;
text-align: center;
margin-bottom: 20px;
}
.payment-buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn1 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.bt_11 {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
@media (max-width: 600px) {
.payment-title h1 {
font-size: 24px;
}
.income-date {
font-size: 16px;
}
.payment-message h2 {
font-size: 20px;
}
.btn1, .bt_11 {
width: 120px;
height: 50px;
font-size: 16px;
}
.arr {
top: 10px;
left: 10px;
}
}
@media (max-width: 1024px) {
.payment-title h1 {
font-size: 28px;
}
.income-date {
font-size: 16px;
}
.payment-message h2 {
font-size: 22px;
}
.btn1, .bt_11 {
width: 140px;
height: 55px;
font-size: 18px;
}
.arr {
top: 15px;
left: 15px;
}
}
@media (min-width: 1025px) {
.btn1, .bt_11 {
width: 160px;
height: 60px;
font-size: 18px;
}
.payment-title h1 {
font-size: 30px;
}
.payment-message h2 {
font-size: 24px;
}
}

View File

@ -0,0 +1,81 @@
import React, { useEffect, useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import { useNavigate } from "react-router-dom";
import { Player } from "@lottiefiles/react-lottie-player";
import successAnimation from "../Common/Animation - 1727464749500.json";
import "../Income/IncomeSuccessfully.css";
function IncomeSuccessfully() {
const [currentDate, setCurrentDate] = useState(new Date());
const navigate = useNavigate();
useEffect(() => {
const timer = setInterval(() => {
setCurrentDate(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const handleBackClick = () => {
navigate("/editPage");
};
const handleBackToHome = () => {
navigate("/");
};
const handleBackToRecord = () => {
navigate("/records")
}
const options = { hour: "2-digit", minute: "2-digit", hour12: true };
const formattedDate = `on ${currentDate.toLocaleDateString()} - ${currentDate.toLocaleTimeString(
[],
options
)}`;
return (
<div className="Payment-container">
<div className="payment-title">
<h1>Income</h1>
<p className="income-date">{formattedDate}</p>
<div className="arr">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow"
onClick={handleBackClick}
/>
</div>
<div className="payment-content">
<div className="payment-animation">
<Player
autoplay
loop={false}
src={successAnimation}
style={{ height: "300px", width: "300px" }}
/>
</div>
<div className="payment-message">
<h2>Was successfully edited & recorded!</h2>
</div>
<div className="payment-buttons">
<div className="btn1" onClick={handleBackToHome}>
Home
</div>
<div className="bt_11" onClick={handleBackToRecord}>
Records
</div>
</div>
</div>
</div>
</div>
);
}
export default IncomeSuccessfully;

View File

@ -0,0 +1,143 @@
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: 'Montserrat', sans-serif;
height: 100vh;
color: white;
position: relative;
}
.back_arrows {
position: absolute;
top: 20px;
left: 20px;
}
.arrow-icon {
font-size: 24px;
cursor: pointer;
}
.success-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.success-titles h1 {
color: #fff;
font-size: 30px;
margin: 10px 0;
text-align: center;
}
.success-datetime {
color: #fff;
font-size: 18px;
text-align: center;
}
.total-amount h2 {
font-size: 24px;
color: #4CAF50;
margin: 10px 0;
}
.categories {
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.categories h3 {
font-size: 15px;
color: #9e9696;
/* margin: 0px 0px 0px 0px; */
/* padding: 5px; */
}
.categories ul {
list-style-type: none;
padding: 5px;
}
.categories li {
font-size: 16px;
color: #deb1b1;
border-bottom: 1px solid #e0e0e0;
padding: 8px 0;
}
@media (max-width: 768px) {
.success-titles h1 {
font-size: 24px;
}
.success-datetime {
font-size: 16px;
}
}
.total-amount {
text-align: center;
font-size: 24px;
color: #4CAF50;
margin: 10px 0;
}
.categories {
color: #fff;
font-size: 10px;
margin: 10px 0;
}
.success-buttons {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 20px;
}
.btn-home {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.btn-edit {
position: relative;
width: 150px;
height: 60px;
color: #fff;
justify-content: center;
align-items: center;
background: #1E1E1E;
box-shadow: -8px -8px 12px rgba(50, 50, 51, 0.66), 8px 8px 16px #040404, inset -2px -2px 2px rgba(4, 4, 4, 0.64), inset 2px 2px 2px rgba(39, 39, 44, 0.56);
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}

View File

@ -0,0 +1,105 @@
import React, { useEffect, useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons";
import '../Records/Records.css';
function Records() {
const navigate = useNavigate();
const location = useLocation();
const [currentDateTime, setCurrentDateTime] = useState("");
const [totalAmount, setTotalAmount] = useState(0);
const [categories, setCategories] = useState([]);
const [entry, setEntry] = useState(null);
const [lastEntry, setLastEntry] = useState(null);
const { entryId } = location.state || {};
useEffect(() => {
const now = new Date();
const formattedDateTime = now.toLocaleString();
setCurrentDateTime(formattedDateTime);
const storedEntries = JSON.parse(localStorage.getItem('entries')) || [];
if (entryId) {
const foundEntry = storedEntries.find((e) => e.id === entryId);
setEntry(foundEntry);
}
const lastEntryData = storedEntries[storedEntries.length - 1];
if (lastEntryData) {
setLastEntry(lastEntryData);
}
}, [entryId]);
useEffect(() => {
if (entry) {
setTotalAmount(parseFloat(entry.amount));
setCategories([entry.category]);
} else if (lastEntry) {
setTotalAmount(parseFloat(lastEntry.amount));
setCategories([lastEntry.category]);
}
}, [entry, lastEntry]);
const handleBackClick = () => {
navigate("/totalsuccessfully");
};
const handleEditClick = () => {
const idToEdit = entryId || (lastEntry ? lastEntry.id : null);
if (idToEdit) {
navigate("/editpage", {
state: {
id: idToEdit,
amount: entry ? entry.amount : lastEntry.amount,
category: entry ? entry.category : lastEntry.category,
},
});
} else {
console.error("No entry found to edit.");
}
};
return (
<div className="container">
<div className="back_arrows">
<FontAwesomeIcon
icon={faArrowLeft}
style={{ cursor: "pointer", color: "#fff" }}
className="arrow-icon"
onClick={handleBackClick}
/>
</div>
<div className="success-datetime">
<h1>Income</h1>
<p>{currentDateTime}</p>
</div>
<div className="total-amount">
<h2>Amount: {totalAmount.toFixed(2)}</h2>
<div className="categories">
<h3>Selected Categories:</h3>
<ul>
{categories.map((category, index) => (
<li key={index}>{category}</li>
))}
</ul>
</div>
</div>
<div className="success-buttons">
<div className="btn-home" onClick={handleBackClick}>Home</div>
<div className="btn-edit" onClick={handleEditClick}>Edit</div>
</div>
</div>
);
}
export default Records;

13
src/index.css Normal file
View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

17
src/index.js Normal file
View File

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

1
src/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

13
src/reportWebVitals.js Normal file
View File

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

5
src/setupTests.js Normal file
View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';