- added organizations - added industries - added logo in 2 colors for light and dark theme - improved authorization to allow multi tenancy
253 lines
11 KiB
HTML
253 lines
11 KiB
HTML
<p-toolbar styleClass="mb-6">
|
|
<ng-template #start>
|
|
<p-button label="Neu" icon="pi pi-plus" severity="secondary" class="mr-2" (onClick)="openNew()" />
|
|
<p-button label="Löschen" icon="pi pi-trash" severity="danger" outlined (onClick)="deleteSelected()" [disabled]="!selectedProperties || !selectedProperties.length" />
|
|
</ng-template>
|
|
|
|
<ng-template #end>
|
|
<p-button label="Exportieren" icon="pi pi-upload" severity="secondary" (onClick)="exportCSV()" />
|
|
</ng-template>
|
|
</p-toolbar>
|
|
|
|
<p-table
|
|
#dt
|
|
[value]="properties()"
|
|
[rows]="10"
|
|
[columns]="cols"
|
|
[paginator]="true"
|
|
[globalFilterFields]="['name', 'street', 'houseNumber', 'zipCode', 'city', 'country', 'notes']"
|
|
[tableStyle]="{ 'min-width': '75rem' }"
|
|
[(selection)]="selectedProperties"
|
|
[rowHover]="true"
|
|
dataKey="id"
|
|
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} properties"
|
|
[showCurrentPageReport]="true"
|
|
[rowsPerPageOptions]="[10, 20, 30]"
|
|
>
|
|
<ng-template #caption>
|
|
<div class="flex items-center justify-between">
|
|
<h5 class="m-0" >Verwalte Liegenschaften</h5>
|
|
<p-iconfield>
|
|
<p-inputicon styleClass="pi pi-search" />
|
|
<input pInputText type="text" (input)="onGlobalFilter(dt, $event)" placeholder="Suche..." />
|
|
</p-iconfield>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #header>
|
|
<tr>
|
|
<th style="width: 3rem">
|
|
<p-tableHeaderCheckbox />
|
|
</th>
|
|
<th pSortableColumn="nr" style="min-width:8rem" >
|
|
Nr.
|
|
<p-sortIcon field="nr" />
|
|
</th>
|
|
<th pSortableColumn="name" style="min-width:8rem" >
|
|
Name
|
|
<p-sortIcon field="name" />
|
|
</th>
|
|
<th pSortableColumn="owner" style="min-width:8rem" >
|
|
Eigentümer
|
|
<p-sortIcon field="owner" />
|
|
</th>
|
|
<th pSortableColumn="street" style="min-width: 8rem" >
|
|
Straße
|
|
<p-sortIcon field="street" />
|
|
</th>
|
|
<th pSortableColumn="houseNumber" style="min-width:8rem" >
|
|
Hausnummer
|
|
<p-sortIcon field="houseNumber" />
|
|
</th>
|
|
<th pSortableColumn="zipCode" style="min-width: 12rem" >
|
|
Postleitzahl
|
|
<p-sortIcon field="zipCode" />
|
|
</th>
|
|
<th pSortableColumn="city" style="min-width: 12rem" >
|
|
Stadt
|
|
<p-sortIcon field="city" />
|
|
</th>
|
|
<th pSortableColumn="bundesland" style="min-width:8rem" >
|
|
Bundesland
|
|
<p-sortIcon field="bundesland" />
|
|
</th>
|
|
<th pSortableColumn="Einheiten" style="min-width:8rem" >
|
|
Einheiten
|
|
<p-sortIcon field="Einheiten" />
|
|
</th>
|
|
<th pSortableColumn="Status" style="min-width:8rem">
|
|
Status
|
|
<p-sortIcon field="Status" />
|
|
</th>
|
|
<th pSortableColumn="Projekte" style="min-width:8rem">
|
|
Projekte
|
|
<p-sortIcon field="Projekte" />
|
|
</th>
|
|
<th pSortableColumn="Labels" style="min-width:8rem">
|
|
Labels
|
|
<p-sortIcon field="Labels" />
|
|
</th>
|
|
<th pSortableColumn="country.name" style="min-width: 6rem">
|
|
Land
|
|
<p-sortIcon field="country.name" />
|
|
</th>
|
|
<th style="min-width: 12rem"></th>
|
|
</tr>
|
|
</ng-template>
|
|
<ng-template #body let-property>
|
|
<tr>
|
|
<td>
|
|
<p-tableCheckbox [value]="property" />
|
|
</td>
|
|
<td>Nr...</td>
|
|
<td>{{ property.name }}</td>
|
|
<td>Eigentümer...</td>
|
|
<td>{{ property.street }}</td>
|
|
<td class="text-right">{{ property.houseNumber }}</td>
|
|
<td class="text-right">{{ property.zipCode }}</td>
|
|
<td>{{ property.city }}</td>
|
|
<td>Bundesland...</td>
|
|
<td>Einheiten...</td>
|
|
<td>Status...</td>
|
|
<td>Projekte...</td>
|
|
<td>Labels...</td>
|
|
<td class="text-center">
|
|
<div class="flex items-center gap-2">
|
|
<img src="https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + (property.country | lowercase)" width="30" />
|
|
<span>{{ property.country?.name }}</span>
|
|
</div>
|
|
</td>
|
|
<td class="text-center">
|
|
<p-button icon="pi pi-pencil" class="mr-2" [rounded]="true" [outlined]="true" (click)="editProperty(property)" />
|
|
<p-button icon="pi pi-trash" severity="danger" [rounded]="true" [outlined]="true" (click)="deleteProperty(property)" />
|
|
</td>
|
|
</tr>
|
|
</ng-template>
|
|
</p-table>
|
|
|
|
<p-dialog [(visible)]="propertyDialog" [style]="{ width: '900px' }" i18n-header header="Liegenschaft Details" [modal]="true">
|
|
<ng-template #content>
|
|
|
|
<div class="grid gap-4 max-w-3xl mx-auto p-4">
|
|
<!-- Name -->
|
|
<div class="flex flex-col">
|
|
<label for="name" class="block font-bold mb-3">Name</label>
|
|
<input type="text" pInputText id="name" [(ngModel)]="property().name" required autofocus fluid />
|
|
@if (submitted && !property().name) {
|
|
<small class="text-red-500">Name is required.</small>
|
|
}
|
|
</div>
|
|
|
|
<!-- Street + Housenumber -->
|
|
<div class="grid gap-4 grid-cols-1 sm:grid-cols-3">
|
|
<div class="flex flex-col sm:col-span-2">
|
|
<label for="street" class="block font-bold mb-3">Straße</label>
|
|
<input type="text" pInputText id="street" [(ngModel)]="property().street" required autofocus fluid />
|
|
@if (submitted && !property().street) {
|
|
<small class="text-red-500">Street is required.</small>
|
|
}
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<label for="houseNumber" class="block font-bold mb-3">Hausnummer</label>
|
|
<input type="text" pInputText id="houseNumber" [(ngModel)]="property().houseNumber" required autofocus fluid />
|
|
@if (submitted && !property().houseNumber) {
|
|
<small class="text-red-500">House number is required.</small>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ZipCode + City -->
|
|
<div class="grid gap-4 grid-cols-1 sm:grid-cols-3">
|
|
<div class="flex flex-col">
|
|
<label for="zipCode" class="block font-bold mb-3">Postleitzahl</label>
|
|
<input type="text" pInputText id="zipCode" [(ngModel)]="property().zipCode" required autofocus fluid />
|
|
@if (submitted && !property().zipCode) {
|
|
<small class="text-red-500">Zip code is required.</small>
|
|
}
|
|
</div>
|
|
<div class="flex flex-col sm:col-span-2">
|
|
<label for="city" class="block font-bold mb-3">Stadt</label>
|
|
<input type="text" pInputText id="city" [(ngModel)]="property().city" required autofocus fluid />
|
|
@if (submitted && !property().city) {
|
|
<small class="text-red-500">City is required.</small>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Country -->
|
|
<div class="flex flex-col">
|
|
<label for="country" class="mb-1 font-medium">Land</label>
|
|
<p-select id="country" [options]="countries" [(ngModel)]="property().country" optionLabel="name" optionValue="code" placeholder="Select a country" class="w-full md:w-56">
|
|
<ng-template #selectedItem let-selectedOption>
|
|
@if (selectedOption) {
|
|
<div class="flex items-center gap-2">
|
|
<img
|
|
src="https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png"
|
|
[class]="'flag flag-' + selectedOption.code.toLowerCase()"
|
|
style="width: 18px"
|
|
/>
|
|
<div>{{ selectedOption.name }}</div>
|
|
</div>
|
|
}
|
|
</ng-template>
|
|
<ng-template let-country #item>
|
|
<div class="flex items-center gap-2">
|
|
<img
|
|
src="https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png"
|
|
[class]="'flag flag-' + country.code.toLowerCase()"
|
|
style="width: 18px"
|
|
/>
|
|
<div>{{ country.name }}</div>
|
|
</div>
|
|
</ng-template>
|
|
<ng-template #dropdownicon>
|
|
<i class="pi pi-map"></i>
|
|
</ng-template>
|
|
</p-select>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="flex flex-col">
|
|
<label for="notes" class="block font-bold mb-3">Bemerkungen</label>
|
|
<p-editor #notes="ngModel"
|
|
[(ngModel)]="property().notes"
|
|
name="notes"
|
|
[style]="{ height: '320px' }">
|
|
</p-editor>
|
|
</div>
|
|
|
|
<!-- Uploads -->
|
|
@if (property().id) {
|
|
<div class="flex flex-col">
|
|
|
|
<p-fieldset i18n-legend legend="Anhänge" [toggleable]="true">
|
|
|
|
<div class="flex flex-wrap gap-2 mb-2">
|
|
@for (attachment of property().attachments; track attachment.id) {
|
|
<p-chip label="{{ attachment.fileName }}" icon="pi pi-file">
|
|
<p-button icon="pi pi-times" [rounded]="true" severity="danger" size="small" (click)="confirmRemoveAttachment($event, property(), attachment)"/>
|
|
</p-chip>
|
|
}
|
|
</div>
|
|
|
|
|
|
<p-fileupload name="attachments" url="{{ environment.apiBaseUrl }}/properties/{{ property().id }}/upload" (onUpload)="onUpload($event)" [multiple]="true" accept="image/*,.pdf" maxFileSize="1000000000" mode="advanced">
|
|
<ng-template #empty>
|
|
<div>Drag and drop files to here to upload.</div>
|
|
</ng-template>
|
|
</p-fileupload>
|
|
</p-fieldset>
|
|
</div>
|
|
}
|
|
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #footer>
|
|
<p-button label="Abbrechen" icon="pi pi-times" text (click)="hideDialog()" />
|
|
<p-button label="Speichern" icon="pi pi-check" (click)="saveProperty()" />
|
|
</ng-template>
|
|
</p-dialog>
|
|
|
|
<p-confirmdialog [style]="{ width: '450px' }" />
|