diff --git a/src/api/api.js b/src/api/api.js
index 12b1baa..24153e2 100644
--- a/src/api/api.js
+++ b/src/api/api.js
@@ -1685,9 +1685,44 @@ export const apiGetAllRoutesAsync = async () => {
return axios.get(`${baseApiUrl}/api/Delivery/routes`);
};
+
+
+export const apiGetStoreIncomeAsync = async (storeId, from, to) => {
+ const fromDate = from.toISOString();
+ const toDate = to.toISOString();
+ const response = await axios.get(
+ `${baseApiUrl}/api/Admin/store/${storeId}/income`,
+ { params: { from: fromDate, to: toDate } }
+ );
+ return response.data;
+};
+
+
+
+export const apiGetAdminProfitAsync = async (from, to, storeIds) => {
+ const response = await axios.get(`${baseApiUrl}/api/loyalty/admin/profit`, {
+ params: {
+ from: from?.toISOString(),
+ to: to?.toISOString(),
+ storeIds,
+ },
+ paramsSerializer: (params) => {
+ const query = new URLSearchParams();
+ if (params.from) query.append('from', params.from);
+ if (params.to) query.append('to', params.to);
+ if (params.storeIds) {
+ params.storeIds.forEach((id) => query.append('storeIds', id));
+ }
+ return query.toString();
+ },
+ });
+ return response.data;
+};
+
export const apiFetchDeliveryAddressByIdAsync = async (addressId) => {
const res = await axios.get(
`${baseApiUrl}/api/user-profile/address/${addressId}`
);
return res.data; // Vraća objekat adrese
};
+
diff --git a/src/components/StoreEarningsTable.jsx b/src/components/StoreEarningsTable.jsx
new file mode 100644
index 0000000..020fd58
--- /dev/null
+++ b/src/components/StoreEarningsTable.jsx
@@ -0,0 +1,88 @@
+import React, { useState, useMemo } from 'react';
+import {
+ Table, TableHead, TableRow, TableCell, TableBody,
+ TablePagination, TableSortLabel, Paper, Box
+} from '@mui/material';
+
+const StoreEarningsTable = ({ data }) => {
+ const [page, setPage] = useState(0);
+ const rowsPerPage = 5;
+ const [orderBy, setOrderBy] = useState('storeRevenue');
+ const [order, setOrder] = useState('desc');
+
+ const handleSort = (property) => {
+ const isAsc = orderBy === property && order === 'asc';
+ setOrder(isAsc ? 'desc' : 'asc');
+ setOrderBy(property);
+ };
+
+ const sortedData = useMemo(() => {
+ return [...data].sort((a, b) =>
+ (order === 'asc' ? a[orderBy] - b[orderBy] : b[orderBy] - a[orderBy])
+ );
+ }, [data, order, orderBy]);
+
+ const paginatedData = sortedData.slice(page * rowsPerPage, (page + 1) * rowsPerPage);
+
+ return (
+
+
+
+
+
+ Store Name
+
+ handleSort('storeRevenue')}
+ >
+ Store Revenue
+
+
+
+ handleSort('adminProfit')}
+ >
+ Admin Profit
+
+
+
+ handleSort('taxRate')}
+ >
+ Tax Rate (%)
+
+
+
+
+
+ {paginatedData.map((row) => (
+
+ {row.name}
+ {(row.storeRevenue ?? 0).toFixed(2)} $
+ {(row.adminProfit ?? 0).toFixed(2)} $
+ {(row.taxRate ?? 0).toFixed(2)} %
+
+
+ ))}
+
+
+
+ setPage(newPage)}
+ />
+
+ );
+};
+
+export default StoreEarningsTable;
diff --git a/src/pages/AnalyticsPage.jsx b/src/pages/AnalyticsPage.jsx
index 4e92b1f..e72978b 100644
--- a/src/pages/AnalyticsPage.jsx
+++ b/src/pages/AnalyticsPage.jsx
@@ -16,6 +16,7 @@ import Calendar from '@components/Calendar'; // From develop
import DealsChart from '@components/DealsChart'; // From develop
import SalesChart from '@components/SalesChart'; // From develop
import { useState, useEffect, useRef } from 'react'; // useRef from develop
+import StoreEarningsTable from '@components/StoreEarningsTable';
import {
apiGetAllAdsAsync,
@@ -27,6 +28,8 @@ import {
apiFetchAdClicksAsync,
apiFetchAdViewsAsync,
apiFetchAdConversionsAsync, // From HEAD, for ProductsSummary
+ apiGetStoreIncomeAsync,
+ apiGetAdminProfitAsync
} from '../api/api.js';
// format and parseISO were in develop but not used in the conflicting part, subMonths is used by both
import { subMonths, format, parseISO } from 'date-fns'; // Added format, parseISO from develop imports
@@ -40,6 +43,7 @@ const HUB_URL = `${baseUrl}${HUB_ENDPOINT_PATH}`;
const AnalyticsPage = () => {
// --- State from develop ---
+ const [totalAdminProfit, setTotalAdminProfit] = useState(0);
const [ads, setAds] = useState([]); // For general ad data, updated by SignalR
const [kpi, setKpi] = useState({
totalViews: 0,
@@ -85,6 +89,9 @@ const AnalyticsPage = () => {
const [storeSpecificConversionData, setStoreSpecificConversionData] =
useState([]);
+ const [storeStats, setStoreStats] = useState([]);
+
+
// --- Pagination Logic (from HEAD) ---
const handlePageChange = (event, value) => {
setCurrentProductPage(value);
@@ -321,6 +328,44 @@ const AnalyticsPage = () => {
calculatedProductsChange
);
+ const adsWithProfitResp = await apiFetchAdsWithProfitAsync();
+ const adsWithProfit = adsWithProfitResp?.data || [];
+
+ const noww= new Date();
+
+ const from = new Date(noww.getFullYear(), noww.getMonth(), 1);
+ const to = new Date(noww.getFullYear(), noww.getMonth() + 1, 0);
+
+ const earningsStats = await Promise.all(
+ stores.map(async (store) => {
+ try {
+ const income = await apiGetStoreIncomeAsync(store.id, from, to);
+ return {
+ storeId: income.StoreId,
+ name: income.StoreName ?? store.name,
+ storeRevenue: income.TotalIncome ,
+ adminProfit: income.TaxedIncome,
+ taxRate: (store.tax) * 100,
+ };
+ } catch (err) {
+ console.error(`❌ Error fetching income for store ${store.id}`, err);
+ return {
+ storeId: store.id,
+ name: store.name,
+ storeRevenue: 0,
+ adminProfit: 0,
+ taxRate: (store.tax) * 100,
+ };
+ }
+ })
+ );
+
+ setStoreStats(earningsStats);
+
+
+ const adminProfit = await apiGetAdminProfitAsync(from, to, stores.map(s => s.id));
+ setTotalAdminProfit(adminProfit);
+
// Other initial data if needed (orders, users - not directly used for KPIs in develop's version)
// const ordersData = await apiFetchOrdersAsync();
// const usersResponse = await apiFetchAllUsersAsync();
@@ -816,6 +861,13 @@ const AnalyticsPage = () => {
)}
+
+
+ Store Earnings (Past Month)
+
+
+
+
{/* //jel ovo ima smisla ovd? (Comment from HEAD)