Globals
Instance Methods
App()
Application root: mounts the router behind the app-wide providers (tracking, tab management) and disables the context menu in production.
Router()
History-API router variant - use when the deploy path is known (basename from VITE_BASE_URL). Mirrors HashRouter.jsx: content + screensaver providers around the routes, pages guarded by the ErrorBoundary. App.jsx picks one of the two.
Router()
Hash-based router variant - works regardless of the deploy path, so it's the default (see App.jsx). Content + screensaver providers around the routes, pages guarded by the ErrorBoundary; the Screensaver and RotateOverlay overlays stay mounted as siblings so their fades work in both directions. RotateOverlay needs router context too (useLocation, useConfig via useSearchParams - see services/orientation.js).
Pages()
Route table of the exhibit: "/" is the app selection, each presentation mode has its own path (with an optional :viewId slide segment), and GeneralPageTracking reports every route change.
RadHeader(props: Object)
Page header shown on every RadEnablement slide (title/subline from content.header); the story icon on the right follows whichever story the current view belongs to.
Parameters
props(Object)props.viewId(string) — Currently shown view id.
useTracking(): Object
React hook to access tracking functions (page views, events, session reset). Must be used within a <TrackingProvider>.
Returns
Object
Other
CacheableVideo
Drop-in replacement for <video src="..."> that's cacheable by the service worker. Renders "Loading video..." until the fetch has completed.
Parameters
src(string) — URL of the video file to fetch and play.playing(boolean, optional) — When given, drives playback: true plays, false pauses and rewinds. Lets an always-mounted but hidden video (e.g. the screensaver behind opacity: 0) stop decoding while it's not visible.props(*) — Passed through to the underlying<video>element (autoPlay, loop, muted, playsInline, ...).
ComponentRenderer
Renders a single content block of a view. Looks the block's type up in the element registry (elements/registry.js) and reshapes the raw block into the component's props via the element's own adapter. Unknown types render a debug hint in dev mode and nothing in production.
Parameters
props(Object)props.block(Object) — A content block from a view'selementsarray, e.g.{ type: "headline", text: "..." }.props.selectedTargetViewId(string | null) — Currently armed target view (story-hub selection), passed through to selectWidget.props.onSelectTarget(function) — Arms/clears the target view selection.props.onNavigate(function) — Navigates to a view id (used by buttonList/buttonGrid).
RotateOverlay
Full-screen "please rotate the display" overlay. Stays mounted at all times (like Screensaver.jsx) so the opacity transition plays in both directions; visibility is toggled via CSS class rather than conditional rendering.
Shown whenever the current route/kiosk (useRequiredOrientation, services/orientation.js) expects a different orientation than the one the device is physically held in (useOrientation, hooks/orientation.jsx) - a route with no requirement (null) never shows it.
Screensaver
Full-screen overlay shown while the app is idle (see useScreensaver). Stays mounted at all times so the opacity transition plays both when fading in and when fading out; visibility is toggled via CSS class. Dismissing it needs no handler here - any interaction is already picked up by the global listeners in useIdle and flips isIdle back to false.
The video shown depends on defaultMode (config-schema.js): each presentation mode's own content file (see PRESENTATION_MODES in presentationModes.js, loaded per-route by ContentProvider) defines its own screensaver under "screensavers", keyed by that mode's key. In multi-app/ navbar mode (defaultMode "all") or for an unrecognized defaultMode value, no entry matches and no video is shown.
SlideNavigation
Fixed bottom navigation of the slide pages, with three modes:
- closed: menu button + prev/next arrows (hidden entirely while the view has no adjacency, e.g. before content has loaded)
- menu: full-width bar with Home / Screensaver / Apps / Slides / close
- slides: same bar plus the full-screen SlidesOverlay
Parameters
props(Object)props.prevViewId(string | null) — Target of the "back" arrow, disables it when null.props.nextViewId(string | null) — Target of the "next" arrow, disables it when null.props.homeViewId(string) — View the menu's Home button navigates to.props.currentViewId(string) — Currently shown view (highlighted in the slides overlay).props.onNavigate(function) — Navigates within the current app, keeping config params.
SlidePage
Shared skeleton of the slide-based presentation pages (ValueAdvisoryServices, RadEnablement): viewId routing, slide navigation, element-bucket layout and the content error/redirect states. The pages themselves only supply their constants, their CSS (via classPrefix) and an optional header.
Parameters
basePath(string) — route prefix, e.g. "/rad-enablement"startViewId(string) — view shown at the bare route, e.g. "rad-intro"storyHubViewId(string) — hub view (see getAdjacentRootViews), also the menu's Home targetclassPrefix(string) — CSS class prefix, e.g. "rad" -> "rad-page", "rad-slide-content"renderHeader(function, optional) — optional per-page header, returning a React node
SlidesOverlay
Full-screen overlay listing every slide of the loaded content file as a clickable thumbnail (from the view's optional thumbnail field, with a text placeholder as fallback), grouped by story. A toggle switch selects "All Slides" or a single story; it opens on the current view's story. Rendered by SlideNavigation in its "slides" mode.
Parameters
props(Object)props.currentViewId(string) — View to highlight and to derive the initial story tab from.props.onSelectSlide(function) — Called with the clicked slide's view id.
Avatar
Round avatar image, used for the portrait next to a Quote.
Parameters
props(Object)props.src(string) — Image URL.props.alt(string) — Alt text.
BodyText
Plain paragraph of body-sized text ("bodyText" element type) - an intro or description paragraph below a headline. Distinct from disclaimer (small, absolutely bottom-pinned legal print) and from headline (display-sized).
Parameters
props(Object)props.text(string) — Paragraph text.
ButtonGrid
Grid of logo tiles ("buttonGrid" element type), e.g. partner institutions. Like ButtonList, clicking reports the target view id to the page instead of navigating directly.
Parameters
props(Object)props.items(Array.<{content: {logo: string}, targetViewId: string}>) — One entry per tile.props.onNavigate(function) — Called with the clicked tile's target view id.
ButtonList
Vertical list of navigation buttons ("buttonList" element type). Buttons don't navigate themselves - they report the chosen view id to the page.
Parameters
props(Object)props.items(Array.<{content: {label: string}, targetViewId: string, icon: string}>) — One entry per button.props.onNavigate(function) — Called with the clicked item's target view id.
Card
Simple text card with optional headline, body and footer line. Used as the detail popup of a Circle in the CircleInfographic.
Parameters
props(Object)props.headline(string, optional) — Card headline.props.text(string, optional) — Card body text.props.underline(string, optional) — Small footer line below the body.
CardGrid
Stat tiles plus an optional highlight card ("cardGrid" element type), e.g. "20% perceived time savings" alongside a customer statement.
Parameters
props(Object)props.stats(Array.<{value: string, label: string}>) — Stat tiles (value + caption).props.highlight(Object | null) — Optional emphasized card.
ChartGrid
One or two chart/diagram images side by side, each with an optional caption above it ("chartGrid" element type). Portrait: stacks to 1 column.
Parameters
props(Object)props.items(Array.<{title: (string|null), image: string}>) — 1-2 chart entries.
CircleChain
N labeled circles overlapping in a horizontal row ("circleChain" element type), brand-gradient colored left to right.
Parameters
props(Object)props.items(Array.<{text: string}>) — Circles, left to right.
Circle
One selectable circle of the CircleInfographic. Toggles its detail Card on tap and closes on tap-outside.
Parameters
props(Object)props.text(string) — Label inside the circle.props.color("black" | "blue" | "white" | "orange") — Color/position variant class.props.card(Object) — Detail card content.props.icons(Array.<{small: string, big: string}>) — Orbiting IconBubbles definitions.props.handleCircleSelect(function) — Notifies the parent to blur the other circles.props.close(function) — Notifies the parent to lift the blur again.
CircleInfographic
Interactive four-circle service infographic ("circleInfographic" element type): tapping a circle opens its detail Card and blurs the rest. Expects exactly four entries; render order is fixed to match the layout.
Parameters
props(Object)props.circle(Array.<{text: string, icons: Array.<{small: string, big: string}>, card: {headline: (string|null), text: (string|null), underline: (string|null)}}>) — The four circle definitions.props.headline(string) — Label shown in the center of the ring.
Disclaimer
Small-print legal/disclaimer line of a slide ("disclaimer" element type).
Parameters
props(Object)props.text(string) — Disclaimer text.
Headline
Semantic heading with app-wide typography classes. Renders the content JSON's "headline" (level 2) and "subheadline" (level 3) element types, and is used directly for page headers.
Parameters
props(Object)props.text(string) — Heading text.props.level(number, optional, default: 1) — Heading level 1-6, controls both tag (h1-h6) and size class.props.color("white" | "orange", optional, default: "\"white\"") — Color variant class.
IconBubbles
Decorative pair of icon bubbles (one big, one small) orbiting a Circle in the CircleInfographic.
Parameters
props(Object)props.big(string) — Icon URL for the big bubble.props.small(string) — Icon URL for the small bubble.
IconWheel
N icon nodes with text labels evenly spaced around a decorative ring ("iconWheel" element type) - unlike CircleInfographic/SelectWidget, purely decorative and non-interactive.
Parameters
props(Object)props.items(Array.<{icon: string, label: string}>) — Ring nodes.
ImageCard
Card with an image and/or caption text. Rendered by ImageCardGrid.
Parameters
props(Object)props.image(string, optional) — Image URL.props.text(string, optional) — Caption text.
ImageCardGrid
Grid of ImageCards ("imageCardGrid" element type), e.g. product screenshots with captions.
Parameters
props(Object)props.items(Array.<{image: (string|null), text: (string|null)}>) — One entry per card.
InstitutionBadge
Country flag + institution logo pair ("institutionBadge" element type), shown on the "Discover real-world impact" slides.
Parameters
props(Object)props.flag(string) — Flag image URL.props.logo(string) — Institution logo URL.
ProcessFlow
N flat step images (photo/mockup with title+bullets already baked in) connected by arrows ("processFlow" element type).
Parameters
props(Object)props.items(Array.<{image: string}>) — Steps, left to right.
Quote
Single quote row: avatar plus headline and quote text. Rendered by QuoteList.
Parameters
props(Object)props.item(Object) — Quote content.
QuoteList
Stack of customer quotes ("quoteList" element type).
Parameters
props(Object)props.items(Array.<{content: {headline: string, icon: string, text: string}}>) — One entry per quote.
SelectWidget
Circular story picker ("selectWidget" element type): options are spread evenly around a ring; selecting one shows its title in the center and arms the page's "next" navigation (it does not navigate by itself).
Parameters
props(Object)props.options(Array.<{id: string, text: string, icon: string}>, optional) — Selectable options;idis a view id.props.orientation("portrait" | "landscape", optional, default: "\"portrait\"") — Ring/item sizing preset (from the content JSON).props.selectedId(string | null) — Currently selected option id.props.onSelect(function) — Called with the tapped option's id.
StepTracker
Horizontal dot progress indicator ("stepTracker" element type): one circle per step, connected by a line, the current step filled solid.
Parameters
props(Object)props.total(number) — Total number of steps.props.current(number) — Current step, 1-based.
StoryTitle
Full-bleed story opener ("storyTitle" element type): big title over an optional background artwork.
Parameters
props(Object)props.title(string) — Story title text.props.background(string, optional) — Background image URL.
TextMediaWidget
Media block with an accompanying text box ("textMediaWidget" element type). Shows an image or a (service-worker-cacheable) video, plus optional text.
Parameters
props(Object)props.image(string | null) — Image URL; mutually exclusive with video in practice.props.video(string | null) — Video URL, played via CacheableVideo.props.text(string | null) — Text shown below the media.
useIdle
Parameters
idleTime(number) — Time in ms of inactivity after whichisIdlebecomes true.
Returns
Object—triggeris the event type that ended the last idle period ("init" on first mount), and is reset to null once idle again - useful for debugging what woke the app up.forceIdleshows the idle state immediately, without waiting for the timeout.
useOrientation
Returns
"landscape" | "portrait"— The current viewport orientation, kept in sync live as the device is rotated/resized.
AppSelectionPage
Landing screen at "/": one tile per presentation mode (see PRESENTATION_MODES). Also the target of the idle session reset and of the menu's "Apps" button.
RadEnablementPage
"RadEnablement Services" presentation app - the shared SlidePage plus a persistent RadHeader (content: public/data/rad-content.json).
ValueAdvisoryServicesPage
"Value Advisory Services" presentation app - the shared SlidePage plus a persistent per-story icon badge (content: public/data/vas-content.json).
VasHeader
Persistent per-story icon badge shown top-right on every VAS slide of a story except its own storyTitle cover (which already fills the screen). Unlike RAD, VAS views author their own headline text per view (there is no app/story-wide title to repeat) - only the story icon is a constant, from stories..header.icon in vas-content.json.
Parameters
props(Object)props.viewId(string) — Currently shown view id.
ValuePartnershipPage
"Value Partnership" presentation app - placeholder page until its content exists. Only functional element is the fixed "Apps" button back to "/".
CONFIG_SCHEMA: Array.<{key: string, source: string, name: string, type: string, default: *, min: number, description: string}>
Declares every kiosk/device config value the app understands. Values come from URL params (source "param", read live by useConfig in config.jsx and kept alive across navigation), each with type, default and a German description shown in admin/debug contexts.
useConfig
React hook that resolves every entry in CONFIG_SCHEMA (config-schema.js) against the current URL search params / import.meta.env and returns them as a flat, typed { key: value } object.
Returns
Object— Config values keyed by their CONFIG_SCHEMAkey.
ContentContext
Context carrying { content, views, stories, error, getView, getAdjacentRootViews } - consume via useContent.
useContent
React hook to access the loaded content object. Returns {} until the content.json fetch in ContentProvider has resolved.
RETRY_DELAY_MS
Resolves the content file for the current route, fetches it (once per file - already-fetched files are served from an in-memory cache so switching between apps doesn't refetch) and makes it available to all descendants via ContentContext. On fetch failure, content stays {}, the failure is exposed as error (pages show a visible message instead of a blank screen) and the fetch is retried until it succeeds.
useRequiredOrientation
Returns
"landscape" | "portrait" | null— The orientation the current route (optionally overridden bydeviceType) expects, ornullif the route has no orientation requirement.
PRESENTATION_MODES: Array.<{key: string, label: string, path: string, contentFile: (string|null), orientation: ('landscape'|'portrait')}>
Single source of truth for the 3 presentation modes/sales apps. key doubles as the valid defaultMode config value (config-schema.js) and as the route path segment (see Routes.jsx, AppSelection.jsx). contentFile is the JSON this mode's route loads via ContentProvider (services/content.jsx); null means the page doesn't fetch any content (yet). orientation is the physical device orientation this app's kiosk layout is built for - read by useRequiredOrientation (services/orientation.js) to decide when to show the RotateOverlay; the deviceType config value (config-schema.js) can override it per kiosk.
ScreensaverProvider
Tracks idle state and exposes it via ScreensaverContext.
useScreensaver
React hook to access { isIdle, trigger, screensaverFadeDuration, showNow }. Must be used within a <ScreensaverProvider>.
TabProvider
Provides openTab/closeTab (see useTabs) to the component tree, tracking open external tabs/windows per URL.
useTabs
React hook to access openTab/closeTab. Must be used within a <TabProvider>.
GeneralPageTracking
Invisible helper mounted next to the routes (see Routes.jsx): keeps document.title in sync with the current route and, when VITE_MATOMO_ENABLE_ROUTER_PAGE_TRACKING is "true", reports every route change as a Matomo pageview.
parseConfigValue
Parses and validates a single raw config value against its schema definition.
Parameters
rawValue(string | null | undefined) — The raw value as read fromsearchParams.get(...)orimport.meta.env[...]. Always a string when set.definition(Object) — The matching entry from CONFIG_SCHEMA.definition.type("boolean" | "number" | "string") — How to interpret rawValue.definition.default(*) — Value to use when rawValue is missing/invalid.definition.min(number, optional) — Only for type "number": reject values below this.definition.max(number, optional) — Only for type "number": reject values above this.definition.key(string) — Config key name, used only for warning messages.
Returns
*— The parsed value, ordefinition.defaultif rawValue was empty or failed validation.
navigateWithTransition
Navigates with a native View Transition cross-fade. react-router's own viewTransition navigate option only works with the data router (createHashRouter/RouterProvider) - this app uses the plain declarative /, so the native API is driven manually. flushSync forces the DOM update to happen synchronously inside the callback, which the API requires.
Callers are responsible for keeping the current query string alive (kiosk/device config, see config-schema.js) by including it in path.