Productbiografie ‐ Liam - Liamvanbart1/Framez GitHub Wiki
- Ik wil nog meer leren over CSS.
Ik heb de basis aan het begin van de opleiding geleerd, maar heb daar te lang op vertrouwd. Ik merk tijdens de minor dat er nog veel dingen zijn die ik niet weet en die vaak handiger/beter zijn dan de oplossingen die ik bedenk.
- Ik wil graag meer leren over back-end.
Tijdens de API zijn we hier al een klein beetje mee bezig geweest door NodeJS te gebruiken en dit vond ik erg interessant. Ik hoop hier tijdens de meesterproef meer over te kunnen leren.
- Ik wil tijdens de meesterproef graag taakgerichter worden en mijn taken op tijd afmaken.
Ik merk dat ik vaak goede ideeën heb, maar deze door tijdgebrek uiteindelijk niet kan realiseren.
Aan het begin van deze week zijn wij met het team naar Framer Framed gegaan om meer informatie over de opdracht te krijgen. Voorafgaand aan de afspraak hebben we met het team een vragenlijst opgesteld. Wij waren als tweede team aan de beurt, dus de opdrachtgever had al een vrij vast verhaal dat hij aan ons vertelde. We kunnen kiezen uit twee opdrachten, namelijk:
-
Opdracht 1: Ontwerp en bouw een ‘mirror’ voor de huidige WordPress website van Framer Framed voor een specifieke doelgroep met specifieke toegankelijkheidseisen.
-
Opdracht 2: Ontsluiting van het digitale archief van Framer Framed voor een specifieke doelgroep met specifieke eisen op het gebied van toegankelijkheid. Ontwerp en bouw een nieuwe interface voor het digitale archief van Framer Framed opgeslagen en georganiseerd in de database van Bibliograph.
Ik wist eigenlijk al meteen dat opdracht 1 niet mogelijk zou zijn voor ons aangezien de meesterproef bedoeld was een afsluitende opdracht voor alles wat we deze periode hebben geleerd. Het probleem hierbij is dat we niks met Wordpress hebben gedaan en het uitvogelen van de Wordpress Api en de ingewikkelde achterkant van de website zou te veel tijd kosten. Daarom was het eigenlijk al vrij snel duidelijk dat we ons moeten focussen op opdracht 2.
Het probleem tijdens de debrief was echter dat ik niet de kans kreeg om aan de opdrachtgever uit te leggen waarom opdracht 1 niet haalbaar zou zijn. Omdat hij vond dat één van de twee teams opdracht 1 moest uitwerken, werd daar helaas geen ruimte voor gegeven. Hierdoor kwamen we een beetje vast te zitten en konden wij ook niet verder.
Na overleg met Declan op woensdag hadden we besloten toch voor opdracht 1 te gaan. Hij gaf aan dat we niet dwars moesten gaan liggen tegenover de opdrachtgever, maar dat we een duidelijk voorstel moesten schrijven waarin we uitlegden waarom opdracht 2 de betere optie zou zijn — en dit goed moesten uitwerken.
Uiteindelijk hebben wij besloten om een nieuwe ontsluiting te maken van het digitale archief van Framer Framed waarbij wij de focus leggen op toegankelijkheid voor de volgende doelgroepen:
- Toegankelijk voor Mensen met een visuele beperking (slechtziend of blind)
- Toegankelijk voor gebruikers van screenreaders of spraaknavigatie
- Toegankelijk voor gebruikers zonder muis
Hierbij maken we het visueel wel aantrekkelijk maar proberen we het zo toegankelijk mogelijk te maken. We zitten helaas met wat beperkingen vanuit de database omdat hier bijvoorbeeld geen Alt teksten bij de afbeeldingen staan.
Na het bepalen van de opdracht zijn we bezig gegaan met de het maken van lo-fi wireframes en een sitemap.




Uiteindelijk hebben wij gekozen voor het laatste wireframe. Daarnaast hebben we ook de codeconventies geformuleerd.
Deze week begon op maandag, toen wij op bezoek gingen bij de opdrachtgever. Wij hadden ons hier goed op voorbereid, omdat we de opdrachtgever moesten overtuigen. We zijn met beide teams tegelijkertijd naar Framer Framed gegaan en hebben duidelijk uitgelegd dat opdracht 1 niet voldoende was voor de meesterproef, en dat we daarom beiden voor opdracht 2 moesten gaan.
De opdrachtgever baalde hiervan, omdat hem niet was verteld dat WordPress geen optie was. Hij gaf aan dat hij behoorlijk wat tijd had gestoken in het formuleren van de opdracht, en het is dan ook logisch dat hij teleurgesteld was. Later tijdens de meeting sloot de developer aan die ons gaat ondersteunen tijdens de meesterproef hierbij hebben wat meer duidelijkheid kunnen krijgen over de opzet van de database en de mogelijkheden qua endpoints. Al met al was dit een goed gesprek en was het ook fijn dat we eindelijk door konden gaan met ontwerpen/plannen.
Na het overleg met de opdrachtgever ben ik begonnen met één van mijn leerdoelen namelijk meer designen ik heb ervoor gekozen om het design voor onze app te maken in figma. Ik heb de huidige stijl van Biblio-graph genomen als inspiratie.




