# Homepage Rows The homepage layout is now driven by the API. Instead of hardcoding which rows to show and in what order, the frontend fetches a configuration from the backend and renders rows dynamically. ## How it works 1. Frontend calls `GET /client/v1/homepage/rows` on page load 2. The API returns an ordered list of active rows, each with a `rowType` that tells the frontend which component to render 3. Frontend renders each row in the returned order, using the `rowType` to pick the right component ## API ### GET /client/v1/homepage/rows Returns active homepage rows ordered by `displayOrder`. **Response:** ```json [ { "id": "aBcDeFgHiJ", "rowType": 1, "title": "Banner", "displayOrder": 1, "isActive": true }, { "id": "kLmNoPqRsT", "rowType": 3, "title": "Slow TV", "displayOrder": 2, "isActive": true }, { "id": "uVwXyZ1234", "rowType": 9, "title": "Filma", "displayOrder": 3, "isActive": true } ] ``` ## HomepageRowType enum ```csharp public enum HomepageRowType { Banner = 1, LiveChannels = 2, SlowTv = 3, LiveEvents = 4, PreliveEvents = 5, ContinueWatching = 6, Shorts = 7, Videos = 8, Movies = 9, Series = 10, Channels = 11 } ``` | Value | Name | Component | |-------|------------------|----------------------| | 1 | Banner | `HomeBanner` | | 2 | LiveChannels | `HomeLiveChannels` | | 3 | SlowTv | `HomeSlowTv` | | 4 | LiveEvents | `HomeLiveEvents` | | 5 | PreliveEvents | `HomePreliveEvents` | | 6 | ContinueWatching | `HomeContinueWatching` | | 7 | Shorts | `HomeShorts` | | 8 | Videos | `HomeVideos` | | 9 | Movies | `HomeMovies` | | 10 | Series | `HomeShows` | | 11 | Channels | `HomeChannels` | ## Frontend implementation ### 1. Create a component map Map each `rowType` to the corresponding component: ```tsx const COMPONENT_MAP: Record> = { 1: HomeBanner, 2: HomeLiveChannels, 3: HomeSlowTv, 4: HomeLiveEvents, 5: HomePreliveEvents, 6: HomeContinueWatching, 7: HomeShorts, 8: HomeVideos, 9: HomeMovies, 10: HomeShows, 11: HomeChannels, }; ``` ### 2. Fetch rows and render dynamically ```tsx function HomePage() { const { data: rows } = useQuery({ queryKey: ["homepage-rows"], queryFn: () => api.get("/client/v1/homepage/rows"), }); if (!rows) return ; return ( <> {rows.map((row) => { const Component = COMPONENT_MAP[row.rowType]; if (!Component) return null; return ; })} ); } ``` Each component keeps its existing data-fetching logic but should check `row.filterParams` for additional filters (e.g., channelId). The **order** and **visibility** of rows is now controlled by the API instead of being hardcoded. ### 3. Apply filterParams `filterParams` is a nullable JSON string with optional filters. Components should parse it and pass the values to their API calls: ```tsx // Example filterParams: {"channelId": "2D5jWBl6MZ"} function HomeVideos({ row }: RowProps) { const filters = row.filterParams ? JSON.parse(row.filterParams) : {}; const { data } = useQuery({ queryKey: ["videos", filters], queryFn: () => api.get("/videos/vod", { params: { pageSize: 8, ...filters } }), }); // ... } ``` This allows the admin to create multiple rows of the same type with different filters. For example, two "Videos" rows — one for all videos and one filtered to a specific channel. ## What changes from the current implementation | Before | After | |--------|-------| | Row order is hardcoded in frontend | Row order comes from API | | Adding/removing a row requires a frontend deploy | Admin toggles `isActive` or changes `displayOrder` | | Row titles are hardcoded | Titles come from API via `row.title` | ## Admin endpoints These are used by the admin panel to manage rows: | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/admin/v1/homepage-rows` | List all rows | | GET | `/admin/v1/homepage-rows/{id}` | Get a single row | | POST | `/admin/v1/homepage-rows` | Create a row | | PUT | `/admin/v1/homepage-rows/{id}` | Update a row | | DELETE | `/admin/v1/homepage-rows/{id}` | Delete a row | ### Create/Update payload ```json { "rowType": 8, "title": "Gjirafa Studios", "displayOrder": 3, "isActive": true, "filterParams": "{\"channelId\":\"2D5jWBl6MZ\"}" } ``` `filterParams` is optional. When null, the row has no extra filters. Supported keys depend on the row type (e.g., `channelId` for Videos). ## Notes - The response is cached on the backend. Changes made via admin are reflected after cache invalidation (handled automatically via Debezium CDC). - Unknown `rowType` values should be skipped (future-proofing for new row types). - `rowType` is validated on create/update — only values from the enum (1-11) are accepted.