135 lines
5.4 KiB
React
135 lines
5.4 KiB
React
|
|
import React from 'react'
|
|||
|
|
import SkillTreeSelect from '../SkillTreeSelect'
|
|||
|
|
import { skillCatalogPathLabel } from '../../utils/skillCatalogTree'
|
|||
|
|
import { SKILL_LEVEL_OPTIONS } from '../../constants/skillLevels'
|
|||
|
|
import {
|
|||
|
|
EXERCISE_SKILL_INTENSITY_DEFAULT,
|
|||
|
|
EXERCISE_SKILL_INTENSITY_OPTIONS,
|
|||
|
|
normalizeExerciseSkillIntensity,
|
|||
|
|
} from '../../constants/exerciseSkillIntensity'
|
|||
|
|
|
|||
|
|
export default function ExerciseSkillsEditor({
|
|||
|
|
rows,
|
|||
|
|
skillsCatalog,
|
|||
|
|
skillPick,
|
|||
|
|
onSkillPickChange,
|
|||
|
|
onAdd,
|
|||
|
|
onRemove,
|
|||
|
|
onUpdateField,
|
|||
|
|
}) {
|
|||
|
|
return (
|
|||
|
|
<div className="exercise-meta-block exercise-meta-block--skills">
|
|||
|
|
<div className="exercise-meta-block__head">
|
|||
|
|
<h4 className="exercise-meta-block__title">Fähigkeiten</h4>
|
|||
|
|
</div>
|
|||
|
|
<p className="exercise-meta-block__hint">Je Übung mehrere Fähigkeiten mit Intensität und Niveau (von–bis).</p>
|
|||
|
|
|
|||
|
|
<div className="exercise-skills-add">
|
|||
|
|
<SkillTreeSelect
|
|||
|
|
value={skillPick}
|
|||
|
|
onChange={onSkillPickChange}
|
|||
|
|
skills={skillsCatalog}
|
|||
|
|
excludeIds={rows.map((s) => s.skill_id)}
|
|||
|
|
placeholder="Fähigkeit wählen…"
|
|||
|
|
/>
|
|||
|
|
<button type="button" className="btn btn-secondary" onClick={onAdd}>
|
|||
|
|
Hinzufügen
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{rows.length === 0 ? (
|
|||
|
|
<p className="exercise-meta-block__empty">Noch keine Fähigkeit zugeordnet.</p>
|
|||
|
|
) : (
|
|||
|
|
<ul className="exercise-skills-list">
|
|||
|
|
{rows.map((row, idx) => {
|
|||
|
|
const sk = skillsCatalog.find((s) => s.id === row.skill_id)
|
|||
|
|
const intensity = normalizeExerciseSkillIntensity(row.intensity)
|
|||
|
|
return (
|
|||
|
|
<li key={`${row.skill_id}-${idx}`} className="exercise-skill-chip">
|
|||
|
|
<div className="exercise-skill-chip__identity">
|
|||
|
|
<span className="exercise-skill-chip__name">{sk?.name || `Skill #${row.skill_id}`}</span>
|
|||
|
|
{sk ? (
|
|||
|
|
<span className="exercise-skill-chip__path" title={skillCatalogPathLabel(sk)}>
|
|||
|
|
{skillCatalogPathLabel(sk)}
|
|||
|
|
</span>
|
|||
|
|
) : null}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="exercise-skill-chip__controls">
|
|||
|
|
<div className="exercise-skill-chip__field">
|
|||
|
|
<span className="exercise-skill-chip__caption">Intensität</span>
|
|||
|
|
<div className="exercise-intensity-segment" role="radiogroup" aria-label="Intensität">
|
|||
|
|
{EXERCISE_SKILL_INTENSITY_OPTIONS.map((o) => (
|
|||
|
|
<button
|
|||
|
|
key={o.value}
|
|||
|
|
type="button"
|
|||
|
|
role="radio"
|
|||
|
|
aria-checked={intensity === o.value}
|
|||
|
|
className={`exercise-intensity-segment__btn${
|
|||
|
|
intensity === o.value ? ' exercise-intensity-segment__btn--active' : ''
|
|||
|
|
}`}
|
|||
|
|
onClick={() => onUpdateField(idx, 'intensity', o.value)}
|
|||
|
|
>
|
|||
|
|
{o.label}
|
|||
|
|
</button>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="exercise-skill-chip__levels">
|
|||
|
|
<label className="exercise-skill-chip__field">
|
|||
|
|
<span className="exercise-skill-chip__caption">von</span>
|
|||
|
|
<select
|
|||
|
|
className="form-input exercise-skill-level-select"
|
|||
|
|
value={row.required_level || ''}
|
|||
|
|
title="Mindest-Niveau"
|
|||
|
|
onChange={(e) => onUpdateField(idx, 'required_level', e.target.value)}
|
|||
|
|
>
|
|||
|
|
{SKILL_LEVEL_OPTIONS.map((o) => (
|
|||
|
|
<option key={`r-${o.value}`} value={o.value} title={o.label}>
|
|||
|
|
{o.level != null ? o.level : '–'}
|
|||
|
|
</option>
|
|||
|
|
))}
|
|||
|
|
</select>
|
|||
|
|
</label>
|
|||
|
|
<span className="exercise-skill-chip__dash" aria-hidden>
|
|||
|
|
→
|
|||
|
|
</span>
|
|||
|
|
<label className="exercise-skill-chip__field">
|
|||
|
|
<span className="exercise-skill-chip__caption">bis</span>
|
|||
|
|
<select
|
|||
|
|
className="form-input exercise-skill-level-select"
|
|||
|
|
value={row.target_level || ''}
|
|||
|
|
title="Ziel-Niveau"
|
|||
|
|
onChange={(e) => onUpdateField(idx, 'target_level', e.target.value)}
|
|||
|
|
>
|
|||
|
|
{SKILL_LEVEL_OPTIONS.map((o) => (
|
|||
|
|
<option key={`t-${o.value}`} value={o.value} title={o.label}>
|
|||
|
|
{o.level != null ? o.level : '–'}
|
|||
|
|
</option>
|
|||
|
|
))}
|
|||
|
|
</select>
|
|||
|
|
</label>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
className="exercise-skill-chip__remove"
|
|||
|
|
aria-label="Fähigkeit entfernen"
|
|||
|
|
title="Entfernen"
|
|||
|
|
onClick={() => onRemove(idx)}
|
|||
|
|
>
|
|||
|
|
✕
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</li>
|
|||
|
|
)
|
|||
|
|
})}
|
|||
|
|
</ul>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export { EXERCISE_SKILL_INTENSITY_DEFAULT }
|