UX. refactor: simplify AdminPageNav component by removing unused hooks and improving styling
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 6s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 28s
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 6s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 28s
- Removed the useLocation hook as it was unnecessary for the component's functionality. - Updated the navigation styling to use CSS classes instead of inline styles, enhancing maintainability and readability. - Improved accessibility by adding aria-labels to navigation elements.
This commit is contained in:
parent
2007f3f659
commit
14884e6e55
|
|
@ -1,7 +1,7 @@
|
|||
:root {
|
||||
--bg: #f4f3ef;
|
||||
--bg: #f6f5f0;
|
||||
--surface: #ffffff;
|
||||
--surface2: #f9f8f5;
|
||||
--surface2: #fafaf6;
|
||||
--border: rgba(0,0,0,0.09);
|
||||
--border2: rgba(0,0,0,0.16);
|
||||
--text1: #1c1b18;
|
||||
|
|
@ -1075,6 +1075,15 @@ a.analysis-split__nav-item {
|
|||
}
|
||||
}
|
||||
|
||||
button.capture-shell__nav-item {
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.capture-shell__nav-item svg.capture-shell__nav-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Einstellungen: gleiche Split-Struktur wie Analyse/Admin */
|
||||
.settings-shell {
|
||||
width: 100%;
|
||||
|
|
@ -1135,6 +1144,108 @@ a.analysis-split__nav-item {
|
|||
background: var(--surface2);
|
||||
}
|
||||
|
||||
/* Admin: horizontale Seiten-Weiche (Hierarchie · Nutzer · …) */
|
||||
.admin-top-nav {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-bottom: 2px solid var(--border);
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.admin-top-nav__link {
|
||||
padding: 12px 18px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
margin-bottom: -2px;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--text2);
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: color 0.15s, background 0.15s, border-color 0.15s;
|
||||
font-family: inherit;
|
||||
border-radius: 8px 8px 0 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.admin-top-nav__link:hover {
|
||||
color: var(--text1);
|
||||
background: var(--surface2);
|
||||
}
|
||||
.admin-top-nav__link--active {
|
||||
color: var(--accent);
|
||||
border-bottom-color: var(--accent);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Trainingsplanung: kompakte Segmente (Gruppe / Verein) */
|
||||
.planning-segment-group {
|
||||
display: inline-flex;
|
||||
border-radius: 10px;
|
||||
border: 1.5px solid var(--border2);
|
||||
overflow: hidden;
|
||||
background: var(--surface2);
|
||||
}
|
||||
.planning-segment-group__btn {
|
||||
border: none;
|
||||
padding: 8px 14px;
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
color: var(--text1);
|
||||
white-space: nowrap;
|
||||
transition: background 0.12s, color 0.12s;
|
||||
}
|
||||
.planning-segment-group__btn:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
.planning-segment-group__btn--active {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
.planning-segment-group__btn:not(:first-child) {
|
||||
border-left: 1.5px solid var(--border2);
|
||||
}
|
||||
|
||||
/* Ausklappbare Kontext-Hilfe (Filterzeile Planung) */
|
||||
.planning-filter-help {
|
||||
flex: 1 1 100%;
|
||||
margin-top: 4px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.planning-filter-help__summary {
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent-dark);
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
}
|
||||
.planning-filter-help__summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.planning-filter-help__body {
|
||||
margin-top: 10px;
|
||||
padding: 12px 14px;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.5;
|
||||
color: var(--text2);
|
||||
background: var(--surface2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.planning-filter-help__summary {
|
||||
color: var(--accent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Admin: Split-Layout wie .analysis-split (nur Gruppen in der Nav) */
|
||||
.admin-shell {
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { NavLink, useLocation } from 'react-router-dom'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { TreePine, FolderTree, Download, Grid3x3, Users } from 'lucide-react'
|
||||
|
||||
/**
|
||||
|
|
@ -6,8 +6,6 @@ import { TreePine, FolderTree, Download, Grid3x3, Users } from 'lucide-react'
|
|||
* Wechselt zwischen verschiedenen Admin-Seiten
|
||||
*/
|
||||
export default function AdminPageNav() {
|
||||
const location = useLocation()
|
||||
|
||||
const pages = [
|
||||
{ to: '/admin/hierarchy', label: 'Hierarchie', icon: TreePine },
|
||||
{ to: '/admin/users', label: 'Nutzer', icon: Users },
|
||||
|
|
@ -17,51 +15,18 @@ export default function AdminPageNav() {
|
|||
]
|
||||
|
||||
return (
|
||||
<nav style={{
|
||||
display: 'flex',
|
||||
gap: '8px',
|
||||
borderBottom: '2px solid var(--border)',
|
||||
marginBottom: '24px',
|
||||
flexWrap: 'wrap'
|
||||
}}>
|
||||
{pages.map(page => {
|
||||
<nav className="admin-top-nav" aria-label="Administration">
|
||||
{pages.map((page) => {
|
||||
const Icon = page.icon
|
||||
const isActive = location.pathname === page.to
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
key={page.to}
|
||||
to={page.to}
|
||||
style={{
|
||||
padding: '12px 20px',
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: '3px solid transparent',
|
||||
cursor: 'pointer',
|
||||
fontSize: '16px',
|
||||
fontWeight: 500,
|
||||
color: isActive ? 'var(--accent)' : 'var(--text2)',
|
||||
borderBottomColor: isActive ? 'var(--accent)' : 'transparent',
|
||||
textDecoration: 'none',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
transition: 'all 0.2s'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!isActive) {
|
||||
e.currentTarget.style.color = 'var(--text1)'
|
||||
e.currentTarget.style.background = 'var(--surface2)'
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (!isActive) {
|
||||
e.currentTarget.style.color = 'var(--text2)'
|
||||
e.currentTarget.style.background = 'transparent'
|
||||
}
|
||||
}}
|
||||
className={({ isActive }) =>
|
||||
'admin-top-nav__link' + (isActive ? ' admin-top-nav__link--active' : '')
|
||||
}
|
||||
>
|
||||
<Icon size={18} />
|
||||
<Icon size={18} strokeWidth={2} aria-hidden />
|
||||
<span>{page.label}</span>
|
||||
</NavLink>
|
||||
)
|
||||
|
|
|
|||
50
frontend/src/components/AppSubnavShell.jsx
Normal file
50
frontend/src/components/AppSubnavShell.jsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Einheitliche Sub-Navigation (Jinkendo-Muster):
|
||||
* Mobil = horizontale Chips, Desktop ≥1024px = linke Spalte (sticky).
|
||||
* Nutzt .capture-shell* aus app.css.
|
||||
*/
|
||||
export default function AppSubnavShell({
|
||||
ariaLabel,
|
||||
items,
|
||||
value,
|
||||
onChange,
|
||||
children,
|
||||
iconSize = 18,
|
||||
}) {
|
||||
return (
|
||||
<div className="capture-shell app-subnav-shell">
|
||||
<div className="capture-shell__layout">
|
||||
<div className="capture-shell__nav-wrap">
|
||||
<nav className="capture-shell__nav" aria-label={ariaLabel}>
|
||||
{items.map((item) => {
|
||||
const Icon = item.icon
|
||||
const active = value === item.id
|
||||
return (
|
||||
<button
|
||||
key={item.id}
|
||||
type="button"
|
||||
className={
|
||||
'capture-shell__nav-item' +
|
||||
(active ? ' capture-shell__nav-item--active' : '')
|
||||
}
|
||||
onClick={() => onChange(item.id)}
|
||||
>
|
||||
{Icon ? (
|
||||
<Icon
|
||||
className="capture-shell__nav-icon"
|
||||
size={iconSize}
|
||||
strokeWidth={2}
|
||||
aria-hidden
|
||||
/>
|
||||
) : null}
|
||||
<span className="capture-shell__nav-label">{item.label}</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
<div className="capture-shell__main">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { TreePine, FolderTree, Link2 } from 'lucide-react'
|
||||
import { api } from '../utils/api'
|
||||
import AdminPageNav from '../components/AdminPageNav'
|
||||
import AppSubnavShell from '../components/AppSubnavShell'
|
||||
import HierarchyTab from '../components/admin/HierarchyTab'
|
||||
import CatalogsTab from '../components/admin/CatalogsTab'
|
||||
import AssignmentsTab from '../components/admin/AssignmentsTab'
|
||||
|
|
@ -10,17 +12,14 @@ function AdminHierarchyPage() {
|
|||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState('')
|
||||
|
||||
// Hierarchy Tab State
|
||||
const [hierarchy, setHierarchy] = useState([])
|
||||
const [expandedNodes, setExpandedNodes] = useState(new Set())
|
||||
const [selectedItem, setSelectedItem] = useState(null)
|
||||
|
||||
// Catalogs Tab State
|
||||
const [targetGroups, setTargetGroups] = useState([])
|
||||
const [skillCategories, setSkillCategories] = useState([])
|
||||
const [trainingCharacters, setTrainingCharacters] = useState([])
|
||||
|
||||
// Assignments Tab State
|
||||
const [styleDirections, setStyleDirections] = useState([])
|
||||
const [assignments, setAssignments] = useState([])
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ function AdminHierarchyPage() {
|
|||
}
|
||||
|
||||
function handleToggleNode(nodeId) {
|
||||
setExpandedNodes(prev => {
|
||||
setExpandedNodes((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
if (newSet.has(nodeId)) {
|
||||
newSet.delete(nodeId)
|
||||
|
|
@ -86,33 +85,26 @@ function AdminHierarchyPage() {
|
|||
loadData()
|
||||
}
|
||||
|
||||
const tabs = [
|
||||
{ id: 'hierarchy', label: '🌳 Hierarchie', icon: '🌳' },
|
||||
{ id: 'catalogs', label: '📋 Kataloge', icon: '📋' },
|
||||
{ id: 'assignments', label: '🔗 Zuordnungen', icon: '🔗' }
|
||||
const subnavItems = [
|
||||
{ id: 'hierarchy', label: 'Hierarchie', icon: TreePine },
|
||||
{ id: 'catalogs', label: 'Kataloge', icon: FolderTree },
|
||||
{ id: 'assignments', label: 'Zuordnungen', icon: Link2 }
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="app-page">
|
||||
<div className="app-page admin-hierarchy-page">
|
||||
<AdminPageNav />
|
||||
|
||||
<h1 style={{ marginTop: 0 }}>Admin: Katalog-Hierarchie</h1>
|
||||
<h1 className="page-title" style={{ marginBottom: '12px' }}>
|
||||
Katalog & Hierarchie
|
||||
</h1>
|
||||
|
||||
{/* Tab Navigation */}
|
||||
<div className="tab-navigation">
|
||||
{tabs.map(tab => (
|
||||
<button
|
||||
key={tab.id}
|
||||
className={activeTab === tab.id ? 'tab-button active' : 'tab-button'}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
>
|
||||
{tab.icon} {tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Tab Content */}
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<AppSubnavShell
|
||||
ariaLabel="Bereich Katalogadministration"
|
||||
items={subnavItems}
|
||||
value={activeTab}
|
||||
onChange={setActiveTab}
|
||||
>
|
||||
{activeTab === 'hierarchy' && (
|
||||
<HierarchyTab
|
||||
hierarchy={hierarchy}
|
||||
|
|
@ -147,48 +139,7 @@ function AdminHierarchyPage() {
|
|||
onUpdate={handleUpdate}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
.tab-navigation {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
border-bottom: 2px solid var(--border);
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
padding: 12px 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--text2);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab-button:hover {
|
||||
color: var(--text1);
|
||||
background: var(--surface2);
|
||||
}
|
||||
|
||||
.tab-button.active {
|
||||
color: var(--accent);
|
||||
border-bottom-color: var(--accent);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.tab-button {
|
||||
flex: 1 1 auto;
|
||||
min-width: 120px;
|
||||
font-size: 14px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</AppSubnavShell>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,31 +106,32 @@ function Dashboard() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="app-page">
|
||||
<h1>Dashboard</h1>
|
||||
<p style={{ color: 'var(--text2)', marginTop: '0.5rem' }}>
|
||||
Willkommen, {user?.name || user?.email}!
|
||||
</p>
|
||||
{profile && <EmailVerificationBanner profile={profile} />}
|
||||
{/* Welcome Card */}
|
||||
<div className="card" style={{ marginTop: '1.5rem', marginBottom: '1.5rem' }}>
|
||||
<h2>Willkommen bei Shinkan Jinkendo</h2>
|
||||
<p style={{ color: 'var(--text2)' }}>
|
||||
Trainer- und Vereinsplattform für Kampfsport-Trainingsplanung
|
||||
<div className="app-page dashboard-page">
|
||||
<div className="dashboard-greeting">
|
||||
<div>
|
||||
<h1 className="page-title" style={{ marginBottom: '6px' }}>
|
||||
Dashboard
|
||||
</h1>
|
||||
<p className="muted" style={{ marginTop: 0 }}>
|
||||
Willkommen, {user?.name || user?.email}! Shinkan unterstützt dich bei Übungen, Planung und Vereinsstruktur.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{profile && <EmailVerificationBanner profile={profile} />}
|
||||
|
||||
{user?.id && (
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 280px), 1fr))',
|
||||
gap: '1rem',
|
||||
marginBottom: '1.5rem'
|
||||
}}
|
||||
>
|
||||
<div className="card">
|
||||
<h3 style={{ fontSize: '1.05rem', marginBottom: '0.65rem' }}>Deine nächsten Trainings</h3>
|
||||
{user?.id && (
|
||||
<div
|
||||
className="dashboard-training-grid"
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 280px), 1fr))',
|
||||
gap: '1rem',
|
||||
alignItems: 'stretch',
|
||||
marginBottom: '1.5rem',
|
||||
}}
|
||||
>
|
||||
<div className="card">
|
||||
<h3 style={{ fontSize: '1.05rem', marginBottom: '0.65rem' }}>Deine nächsten Trainings</h3>
|
||||
{trainingHomeErr ? (
|
||||
<p style={{ color: 'var(--danger)', fontSize: '0.9rem' }}>{trainingHomeErr}</p>
|
||||
) : trainingHome?.upcoming?.length ? (
|
||||
|
|
@ -216,43 +217,6 @@ function Dashboard() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Status Grid */}
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))',
|
||||
gap: '1rem',
|
||||
marginBottom: '1.5rem'
|
||||
}}>
|
||||
<div className="card">
|
||||
<h3>✅ Fertig</h3>
|
||||
<ul style={{ marginTop: '1rem', paddingLeft: '1.5rem' }}>
|
||||
<li>Backend-Basis</li>
|
||||
<li>Datenbank-Schema</li>
|
||||
<li>Auth-System</li>
|
||||
<li>Login & Registrierung</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="card">
|
||||
<h3>🚧 In Arbeit</h3>
|
||||
<ul style={{ marginTop: '1rem', paddingLeft: '1.5rem' }}>
|
||||
<li>Übungsverwaltung</li>
|
||||
<li>Trainingsplanung</li>
|
||||
<li>Kataloge (Skills, Methods)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="card">
|
||||
<h3>📋 Geplant</h3>
|
||||
<ul style={{ marginTop: '1rem', paddingLeft: '1.5rem' }}>
|
||||
<li>MediaWiki-Import</li>
|
||||
<li>Trainingsprogramme</li>
|
||||
<li>Admin-Panel</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* System Info */}
|
||||
{version && (
|
||||
<div className="card">
|
||||
<h3>System-Information</h3>
|
||||
|
|
|
|||
|
|
@ -1067,53 +1067,28 @@ function TrainingPlanningPage() {
|
|||
<span className="form-label" style={{ marginBottom: 0, alignSelf: 'center' }}>
|
||||
Einblenden
|
||||
</span>
|
||||
<div
|
||||
role="group"
|
||||
aria-label="Gruppe oder ganzer Verein"
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
borderRadius: '10px',
|
||||
border: '1.5px solid var(--border2)',
|
||||
overflow: 'hidden',
|
||||
background: 'var(--surface2)',
|
||||
}}
|
||||
>
|
||||
<div className="planning-segment-group" role="group" aria-label="Gruppe oder ganzer Verein">
|
||||
<button
|
||||
type="button"
|
||||
className={
|
||||
'planning-segment-group__btn' +
|
||||
(planScope === 'group' ? ' planning-segment-group__btn--active' : '')
|
||||
}
|
||||
aria-pressed={planScope === 'group'}
|
||||
disabled={!selectedGroupId}
|
||||
onClick={() => setPlanScope('group')}
|
||||
style={{
|
||||
border: 'none',
|
||||
padding: '8px 14px',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.85rem',
|
||||
cursor: selectedGroupId ? 'pointer' : 'not-allowed',
|
||||
opacity: selectedGroupId ? 1 : 0.55,
|
||||
background: planScope === 'group' ? 'var(--accent-dark)' : 'transparent',
|
||||
color: planScope === 'group' ? '#fff' : 'var(--text1)',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
Nur diese Gruppe
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={
|
||||
'planning-segment-group__btn' +
|
||||
(planScope === 'club' ? ' planning-segment-group__btn--active' : '')
|
||||
}
|
||||
aria-pressed={planScope === 'club'}
|
||||
disabled={!selectedGroupId}
|
||||
onClick={() => setPlanScope('club')}
|
||||
style={{
|
||||
border: 'none',
|
||||
borderLeft: '1.5px solid var(--border2)',
|
||||
padding: '8px 14px',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.85rem',
|
||||
cursor: selectedGroupId ? 'pointer' : 'not-allowed',
|
||||
opacity: selectedGroupId ? 1 : 0.55,
|
||||
background: planScope === 'club' ? 'var(--accent-dark)' : 'transparent',
|
||||
color: planScope === 'club' ? '#fff' : 'var(--text1)',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
Ganzer Verein
|
||||
</button>
|
||||
|
|
@ -1137,16 +1112,39 @@ function TrainingPlanningPage() {
|
|||
/>
|
||||
Nur meine Zuordnung (Leitung / Co)
|
||||
</label>
|
||||
<span style={{ fontSize: '0.78rem', color: 'var(--text3)', lineHeight: 1.4, flex: '1 1 240px' }}>
|
||||
„Ganzer Verein“ bezieht sich auf denselben Verein wie die gewählte Gruppe: Dort siehst du Termine mehrerer Gruppen; neu angelegte Termine gelten weiter für die gesondert gewählte Gruppe.
|
||||
{selectedGroupId ? (
|
||||
<span style={{ display: 'block', marginTop: '6px', color: 'var(--text2)' }}>
|
||||
Über <strong>Trainer</strong> oder <strong>Trainer zuweisen</strong>: Leitung und Co je Einheit bearbeitbar (berechtigt: Vereinsorganisation, Haupt-/Co‑Trainer der Gruppe sowie Erstellung der Einheit).
|
||||
Das Mitgliederverzeichnis listet nur <strong>eigene Vereinsmitglieder</strong>; die Leitung erscheint nicht unter Co‑Trainer.
|
||||
Gasttrainer aus anderen Vereinen (Zugriff nur auf eine Session, nicht auf den Verein insgesamt) sind für später vorgesehen.
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
<p
|
||||
style={{
|
||||
fontSize: '0.78rem',
|
||||
color: 'var(--text3)',
|
||||
lineHeight: 1.45,
|
||||
flex: '1 1 220px',
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
Neue Termine gelten immer für die gewählte Gruppe. „Ganzer Verein“ zeigt zusätzlich Termine
|
||||
anderer Gruppen desselben Vereins.
|
||||
</p>
|
||||
<details className="planning-filter-help">
|
||||
<summary className="planning-filter-help__summary">Mehr zu Ansicht & Trainerzuordnung</summary>
|
||||
<div className="planning-filter-help__body">
|
||||
<p style={{ margin: '0 0 0.65rem' }}>
|
||||
„Ganzer Verein“ bezieht sich auf denselben Verein wie die gewählte Gruppe. Neu angelegte Termine
|
||||
beziehen sich weiterhin auf die Gruppe, die du oben gewählt hast.
|
||||
</p>
|
||||
{selectedGroupId ? (
|
||||
<p style={{ margin: 0 }}>
|
||||
Über <strong>Trainer</strong> oder <strong>Trainer zuweisen</strong> bearbeitest du Leitung und
|
||||
Co je Einheit (berechtigt: Vereinsorganisation, Haupt-/Co‑Trainer der Gruppe sowie Erstellung
|
||||
der Einheit). Das Mitgliederverzeichnis listet nur eigene Vereinsmitglieder; die Leitung erscheint
|
||||
nicht unter Co‑Trainer.
|
||||
</p>
|
||||
) : (
|
||||
<p style={{ margin: 0, color: 'var(--text3)' }}>
|
||||
Wähle zuerst eine Gruppe — dann erweitert sich die Hilfe zu Trainer und Berechtigungen.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -1172,9 +1170,8 @@ function TrainingPlanningPage() {
|
|||
<div className="training-planning-create__intro">
|
||||
<h3 className="training-planning-create__title">Neue Trainingseinheit</h3>
|
||||
<p className="training-planning-create__lede">
|
||||
Termin mit Datum, Zeiten und Ablauf (Abschnitte & Übungen) festlegen — optional eine{' '}
|
||||
<strong>Trainingsvorlage</strong> für die Gliederung wählen oder Inhalte aus einem{' '}
|
||||
<strong>Rahmenprogramm</strong> übernehmen.
|
||||
Datum, Zeiten und Ablauf (Abschnitte & Übungen) — optional{' '}
|
||||
<strong>Trainingsvorlage</strong> oder Inhalte aus einem <strong>Rahmenprogramm</strong> im Dialog.
|
||||
</p>
|
||||
{!selectedGroupId && (
|
||||
<p className="training-planning-create__hint training-planning-create__hint--warn">
|
||||
|
|
@ -1208,10 +1205,6 @@ function TrainingPlanningPage() {
|
|||
Aus Rahmen übernehmen…
|
||||
</button>
|
||||
</div>
|
||||
<p className="training-planning-create__hint">
|
||||
Vorlage („Ohne Vorlage“ oder gespeicherte Gliederung) stellst du im sich öffnenden Dialog ein; dort auch
|
||||
Kalenderdatum und Zeiten.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user