This commit is contained in:
@@ -27,7 +27,9 @@ const stubDashboardRequests = () => {
|
|||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
cy.intercept("GET", "**/api/proxy/dashboard/summary**", (req) => {
|
cy.intercept("GET", "**/api/proxy/dashboard/summary**", (req) => {
|
||||||
expect(req.query.closing_window).to.be.undefined;
|
const days = Number(req.query.days);
|
||||||
|
expect(req.query.closing_window).to.eq("168");
|
||||||
|
req.alias = days === 30 ? "summary30Days" : "summary14Days";
|
||||||
req.reply({
|
req.reply({
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
body: apiResponse({
|
body: apiResponse({
|
||||||
@@ -39,10 +41,15 @@ const stubDashboardRequests = () => {
|
|||||||
closing_soon: 12,
|
closing_soon: 12,
|
||||||
total_estimated_value: 2500000,
|
total_estimated_value: 2500000,
|
||||||
value_currency: "EUR",
|
value_currency: "EUR",
|
||||||
|
days,
|
||||||
|
scraped_ted: [
|
||||||
|
{ date: "2026-06-08", count: days === 30 ? 12 : 5 },
|
||||||
|
{ date: "2026-06-09", count: days === 30 ? 18 : 8 },
|
||||||
|
],
|
||||||
generated_at: now,
|
generated_at: now,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}).as("dashboardSummary");
|
});
|
||||||
|
|
||||||
cy.intercept("GET", "**/api/proxy/dashboard/trend**", (req) => {
|
cy.intercept("GET", "**/api/proxy/dashboard/trend**", (req) => {
|
||||||
expect(req.query).to.include({ days: "14", metric: "created" });
|
expect(req.query).to.include({ days: "14", metric: "created" });
|
||||||
@@ -139,10 +146,6 @@ const stubDashboardRequests = () => {
|
|||||||
days,
|
days,
|
||||||
generated_at: now,
|
generated_at: now,
|
||||||
daily: {
|
daily: {
|
||||||
scraped_ted: [
|
|
||||||
{ date: "2026-06-08", count: days === 30 ? 12 : 5 },
|
|
||||||
{ date: "2026-06-09", count: days === 30 ? 18 : 8 },
|
|
||||||
],
|
|
||||||
scraped_documents: [
|
scraped_documents: [
|
||||||
{ date: "2026-06-08", count: days === 30 ? 40 : 20 },
|
{ date: "2026-06-08", count: days === 30 ? 40 : 20 },
|
||||||
{ date: "2026-06-09", count: days === 30 ? 60 : 30 },
|
{ date: "2026-06-09", count: days === 30 ? 60 : 30 },
|
||||||
@@ -155,6 +158,7 @@ const stubDashboardRequests = () => {
|
|||||||
totals: {
|
totals: {
|
||||||
scraped_documents: days === 30 ? 9876 : 4321,
|
scraped_documents: days === 30 ? 9876 : 4321,
|
||||||
translated_tenders: days === 30 ? 654 : 321,
|
translated_tenders: days === 30 ? 654 : 321,
|
||||||
|
scraped_ted_notices: days === 30 ? 2468 : 1234,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -171,7 +175,7 @@ describe("tender dashboard", () => {
|
|||||||
visitDashboard();
|
visitDashboard();
|
||||||
|
|
||||||
cy.wait([
|
cy.wait([
|
||||||
"@dashboardSummary",
|
"@summary14Days",
|
||||||
"@dashboardTrend",
|
"@dashboardTrend",
|
||||||
"@dashboardCountries",
|
"@dashboardCountries",
|
||||||
"@dashboardNoticeTypes",
|
"@dashboardNoticeTypes",
|
||||||
@@ -213,10 +217,13 @@ describe("tender dashboard", () => {
|
|||||||
|
|
||||||
it("reloads scraping and translation statistics for a selected range", () => {
|
it("reloads scraping and translation statistics for a selected range", () => {
|
||||||
visitDashboard();
|
visitDashboard();
|
||||||
cy.wait("@statistics14Days");
|
cy.wait(["@summary14Days", "@statistics14Days"]);
|
||||||
|
|
||||||
cy.contains("button", "14d").should("have.class", "bg-primary");
|
cy.contains("button", "14d").should("have.class", "bg-primary");
|
||||||
cy.contains("button", "30d").click();
|
cy.contains("button", "30d").click();
|
||||||
|
cy.wait("@summary30Days")
|
||||||
|
.its("request.query.days")
|
||||||
|
.should("eq", "30");
|
||||||
cy.wait("@statistics30Days")
|
cy.wait("@statistics30Days")
|
||||||
.its("request.query.days")
|
.its("request.query.days")
|
||||||
.should("eq", "30");
|
.should("eq", "30");
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ import { toLabeledPoints } from "./to-labeled-points";
|
|||||||
export type DashboardMetrics = ReturnType<typeof useDashboardData>;
|
export type DashboardMetrics = ReturnType<typeof useDashboardData>;
|
||||||
|
|
||||||
export function useDashboardData() {
|
export function useDashboardData() {
|
||||||
const summaryQuery = useDashboardSummaryQuery();
|
const summaryQuery = useDashboardSummaryQuery({
|
||||||
|
closing_window: 168,
|
||||||
|
days: 14,
|
||||||
|
});
|
||||||
const trendQuery = useDashboardTrendQuery({ days: 14, metric: "created" });
|
const trendQuery = useDashboardTrendQuery({ days: 14, metric: "created" });
|
||||||
const countriesQuery = useDashboardCountriesQuery({ limit: 6 });
|
const countriesQuery = useDashboardCountriesQuery({ limit: 6 });
|
||||||
const noticeTypesQuery = useDashboardNoticeTypesQuery();
|
const noticeTypesQuery = useDashboardNoticeTypesQuery();
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useDashboardStatisticsQuery } from "@/hooks/queries";
|
import {
|
||||||
|
useDashboardStatisticsQuery,
|
||||||
|
useDashboardSummaryQuery,
|
||||||
|
} from "@/hooks/queries";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { toLabeledPoints } from "./to-labeled-points";
|
import { toLabeledPoints } from "./to-labeled-points";
|
||||||
|
|
||||||
@@ -11,14 +14,16 @@ export type StatisticsDays = (typeof STATISTICS_DAY_OPTIONS)[number];
|
|||||||
export function useStatistics() {
|
export function useStatistics() {
|
||||||
const [days, setDays] = useState<StatisticsDays>(14);
|
const [days, setDays] = useState<StatisticsDays>(14);
|
||||||
|
|
||||||
|
const summaryQuery = useDashboardSummaryQuery({ closing_window: 168, days });
|
||||||
const query = useDashboardStatisticsQuery({ days });
|
const query = useDashboardStatisticsQuery({ days });
|
||||||
|
const summary = summaryQuery.data?.data;
|
||||||
const stats = query.data?.data;
|
const stats = query.data?.data;
|
||||||
|
|
||||||
const daily = stats?.daily;
|
const daily = stats?.daily;
|
||||||
|
|
||||||
const scrapedTed = useMemo(
|
const scrapedTed = useMemo(
|
||||||
() => toLabeledPoints(daily?.scraped_ted ?? []),
|
() => toLabeledPoints(summary?.scraped_ted ?? []),
|
||||||
[daily],
|
[summary],
|
||||||
);
|
);
|
||||||
const scrapedDocuments = useMemo(
|
const scrapedDocuments = useMemo(
|
||||||
() => toLabeledPoints(daily?.scraped_documents ?? []),
|
() => toLabeledPoints(daily?.scraped_documents ?? []),
|
||||||
@@ -32,9 +37,12 @@ export function useStatistics() {
|
|||||||
return {
|
return {
|
||||||
days,
|
days,
|
||||||
setDays,
|
setDays,
|
||||||
isLoading: query.isPending,
|
isLoading: query.isPending || summaryQuery.isPending,
|
||||||
isError: query.isError,
|
isError: query.isError || summaryQuery.isError,
|
||||||
refetch: query.refetch,
|
refetch: () => {
|
||||||
|
summaryQuery.refetch();
|
||||||
|
query.refetch();
|
||||||
|
},
|
||||||
scrapedTed,
|
scrapedTed,
|
||||||
scrapedDocuments,
|
scrapedDocuments,
|
||||||
translatedNotices,
|
translatedNotices,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useMemo } from "react";
|
|||||||
|
|
||||||
export const useDashboardSummaryQuery = (params?: {
|
export const useDashboardSummaryQuery = (params?: {
|
||||||
closing_window?: number;
|
closing_window?: number;
|
||||||
|
days?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey = useMemo(
|
const queryKey = useMemo(
|
||||||
() => [API_ENDPOINTS.DASHBOARD.SUMMARY, params],
|
() => [API_ENDPOINTS.DASHBOARD.SUMMARY, params],
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
export const dashboardService = {
|
export const dashboardService = {
|
||||||
summary: async (params?: {
|
summary: async (params?: {
|
||||||
closing_window?: number;
|
closing_window?: number;
|
||||||
|
days?: number;
|
||||||
}): Promise<ApiResponse<TDashboardSummary>> => {
|
}): Promise<ApiResponse<TDashboardSummary>> => {
|
||||||
try {
|
try {
|
||||||
return (await api.get(API_ENDPOINTS.DASHBOARD.SUMMARY, { params })).data;
|
return (await api.get(API_ENDPOINTS.DASHBOARD.SUMMARY, { params })).data;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export type TDashboardSummary = {
|
|||||||
closing_soon: number;
|
closing_soon: number;
|
||||||
total_estimated_value: number;
|
total_estimated_value: number;
|
||||||
value_currency: string;
|
value_currency: string;
|
||||||
|
days: number;
|
||||||
|
scraped_ted: TDashboardTrendPoint[];
|
||||||
generated_at: number;
|
generated_at: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -22,7 +24,6 @@ export type TDashboardTrend = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TDashboardStatisticsDaily = {
|
export type TDashboardStatisticsDaily = {
|
||||||
scraped_ted: TDashboardTrendPoint[];
|
|
||||||
scraped_documents: TDashboardTrendPoint[];
|
scraped_documents: TDashboardTrendPoint[];
|
||||||
translated_notices: TDashboardTrendPoint[];
|
translated_notices: TDashboardTrendPoint[];
|
||||||
};
|
};
|
||||||
@@ -30,6 +31,7 @@ export type TDashboardStatisticsDaily = {
|
|||||||
export type TDashboardStatisticsTotals = {
|
export type TDashboardStatisticsTotals = {
|
||||||
scraped_documents: number;
|
scraped_documents: number;
|
||||||
translated_tenders: number;
|
translated_tenders: number;
|
||||||
|
scraped_ted_notices: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDashboardStatistics = {
|
export type TDashboardStatistics = {
|
||||||
|
|||||||
Reference in New Issue
Block a user