| @@ -2784,10 +2784,12 @@ components: | |||||
| $ref: '#/components/schemas/User' | $ref: '#/components/schemas/User' | ||||
| captainName: | captainName: | ||||
| type: string | type: string | ||||
| startDate: | |||||
| type: string | |||||
| format: date-time | |||||
| endDate: | |||||
| signatureUrl: | |||||
| readOnly: true | |||||
| type: | |||||
| - string | |||||
| - 'null' | |||||
| completedDate: | |||||
| type: string | type: string | ||||
| format: date-time | format: date-time | ||||
| createdAt: | createdAt: | ||||
| @@ -2798,8 +2800,7 @@ components: | |||||
| format: date-time | format: date-time | ||||
| required: | required: | ||||
| - captainName | - captainName | ||||
| - startDate | |||||
| - endDate | |||||
| - completedDate | |||||
| UserTrip.jsonld: | UserTrip.jsonld: | ||||
| type: object | type: object | ||||
| description: '' | description: '' | ||||
| @@ -2839,10 +2840,12 @@ components: | |||||
| $ref: '#/components/schemas/User.jsonld' | $ref: '#/components/schemas/User.jsonld' | ||||
| captainName: | captainName: | ||||
| type: string | type: string | ||||
| startDate: | |||||
| type: string | |||||
| format: date-time | |||||
| endDate: | |||||
| signatureUrl: | |||||
| readOnly: true | |||||
| type: | |||||
| - string | |||||
| - 'null' | |||||
| completedDate: | |||||
| type: string | type: string | ||||
| format: date-time | format: date-time | ||||
| createdAt: | createdAt: | ||||
| @@ -2853,8 +2856,7 @@ components: | |||||
| format: date-time | format: date-time | ||||
| required: | required: | ||||
| - captainName | - captainName | ||||
| - startDate | |||||
| - endDate | |||||
| - completedDate | |||||
| UserTripEvent: | UserTripEvent: | ||||
| type: object | type: object | ||||
| description: '' | description: '' | ||||
| @@ -133,8 +133,8 @@ export const userTripForm = new FormGroup({ | |||||
| trip: new FormControl(null, []), | trip: new FormControl(null, []), | ||||
| user: new FormControl(null, []), | user: new FormControl(null, []), | ||||
| captainName: new FormControl(null, [Validators.required]), | captainName: new FormControl(null, [Validators.required]), | ||||
| startDate: new FormControl(null, [Validators.required]), | |||||
| endDate: new FormControl(null, [Validators.required]), | |||||
| signatureUrl: new FormControl(null, []), | |||||
| completedDate: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| @@ -143,8 +143,8 @@ export const userTripJsonldForm = new FormGroup({ | |||||
| trip: new FormControl(null, []), | trip: new FormControl(null, []), | ||||
| user: new FormControl(null, []), | user: new FormControl(null, []), | ||||
| captainName: new FormControl(null, [Validators.required]), | captainName: new FormControl(null, [Validators.required]), | ||||
| startDate: new FormControl(null, [Validators.required]), | |||||
| endDate: new FormControl(null, [Validators.required]), | |||||
| signatureUrl: new FormControl(null, []), | |||||
| completedDate: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| @@ -14,8 +14,8 @@ | |||||
| ></app-trip-form> | ></app-trip-form> | ||||
| </mat-tab> | </mat-tab> | ||||
| <mat-tab label="{{ 'trip.itinerary' | translate }}"> | <mat-tab label="{{ 'trip.itinerary' | translate }}"> | ||||
| <div class="container-fluid p-4 bg-dark text-white"> | |||||
| <h4 class="mb-4">trip.locations</h4> | |||||
| <div> | |||||
| <h4 class="mb-4">{{ 'trip.itinerary_locations' | translate }}</h4> | |||||
| <div *ngFor="let tripLocation of tripLocations; let i = index" class="mb-4"> | <div *ngFor="let tripLocation of tripLocations; let i = index" class="mb-4"> | ||||
| <div class="row"> | <div class="row"> | ||||
| @@ -31,7 +31,7 @@ | |||||
| [dataSet]="tripLocation.location" | [dataSet]="tripLocation.location" | ||||
| > | > | ||||
| </app-search-select> | </app-search-select> | ||||
| <input [id]="'location_' + i" type="hidden" formControlName="location"/> | |||||
| <!-- <input [id]="'location_' + i" type="hidden" formControlName="location"/>--> | |||||
| </div> | </div> | ||||
| <div class="col-12 col-md-2 mb-3"> | <div class="col-12 col-md-2 mb-3"> | ||||
| @@ -67,34 +67,30 @@ | |||||
| [checked]="tripLocation.isArrival" | [checked]="tripLocation.isArrival" | ||||
| (change)="onIsArrivalChange($event, i)" | (change)="onIsArrivalChange($event, i)" | ||||
| > | > | ||||
| <label class="form-check-label text-white" [for]="'isArrival_' + i"> | |||||
| trip.is_arrival | |||||
| <label class="form-check-label" [for]="'isArrival_' + i"> | |||||
| {{ 'trip.is_arrival' | translate }} | |||||
| </label> | </label> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="col-12 col-md-2 mb-3 d-flex align-items-end"> | <div class="col-12 col-md-2 mb-3 d-flex align-items-end"> | ||||
| <button type="button" class="btn btn-danger" (click)="removeTripLocation(i)"> | |||||
| basic.remove | |||||
| </button> | |||||
| <button type="button" class="btn btn-danger" (click)="removeTripLocation(i)">X</button> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="my-3"> | <div class="my-3"> | ||||
| <button type="button" class="btn btn-primary" (click)="addNewTripLocation()"> | |||||
| basic.add | |||||
| </button> | |||||
| <button type="button" class="btn btn-primary" (click)="addNewTripLocation()">+</button> | |||||
| </div> | </div> | ||||
| <div class="mt-4"> | <div class="mt-4"> | ||||
| <button type="button" class="btn btn-success" (click)="saveAllTripLocations()"> | <button type="button" class="btn btn-success" (click)="saveAllTripLocations()"> | ||||
| Save | |||||
| {{ 'trip.save_itinerary' | translate }} | |||||
| </button> | </button> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </mat-tab> | </mat-tab> | ||||
| <mat-tab label="{{ 'user_trip.view' | translate }}"> | |||||
| <mat-tab label="{{ 'trip.assigned_users' | translate }}"> | |||||
| </mat-tab> | </mat-tab> | ||||
| </mat-tab-group> | </mat-tab-group> | ||||
| @@ -1,11 +1,19 @@ | |||||
| import { Component, OnInit, AfterViewInit, QueryList, ViewChildren } from '@angular/core'; | import { Component, OnInit, AfterViewInit, QueryList, ViewChildren } from '@angular/core'; | ||||
| import { FormBuilder, FormGroup } from '@angular/forms'; | import { FormBuilder, FormGroup } from '@angular/forms'; | ||||
| import { TripJsonld, TripLocationJsonld, TripLocationService, TripService, LocationService, LocationJsonld } from "@app/core/api/v1"; | |||||
| import { | |||||
| TripJsonld, | |||||
| TripLocationJsonld, | |||||
| TripLocationService, | |||||
| TripService, | |||||
| LocationService, | |||||
| LocationJsonld, | |||||
| UserTripService, UserService, UserTripJsonld, UserJsonld | |||||
| } from "@app/core/api/v1"; | |||||
| import { AppHelperService } from "@app/_helpers/app-helper.service"; | import { AppHelperService } from "@app/_helpers/app-helper.service"; | ||||
| import { ActivatedRoute } from "@angular/router"; | import { ActivatedRoute } from "@angular/router"; | ||||
| import { FormMode, FormSubmitEvent } from "@app/_components/_abstract/abstract-data-form-component"; | import { FormMode, FormSubmitEvent } from "@app/_components/_abstract/abstract-data-form-component"; | ||||
| import { ModalStatus } from "@app/_helpers/modal.states"; | import { ModalStatus } from "@app/_helpers/modal.states"; | ||||
| import { Observable } from 'rxjs'; | |||||
| import {firstValueFrom, Observable} from 'rxjs'; | |||||
| import { ListColDefinition } from '@app/_components/list/list-col-definition'; | import { ListColDefinition } from '@app/_components/list/list-col-definition'; | ||||
| import { SearchSelectComponent } from '@app/_components/search-select/search-select.component'; | import { SearchSelectComponent } from '@app/_components/search-select/search-select.component'; | ||||
| @@ -18,6 +26,8 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||||
| protected trip!: TripJsonld; | protected trip!: TripJsonld; | ||||
| protected readonly FormMode = FormMode; | protected readonly FormMode = FormMode; | ||||
| protected tripLocations: TripLocationJsonld[] = []; | protected tripLocations: TripLocationJsonld[] = []; | ||||
| protected userTrips: UserTripJsonld[] = []; | |||||
| protected users: UserJsonld[] = []; | |||||
| protected locationForms: FormGroup[] = []; | protected locationForms: FormGroup[] = []; | ||||
| protected locationColDefinitions: ListColDefinition[] = SearchSelectComponent.getDefaultColDefLocations(); | protected locationColDefinitions: ListColDefinition[] = SearchSelectComponent.getDefaultColDefLocations(); | ||||
| @@ -27,6 +37,8 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||||
| private tripService: TripService, | private tripService: TripService, | ||||
| private tripLocationService: TripLocationService, | private tripLocationService: TripLocationService, | ||||
| private locationService: LocationService, | private locationService: LocationService, | ||||
| private userTripService: UserTripService, | |||||
| private userService: UserService, | |||||
| protected appHelperService: AppHelperService, | protected appHelperService: AppHelperService, | ||||
| private route: ActivatedRoute, | private route: ActivatedRoute, | ||||
| private fb: FormBuilder | private fb: FormBuilder | ||||
| @@ -38,6 +50,13 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||||
| data => { | data => { | ||||
| this.trip = data; | this.trip = data; | ||||
| this.loadTripLocations(); | this.loadTripLocations(); | ||||
| this.userTripService.userTripsGetCollection( | |||||
| ).subscribe( | |||||
| data => { | |||||
| this.userTrips = data.member; | |||||
| console.log(this.userTrips); | |||||
| } | |||||
| ) | |||||
| } | } | ||||
| ); | ); | ||||
| }); | }); | ||||
| @@ -195,13 +214,13 @@ export class TripDetailComponent implements OnInit, AfterViewInit { | |||||
| const savePromises = validTripLocations.map(tripLocation => { | const savePromises = validTripLocations.map(tripLocation => { | ||||
| if (tripLocation.id) { | if (tripLocation.id) { | ||||
| // Update existing | // Update existing | ||||
| return this.tripLocationService.tripLocationsIdPatch( | |||||
| return firstValueFrom(this.tripLocationService.tripLocationsIdPatch( | |||||
| this.appHelperService.extractId(tripLocation.id), | this.appHelperService.extractId(tripLocation.id), | ||||
| tripLocation | tripLocation | ||||
| ).toPromise(); | |||||
| )); | |||||
| } else { | } else { | ||||
| // Create new | // Create new | ||||
| return this.tripLocationService.tripLocationsPost(tripLocation).toPromise(); | |||||
| return firstValueFrom(this.tripLocationService.tripLocationsPost(tripLocation)); | |||||
| } | } | ||||
| }); | }); | ||||
| @@ -1,20 +1,15 @@ | |||||
| import { Component } from '@angular/core'; | import { Component } from '@angular/core'; | ||||
| import { | import { | ||||
| AbstractDataFormComponent, DeleteFunction, | |||||
| SaveFunction, | |||||
| UpdateFunction | |||||
| AbstractDataFormComponent | |||||
| } from "@app/_components/_abstract/abstract-data-form-component"; | } from "@app/_components/_abstract/abstract-data-form-component"; | ||||
| import { | import { | ||||
| LocationJsonld, LocationService, | |||||
| ShippingCompanyService, | |||||
| LocationService, | |||||
| TripJsonld, | TripJsonld, | ||||
| TripService, | TripService, | ||||
| VesselJsonld, | |||||
| VesselService | VesselService | ||||
| } from "@app/core/api/v1"; | } from "@app/core/api/v1"; | ||||
| import {SearchSelectComponent} from "@app/_components/search-select/search-select.component"; | import {SearchSelectComponent} from "@app/_components/search-select/search-select.component"; | ||||
| import {tripForm, vesselForm} from "@app/_forms/apiForms"; | |||||
| import {FormGroup} from "@angular/forms"; | |||||
| import {tripForm} from "@app/_forms/apiForms"; | |||||
| import {TranslateService} from "@ngx-translate/core"; | import {TranslateService} from "@ngx-translate/core"; | ||||
| import {Router} from "@angular/router"; | import {Router} from "@angular/router"; | ||||
| import {ROUTE_BASE_DATA} from "@app/app-routing.module"; | import {ROUTE_BASE_DATA} from "@app/app-routing.module"; | ||||
| @@ -1 +0,0 @@ | |||||
| <p>user-trip-form works!</p> | |||||
| @@ -1,23 +0,0 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { UserTripFormComponent } from './user-trip-form.component'; | |||||
| describe('UserTripFormComponent', () => { | |||||
| let component: UserTripFormComponent; | |||||
| let fixture: ComponentFixture<UserTripFormComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [UserTripFormComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(UserTripFormComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -1,10 +0,0 @@ | |||||
| import { Component } from '@angular/core'; | |||||
| @Component({ | |||||
| selector: 'app-user-trip-form', | |||||
| templateUrl: './user-trip-form.component.html', | |||||
| styleUrl: './user-trip-form.component.scss' | |||||
| }) | |||||
| export class UserTripFormComponent { | |||||
| } | |||||
| @@ -1 +1,7 @@ | |||||
| <p>user-trip-list works!</p> | |||||
| <div class="spt-container"> | |||||
| <app-list #listComponent | |||||
| [listId]="'userTripList'" | |||||
| [getDataFunction]="getData" | |||||
| [listColDefinitions]="listColDefinitions" | |||||
| ></app-list> | |||||
| </div> | |||||
| @@ -1,6 +1,5 @@ | |||||
| import {Component, ViewChild} from '@angular/core'; | import {Component, ViewChild} from '@angular/core'; | ||||
| import {ListComponent} from "@app/_components/list/list.component"; | import {ListComponent} from "@app/_components/list/list.component"; | ||||
| import {TripFormComponent} from "@app/_views/trip/trip-form/trip-form.component"; | |||||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | import {ListColDefinition} from "@app/_components/list/list-col-definition"; | ||||
| import {UserTripService} from "@app/core/api/v1"; | import {UserTripService} from "@app/core/api/v1"; | ||||
| import {AppHelperService} from "@app/_helpers/app-helper.service"; | import {AppHelperService} from "@app/_helpers/app-helper.service"; | ||||
| @@ -16,7 +15,6 @@ export class UserTripListComponent { | |||||
| @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | ||||
| protected readonly tripFormComponent = TripFormComponent; | |||||
| protected listColDefinitions!: ListColDefinition[]; | protected listColDefinitions!: ListColDefinition[]; | ||||
| constructor( | constructor( | ||||
| @@ -2,5 +2,5 @@ | |||||
| <div class="spt-headline d-flex justify-content-between align-items-start"> | <div class="spt-headline d-flex justify-content-between align-items-start"> | ||||
| <h2>{{ 'user_trip.view' | translate }}</h2> | <h2>{{ 'user_trip.view' | translate }}</h2> | ||||
| </div> | </div> | ||||
| <app-trip-list></app-trip-list> | |||||
| <app-user-trip-list></app-user-trip-list> | |||||
| </div> | </div> | ||||
| @@ -16,6 +16,8 @@ import { | |||||
| } from "@app/_views/shipping-company/shipping-company-detail/shipping-company-detail.component"; | } from "@app/_views/shipping-company/shipping-company-detail/shipping-company-detail.component"; | ||||
| import {TripComponent} from "@app/_views/trip/trip.component"; | import {TripComponent} from "@app/_views/trip/trip.component"; | ||||
| import {TripDetailComponent} from "@app/_views/trip/trip-detail/trip-detail.component"; | import {TripDetailComponent} from "@app/_views/trip/trip-detail/trip-detail.component"; | ||||
| import {UserTripComponent} from "@app/_views/user-trip/user-trip.component"; | |||||
| import {UserTripDetailComponent} from "@app/_views/user-trip/user-trip-detail/user-trip-detail.component"; | |||||
| const accountModule = () => import('@app/_views/account/account.module').then(x => x.AccountModule); | const accountModule = () => import('@app/_views/account/account.module').then(x => x.AccountModule); | ||||
| @@ -24,6 +26,7 @@ export const ROUTE_BASE_DATA = 'base-data'; | |||||
| export const ROUTE_LOCATIONS = 'locations'; | export const ROUTE_LOCATIONS = 'locations'; | ||||
| export const ROUTE_SHIPPING_COMPANIES = 'shipping-companies'; | export const ROUTE_SHIPPING_COMPANIES = 'shipping-companies'; | ||||
| export const ROUTE_TRIPS = 'trips'; | export const ROUTE_TRIPS = 'trips'; | ||||
| export const ROUTE_USER_TRIPS = 'user-trips'; | |||||
| export const ROUTE_PROFILE = 'profile'; | export const ROUTE_PROFILE = 'profile'; | ||||
| export const ROUTE_USERS = 'users'; | export const ROUTE_USERS = 'users'; | ||||
| export const ROUTE_VESSELS = 'vessels'; | export const ROUTE_VESSELS = 'vessels'; | ||||
| @@ -75,6 +78,22 @@ const routes: Routes = [ | |||||
| {path: ':id', component: TripDetailComponent}, | {path: ':id', component: TripDetailComponent}, | ||||
| ] | ] | ||||
| }, | }, | ||||
| { | |||||
| path: ROUTE_USER_TRIPS, | |||||
| component: TwoColumnComponent, | |||||
| canActivate: [userGuard], | |||||
| children: [ | |||||
| {path: '', component: UserTripComponent}, | |||||
| ] | |||||
| }, | |||||
| { | |||||
| path: ROUTE_USER_TRIPS, | |||||
| component: TwoColumnComponent, | |||||
| canActivate: [userGuard], | |||||
| children: [ | |||||
| {path: ':id', component: UserTripDetailComponent}, | |||||
| ] | |||||
| }, | |||||
| { | { | ||||
| path: ROUTE_ZONES, | path: ROUTE_ZONES, | ||||
| component: TwoColumnComponent, | component: TwoColumnComponent, | ||||
| @@ -66,7 +66,6 @@ import {DatetimePickerComponent} from "@app/_components/datetime-picker/datetime | |||||
| import { UserTripComponent } from './_views/user-trip/user-trip.component'; | import { UserTripComponent } from './_views/user-trip/user-trip.component'; | ||||
| import { UserTripListComponent } from './_views/user-trip/user-trip-list/user-trip-list.component'; | import { UserTripListComponent } from './_views/user-trip/user-trip-list/user-trip-list.component'; | ||||
| import { UserTripDetailComponent } from './_views/user-trip/user-trip-detail/user-trip-detail.component'; | import { UserTripDetailComponent } from './_views/user-trip/user-trip-detail/user-trip-detail.component'; | ||||
| import { UserTripFormComponent } from './_views/user-trip/user-trip-form/user-trip-form.component'; | |||||
| registerLocaleData(localeDe, 'de-DE'); | registerLocaleData(localeDe, 'de-DE'); | ||||
| @@ -158,7 +157,6 @@ export function HttpLoaderFactory(http: HttpClient) { | |||||
| UserTripComponent, | UserTripComponent, | ||||
| UserTripListComponent, | UserTripListComponent, | ||||
| UserTripDetailComponent, | UserTripDetailComponent, | ||||
| UserTripFormComponent, | |||||
| ], | ], | ||||
| providers: [ | providers: [ | ||||
| {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | ||||
| @@ -21,8 +21,8 @@ export interface UserTrip { | |||||
| trip?: Trip; | trip?: Trip; | ||||
| user?: User; | user?: User; | ||||
| captainName: string; | captainName: string; | ||||
| startDate: string; | |||||
| endDate: string; | |||||
| readonly signatureUrl?: string | null; | |||||
| completedDate: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -25,8 +25,8 @@ export interface UserTripJsonld { | |||||
| trip?: TripJsonld; | trip?: TripJsonld; | ||||
| user?: UserJsonld; | user?: UserJsonld; | ||||
| captainName: string; | captainName: string; | ||||
| startDate: string; | |||||
| endDate: string; | |||||
| readonly signatureUrl?: string | null; | |||||
| completedDate: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -27,7 +27,13 @@ | |||||
| "end_location": "End location", | "end_location": "End location", | ||||
| "start_date": "Start date", | "start_date": "Start date", | ||||
| "end_date": "End date", | "end_date": "End date", | ||||
| "itinerary": "Itinerary" | |||||
| "is_arrival": "is arrival", | |||||
| "itinerary": "Itinerary", | |||||
| "itinerary_locations": "Itinerary locations", | |||||
| "add_itinerary_location": "Add itinerary location", | |||||
| "remove_itinerary_location": "Remove itinerary location", | |||||
| "save_itinerary": "Save itinerary", | |||||
| "assigned_users": "Assigned Users (User Trips)" | |||||
| }, | }, | ||||
| "user_trip": | "user_trip": | ||||
| { | { | ||||
| @@ -0,0 +1,35 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace DoctrineMigrations; | |||||
| use Doctrine\DBAL\Schema\Schema; | |||||
| use Doctrine\Migrations\AbstractMigration; | |||||
| /** | |||||
| * Auto-generated Migration: Please modify to your needs! | |||||
| */ | |||||
| final class Version20250310140210 extends AbstractMigration | |||||
| { | |||||
| public function getDescription(): string | |||||
| { | |||||
| return ''; | |||||
| } | |||||
| public function up(Schema $schema): void | |||||
| { | |||||
| // this up() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE user_trip ADD signature_id INT DEFAULT NULL, ADD completed_date DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', DROP start_date, DROP end_date'); | |||||
| $this->addSql('ALTER TABLE user_trip ADD CONSTRAINT FK_CD7B9F2ED61183A FOREIGN KEY (signature_id) REFERENCES media_object (id) ON DELETE SET NULL'); | |||||
| $this->addSql('CREATE INDEX IDX_CD7B9F2ED61183A ON user_trip (signature_id)'); | |||||
| } | |||||
| public function down(Schema $schema): void | |||||
| { | |||||
| // this down() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE user_trip DROP FOREIGN KEY FK_CD7B9F2ED61183A'); | |||||
| $this->addSql('DROP INDEX IDX_CD7B9F2ED61183A ON user_trip'); | |||||
| $this->addSql('ALTER TABLE user_trip ADD end_date DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', DROP signature_id, CHANGE completed_date start_date DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\''); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace DoctrineMigrations; | |||||
| use Doctrine\DBAL\Schema\Schema; | |||||
| use Doctrine\Migrations\AbstractMigration; | |||||
| /** | |||||
| * Auto-generated Migration: Please modify to your needs! | |||||
| */ | |||||
| final class Version20250310141546 extends AbstractMigration | |||||
| { | |||||
| public function getDescription(): string | |||||
| { | |||||
| return ''; | |||||
| } | |||||
| public function up(Schema $schema): void | |||||
| { | |||||
| // this up() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('CREATE UNIQUE INDEX unique_user_trip ON user_trip (trip_id, user_id)'); | |||||
| } | |||||
| public function down(Schema $schema): void | |||||
| { | |||||
| // this down() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('DROP INDEX unique_user_trip ON user_trip'); | |||||
| } | |||||
| } | |||||
| @@ -94,11 +94,11 @@ class UserTripApi | |||||
| #[Assert\NotBlank] | #[Assert\NotBlank] | ||||
| public string $captainName; | public string $captainName; | ||||
| #[Assert\NotBlank] | |||||
| public \DateTimeImmutable $startDate; | |||||
| #[ApiProperty(writable: false)] | |||||
| public ?string $signatureUrl = null; | |||||
| #[Assert\NotBlank] | #[Assert\NotBlank] | ||||
| public \DateTimeImmutable $endDate; | |||||
| public \DateTimeImmutable $completedDate; | |||||
| #[ApiProperty(writable: false)] | #[ApiProperty(writable: false)] | ||||
| public ?\DateTimeImmutable $createdAt = null; | public ?\DateTimeImmutable $createdAt = null; | ||||
| @@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping as ORM; | |||||
| #[ORM\Entity] | #[ORM\Entity] | ||||
| #[ORM\Table(name: 'user_trip')] | #[ORM\Table(name: 'user_trip')] | ||||
| #[ORM\UniqueConstraint(name: "unique_user_trip", columns: ["trip_id", "user_id"])] | |||||
| class UserTrip | class UserTrip | ||||
| { | { | ||||
| #[ORM\Id] | #[ORM\Id] | ||||
| @@ -29,11 +30,12 @@ class UserTrip | |||||
| #[ORM\Column(length: 255)] | #[ORM\Column(length: 255)] | ||||
| private string $captainName; | private string $captainName; | ||||
| #[ORM\Column] | |||||
| private DateTimeImmutable $startDate; | |||||
| #[ORM\ManyToOne] | |||||
| #[ORM\JoinColumn(nullable: true, onDelete: "SET NULL")] | |||||
| private ?MediaObject $signature = null; | |||||
| #[ORM\Column] | #[ORM\Column] | ||||
| private DateTimeImmutable $endDate; | |||||
| private DateTimeImmutable $completedDate; | |||||
| #[ORM\Column] | #[ORM\Column] | ||||
| private DateTimeImmutable $createdAt; | private DateTimeImmutable $createdAt; | ||||
| @@ -51,8 +53,7 @@ class UserTrip | |||||
| $this->trip = $trip; | $this->trip = $trip; | ||||
| $this->user = $user; | $this->user = $user; | ||||
| $this->captainName = $captainName; | $this->captainName = $captainName; | ||||
| $this->startDate = $startDate; | |||||
| $this->endDate = $endDate; | |||||
| $this->completedDate = $endDate; | |||||
| $this->createdAt = new DateTimeImmutable(); | $this->createdAt = new DateTimeImmutable(); | ||||
| $this->userTripEvents = new ArrayCollection(); | $this->userTripEvents = new ArrayCollection(); | ||||
| } | } | ||||
| @@ -95,25 +96,24 @@ class UserTrip | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getStartDate(): DateTimeImmutable | |||||
| public function getSignature(): ?MediaObject | |||||
| { | { | ||||
| return $this->startDate; | |||||
| return $this->signature; | |||||
| } | } | ||||
| public function setStartDate(DateTimeImmutable $startDate): self | |||||
| public function setSignature(?MediaObject $signature): void | |||||
| { | { | ||||
| $this->startDate = $startDate; | |||||
| return $this; | |||||
| $this->signature = $signature; | |||||
| } | } | ||||
| public function getEndDate(): DateTimeImmutable | |||||
| public function getCompletedDate(): DateTimeImmutable | |||||
| { | { | ||||
| return $this->endDate; | |||||
| return $this->completedDate; | |||||
| } | } | ||||
| public function setEndDate(DateTimeImmutable $endDate): self | |||||
| public function setCompletedDate(DateTimeImmutable $completedDate): self | |||||
| { | { | ||||
| $this->endDate = $endDate; | |||||
| $this->completedDate = $completedDate; | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| @@ -67,7 +67,7 @@ class UserTripApiToEntityMapper implements MapperInterface | |||||
| $entity->setCaptainName($dto->captainName); | $entity->setCaptainName($dto->captainName); | ||||
| $entity->setStartDate($dto->startDate); | $entity->setStartDate($dto->startDate); | ||||
| $entity->setEndDate($dto->endDate); | |||||
| $entity->setCompletedDate($dto->endDate); | |||||
| return $entity; | return $entity; | ||||
| } | } | ||||
| @@ -6,6 +6,7 @@ use App\ApiResource\TripApi; | |||||
| use App\ApiResource\UserApi; | use App\ApiResource\UserApi; | ||||
| use App\ApiResource\UserTripApi; | use App\ApiResource\UserTripApi; | ||||
| use App\Entity\UserTrip; | use App\Entity\UserTrip; | ||||
| use App\Service\FileUrlService; | |||||
| use Symfonycasts\MicroMapper\AsMapper; | use Symfonycasts\MicroMapper\AsMapper; | ||||
| use Symfonycasts\MicroMapper\MapperInterface; | use Symfonycasts\MicroMapper\MapperInterface; | ||||
| use Symfonycasts\MicroMapper\MicroMapperInterface; | use Symfonycasts\MicroMapper\MicroMapperInterface; | ||||
| @@ -14,7 +15,8 @@ use Symfonycasts\MicroMapper\MicroMapperInterface; | |||||
| class UserTripEntityToApiMapper implements MapperInterface | class UserTripEntityToApiMapper implements MapperInterface | ||||
| { | { | ||||
| public function __construct( | public function __construct( | ||||
| private MicroMapperInterface $microMapper | |||||
| private MicroMapperInterface $microMapper, | |||||
| private FileUrlService $fileUrlService | |||||
| ) { | ) { | ||||
| } | } | ||||
| @@ -38,8 +40,8 @@ class UserTripEntityToApiMapper implements MapperInterface | |||||
| $dto->dbId = $entity->getId(); | $dto->dbId = $entity->getId(); | ||||
| $dto->captainName = $entity->getCaptainName(); | $dto->captainName = $entity->getCaptainName(); | ||||
| $dto->startDate = $entity->getStartDate(); | |||||
| $dto->endDate = $entity->getEndDate(); | |||||
| $dto->signatureUrl = $this->fileUrlService->getFileUrl($entity->getSignature()); | |||||
| $dto->completedDate = $entity->getCompletedDate(); | |||||
| $dto->createdAt = $entity->getCreatedAt(); | $dto->createdAt = $entity->getCreatedAt(); | ||||
| $dto->trip = $this->microMapper->map($entity->getTrip(), TripApi::class, [ | $dto->trip = $this->microMapper->map($entity->getTrip(), TripApi::class, [ | ||||