From 7db2460833dcb778a3cc256454e4464fe81b82c8 Mon Sep 17 00:00:00 2001 From: Monika Stefanova Date: Thu, 5 Feb 2026 14:11:31 +0100 Subject: [PATCH 1/6] mapEmbalseToSearch on a separate file --- front/src/pods/embalse-search/embalse-search.mapper.ts | 7 +++++++ front/src/pods/embalse-search/embalse-search.tsx | 8 ++------ .../{embalse-search.model.ts => embalse-search.vm.ts} | 0 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 front/src/pods/embalse-search/embalse-search.mapper.ts rename front/src/pods/embalse-search/{embalse-search.model.ts => embalse-search.vm.ts} (100%) diff --git a/front/src/pods/embalse-search/embalse-search.mapper.ts b/front/src/pods/embalse-search/embalse-search.mapper.ts new file mode 100644 index 0000000..1804100 --- /dev/null +++ b/front/src/pods/embalse-search/embalse-search.mapper.ts @@ -0,0 +1,7 @@ +import { EmbalseSearchModel } from "./embalse-search.vm"; +import { Embalse } from "./api"; + +export const mapEmbalseToSearch = (embalse: Embalse): EmbalseSearchModel => ({ + slug: embalse._id, + name: `${embalse.name} (${embalse.province})`, +}); diff --git a/front/src/pods/embalse-search/embalse-search.tsx b/front/src/pods/embalse-search/embalse-search.tsx index 5b5c7b4..906e126 100644 --- a/front/src/pods/embalse-search/embalse-search.tsx +++ b/front/src/pods/embalse-search/embalse-search.tsx @@ -4,12 +4,8 @@ import { useState, useEffect } from "react"; import { useCombobox } from "downshift"; import { SearchIcon } from "./components/search-icon"; import { Embalse, getEmbalsesCollection } from "./api"; -import { EmbalseSearchModel } from "./embalse-search.model"; - -const mapEmbalseToSearch = (embalse: Embalse): EmbalseSearchModel => ({ - slug: embalse._id, - name: `${embalse.name} (${embalse.province})`, -}); +import { EmbalseSearchModel } from "./embalse-search.vm"; +import { mapEmbalseToSearch } from "./embalse-search.mapper"; export const EmbalseSearch: React.FC = () => { const [embalses, setEmbalses] = useState([]); diff --git a/front/src/pods/embalse-search/embalse-search.model.ts b/front/src/pods/embalse-search/embalse-search.vm.ts similarity index 100% rename from front/src/pods/embalse-search/embalse-search.model.ts rename to front/src/pods/embalse-search/embalse-search.vm.ts From 48e6657516ba248aa7236311bb6d5f156feec806 Mon Sep 17 00:00:00 2001 From: Monika Stefanova Date: Thu, 5 Feb 2026 15:29:17 +0100 Subject: [PATCH 2/6] done: fetch data from the DB and use it in the search input; mapper function in a separate file --- front/src/app/page.tsx | 8 +- .../src/pods/embalse-search/api/api.model.ts | 4 +- .../embalse-search/api/embalse-search.mock.ts | 239 ------------------ .../pods/embalse-search/api/embalse.api.ts | 4 +- front/src/pods/embalse-search/api/index.ts | 1 - .../embalse-search/embalse-search.mapper.ts | 10 +- .../embalse-search.repository.ts | 27 ++ .../pods/embalse-search/embalse-search.tsx | 19 +- .../pods/embalse-search/embalse-search.vm.ts | 2 +- 9 files changed, 52 insertions(+), 262 deletions(-) delete mode 100644 front/src/pods/embalse-search/api/embalse-search.mock.ts create mode 100644 front/src/pods/embalse-search/embalse-search.repository.ts diff --git a/front/src/app/page.tsx b/front/src/app/page.tsx index fb80fb1..05e01be 100644 --- a/front/src/app/page.tsx +++ b/front/src/app/page.tsx @@ -1,8 +1,10 @@ import { EmbalseSearch } from "@/pods/embalse-search"; -import Link from "next/link"; +import { getEmbalsesCollection } from "@/pods/embalse-search/api"; -const RootPage = () => { - return ; +const RootPage = async () => { + const embalses = await getEmbalsesCollection(); + + return ; }; export default RootPage; diff --git a/front/src/pods/embalse-search/api/api.model.ts b/front/src/pods/embalse-search/api/api.model.ts index e706396..3715b4e 100644 --- a/front/src/pods/embalse-search/api/api.model.ts +++ b/front/src/pods/embalse-search/api/api.model.ts @@ -1,5 +1,5 @@ export interface Embalse { _id: string; - name: string; - province: string; + nombre: string; + provincia: string; } diff --git a/front/src/pods/embalse-search/api/embalse-search.mock.ts b/front/src/pods/embalse-search/api/embalse-search.mock.ts deleted file mode 100644 index cf888c7..0000000 --- a/front/src/pods/embalse-search/api/embalse-search.mock.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { Embalse } from "./api.model"; - -export const embalseSearchMock: Embalse[] = [ - { - _id: "alarcón", - name: "Embalse de Alarcón", - province: "Cuenca", - }, - { - _id: "la-serena", - name: "Embalse de La Serena", - province: "Badajoz", - }, - { - _id: "alcántara", - name: "Embalse de Alcántara", - province: "Cáceres", - }, - { - _id: "buendía", - name: "Embalse de Buendía", - province: "Guadalajara", - }, - { - _id: "entrepeñas", - name: "Embalse de Entrepeñas", - province: "Guadalajara", - }, - { - _id: "yesa", - name: "Embalse de Yesa", - province: "Navarra", - }, - { - _id: "mequinenza", - name: "Embalse de Mequinenza", - province: "Zaragoza", - }, - { - _id: "mediano", - name: "Embalse de Mediano", - province: "Huesca", - }, - { - _id: "el-grado", - name: "Embalse de El Grado", - province: "Huesca", - }, - { - _id: "la-tranquera", - name: "Embalse de La Tranquera", - province: "Zaragoza", - }, - { - _id: "santillana", - name: "Embalse de Santillana", - province: "Madrid", - }, - { - _id: "valmayor", - name: "Embalse de Valmayor", - province: "Madrid", - }, - { - _id: "el-atazar", - name: "Embalse de El Atazar", - province: "Madrid", - }, - { - _id: "san-juan", - name: "Embalse de San Juan", - province: "Madrid", - }, - { - _id: "navacerrada", - name: "Embalse de Navacerrada", - province: "Madrid", - }, - { - _id: "iznájar", - name: "Embalse de Iznájar", - province: "Córdoba", - }, - { - _id: "la-viñuela", - name: "Embalse de La Viñuela", - province: "Málaga", - }, - { - _id: "conde-de-guadalhorce", - name: "Embalse de Conde de Guadalhorce", - province: "Málaga", - }, - { - _id: "guadalteba", - name: "Embalse de Guadalteba", - province: "Málaga", - }, - { - _id: "la-colada", - name: "Embalse de La Colada", - province: "Córdoba", - }, - { - _id: "la-breña", - name: "Embalse de La Breña", - province: "Córdoba", - }, - { - _id: "guadalcacín", - name: "Embalse de Guadalcacín", - province: "Cádiz", - }, - { - _id: "zahara", - name: "Embalse de Zahara", - province: "Cádiz", - }, - { - _id: "bembézar", - name: "Embalse de Bembézar", - province: "Córdoba", - }, - { - _id: "negratín", - name: "Embalse de Negratín", - province: "Granada", - }, - { - _id: "canales", - name: "Embalse de Canales", - province: "Granada", - }, - { - _id: "los-bermejales", - name: "Embalse de Los Bermejales", - province: "Granada", - }, - { - _id: "cubillas", - name: "Embalse de Cubillas", - province: "Granada", - }, - { - _id: "rules", - name: "Embalse de Rules", - province: "Granada", - }, - { - _id: "el-gergal", - name: "Embalse de El Gergal", - province: "Sevilla", - }, - { - _id: "melonares", - name: "Embalse de Melonares", - province: "Sevilla", - }, - { - _id: "el-pintado", - name: "Embalse de El Pintado", - province: "Sevilla", - }, - { - _id: "la-minilla", - name: "Embalse de La Minilla", - province: "Sevilla", - }, - { - _id: "aracena", - name: "Embalse de Aracena", - province: "Huelva", - }, - { - _id: "andévalo", - name: "Embalse de Andévalo", - province: "Huelva", - }, - { - _id: "chanza", - name: "Embalse de Chanza", - province: "Huelva", - }, - { - _id: "el-encinarejo", - name: "Embalse de El Encinarejo", - province: "Jaén", - }, - { - _id: "el-rumblar", - name: "Embalse de El Rumblar", - province: "Jaén", - }, - { - _id: "el-tranco", - name: "Embalse de El Tranco", - province: "Jaén", - }, - { - _id: "giribaile", - name: "Embalse de Giribaile", - province: "Jaén", - }, - { - _id: "guadalmena", - name: "Embalse de Guadalmena", - province: "Jaén", - }, - { - _id: "la-bolera", - name: "Embalse de La Bolera", - province: "Jaén", - }, - { - _id: "tous", - name: "Embalse de Tous", - province: "Valencia", - }, - { - _id: "benagéber", - name: "Embalse de Benagéber", - province: "Valencia", - }, - { - _id: "orellana", - name: "Embalse de Orellana", - province: "Badajoz", - }, - { - _id: "cíjara", - name: "Embalse de Cíjara", - province: "Badajoz", - }, - { - _id: "zújar", - name: "Embalse de Zújar", - province: "Badajoz", - }, -]; diff --git a/front/src/pods/embalse-search/api/embalse.api.ts b/front/src/pods/embalse-search/api/embalse.api.ts index 4e3c24f..9f1cabe 100644 --- a/front/src/pods/embalse-search/api/embalse.api.ts +++ b/front/src/pods/embalse-search/api/embalse.api.ts @@ -1,6 +1,6 @@ +import { getEmbalsesFromDb } from "../embalse-search.repository"; import { Embalse } from "./api.model"; -import { embalseSearchMock } from "./embalse-search.mock"; export const getEmbalsesCollection = async (): Promise => { - return embalseSearchMock; + return getEmbalsesFromDb(); }; diff --git a/front/src/pods/embalse-search/api/index.ts b/front/src/pods/embalse-search/api/index.ts index 2431999..b512195 100644 --- a/front/src/pods/embalse-search/api/index.ts +++ b/front/src/pods/embalse-search/api/index.ts @@ -1,3 +1,2 @@ export * from "./api.model"; export * from "./embalse.api"; -export * from "./embalse-search.mock"; diff --git a/front/src/pods/embalse-search/embalse-search.mapper.ts b/front/src/pods/embalse-search/embalse-search.mapper.ts index 1804100..229d5b9 100644 --- a/front/src/pods/embalse-search/embalse-search.mapper.ts +++ b/front/src/pods/embalse-search/embalse-search.mapper.ts @@ -1,7 +1,9 @@ -import { EmbalseSearchModel } from "./embalse-search.vm"; -import { Embalse } from "./api"; +import * as vm from "./embalse-search.vm"; +import * as api from "db-model"; -export const mapEmbalseToSearch = (embalse: Embalse): EmbalseSearchModel => ({ +export const mapEmbalseToSearch = ( + embalse: api.Embalse, +): vm.EmbalseSearchModel => ({ slug: embalse._id, - name: `${embalse.name} (${embalse.province})`, + name: `${embalse.nombre} (${embalse.provincia})`, }); diff --git a/front/src/pods/embalse-search/embalse-search.repository.ts b/front/src/pods/embalse-search/embalse-search.repository.ts new file mode 100644 index 0000000..5e92f68 --- /dev/null +++ b/front/src/pods/embalse-search/embalse-search.repository.ts @@ -0,0 +1,27 @@ +"use server"; + +import { getDb } from "@/lib/mongodb"; +import type { Embalse } from "./api/api.model"; + +export async function getEmbalsesFromDb(): Promise { + const db = getDb(); + const docs = await db + .collection("embalses") + .find( + {}, + { + projection: { + _id: 1, + nombre: 1, + provincia: 1, + }, + }, + ) + .toArray(); + + return docs.map((doc) => ({ + _id: doc._id?.toString() ?? "", + nombre: doc.nombre ?? "", + provincia: doc.provincia ?? "", + })); +} diff --git a/front/src/pods/embalse-search/embalse-search.tsx b/front/src/pods/embalse-search/embalse-search.tsx index 906e126..4744f30 100644 --- a/front/src/pods/embalse-search/embalse-search.tsx +++ b/front/src/pods/embalse-search/embalse-search.tsx @@ -1,30 +1,29 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { useCombobox } from "downshift"; import { SearchIcon } from "./components/search-icon"; -import { Embalse, getEmbalsesCollection } from "./api"; +import { Embalse } from "./api"; import { EmbalseSearchModel } from "./embalse-search.vm"; import { mapEmbalseToSearch } from "./embalse-search.mapper"; -export const EmbalseSearch: React.FC = () => { - const [embalses, setEmbalses] = useState([]); +interface EmbalseSearchProps { + embalses: Embalse[]; +} + +export const EmbalseSearch: React.FC = ({ embalses }) => { const [filteredEmbalses, setFilteredEmbalses] = useState< EmbalseSearchModel[] >([]); - useEffect(() => { - getEmbalsesCollection().then(setEmbalses); - }, []); - const getFilteredEmbalses = (inputValue: string): EmbalseSearchModel[] => { const lower = inputValue.toLowerCase(); return embalses .filter( (e) => - e.name.toLowerCase().includes(lower) || - e.province.toLowerCase().includes(lower), + e.nombre.toLowerCase().includes(lower) || + e.provincia.toLowerCase().includes(lower), ) .map(mapEmbalseToSearch); }; diff --git a/front/src/pods/embalse-search/embalse-search.vm.ts b/front/src/pods/embalse-search/embalse-search.vm.ts index a6dae0b..8fd1931 100644 --- a/front/src/pods/embalse-search/embalse-search.vm.ts +++ b/front/src/pods/embalse-search/embalse-search.vm.ts @@ -1,4 +1,4 @@ export interface EmbalseSearchModel { - slug: string; // embalse id used in the URL + slug: string; // params de la URL -> nombre del embalse name: string; // Combination of name (province) } From 9f3af2ba171d10660b75201ba20c176ed13a7b0a Mon Sep 17 00:00:00 2001 From: Monika Stefanova Date: Thu, 5 Feb 2026 17:28:16 +0100 Subject: [PATCH 3/6] update embalse-search.repository --- .../embalse-search/embalse-search.repository.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/front/src/pods/embalse-search/embalse-search.repository.ts b/front/src/pods/embalse-search/embalse-search.repository.ts index 5e92f68..6a2a7d8 100644 --- a/front/src/pods/embalse-search/embalse-search.repository.ts +++ b/front/src/pods/embalse-search/embalse-search.repository.ts @@ -14,14 +14,25 @@ export async function getEmbalsesFromDb(): Promise { _id: 1, nombre: 1, provincia: 1, + slug: 1, }, }, ) .toArray(); return docs.map((doc) => ({ - _id: doc._id?.toString() ?? "", + _id: doc.slug ?? createSlug(doc.nombre ?? ""), nombre: doc.nombre ?? "", provincia: doc.provincia ?? "", })); } + +const createSlug = (nombre: string): string => { + return nombre + .toLowerCase() + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .replace(/ñ/g, "n") + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); +}; From fe973272fd066167e5b10666c07e0a602a83402e Mon Sep 17 00:00:00 2001 From: Monika Stefanova Date: Thu, 5 Feb 2026 17:32:39 +0100 Subject: [PATCH 4/6] update props --- front/src/pods/embalse-search/embalse-search.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/front/src/pods/embalse-search/embalse-search.tsx b/front/src/pods/embalse-search/embalse-search.tsx index 4744f30..d69cf49 100644 --- a/front/src/pods/embalse-search/embalse-search.tsx +++ b/front/src/pods/embalse-search/embalse-search.tsx @@ -7,11 +7,12 @@ import { Embalse } from "./api"; import { EmbalseSearchModel } from "./embalse-search.vm"; import { mapEmbalseToSearch } from "./embalse-search.mapper"; -interface EmbalseSearchProps { +interface Props { embalses: Embalse[]; } -export const EmbalseSearch: React.FC = ({ embalses }) => { +export const EmbalseSearch: React.FC = (props) => { + const { embalses } = props; const [filteredEmbalses, setFilteredEmbalses] = useState< EmbalseSearchModel[] >([]); From 3fa41925fd09a0d6af4442e889eec0603eb4781e Mon Sep 17 00:00:00 2001 From: Monika Stefanova Date: Thu, 5 Feb 2026 17:43:11 +0100 Subject: [PATCH 5/6] comment update --- front/src/pods/embalse-search/embalse-search.vm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/pods/embalse-search/embalse-search.vm.ts b/front/src/pods/embalse-search/embalse-search.vm.ts index 8fd1931..84b37b2 100644 --- a/front/src/pods/embalse-search/embalse-search.vm.ts +++ b/front/src/pods/embalse-search/embalse-search.vm.ts @@ -1,4 +1,4 @@ export interface EmbalseSearchModel { - slug: string; // params de la URL -> nombre del embalse + slug: string; // Name of the reservoir for the URL name: string; // Combination of name (province) } From 6226d7bc01ccf65c593017671075da02a2a3560a Mon Sep 17 00:00:00 2001 From: Braulio Date: Fri, 6 Feb 2026 08:31:35 +0100 Subject: [PATCH 6/6] test --- front/src/pods/embalse-search/embalse-search.repository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/pods/embalse-search/embalse-search.repository.ts b/front/src/pods/embalse-search/embalse-search.repository.ts index 6a2a7d8..e2d9156 100644 --- a/front/src/pods/embalse-search/embalse-search.repository.ts +++ b/front/src/pods/embalse-search/embalse-search.repository.ts @@ -4,7 +4,7 @@ import { getDb } from "@/lib/mongodb"; import type { Embalse } from "./api/api.model"; export async function getEmbalsesFromDb(): Promise { - const db = getDb(); + const db = await getDb(); const docs = await db .collection("embalses") .find(