| @@ -2238,7 +2238,16 @@ components: | |||
| - integer | |||
| - 'null' | |||
| zone: | |||
| $ref: '#/components/schemas/Zone' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| zoneIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| name: | |||
| type: string | |||
| code: | |||
| @@ -2256,6 +2265,7 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - zoneIri | |||
| - name | |||
| - code | |||
| Location.jsonld: | |||
| @@ -2292,7 +2302,14 @@ components: | |||
| - integer | |||
| - 'null' | |||
| zone: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Zone.jsonld' | |||
| zoneIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| name: | |||
| type: string | |||
| code: | |||
| @@ -2310,6 +2327,7 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - zoneIri | |||
| - name | |||
| - code | |||
| MediaObject: | |||
| @@ -2467,7 +2485,16 @@ components: | |||
| - integer | |||
| - 'null' | |||
| vessel: | |||
| $ref: '#/components/schemas/Vessel' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| vesselIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| pilotageReference: | |||
| readOnly: true | |||
| type: | |||
| @@ -2482,9 +2509,27 @@ components: | |||
| - string | |||
| - 'null' | |||
| startLocation: | |||
| $ref: '#/components/schemas/Location' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| startLocationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| endLocation: | |||
| $ref: '#/components/schemas/Location' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| endLocationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| startDate: | |||
| type: string | |||
| format: date-time | |||
| @@ -2502,6 +2547,9 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - vesselIri | |||
| - startLocationIri | |||
| - endLocationIri | |||
| - startDate | |||
| - endDate | |||
| Trip.jsonld: | |||
| @@ -2538,7 +2586,14 @@ components: | |||
| - integer | |||
| - 'null' | |||
| vessel: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Vessel.jsonld' | |||
| vesselIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| pilotageReference: | |||
| readOnly: true | |||
| type: | |||
| @@ -2553,9 +2608,23 @@ components: | |||
| - string | |||
| - 'null' | |||
| startLocation: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Location.jsonld' | |||
| startLocationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| endLocation: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Location.jsonld' | |||
| endLocationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| startDate: | |||
| type: string | |||
| format: date-time | |||
| @@ -2573,6 +2642,9 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - vesselIri | |||
| - startLocationIri | |||
| - endLocationIri | |||
| - startDate | |||
| - endDate | |||
| TripLocation: | |||
| @@ -2587,8 +2659,20 @@ components: | |||
| - 'null' | |||
| trip: | |||
| $ref: '#/components/schemas/Trip' | |||
| tripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| location: | |||
| $ref: '#/components/schemas/Location' | |||
| locationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| isArrival: | |||
| type: boolean | |||
| date: | |||
| @@ -2601,6 +2685,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - tripIri | |||
| - locationIri | |||
| - date | |||
| TripLocation.jsonld: | |||
| type: object | |||
| @@ -2637,8 +2723,20 @@ components: | |||
| - 'null' | |||
| trip: | |||
| $ref: '#/components/schemas/Trip.jsonld' | |||
| tripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| location: | |||
| $ref: '#/components/schemas/Location.jsonld' | |||
| locationIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| isArrival: | |||
| type: boolean | |||
| date: | |||
| @@ -2651,6 +2749,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - tripIri | |||
| - locationIri | |||
| - date | |||
| User: | |||
| type: object | |||
| @@ -2804,9 +2904,27 @@ components: | |||
| - integer | |||
| - 'null' | |||
| trip: | |||
| $ref: '#/components/schemas/Trip' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| tripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| user: | |||
| $ref: '#/components/schemas/User' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| userIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| captainName: | |||
| type: | |||
| - string | |||
| @@ -2814,7 +2932,16 @@ components: | |||
| completed: | |||
| type: boolean | |||
| signature: | |||
| $ref: '#/components/schemas/MediaObject' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| signatureIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| signatureUrl: | |||
| readOnly: true | |||
| type: | |||
| @@ -2832,8 +2959,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - trip | |||
| - user | |||
| - tripIri | |||
| - userIri | |||
| - completed | |||
| UserTrip.jsonld: | |||
| type: object | |||
| @@ -2869,9 +2996,23 @@ components: | |||
| - integer | |||
| - 'null' | |||
| trip: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Trip.jsonld' | |||
| tripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| user: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/User.jsonld' | |||
| userIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| captainName: | |||
| type: | |||
| - string | |||
| @@ -2879,7 +3020,14 @@ components: | |||
| completed: | |||
| type: boolean | |||
| signature: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/MediaObject.jsonld' | |||
| signatureIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| signatureUrl: | |||
| readOnly: true | |||
| type: | |||
| @@ -2897,8 +3045,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - trip | |||
| - user | |||
| - tripIri | |||
| - userIri | |||
| - completed | |||
| UserTripEvent: | |||
| type: object | |||
| @@ -2913,11 +3061,23 @@ components: | |||
| userTrip: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/UserTrip' | |||
| userTripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| event: | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| eventIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| date: | |||
| type: string | |||
| format: date-time | |||
| @@ -2932,6 +3092,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - userTripIri | |||
| - eventIri | |||
| - date | |||
| UserTripEvent.jsonld: | |||
| type: object | |||
| @@ -2969,9 +3131,21 @@ components: | |||
| userTrip: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/UserTrip.jsonld' | |||
| userTripIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| event: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/Event.jsonld' | |||
| eventIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| date: | |||
| type: string | |||
| format: date-time | |||
| @@ -2986,6 +3160,8 @@ components: | |||
| - 'null' | |||
| format: date-time | |||
| required: | |||
| - userTripIri | |||
| - eventIri | |||
| - date | |||
| Vessel: | |||
| type: object | |||
| @@ -3002,7 +3178,16 @@ components: | |||
| code: | |||
| type: string | |||
| company: | |||
| $ref: '#/components/schemas/ShippingCompany' | |||
| readOnly: true | |||
| type: string | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| companyIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| createdAt: | |||
| readOnly: true | |||
| type: | |||
| @@ -3012,6 +3197,7 @@ components: | |||
| required: | |||
| - name | |||
| - code | |||
| - companyIri | |||
| Vessel.jsonld: | |||
| type: object | |||
| description: '' | |||
| @@ -3050,7 +3236,14 @@ components: | |||
| code: | |||
| type: string | |||
| company: | |||
| readOnly: true | |||
| $ref: '#/components/schemas/ShippingCompany.jsonld' | |||
| companyIri: | |||
| type: | |||
| - string | |||
| - 'null' | |||
| format: iri-reference | |||
| example: 'https://example.com/' | |||
| createdAt: | |||
| readOnly: true | |||
| type: | |||
| @@ -3060,6 +3253,7 @@ components: | |||
| required: | |||
| - name | |||
| - code | |||
| - companyIri | |||
| Zone: | |||
| type: object | |||
| description: '' | |||
| @@ -64,6 +64,7 @@ export abstract class AbstractDataFormComponent<T extends { [key: string]: any } | |||
| if (request$ !== undefined) { | |||
| request$.subscribe({ | |||
| next: (response) => { | |||
| this.data = response; | |||
| this.submit.emit({ | |||
| status: ModalStatus.Submitted, | |||
| data: response | |||
| @@ -12,6 +12,7 @@ export const eventJsonldForm = new FormGroup({ | |||
| export const locationForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| zone: new FormControl(null, []), | |||
| zoneIri: new FormControl(null, [Validators.required]), | |||
| name: new FormControl(null, [Validators.required]), | |||
| code: new FormControl(null, [Validators.required]), | |||
| isZone: new FormControl(null, []), | |||
| @@ -23,6 +24,7 @@ export const locationForm = new FormGroup({ | |||
| export const locationJsonldForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| zone: new FormControl(null, []), | |||
| zoneIri: new FormControl(null, [Validators.required]), | |||
| name: new FormControl(null, [Validators.required]), | |||
| code: new FormControl(null, [Validators.required]), | |||
| isZone: new FormControl(null, []), | |||
| @@ -63,11 +65,14 @@ export const shippingCompanyJsonldForm = new FormGroup({ | |||
| export const tripForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| vessel: new FormControl(null, []), | |||
| vesselIri: new FormControl(null, [Validators.required]), | |||
| pilotageReference: new FormControl(null, []), | |||
| customerReference: new FormControl(null, []), | |||
| captainName: new FormControl(null, []), | |||
| startLocation: new FormControl(null, []), | |||
| startLocationIri: new FormControl(null, [Validators.required]), | |||
| endLocation: new FormControl(null, []), | |||
| endLocationIri: new FormControl(null, [Validators.required]), | |||
| startDate: new FormControl(null, [Validators.required]), | |||
| endDate: new FormControl(null, [Validators.required]), | |||
| note: new FormControl(null, []), | |||
| @@ -77,11 +82,14 @@ export const tripForm = new FormGroup({ | |||
| export const tripJsonldForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| vessel: new FormControl(null, []), | |||
| vesselIri: new FormControl(null, [Validators.required]), | |||
| pilotageReference: new FormControl(null, []), | |||
| customerReference: new FormControl(null, []), | |||
| captainName: new FormControl(null, []), | |||
| startLocation: new FormControl(null, []), | |||
| startLocationIri: new FormControl(null, [Validators.required]), | |||
| endLocation: new FormControl(null, []), | |||
| endLocationIri: new FormControl(null, [Validators.required]), | |||
| startDate: new FormControl(null, [Validators.required]), | |||
| endDate: new FormControl(null, [Validators.required]), | |||
| note: new FormControl(null, []), | |||
| @@ -91,7 +99,9 @@ export const tripJsonldForm = new FormGroup({ | |||
| export const tripLocationForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| trip: new FormControl(null, []), | |||
| tripIri: new FormControl(null, [Validators.required]), | |||
| location: new FormControl(null, []), | |||
| locationIri: new FormControl(null, [Validators.required]), | |||
| isArrival: new FormControl(null, []), | |||
| date: new FormControl(null, [Validators.required]), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -100,7 +110,9 @@ export const tripLocationForm = new FormGroup({ | |||
| export const tripLocationJsonldForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| trip: new FormControl(null, []), | |||
| tripIri: new FormControl(null, [Validators.required]), | |||
| location: new FormControl(null, []), | |||
| locationIri: new FormControl(null, [Validators.required]), | |||
| isArrival: new FormControl(null, []), | |||
| date: new FormControl(null, [Validators.required]), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -138,11 +150,14 @@ export const userJsonldForm = new FormGroup({ | |||
| export const userTripForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| trip: new FormControl(null, [Validators.required]), | |||
| user: new FormControl(null, [Validators.required]), | |||
| trip: new FormControl(null, []), | |||
| tripIri: new FormControl(null, [Validators.required]), | |||
| user: new FormControl(null, []), | |||
| userIri: new FormControl(null, [Validators.required]), | |||
| captainName: new FormControl(null, []), | |||
| completed: new FormControl(null, [Validators.required]), | |||
| signature: new FormControl(null, []), | |||
| signatureIri: new FormControl(null, []), | |||
| signatureUrl: new FormControl(null, []), | |||
| completedDate: new FormControl(null, []), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -150,11 +165,14 @@ export const userTripForm = new FormGroup({ | |||
| export const userTripJsonldForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| trip: new FormControl(null, [Validators.required]), | |||
| user: new FormControl(null, [Validators.required]), | |||
| trip: new FormControl(null, []), | |||
| tripIri: new FormControl(null, [Validators.required]), | |||
| user: new FormControl(null, []), | |||
| userIri: new FormControl(null, [Validators.required]), | |||
| captainName: new FormControl(null, []), | |||
| completed: new FormControl(null, [Validators.required]), | |||
| signature: new FormControl(null, []), | |||
| signatureIri: new FormControl(null, []), | |||
| signatureUrl: new FormControl(null, []), | |||
| completedDate: new FormControl(null, []), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -163,7 +181,9 @@ export const userTripJsonldForm = new FormGroup({ | |||
| export const userTripEventForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| userTrip: new FormControl(null, []), | |||
| userTripIri: new FormControl(null, [Validators.required]), | |||
| event: new FormControl(null, []), | |||
| eventIri: new FormControl(null, [Validators.required]), | |||
| date: new FormControl(null, [Validators.required]), | |||
| note: new FormControl(null, []), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -172,7 +192,9 @@ export const userTripEventForm = new FormGroup({ | |||
| export const userTripEventJsonldForm = new FormGroup({ | |||
| dbId: new FormControl(null, []), | |||
| userTrip: new FormControl(null, []), | |||
| userTripIri: new FormControl(null, [Validators.required]), | |||
| event: new FormControl(null, []), | |||
| eventIri: new FormControl(null, [Validators.required]), | |||
| date: new FormControl(null, [Validators.required]), | |||
| note: new FormControl(null, []), | |||
| createdAt: new FormControl(null, []) | |||
| @@ -183,6 +205,7 @@ export const vesselForm = new FormGroup({ | |||
| name: new FormControl(null, [Validators.required]), | |||
| code: new FormControl(null, [Validators.required]), | |||
| company: new FormControl(null, []), | |||
| companyIri: new FormControl(null, [Validators.required]), | |||
| createdAt: new FormControl(null, []) | |||
| }); | |||
| @@ -191,6 +214,7 @@ export const vesselJsonldForm = new FormGroup({ | |||
| name: new FormControl(null, [Validators.required]), | |||
| code: new FormControl(null, [Validators.required]), | |||
| company: new FormControl(null, []), | |||
| companyIri: new FormControl(null, [Validators.required]), | |||
| createdAt: new FormControl(null, []) | |||
| }); | |||
| @@ -84,4 +84,33 @@ export class AppHelperService { | |||
| return JSON.stringify(obj, null, 2); // Das `null, 2` formatiert das JSON mit Einrückungen | |||
| } | |||
| public convertJsonldToJson<T extends object>(jsonldObj: any): T { | |||
| // Erstelle ein neues Objekt ohne die JSON-LD spezifischen Eigenschaften | |||
| const result: any = {}; | |||
| // Kopiere alle Eigenschaften außer context, id und type | |||
| for (const key in jsonldObj) { | |||
| if ( | |||
| jsonldObj.hasOwnProperty(key) && | |||
| key !== 'context' && | |||
| key !== 'id' && | |||
| key !== 'type' | |||
| ) { | |||
| // Wenn der Wert ein Objekt ist und JSON-LD Metadaten enthält, konvertiere es rekursiv | |||
| if ( | |||
| typeof jsonldObj[key] === 'object' && | |||
| jsonldObj[key] !== null && | |||
| (jsonldObj[key].context || jsonldObj[key].id || jsonldObj[key].type) | |||
| ) { | |||
| result[key] = this.convertJsonldToJson(jsonldObj[key]); | |||
| } else { | |||
| result[key] = jsonldObj[key]; | |||
| } | |||
| } | |||
| } | |||
| return result as T; | |||
| } | |||
| } | |||
| @@ -13,18 +13,18 @@ | |||
| <input type="text" class="form-control" id="code" formControlName="code" required/> | |||
| </div> | |||
| <div class="mb-3"> | |||
| <label for="zone" class="form-label">{{ 'model.zone' | translate }}:</label> | |||
| <label for="zoneIri" class="form-label">{{ 'model.zone' | translate }}:</label> | |||
| <app-search-select #zoneSearchSelect | |||
| [formId]="'zone'" | |||
| [formId]="'zoneIri'" | |||
| [formLabelLangKey]="'model.zone'" | |||
| [documentForm]="form" | |||
| [getDataFunction]="getZones" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="zoneColDefinitions" | |||
| [dataSet]="data?.zone" | |||
| [dataSet]="data?.zoneIri" | |||
| > | |||
| </app-search-select> | |||
| <input id="zone" type="hidden" formControlName="zone"/> | |||
| <input id="zoneIri" type="hidden" formControlName="zoneIri"/> | |||
| </div> | |||
| <div class="col-12 col-sm-6 col-md-4 col-lg-3 mb-3 switch-widget"> | |||
| @@ -8,6 +8,7 @@ import { ListGetDataFunctionType } from "@app/_components/list/list-get-data-fun | |||
| import { TranslateService } from "@ngx-translate/core"; | |||
| import { Router } from "@angular/router"; | |||
| import { ROUTE_BASE_DATA } from "@app/app-routing.module"; | |||
| import {AppHelperService} from "@app/_helpers/app-helper.service"; | |||
| @Component({ | |||
| selector: 'app-location-form', | |||
| @@ -21,13 +22,17 @@ export class LocationFormComponent extends AbstractDataFormComponent<LocationJso | |||
| constructor( | |||
| private locationService: LocationService, | |||
| private zoneService: ZoneService, | |||
| private appHelperService: AppHelperService, | |||
| translateService: TranslateService, | |||
| router: Router | |||
| ) { | |||
| super( | |||
| locationForm, | |||
| (data: LocationJsonld) => this.locationService.locationsPost(data), | |||
| (id: string | number, data: LocationJsonld) => this.locationService.locationsIdPatch(id.toString(), data), | |||
| (id: string | number, data: LocationJsonld) => this.locationService.locationsIdPatch( | |||
| id.toString(), | |||
| this.appHelperService.convertJsonldToJson(data) | |||
| ), | |||
| (id: string | number) => this.locationService.locationsIdDelete(id.toString()), | |||
| translateService, | |||
| router | |||
| @@ -22,13 +22,13 @@ | |||
| <div class="col-12 col-md-4 mb-3"> | |||
| <label [for]="'location_' + i" class="form-label">Location*:</label> | |||
| <app-search-select | |||
| [formId]="'location'" | |||
| [formId]="'locationIri'" | |||
| [formLabelLangKey]="'model.location'" | |||
| [documentForm]="locationForms[i]" | |||
| [getDataFunction]="getLocations" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="locationColDefinitions" | |||
| [dataSet]="tripLocation.location" | |||
| [dataSet]="tripLocation.locationIri" | |||
| > | |||
| </app-search-select> | |||
| </div> | |||
| @@ -104,7 +104,7 @@ | |||
| [getDataFunction]="getUsers" | |||
| [displayedDataField]="'fullName'" | |||
| [listColDefinitions]="userColDefinitions" | |||
| [dataSet]="userTrip.user" | |||
| [dataSet]="userTrip.userIri" | |||
| (change)="onUserSelectChange(i)" | |||
| > | |||
| </app-search-select> | |||
| @@ -111,7 +111,7 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| // IDs aus bestehenden UserTrips (mit gültiger ID) | |||
| this.userTrips | |||
| .filter(ut => ut.user && ut.user.id) | |||
| .forEach(ut => assignedUserIds.push(this.appHelperService.extractId(ut.user.id!))); | |||
| .forEach(ut => assignedUserIds.push(this.appHelperService.extractId(ut.user?.id!))); | |||
| // IDs aus aktuellen Formularwerten (auch für noch nicht gespeicherte Einträge) | |||
| this.userForms.forEach(form => { | |||
| @@ -120,7 +120,6 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| assignedUserIds.push(this.appHelperService.extractId(userValue)); | |||
| } | |||
| }); | |||
| console.log(assignedUserIds); | |||
| // Filtere Benutzer, die bereits ausgewählt sind (gespeichert oder nicht) | |||
| return this.userService.usersGetCollection(page, pageSize, undefined, term).pipe( | |||
| @@ -191,11 +190,10 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| addNewTripLocation() { | |||
| // Create a new empty trip location | |||
| const newTripLocation: TripLocationJsonld = { | |||
| trip: { | |||
| 'id': this.trip.id // Ensure we send the trip ID in the correct format | |||
| } as TripJsonld, | |||
| tripIri: this.trip.id!, | |||
| date: new Date().toISOString(), | |||
| isArrival: false | |||
| isArrival: false, | |||
| locationIri: null | |||
| }; | |||
| this.tripLocations.push(newTripLocation); | |||
| @@ -321,7 +319,7 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| // Update existing | |||
| return firstValueFrom(this.tripLocationService.tripLocationsIdPatch( | |||
| this.appHelperService.extractId(tripLocation.id), | |||
| tripLocation | |||
| this.appHelperService.convertJsonldToJson(tripLocation) | |||
| )); | |||
| } else { | |||
| // Create new | |||
| @@ -348,9 +346,7 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| if (userFormValue) { | |||
| // If just an ID was set, create a proper user object | |||
| if (typeof userFormValue === 'string') { | |||
| userTrip.user = { | |||
| 'id': userFormValue | |||
| } as UserJsonld; | |||
| userTrip.userIri = userFormValue; | |||
| } | |||
| } | |||
| }); | |||
| @@ -370,7 +366,7 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||
| // Update existing | |||
| return firstValueFrom(this.userTripService.userTripsIdPatch( | |||
| this.appHelperService.extractId(userTrip.id), | |||
| userTrip | |||
| this.appHelperService.convertJsonldToJson(userTrip) | |||
| )); | |||
| } else { | |||
| // Create new | |||
| @@ -7,46 +7,46 @@ | |||
| <div class="spt-form"> | |||
| <form [formGroup]="tripForm" (ngSubmit)="onSubmit()"> | |||
| <div class="mb-3"> | |||
| <label for="vessel" class="form-label">{{ 'trip.vessel' | translate }}*:</label> | |||
| <label for="vesselIri" class="form-label">{{ 'trip.vessel' | translate }}*:</label> | |||
| <app-search-select #vesselSearchSelect | |||
| [formId]="'vessel'" | |||
| [formId]="'vesselIri'" | |||
| [formLabelLangKey]="'model.vessel'" | |||
| [documentForm]="form" | |||
| [getDataFunction]="getVessels" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="vesselColDefinitions" | |||
| [dataSet]="data?.vessel" | |||
| [dataSet]="data?.vesselIri" | |||
| > | |||
| </app-search-select> | |||
| <input id="vessel" type="hidden" formControlName="vessel" required/> | |||
| <input id="vesselIri" type="hidden" formControlName="vesselIri" required/> | |||
| </div> | |||
| <div class="mb-3"> | |||
| <label for="startLocation" class="form-label">{{ 'trip.start_location' | translate }}*:</label> | |||
| <label for="startLocationIri" class="form-label">{{ 'trip.start_location' | translate }}*:</label> | |||
| <app-search-select #startLocationSearchSelect | |||
| [formId]="'startLocation'" | |||
| [formId]="'startLocationIri'" | |||
| [formLabelLangKey]="'model.location'" | |||
| [documentForm]="form" | |||
| [getDataFunction]="getLocations" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="locationColDefinitions" | |||
| [dataSet]="data?.startLocation" | |||
| [dataSet]="data?.startLocationIri" | |||
| > | |||
| </app-search-select> | |||
| <input id="startLocation" type="hidden" formControlName="startLocation" required/> | |||
| <input id="startLocationIri" type="hidden" formControlName="startLocationIri" required/> | |||
| </div> | |||
| <div class="mb-3"> | |||
| <label for="endLocation" class="form-label">{{ 'trip.end_location' | translate }}*:</label> | |||
| <label for="endLocationIri" class="form-label">{{ 'trip.end_location' | translate }}*:</label> | |||
| <app-search-select #endLocationSearchSelect | |||
| [formId]="'endLocation'" | |||
| [formId]="'endLocationIri'" | |||
| [formLabelLangKey]="'model.location'" | |||
| [documentForm]="form" | |||
| [getDataFunction]="getLocations" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="locationColDefinitions" | |||
| [dataSet]="data?.endLocation" | |||
| [dataSet]="data?.endLocationIri" | |||
| > | |||
| </app-search-select> | |||
| <input id="endLocation" type="hidden" formControlName="endLocation" required/> | |||
| <input id="endLocationIri" type="hidden" formControlName="endLocationIri" required/> | |||
| </div> | |||
| <div class="mb-3"> | |||
| @@ -15,6 +15,7 @@ import {Router} from "@angular/router"; | |||
| import {ROUTE_BASE_DATA} from "@app/app-routing.module"; | |||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | |||
| import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | |||
| import {AppHelperService} from "@app/_helpers/app-helper.service"; | |||
| @Component({ | |||
| selector: 'app-trip-form', | |||
| @@ -32,13 +33,18 @@ export class TripFormComponent extends AbstractDataFormComponent<TripJsonld> { | |||
| private tripService: TripService, | |||
| private vesselService: VesselService, | |||
| private locationService: LocationService, | |||
| private appHelperService: AppHelperService, | |||
| translateService: TranslateService, | |||
| router: Router | |||
| ) { | |||
| super( | |||
| tripForm, | |||
| (data: TripJsonld) => this.tripService.tripsPost(data), | |||
| (id: string | number, data: TripJsonld) => this.tripService.tripsIdPatch(id.toString(), data), | |||
| (id: string | number, data: TripJsonld) => | |||
| this.tripService.tripsIdPatch( | |||
| id.toString(), | |||
| this.appHelperService.convertJsonldToJson(data) | |||
| ), | |||
| (id: string | number) => this.tripService.tripsIdDelete(id.toString()), | |||
| translateService, | |||
| router | |||
| @@ -2,7 +2,7 @@ | |||
| <div class="spt-container"> | |||
| <div class="spt-headline d-flex justify-content-between align-items-start"> | |||
| <h2>{{ ('basic.edit') | translate }} {{ 'model.user_trip' | translate }} | |||
| {{ userTrip.trip.pilotageReference }} ({{ userTrip.user.fullName }})</h2> | |||
| {{ userTrip.trip?.pilotageReference }} ({{ userTrip.user?.fullName }})</h2> | |||
| </div> | |||
| </div> | |||
| <mat-tab-group> | |||
| @@ -3,9 +3,9 @@ | |||
| @if (data !== undefined) { | |||
| <form [formGroup]="userTripForm" (ngSubmit)="onSubmit()"> | |||
| <input type="hidden" formControlName="trip" /> | |||
| <input type="hidden" formControlName="user" /> | |||
| <input type="hidden" formControlName="signature" /> | |||
| <input type="hidden" formControlName="tripIri" /> | |||
| <input type="hidden" formControlName="userIri" /> | |||
| <input type="hidden" formControlName="signatureIri" /> | |||
| <div class="mb-3"> | |||
| <label for="captainName" class="form-label">{{ 'trip.captain_name' | translate }}:</label> | |||
| <input type="text" class="form-control" id="captainName" formControlName="captainName"/> | |||
| @@ -21,13 +21,22 @@ | |||
| <!-- Neues File-Upload-Feld für MediaObject --> | |||
| <div class="mb-3"> | |||
| <label for="mediaFile" class="form-label">{{ 'user_trip.signature' | translate }}:</label> | |||
| <input type="file" class="form-control" id="mediaFile" (change)="onFileSelected($event)"/> | |||
| <!-- File-Input ist deaktiviert, wenn ein Bild existiert und nicht zum Löschen markiert ist --> | |||
| <input type="file" class="form-control" id="mediaFile" | |||
| [disabled]="data.signatureUrl && showSignatureImage" | |||
| (change)="onFileSelected($event)"/> | |||
| @if (selectedFile) { | |||
| <small class="text-muted">{{ selectedFile.name }}</small> | |||
| } | |||
| @if (data.signatureUrl) { | |||
| <div class="mt-1"> | |||
| @if (data.signatureUrl && showSignatureImage) { | |||
| <div class="mt-1 d-flex align-items-start gap-2"> | |||
| <img [src]="data.signatureUrl" alt="Signatur" class="img-fluid" /> | |||
| <button type="button" class="btn btn-sm btn-danger" (click)="markSignatureForRemoval()"> | |||
| {{ 'basic.remove' | translate }} | |||
| </button> | |||
| </div> | |||
| } | |||
| </div> | |||
| @@ -37,7 +46,8 @@ | |||
| </div> | |||
| <div class="flex gap-2"> | |||
| <button type="submit" class="btn btn-primary" [disabled]="form.invalid" (click)="onSubmit()"> | |||
| <!-- <button type="submit" class="btn btn-primary" [disabled]="form.invalid" (click)="onSubmit()">--> | |||
| <button type="submit" class="btn btn-primary" (click)="onSubmit()"> | |||
| {{ 'basic.save' | translate }} | |||
| </button> | |||
| @@ -1,21 +1,18 @@ | |||
| import { Component } from '@angular/core'; | |||
| import { | |||
| AbstractDataFormComponent, | |||
| FormMode, | |||
| FormSubmitEvent | |||
| AbstractDataFormComponent, FormSubmitEvent, | |||
| } from "@app/_components/_abstract/abstract-data-form-component"; | |||
| import { | |||
| LocationService, MediaObjectJsonld, MediaObjectService, TripJsonld, UserTrip, | |||
| MediaObjectService, | |||
| UserTripJsonld, | |||
| UserTripService, | |||
| VesselService | |||
| } from "@app/core/api/v1"; | |||
| import { tripForm, userTripForm } from "@app/_forms/apiForms"; | |||
| import { userTripForm } from "@app/_forms/apiForms"; | |||
| import { TranslateService } from "@ngx-translate/core"; | |||
| import { Router } from "@angular/router"; | |||
| import { ROUTE_USER_TRIPS } from "@app/app-routing.module"; | |||
| import { ModalStatus } from "@app/_helpers/modal.states"; | |||
| import { firstValueFrom } from 'rxjs'; | |||
| import {AppHelperService} from "@app/_helpers/app-helper.service"; | |||
| @Component({ | |||
| selector: 'app-user-trip-form', | |||
| @@ -26,17 +23,24 @@ export class UserTripFormComponent extends AbstractDataFormComponent<UserTripJso | |||
| protected readonly userTripForm = userTripForm; | |||
| selectedFile: File | null = null; | |||
| signatureToDelete: string | null = null; | |||
| showSignatureImage: boolean = true; | |||
| constructor( | |||
| private userTripService: UserTripService, | |||
| private mediaObjectService: MediaObjectService, | |||
| private appHelperService: AppHelperService, | |||
| translateService: TranslateService, | |||
| router: Router | |||
| ) { | |||
| super( | |||
| userTripForm, | |||
| undefined, | |||
| (id: string | number, data: UserTripJsonld) => this.userTripService.userTripsIdPatch(id.toString(), data), | |||
| (id: string | number, data: UserTripJsonld) => | |||
| this.userTripService.userTripsIdPatch( | |||
| id.toString(), | |||
| this.appHelperService.convertJsonldToJson(data) | |||
| ), | |||
| (id: string | number) => this.userTripService.userTripsIdDelete(id.toString()), | |||
| translateService, | |||
| router | |||
| @@ -47,18 +51,24 @@ export class UserTripFormComponent extends AbstractDataFormComponent<UserTripJso | |||
| override ngOnInit(): void { | |||
| super.ngOnInit(); | |||
| // Debug-Ausgabe für Formularvalidierung | |||
| this.form.statusChanges.subscribe(status => { | |||
| console.log('Form status:', status); | |||
| console.log('Form errors:', this.form.errors); | |||
| Object.keys(this.form.controls).forEach(key => { | |||
| const control = this.form.get(key); | |||
| if (control?.invalid) { | |||
| console.log(`Control '${key}' is invalid:`, control.errors); | |||
| } | |||
| }); | |||
| this.submit.subscribe((event: FormSubmitEvent<UserTripJsonld>) => { | |||
| if (event.status === ModalStatus.Submitted) { | |||
| this.updateImageStatus(); | |||
| } | |||
| }); | |||
| // Debug-Ausgabe für Formularvalidierung | |||
| // this.form.statusChanges.subscribe(status => { | |||
| // console.log('Form status:', status); | |||
| // console.log('Form errors:', this.form.errors); | |||
| // | |||
| // Object.keys(this.form.controls).forEach(key => { | |||
| // const control = this.form.get(key); | |||
| // if (control?.invalid) { | |||
| // console.log(`Control '${key}' is invalid:`, control.errors); | |||
| // } | |||
| // }); | |||
| // }); | |||
| } | |||
| onFileSelected(event: Event): void { | |||
| @@ -73,29 +83,105 @@ export class UserTripFormComponent extends AbstractDataFormComponent<UserTripJso | |||
| return url.split('/').pop() || ''; | |||
| } | |||
| markSignatureForRemoval(): void { | |||
| // Speichere die aktuelle signatureIri, um sie später zu löschen | |||
| this.signatureToDelete = this.form.get('signatureIri')?.value; | |||
| // Aktualisiere den Formularwert | |||
| this.form.patchValue({ | |||
| signatureIri: null | |||
| }); | |||
| // Verstecke das Bild in der UI | |||
| this.showSignatureImage = false; | |||
| // Falls eine Datei zum Hochladen ausgewählt wurde, entferne diese auch | |||
| this.selectedFile = null; | |||
| } | |||
| updateImageStatus(): void { | |||
| // Wenn das Formular erfolgreich gespeichert wurde, wird diese Methode aufgerufen | |||
| // Prüfen, ob es ein Bild gibt oder nicht | |||
| if (this.data?.signatureUrl) { | |||
| // Es gibt ein Bild, also zeige es an | |||
| this.showSignatureImage = true; | |||
| } else { | |||
| // Es gibt kein Bild, also verstecke es | |||
| this.showSignatureImage = false; | |||
| } | |||
| // Zurücksetzen der temporären Variablen | |||
| this.signatureToDelete = null; | |||
| this.selectedFile = null; | |||
| } | |||
| override onSubmit(): void { | |||
| if (!this.form.valid) { | |||
| // console.log('Form is invalid:', this.form.errors); | |||
| // Object.keys(this.form.controls).forEach(key => { | |||
| // const control = this.form.get(key); | |||
| // if (control?.invalid) { | |||
| // console.log(`Control '${key}' is invalid:`, control.errors); | |||
| // } | |||
| // }); | |||
| return; | |||
| } | |||
| if (!this.selectedFile) { | |||
| const currentValue = this.form.get('signature')?.value; | |||
| if (currentValue === null) { | |||
| this.form.patchValue({ | |||
| signature: undefined | |||
| // Drei Fälle: | |||
| // 1. Ein neues Bild wurde ausgewählt | |||
| // 2. Ein bestehendes Bild soll gelöscht werden | |||
| // 3. Keine Änderungen am Bild | |||
| if (this.selectedFile && this.signatureToDelete) { | |||
| // Fall 1a: Ein neues Bild wurde ausgewählt UND ein altes soll gelöscht werden | |||
| // Zuerst das alte Bild löschen, dann das neue hochladen | |||
| if (this.data?.signature?.dbId) { | |||
| this.mediaObjectService.mediaObjectsIdDelete(this.data?.signature?.dbId?.toString()).subscribe({ | |||
| next: () => { | |||
| // Altes Bild wurde gelöscht, jetzt neues hochladen | |||
| this.uploadNewFile(); | |||
| }, | |||
| error: (error) => { | |||
| console.error('Error deleting signature:', error); | |||
| // Trotz Fehler neues Bild hochladen | |||
| this.uploadNewFile(); | |||
| } | |||
| }); | |||
| } | |||
| } else if (this.selectedFile) { | |||
| // Fall 1b: Nur ein neues Bild wurde ausgewählt (kein altes vorhanden) | |||
| this.uploadNewFile(); | |||
| } else if (this.signatureToDelete && this.data?.signature?.dbId) { | |||
| // Fall 2: Nur ein bestehendes Bild soll gelöscht werden | |||
| this.mediaObjectService.mediaObjectsIdDelete(this.data?.signature?.dbId?.toString()).subscribe({ | |||
| next: () => { | |||
| this.signatureToDelete = null; | |||
| super.onSubmit(); | |||
| }, | |||
| error: (error) => { | |||
| console.error('Error deleting signature:', error); | |||
| super.onSubmit(); | |||
| } | |||
| }); | |||
| } else { | |||
| // Fall 3: Keine Änderungen am Bild | |||
| super.onSubmit(); | |||
| return; | |||
| } | |||
| } | |||
| private uploadNewFile(): void { | |||
| if (!this.selectedFile) return; | |||
| // 1. Handle file upload if a file is selected | |||
| this.mediaObjectService.mediaObjectsPost(this.selectedFile).subscribe({ | |||
| next: (mediaObject) => { | |||
| // 2. Update the form data with the new mediaObject | |||
| console.log(mediaObject.id); | |||
| // Aktualisiere die Formulardaten mit dem neuen mediaObject | |||
| this.form.patchValue({ | |||
| signature: mediaObject.id | |||
| signatureIri: mediaObject.id | |||
| }); | |||
| // 3. Call the parent method to handle the standard save process | |||
| // Rufe die übergeordnete Methode auf, um den Standard-Speicherprozess zu verarbeiten | |||
| super.onSubmit(); | |||
| }, | |||
| error: (error) => { | |||
| @@ -23,17 +23,17 @@ | |||
| </div> | |||
| <div class="mb-3"> | |||
| <label for="company" class="form-label">{{ 'model.shipping_company' | translate }}:</label> | |||
| <label for="companyIri" class="form-label">{{ 'model.shipping_company' | translate }}:</label> | |||
| <app-search-select #shippingCompanySearchSelect | |||
| [formId]="'company'" | |||
| [formId]="'companyIri'" | |||
| [formLabelLangKey]="'model.shipping_company'" | |||
| [documentForm]="form" | |||
| [getDataFunction]="getShippingCompanies" | |||
| [displayedDataField]="'name'" | |||
| [listColDefinitions]="shippingCompanyColDefinitions" | |||
| [dataSet]="data?.company"> | |||
| [dataSet]="data?.companyIri"> | |||
| </app-search-select> | |||
| <input id="company" type="hidden" formControlName="company"/> | |||
| <input id="companyIri" type="hidden" formControlName="companyIri"/> | |||
| </div> | |||
| <div class="flex gap-2"> | |||
| @@ -8,6 +8,7 @@ import { AbstractDataFormComponent } from "@app/_components/_abstract/abstract-d | |||
| import { TranslateService } from "@ngx-translate/core"; | |||
| import { Router } from "@angular/router"; | |||
| import { ROUTE_BASE_DATA } from "@app/app-routing.module"; | |||
| import {AppHelperService} from "@app/_helpers/app-helper.service"; | |||
| @Component({ | |||
| selector: 'app-vessel-form', | |||
| @@ -20,13 +21,18 @@ export class VesselFormComponent extends AbstractDataFormComponent<VesselJsonld> | |||
| constructor( | |||
| private vesselService: VesselService, | |||
| private shippingCompanyService: ShippingCompanyService, | |||
| private appHelperService: AppHelperService, | |||
| translateService: TranslateService, | |||
| router: Router | |||
| ) { | |||
| super( | |||
| vesselForm, | |||
| (data: VesselJsonld) => this.vesselService.vesselsPost(data), | |||
| (id: string | number, data: VesselJsonld) => this.vesselService.vesselsIdPatch(id.toString(), data), | |||
| (id: string | number, data: VesselJsonld) => | |||
| this.vesselService.vesselsIdPatch( | |||
| id.toString(), | |||
| this.appHelperService.convertJsonldToJson(data) | |||
| ), | |||
| (id: string | number) => this.vesselService.vesselsIdDelete(id.toString()), | |||
| translateService, | |||
| router | |||
| @@ -9,7 +9,6 @@ | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { Zone } from './zone'; | |||
| /** | |||
| @@ -17,7 +16,8 @@ import { Zone } from './zone'; | |||
| */ | |||
| export interface Location { | |||
| readonly dbId?: number | null; | |||
| zone?: Zone; | |||
| readonly zone?: string; | |||
| zoneIri: string | null; | |||
| name: string; | |||
| code: string; | |||
| isZone?: boolean; | |||
| @@ -21,7 +21,8 @@ export interface LocationJsonld { | |||
| readonly id?: string; | |||
| readonly type?: string; | |||
| readonly dbId?: number | null; | |||
| zone?: ZoneJsonld; | |||
| readonly zone?: ZoneJsonld; | |||
| zoneIri: string | null; | |||
| name: string; | |||
| code: string; | |||
| isZone?: boolean; | |||
| @@ -9,8 +9,6 @@ | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { Vessel } from './vessel'; | |||
| import { Location } from './location'; | |||
| /** | |||
| @@ -18,12 +16,15 @@ import { Location } from './location'; | |||
| */ | |||
| export interface Trip { | |||
| readonly dbId?: number | null; | |||
| vessel?: Vessel; | |||
| readonly vessel?: string; | |||
| vesselIri: string | null; | |||
| readonly pilotageReference?: string | null; | |||
| customerReference?: string | null; | |||
| captainName?: string | null; | |||
| startLocation?: Location; | |||
| endLocation?: Location; | |||
| readonly startLocation?: string; | |||
| startLocationIri: string | null; | |||
| readonly endLocation?: string; | |||
| endLocationIri: string | null; | |||
| startDate: string; | |||
| endDate: string; | |||
| note?: string | null; | |||
| @@ -22,12 +22,15 @@ export interface TripJsonld { | |||
| readonly id?: string; | |||
| readonly type?: string; | |||
| readonly dbId?: number | null; | |||
| vessel?: VesselJsonld; | |||
| readonly vessel?: VesselJsonld; | |||
| vesselIri: string | null; | |||
| readonly pilotageReference?: string | null; | |||
| customerReference?: string | null; | |||
| captainName?: string | null; | |||
| startLocation?: LocationJsonld; | |||
| endLocation?: LocationJsonld; | |||
| readonly startLocation?: LocationJsonld; | |||
| startLocationIri: string | null; | |||
| readonly endLocation?: LocationJsonld; | |||
| endLocationIri: string | null; | |||
| startDate: string; | |||
| endDate: string; | |||
| note?: string | null; | |||
| @@ -19,7 +19,9 @@ import { Location } from './location'; | |||
| export interface TripLocation { | |||
| readonly dbId?: number | null; | |||
| trip?: Trip; | |||
| tripIri: string | null; | |||
| location?: Location; | |||
| locationIri: string | null; | |||
| isArrival?: boolean; | |||
| date: string; | |||
| readonly createdAt?: string | null; | |||
| @@ -23,7 +23,9 @@ export interface TripLocationJsonld { | |||
| readonly type?: string; | |||
| readonly dbId?: number | null; | |||
| trip?: TripJsonld; | |||
| tripIri: string | null; | |||
| location?: LocationJsonld; | |||
| locationIri: string | null; | |||
| isArrival?: boolean; | |||
| date: string; | |||
| readonly createdAt?: string | null; | |||
| @@ -9,9 +9,6 @@ | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { Trip } from './trip'; | |||
| import { User } from './user'; | |||
| import { MediaObject } from './mediaObject'; | |||
| /** | |||
| @@ -19,11 +16,14 @@ import { MediaObject } from './mediaObject'; | |||
| */ | |||
| export interface UserTrip { | |||
| readonly dbId?: number | null; | |||
| trip: Trip; | |||
| user: User; | |||
| readonly trip?: string; | |||
| tripIri: string | null; | |||
| readonly user?: string; | |||
| userIri: string | null; | |||
| captainName?: string | null; | |||
| completed: boolean; | |||
| signature?: MediaObject; | |||
| readonly signature?: string; | |||
| signatureIri?: string | null; | |||
| readonly signatureUrl?: string | null; | |||
| completedDate?: string | null; | |||
| readonly createdAt?: string | null; | |||
| @@ -18,7 +18,9 @@ import { UserTrip } from './userTrip'; | |||
| export interface UserTripEvent { | |||
| readonly dbId?: number | null; | |||
| readonly userTrip?: UserTrip; | |||
| userTripIri: string | null; | |||
| readonly event?: string; | |||
| eventIri: string | null; | |||
| date: string; | |||
| note?: string | null; | |||
| readonly createdAt?: string | null; | |||
| @@ -23,7 +23,9 @@ export interface UserTripEventJsonld { | |||
| readonly type?: string; | |||
| readonly dbId?: number | null; | |||
| readonly userTrip?: UserTripJsonld; | |||
| userTripIri: string | null; | |||
| readonly event?: EventJsonld; | |||
| eventIri: string | null; | |||
| date: string; | |||
| note?: string | null; | |||
| readonly createdAt?: string | null; | |||
| @@ -23,11 +23,14 @@ export interface UserTripJsonld { | |||
| readonly id?: string; | |||
| readonly type?: string; | |||
| readonly dbId?: number | null; | |||
| trip: TripJsonld; | |||
| user: UserJsonld; | |||
| readonly trip?: TripJsonld; | |||
| tripIri: string | null; | |||
| readonly user?: UserJsonld; | |||
| userIri: string | null; | |||
| captainName?: string | null; | |||
| completed: boolean; | |||
| signature?: MediaObjectJsonld; | |||
| readonly signature?: MediaObjectJsonld; | |||
| signatureIri?: string | null; | |||
| readonly signatureUrl?: string | null; | |||
| completedDate?: string | null; | |||
| readonly createdAt?: string | null; | |||
| @@ -9,7 +9,6 @@ | |||
| * https://openapi-generator.tech | |||
| * Do not edit the class manually. | |||
| */ | |||
| import { ShippingCompany } from './shippingCompany'; | |||
| /** | |||
| @@ -19,7 +18,8 @@ export interface Vessel { | |||
| readonly dbId?: number | null; | |||
| name: string; | |||
| code: string; | |||
| company?: ShippingCompany; | |||
| readonly company?: string; | |||
| companyIri: string | null; | |||
| readonly createdAt?: string | null; | |||
| } | |||
| @@ -23,7 +23,8 @@ export interface VesselJsonld { | |||
| readonly dbId?: number | null; | |||
| name: string; | |||
| code: string; | |||
| company?: ShippingCompanyJsonld; | |||
| readonly company?: ShippingCompanyJsonld; | |||
| companyIri: string | null; | |||
| readonly createdAt?: string | null; | |||
| } | |||
| @@ -19,6 +19,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'Location', | |||
| @@ -61,9 +62,9 @@ class LocationApi | |||
| * @var ZoneApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: true, | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| @@ -73,6 +74,10 @@ class LocationApi | |||
| )] | |||
| public ?ZoneApi $zone = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?ZoneApi $zoneIri = null; | |||
| #[Assert\NotBlank] | |||
| public string $name; | |||
| @@ -19,6 +19,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'Trip', | |||
| @@ -57,22 +58,26 @@ class TripApi | |||
| #[ApiProperty(writable: false)] | |||
| public ?int $dbId = null; | |||
| // /** | |||
| // * @var VesselApi | |||
| // */ | |||
| // #[ApiProperty( | |||
| // writable: true, | |||
| // readableLink: true, | |||
| // writableLink: false, | |||
| // builtinTypes: [ | |||
| // new Type( | |||
| // 'object', | |||
| // class: VesselApi::class, | |||
| // ) | |||
| // ] | |||
| // )] | |||
| /** | |||
| * @var VesselApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| class: VesselApi::class, | |||
| ) | |||
| ] | |||
| )] | |||
| public ?VesselApi $vessel = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?VesselApi $vesselIri = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?string $pilotageReference = null; | |||
| @@ -80,38 +85,46 @@ class TripApi | |||
| public ?string $captainName = null; | |||
| // /** | |||
| // * @var LocationApi | |||
| // */ | |||
| // #[ApiProperty( | |||
| // writable: true, | |||
| // readableLink: true, | |||
| // writableLink: false, | |||
| // builtinTypes: [ | |||
| // new Type( | |||
| // 'object', | |||
| // class: LocationApi::class, | |||
| // ) | |||
| // ] | |||
| // )] | |||
| /** | |||
| * @var LocationApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| class: LocationApi::class, | |||
| ) | |||
| ] | |||
| )] | |||
| public ?LocationApi $startLocation = null; | |||
| // /** | |||
| // * @var LocationApi | |||
| // */ | |||
| // #[ApiProperty( | |||
| // writable: true, | |||
| // readableLink: true, | |||
| // writableLink: false, | |||
| // builtinTypes: [ | |||
| // new Type( | |||
| // 'object', | |||
| // class: LocationApi::class, | |||
| // ) | |||
| // ] | |||
| // )] | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?LocationApi $startLocationIri = null; | |||
| /** | |||
| * @var LocationApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| class: LocationApi::class, | |||
| ) | |||
| ] | |||
| )] | |||
| public ?LocationApi $endLocation = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?LocationApi $endLocationIri = null; | |||
| #[Assert\NotBlank] | |||
| public \DateTimeImmutable $startDate; | |||
| @@ -19,6 +19,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'TripLocation', | |||
| @@ -73,6 +74,10 @@ class TripLocationApi | |||
| )] | |||
| public ?TripApi $trip = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?TripApi $tripIri = null; | |||
| /** | |||
| * @var LocationApi | |||
| */ | |||
| @@ -89,6 +94,10 @@ class TripLocationApi | |||
| )] | |||
| public ?LocationApi $location = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?LocationApi $locationIri = null; | |||
| public bool $isArrival; | |||
| #[Assert\NotBlank] | |||
| @@ -20,6 +20,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'UserTrip', | |||
| @@ -63,9 +64,9 @@ class UserTripApi | |||
| * @var TripApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: true, | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| @@ -73,16 +74,19 @@ class UserTripApi | |||
| ) | |||
| ] | |||
| )] | |||
| #[Assert\NotBlank] | |||
| public ?TripApi $trip = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?TripApi $tripIri = null; | |||
| /** | |||
| * @var UserApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: true, | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| @@ -90,9 +94,12 @@ class UserTripApi | |||
| ) | |||
| ] | |||
| )] | |||
| #[Assert\NotBlank] | |||
| public ?UserApi $user = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?UserApi $userIri = null; | |||
| public ?string $captainName = null; | |||
| #[Assert\NotNull] | |||
| @@ -102,9 +109,9 @@ class UserTripApi | |||
| * @var MediaObjectApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: true, | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| @@ -114,6 +121,9 @@ class UserTripApi | |||
| )] | |||
| public ?MediaObjectApi $signature = null; | |||
| #[ApiProperty(writable: true)] | |||
| public ?MediaObjectApi $signatureIri = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?string $signatureUrl = null; | |||
| @@ -15,6 +15,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'UserTripEvent', | |||
| @@ -61,6 +62,10 @@ class UserTripEventApi | |||
| )] | |||
| public ?UserTripApi $userTrip = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?UserTripApi $userTripIri = null; | |||
| /** | |||
| * @var EventApi | |||
| */ | |||
| @@ -77,6 +82,10 @@ class UserTripEventApi | |||
| )] | |||
| public ?EventApi $event = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?EventApi $eventIri = null; | |||
| #[Assert\NotBlank] | |||
| public \DateTimeImmutable $date; | |||
| @@ -19,6 +19,7 @@ use App\State\EntityClassDtoStateProcessor; | |||
| use App\State\EntityToDtoStateProvider; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| shortName: 'Vessel', | |||
| @@ -67,9 +68,9 @@ class VesselApi | |||
| * @var ShippingCompanyApi | |||
| */ | |||
| #[ApiProperty( | |||
| writable: true, | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| builtinTypes: [ | |||
| new Type( | |||
| 'object', | |||
| @@ -79,6 +80,10 @@ class VesselApi | |||
| )] | |||
| public ?ShippingCompanyApi $company = null; | |||
| #[NotBlank] | |||
| #[ApiProperty(writable: true)] | |||
| public ?ShippingCompanyApi $companyIri = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?\DateTimeImmutable $createdAt = null; | |||
| } | |||
| @@ -43,7 +43,7 @@ class LocationEntityToApiMapper implements MapperInterface | |||
| $dto->isPort = $entity->isPort(); | |||
| $dto->createdAt = $entity->getCreatedAt(); | |||
| $dto->zone = $this->microMapper->map($entity->getZone(), ZoneApi::class, [ | |||
| $dto->zoneIri = $dto->zone = $this->microMapper->map($entity->getZone(), ZoneApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| @@ -4,6 +4,7 @@ namespace App\Mapper; | |||
| use App\ApiResource\UserTripApi; | |||
| use App\Entity\UserTrip; | |||
| use App\Repository\MediaObjectRepository; | |||
| use App\Repository\UserTripRepository; | |||
| use App\Repository\TripRepository; | |||
| use App\Repository\UserRepository; | |||
| @@ -18,6 +19,7 @@ class UserTripApiToEntityMapper implements MapperInterface | |||
| private UserTripRepository $repository, | |||
| private TripRepository $tripRepository, | |||
| private UserRepository $userRepository, | |||
| private MediaObjectRepository $mediaObjectRepository | |||
| ) { | |||
| } | |||
| @@ -64,16 +66,19 @@ class UserTripApiToEntityMapper implements MapperInterface | |||
| $entity->setCaptainName($dto->captainName); | |||
| if ($dto->completed && !$entity->isCompleted()) { | |||
| if ($entity->getSignature() === null) { | |||
| if ($dto->signatureUrl === null) { | |||
| if ($dto->completed && $entity->getCompletedDate() === null) { | |||
| $entity->setCompletedDate(new \DateTimeImmutable()); | |||
| } | |||
| $entity->setCompleted($dto->completed); | |||
| } | |||
| if ($dto->signatureIri) { | |||
| $signature = $this->mediaObjectRepository->find($dto->signatureIri->id); | |||
| if (!$signature) { | |||
| throw new \Exception('Signature not found'); | |||
| } | |||
| $entity->setCompleted($dto->completed); | |||
| $entity->setCompletedDate(new \DateTimeImmutable()); | |||
| $entity->setSignature($signature); | |||
| } else { | |||
| $entity->setSignature(null); | |||
| } | |||
| return $entity; | |||
| @@ -46,17 +46,17 @@ class UserTripEntityToApiMapper implements MapperInterface | |||
| $dto->completedDate = $entity->getCompletedDate(); | |||
| $dto->createdAt = $entity->getCreatedAt(); | |||
| $dto->trip = $this->microMapper->map($entity->getTrip(), TripApi::class, [ | |||
| $dto->tripIri = $dto->trip = $this->microMapper->map($entity->getTrip(), TripApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $dto->user = $this->microMapper->map($entity->getUser(), UserApi::class, [ | |||
| $dto->userIri = $dto->user = $this->microMapper->map($entity->getUser(), UserApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $dto->signature = null; | |||
| $dto->signatureIri = $dto->signature = null; | |||
| if ($entity->getSignature() !== null) { | |||
| $dto->signature = $this->microMapper->map($entity->getSignature(), MediaObjectApi::class, [ | |||
| $dto->signatureIri = $dto->signature = $this->microMapper->map($entity->getSignature(), MediaObjectApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| } | |||
| @@ -46,11 +46,17 @@ class EntityClassDtoStateProcessor implements ProcessorInterface | |||
| $this->persistProcessor->process($entity, $operation, $uriVariables, $context); | |||
| $data->id = $entity->getId(); | |||
| return $data; | |||
| $resourceClass = $operation->getClass(); | |||
| return $this->mapEntityToDto($entity, $resourceClass); | |||
| } | |||
| private function mapDtoToEntity(object $dto, string $entityClass): object | |||
| { | |||
| return $this->microMapper->map($dto, $entityClass); | |||
| } | |||
| private function mapEntityToDto(object $entity, string $resourceClass): object | |||
| { | |||
| return $this->microMapper->map($entity, $resourceClass); | |||
| } | |||
| } | |||