diff --git a/front/next-env.d.ts b/front/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/front/next-env.d.ts +++ b/front/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -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. diff --git a/front/src/app/embalse-cuenca/[cuenca]/page.tsx b/front/src/app/embalse-cuenca/[cuenca]/page.tsx new file mode 100644 index 0000000..42c6c08 --- /dev/null +++ b/front/src/app/embalse-cuenca/[cuenca]/page.tsx @@ -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 { + 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 { + const { cuenca } = await params; + const datosCuenca = getCuencaBySlug(cuenca); + + const embalsesPorCuencaDesdeApi = await getEmbalsesPorCuenca( + datosCuenca.nombre, + ); + const embalsesPorCuenca = mapLookupListFromApiToViewModel( + embalsesPorCuencaDesdeApi, + ); + + return ( + + ); +} diff --git a/front/src/app/embalse-cuenca/page.tsx b/front/src/app/embalse-cuenca/page.tsx new file mode 100644 index 0000000..ea7ff72 --- /dev/null +++ b/front/src/app/embalse-cuenca/page.tsx @@ -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 ; +} diff --git a/front/src/common/mappers/index.ts b/front/src/common/mappers/index.ts new file mode 100644 index 0000000..cfbbb94 --- /dev/null +++ b/front/src/common/mappers/index.ts @@ -0,0 +1 @@ +export * from "./lookup.mappers"; diff --git a/front/src/common/mappers/lookup.mappers.ts b/front/src/common/mappers/lookup.mappers.ts new file mode 100644 index 0000000..2957cc2 --- /dev/null +++ b/front/src/common/mappers/lookup.mappers.ts @@ -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, +}); diff --git a/front/src/common/models/cuencas.model.ts b/front/src/common/models/cuencas.model.ts new file mode 100644 index 0000000..ec82594 --- /dev/null +++ b/front/src/common/models/cuencas.model.ts @@ -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; +} diff --git a/front/src/common/models/index.ts b/front/src/common/models/index.ts index a13e258..4baf92a 100644 --- a/front/src/common/models/index.ts +++ b/front/src/common/models/index.ts @@ -1 +1,2 @@ export * from "./lookup.model"; +export * from "./cuencas.model"; diff --git a/front/src/common/models/lookup.model.ts b/front/src/common/models/lookup.model.ts index cd43ce3..f5cf627 100644 --- a/front/src/common/models/lookup.model.ts +++ b/front/src/common/models/lookup.model.ts @@ -2,3 +2,8 @@ export interface Lookup { id: string; name: string; } + +export interface LookupApi { + _id: string; + nombre: string; +} diff --git a/front/src/core/constants/cuencas.constants.ts b/front/src/core/constants/cuencas.constants.ts new file mode 100644 index 0000000..8f58b15 --- /dev/null +++ b/front/src/core/constants/cuencas.constants.ts @@ -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; diff --git a/front/src/core/constants/index.ts b/front/src/core/constants/index.ts index d333a56..768ed5b 100644 --- a/front/src/core/constants/index.ts +++ b/front/src/core/constants/index.ts @@ -1 +1,2 @@ export * from "./provincias.constants"; +export * from "./cuencas.constants"; diff --git a/front/src/layouts/footer.component.tsx b/front/src/layouts/footer.component.tsx index 5783e29..9a4312c 100644 --- a/front/src/layouts/footer.component.tsx +++ b/front/src/layouts/footer.component.tsx @@ -14,6 +14,12 @@ export const FooterComponent: FC = () => { > Embalses por provincias + + Embalses por cuencas + { - 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 { + 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 { - const client = await getClient(); - return client.db(); + const client = await getClient(); + return client.db(); } diff --git a/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.component.tsx b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.component.tsx new file mode 100644 index 0000000..7a10e9e --- /dev/null +++ b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.component.tsx @@ -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) => { + const { cuencaList } = props; + return ( + + + Embalses por cuencas + + {cuencaList.map(({ id, name }) => ( + + {name} + + ))} + + + + ); +}; diff --git a/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.pod.tsx b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.pod.tsx new file mode 100644 index 0000000..bd0de55 --- /dev/null +++ b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.pod.tsx @@ -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 = async (props) => { + const { cuencaList } = props; + return ; +}; diff --git a/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.repository.ts b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.repository.ts new file mode 100644 index 0000000..335ef57 --- /dev/null +++ b/front/src/pods/embalse-cuenca-list/embalse-cuenca-list.repository.ts @@ -0,0 +1,20 @@ +"use server"; + +import { LookupApi } from "@/common/models"; +import { getDb } from "@/lib/mongodb"; + +export async function getRiverBasins(): Promise { + try { + const db = await getDb(); + return await db + .collection("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, + ); + } +} diff --git a/front/src/pods/embalse-cuenca-list/index.ts b/front/src/pods/embalse-cuenca-list/index.ts new file mode 100644 index 0000000..54c55e3 --- /dev/null +++ b/front/src/pods/embalse-cuenca-list/index.ts @@ -0,0 +1,2 @@ +export * from "./embalse-cuenca-list.pod"; +export * from "./embalse-cuenca-list.repository"; diff --git a/front/src/pods/embalse-cuenca/embalse-cuenca.component.tsx b/front/src/pods/embalse-cuenca/embalse-cuenca.component.tsx new file mode 100644 index 0000000..2e5879e --- /dev/null +++ b/front/src/pods/embalse-cuenca/embalse-cuenca.component.tsx @@ -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) => { + const { nombreCuenca, embalses } = props; + return ( + + + {embalses.length === 0 ? ( + No se encontraron embalses para {nombreCuenca} + ) : ( + Embalses de {nombreCuenca} + )} + + {embalses.map(({ id, name }) => ( + + {name} + + ))} + + + + + ); +}; diff --git a/front/src/pods/embalse-cuenca/embalse-cuenca.pod.tsx b/front/src/pods/embalse-cuenca/embalse-cuenca.pod.tsx new file mode 100644 index 0000000..80894e3 --- /dev/null +++ b/front/src/pods/embalse-cuenca/embalse-cuenca.pod.tsx @@ -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) => { + const { nombreCuenca, embalses } = props; + return ( + + ); +}; diff --git a/front/src/pods/embalse-cuenca/embalse-cuenca.repository.ts b/front/src/pods/embalse-cuenca/embalse-cuenca.repository.ts new file mode 100644 index 0000000..cf2c531 --- /dev/null +++ b/front/src/pods/embalse-cuenca/embalse-cuenca.repository.ts @@ -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 => { + try { + const db = await getDb(); + return await db + .collection("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, + ); + } +}; diff --git a/front/src/pods/embalse-cuenca/index.ts b/front/src/pods/embalse-cuenca/index.ts new file mode 100644 index 0000000..25806f0 --- /dev/null +++ b/front/src/pods/embalse-cuenca/index.ts @@ -0,0 +1,2 @@ +export * from "./embalse-cuenca.pod"; +export * from "./embalse-cuenca.repository";