feat(journal): wrap Crew an diesem Reisetag card inside a collapsible accordion defaulting to collapsed
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Users } from 'lucide-react'
|
import { Users, ChevronDown, ChevronUp } from 'lucide-react'
|
||||||
import type { EntryCrewFields, PersonSnapshot } from '../types/person.js'
|
import type { EntryCrewFields, PersonSnapshot } from '../types/person.js'
|
||||||
import { loadPersonPool } from '../services/personPool.js'
|
import { loadPersonPool } from '../services/personPool.js'
|
||||||
import { loadLogbookCrewSelection } from '../services/logbookCrewSelection.js'
|
import { loadLogbookCrewSelection } from '../services/logbookCrewSelection.js'
|
||||||
@@ -24,6 +24,7 @@ export default function EntryCrewSection({
|
|||||||
preloadedPool
|
preloadedPool
|
||||||
}: EntryCrewSectionProps) {
|
}: EntryCrewSectionProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const [collapsed, setCollapsed] = useState(true)
|
||||||
const [pool, setPool] = useState<Map<string, PersonData>>(preloadedPool ?? new Map())
|
const [pool, setPool] = useState<Map<string, PersonData>>(preloadedPool ?? new Map())
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -90,54 +91,78 @@ export default function EntryCrewSection({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-card" data-tour="entry-crew">
|
<div className="form-card" data-tour="entry-crew">
|
||||||
<div className="form-header">
|
<div
|
||||||
<Users size={22} className="form-icon" />
|
className="form-header accordion-header"
|
||||||
<h3>{t('entry_crew.title')}</h3>
|
onClick={() => setCollapsed(!collapsed)}
|
||||||
</div>
|
onKeyDown={(e) => {
|
||||||
<p className="help-text mb-3">{t('entry_crew.subtitle')}</p>
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault()
|
||||||
<div className="input-group mb-3">
|
setCollapsed(!collapsed)
|
||||||
<label>{t('entry_crew.day_skipper')}</label>
|
}
|
||||||
{skippers.length === 0 ? (
|
}}
|
||||||
<p className="help-text">{t('entry_crew.no_skipper')}</p>
|
role="button"
|
||||||
|
aria-expanded={!collapsed}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<div className="accordion-header-title">
|
||||||
|
<Users size={22} className="form-icon" />
|
||||||
|
<h3>{t('entry_crew.title')}</h3>
|
||||||
|
</div>
|
||||||
|
{collapsed ? (
|
||||||
|
<ChevronDown size={20} className="accordion-chevron" />
|
||||||
) : (
|
) : (
|
||||||
<div className="crew-selection-list">
|
<ChevronUp size={20} className="accordion-chevron" />
|
||||||
{skippers.map(([id, data]) => (
|
|
||||||
<label key={id} className="crew-selection-item">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name={`entry-skipper-${logbookId}`}
|
|
||||||
checked={value.selectedSkipperId === id}
|
|
||||||
onChange={() => !readOnly && applyChange(id, value.selectedCrewIds)}
|
|
||||||
disabled={readOnly}
|
|
||||||
/>
|
|
||||||
<span>{data.name || t('logbook_crew.unnamed')}</span>
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-group">
|
{!collapsed && (
|
||||||
<label>{t('entry_crew.day_crew')}</label>
|
<>
|
||||||
{crewEntries.length === 0 ? (
|
<p className="help-text mb-3" style={{ marginTop: '16px' }}>{t('entry_crew.subtitle')}</p>
|
||||||
<p className="help-text">{t('entry_crew.no_crew')}</p>
|
|
||||||
) : (
|
<div className="input-group mb-3">
|
||||||
<div className="crew-selection-list">
|
<label>{t('entry_crew.day_skipper')}</label>
|
||||||
{crewEntries.map(([id, data]) => (
|
{skippers.length === 0 ? (
|
||||||
<label key={id} className="crew-selection-item">
|
<p className="help-text">{t('entry_crew.no_skipper')}</p>
|
||||||
<input
|
) : (
|
||||||
type="checkbox"
|
<div className="crew-selection-list">
|
||||||
checked={value.selectedCrewIds.includes(id)}
|
{skippers.map(([id, data]) => (
|
||||||
onChange={() => toggleCrew(id)}
|
<label key={id} className="crew-selection-item">
|
||||||
disabled={readOnly}
|
<input
|
||||||
/>
|
type="radio"
|
||||||
<span>{data.name || t('logbook_crew.unnamed')}</span>
|
name={`entry-skipper-${logbookId}`}
|
||||||
</label>
|
checked={value.selectedSkipperId === id}
|
||||||
))}
|
onChange={() => !readOnly && applyChange(id, value.selectedCrewIds)}
|
||||||
|
disabled={readOnly}
|
||||||
|
/>
|
||||||
|
<span>{data.name || t('logbook_crew.unnamed')}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
<div className="input-group">
|
||||||
|
<label>{t('entry_crew.day_crew')}</label>
|
||||||
|
{crewEntries.length === 0 ? (
|
||||||
|
<p className="help-text">{t('entry_crew.no_crew')}</p>
|
||||||
|
) : (
|
||||||
|
<div className="crew-selection-list">
|
||||||
|
{crewEntries.map(([id, data]) => (
|
||||||
|
<label key={id} className="crew-selection-item">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={value.selectedCrewIds.includes(id)}
|
||||||
|
onChange={() => toggleCrew(id)}
|
||||||
|
disabled={readOnly}
|
||||||
|
/>
|
||||||
|
<span>{data.name || t('logbook_crew.unnamed')}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user