diff --git a/.gitignore b/.gitignore index 4d29575..61ef65f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +bun.lock +bun.lockb diff --git a/package.json b/package.json index 89282b5..49490c5 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,14 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^13.5.0", + "bootstrap": "^5.3.7", + "chart.js": "^4.5.0", + "faker": "^6.6.6", "react": "^19.1.0", + "react-bootstrap": "^2.10.10", + "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", + "react-router-dom": "^7.7.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.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); - } -} diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 3784575..0000000 --- a/src/App.js +++ /dev/null @@ -1,25 +0,0 @@ -import logo from './logo.svg'; -import './App.css'; - -function App() { - return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); -} - -export default App; diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..d1b9bc5 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,38 @@ +import "./css/App.css"; +import NavigationBar from "./components/NavigationBar/NavigationBar"; +import { useTheme } from "./contexts/ThemeContext"; +import { useEffect } from "react"; +import Transactions from "./pages/Transactions"; +import Home from "./pages/Home"; +import { + BrowserRouter as Router, + Routes, + Route, + Navigate, +} from "react-router-dom"; +// import { Container } from "react-bootstrap"; +import NotFound from "./pages/NotFound"; + +function App() { + const { theme } = useTheme(); + + useEffect(() => { + document.body.setAttribute("data-bs-theme", theme); + }, [theme]); + + return ( + + + <> + + } /> + } /> + } /> + } /> + + + + ); +} + +export default App; diff --git a/src/components/AppointmentDashboard/AppointmentDashboard.jsx b/src/components/AppointmentDashboard/AppointmentDashboard.jsx new file mode 100644 index 0000000..e68052a --- /dev/null +++ b/src/components/AppointmentDashboard/AppointmentDashboard.jsx @@ -0,0 +1,167 @@ +import { Card, Accordion, ProgressBar } from "react-bootstrap"; + +const AppointmentDashboard = ({ ...props }) => { + return ( + <> + + +

+ Appointment +

+ + + +
+
😀
+
+
+
+

+ Cash loan +

+

+ 21531,00 ₽ +

+
+
+ +
+ 75% +
+
+
+
+ +
+
+
➞
+
+
+
+

+ Cash loan +

+

+ 21531,00 ₽ +

+
+
+ +
+ 100% +
+
+
+
+
+
+
+
➞
+
+
+
+

+ Cash loan +

+

+ 21531,00 ₽ +

+
+
+ +
+ 100% +
+
+
+
+
+
+
+
+ {/*
+
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
*/} +
+
+ + ); +}; +export default AppointmentDashboard; diff --git a/src/components/BalanceBlock/BalanceBlock.jsx b/src/components/BalanceBlock/BalanceBlock.jsx new file mode 100644 index 0000000..d1b4907 --- /dev/null +++ b/src/components/BalanceBlock/BalanceBlock.jsx @@ -0,0 +1,26 @@ +import React from "react"; +import { Card } from "react-bootstrap"; +import AddOperationModal from "../../modals/AddOperationModal/AddOperationModal"; + +const BalanceBlock = ({ balance }) => { + return ( + + +
+
+ Balance +
+

+ 40 407,17 ₽ +

+
+ +
+
+ ); +}; + +export default BalanceBlock; diff --git a/src/components/FinancialDashboard/FinancialDashboard.jsx b/src/components/FinancialDashboard/FinancialDashboard.jsx new file mode 100644 index 0000000..e0a4f86 --- /dev/null +++ b/src/components/FinancialDashboard/FinancialDashboard.jsx @@ -0,0 +1,121 @@ +import React from "react"; +import { Card, Col } from "react-bootstrap"; +import { Bar } from "react-chartjs-2"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Tooltip, +} from "chart.js"; +// import { useTheme } from "../../contexts/ThemeContext"; +import styles from "./FinancialDashboard.module.css"; + +ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip); + +const FinancialDashboard = ({ + chartData, + chartOptions, + maxValue, + LeftCardData, + RightCardData, +}) => { + // const { theme } = useTheme(); + // const [incomedata, setIncomeData] = useState(income); + // const [expensesdata, setExpensesData] = useState(expenses); + + return ( +
+ {/* Карточка с диаграммой */} + + +
+ + + +
+
+
+

