Skip to content
Merged
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
2 changes: 1 addition & 1 deletion front/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
46 changes: 46 additions & 0 deletions front/src/app/embalse-cuenca/[cuenca]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { EmbalsesCuencaPod, getEmbalsesPorCuenca } from "@/pods/embalse-cuenca";
import { cuencas } from "@/core/constants";
import { Metadata } from "next";
import { mapLookupListFromApiToViewModel } from "@/common/mappers";

interface Props {
params: Promise<{ cuenca: string }>;
}

const getCuencaBySlug = (slug: string) => {
return Object.values(cuencas).find((cuenca) => cuenca.slug === slug);
};

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { cuenca } = await params;
const datosCuenca = getCuencaBySlug(cuenca);

if (!datosCuenca) {
return {};
}

return {
title: `Embalses de ${datosCuenca.nombre}`,
};
}

export default async function EmbalseCuencaListadoPage({
params,
}: Props): Promise<React.JSX.Element> {
const { cuenca } = await params;
const datosCuenca = getCuencaBySlug(cuenca);

const embalsesPorCuencaDesdeApi = await getEmbalsesPorCuenca(
datosCuenca.nombre,
);
const embalsesPorCuenca = mapLookupListFromApiToViewModel(
embalsesPorCuencaDesdeApi,
);

return (
<EmbalsesCuencaPod
nombreCuenca={datosCuenca.nombre}
embalses={embalsesPorCuenca}
/>
);
}
14 changes: 14 additions & 0 deletions front/src/app/embalse-cuenca/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { mapLookupListFromApiToViewModel } from "@/common/mappers";
import { EmbalseCuencaListPod } from "@/pods/embalse-cuenca-list";
import { getRiverBasins } from "@/pods/embalse-cuenca-list/embalse-cuenca-list.repository";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Embalses por cuencas",
};
export default async function EmbalsesCuencasPage() {
const cuencasAPI = await getRiverBasins();
const cuencaList = mapLookupListFromApiToViewModel(cuencasAPI);

return <EmbalseCuencaListPod cuencaList={cuencaList} />;
}
1 change: 1 addition & 0 deletions front/src/common/mappers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./lookup.mappers";
12 changes: 12 additions & 0 deletions front/src/common/mappers/lookup.mappers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { LookupApi } from "@/common/models";
import { Lookup } from "@content-island/api-client";

export const mapLookupListFromApiToViewModel = (
lookupList: LookupApi[],
): Lookup[] =>
Array.isArray(lookupList) ? lookupList.map(mapLookupFromApiToViewModel) : [];

const mapLookupFromApiToViewModel = (lookup: LookupApi): Lookup => ({
id: lookup._id,
name: lookup.nombre,
});
14 changes: 14 additions & 0 deletions front/src/common/models/cuencas.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { LookupApi } from "./lookup.model";

export interface EmbalsesCuencaListApi {
embalse_id: string;
nombre: string;
slug: string;
cuenca: LookupApi;
}

export interface EmbalsesCuencaList {
id: string;
name: string;
slug?: string;
}
1 change: 1 addition & 0 deletions front/src/common/models/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./lookup.model";
export * from "./cuencas.model";
5 changes: 5 additions & 0 deletions front/src/common/models/lookup.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ export interface Lookup {
id: string;
name: string;
}

