Some checks failed
Test Suite / playwright-tests (push) Waiting to run
Deploy Development / deploy (push) Successful in 40s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 14s
Test Suite / k6 /health Baseline (push) Has been cancelled
- Updated the TrainingFrameworkProgramsListPage to utilize new CSS classes for improved layout and styling. - Removed deprecated components and functions, streamlining the codebase for better maintainability. - Introduced utility functions for splitting aggregated strings, enhancing data handling for framework program attributes. - Enhanced the user interface with loading and empty state indicators, improving overall user experience.
135 lines
5.0 KiB
JavaScript
135 lines
5.0 KiB
JavaScript
import React from 'react'
|
|
import NavStateLink from '../NavStateLink'
|
|
import {
|
|
frameworkSessionDurationLabel,
|
|
splitFrameworkCommaAgg,
|
|
splitFrameworkGoalsAgg,
|
|
frameworkProgramHasCatalogMeta,
|
|
} from '../../utils/frameworkProgramListHelpers'
|
|
|
|
function CatalogGroup({ label, items, variant }) {
|
|
if (!items.length) return null
|
|
return (
|
|
<div className={`fw-prog-card__catalog-group fw-prog-card__catalog-group--${variant}`}>
|
|
<span className="fw-prog-card__catalog-label">{label}</span>
|
|
<ul className="fw-prog-card__chip-list" aria-label={label}>
|
|
{items.map((name) => (
|
|
<li key={name} className="fw-prog-card__chip">
|
|
{name}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Einzelkarte für die Rahmenprogramm-Bibliothek.
|
|
*/
|
|
export default function FrameworkProgramListCard({ row, returnContext, onDelete }) {
|
|
const title = (row.title || '').trim() || `Rahmen #${row.id}`
|
|
const description = (row.description || '').trim()
|
|
const durationLabel = frameworkSessionDurationLabel(row)
|
|
const hasDuration = durationLabel !== 'Dauer nicht angegeben'
|
|
const goals = splitFrameworkGoalsAgg(row.goal_titles_agg)
|
|
const focusAreas = splitFrameworkCommaAgg(row.focus_area_names_agg)
|
|
const styleDirs = splitFrameworkCommaAgg(
|
|
row.style_direction_names_agg || row.style_direction_name
|
|
)
|
|
const trainingTypes = splitFrameworkCommaAgg(row.training_type_names_agg)
|
|
const targetGroups = splitFrameworkCommaAgg(row.target_group_names_agg)
|
|
const goalsCount = Number(row.goals_count)
|
|
const slotsCount = Number(row.slots_count)
|
|
const showCatalog = frameworkProgramHasCatalogMeta(row)
|
|
|
|
return (
|
|
<article className="fw-prog-card card">
|
|
<div className="fw-prog-card__accent" aria-hidden="true" />
|
|
<div className="fw-prog-card__inner">
|
|
<header className="fw-prog-card__head">
|
|
<div className="fw-prog-card__title-block">
|
|
<h2 className="fw-prog-card__title">
|
|
<NavStateLink
|
|
to={`/planning/framework-programs/${row.id}`}
|
|
returnContext={returnContext}
|
|
className="fw-prog-card__title-link"
|
|
>
|
|
{title}
|
|
</NavStateLink>
|
|
</h2>
|
|
{description ? (
|
|
<p className="fw-prog-card__desc">{description}</p>
|
|
) : null}
|
|
</div>
|
|
|
|
<ul className="fw-prog-card__stats" aria-label="Kennzahlen">
|
|
<li
|
|
className={
|
|
'fw-prog-card__stat' +
|
|
(hasDuration ? ' fw-prog-card__stat--duration' : ' fw-prog-card__stat--muted')
|
|
}
|
|
>
|
|
<span className="fw-prog-card__stat-label">Session</span>
|
|
<span className="fw-prog-card__stat-value">{durationLabel}</span>
|
|
</li>
|
|
<li className="fw-prog-card__stat">
|
|
<span className="fw-prog-card__stat-label">Ziele</span>
|
|
<span className="fw-prog-card__stat-value">
|
|
{Number.isFinite(goalsCount) ? goalsCount : '—'}
|
|
</span>
|
|
</li>
|
|
<li className="fw-prog-card__stat">
|
|
<span className="fw-prog-card__stat-label">Sessions</span>
|
|
<span className="fw-prog-card__stat-value">
|
|
{Number.isFinite(slotsCount) ? slotsCount : '—'}
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</header>
|
|
|
|
{goals.length > 0 ? (
|
|
<section className="fw-prog-card__section fw-prog-card__section--goals">
|
|
<h3 className="fw-prog-card__section-title">Entwicklungsziele</h3>
|
|
<ul className="fw-prog-card__goal-list" aria-label="Entwicklungsziele">
|
|
{goals.map((g) => (
|
|
<li key={g} className="fw-prog-card__goal">
|
|
{g}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
) : null}
|
|
|
|
{showCatalog ? (
|
|
<section className="fw-prog-card__section fw-prog-card__section--catalog">
|
|
<h3 className="fw-prog-card__section-title">Einordnung</h3>
|
|
<div className="fw-prog-card__catalog">
|
|
<CatalogGroup label="Fokus" items={focusAreas} variant="focus" />
|
|
<CatalogGroup label="Stil" items={styleDirs} variant="style" />
|
|
<CatalogGroup label="Trainingsart" items={trainingTypes} variant="type" />
|
|
<CatalogGroup label="Zielgruppe" items={targetGroups} variant="target" />
|
|
</div>
|
|
</section>
|
|
) : null}
|
|
|
|
<footer className="fw-prog-card__actions">
|
|
<NavStateLink
|
|
to={`/planning/framework-programs/${row.id}`}
|
|
returnContext={returnContext}
|
|
className="btn btn-primary fw-prog-card__btn-primary"
|
|
>
|
|
Öffnen
|
|
</NavStateLink>
|
|
<button
|
|
type="button"
|
|
className="btn btn-secondary fw-prog-card__btn-danger"
|
|
onClick={() => onDelete(row.id, row.title)}
|
|
>
|
|
Löschen
|
|
</button>
|
|
</footer>
|
|
</div>
|
|
</article>
|
|
)
|
|
}
|