Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions front/src/app/embalse/[embalse]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import {
EmbalsePod,
getReservoirInfoBySlugCached,
getEmbalseBySlugCached,
getAverageLastYearByMonthCached,
getAverageHistoricalByMonthCached,
} from "@/pods/embalse";
import { mapEmbalseToReservoirData } from "@/pods/embalse/embalse.mapper";
import {
mapReservoirLastYearToViewModel,
mapEmbalseToReservoirData,
mapHistoricalReservoirToViewModel,
} from "@/pods/embalse/embalse.mapper";

export const revalidate = 300; // ISR: regenerar cada 5 minutos

Expand All @@ -30,10 +36,32 @@ export default async function EmbalseDetallePage({ params }: Props) {
const { embalse } = await params;
const embalseDoc = await getEmbalseBySlugCached(embalse);
const embalseInfo = await getReservoirInfoBySlugCached(embalse);
const actualYear = new Date().getFullYear();
const actualMonth = new Date().getMonth(); // return month 0-11

if (!embalseDoc) {
notFound();
}
const reservoirData = mapEmbalseToReservoirData(embalseDoc, embalseInfo);
return <EmbalsePod reservoirData={reservoirData} />;

const dataMappedOneYearAgo = await getAverageLastYearByMonthCached(
embalseDoc.nombre,
actualMonth + 1,
).then(mapReservoirLastYearToViewModel);

const averageHistoricalData = await getAverageHistoricalByMonthCached(
embalseDoc.nombre,
actualMonth + 1,
actualYear - 10, // 10 years ago
).then(mapHistoricalReservoirToViewModel);

return (
<>
<EmbalsePod
reservoirData={reservoirData}
dataOneYearAgo={dataMappedOneYearAgo}
dataTenYearsAgo={averageHistoricalData}
/>
</>
);
}
4 changes: 3 additions & 1 deletion front/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
/* Title color */
--color-title: #051c1f;

/* Graphic total water */
/* Colors of reservoir graphics */
--color-total-water: #26d6ed;
--line-average-last-year: #6904bb;
--line-average-last-ten-years: #952e00;

/* Accesible visited link color */
--color-visited-link: #257782;
Expand Down
12 changes: 12 additions & 0 deletions front/src/pods/embalse/api/embalse.api-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ export interface ReservoirInfo {
description: string;
mapUrl?: string;
}

export interface ReservoirLastYearModel {
mes: number;
promedio_agua_actual: number;
}

export interface HistoricalAverageReservoir {
embalse: string;
mes: number;
año: number;
promedio_agua_actual: number;
}
71 changes: 69 additions & 2 deletions front/src/pods/embalse/api/embalse.api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import "server-only";
import { unstable_cache } from "next/cache";
import type { ReservoirInfo } from "./embalse.api-model";
import type {
ReservoirInfo,
ReservoirLastYearModel,
HistoricalAverageReservoir,
} from "./embalse.api-model";
import { contentIslandClient } from "@/lib";
import { getEmbalseBySlug } from "../embalse.repository";
import {
getEmbalseBySlug,
getAverageLastYearByMonth,
getAverageHistoricalByMonth,
} from "../embalse.repository";
import type { Embalse } from "db-model";

/**
Expand Down Expand Up @@ -46,3 +54,62 @@ export const getEmbalseBySlugCached = unstable_cache(
["embalse-by-slug"],
{ revalidate: 60 },
);

/**
* Function for historical average.
*
* Cached version of getHistoricalAverageByMonths.
* Revalidates every 60 minutes.
**/
export const getAverageLastYearByMonthCached = unstable_cache(
async (name: string, month: number): Promise<ReservoirLastYearModel> => {
try {
const statisticsReservoir = await getAverageLastYearByMonth(name, month);

if (!statisticsReservoir) {
throw new Error("Empty data last year by month - skip cache");
}

return statisticsReservoir;
} catch (error) {
console.warn(
"getAverageLastYearByMonthCached: MongoDB not available or empty, returning empty array.",
"Error:",
error instanceof Error ? error.message : error,
);
return;
}
},
["reservoir-last-year"],
{ revalidate: 3600 },
);