+ {LeftCardData.value.toLocaleString("ru-RU", { + minimumFractionDigits: 2, + })}{" "} + ₽ +

+
+
+
+ {LeftCardData.label} +
+ + + + + + +
+
+
+

+ {RightCardData.value.toLocaleString("ru-RU", { + minimumFractionDigits: 2, + })}{" "} + ₽ +

+
+
+
+ {RightCardData.label} +
+ + + +
+ + {/* Контейнер для диаграммы */} +
+ +
+
+
+
+ ); +}; + +export default FinancialDashboard; diff --git a/src/components/FinancialDashboard/FinancialDashboard.module.css b/src/components/FinancialDashboard/FinancialDashboard.module.css new file mode 100644 index 0000000..fbb56d9 --- /dev/null +++ b/src/components/FinancialDashboard/FinancialDashboard.module.css @@ -0,0 +1,13 @@ +.chartContainer { + margin: 0; + height: 200px; + width: auto; + position: relative; + margin-bottom: 0; +} + +@media (max-width: 768px) { + .chartContainer { + height: 100px; + } +} diff --git a/src/components/NavigationBar/NavigationBar.jsx b/src/components/NavigationBar/NavigationBar.jsx new file mode 100644 index 0000000..1fa9177 --- /dev/null +++ b/src/components/NavigationBar/NavigationBar.jsx @@ -0,0 +1,18 @@ +import React from "react"; +import Navbar from "react-bootstrap/Navbar"; +import SettingsModal from "../../modals/SettingsModal/SettingsModal"; + +const NavigationBar = () => { + return ( + + Wallet + + + ); +}; + +export default NavigationBar; diff --git a/src/components/NavigationBar/NavigationBar.module.css b/src/components/NavigationBar/NavigationBar.module.css new file mode 100644 index 0000000..e69de29 diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx new file mode 100644 index 0000000..449ad07 --- /dev/null +++ b/src/components/ThemeToggle.jsx @@ -0,0 +1,25 @@ +import React from "react"; +import { Form, Row, Col } from "react-bootstrap"; +import { useTheme } from "../contexts/ThemeContext"; + +const ThemeToggle = () => { + const { theme, toggleTheme } = useTheme(); + + return ( + <> + + Dark Mode + + + + + + ); +}; + +export default ThemeToggle; diff --git a/src/contexts/ThemeContext.js b/src/contexts/ThemeContext.js new file mode 100644 index 0000000..71ba751 --- /dev/null +++ b/src/contexts/ThemeContext.js @@ -0,0 +1,35 @@ +import React, { createContext, useState, useEffect, useContext } from "react"; + +const ThemeContext = createContext(); + +export const ThemeProvider = ({ children }) => { + const [theme, setTheme] = useState(() => { + if (typeof window !== "undefined") { + const savedTheme = localStorage.getItem("theme"); + const systemPreferDark = window.matchMedia( + "(prefers-color-scheme: dark)", + ).matches; + return savedTheme || (systemPreferDark ? "dark" : "light"); + } + return "light"; + }); + + useEffect(() => { + if (typeof window !== "undefined") { + document.body.setAttribute("data-bs-theme", theme); + localStorage.setItem("theme", theme); + } + }, [theme]); + + const toggleTheme = () => { + setTheme((prev) => (prev === "light" ? "dark" : "light")); + }; + + return ( + + {children} + + ); +}; + +export const useTheme = () => useContext(ThemeContext); diff --git a/src/css/App.css b/src/css/App.css new file mode 100644 index 0000000..5c79a4d --- /dev/null +++ b/src/css/App.css @@ -0,0 +1,36 @@ +/* src/App.css */ +body[data-bs-theme="dark"] { + background-color: #121212; + color: #f8f9fa; + .modal-content { + background-color: #121212 !important; + } + .nav-link.active { + background-color: #121212 !important; + } +} + +body[data-bs-theme="light"] { + background-color: #f8f9fa; + color: #212529; +} + +.progress { + border-radius: 20px; +} + +.progress-bar { + border-radius: 20px; +} + +.accordion-button { + padding: 10px !important; +} + +.accordion-body { + padding: 0 10px !important; +} + +hr { + margin: 0 !important; +} diff --git a/src/css/index.css b/src/css/index.css new file mode 100644 index 0000000..4363b68 --- /dev/null +++ b/src/css/index.css @@ -0,0 +1,19 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + 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; +} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -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; -} diff --git a/src/index.js b/src/index.js index d563c0f..059eed5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,25 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./css/index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; +import "bootstrap/dist/css/bootstrap.min.css"; +import { ThemeProvider } from "./contexts/ThemeContext"; -const root = ReactDOM.createRoot(document.getElementById('root')); +const savedTheme = + localStorage.getItem("theme") || + (window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"); +document.body.setAttribute("data-bs-theme", savedTheme); + +const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - - + + + + , ); // If you want to start measuring performance in your app, pass a function diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/modals/AddOperationModal/AddOperationModal.jsx b/src/modals/AddOperationModal/AddOperationModal.jsx new file mode 100644 index 0000000..fb6bdf7 --- /dev/null +++ b/src/modals/AddOperationModal/AddOperationModal.jsx @@ -0,0 +1,194 @@ +import { useState } from "react"; +import { useTheme } from "../../contexts/ThemeContext"; +import { + ListGroup, + Modal, + Button, + Card, + Form, + Row, + Col, +} from "react-bootstrap"; +// import styles from "./HistoryModal.module.css"; + +const AddOperationModal = ({ variant }) => { + const { theme } = useTheme(); + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + const [isIncome, setIsIncome] = useState(false); + const [isExpense, setIsExpense] = useState(true); + const [isNoteVisible, setIsNoteVisible] = useState(false); + const [amount, setAmount] = useState(); + return ( + <> + {variant ? ( + + ) : ( + + )} + + + + Add operation + + + +
+

+ Amount +

+
+ setAmount(e.target.value)} + /> + +
+
+ + +
+
+
+

