Add support for trainings and small fixes
This commit is contained in:
parent
3f7be4beb8
commit
1f61d2e96a
|
@ -118,7 +118,7 @@ class ServiceController extends Controller
|
|||
$service->chief()->associate($request->chief);
|
||||
$service->type()->associate($request->type);
|
||||
$service->notes = $request->notes;
|
||||
$service->start = $request->start/1000; //TODO: fix client-side
|
||||
$service->start = $request->start/1000;
|
||||
$service->end = $request->end/1000;
|
||||
$service->place()->associate($place);
|
||||
$service->addedBy()->associate($request->user());
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Training;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Utils\Logger;
|
||||
|
||||
class TrainingController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
User::where('id', $request->user()->id)->update(['last_access' => now()]);
|
||||
|
||||
return response()->json(
|
||||
Training::join('users', 'users.id', '=', 'chief_id')
|
||||
->select('trainings.*', 'users.name as chief')
|
||||
->with('crew:name')
|
||||
->orderBy('start', 'desc')
|
||||
->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single Training
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
User::where('id', $request->user()->id)->update(['last_access' => now()]);
|
||||
|
||||
return response()->json(
|
||||
Training::join('users', 'users.id', '=', 'chief_id')
|
||||
->select('trainings.*', 'users.name as chief')
|
||||
->with('crew:name')
|
||||
->find($id)
|
||||
);
|
||||
}
|
||||
|
||||
private function extractTrainingUsers($training)
|
||||
{
|
||||
$usersList = [$training->chief_id];
|
||||
foreach($training->crew as $crew) {
|
||||
$usersList[] = $crew->id;
|
||||
}
|
||||
return array_unique($usersList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update Training.
|
||||
*/
|
||||
public function createOrUpdate(Request $request)
|
||||
{
|
||||
$adding = !isset($request->id) || is_null($request->id);
|
||||
|
||||
$training = $adding ? new Training() : Training::where("id",$request->id)->with('crew')->first();
|
||||
|
||||
if(is_null($training)) abort(404);
|
||||
|
||||
if(!$adding) {
|
||||
$usersToDecrement = $this->extractTrainingUsers($training);
|
||||
User::whereIn('id', $usersToDecrement)->decrement('trainings');
|
||||
|
||||
$training->crew()->detach();
|
||||
$training->save();
|
||||
}
|
||||
|
||||
$training->name = $request->name;
|
||||
$training->chief()->associate($request->chief);
|
||||
$training->notes = $request->notes;
|
||||
$training->start = $request->start/1000;
|
||||
$training->end = $request->end/1000;
|
||||
$training->place = $request->place;
|
||||
$training->addedBy()->associate($request->user());
|
||||
$training->updatedBy()->associate($request->user());
|
||||
$training->save();
|
||||
|
||||
$training->crew()->attach(array_unique($request->crew));
|
||||
$training->save();
|
||||
|
||||
$usersToIncrement = array_unique(array_merge(
|
||||
[$request->chief],
|
||||
$request->crew
|
||||
));
|
||||
User::whereIn('id', $usersToIncrement)->increment('trainings');
|
||||
|
||||
Logger::log($adding ? "Esercitazione aggiunta" : "Esercitazione modificata");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$training = Training::find($id);
|
||||
$usersToDecrement = $this->extractTrainingUsers($training);
|
||||
User::whereIn('id', $usersToDecrement)->decrement('trainings');
|
||||
$training->delete();
|
||||
Logger::log("Esercitazione eliminata");
|
||||
}
|
||||
}
|
|
@ -82,12 +82,4 @@ class Service extends Model
|
|||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that added the service.
|
||||
*/
|
||||
public function deletedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Training extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'place',
|
||||
'notes'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'start' => 'datetime',
|
||||
'end' => 'datetime'
|
||||
];
|
||||
|
||||
public function chief(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function crew(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
User::class,
|
||||
'trainings_crew',
|
||||
'training_id',
|
||||
'user_id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that added the service.
|
||||
*/
|
||||
public function addedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that added the service.
|
||||
*/
|
||||
public function updatedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
|
@ -51,7 +51,6 @@ return new class extends Migration
|
|||
$table->dateTime('end');
|
||||
$table->foreignId('added_by_id')->constrained('users');
|
||||
$table->foreignId('updated_by_id')->constrained('users');
|
||||
$table->foreignId('deleted_by_id')->nullable()->constrained('users');
|
||||
$table->softDeletes();
|
||||
$table->unique(['code']);
|
||||
$table->timestamps();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('trainings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->dateTime('start');
|
||||
$table->dateTime('end');
|
||||
$table->foreignId('chief_id')->constrained('users');
|
||||
$table->string('place');
|
||||
$table->string('notes')->nullable();
|
||||
$table->foreignId('added_by_id')->constrained('users');
|
||||
$table->foreignId('updated_by_id')->constrained('users');
|
||||
$table->unique(['name']);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('trainings_crew', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('user_id')->unsigned();
|
||||
$table->foreign('user_id')
|
||||
->references('id')
|
||||
->on('users')->onDelete('cascade');
|
||||
$table->unsignedBigInteger('training_id')->unsigned();
|
||||
$table->foreign('training_id')
|
||||
->references('id')
|
||||
->on('trainings')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('trainings');
|
||||
}
|
||||
};
|
|
@ -10,6 +10,7 @@ use App\Http\Controllers\TelegramController;
|
|||
use App\Http\Controllers\ServiceController;
|
||||
use App\Http\Controllers\PlacesController;
|
||||
use App\Http\Controllers\ServiceTypeController;
|
||||
use App\Http\Controllers\TrainingController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
|
@ -53,6 +54,11 @@ Route::middleware('auth:sanctum')->group( function () {
|
|||
Route::get('/places/search', [PlacesController::class, 'search']);
|
||||
Route::get('/places/{id}', [PlacesController::class, 'show']);
|
||||
|
||||
Route::get('/trainings', [TrainingController::class, 'index']);
|
||||
Route::post('/trainings', [TrainingController::class, 'createOrUpdate']);
|
||||
Route::get('/trainings/{id}', [TrainingController::class, 'show']);
|
||||
Route::delete('/trainings/{id}', [TrainingController::class, 'destroy']);
|
||||
|
||||
Route::get('/logs', [LogsController::class, 'index']);
|
||||
|
||||
Route::post('/telegram_login_token', [TelegramController::class, 'loginToken']);
|
||||
|
|
|
@ -129,14 +129,14 @@
|
|||
<tr *ngFor="let row of displayedData; index as i">
|
||||
<td>{{ data.length - (rowsPerPage * (currentPage-1) + i) }}</td>
|
||||
<td>{{ row.name }}</td>
|
||||
<td>{{ row.beginning }}</td>
|
||||
<td>{{ row.end }}</td>
|
||||
<td>{{ row.start | date:'dd/MM/YYYY, HH:mm' }}</td>
|
||||
<td>{{ row.end | date:'dd/MM/YYYY, HH:mm' }}</td>
|
||||
<td>{{ row.chief }}</td>
|
||||
<td>{{ row.crew }}</td>
|
||||
<td>{{ extractNamesFromObject(row.crew).join(', ') }}</td>
|
||||
<td>{{ row.place }}</td>
|
||||
<td>{{ row.notes }}</td>
|
||||
<td><i class="fa fa-edit"></i></td>
|
||||
<td><i class="fa fa-trash"></i></td>
|
||||
<td (click)="editTraining(row.id)"><i class="fa fa-edit"></i></td>
|
||||
<td (click)="deleteTraining(row.id)"><i class="fa fa-trash"></i></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -215,6 +215,38 @@ export class TableComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
editTraining(id: number) {
|
||||
this.router.navigate(['/trainings', id]);
|
||||
}
|
||||
|
||||
deleteTraining(id: number) {
|
||||
this.translate.get(['table.yes_remove', 'table.cancel', 'table.remove_training_confirm', 'table.remove_training_text']).subscribe((res: { [key: string]: string; }) => {
|
||||
Swal.fire({
|
||||
title: res['table.remove_training_confirm'],
|
||||
text: res['table.remove_training_confirm_text'],
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: res['table.yes_remove'],
|
||||
cancelButtonText: res['table.cancel']
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
this.api.delete(`trainings/${id}`).then((response) => {
|
||||
this.translate.get('table.training_deleted_successfully').subscribe((res: string) => {
|
||||
this.toastr.success(res);
|
||||
});
|
||||
this.loadTableData();
|
||||
}).catch((e) => {
|
||||
this.translate.get('table.training_deleted_error').subscribe((res: string) => {
|
||||
this.toastr.error(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
extractNamesFromObject(obj: any) {
|
||||
return obj.flatMap((e: any) => e.name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { EditTrainingComponent } from './edit-training.component';
|
||||
|
||||
const routes: Routes = [{ path: '', component: EditTrainingComponent }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class EditTrainingRoutingModule { }
|
|
@ -0,0 +1,73 @@
|
|||
<back-btn></back-btn>
|
||||
<br>
|
||||
<form method="post" [formGroup]="trainingForm" (ngSubmit)="formSubmit()">
|
||||
<div class="container">
|
||||
<div class="form-group has-validation">
|
||||
<label for="date-picker-start">{{ 'start'|translate|titlecase }}</label>
|
||||
<datetime-picker formControlName="start" [class.is-invalid]="!isFieldValid('start')" id="date-picker-start"></datetime-picker>
|
||||
<div class="invalid-feedback" *ngIf="start.errors?.['required']" translate>
|
||||
edit_training.select_start_datetime
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-validation">
|
||||
<label for="date-picker-end">{{ 'end'|translate|titlecase }}</label>
|
||||
<datetime-picker formControlName="end" [class.is-invalid]="!isFieldValid('end')" id="date-picker-end"></datetime-picker>
|
||||
<div class="invalid-feedback" *ngIf="end.errors?.['required']" translate>
|
||||
edit_training.select_end_datetime
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-validation">
|
||||
<label for="name">{{ 'name'|translate|titlecase }}</label>
|
||||
<input formControlName="name" [class.is-invalid]="!isFieldValid('name')" id="name" class="form-control"
|
||||
type="text" [placeholder]="'edit_training.name_placeholder'|translate">
|
||||
<div class="invalid-feedback" *ngIf="name.errors?.['required']" translate>
|
||||
edit_training.insert_name
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-validation" [class.is-invalid-div]="!isFieldValid('chief')">
|
||||
<label>{{ 'chief'|translate|titlecase }}</label>
|
||||
<br>
|
||||
<ng-container *ngFor="let user of users">
|
||||
<div class="form-check">
|
||||
<input formControlName="chief" [class.is-invalid]="!isFieldValid('chief')"
|
||||
class="form-check-input" id="chief-{{ user.id }}" type="radio" value='{{ user.id }}'>
|
||||
<label class="form-check-label" for="chief-{{ user.id }}">
|
||||
{{ user.name }}
|
||||
</label>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="form-group has-validation" [class.is-invalid-div]="!isFieldValid('crew')">
|
||||
<label translate>edit_training.other_crew_members</label>
|
||||
<br>
|
||||
<ng-container *ngFor="let user of users">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" id="crew-{{ user.id }}" [class.is-invalid]="!isFieldValid('crew')"
|
||||
(change)="onCrewCheckboxChange($event)" [checked]="isCrewSelected(user.id)" type="checkbox" value='{{ user.id }}'>
|
||||
<label class="form-check-label" for="crew-{{ user.id }}">
|
||||
{{ user.name }}
|
||||
</label>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="form-group has-validation">
|
||||
<label for="place">{{ 'place'|translate|titlecase }}</label>
|
||||
<input formControlName="place" [class.is-invalid]="!isFieldValid('place')" id="place" class="form-control"
|
||||
type="text">
|
||||
<div class="invalid-feedback" *ngIf="place.errors?.['required']" translate>
|
||||
edit_training.insert_place
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notes">{{ 'notes'|translate|titlecase }}</label><br>
|
||||
<textarea formControlName="notes" class="form-control" id="notes"></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="submit_button" type="submit" class="btn btn-primary" [disabled]="submittingForm">{{ 'submit'|translate|titlecase }}</button>
|
||||
<button class="btn" type="button" (click)="formReset()" [disabled]="submittingForm">{{ 'reset'|translate|titlecase }}</button>
|
||||
<div class="d-flex justify-content-center mt-2 pt-2 mb-3" *ngIf="submittingForm">
|
||||
<div class="spinner spinner-border"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,9 @@
|
|||
.form-group {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.form-check-input[type="checkbox"] {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.is-invalid-div {
|
||||
border: 1px solid #dc3545;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { ApiClientService } from 'src/app/_services/api-client.service';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-training',
|
||||
templateUrl: './edit-training.component.html',
|
||||
styleUrls: ['./edit-training.component.scss']
|
||||
})
|
||||
export class EditTrainingComponent implements OnInit {
|
||||
addingTraining = false;
|
||||
trainingId: string | undefined;
|
||||
loadedTraining = {
|
||||
start: '',
|
||||
end: '',
|
||||
name: '',
|
||||
chief: '',
|
||||
crew: [],
|
||||
place: '',
|
||||
notes: ''
|
||||
};
|
||||
|
||||
users: any[] = [];
|
||||
|
||||
trainingForm: any;
|
||||
private formSubmitAttempt: boolean = false;
|
||||
submittingForm = false;
|
||||
|
||||
get start() { return this.trainingForm.get('start'); }
|
||||
get end() { return this.trainingForm.get('end'); }
|
||||
get name() { return this.trainingForm.get('name'); }
|
||||
get chief() { return this.trainingForm.get('chief'); }
|
||||
get crew() { return this.trainingForm.get('crew'); }
|
||||
get place() { return this.trainingForm.get('place'); }
|
||||
|
||||
ngOnInit() {
|
||||
this.trainingForm = this.fb.group({
|
||||
start: [this.loadedTraining.start, [Validators.required]],
|
||||
end: [this.loadedTraining.end, [Validators.required]],
|
||||
name: [this.loadedTraining.name, [Validators.required, Validators.minLength(3)]],
|
||||
chief: [this.loadedTraining.chief, [Validators.required]],
|
||||
crew: [this.loadedTraining.crew, [Validators.required]],
|
||||
place: [this.loadedTraining.place, [Validators.required, Validators.minLength(3)]],
|
||||
notes: [this.loadedTraining.notes]
|
||||
});
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private api: ApiClientService,
|
||||
private toastr: ToastrService,
|
||||
private fb: UntypedFormBuilder,
|
||||
private translate: TranslateService
|
||||
) {
|
||||
this.route.paramMap.subscribe(params => {
|
||||
this.trainingId = params.get('id') || undefined;
|
||||
if (this.trainingId === "new") {
|
||||
this.addingTraining = true;
|
||||
} else {
|
||||
this.api.get(`trainings/${this.trainingId}`).then((training) => {
|
||||
this.loadedTraining = training;
|
||||
|
||||
this.chief.setValue(training.chief_id);
|
||||
|
||||
console.log(training);
|
||||
|
||||
let patch = Object.assign({}, training);
|
||||
patch.start = new Date(patch.start);
|
||||
patch.end = new Date(patch.end);
|
||||
patch.chief = patch.chief_id;
|
||||
patch.crew = patch.crew.map((e: any) => e.pivot.user_id+"");
|
||||
this.trainingForm.patchValue(patch);
|
||||
}).catch((err) => {
|
||||
this.toastr.error("Errore nel caricare l'esercitazione. Ricarica la pagina e riprova.");
|
||||
});
|
||||
}
|
||||
console.log(this.trainingId);
|
||||
});
|
||||
this.api.get("list").then((users) => {
|
||||
this.users = users;
|
||||
console.log(this.users);
|
||||
}).catch((err) => {
|
||||
this.toastr.error("Errore nel caricare la lista degli utenti. Ricarica la pagina e riprova.");
|
||||
});
|
||||
}
|
||||
|
||||
onCrewCheckboxChange(event: any) {
|
||||
if (event.target.checked) {
|
||||
this.crew.setValue([...this.crew.value, event.target.value]);
|
||||
} else {
|
||||
this.crew.setValue(this.crew.value.filter((x: number) => x !== event.target.value));
|
||||
}
|
||||
}
|
||||
isCrewSelected(id: number) {
|
||||
return this.crew.value.find((x: number) => x == id);
|
||||
}
|
||||
|
||||
//https://loiane.com/2017/08/angular-reactive-forms-trigger-validation-on-submit/
|
||||
isFieldValid(field: string) {
|
||||
return this.formSubmitAttempt ? this.trainingForm.get(field).valid : true;
|
||||
}
|
||||
|
||||
formSubmit() {
|
||||
console.log("form values", this.trainingForm.value);
|
||||
this.formSubmitAttempt = true;
|
||||
if (this.trainingForm.valid) {
|
||||
this.submittingForm = true;
|
||||
let values = Object.assign({}, this.trainingForm.value);
|
||||
values.start = values.start.getTime();
|
||||
values.end = values.end.getTime();
|
||||
console.log(values);
|
||||
if (this.trainingId !== "new") {
|
||||
values.id = this.trainingId;
|
||||
this.api.post("trainings", values).then((res) => {
|
||||
console.log(res);
|
||||
this.translate.get('edit_training.training_added_successfully').subscribe((res: string) => {
|
||||
this.toastr.success(res);
|
||||
});
|
||||
this.submittingForm = false;
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
this.translate.get('edit_training.training_add_failed').subscribe((res: string) => {
|
||||
this.toastr.error(res);
|
||||
});
|
||||
this.submittingForm = false;
|
||||
});
|
||||
} else {
|
||||
this.api.post("trainings", values).then((res) => {
|
||||
console.log(res);
|
||||
this.translate.get('edit_training.training_added_successfully').subscribe((res: string) => {
|
||||
this.toastr.success(res);
|
||||
});
|
||||
this.submittingForm = false;
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
this.translate.get('edit_training.training_add_failed').subscribe((res: string) => {
|
||||
this.toastr.error(res);
|
||||
});
|
||||
this.submittingForm = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formReset() {
|
||||
this.formSubmitAttempt = false;
|
||||
this.trainingForm.reset();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||
import { MapPickerModule } from '../../_components/map-picker/map-picker.module';
|
||||
import { DatetimePickerModule } from '../../_components/datetime-picker/datetime-picker.module';
|
||||
import { BackBtnModule } from '../../_components/back-btn/back-btn.module';
|
||||
import { TranslationModule } from '../../translation.module';
|
||||
|
||||
import { EditTrainingRoutingModule } from './edit-training-routing.module';
|
||||
import { EditTrainingComponent } from './edit-training.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
EditTrainingComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
EditTrainingRoutingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
BsDatepickerModule.forRoot(),
|
||||
MapPickerModule,
|
||||
DatetimePickerModule,
|
||||
BackBtnModule,
|
||||
TranslationModule
|
||||
]
|
||||
})
|
||||
export class EditTrainingModule { }
|
|
@ -1,8 +1,5 @@
|
|||
<owner-image></owner-image>
|
||||
<div *ngIf="false" class="text-center mb-4">
|
||||
<button type="button" class="btn btn-primary" disabled>{{ 'add'|translate|titlecase }} {{ 'training'|translate }}</button>
|
||||
</div>
|
||||
<app-table *ngIf="false" [sourceType]="'trainings'" [refreshInterval]="1200000"></app-table>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
Questa sezione di AllertaVVF è stata temporaneamente disabilitata per motivi di manutenzione. Ci scusiamo per il disagio.
|
||||
<div class="text-center mb-4">
|
||||
<button type="button" class="btn btn-primary" (click)="addTraining()">{{ 'add'|translate|titlecase }} {{ 'training'|translate }}</button>
|
||||
</div>
|
||||
<app-table [sourceType]="'trainings'" [refreshInterval]="1200000"></app-table>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-trainings',
|
||||
|
@ -7,9 +8,13 @@ import { Component, OnInit } from '@angular/core';
|
|||
})
|
||||
export class TrainingsComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
constructor(private router: Router) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
addTraining() {
|
||||
this.router.navigate(['trainings', 'new']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@ const routes: Routes = [
|
|||
canActivate: [AuthorizeGuard]
|
||||
},
|
||||
{ path: 'trainings', component: TrainingsComponent, canActivate: [AuthorizeGuard] },
|
||||
{
|
||||
path: 'trainings/:id',
|
||||
loadChildren: () => import('./_routes/edit-training/edit-training.module').then(m => m.EditTrainingModule),
|
||||
canActivate: [AuthorizeGuard]
|
||||
},
|
||||
{ path: "login/:redirect/:extraParam", component: LoginComponent },
|
||||
{ path: "login/:redirect", component: LoginComponent },
|
||||
//
|
||||
|
|
|
@ -56,7 +56,16 @@
|
|||
"type_already_exists": "Type already exists",
|
||||
"type_added_successfully": "Type added successfully",
|
||||
"service_added_successfully": "Service added successfully",
|
||||
"service_add_error": "Service could not be added. Please try again"
|
||||
"service_add_failed": "Service could not be added. Please try again"
|
||||
},
|
||||
"edit_training": {
|
||||
"select_start_datetime": "Select start date and time for the training",
|
||||
"select_end_datetime": "Select end date and time for the training",
|
||||
"insert_name": "Insert training name",
|
||||
"name_placeholder": "Training name",
|
||||
"other_crew_members": "Other crew members",
|
||||
"training_added_successfully": "Training added successfully",
|
||||
"training_add_failed": "Training could not be added. Please try again"
|
||||
},
|
||||
"update_availability_schedule": "Update availability schedule",
|
||||
"save_changes": "Save changes",
|
||||
|
|
|
@ -56,7 +56,16 @@
|
|||
"type_already_exists": "La tipologia è già presente",
|
||||
"type_added_successfully": "Tipologia aggiunta con successo",
|
||||
"service_added_successfully": "Intervento aggiunto con successo",
|
||||
"service_add_error": "Errore durante l'aggiunta dell'intervento. Riprovare più tardi"
|
||||
"service_add_failed": "Errore durante l'aggiunta dell'intervento. Riprovare più tardi"
|
||||
},
|
||||
"edit_training": {
|
||||
"select_start_datetime": "Seleziona data e ora di inizio dell'esercitazione",
|
||||
"select_end_datetime": "Seleziona data e ora di fine dell'esercitazione",
|
||||
"insert_name": "Inserisci il nome dell'esercitazione",
|
||||
"name_placeholder": "Esercitazione di gennaio",
|
||||
"other_crew_members": "Altri membri della squadra",
|
||||
"training_added_successfully": "Esercitazione aggiunta con successo",
|
||||
"training_add_failed": "Errore durante l'aggiunta dell'esercitazione. Riprovare più tardi"
|
||||
},
|
||||
"update_availability_schedule": "Aggiorna programmazione disponibilità",
|
||||
"save_changes": "Salva modifiche",
|
||||
|
|
Loading…
Reference in New Issue