Skip to content

<goma-missions-hub>

The My Missions hub: an Active / Pending / Finished tab strip over a list of mission cards ("challenger cards"), with per-tab empty states whose illustrations are host-injectable.

Part 1 — UI only

The missions backend is not wired yet, so this widget is host-fed: you push the mission list in via the missions property (the same model as <goma-multi-banners>). A later release adds a live data source.

Tapping a card emits goma:mission-select so a sibling <goma-mission-details> can follow it — the same cooperation pattern as events-horizontal ↔ game-details.

Element tag

html
<goma-missions-hub></goma-missions-hub>

Installation

bash
pnpm add @gomagaming/missions-hub vue pinia vue-router vue-i18n @vueuse/core

Configuration

Set config for the runtime basics (all widgets share this shape):

KeyTypeDefaultDescription
localestring'en'i18n locale (en / fr / pt bundled).
themeobjectPulse theme--goma-* token overrides.
messagesobjectPer-locale i18n overrides merged over the bundled copy.

Data source

Host-fed only. Provide the mission list via the missions property (array) or the missions HTML attribute (JSON string).

Assumed Mission shape

js
{
  id: 'm1',
  platform: 'casino' | 'sports',
  title: 'Wager to win top prizes',
  imageUrl: 'https://…',                  // banner
  status: null | 'new' | 'suspended' | 'forfeit',
  statusLabel: 'New',
  totalLevels: 4,
  reward: 'Get an extra 100 spins…',      // the "Get:" line
  termsUrl: 'https://…',
  tab: 'active' | 'pending' | 'finished',
  joinState: 'active' | 'not-joined' | 'pending' | 'finished' | 'forfeited',
  cta: 'start'|'deposit'|'resume'|'view', // optional override; else derived
  currentLevel: 2, levelCount: 3, progress: 67, // in-progress badge + bar
  endsAt: 1771761283000,                  // optional ms epoch → "Ends in …"
  // finished-tab extras:
  totalWon: '50 kr bonus +100 free spins',
  levels: [{ level, state: 'completed'|'forfeited', reward, completedAt }],
}

Props / attributes

PropertyAttributeTypeDefaultDescription
missionsmissionsMission[][]The mission list.
activeTabactive-tab'active'|'pending'|'finished''active'Initial tab; updated when a pill is tapped.
emptyStateImagesempty-state-images{ active?, pending?, finished? }{}Per-tab empty-state illustration URLs.
offersUrloffers-urlstring''Optional href hint carried in the empty-state CTA event.

Events

All events are composed + bubbling (cross the Shadow DOM boundary).

EventdetailWhen
goma:mission-select{ missionId, mission }A mission card was tapped.
goma:mission-cta{ missionId, action }A card's CTA (start / deposit / resume / view) was pressed.
goma:missions-offers{ tab, offersUrl }The empty-state CTA link (e.g. "See current offers") was pressed.
ready{}Mounted and rendered.
error{ message, code }Render error caught by the boundary.

Embedding

Vanilla / CDN

html
<goma-missions-hub id="hub"></goma-missions-hub>
<script type="module">
  import '@gomagaming/missions-hub'
  const hub = document.getElementById('hub')
  hub.config = { locale: 'en' }
  hub.missions = [/* Mission[] */]
  hub.emptyStateImages = {
    active: 'https://…/goal.svg',
    pending: 'https://…/stopwatch.svg',
    finished: 'https://…/star.svg',
  }
  hub.addEventListener('goma:mission-select', (e) => console.log(e.detail.missionId))
</script>

React

jsx
import '@gomagaming/missions-hub'

<goma-missions-hub
  ref={(el) => {
    if (!el) return
    el.config = { locale: 'en' }
    el.missions = missions
  }}
  onGoma:mission-select={(e) => openDetail(e.detail.missionId)}
/>

Vue

vue
<script setup>
import '@gomagaming/missions-hub'
import { ref } from 'vue'
const missions = ref([/* Mission[] */])
</script>

<template>
  <goma-missions-hub
    :missions.prop="missions"
    @goma:mission-select="onSelect"
  />
</template>

Source layout

LayerFile
Element classpackages/missions-hub/src/MissionsHubElement.js
App wrapperpackages/missions-hub/src/MissionsHubApp.vue
Tab strippackages/missions-hub/src/components/MissionsHub/MissionsTabPills.vue
Listpackages/missions-hub/src/components/MissionsHub/MissionsList.vue
Shared cards / helperspackages/sports-domain/src/components/Missions/*, packages/sports-domain/src/composables/missions/useMissions.js
Playground manifestpackages/missions-hub/src/playground.manifest.js
Testspackages/missions-hub/tests/{MissionsHub,playground-manifest}.test.js