exchange v1
This commit is contained in:
parent
e81823aa47
commit
1925e4ef49
File diff suppressed because one or more lines are too long
@ -34,6 +34,7 @@ const instructorsRoutes = require('./routes/instructors');
|
||||
const studentsRoutes = require('./routes/students');
|
||||
|
||||
const weatherRoutes = require('./routes/weather');
|
||||
const exchangeRoutes = require('./routes/exchange');
|
||||
const rolesRoutes = require('./routes/roles');
|
||||
|
||||
const permissionsRoutes = require('./routes/permissions');
|
||||
@ -102,6 +103,7 @@ app.use('/api/auth', authRoutes);
|
||||
app.use('/api/file', fileRoutes);
|
||||
app.use('/api/pexels', pexelsRoutes);
|
||||
app.enable('trust proxy');
|
||||
app.use('/api/exchange', exchangeRoutes);
|
||||
app.use('/api/weather', weatherRoutes);
|
||||
|
||||
|
||||
|
||||
21
backend/src/routes/exchange.js
Normal file
21
backend/src/routes/exchange.js
Normal file
@ -0,0 +1,21 @@
|
||||
const express = require('express');
|
||||
const axios = require('axios');
|
||||
const router = express.Router();
|
||||
|
||||
// GET /api/exchange?base=USD
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const base = req.query.base || 'USD';
|
||||
const response = await axios.get(
|
||||
`https://api.exchangerate.host/latest?base=${encodeURIComponent(base)}&symbols=USD,EUR`
|
||||
);
|
||||
// Return only necessary data
|
||||
const { base: responseBase, rates, date } = response.data;
|
||||
res.json({ base: responseBase, rates, date });
|
||||
} catch (error) {
|
||||
console.error('Exchange route error:', error.message);
|
||||
res.status(500).json({ error: 'Failed to fetch exchange rates' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@ -1 +1 @@
|
||||
{}
|
||||
{"message":"Cannot read properties of undefined (reading 'USD')","stack":"\n at Dashboard (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/%5Broot-of-the-server%5D__184a14d7._.js:5807:198)\n at ErrorBoundary (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/%5Broot-of-the-server%5D__e0e8a8ac._.js:2944:9)\n at div (<anonymous>)\n at div (<anonymous>)\n at LayoutAuthenticated (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/%5Broot-of-the-server%5D__184a14d7._.js:2784:32)\n at Provider (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_ef42dc8f._.js:13186:21)\n at MyApp (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/%5Broot-of-the-server%5D__e0e8a8ac._.js:3483:18)\n at AppWithTranslation (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_ef42dc8f._.js:15878:26)\n at PathnameContextProviderAdapter (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_shared_lib_67de5af5._.js:5103:11)\n at PagesDevOverlayErrorBoundary (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_client_762395d3._.js:2230:9)\n at PagesDevOverlay (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_client_762395d3._.js:12428:11)\n at Container (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_client_762395d3._.js:12577:1)\n at AppContainer (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_client_762395d3._.js:12688:11)\n at Root (https://test-i18-31433-dev-lnm5nd2pia-uc.a.run.app/_next/static/chunks/node_modules_next_dist_client_762395d3._.js:12866:11)"}
|
||||
22
frontend/src/helpers/exchange.ts
Normal file
22
frontend/src/helpers/exchange.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
|
||||
export interface ExchangeData {
|
||||
base: string;
|
||||
rates: {
|
||||
USD: number;
|
||||
EUR: number;
|
||||
};
|
||||
date: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches latest exchange rates for USD and EUR relative to the given base currency
|
||||
*/
|
||||
export const getExchangeRates = async (
|
||||
base: string
|
||||
): Promise<ExchangeData> => {
|
||||
const response: AxiosResponse<ExchangeData> = await axios.get(
|
||||
`/exchange?base=${encodeURIComponent(base)}`
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
@ -18,6 +18,7 @@ import { SmartWidget } from '../components/SmartWidget/SmartWidget';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
import { getWeather, WeatherData } from '../helpers/weather';
|
||||
import { getExchangeRates, ExchangeData } from '../helpers/exchange';
|
||||
const Dashboard = () => {
|
||||
const { t } = useTranslation('common');
|
||||
const dispatch = useAppDispatch();
|
||||
@ -49,6 +50,10 @@ const Dashboard = () => {
|
||||
const [selectedCity, setSelectedCity] = React.useState('London');
|
||||
|
||||
const [weather, setWeather] = React.useState<WeatherData | null>(null);
|
||||
const [exchangeData, setExchangeData] = React.useState<ExchangeData | null>(null);
|
||||
const [baseCurrency, setBaseCurrency] = React.useState('USD');
|
||||
|
||||
|
||||
|
||||
const { isFetchingQuery } = useAppSelector((state) => state.openAi);
|
||||
|
||||
@ -118,6 +123,13 @@ const Dashboard = () => {
|
||||
}, [widgetsRole?.role?.value]);
|
||||
|
||||
// Load weather data
|
||||
// Load exchange rates data
|
||||
React.useEffect(() => {
|
||||
getExchangeRates(baseCurrency)
|
||||
.then(data => setExchangeData(data))
|
||||
.catch(err => console.error('Exchange load error', err));
|
||||
}, [baseCurrency]);
|
||||
|
||||
React.useEffect(() => {
|
||||
getWeather(selectedCity)
|
||||
.then((data) => setWeather(data))
|
||||
@ -257,6 +269,19 @@ const Dashboard = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{exchangeData?.rates && (
|
||||
<div className={`${corners !== 'rounded-full' ? corners : 'rounded-3xl'} dark:bg-dark-900 ${cardsStyle} dark:border-dark-700 p-6`}>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-lg leading-tight text-gray-500 dark:text-gray-400">
|
||||
Exchange Rates
|
||||
</div>
|
||||
<div className="mt-4 text-sm text-gray-600 dark:text-gray-500">
|
||||
<div>{`1 ${exchangeData.base} = ${exchangeData.rates.USD.toFixed(4)} USD`}</div>
|
||||
<div>{`1 ${exchangeData.base} = ${exchangeData.rates.EUR.toFixed(4)} EUR`}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasPermission(currentUser, 'READ_USERS') && (
|
||||
<Link href={'/users/users-list'}>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user