shinkan-jinkendo/frontend/src/components/admin/FocusAreaNode.jsx
Lars 68923b0364
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 29s
feat: enhance UI and functionality for Skills and Exercises pages
- Added new CSS styles for Skills and Exercises pages, improving layout and responsiveness.
- Refactored components to utilize new styles, enhancing visual consistency and user experience.
- Implemented horizontal scrollable navigation for exercises and skills tabs, improving usability on smaller screens.
- Updated button styles and introduced new class names for better maintainability and accessibility.
- Enhanced loading states and empty messages for improved user feedback during data fetching.
2026-05-06 11:24:44 +02:00

154 lines
5.0 KiB
JavaScript

import React from 'react'
import { ChevronDown, ChevronRight } from 'lucide-react'
function FocusAreaNode({ focusArea, expanded, onToggle, onSelect, selectedId, selectedType }) {
const nodeId = `fa-${focusArea.id}`
const isExpanded = expanded.has(nodeId)
const isSelected = selectedType === 'focus_area' && selectedId === focusArea.id
return (
<div className="focus-tree-root">
<div className={'focus-tree-header' + (isSelected ? ' focus-tree-header--selected' : '')}>
<button
type="button"
className="focus-tree-toggle"
aria-expanded={isExpanded}
aria-label={isExpanded ? 'Bereich einklappen' : 'Bereich aufklappen'}
onClick={(e) => {
e.stopPropagation()
onToggle(nodeId)
}}
>
{isExpanded ? (
<ChevronDown size={18} strokeWidth={2} aria-hidden />
) : (
<ChevronRight size={18} strokeWidth={2} aria-hidden />
)}
</button>
<button
type="button"
className="focus-tree-header__label"
onClick={() => onSelect(focusArea, 'focus_area')}
>
{focusArea.icon ? (
<span className="focus-tree-emoji" aria-hidden>
{focusArea.icon}
</span>
) : null}
<span>{focusArea.name}</span>
</button>
</div>
{isExpanded && (
<div className="focus-tree-children">
<div className="focus-tree-group">
<div className="focus-tree-group__head">
<span>Stilrichtungen</span>
<button
type="button"
className="btn btn-secondary btn-tiny focus-tree-add-btn"
onClick={(e) => {
e.stopPropagation()
onSelect(
{ _createType: 'style_direction', focus_area_id: focusArea.id, focus_area_name: focusArea.name },
'create_style_direction'
)
}}
>
+ Neu
</button>
</div>
{focusArea.style_directions &&
focusArea.style_directions.map((sd) => (
<StyleDirectionNode
key={sd.id}
styleDirection={sd}
onSelect={onSelect}
isSelected={selectedType === 'style_direction' && selectedId === sd.id}
/>
))}
</div>
<div className="focus-tree-group">
<div className="focus-tree-group__head">
<span>Trainingstypen</span>
<button
type="button"
className="btn btn-secondary btn-tiny focus-tree-add-btn"
onClick={(e) => {
e.stopPropagation()
onSelect(
{ _createType: 'training_type', focus_area_id: focusArea.id, focus_area_name: focusArea.name },
'create_training_type'
)
}}
>
+ Neu
</button>
</div>
{focusArea.training_types &&
focusArea.training_types.map((tt) => (
<TrainingTypeNode
key={tt.id}
trainingType={tt}
onSelect={onSelect}
isSelected={selectedType === 'training_type' && selectedId === tt.id}
/>
))}
</div>
</div>
)}
</div>
)
}
function StyleDirectionNode({ styleDirection, onSelect, isSelected }) {
return (
<div
role="button"
tabIndex={0}
className={'focus-tree-item' + (isSelected ? ' focus-tree-item--selected' : '')}
onClick={() => onSelect(styleDirection, 'style_direction')}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onSelect(styleDirection, 'style_direction')
}
}}
>
{styleDirection.name}
{styleDirection.abbreviation ? (
<span className="focus-tree-item__abbr">({styleDirection.abbreviation})</span>
) : null}
{styleDirection.target_groups && styleDirection.target_groups.length > 0 ? (
<div className="focus-tree-item__meta">
Zielgruppen: {styleDirection.target_groups.map((tg) => tg.name).join(', ')}
</div>
) : null}
</div>
)
}
function TrainingTypeNode({ trainingType, onSelect, isSelected }) {
return (
<div
role="button"
tabIndex={0}
className={'focus-tree-item' + (isSelected ? ' focus-tree-item--selected' : '')}
onClick={() => onSelect(trainingType, 'training_type')}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onSelect(trainingType, 'training_type')
}
}}
>
{trainingType.name}
{trainingType.abbreviation ? (
<span className="focus-tree-item__abbr">({trainingType.abbreviation})</span>
) : null}
</div>
)
}
export default FocusAreaNode