+ Appointment +

+ +
+ + +
+ ADDITIONAL +
+ + + + Date + + + + + + + + Tag + + + + + + + + + Note + + setIsNoteVisible(!isNoteVisible)} + /> + + + + + + + + + + Repeat payment + + + + + + + +
+
+
+
+ + ); +}; +export default AddOperationModal; diff --git a/src/modals/AnalyticsModal/AnalyticsModal.jsx b/src/modals/AnalyticsModal/AnalyticsModal.jsx new file mode 100644 index 0000000..f93193d --- /dev/null +++ b/src/modals/AnalyticsModal/AnalyticsModal.jsx @@ -0,0 +1,185 @@ +import { useState } from "react"; +import { useTheme } from "../../contexts/ThemeContext"; +import { Tabs, Tab, Modal, Button } from "react-bootstrap"; +import FinancialDashboard from "../../components/FinancialDashboard/FinancialDashboard"; +import AppointmentDashboard from "../../components/AppointmentDashboard/AppointmentDashboard"; +import styles from "./AnalyticsModal.module.css"; + +const AnalyticsModal = () => { + const { theme } = useTheme(); + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + + // const income = 40407.17; + const expenses = 39985.23; + + const monthdata = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 141, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 2, 29, 30, 31, + ]; + + const monthMaxValue = Math.max(...monthdata); + + const MonthChartData = { + labels: [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + ], + datasets: [ + { + data: monthdata, + backgroundColor: "#3576C3", + categoryPercentage: 0.5, + borderRadius: 3, + responsive: true, + }, + ], + }; + + const MonthLeftCardData = { + label: "Total for the period", + value: expenses, + }; + + const MonthRightCardData = { + label: "Daily average", + value: expenses / monthdata.length, + }; + + const MonthChartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + display: false, + beginAtZero: true, + max: monthMaxValue * 1.1, + }, + x: { + grid: { + display: false, + drawBorder: false, + }, + ticks: { + color: "#6b7280", + font: { + size: 12, + weight: "500", + }, + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + // enabled: true, + callbacks: { + // title: function (context) { + // // Customize the tooltip title + // return `${context[0].label}`; + // }, + label: function (context) { + // Customize the tooltip label + let label = context.dataset.label || ""; + if (label) { + label += ": "; + } + if (context.parsed.y !== null) { + label += `${context.parsed.y} ₽`; + } + return label; + }, + }, + }, + }, + }; + return ( + <> + + + + + + Analytics + + + + + + +
+
+

+ July 2025 +

+
+ Period: month +
+
+
+
+
+ + +
+
+
+
+
+ + ); +}; +export default AnalyticsModal; diff --git a/src/modals/AnalyticsModal/AnalyticsModal.module.css b/src/modals/AnalyticsModal/AnalyticsModal.module.css new file mode 100644 index 0000000..8626f1c --- /dev/null +++ b/src/modals/AnalyticsModal/AnalyticsModal.module.css @@ -0,0 +1,11 @@ +.scrollableContent { + height: calc(100vh - 220px); + bottom: 0; + overflow-y: auto; +} + +@media (max-width: 768px) { + .scrollableContent { + height: calc(100vh - 280px); + } +} diff --git a/src/modals/HistoryModal/HistoryModal.jsx b/src/modals/HistoryModal/HistoryModal.jsx new file mode 100644 index 0000000..29ef4de --- /dev/null +++ b/src/modals/HistoryModal/HistoryModal.jsx @@ -0,0 +1,652 @@ +import { useState } from "react"; +import { useTheme } from "../../contexts/ThemeContext"; +import { ListGroup, Tabs, Tab, Modal, Button } from "react-bootstrap"; +import styles from "./HistoryModal.module.css"; +import AddOperationModal from "../AddOperationModal/AddOperationModal"; + +const HistoryModal = () => { + const { theme } = useTheme(); + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + return ( + <> + + + + + + History + + {/* */} + + + + +
+
+
+

+ 25 Jul 2025 +

+
+
+ Income: 0,00 ₽ +
+
+ Expense: 0,00 ₽ +
+
+
+
+ + +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
🗼
+
+
+

+ 18000 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+
+
+
+

+ 25 Jul 2025 +

+
+
+ Income: 0,00 ₽ +
+
+ Expense: 0,00 ₽ +
+
+
+
+ + +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
🗼
+
+
+

+ 18000 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+
+
+
+

+ 25 Jul 2025 +

+
+
+ Income: 0,00 ₽ +
+
+ Expense: 0,00 ₽ +
+
+
+
+ + +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
🗼
+
+
+

+ 18000 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+
+
+
+

+ 25 Jul 2025 +

+
+
+ Income: 0,00 ₽ +
+
+ Expense: 0,00 ₽ +
+
+
+
+ + +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
🗼
+
+
+

+ 18000 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+ +
+
+
😀
+
+
+

+ -63.00 ₽ +

+
+ Transport +
+
+ Note +
+
+
+
+ 09:14 +
+
+
+
+
+
+
+ + + +
+
+
+ + ); +}; +export default HistoryModal; diff --git a/src/modals/HistoryModal/HistoryModal.module.css b/src/modals/HistoryModal/HistoryModal.module.css new file mode 100644 index 0000000..4e8181a --- /dev/null +++ b/src/modals/HistoryModal/HistoryModal.module.css @@ -0,0 +1,10 @@ +.scrollableContent { + height: calc(100vh - 220px); + overflow-y: auto; +} + +@media (max-width: 768px) { + .scrollableContent { + height: calc(100vh - 240px); + } +} diff --git a/src/modals/SettingsModal/SettingsModal.jsx b/src/modals/SettingsModal/SettingsModal.jsx new file mode 100644 index 0000000..d2ae274 --- /dev/null +++ b/src/modals/SettingsModal/SettingsModal.jsx @@ -0,0 +1,52 @@ +import { useState } from "react"; +import { useTheme } from "../../contexts/ThemeContext"; +import { ListGroup, Modal, Button } from "react-bootstrap"; +import ThemeToggle from "../../components/ThemeToggle"; + +const SettingsModal = () => { + const { theme } = useTheme(); + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + const handleShow = () => setShow(true); + return ( + <> + + + + + +

Settings

+
+ +
+ + + + + + + +
+ + ); +}; +export default SettingsModal; diff --git a/src/modals/SettingsModal/SettingsModal.module.css b/src/modals/SettingsModal/SettingsModal.module.css new file mode 100644 index 0000000..4e8181a --- /dev/null +++ b/src/modals/SettingsModal/SettingsModal.module.css @@ -0,0 +1,10 @@ +.scrollableContent { + height: calc(100vh - 220px); + overflow-y: auto; +} + +@media (max-width: 768px) { + .scrollableContent { + height: calc(100vh - 240px); + } +} diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx new file mode 100644 index 0000000..2104fe6 --- /dev/null +++ b/src/pages/Home.jsx @@ -0,0 +1,110 @@ +import FinancialDashboard from "../components/FinancialDashboard/FinancialDashboard"; +import { Row, Col } from "react-bootstrap"; +import HistoryModal from "../modals/HistoryModal/HistoryModal"; +import AnalyticsModal from "../modals/AnalyticsModal/AnalyticsModal"; +import BalanceBlock from "../components/BalanceBlock/BalanceBlock"; + +const Home = () => { + const weeklyData = [63, 63, 63, 63, 63, 63, 63]; + const weeklyData1 = [20, 80, 50, 100, 1800, 60, 90]; + const weeklyMaxValue = Math.max(...weeklyData, ...weeklyData1); + const chartData = { + labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + datasets: [ + { + data: weeklyData, + backgroundColor: "#3576C3", + categoryPercentage: 0.5, + borderRadius: 3, + responsive: true, + }, + { + data: weeklyData1, + backgroundColor: "#38393F", + categoryPercentage: 0.5, + borderRadius: 3, + responsive: true, + }, + ], + }; + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + display: false, + beginAtZero: true, + max: weeklyMaxValue * 1.1, + }, + x: { + grid: { + display: false, + drawBorder: false, + }, + ticks: { + color: "#6b7280", + font: { + size: 12, + weight: "500", + }, + }, + }, + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + callbacks: { + label: function (context) { + let label = context.dataset.label || ""; + if (label) { + label += ": "; + } + if (context.parsed.y !== null) { + label += + `${weeklyData[context.dataIndex]}₽ ` + + `${weeklyData1[context.dataIndex]}₽`; + } + return label; + }, + }, + }, + }, + }; + const income = 40407.17; + const expenses = 39985.23; + + const LeftCardData = { + label: "Monthly Icome", + value: income, + }; + + const RightCardData = { + label: "Monthly Expenses", + value: expenses, + }; + + return ( + <> + + + + + + + + + + + + ); +}; + +export default Home; diff --git a/src/pages/NotFound.jsx b/src/pages/NotFound.jsx new file mode 100644 index 0000000..140525c --- /dev/null +++ b/src/pages/NotFound.jsx @@ -0,0 +1,14 @@ +import { Alert, Button } from "react-bootstrap"; +import { Link } from "react-router-dom"; + +const NotFound = () => ( + + 404 - Page Not Found +

The page you're looking for doesn't exist.

+ +
+); + +export default NotFound; diff --git a/src/pages/Transactions.jsx b/src/pages/Transactions.jsx new file mode 100644 index 0000000..c1ad67d --- /dev/null +++ b/src/pages/Transactions.jsx @@ -0,0 +1,9 @@ +const Transactions = () => { + return ( + <> +

Welcome to transactions

+ + ); +}; + +export default Transactions;