Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Turnierplan.App/Client/src/app/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,9 @@ export const de = {
Views: 'Ansichten',
Settings: 'Einstellungen'
},
ManageResources: {
EmptyGroup: 'Keine Einträge vorhanden'
},
Settings: {
Rename: {
Button: 'Umbenennen',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@if (viewModel) {
<div class="mb-5 d-flex flex-row gap-3">
@for (column of viewModel.columns; track $index) {
<div class="d-flex flex-column gap-3" style="min-width: 300px; max-width: 300px">
@for (group of column.groups; track group.id) {
<div class="card">
<div class="card-header tp-text-ellipsis">{{ group.name }}</div>
<ul class="list-group list-group-flush">
@for (resource of group.resources; track resource.id) {
<li class="list-group-item tp-text-ellipsis">
@switch (resource.type) {
@case (resourceType.Commodity) {
<i class="bi bi-box-seam me-2"></i>
}
@case (resourceType.Personnel) {
<i class="bi bi-person me-2"></i>
}
}
<span>{{ resource.name }}</span>
</li>
} @empty {
<li
class="list-group-item fst-italic text-muted small"
[translate]="'Portal.ViewResourcePlanner.ManageResources.EmptyGroup'"></li>
}
</ul>
</div>
}
</div>
}
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { ResourcePlannerDto } from '../../../api/models/resource-planner-dto';
import { ResourceGroupType } from '../../../api/models/resource-group-type';
import { ResourceAssignmentState } from '../../../api/models/resource-assignment-state';
import { ResourceType } from '../../../api/models/resource-type';
import { TranslateDirective } from '@ngx-translate/core';

type ResourcesViewModel = {
columns: {
groups: {
id: number;
name: string;
description?: string;
type: ResourceGroupType;
range?: {
start: Date;
end: Date;
};
resources: {
id: number;
type: ResourceType;
name: string;
notes?: string;
state: ResourceAssignmentState;
}[];
}[];
}[];
};

@Component({
selector: 'tp-manage-resources',
imports: [TranslateDirective],
templateUrl: './manage-resources.component.html'
})
export class ManageResourcesComponent {
@Input()
public set resourcePlanner(value: ResourcePlannerDto) {
this._resourcePlanner = value;
this.updateViewModel();
}

@Output()
public errorOccured = new EventEmitter<unknown>();

protected readonly resourceType = ResourceType;

protected viewModel?: ResourcesViewModel;
private _resourcePlanner?: ResourcePlannerDto;

private updateViewModel(): void {
// TODO: Convert resource planner to view model

const time = (h: number, m: number) => {
return new Date(2026, 7, 29, h, m, 0);
};

let id = 1;

const column = (k: number) => ({
groups: [
{
id: id++,
name: 'Ansprechperson',
type: ResourceGroupType.Workshift,
range: {
start: time(11, 30),
end: time(17, 30)
},
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Schicht 1',
type: ResourceGroupType.Workshift,
range: {
start: time(10, 0),
end: time(13, 0)
},
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Requested
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Schicht 2',
type: ResourceGroupType.Workshift,
range: {
start: time(13, 0),
end: time(16, 0)
},
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Requested
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Proposed
}
]
},
{
id: id++,
name: 'Schicht 3',
type: ResourceGroupType.Workshift,
range: {
start: time(16, 0),
end: time(19, 0)
},
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Kuchen',
type: ResourceGroupType.General,
resources: [
{
id: id++,
name: 'Quark Sahne Torte',
type: ResourceType.Commodity,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Käsekuchen',
type: ResourceType.Commodity,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Hasselnuss-Gugelhupf',
type: ResourceType.Commodity,
state: ResourceAssignmentState.Requested
}
]
},
{
id: id++,
name: 'Turnierleitung',
type: ResourceGroupType.General,
resources:
k == 3
? []
: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Turnieraufsicht',
type: ResourceGroupType.General,
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Hallensprecher',
type: ResourceGroupType.General,
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
},
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Siegerehrung',
type: ResourceGroupType.General,
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
},
{
id: id++,
name: 'Sanitäter',
type: ResourceGroupType.General,
resources: [
{
id: id++,
name: 'Max Mustermann',
type: ResourceType.Personnel,
state: ResourceAssignmentState.Confirmed
}
]
}
]
});

this.viewModel = {
columns: [column(0), column(1), column(2), column(3), column(4)]
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,20 @@
}
@case (2) {
<!-- Settings page -->
@if (isUpdatingName) {
<tp-small-spinner />
}
<tp-rename-button
translationKey="Portal.ViewResourcePlanner.Settings.Rename"
[current]="resourcePlanner.name"
[disabled]="isUpdatingName"
(renamed)="renameResourcePlanner($event)" />
}
}
</ng-template>

<ng-template #mainContent>
<!-- Resources page does not need the div since it uses full-width content exlusively. -->
<!-- Resources page does not need the div since it uses full-width content exclusively. -->
@if (currentPage !== 0) {
<div class="card">
@switch (currentPage) {
Expand Down Expand Up @@ -61,7 +65,15 @@
<ng-template #fullWidthContent>
@if (currentPage === 0) {
<!-- Resources page -->
resources
<div class="mt-3 d-flex flex-row px-3">
<div class="flex-grow-1"></div>
<div style="max-width: 2400px" class="overflow-x-auto">
<tp-manage-resources
[resourcePlanner]="resourcePlanner"
(errorOccured)="loadingState = { isLoading: false, error: $event }" />
</div>
<div class="flex-grow-1"></div>
</div>
}
</ng-template>
</tp-page-frame>
Expand Down
Loading
Loading