Daniel 1年前
コミット
a21be9ec55
4個のファイルの変更159行の追加13行の削除
  1. +34
    -0
      angular/src/app/_views/trip/trip-detail/trip-detail.component.html
  2. +121
    -7
      angular/src/app/_views/trip/trip-detail/trip-detail.component.ts
  3. +3
    -4
      httpdocs/src/Entity/UserTrip.php
  4. +1
    -2
      httpdocs/src/Mapper/UserTripApiToEntityMapper.php

+ 34
- 0
angular/src/app/_views/trip/trip-detail/trip-detail.component.html ファイルの表示

@@ -90,7 +90,41 @@
</div>
</mat-tab>
<mat-tab label="{{ 'trip.assigned_users' | translate }}">
<div>
<h4 class="mb-4">{{ 'trip.user_assignments' | translate }}</h4>

<div *ngFor="let userTrip of userTrips; let i = index" class="mb-4">
<div class="row">
<div class="col-12 col-md-6 mb-3">
<label [for]="'user_' + i" class="form-label">{{ 'model.user' | translate }}*:</label>
<app-search-select
[formId]="'user'"
[formLabelLangKey]="'model.user'"
[documentForm]="userForms[i]"
[getDataFunction]="getUsers"
[displayedDataField]="'fullName'"
[listColDefinitions]="userColDefinitions"
[dataSet]="userTrip.user"
>
</app-search-select>
</div>

<div class="col-12 col-md-2 mb-3 d-flex align-items-end">
<button type="button" class="btn btn-danger" (click)="removeUserTrip(i)">X</button>
</div>
</div>
</div>

<div class="my-3">
<button type="button" class="btn btn-primary" (click)="addNewUserTrip()">+</button>
</div>

<div class="mt-4">
<button type="button" class="btn btn-success" (click)="saveAllUserTrips()">
{{ 'trip.save_user_assignments' | translate }}
</button>
</div>
</div>
</mat-tab>
</mat-tab-group>


+ 121
- 7
angular/src/app/_views/trip/trip-detail/trip-detail.component.ts ファイルの表示

@@ -30,6 +30,8 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
protected users: UserJsonld[] = [];
protected locationForms: FormGroup[] = [];
protected locationColDefinitions: ListColDefinition[] = SearchSelectComponent.getDefaultColDefLocations();
protected userForms: FormGroup[] = [];
protected userColDefinitions: ListColDefinition[] = SearchSelectComponent.getDefaultColDefUsers();

@ViewChildren(SearchSelectComponent) searchSelects!: QueryList<SearchSelectComponent>;

@@ -50,13 +52,7 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
data => {
this.trip = data;
this.loadTripLocations();
this.userTripService.userTripsGetCollection(
).subscribe(
data => {
this.userTrips = data.member;
console.log(this.userTrips);
}
)
this.loadUserTrips(); // Verwenden Sie die neue loadUserTrips-Methode
}
);
});
@@ -97,10 +93,20 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
});
}

createUserForm(): FormGroup {
return this.fb.group({
user: [null]
});
}

getLocations = (page: number, pageSize: number, term?: string): Observable<any> => {
return this.locationService.locationsGetCollection(page, pageSize, undefined, term);
}

getUsers = (page: number, pageSize: number, term?: string): Observable<any> => {
return this.userService.usersGetCollection(page, pageSize, undefined, term);
}

onFormUpdate(event: FormSubmitEvent<TripJsonld>) {
if (event.status === ModalStatus.Submitted && event.data) {
this.trip = event.data;
@@ -166,6 +172,46 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
});
}

addNewUserTrip() {
// Create a new empty user trip
const newUserTrip: UserTripJsonld = {
trip: {
'id': this.trip.id
} as TripJsonld,
// No default user set
};

this.userTrips.push(newUserTrip);
this.userForms.push(this.createUserForm());

// Force update in the next event loop to properly initialize the search-select
setTimeout(() => {
if (this.searchSelects) {
const lastSelect = this.searchSelects.last;
if (lastSelect) {
lastSelect.ngAfterViewInit();
}
}
});
}