Ik heb de designs tijdens de feedbacksessie besproken met Sanne. Hij gaf aan dat we beter moesten nadenken over de doelgroep waarvoor we ontwerpen — namelijk mensen met een visuele beperking, zoals slechtzienden. Naar aanleiding daarvan heb ik ervoor gekozen om het design aan te passen, en om hier ook extra aandacht aan te besteden tijdens de technische uitwerking in code. Omdat ik niet te lang bezig wil zijn met designen in figma maar liever verder ga in code zelf heb ik besloten om niet verder te itereren op het design.
Aan het begin van deze week hebben we van de developer de nieuwe API gekregen en de bijbehorende Endpoints. Ik heb besloten om te gaan werken aan de zoekfunctie. Hieronder volgt het begin hiervan.
Ten eerste heb ik besloten om alle endpoints in een .env-bestand te zetten, zodat deze niet openbaar op GitHub komen te staan. Ik merkte namelijk dat bij het opvragen van een gebruiker het gehashte wachtwoord zichtbaar is, wat natuurlijk niet de bedoeling is. Vervolgens heb ik een nieuwe route aangemaakt voor het search component. We willen de search over de hele app bruikbaar maken. Hiervoor moet het fetchen naar de search endpoint gebeuren in de client en niet in de server aangezien dit ervoor zou zorgen dat bij elke letter de pagina opnieuw zou laden.
const baseUrl = process.env.NIEUWE_BASE_URL;
const query = req.query.q;
try {
const apiUrl = new URL(`/search?s=${encodeURIComponent(query)}`, baseUrl);
const response = await fetch(apiUrl);
const data = await response.json();
res.json({ results: data });
} catch (err) {
console.error("Search failed:", err);
res.status(500).json({ error: "Search error" });
}
Op woensdag heb ik met victor samen naar een bug gekeken. Omdat ik new URL gebruikte (geleerd tijdens api van Declan) pakte hij alleen de baseURL uit het .env bestand dit zorgde ervoor dat de search parameters dus /api/ff/search niet werden mee gegeven. ik heb dit aangepast door het volgende aan te passen.
app.get("/search", async (req, res) => {
const baseUrl = process.env.NIEUWE_BASE_URL;
const query = req.query.q;
try {
const apiUrl = new URL("/api/ff/search", baseUrl);
apiUrl.searchParams.append("s", query); // Veilig en automatisch geëncodeerd
// new URL is minder foutgevoelig en zorgt ervoor dat de string correct wordt geparsed naar een geldige URL
const response = await fetch(apiUrl);
console.log(response, "response");
const data = await response.json();
console.log(data, "data");
res.json({ results: data });
} catch (err) {
console.error("Search failed:", err);
res.status(500).json({ error: "Search error" });
}
});
Het gebruik van new URL() zorgt voor automatische validatie, correcte samenvoeging van base-URL en pad, eenvoudige en veilige toevoeging van queryparameters, en maakt de URL makkelijker te beheren en debuggen dan het handmatig samenstellen van een string.
Het fetchen gebeurt zoals eerder gezegd dus in de front-end dat doe ik met de volgende code:
const input = document.getElementById("search-input");
const overlay = document.getElementById("search-overlay");
const resultsContainer = document.getElementById("search-results");
let timeout;
input.addEventListener("input", () => {
const query = input.value.trim();
clearTimeout(timeout);
if (query.length < 2) {
overlay.classList.add("hidden");
resultsContainer.innerHTML = "";
return;
}
timeout = setTimeout(async () => {
try {
const res = await fetch(`/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
if (data.results && data.results.length > 0) {
resultsContainer.innerHTML = data.results
.map(
(result) =>
`<div>${result.title || result.title_en || result.name}</div>`
)
.join("");
overlay.classList.remove("hidden");
} else {
resultsContainer.innerHTML = "<div>No results found</div>";
overlay.classList.remove("hidden");
}
} catch (err) {
resultsContainer.innerHTML = "<div>Error loading search</div>";
overlay.classList.remove("hidden");
console.error(err);
}
}, 300);
});
De setTimeout zorgt hier voor debouncing, omdat de functie anders erg vaak wordt aangeroepen. Zonder deze techniek zou bij elke toetsaanslag de fetch worden uitgevoerd. Wat er nu gebeurt, is dat de functie pas 300 ms na de laatste toetsaanslag wordt aangeroepen.
Helaas zijn de resultaten uit de search heel erg verschillend op dit moment kan ik op geen manier identificeren wat voor object ik terug krijg. Wanneer je zoekt via de algemene zoekfunctie, bevatten de resultaten soms een ff_id, soms een aid, soms een uuid, enzovoort. Wij willen graag kunnen zien wat voor type object het resultaat is, zodat we deze kunnen categoriseren. Als het bijvoorbeeld een persoon is, linken we naar de detailpagina van die persoon; als het een evenement is, dan linken we naar de detailpagina van dat evenement. Omdat dit nu niet mogelijk is heb ik besloten verder te gaan aan het maken/stylen van de header.