Lebensphasen-Zellen oeffnen jetzt ein Popup (statt unterem Detail-Panel)
Deploy App / deploy (push) Successful in 1m5s
Deploy App / deploy (push) Successful in 1m5s
Klick auf eine Element-Zelle in einer Lebensphase oeffnet neu ein kleines Popup (PhaseCellDialog mit ElementDetail) - analog zu den Uebergangszellen. Das untere Detail-Panel dient nur noch der Phasen-Kopf-Bearbeitung. Popup ist per key stabil (kein Uebertrag des Formularzustands zwischen Elementen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+75
-45
@@ -75,7 +75,6 @@ type Column =
|
|||||||
| { kind: "transition"; fromPhase: PhaseComputed; toPhase: PhaseComputed };
|
| { kind: "transition"; fromPhase: PhaseComputed; toPhase: PhaseComputed };
|
||||||
|
|
||||||
type Selection =
|
type Selection =
|
||||||
| { type: "phaseCell"; elementId: string; phaseId: string }
|
|
||||||
| { type: "phase"; phaseId: string };
|
| { type: "phase"; phaseId: string };
|
||||||
|
|
||||||
export function PlanView({
|
export function PlanView({
|
||||||
@@ -94,6 +93,7 @@ export function PlanView({
|
|||||||
const [showSettings, setShowSettings] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
const [reviewFromPhaseId, setReviewFromPhaseId] = useState<string | null>(null);
|
const [reviewFromPhaseId, setReviewFromPhaseId] = useState<string | null>(null);
|
||||||
const [editTransition, setEditTransition] = useState<{ elementId: string; fromPhaseId: string } | null>(null);
|
const [editTransition, setEditTransition] = useState<{ elementId: string; fromPhaseId: string } | null>(null);
|
||||||
|
const [editPhaseCell, setEditPhaseCell] = useState<{ elementId: string; phaseId: string } | null>(null);
|
||||||
|
|
||||||
const columns = useMemo<Column[]>(() => {
|
const columns = useMemo<Column[]>(() => {
|
||||||
const cols: Column[] = [];
|
const cols: Column[] = [];
|
||||||
@@ -389,17 +389,13 @@ export function PlanView({
|
|||||||
{columns.map((col) => {
|
{columns.map((col) => {
|
||||||
if (col.kind === "phase") {
|
if (col.kind === "phase") {
|
||||||
const ce = computedElement(col.phase.id, el.id);
|
const ce = computedElement(col.phase.id, el.id);
|
||||||
const isSel =
|
|
||||||
selected?.type === "phaseCell" &&
|
|
||||||
selected.elementId === el.id &&
|
|
||||||
selected.phaseId === col.phase.id;
|
|
||||||
return (
|
return (
|
||||||
<td
|
<td
|
||||||
key={col.phase.id}
|
key={col.phase.id}
|
||||||
onClick={() => setSelected({ type: "phaseCell", elementId: el.id, phaseId: col.phase.id })}
|
onClick={() => setEditPhaseCell({ elementId: el.id, phaseId: col.phase.id })}
|
||||||
className={`cursor-pointer border-b border-r border-border px-2 py-1.5 text-center text-xs ${
|
className={`cursor-pointer border-b border-r border-border px-2 py-1.5 text-center text-xs ${
|
||||||
isSel ? "bg-accent-soft" : ""
|
ce?.locked ? "text-faint" : "text-fg"
|
||||||
} ${ce?.locked ? "text-faint" : "text-fg"}`}
|
}`}
|
||||||
>
|
>
|
||||||
{phaseCellContent(ce)}
|
{phaseCellContent(ce)}
|
||||||
</td>
|
</td>
|
||||||
@@ -443,10 +439,7 @@ export function PlanView({
|
|||||||
{/* Detail-Panel. Der key erzwingt beim Wechsel von Zelle/Phase einen Neuaufbau,
|
{/* Detail-Panel. Der key erzwingt beim Wechsel von Zelle/Phase einen Neuaufbau,
|
||||||
damit der lokale Formular-Zustand nicht vom vorher geoeffneten Element uebrig bleibt. */}
|
damit der lokale Formular-Zustand nicht vom vorher geoeffneten Element uebrig bleibt. */}
|
||||||
{selected && (
|
{selected && (
|
||||||
<div
|
<div key={`ph-${selected.phaseId}`} className="rounded-xl border border-accent bg-surface p-4 shadow-sm">
|
||||||
key={selected.type === "phase" ? `ph-${selected.phaseId}` : `pc-${selected.elementId}-${selected.phaseId}`}
|
|
||||||
className="rounded-xl border border-accent bg-surface p-4 shadow-sm"
|
|
||||||
>
|
|
||||||
{renderDetail()}
|
{renderDetail()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -526,6 +519,31 @@ export function PlanView({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
|
{editPhaseCell && (() => {
|
||||||
|
const element = plan.elements.find((e) => e.id === editPhaseCell.elementId);
|
||||||
|
const phase = computed.phases.find((p) => p.id === editPhaseCell.phaseId);
|
||||||
|
if (!element || !phase) return null;
|
||||||
|
const context = buildPhaseContext(phase, element);
|
||||||
|
return (
|
||||||
|
<PhaseCellDialog
|
||||||
|
key={`${editPhaseCell.elementId}-${editPhaseCell.phaseId}`}
|
||||||
|
element={element}
|
||||||
|
phase={phase}
|
||||||
|
context={context}
|
||||||
|
phaseData={element.phaseValues[phase.id] ?? {}}
|
||||||
|
onClose={() => setEditPhaseCell(null)}
|
||||||
|
onSaved={() => {
|
||||||
|
setEditPhaseCell(null);
|
||||||
|
onChanged();
|
||||||
|
}}
|
||||||
|
onDeleted={() => {
|
||||||
|
setEditPhaseCell(null);
|
||||||
|
deleteElement(element.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -541,41 +559,21 @@ export function PlanView({
|
|||||||
|
|
||||||
function renderDetail() {
|
function renderDetail() {
|
||||||
if (!selected) return null;
|
if (!selected) return null;
|
||||||
|
const phase = computed.phases.find((p) => p.id === selected.phaseId);
|
||||||
if (selected.type === "phase") {
|
const phaseInput = plan.phases.find((p) => p.id === selected.phaseId);
|
||||||
const phase = computed.phases.find((p) => p.id === selected.phaseId);
|
if (!phase || !phaseInput) return null;
|
||||||
const phaseInput = plan.phases.find((p) => p.id === selected.phaseId);
|
const isLast = phase.sequenceNumber === computed.phases.length;
|
||||||
if (!phase || !phaseInput) return null;
|
|
||||||
const isLast = phase.sequenceNumber === computed.phases.length;
|
|
||||||
return (
|
|
||||||
<PhaseDetail
|
|
||||||
phase={phaseInput}
|
|
||||||
maxDurationYears={phase.maxDurationYears}
|
|
||||||
isLast={isLast}
|
|
||||||
inflationDefault={plan.inflationRateDefault}
|
|
||||||
onSaved={onChanged}
|
|
||||||
onDeleted={() => {
|
|
||||||
setSelected(null);
|
|
||||||
onChanged();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const element = plan.elements.find((e) => e.id === selected.elementId);
|
|
||||||
if (!element) return null;
|
|
||||||
|
|
||||||
// phaseCell
|
|
||||||
const phase = computed.phases.find((p) => p.id === selected.phaseId)!;
|
|
||||||
const context = buildPhaseContext(phase, element);
|
|
||||||
return (
|
return (
|
||||||
<ElementDetail
|
<PhaseDetail
|
||||||
element={element}
|
phase={phaseInput}
|
||||||
context={context}
|
maxDurationYears={phase.maxDurationYears}
|
||||||
phaseData={element.phaseValues[phase.id] ?? {}}
|
isLast={isLast}
|
||||||
transitionData={{}}
|
inflationDefault={plan.inflationRateDefault}
|
||||||
onSaved={onChanged}
|
onSaved={onChanged}
|
||||||
onDeleteElement={() => deleteElement(element.id)}
|
onDeleted={() => {
|
||||||
|
setSelected(null);
|
||||||
|
onChanged();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1040,6 +1038,38 @@ function TransitionReviewDialog({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Dialog: Element-Werte einer Lebensphase (per Klick auf eine Phasenzelle) ---
|
||||||
|
function PhaseCellDialog({
|
||||||
|
element,
|
||||||
|
phase,
|
||||||
|
context,
|
||||||
|
phaseData,
|
||||||
|
onClose,
|
||||||
|
onSaved,
|
||||||
|
onDeleted,
|
||||||
|
}: {
|
||||||
|
element: ElementInput;
|
||||||
|
phase: PhaseComputed;
|
||||||
|
context: CellContext;
|
||||||
|
phaseData: PhaseData;
|
||||||
|
onClose: () => void;
|
||||||
|
onSaved: () => void;
|
||||||
|
onDeleted: () => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<DialogShell title={`Lebensphase: ${phase.name}`} onClose={onClose} wide>
|
||||||
|
<ElementDetail
|
||||||
|
element={element}
|
||||||
|
context={context}
|
||||||
|
phaseData={phaseData}
|
||||||
|
transitionData={{}}
|
||||||
|
onSaved={onSaved}
|
||||||
|
onDeleteElement={onDeleted}
|
||||||
|
/>
|
||||||
|
</DialogShell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Dialog: einzelner Übergangs-Entscheid (per Klick auf eine Übergangszelle) ---
|
// --- Dialog: einzelner Übergangs-Entscheid (per Klick auf eine Übergangszelle) ---
|
||||||
function TransitionCellDialog({
|
function TransitionCellDialog({
|
||||||
element,
|
element,
|
||||||
|
|||||||
Reference in New Issue
Block a user