" project commit "
|
@ -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*
|
|
@ -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)
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
|
||||
]
|
After Width: | Height: | Size: 3.8 KiB |
|
@ -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>
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 9.4 KiB |
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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();
|
||||
});
|
After Width: | Height: | Size: 832 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.9 KiB |
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,10 @@
|
|||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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;
|
|
@ -0,0 +1,10 @@
|
|||
.layout-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
|
@ -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%;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
|
@ -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 |
|
@ -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;
|
|
@ -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';
|