ClubHub – Fáza 1: Inštrukcie
Tento dokument hovorí, ako budete vo Fáze 1 pracovať a kto čo robí ktorý týždeň. Čo má appka vedieť, nájdete v špecifikácii Fázy 1.
Ako pracujeme
V tíme ste 2 vývojári, A a B (v trojici aj C). Všetci programujete a každý týždeň má každý z vás vlastnú úlohu. Každú zmenu skontroluje ten druhý, než sa zlúči.
Ako vzniká jedna úloha
- Úlohy z plánu po týždňoch si zapíšete na board v Notione a dohodnete sa, kto z vás je A a kto B.
- Vývojár si úlohu priradí a vytvorí si z hlavnej vetvy projektu novú vetvu s názvom
feature/<nazov-ulohy>, napr.feature/karta-podujatia. - Pred začatím napíše krátky plán úlohy podľa stránky Ako plánovať úlohu a dá ho prečítať kolegovi.
- Hotovú úlohu pošle ako merge request.
- Druhý člen tímu spraví code review podľa stránky Code review; po schválení sa zmena zlúči.
- Na konci fázy odprezentujete mentorovi, čo ste spravili.
Definition of Done
Úloha je hotová, keď:
- spĺňa všetky akceptačné kritériá svojej user story,
- dodržiava technické zásady,
- prešla code review a je zlúčená do hlavnej vetvy,
- v konzole nie sú chyby.
Plán po týždňoch
Fáza 1 má 6 piatkov (9. 10. – 20. 11. 2026, 30. 10. sú jesenné prázdniny). Čo nestihnete na hodine, dokončite na pracovných hodinách alebo doma do ďalšieho piatku.
Ak ste v tíme traja, vývojár C preberá pri každom týždni časť práce A alebo B – je to uvedené pri danom týždni. Odkazy A1, B1… vedú na obrazovky v dizajne.
1. týždeň · 9. 10. – Kickoff a setup
Cieľ: viete, čo budete robiť, a obaja máte projekt rozbehnutý lokálne. Dostanete odkaz na dizajn (je v špecifikácii) a mock dáta; dátumy v dátach si upravte podľa potreby.
- Vývojár A: podľa stránky Setup projektu založí repozitár v GitLabe, pridá B, vytvorí a uprace projekt, pushne ho a nastaví ochranu hlavnej vetvy.
- Vývojár B: nainštaluje si prostredie podľa Setup projektu, krok 1. Založí board v Notione a zapíše do neho úlohy z plánu po týždňoch, aby ste videli, ako napredujete. Na konci si naklonuje projekt a spustí ho lokálne.
- Vývojár C (ak ste traja): nainštaluje si prostredie, pomáha B s boardom, na konci si naklonuje projekt.
2. týždeň · 16. 10. – Layout a karta
Cieľ: navigácia appky a karta podujatia.
- Vývojár A: US-01 – layout so spodnou lištou a 2 prázdnymi obrazovkami (Podujatia, Uložené). Dizajn: spodná lišta v A1 a C1.
- Vývojár B: US-02 – komponent karty podujatia podľa dizajnu vrátane náhradného obrázka podľa kategórie. Vloží mock dáta do projektu: events.json – vložte ich napr. do
src/plugins/app@events/_data/events.jsona dátumy si upravte podľa potreby. Dizajn: karta v A1, v design systéme komponenty Event Card a Category Image. - Vývojár C (ak ste traja): vloží mock dáta a urobí náhradný obrázok kategórie – gradient s ikonou podľa dizajnu. B robí len kartu.
3. týždeň · 23. 10. – Zoznam a detail
Cieľ: zoznam podujatí a detail.
- Vývojár A: US-02 – obrazovka Podujatia: načítanie dát, zoradenie, skrytie minulých podujatí, prázdny stav, karty od B. Dizajn: A1, prázdny stav A1b.
- Vývojár B: US-03 – obrazovka detailu so všetkými údajmi, logikou ceny, hláškou „Podujatie sa nenašlo“ a prechodom z karty. Dizajn: B1, B1b.
- Vývojár C (ak ste traja): prázdny stav zoznamu (A1b) a hláška „Podujatie sa nenašlo“ (B1b). A a B robia len hlavné obrazovky.
4. týždeň · 6. 11. – Uloženie a hľadanie
Cieľ: uloženie podujatí a vyhľadávanie.
- Vývojár A: US-06 – ukladanie „Zaujíma ma“, ktoré prežije reštart appky, tlačidlo na karte aj v detaile, obrazovka Uložené s prázdnym stavom. Dizajn: srdiečko v A1 a B1, obrazovka C1, prázdny stav C1b.
- Vývojár B: US-04 – vyhľadávanie bez ohľadu na diakritiku a veľkosť písmen, hláška pri prázdnom výsledku. Dizajn: A1, prázdny výsledok A1c.
- Vývojár C (ak ste traja): obrazovka Uložené s prázdnym stavom (C1, C1b). A robí len ukladanie a tlačidlá.
5. týždeň · 13. 11. – Filtre
Cieľ: filtre spolu s vyhľadávaním.
- Vývojár A: US-05 – filter kategórií (viac naraz) a filter obdobia. Dizajn: A1.
- Vývojár B: US-05 – zobrazenie aktívnych filtrov, zrušenie všetkých, prepojenie filtrov s vyhľadávaním. Zachovanie filtrov po návrate z detailu. Dizajn: aktívne filtre a „Zrušiť filtre“ v A1c.
- Vývojár C (ak ste traja): filter obdobia. A robí len filter kategórií.
6. týždeň · 20. 11. – Prezentácia
Cieľ: hotová fáza odprezentovaná mentorovi.
- Vývojár A: otestuje US-01 až US-03 podľa akceptačných kritérií v prehliadači v mobilnom zobrazení a opraví chyby.
- Vývojár B: otestuje US-04 až US-06 rovnako a opraví chyby. Spolu s A pripraví 10-minútovú prezentáciu.
- Vývojár C (ak ste traja): testovanie v prehliadači v mobilnom zobrazení, príprava prezentácie.
Technické pokyny
Ukážky nižšie sú len kostra – vzhľad a texty robte podľa dizajnu a akceptačných kritérií. Cesty k súborom zodpovedajú štruktúre z technických zásad.
Navigácia s tabmi (US-01)
Spodná lišta je layout, v ktorom sú ostatné obrazovky ako deti v routeri. V router nastavte:
js
routes: [
{ path: '/', redirect: '/tabs/events' },
{
path: '/tabs/',
component: () => import('../_layout/tabs-layout.vue'),
children: [
{ path: '', redirect: '/tabs/events' },
{ path: 'events', component: () => import('../../app@events/events-list.vue') },
{ path: 'events/:id', component: () => import('../../app@events/event-detail/event-detail.vue') },
{ path: 'saved', component: () => import('../../app@saved/saved.vue') },
],
},
],Layout app/_layout/tabs-layout.vue obsahuje ion-tabs so spodnou lištou. Každé tlačidlo má href na svoju obrazovku:
vue
<template>
<ion-page>
<ion-tabs>
<ion-router-outlet />
<ion-tab-bar slot="bottom">
<ion-tab-button tab="events" href="/tabs/events">
<ion-icon :icon="calendarOutline" />
<ion-label>Podujatia</ion-label>
</ion-tab-button>
<ion-tab-button tab="saved" href="/tabs/saved">
<ion-icon :icon="heartOutline" />
<ion-label>Uložené</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-page>
</template>
<script setup>
import { IonPage, IonTabs, IonRouterOutlet, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/vue'
import { calendarOutline, heartOutline } from 'ionicons/icons'
</script>Každá obrazovka (events-list.vue, saved.vue…) má v šablóne ako koreň ion-page a v ňom ion-content.
Načítanie mock dát (US-02)
Súbor events.json vložte do app@events/_data/ a naimportujte ho ako obyčajný modul. Dostanete priamo pole podujatí:
js
import events from './_data/events.json'Detail podľa ID v adrese (US-03)
Na detail sa dostanete cez /tabs/events/<id>. Z karty naň prejdete napríklad router.push(`/tabs/events/${event.id}`). V detaile si ID prečítate z adresy cez useRoute – je to text, preto ho zmeňte na číslo:
js
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import events from '../_data/events.json'
const route = useRoute()
const event = computed(() => events.find(item => item.id === Number(route.params.id)))Keď event nie je nájdený (undefined), zobrazte hlášku „Podujatie sa nenašlo“.
Náhradný obrázok kategórie (US-02)
Keď podujatie nemá obrázok, karta aj detail ukážu fialový gradient s ikonou kategórie (v dizajne komponent Category Image). Je to div s gradientom z palety a ion-icon v strede, nie obrázok:
| Kategória | Ikona |
|---|---|
| Šport | footballOutline |
| Kultúra | musicalNotesOutline |
| Veda a technika | flaskOutline |
| Výlety | mapOutline |
| Krúžky | colorPaletteOutline |
| Ostatné | ellipsisHorizontalOutline |
vue
<template>
<div class="flex aspect-video items-center justify-center" :style="{ background: 'var(--gradient-primary)' }">
<ion-icon :icon="categoryIcon" class="size-16 text-primary-contrast" />
</div>
</template>Priradenie kategórie k ikone majte na jednom mieste, napr. v _utils/category-icons.js, aby ho karta aj detail používali rovnako.
Formát dátumu (US-02, US-03)
Dátumy sú v dátach ako text, napr. "2026-12-18T17:00:00". Do tvaru „18. 12. 2026 17:00“ ich prevedie funkcia v app/_utils/format-date.js:
js
export function formatDate(isoString) {
return new Date(isoString).toLocaleString('sk-SK', {
day: 'numeric',
month: 'numeric',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
})
}Vyhľadávanie bez diakritiky (US-04)
Text vyhľadávania aj názov podujatia najprv upravte rovnakou funkciou – bez diakritiky, malými písmenami a bez medzier na okrajoch – a až potom ich porovnajte. Funkcia v app/_utils/normalize-text.js:
js
export function normalizeText(text) {
return text
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.trim()
}Použitie: normalizeText(event.title).includes(normalizeText(query)).
Uloženie „Zaujíma ma“ (US-06)
Do localStorage sa dá uložiť len text, preto pole ID uložených podujatí prevediete cez JSON.stringify a pri načítaní späť cez JSON.parse. Funkcie v app/_utils/saved-events.js:
js
const STORAGE_KEY = 'savedEventIds'
export function loadSavedIds() {
return JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')
}
export function storeSavedIds(ids) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(ids))
}Pri každom kliknutí na „Zaujíma ma“ ID pridajte do poľa alebo ho z neho odoberte a pole znova uložte cez storeSavedIds. Keď appku zatvoríte a otvoríte, loadSavedIds vráti uložené ID.
Na čo si dať pozor
- Týždeň 1: kým A zakladá projekt, B nemá čo kódovať. Preto robí board a prostredie a projekt si naklonuje až na konci hodiny.
- Týždeň 3: A potrebuje kartu od B z 2. týždňa. Ak ešte nie je zlúčená, A začne s dočasnou kartou a neskôr ju vymení.
- Týždeň 5: obaja meníte tú istú obrazovku, takže pri zlúčení vzniknú konflikty. Dohodnite sa na začiatku, kto zlúči ako prvý; druhý si potom stiahne zmeny a konflikty vyrieši.
Odovzdanie fázy
Fáza končí 20. 11. prezentáciou, na ktorej každý tím za 10 minút ukáže mentorovi, čo spravil.
Po prezentácii dostanete zadanie Fázy 2.