loadUserTrips() {
this.userTripService.userTripsGetCollection(
1,
200,
this.trip !== undefined ? this.trip.id : undefined,
).subscribe(
data => {
this.userTrips = data.member;
// Create a form for each user trip
this.userForms = [];
this.userTrips.forEach(() => {
this.userForms.push(this.createUserForm());
});
}
);
}

removeTripLocation(index: number) {
const tripLocationId = this.tripLocations[index].id;

@@ -184,6 +230,24 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
}
}

removeUserTrip(index: number) {
const userTripId = this.userTrips[index].id;

if (userTripId) {
// If it exists on the server, delete it
this.userTripService.userTripsIdDelete(this.appHelperService.extractId(userTripId)).subscribe(
() => {
this.userTrips.splice(index, 1);
this.userForms.splice(index, 1);
}
);
} else {
// If it's only local, just remove it from the array
this.userTrips.splice(index, 1);
this.userForms.splice(index, 1);
}
}

saveAllTripLocations() {
// First update the location objects in our tripLocations array
this.tripLocations.forEach((tripLocation, index) => {
@@ -233,4 +297,54 @@ export class TripDetailComponent implements OnInit, AfterViewInit {
console.error('Error saving trip locations:', error);
});
}

saveAllUserTrips() {
// First update the user objects in our userTrips array
this.userTrips.forEach((userTrip, index) => {
const userFormValue = this.userForms[index].get('user')?.value;

// Ensure we have a user
if (userFormValue) {
// If just an ID was set, create a proper user object
if (typeof userFormValue === 'string') {
userTrip.user = {
'id': userFormValue
} as UserJsonld;
}
} else {
// If no user is set, show an error
return;
}
});

// Filter out user trips that have no user set
const validUserTrips = this.userTrips.filter(ut => ut.user);

if (validUserTrips.length === 0) {
return;
}

// Save all user trips
const savePromises = validUserTrips.map(userTrip => {
if (userTrip.id) {
// Update existing
return firstValueFrom(this.userTripService.userTripsIdPatch(
this.appHelperService.extractId(userTrip.id),
userTrip
));
} else {
// Create new
return firstValueFrom(this.userTripService.userTripsPost(userTrip));
}
});

Promise.all(savePromises)
.then(() => {
// Reload user trips to get updated data
this.loadUserTrips();
})
.catch(error => {
console.error('Error saving user trips:', error);
});
}
}

+ 3
- 4
httpdocs/src/Entity/UserTrip.php ファイルの表示

@@ -35,7 +35,7 @@ class UserTrip
private ?MediaObject $signature = null;

#[ORM\Column(nullable: true)]
private DateTimeImmutable $completedDate;
private ?DateTimeImmutable $completedDate;

#[ORM\Column]
private DateTimeImmutable $createdAt;
@@ -100,15 +100,14 @@ class UserTrip
$this->signature = $signature;
}

public function getCompletedDate(): DateTimeImmutable
public function getCompletedDate(): ?DateTimeImmutable
{
return $this->completedDate;
}

public function setCompletedDate(DateTimeImmutable $completedDate): self
public function setCompletedDate(?DateTimeImmutable $completedDate): void
{
$this->completedDate = $completedDate;
return $this;
}

public function getUserTripEvents(): Collection


+ 1
- 2
httpdocs/src/Mapper/UserTripApiToEntityMapper.php ファイルの表示

@@ -63,8 +63,7 @@ class UserTripApiToEntityMapper implements MapperInterface
assert($entity instanceof UserTrip);

$entity->setCaptainName($dto->captainName);
$entity->setStartDate($dto->startDate);
$entity->setCompletedDate($dto->endDate);
$entity->setCompletedDate($dto->completedDate);

return $entity;
}

読み込み中…
キャンセル
保存