Hallo Stroke

Features

User-facing and admin features and their routes.

User features

Home

  • / — HomeNotLoggedIn: latest 2 videos + 2 articles, 5-icon menu grid, emergency button (dials the per-province number from GET /api/emergency/nearby, falling back to tel:112), FAQ, user guide.
  • /homelogin — HomeLoggedIn: same content + avatar, notifications bell, hamburger sidebar (language, profile, privacy, FAQ, logout), push registration on mount.

The section order and visibility of both home pages is driven by remote config — see Remote config. Resolution: GPS → inputted domicile → DEFAULT_CONFIG.

Videos & Articles

  • /videos, /video/:id — educational videos (YouTube embed) with comments.
  • /articles, /article/:id — articles rendered from react-quill content, with likes and comments.
  • Video thumbnails come straight from the API (largest real resolution) and render through <SmartThumb> (src/utils/youtube.js) — a failed load falls back to a placeholder; it never guesses maxres URLs, so low-res videos (e.g. Me at the zoo) still show their real thumbnail.
  • Save-for-later supported on both (see backend POST /api/articles/save, POST /api/youtube/save).

Faskes finder

/faskes (FaskesStroke.js) — uses the browser geolocation to find nearby stroke facilities (GET /api/faskes/nearby) and doctors. Doctors come from GET /api/dokter/nearby (province-matched, sorted by distance, each card shows a ⚲ km badge); on failure it falls back to GET /api/dokter (unsorted, no badges). A radius dropdown on the Dokter tab (Semua / ≤5 / ≤10 / ≤25 / ≤50 km) filters client-side — default "Semua" hides nobody. Tabs for Faskes/Dokter, Google Maps links, call buttons, telemedicine links.

Teleconsultation

/telekonsultasi (Telekonsultasi.js) — redirects to telehealth apps: Halodoc, Alodokter, KlikDokter, Dkonsul. Uses deep links with app-store fallback.

Profile & notifications

  • /profile, /edit-profile — profile + image upload (POST /api/profile multipart), preferences, roles.
  • /notif — push notification list, mark-as-read.
  • /reminders — reminder list with type filter and medicine grouping.

Admin panel

Navigation via AdminSidebar (11 menu items + help + logout):

AreaRoutes
Overview/admin/overview — aggregate dashboard (totals, growth, activity, exports)
Videos/admin/video, /admin/video/upload, /admin/video/edit/:videoId — upload/edit forms show a live thumbnail preview under the URL field (parsed from the URL; edit page falls back to the stored thumbnail)
Articles/admin/article, /admin/article/upload, /admin/article/edit/:id
Communities/admin/community, /admin/community/add, /admin/community/update/:id
Facilities & Doctors/admin/faskes, /admin/faskes/add, /admin/faskes/edit/:place_id, /admin/faskes/add-doctor, /admin/faskes/edit-doctor/:id
Admin users/admin/adminlist, /admin/adminlist/add, /admin/adminlist/edit/:username
Users/admin/userlist, /admin/users/:id/edit (roles, caregiver links)
Categories/admin/category (CRUD)
Emergency numbers/admin/emergency-number (per-province)
Remote config/admin/remote-config (per-province home layout)
Caregiver–patient/admin/caregiver-patient (pairing management)

Overview dashboard

/admin/overview (AdminOverview.js) — aggregate statistics pulled from GET /api/admins/overview: user/admin totals, per-province distribution, monthly user growth, top activities, forum & reminder category counts, and recent activity. A date-range filter (start/end) scopes every query. The page also exports reports (GET /api/admins/export/:report?format=) — users, admins, activity-logs, domicile as CSV / PDF / XLSX.

Emergency numbers (per-province)

/admin/emergency-number (AdminProvince.js) — admin CRUD for per-province emergency phone numbers (POST/PUT/DELETE /api/emergency). The public home page calls GET /api/emergency/nearby?lat=&lng= with the user's GPS, reverse-geocodes to a province, and dials that province's number; it falls back to tel:112 when there is no match. Admins must re-enter the numbers here after the migration — old static emergency handling was replaced by this table.

Remote config (per-province home layout)

/admin/remote-config (AdminRemoteConfig.js) — lets an admin control the order and visibility of home-page sections per province. Each province gets a full sections: [{id, enabled, order}] config (replaced wholesale on save via PUT /api/province-config/:province). The special province "default" controls the logged-out home page.

Province resolution on the home page, in priority order:

  1. GPS — GET /api/province-config/nearby?lat=&lng= reverse-geocodes the user's location.
  2. Inputted domicile — the province the user entered at registration (fallback when GPS fails).
  3. DEFAULT_CONFIG — built-in defaults in src/utils/homeSections.js (final fallback).

The page uses @dnd-kit for drag-to-reorder, a live phone-shaped preview (HomePreview.jsx) showing header/greeting/sections/footer with all buttons disabled, and a toggle per section.

Guided tours (driver.js)

/admin/remote-config, /admin/emergency-number, /admin/faskes, /admin/faskes/add and /admin/faskes/edit/:place_id ship a driver.js guided tour (shared hook: src/hooks/useTour.js, usePageTour + HelpButton). It auto-triggers on the first visit to each page (tracked in localStorage, so it persists across sessions) and a Bantuan ("?") button in the heading repeats it on demand. Tours start only after the page's data has loaded (tours delay until the target elements exist in the DOM).

Faskes admin forms

/admin/faskes/add and /admin/faskes/edit/:place_id accept three ways to set a location: typing lat, lng manually, pasting a Google Maps link (parsed by src/utils/gmaps.js — also auto-fills the name), or clicking the Leaflet map (pin moves, coordinates fill, address reverse-geocodes via the existing debounce). On add, the backend rejects duplicates: same place_id, or an existing faskes within 100 m with a similar name.

Superadmin panel

/superadmin (superAdmin/SuperAdmin.js) — a raw SQL database browser: list tables, view data, execute arbitrary SQL, export to CSV. Login is a separate prompt()-based flow hitting /api/superadmin/login.

Powerful and dangerous

The superadmin panel executes arbitrary SQL. It is gated by a separate JWT (role: "superadmin") and shows a warning banner.

On this page