export interface LookupApi {
_id: string;
nombre: string;
}
36 changes: 36 additions & 0 deletions front/src/core/constants/cuencas.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export const cuencas = {
SEGURA: { nombre: "Segura", slug: "segura" },
MINO_SIL: { nombre: "Miño - Sil", slug: "mino-sil" },
EBRO: { nombre: "Ebro", slug: "ebro" },
GUADALQUIVIR: { nombre: "Guadalquivir", slug: "guadalquivir" },
JUCAR: { nombre: "Júcar", slug: "jucar" },
DUERO: { nombre: "Duero", slug: "duero" },
CANTABRICO_ORIENTAL: {
nombre: "Cantábrico Oriental",
slug: "cantabrico-oriental",
},
CUENCA_MEDITERRANEA_ANDALUZA: {
nombre: "Cuenca Mediterránea Andaluza",
slug: "cuenca-mediterranea-andaluza",
},
GUADIANA: { nombre: "Guadiana", slug: "guadiana" },
CANTABRICO_OCCIDENTAL: {
nombre: "Cantábrico Occidental",
slug: "cantabrico-occidental",
},
TINTO_ODIEL_Y_PIEDRAS: {
nombre: "Tinto, Odiel y Piedras",
slug: "tinto-odiel-y-piedras",
},
TAJO: { nombre: "Tajo", slug: "tajo" },
GALICIA_COSTA: { nombre: "Galicia Costa", slug: "galicia-costa" },
GUADALETE_BARBATE: { nombre: "Guadalete-Barbate", slug: "guadalete-barbate" },
CUENCAS_INTERNAS_DEL_PAIS_VASCO: {
nombre: "Cuencas Internas del País Vasco",
slug: "cuencas-internas-del-pais-vasco",
},
CUENCAS_INTERNAS_DE_CATALUNA: {
nombre: "Cuencas Internas de Cataluña",
slug: "cuencas-internas-de-cataluna",
},
} as const;
1 change: 1 addition & 0 deletions front/src/core/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./provincias.constants";
export * from "./cuencas.constants";
6 changes: 6 additions & 0 deletions front/src/layouts/footer.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export const FooterComponent: FC = () => {
>
Embalses por provincias
</Link>
<Link
href="/embalse-cuenca"
className="link-accessible text-[15px] leading-none font-normal"
>
Embalses por cuencas
</Link>
<Link
href="/equipo"
className="link-accessible text-[15px] leading-none font-normal"
Expand Down
37 changes: 20 additions & 17 deletions front/src/lib/mongodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,32 @@ import { MongoClient, type Db } from "mongodb";

//hack de TypeScript para tipar globalThis con nuestra propiedad custom _mongoClient
const globalForMongo = globalThis as typeof globalThis & {
_mongoClient?: MongoClient;
_mongoClient?: MongoClient;
};

//crea el cliente solo si no existe ya (singleton)
async function getClient(): Promise<MongoClient> {
const connectionString = process.env.MONGODB_CONNECTION_STRING;
if (!connectionString) {
throw new Error(
"Please define the MONGODB_CONNECTION_STRING environment variable in .env.local"
);
}
async function getClient(): Promise<MongoClient> {
const connectionString = process.env.MONGODB_CONNECTION_STRING;
if (!connectionString) {
throw new Error(
"Please define the MONGODB_CONNECTION_STRING environment variable in .env.local",
);
}

if (!globalForMongo._mongoClient) {
console.log("[mongodb] Connecting to MongoDB...", connectionString.replace(/\/\/.*@/, "//***@"));
globalForMongo._mongoClient = new MongoClient(connectionString);
await globalForMongo._mongoClient.connect();
console.log("[mongodb] Connected successfully");
}
if (!globalForMongo._mongoClient) {
console.log(
"[mongodb] Connecting to MongoDB...",
connectionString.replace(/\/\/.*@/, "//***@"),
);
globalForMongo._mongoClient = new MongoClient(connectionString);
await globalForMongo._mongoClient.connect();
console.log("[mongodb] Connected successfully");
}

return globalForMongo._mongoClient;
return globalForMongo._mongoClient;
}
//lo que exportamo devuelve la instancia de Db lista para hacer queries
export async function getDb(): Promise<Db> {
const client = await getClient();
return client.db();
const client = await getClient();
return client.db();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Card } from "@/common/components/card.component";
import Link from "next/link";
import { generateSlug } from "db-model";
import { Lookup } from "@/common/models";

interface Props {
cuencaList: Lookup[];
}

export const EmbalsesCuencaList: React.FC<Props> = (props) => {
const { cuencaList } = props;
return (
<Card className="mx-auto w-full pt-6 pr-4 pb-6 pl-4 md:max-w-225 md:p-8">
<div className="bg-base-100 rounded-2xl p-6">
<h2>Embalses por cuencas</h2>
<div className="grid grid-cols-1 gap-4 p-6 sm:grid-cols-2 md:grid-cols-3">
{cuencaList.map(({ id, name }) => (
<Link
key={id}
href={`/embalse-cuenca/${generateSlug(name)}`}
className="link-accessible"
>
{name}
</Link>
))}
</div>
</div>
</Card>
);
};
12 changes: 12 additions & 0 deletions front/src/pods/embalse-cuenca-list/embalse-cuenca-list.pod.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
import { EmbalsesCuencaList } from "./embalse-cuenca-list.component";
import { Lookup } from "@/common/models";

interface Props {
cuencaList: Lookup[];
}

export const EmbalseCuencaListPod: React.FC<Props> = async (props) => {
const { cuencaList } = props;
return <EmbalsesCuencaList cuencaList={cuencaList} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use server";

import { LookupApi } from "@/common/models";
import { getDb } from "@/lib/mongodb";

export async function getRiverBasins(): Promise<LookupApi[]> {
try {
const db = await getDb();
return await db
.collection<LookupApi>("cuencas")
.find({}, { projection: { _id: 1, nombre: 1 } })
.toArray();
} catch (error) {
console.warn(
"getEmbalsesByRiverBasin: MongoDB not available (build time?), returning empty array.",
"Error:",
error instanceof Error ? error.message : error,
);
}
}
2 changes: 2 additions & 0 deletions front/src/pods/embalse-cuenca-list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./embalse-cuenca-list.pod";
export * from "./embalse-cuenca-list.repository";
41 changes: 41 additions & 0 deletions front/src/pods/embalse-cuenca/embalse-cuenca.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";
import { Card } from "@/common/components/card.component";
import { Lookup } from "@/common/models";
import { generateSlug } from "db-model";
import Link from "next/link";

export interface Props {
nombreCuenca: string;
embalses: Lookup[];
}

export const EmbalseCuencaComponent: React.FC<Props> = (props) => {
const { nombreCuenca, embalses } = props;
return (
<Card className="mx-auto w-full pt-6 pr-4 pb-6 pl-4 md:max-w-225 md:p-8">
<div className="bg-base-100 rounded-2xl p-6">
{embalses.length === 0 ? (
<h2>No se encontraron embalses para {nombreCuenca}</h2>
) : (
<h2>Embalses de {nombreCuenca}</h2>
)}
<div className="grid grid-cols-1 gap-4 p-6 sm:grid-cols-2 md:grid-cols-3">
{embalses.map(({ id, name }) => (
<Link
key={id}
href={`/embalse/${generateSlug(name)}`}
className="link-accessible"
>
{name}
</Link>
))}
</div>
<img
className="mt-4 w-full rounded-xl md:aspect-434/171"
src="/images/embalse-generico.jpg"
alt={`Mapa de ubicación de embalses de ${nombreCuenca}`}
/>
</div>
</Card>
);
};
14 changes: 14 additions & 0 deletions front/src/pods/embalse-cuenca/embalse-cuenca.pod.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { EmbalseCuencaComponent } from "./embalse-cuenca.component";
import { Lookup } from "@/common/models";

export interface Props {
nombreCuenca: string;
embalses: Lookup[];
}
export const EmbalsesCuencaPod: React.FC<Props> = (props) => {
const { nombreCuenca, embalses } = props;
return (
<EmbalseCuencaComponent nombreCuenca={nombreCuenca} embalses={embalses} />
);
};
23 changes: 23 additions & 0 deletions front/src/pods/embalse-cuenca/embalse-cuenca.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use server";

import { LookupApi } from "@/common/models";
import { getDb } from "@/lib/mongodb";
import { Embalse } from "db-model";

export const getEmbalsesPorCuenca = async (
nombre: string,
): Promise<LookupApi[]> => {
try {
const db = await getDb();
return await db
.collection<Embalse>("embalses")
.find({ "cuenca.nombre": nombre }, { projection: { _id: 1, nombre: 1 } })
.toArray();
} catch (error) {
console.warn(
"getEmbalsesByRiverBasin: MongoDB not available (build time?), returning empty array.",
"Error:",
error instanceof Error ? error.message : error,
);
}
};
2 changes: 2 additions & 0 deletions front/src/pods/embalse-cuenca/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./embalse-cuenca.pod";
export * from "./embalse-cuenca.repository";