See the live version of Currency Wallet.
The Currency Wallet application is a financial tracking tool that allows users to manually input their historical transactions involving various currencies. It utilizes APIs to fetch the historical exchange rates for each transaction date, providing an accurate financial overview. The application then displays a chart showing the profit or loss for each transaction, calculated based on current currency rates, enabling users to assess their investment performance over time.
Main features:
-
API Rate Fetching
- Integrates with APIs for real-time and historical currency exchange rates.
- Ensures accurate financial data for each transaction.
-
Live Transaction Validation
- Performs live validation during transaction entry.
-
ChartJS 2 Integration
- Uses ChartJS 2 for visual representation of financial data.
- Provides clear, interactive charts to display profit or loss.
-
Redux Toolkit
- Employs Redux Toolkit for efficient state management.
-
Dark Mode
- Offers a user-friendly dark mode.
- Reduces eye strain and provides an alternative aesthetic.
-
Custom Hooks for Form
- Custom hooks enhance form handling and selection options.
-
Local Storage
- Stores user data and preferences locally.
- Allows for persistent user experiences and quick data retrieval.
The project uses node and npm. After ensuring they are installed, follow these steps:
-
Install Dependencies
- Open your terminal.
- Navigate to the project's root directory.
- Type
npm i
to install the necessary packages.
-
API Key Setup
-
Obtain an API key from API Layer's Exchange Rates.
-
In the
src
folder of the project, create a file namedAPI_KEY.js
. -
Inside
API_KEY.js
, export the API key as follows:const API_KEY = 'your_api_key_here'; export default API_KEY;
-
Replace
your_api_key_here
with the actual API key you obtained.
-
By following these steps, you will set up the necessary environment and API access for the application.
Custom Hook for the form component
function useForm() {
const { formData, formErrors } = useSelector((store) => store.form);
const { loading, error: fetchError } = useSelector((store) => store.currency.historical);
const dispatch = useDispatch();
useEffect(() => {
if (formData.date !== '' && formData.currency !== '') {
const [dateString] = formData.date.split('T');
const [_, currencyString] = formData.currency.split(' ');
dispatch(fetchRates({ currency: currencyString, date: dateString, dataType: 'historical' }));
}
}, [formData.date, formData.currency]);
const liveValidation = (input) => {
const { name } = input;
const errorInState = formErrors[name];
if (!errorInState) return;
const inputError = h.validate(db.formFields, [input]);
const isErrorObjEmpty = h.isObjectEmpty(inputError);
if (!isErrorObjEmpty) return;
dispatch(formActions.removeError({ name }));
};
const handleCustomInputSelection = (name, value) => {
dispatch(formActions.setFormData({ name, value }));
dispatch(formActions.removeError({ name }));
};
const handleSubmit = (e) => {
e.preventDefault();
const form = e.target;
// input validation
const inputElements = h.findInputElementsInForm(form);
const fieldErrors = h.validate(db.formFields, inputElements);
// custom validation
const customInputsErrors = h.customValidation(db.formFields, formData);
const updatedErrors = { ...fieldErrors, ...customInputsErrors };
dispatch(formActions.setErrors(updatedErrors));
const isFormClean = h.checkErrors([formErrors, updatedErrors]);
if (!isFormClean) {
return;
}
dispatch(transactionsActions.addTransaction({ transaction: formData }));
dispatch(formActions.resetForm());
};
const handleFetchErrorReset = () => {
dispatch(currencyActions.resetFetchError({ dataType: 'historical' }));
};
const handleFieldChange = (e) => {
const { name, value } = e.target;
dispatch(formActions.setFormData({ name, value }));
liveValidation(e.target);
};
return {
formData,
formErrors,
loading,
fetchError,
liveValidation,
handleCustomInputSelection,
handleSubmit,
handleFetchErrorReset,
handleFieldChange,
};
}
- Custom Select: Offers both search and select function with keys.
- Error handling: Offers fetch error handling.
- Filtering by month/year, biggest gain/loss
Write sth nice ;) Find me on LinkedIn or Instagram
Thanks to my Mentor - devmentor.pl – for providing me with this task and for code review.