Add user info modal
This commit is contained in:
parent
a044ead825
commit
c63a9789cc
|
@ -51,9 +51,11 @@ class UserController extends Controller
|
|||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(User $user)
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
//
|
||||
User::where('id', $request->user()->id)->update(['last_access' => now()]);
|
||||
|
||||
return response()->json(User::findOrFail($id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ class User extends Authenticatable implements LaratrustUser
|
|||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'surname',
|
||||
'username',
|
||||
'email',
|
||||
'phone_number',
|
||||
|
@ -37,6 +38,10 @@ class User extends Authenticatable implements LaratrustUser
|
|||
'banned',
|
||||
'hidden',
|
||||
'password',
|
||||
'birthplace',
|
||||
'birthplace_province',
|
||||
'ssn',
|
||||
'address'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -58,6 +63,8 @@ class User extends Authenticatable implements LaratrustUser
|
|||
'email_verified_at' => 'datetime',
|
||||
'last_access' => 'datetime',
|
||||
'last_availability_change' => 'datetime',
|
||||
'birthday' => 'datetime',
|
||||
'course_date' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?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::table('users', function (Blueprint $table) {
|
||||
$table->string('surname')->nullable()->after('name');
|
||||
$table->string('birthplace')->nullable()->after('surname');
|
||||
$table->string('birthplace_province')->nullable()->after('birthplace');
|
||||
$table->string('ssn')->nullable()->after('birthplace_province');
|
||||
$table->string('address')->nullable()->after('ssn');
|
||||
$table->timestamp('birthday')->nullable()->after('last_availability_change');
|
||||
$table->timestamp('course_date')->nullable()->after('birthday');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('surname');
|
||||
$table->dropColumn('birthplace');
|
||||
$table->dropColumn('birthplace_province');
|
||||
$table->dropColumn('ssn');
|
||||
$table->dropColumn('address');
|
||||
$table->dropColumn('birthday');
|
||||
$table->dropColumn('course_date');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -45,6 +45,8 @@ Route::middleware('auth:sanctum')->group( function () {
|
|||
|
||||
Route::get('/list', [UserController::class, 'index'])->middleware(ETag::class);
|
||||
|
||||
Route::get('/users/{id}', [UserController::class, 'show']);
|
||||
|
||||
Route::get('/schedules', [ScheduleSlotsController::class, 'index']);
|
||||
Route::post('/schedules', [ScheduleSlotsController::class, 'store']);
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<div class="modal-header">
|
||||
<h4 class="modal-title pull-left" translate>user_info_modal.title</h4>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close close pull-right"
|
||||
[attr.aria-label]="'close' | translate | titlecase"
|
||||
(click)="bsModalRef.hide()"
|
||||
>
|
||||
<span aria-hidden="true" class="visually-hidden">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="id == 0 || loaded == false">
|
||||
<div class="d-flex justify-content-center mt-2 pt-2 mb-3">
|
||||
<div class="spinner spinner-border"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="id !== 0 && loaded">
|
||||
<h2 class="text-center">{{ user.surname }} {{ user.name }}</h2>
|
||||
<table class="mx-auto" style="border-collapse: separate; border-spacing: 0px">
|
||||
<th></th>
|
||||
<th></th>
|
||||
<tr *ngIf="user.surname">
|
||||
<td>Cognome</td>
|
||||
<td>{{ user.surname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nome</td>
|
||||
<td>{{ user.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Username</td>
|
||||
<td>{{ user.username }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="user.birthday">
|
||||
<td>Data di nascita</td>
|
||||
<td>{{ user.birthday | date:'dd/MM/yyyy' }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="user.birthplace">
|
||||
<td>Luogo di nascita</td>
|
||||
<td>{{ user.birthplace }}<ng-container *ngIf="user.birthplace_province"> ({{ user.birthplace_province }})</ng-container></td>
|
||||
</tr>
|
||||
<tr *ngIf="user.ssn">
|
||||
<td>Codice fiscale</td>
|
||||
<td>{{ user.ssn }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="text-center">
|
||||
<br />
|
||||
<h5>RECAPITI</h5>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="user.address">
|
||||
<td>Indirizzo</td>
|
||||
<td>
|
||||
<a href="https://maps.google.com/?q={{ user.address }}" target="_blank">
|
||||
{{ user.address }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Telefono</td>
|
||||
<td><a href="tel:{{ user.phone_number }}">{{ user.phone_number }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Email</td>
|
||||
<td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td colspan="2" class="text-center">
|
||||
<br />
|
||||
<h5>DOCUMENTI</h5>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href='./aj/download.php?f=p&d=pat' target='_blank'>Patente</a>
|
||||
</td>
|
||||
<td>
|
||||
<small>Nr:</small> 123456789<br><small>Scad:</small> 11/02/2024
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td colspan="2" class="text-center">
|
||||
<br />
|
||||
<h5>INFORMAZIONI SERVIZIO</h5>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Autista</td>
|
||||
<td>
|
||||
<i class="fa fa-check" style="color:green" *ngIf="user.driver"></i>
|
||||
<i class="fa fa-times" style="color:red" *ngIf="!user.driver"></i>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tipologia</td>
|
||||
<td>
|
||||
<img alt="red helmet" src="./assets/icons/red_helmet.png" width="20px" *ngIf="user.chief">
|
||||
<img alt="black helmet" src="./assets/icons/black_helmet.png" width="20px" *ngIf="!user.chief">
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="user.course_date">
|
||||
<td>Data corso</td>
|
||||
<td>{{ user.course_date }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button *ngIf="false" type="button" class="btn btn-primary" (click)="goToEditPage()" [disabled]="!canGoToEditPage">
|
||||
{{ "edit" | translate | titlecase }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" (click)="bsModalRef.hide()">
|
||||
{{ "close" | translate }}
|
||||
</button>
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
td {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal';
|
||||
import { ApiClientService } from 'src/app/_services/api-client.service';
|
||||
import { AuthService } from 'src/app/_services/auth.service';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-user-info',
|
||||
templateUrl: './modal-user-info.component.html',
|
||||
styleUrls: ['./modal-user-info.component.scss']
|
||||
})
|
||||
export class ModalUserInfoComponent implements OnInit {
|
||||
id = 0;
|
||||
loaded = false;
|
||||
|
||||
canGoToEditPage = false;
|
||||
|
||||
user: any = {};
|
||||
|
||||
constructor(
|
||||
public bsModalRef: BsModalRef,
|
||||
private api: ApiClientService,
|
||||
public auth: AuthService,
|
||||
private toastr: ToastrService,
|
||||
private translate: TranslateService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.api.get(`users/${this.id}`).then((response) => {
|
||||
this.user = response;
|
||||
this.loaded = true;
|
||||
console.log(response);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
this.canGoToEditPage = this.auth.profile.id === this.id || this.auth.profile.can('users-read');
|
||||
}
|
||||
|
||||
goToEditPage() {
|
||||
if(!this.canGoToEditPage) return;
|
||||
this.bsModalRef.hide();
|
||||
|
||||
}
|
||||
}
|
|
@ -27,10 +27,12 @@
|
|||
<tr *ngFor="let row of data">
|
||||
<td>
|
||||
<i *ngIf="auth.profile.can('users-impersonate') && row.id !== auth.profile.id" class="fa fa-user me-2" (click)="onUserImpersonate(row.id)"></i>
|
||||
<div (click)="onMoreDetails(row.id)" class="d-inline">
|
||||
<img alt="red helmet" src="./assets/icons/red_helmet.png" width="20px" *ngIf="row.chief">
|
||||
<img alt="red helmet" src="./assets/icons/black_helmet.png" width="20px" *ngIf="!row.chief">
|
||||
<img alt="black helmet" src="./assets/icons/black_helmet.png" width="20px" *ngIf="!row.chief">
|
||||
<ng-container *ngIf="row.online;else userOffline"><u>{{ row.name }}</u></ng-container>
|
||||
<ng-template #userOffline>{{ row.name }}</ng-template>
|
||||
</div>
|
||||
</td>
|
||||
<td (click)="onChangeAvailability(row.id, row.available ? 0 : 1)">
|
||||
<i class="fa fa-check" style="color:green" *ngIf="row.available"></i>
|
||||
|
|
|
@ -63,6 +63,7 @@ export class TableComponent implements OnInit, OnDestroy {
|
|||
|
||||
@Output() changeAvailability: EventEmitter<{user: number, newState: 0|1}> = new EventEmitter<{user: number, newState: 0|1}>();
|
||||
@Output() userImpersonate: EventEmitter<number> = new EventEmitter<number>();
|
||||
@Output() moreDetails: EventEmitter<{rowId: number}> = new EventEmitter<{rowId: number}>();
|
||||
|
||||
public data: any = [];
|
||||
public displayedData: any = [];
|
||||
|
@ -199,6 +200,10 @@ export class TableComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onMoreDetails(rowId: number) {
|
||||
this.moreDetails.emit({rowId});
|
||||
}
|
||||
|
||||
openPlaceDetails(id: number) {
|
||||
this.router.navigate(['/place-details', id]);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<app-table [sourceType]="'list'" (changeAvailability)="changeAvailibility($event.newState, $event.user)" #table></app-table>
|
||||
<app-table [sourceType]="'list'" (changeAvailability)="changeAvailibility($event.newState, $event.user)" (moreDetails)="openUserInfoPage($event.rowId)" #table></app-table>
|
||||
<div class="text-center">
|
||||
<button (click)="requestTelegramToken()" class="btn btn-md btn-success mt-3">{{ 'list.connect_telegram_bot'|translate }}</button>
|
||||
<div class="alert alert-primary mt-4" role="alert" translate>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
|||
import { TableComponent } from '../../_components/table/table.component';
|
||||
import { ModalAvailabilityScheduleComponent } from '../../_components/modal-availability-schedule/modal-availability-schedule.component';
|
||||
import { ModalAlertComponent } from 'src/app/_components/modal-alert/modal-alert.component';
|
||||
import { ModalUserInfoComponent } from 'src/app/_components/modal-user-info/modal-user-info.component';
|
||||
import { ApiClientService } from 'src/app/_services/api-client.service';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
|
||||
|
@ -119,6 +120,14 @@ export class ListComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
openUserInfoPage(id: number) {
|
||||
this.modalService.show(ModalUserInfoComponent, {
|
||||
initialState: {
|
||||
id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadAvailabilityInterval = setInterval(() => {
|
||||
this.loadAvailability();
|
||||
|
|
|
@ -23,6 +23,7 @@ import { environment } from '../environments/environment';
|
|||
import { TableComponent } from './_components/table/table.component';
|
||||
import { ModalAvailabilityScheduleComponent } from './_components/modal-availability-schedule/modal-availability-schedule.component';
|
||||
import { ModalAlertComponent } from './_components/modal-alert/modal-alert.component';
|
||||
import { ModalUserInfoComponent } from './_components/modal-user-info/modal-user-info.component';
|
||||
import { OwnerImageComponent } from './_components/owner-image/owner-image.component';
|
||||
|
||||
import { DaterangePickerModule } from './_components/daterange-picker/daterange-picker.module';
|
||||
|
@ -43,6 +44,7 @@ import { AuthInterceptor } from './_providers/auth-interceptor.provider';
|
|||
TableComponent,
|
||||
ModalAvailabilityScheduleComponent,
|
||||
ModalAlertComponent,
|
||||
ModalUserInfoComponent,
|
||||
OwnerImageComponent,
|
||||
//
|
||||
LoginComponent,
|
||||
|
|
|
@ -100,6 +100,9 @@
|
|||
"training_load_failed": "Errore durante il caricamento dell'intervento. Riprovare più tardi",
|
||||
"users_load_failed": "Errore durante il caricamento degli utenti. Riprovare più tardi"
|
||||
},
|
||||
"user_info_modal": {
|
||||
"title": "User info"
|
||||
},
|
||||
"warning": "warning",
|
||||
"press_for_more_info": "press here for more info",
|
||||
"update_availability_schedule": "Update availability schedule",
|
||||
|
@ -162,5 +165,6 @@
|
|||
"press_to_select_a_date": "press to select a date",
|
||||
"footer_text": "Allerta-VVF, free software developed for volunteer firefighters brigades.",
|
||||
"revision": "revision",
|
||||
"unknown": "unknown"
|
||||
"unknown": "unknown",
|
||||
"edit": "edit"
|
||||
}
|
|
@ -100,6 +100,9 @@
|
|||
"training_load_failed": "Errore durante il caricamento dell'intervento. Riprovare più tardi",
|
||||
"users_load_failed": "Errore durante il caricamento degli utenti. Riprovare più tardi"
|
||||
},
|
||||
"user_info_modal": {
|
||||
"title": "Scheda utente"
|
||||
},
|
||||
"warning": "attenzione",
|
||||
"press_for_more_info": "premi qui per informazioni",
|
||||
"update_availability_schedule": "Aggiorna programmazione disponibilità",
|
||||
|
@ -162,5 +165,6 @@
|
|||
"press_to_select_a_date": "premi per selezionare una data",
|
||||
"footer_text": "Allerta-VVF, software libero realizzato per i Vigili del Fuoco volontari.",
|
||||
"revision": "revisione",
|
||||
"unknown": "sconosciuto"
|
||||
"unknown": "sconosciuto",
|
||||
"edit": "modifica"
|
||||
}
|
Loading…
Reference in New Issue