export const getAverageHistoricalByMonthCached = unstable_cache(
async (
reservoirName: string,
month: number,
year: number,
): Promise<HistoricalAverageReservoir> => {
try {
const historicalStatistics = await getAverageHistoricalByMonth(
reservoirName,
month,
year,
);

if (!historicalStatistics) {
throw new Error("Empty historical data by month and year");
}
return historicalStatistics;
} catch (error) {
console.warn(
"getAverageHistoricalByMonthCached: MongoDB not available or empty, returning empty array.",
"Error:",
error instanceof Error ? error.message : error,
);
return;
}
},
["reservoir-last-ten-year"],
{ revalidate: 3600 },
);
58 changes: 58 additions & 0 deletions front/src/pods/embalse/components/chart/chart-legend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import { monthsNames } from "./chart.constants";
import { ReferenceLine } from "./chart.helpers";

interface Props {
currentLevel: number;
monthOneYearAgo: number;
yearOneYearAgo: number;
averageOneYearAgo: number;
monthTenYearsAgo: number;
yearTenYearsAgo: number;
averageTenYearsAgo: number;
}
export const ChartLegend: React.FC<Props> = (props) => {
const {
currentLevel,
monthOneYearAgo,
yearOneYearAgo,
averageOneYearAgo,
monthTenYearsAgo,
yearTenYearsAgo,
averageTenYearsAgo,
} = props;

return (
<div className="flex w-full flex-col items-start pt-1">
<div className="flex h-8 flex-row items-center gap-2">
<div className="h-2 w-9.5 rounded-t-sm bg-(--color-primary)"></div>
<div>
<span className="text-base-content text-base">Embalsada:</span>
<span className="pl-1">{currentLevel} Hm³</span>
</div>
</div>
{averageOneYearAgo && (
<div className="flex h-8 flex-row items-center gap-2">
<div className="mx-auto h-0.5 w-10 border-t-4 border-dashed border-(--line-average-last-year)" />
<div>
<span>
{monthsNames[monthOneYearAgo - 1]} de {yearOneYearAgo}:
</span>
<span className="pl-1">{averageOneYearAgo} Hm³</span>
</div>
</div>
)}
{averageTenYearsAgo && (
<div className="flex h-8 flex-row items-center gap-2">
<div className="mx-auto h-0.5 w-10 border-t-4 border-dotted border-(--line-average-last-ten-years)" />
<div>
<span>
{monthsNames[monthTenYearsAgo - 1]} de {yearTenYearsAgo}:
</span>
<span className="pl-1">{averageTenYearsAgo} Hm³</span>
</div>
</div>
)}
</div>
);
};
23 changes: 23 additions & 0 deletions front/src/pods/embalse/components/chart/chart.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Declare the chart dimensions and margins.

export const sizeChart = {
width: 200,
height: 180,
margin: { top: 0, right: 30, bottom: 0, left: 30 },
radius: 10,
};

export const monthsNames = [
"Enero",
"Febrero",
"Marzo",
"Abril",
"Mayo",
"Junio",
"Julio",
"Agosto",
"Septiembre",
"Octubre",
"Noviembre",
"Diciembre",
];
44 changes: 44 additions & 0 deletions front/src/pods/embalse/components/chart/chart.helpers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import { sizeChart as s } from "./chart.constants";

interface barRoundedTopProps {
x: number;
y: number;
width: number;
height: number;
fill: string;
}
export const BarRoundedTop: React.FC<barRoundedTopProps> = ({
x,
y,
width,
height,
fill,
}): React.ReactNode => {
return (
<g fill={fill}>
{/* Barra según porcentaje con esquinas redondeadas */}
<rect x={x} y={y} width={width} height={height} rx={s.radius} />
{/* Barra inferior sin redondeo para aplanar la base */}
<rect x={x} y={y + height / 2} width={width} height={height / 2} />
</g>
);
};

export const ReferenceLine: React.FC<{
yPos: number;
x1: number;
x2: number;
stroke: string;
dashArray: string;
}> = ({ yPos, x1, x2, stroke, dashArray }) => (
<line
y1={yPos}
y2={yPos}
x1={x1}
x2={x2}
stroke={stroke}
strokeWidth={5}
strokeDasharray={dashArray}
/>
);
13 changes: 13 additions & 0 deletions front/src/pods/embalse/components/chart/chart.vm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
DataLastYearModel,
HistoricalAverageReservoir,
} from "@/pods/embalse/embalse.vm";

export interface ChartModel {
titleChart?: string;
reservoirName: string;
currentLevel: number;
maxCapacity: number;
dataOneYearAgo?: DataLastYearModel;
dataTenYearsAgo?: HistoricalAverageReservoir;
}
Loading
Loading