From d03c197b4ba40ff7d817b33c4ba459f8a0f3900f Mon Sep 17 00:00:00 2001
From: naomimariuta <157979968+naomimariuta@users.noreply.github.com>
Date: Mon, 4 Nov 2024 03:20:23 +0200
Subject: [PATCH] transactions and currency
---
package-lock.json | 171 ++++++++++
package.json | 3 +
src/Pages/CurrencyTab/CurrencyTab.jsx | 261 ++++++++++++++-
src/Pages/CurrencyTab/CurrencyTab.module.css | 169 ++++++++++
src/Pages/DashboardPage/DashboardPage.jsx | 1 -
.../DashboardPage/DashboardPage.module.css | 10 +-
src/Pages/Home/Home.jsx | 76 ++++-
src/Pages/Home/Home.module.css | 76 ++++-
.../transactionAction.jsx | 6 -
.../transactionsReducer.jsx | 22 --
.../AddTransactionForm/AddTransactionForm.jsx | 4 +-
.../AddTransactionForm/customStyles.js | 7 +-
src/components/App/App.jsx | 32 +-
src/components/Balance/Balance.jsx | 30 +-
src/components/Balance/Balance.module.css | 52 ++-
.../ButtonAddTransactions.modules.css | 4 +-
src/components/ButtonForm/ButtonForm.jsx | 32 ++
.../ButtonForm/ButtonForm.module.css | 80 +++++
src/components/Currency/Currency.jsx | 311 ++++++++++++++++--
src/components/Currency/Currency.module.css | 181 ++++++++--
.../EditTransactionForm.jsx | 249 ++++++++++----
.../EditTransactionForm.module.css | 256 ++++++++++++--
src/components/Logo/Logo.jsx | 20 ++
src/components/Logo/Logo.module.css | 58 ++++
.../ModalDeleteTransaction.jsx | 88 +++++
.../ModalDeleteTransaction.module.css | 106 ++++++
.../ModalEditTransaction.jsx | 62 ++--
.../ModalEditTransaction.module.css | 115 +++++--
.../TransactionsDesktop.jsx | 63 ++++
.../TransactionsDesktop.module.css | 58 ++++
.../TransactionsDesktopRow.jsx | 105 ++++++
.../TransactionsDesktopRow.module.css | 97 ++++++
.../TransactionsItem/TransactionsItem.jsx | 119 +++++--
.../TransactionsItem.module.css | 148 +++++++--
.../TransactionsList/TransactionsList.jsx | 74 ++---
.../TransactionsList.module.css | 37 +--
src/components/common/allCategories.js | 150 +++++++++
.../common/formatNumberWithSpaces.js | 19 ++
src/components/common/useCurrency.js | 50 +++
src/components/images/icons/sprite.svg | 77 +++++
src/redux/Statistics/operations.js | 1 +
src/redux/Statistics/slice.js | 8 +-
src/redux/operations/authOperations.js | 14 +
.../operations/transactionsOperations.js | 34 +-
src/redux/selectors/authSelectors.js | 1 +
src/redux/selectors/transactionsSelector.js | 20 +-
src/redux/slices/AuthSlice.jsx | 45 ++-
src/redux/slices/GlobalSlice.jsx | 18 +
src/redux/slices/transactionsSlice.js | 84 ++---
49 files changed, 3194 insertions(+), 510 deletions(-)
create mode 100644 src/Pages/CurrencyTab/CurrencyTab.module.css
delete mode 100644 src/actions pentru test doar/transactionAction.jsx
delete mode 100644 src/actions pentru test doar/transactionsReducer.jsx
create mode 100644 src/components/ButtonForm/ButtonForm.jsx
create mode 100644 src/components/ButtonForm/ButtonForm.module.css
create mode 100644 src/components/Logo/Logo.jsx
create mode 100644 src/components/Logo/Logo.module.css
create mode 100644 src/components/ModalDeleteTransaction/ModalDeleteTransaction.jsx
create mode 100644 src/components/ModalDeleteTransaction/ModalDeleteTransaction.module.css
create mode 100644 src/components/TransactionsDesktop/TransactionsDesktop.jsx
create mode 100644 src/components/TransactionsDesktop/TransactionsDesktop.module.css
create mode 100644 src/components/TransactionsDesktopRow/TransactionsDesktopRow.jsx
create mode 100644 src/components/TransactionsDesktopRow/TransactionsDesktopRow.module.css
create mode 100644 src/components/common/allCategories.js
create mode 100644 src/components/common/formatNumberWithSpaces.js
create mode 100644 src/components/common/useCurrency.js
create mode 100644 src/components/images/icons/sprite.svg
diff --git a/package-lock.json b/package-lock.json
index f66569c..d0c16e8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@chakra-ui/react": "^3.0.1",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
+ "@hookform/resolvers": "^3.9.1",
"@reduxjs/toolkit": "^2.3.0",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
@@ -23,6 +24,7 @@
"react-chartjs-2": "^5.2.0",
"react-datepicker": "^7.5.0",
"react-dom": "^18.3.1",
+ "react-hook-form": "^7.53.1",
"react-icons": "^5.3.0",
"react-loader-spinner": "^6.1.6",
"react-modal": "^3.16.1",
@@ -31,6 +33,7 @@
"react-responsive": "^10.0.0",
"react-router-dom": "^6.27.0",
"react-scripts": "5.0.1",
+ "react-select": "^5.8.2",
"react-toastify": "^10.0.6",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
@@ -3305,6 +3308,15 @@
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==",
"license": "MIT"
},
+ "node_modules/@hookform/resolvers": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.1.tgz",
+ "integrity": "sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-hook-form": "^7.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.9.5",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
@@ -4524,6 +4536,15 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.11",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
+ "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -9283,6 +9304,16 @@
"utila": "~0.4"
}
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
@@ -13095,6 +13126,12 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/memoize-one": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
+ "license": "MIT"
+ },
"node_modules/merge-descriptors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
@@ -15394,6 +15431,22 @@
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==",
"license": "MIT"
},
+ "node_modules/react-hook-form": {
+ "version": "7.53.1",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.1.tgz",
+ "integrity": "sha512-6aiQeBda4zjcuaugWvim9WsGqisoUk+etmFEsSUMm451/Ic8L/UAb7sRtMj3V+Hdzm6mMjU1VhiSzYUZeBm0Vg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18 || ^19"
+ }
+ },
"node_modules/react-icons": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
@@ -15622,6 +15675,27 @@
}
}
},
+ "node_modules/react-select": {
+ "version": "5.8.2",
+ "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.2.tgz",
+ "integrity": "sha512-a/LkOckoI62710gGPQSQqUp7A10fGbH/ya3/IR49qaq3XoBvwymgD5mJgtiHxBDsutyEQfdKNycWVh8Cg8UCjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.0",
+ "@emotion/cache": "^11.4.0",
+ "@emotion/react": "^11.8.1",
+ "@floating-ui/dom": "^1.0.1",
+ "@types/react-transition-group": "^4.4.0",
+ "memoize-one": "^6.0.0",
+ "prop-types": "^15.6.0",
+ "react-transition-group": "^4.3.0",
+ "use-isomorphic-layout-effect": "^1.1.2"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react-toastify": {
"version": "10.0.6",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.6.tgz",
@@ -15635,6 +15709,22 @@
"react-dom": ">=18"
}
},
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -17570,6 +17660,20 @@
"requires-port": "^1.0.0"
}
},
+ "node_modules/use-isomorphic-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
@@ -21015,6 +21119,12 @@
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz",
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="
},
+ "@hookform/resolvers": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.1.tgz",
+ "integrity": "sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==",
+ "requires": {}
+ },
"@humanwhocodes/config-array": {
"version": "0.9.5",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
@@ -21923,6 +22033,14 @@
"@types/react": "*"
}
},
+ "@types/react-transition-group": {
+ "version": "4.4.11",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
+ "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -25801,6 +25919,15 @@
"utila": "~0.4"
}
},
+ "dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "requires": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
@@ -28542,6 +28669,11 @@
"fs-monkey": "^1.0.4"
}
},
+ "memoize-one": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
+ },
"merge-descriptors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
@@ -30044,6 +30176,12 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
},
+ "react-hook-form": {
+ "version": "7.53.1",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.1.tgz",
+ "integrity": "sha512-6aiQeBda4zjcuaugWvim9WsGqisoUk+etmFEsSUMm451/Ic8L/UAb7sRtMj3V+Hdzm6mMjU1VhiSzYUZeBm0Vg==",
+ "requires": {}
+ },
"react-icons": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
@@ -30192,6 +30330,22 @@
"workbox-webpack-plugin": "^6.4.1"
}
},
+ "react-select": {
+ "version": "5.8.2",
+ "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.2.tgz",
+ "integrity": "sha512-a/LkOckoI62710gGPQSQqUp7A10fGbH/ya3/IR49qaq3XoBvwymgD5mJgtiHxBDsutyEQfdKNycWVh8Cg8UCjw==",
+ "requires": {
+ "@babel/runtime": "^7.12.0",
+ "@emotion/cache": "^11.4.0",
+ "@emotion/react": "^11.8.1",
+ "@floating-ui/dom": "^1.0.1",
+ "@types/react-transition-group": "^4.4.0",
+ "memoize-one": "^6.0.0",
+ "prop-types": "^15.6.0",
+ "react-transition-group": "^4.3.0",
+ "use-isomorphic-layout-effect": "^1.1.2"
+ }
+ },
"react-toastify": {
"version": "10.0.6",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.6.tgz",
@@ -30200,6 +30354,17 @@
"clsx": "^2.1.0"
}
},
+ "react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "requires": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ }
+ },
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
@@ -31584,6 +31749,12 @@
"requires-port": "^1.0.0"
}
},
+ "use-isomorphic-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
+ "requires": {}
+ },
"use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
diff --git a/package.json b/package.json
index 459c47f..af58f9a 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"@chakra-ui/react": "^3.0.1",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
+ "@hookform/resolvers": "^3.9.1",
"@reduxjs/toolkit": "^2.3.0",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
@@ -19,6 +20,7 @@
"react-chartjs-2": "^5.2.0",
"react-datepicker": "^7.5.0",
"react-dom": "^18.3.1",
+ "react-hook-form": "^7.53.1",
"react-icons": "^5.3.0",
"react-loader-spinner": "^6.1.6",
"react-modal": "^3.16.1",
@@ -27,6 +29,7 @@
"react-responsive": "^10.0.0",
"react-router-dom": "^6.27.0",
"react-scripts": "5.0.1",
+ "react-select": "^5.8.2",
"react-toastify": "^10.0.6",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
diff --git a/src/Pages/CurrencyTab/CurrencyTab.jsx b/src/Pages/CurrencyTab/CurrencyTab.jsx
index 95a1081..a2ab82d 100644
--- a/src/Pages/CurrencyTab/CurrencyTab.jsx
+++ b/src/Pages/CurrencyTab/CurrencyTab.jsx
@@ -1,12 +1,267 @@
-import Currency from '../../components/Currency/Currency';
import React from 'react';
import { useMediaQuery } from 'react-responsive';
+import styles from './CurrencyTab.module.css';
+import useCurrency from 'components/common/useCurrency';
+import Loader from 'components/Loader/Loader';
const CurrencyTab = () => {
- const isDesktopOrLaptop = useMediaQuery({
+ const { data, loading, error } = useCurrency();
+
+ const rateGBP = data?.rates['GBP'];
+ const rateEUR = data?.rates['EUR'];
+ const rateBuyGBP = rateGBP ? rateGBP.toFixed(2) : 'N/A';
+ const rateSellGBP = rateGBP ? (1 / rateGBP).toFixed(2) : 'N/A';
+ const rateBuyEUR = rateEUR ? rateEUR.toFixed(2) : 'N/A';
+ const rateSellEUR = rateEUR ? (1 / rateEUR).toFixed(2) : 'N/A';
+
+ const isMobile = useMediaQuery({
+ query: '(max-width: 767px)',
+ });
+ const isMinTablet = useMediaQuery({
query: '(min-width: 768px)',
});
- return <>{!isDesktopOrLaptop &&
Currency | +Purchase | +Sale | +
---|---|---|
GBP | +{rateBuyGBP} | +{rateSellGBP} | +
EUR | +{rateBuyEUR} | +{rateSellEUR} | +
+ ₴ {balance ? formatNumberWithSpaces(balance) : '0.00'} +
Currency | +Purchase | +Sale | +
---|---|---|
GBP | +{rateBuyGBP} | +{rateSellGBP} | +
EUR | +{rateBuyEUR} | +{rateSellEUR} | +
Are you sure you want to detete this transaction?
+ +Date | +Type | +Category | +Comment | +Sum | ++ | + |
---|
Date: {new Date(date).toLocaleDateString()}
-Type: {type}
-Category: {category}
-Comment: {comment}
-Amount: {type === 'income' ? `+${amount}` : `-${amount}`}
- -Loading...
; - if (error) { - const errorMessage = - typeof error === 'object' && error.message - ? error.message - : JSON.stringify(error); - returnError: {errorMessage}
; - } - if (Array.isArray(transactions) && transactions.length === 0) { - returnNo transactions found.
; - } +const TransactionsList = ({ data, openDeleteModal, openEditModal }) => { + // Sortează array-ul de tranzacții + const sortedData = [...data].sort((a, b) => { + // Sortare după dată + if (a.transactionDate < b.transactionDate) return -1; + if (a.transactionDate > b.transactionDate) return 1; + // Sortare după tipul de tranzacție (Income va fi primul) + if (a.type === 'INCOME' && b.type === 'EXPENSE') return -1; + if (a.type === 'EXPENSE' && b.type === 'INCOME') return 1; + // Dacă sunt la aceeași dată și același tip de tranzacție, nu se schimbă ordinea + return 0; + }); return ( -