generated from bastian/boilerplate
bedarfe
This commit is contained in:
@@ -61,7 +61,7 @@ const requirementPriorities: Record<string, GridValuePresentation> = {
|
||||
const requirementStatuses: Record<string, GridValuePresentation> = {
|
||||
identified: { icon: '◌', label: 'Bedarf erkannt', tone: 'neutral' },
|
||||
research: { icon: '⌕', label: 'Recherche', tone: 'info' },
|
||||
has_options: { icon: '≡', label: 'Alternativen vorhanden', tone: 'info' },
|
||||
has_options: { icon: '≡', label: 'Möbelvorschläge vorhanden', tone: 'info' },
|
||||
decision_open: { icon: '?', label: 'Entscheidung offen', tone: 'warning' },
|
||||
selected: { icon: '✓', label: 'Ausgewählt', tone: 'info' },
|
||||
ordered: { icon: '▣', label: 'Bestellt', tone: 'info' },
|
||||
@@ -172,8 +172,8 @@ const deliveryStatuses: Record<string, GridValuePresentation> = {
|
||||
}
|
||||
@if (view() === 'scenarios') {
|
||||
<p class="scenario-help">
|
||||
Szenariozuweisung: Klicken Sie in eine Szenariospalte und wählen Sie eine Alternative aus.
|
||||
„Nicht zugewiesen“ lässt den Bedarf im Szenario offen.
|
||||
Klicken Sie auf eine Szenariozelle, um passende Möbel in Ruhe zu vergleichen und Ihre
|
||||
Auswahl anschließend zu übernehmen.
|
||||
</p>
|
||||
}
|
||||
<ag-grid-angular
|
||||
@@ -330,6 +330,10 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
@Output() editRequirement = new EventEmitter<FurnitureRequirement>();
|
||||
@Output() addOption = new EventEmitter<FurnitureRequirement>();
|
||||
@Output() editOption = new EventEmitter<FurnitureOption>();
|
||||
@Output() assignScenario = new EventEmitter<{
|
||||
requirement: FurnitureRequirement;
|
||||
scenarioId: string;
|
||||
}>();
|
||||
@Output() dataChanged = new EventEmitter<void>();
|
||||
private readonly api = inject(HauspilotApiService);
|
||||
private readonly auth = inject(AuthService);
|
||||
@@ -352,7 +356,7 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
delayedOnly = false;
|
||||
readonly views: Array<{ id: View; label: string }> = [
|
||||
{ id: 'requirements', label: 'Bedarfe' },
|
||||
{ id: 'options', label: 'Alternativen' },
|
||||
{ id: 'options', label: 'Möbelvorschläge' },
|
||||
{ id: 'orders', label: 'Bestellungen' },
|
||||
{ id: 'scenarios', label: 'Szenarien' },
|
||||
];
|
||||
@@ -432,11 +436,6 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
}
|
||||
cellChanged(event: CellValueChangedEvent<FurnitureRow>) {
|
||||
if (this.rollback || !this.canEdit || event.oldValue === event.newValue || !event.data) return;
|
||||
const scenarioId = this.scenarioId(event.column.getColId());
|
||||
if (scenarioId && 'requiredQuantity' in event.data) {
|
||||
this.saveScenarioSelection(event, scenarioId, event.data);
|
||||
return;
|
||||
}
|
||||
const row = event.data;
|
||||
this.savingRow.set(row.id);
|
||||
this.error.set(null);
|
||||
@@ -464,6 +463,11 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
if (!event.data) return;
|
||||
const id = event.column.getColId();
|
||||
if ('requiredQuantity' in event.data) {
|
||||
const scenarioId = this.scenarioId(id);
|
||||
if (scenarioId && this.canEdit) {
|
||||
this.assignScenario.emit({ requirement: event.data, scenarioId });
|
||||
return;
|
||||
}
|
||||
if (id === 'actions') this.editRequirement.emit(event.data);
|
||||
if (id === 'addOption') this.addOption.emit(event.data);
|
||||
return;
|
||||
@@ -543,7 +547,7 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
valueFormatter: (p) => money(p.value),
|
||||
valueParser: (p) => parseGermanNumber(p.newValue),
|
||||
},
|
||||
{ field: 'optionCount', headerName: 'Alternativen' },
|
||||
{ field: 'optionCount', headerName: 'Möbelvorschläge' },
|
||||
{
|
||||
field: 'cheapestOption',
|
||||
headerName: 'Günstigste',
|
||||
@@ -586,7 +590,7 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
},
|
||||
{
|
||||
colId: 'addOption',
|
||||
headerName: 'Alternative',
|
||||
headerName: 'Möbelvorschlag',
|
||||
valueGetter: () => (this.canEdit ? '+ hinzufügen' : 'anzeigen'),
|
||||
sortable: false,
|
||||
},
|
||||
@@ -734,28 +738,18 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
const option = row.options.find((entry) => entry.id === params.value);
|
||||
return option ? `✓ ${option.name} · ${money(option.totalPrice)}` : '? Nicht zugewiesen';
|
||||
},
|
||||
editable: (params) =>
|
||||
this.canEdit &&
|
||||
!!params.data &&
|
||||
'requiredQuantity' in params.data &&
|
||||
this.selectableOptions(params.data).length > 0,
|
||||
cellEditor: 'agSelectCellEditor',
|
||||
cellEditorParams: (params: { data?: FurnitureRow }) => ({
|
||||
values:
|
||||
params.data && 'requiredQuantity' in params.data
|
||||
? ['', ...this.selectableOptions(params.data).map((option) => option.id)]
|
||||
: [''],
|
||||
}),
|
||||
cellStyle: (params) =>
|
||||
params.value
|
||||
? {
|
||||
color: 'var(--color-success)',
|
||||
backgroundColor: 'var(--color-success-subtle)',
|
||||
fontWeight: '650',
|
||||
cursor: this.canEdit ? 'pointer' : 'default',
|
||||
}
|
||||
: {
|
||||
color: 'var(--color-warning)',
|
||||
backgroundColor: 'var(--color-warning-subtle)',
|
||||
cursor: this.canEdit ? 'pointer' : 'default',
|
||||
},
|
||||
minWidth: 245,
|
||||
}),
|
||||
@@ -803,63 +797,6 @@ export class FurnitureGridComponent implements OnChanges {
|
||||
private scenarioId(columnId: string) {
|
||||
return columnId.startsWith('scenario:') ? columnId.slice('scenario:'.length) : null;
|
||||
}
|
||||
private selectableOptions(requirement: FurnitureRequirement) {
|
||||
return requirement.options.filter(
|
||||
(option) =>
|
||||
!['archived', 'unavailable', 'rejected', 'returned'].includes(option.status) &&
|
||||
!['unavailable', 'discontinued'].includes(option.availability),
|
||||
);
|
||||
}
|
||||
private saveScenarioSelection(
|
||||
event: CellValueChangedEvent<FurnitureRow>,
|
||||
scenarioId: string,
|
||||
requirement: FurnitureRequirement,
|
||||
) {
|
||||
const scenario = this.scenarios.find((entry) => entry.id === scenarioId);
|
||||
if (!scenario) {
|
||||
this.rollbackCell(event);
|
||||
return;
|
||||
}
|
||||
const optionId = typeof event.newValue === 'string' ? event.newValue : '';
|
||||
const option = optionId
|
||||
? this.selectableOptions(requirement).find((entry) => entry.id === optionId)
|
||||
: undefined;
|
||||
if (optionId && !option) {
|
||||
this.rollbackCell(event);
|
||||
this.error.set('Diese Alternative kann dem Szenario nicht zugewiesen werden.');
|
||||
return;
|
||||
}
|
||||
const selections = scenario.selections
|
||||
.filter((selection) => selection.requirementId !== requirement.id)
|
||||
.map((selection) => ({ ...selection }));
|
||||
if (option)
|
||||
selections.push({
|
||||
requirementId: requirement.id,
|
||||
optionId: option.id,
|
||||
quantity: option.quantity,
|
||||
});
|
||||
this.savingRow.set(requirement.id);
|
||||
this.error.set(null);
|
||||
this.api.updateFurnitureScenarioSelections(this.projectId, scenario, selections).subscribe({
|
||||
next: (saved) => {
|
||||
this.scenarios = this.scenarios.map((entry) => (entry.id === saved.id ? saved : entry));
|
||||
this.savingRow.set(null);
|
||||
this.refreshColumns();
|
||||
this.dataChanged.emit();
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
this.rollbackCell(event);
|
||||
this.savingRow.set(null);
|
||||
this.fail(error);
|
||||
if (this.status(error) === 409) this.load(this.page());
|
||||
},
|
||||
});
|
||||
}
|
||||
private rollbackCell(event: CellValueChangedEvent<FurnitureRow>) {
|
||||
this.rollback = true;
|
||||
event.node.setDataValue(event.column.getColId(), event.oldValue);
|
||||
this.rollback = false;
|
||||
}
|
||||
private optionBody(row: FurnitureOption) {
|
||||
return {
|
||||
name: row.name,
|
||||
|
||||
Reference in New Issue
Block a user