Commit 66b5f4ce by sawit

modal จองห้องประชุม

parent c8dc0a75
...@@ -49,6 +49,11 @@ ...@@ -49,6 +49,11 @@
</mat-form-field> </mat-form-field>
</div> </div>
<!-- Room Preview -->
<div class="form-row" *ngIf="getSelectedRoomImage() as img">
<img [src]="img" alt="room" style="width:100%;max-height:180px;object-fit:cover;border-radius:8px;border:1px solid #e9ecef;" />
</div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline" class="form-field"> <mat-form-field appearance="outline" class="form-field">
<mat-label>วันที่เริ่มต้น</mat-label> <mat-label>วันที่เริ่มต้น</mat-label>
...@@ -77,16 +82,37 @@ ...@@ -77,16 +82,37 @@
</mat-form-field> </mat-form-field>
</div> </div>
<!-- Attendees section -->
<div class="form-row">
<mat-form-field appearance="outline" class="form-field">
<mat-label>จำนวนผู้เข้าร่วม</mat-label>
<input matInput type="number" min="0" formControlName="attendeeCount" [value]="attendees.length" readonly>
</mat-form-field>
<mat-form-field appearance="outline" class="form-field">
<mat-label>เพิ่มผู้เข้าร่วม (พิมพ์อีเมลแล้วกด Enter)</mat-label>
<mat-chip-grid #chipList aria-label="Attendees">
<mat-chip-row *ngFor="let a of attendees" [removable]="true" (removed)="removeAttendee(a)">
{{ a }}
<button matChipRemove aria-label="remove">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
<input
placeholder="เพิ่มอีเมลผู้เข้าร่วม"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
(matChipInputTokenEnd)="addAttendee($event)" />
</mat-chip-grid>
</mat-form-field>
</div>
<mat-form-field appearance="outline" class="form-field-full"> <mat-form-field appearance="outline" class="form-field-full">
<mat-label>รายละเอียด</mat-label> <mat-label>รายละเอียด</mat-label>
<textarea matInput formControlName="description" rows="3" placeholder="รายละเอียดเพิ่มเติม (ไม่บังคับ)"></textarea> <textarea matInput formControlName="description" rows="3" placeholder="รายละเอียดเพิ่มเติม (ไม่บังคับ)"></textarea>
</mat-form-field> </mat-form-field>
<div class="form-actions"> <div class="form-actions">
<button mat-raised-button color="primary" type="submit" [disabled]="!bookingForm.valid">
<mat-icon>event</mat-icon>
จองห้องประชุม
</button>
<button mat-button type="button" (click)="bookingForm.reset()"> <button mat-button type="button" (click)="bookingForm.reset()">
<mat-icon>refresh</mat-icon> <mat-icon>refresh</mat-icon>
รีเซ็ต รีเซ็ต
...@@ -95,6 +121,10 @@ ...@@ -95,6 +121,10 @@
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
ยกเลิก ยกเลิก
</button> </button>
<button mat-raised-button color="primary" type="submit" [disabled]="!bookingForm.valid">
<mat-icon>event</mat-icon>
จองห้องประชุม
</button>
</div> </div>
</form> </form>
</div> </div>
...@@ -210,6 +240,7 @@ ...@@ -210,6 +240,7 @@
(click)="onEventClick({ event: e })"> (click)="onEventClick({ event: e })">
<span class="time" *ngIf="e.StartTime && e.EndTime">{{ e.StartTime | date:'HH:mm' }}-{{ e.EndTime | date:'HH:mm' }}</span> <span class="time" *ngIf="e.StartTime && e.EndTime">{{ e.StartTime | date:'HH:mm' }}-{{ e.EndTime | date:'HH:mm' }}</span>
<span class="title">{{ e.Subject }}</span> <span class="title">{{ e.Subject }}</span>
<span class="count" *ngIf="e.AttendeesCount">({{ e.AttendeesCount }})</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -258,6 +289,9 @@ ...@@ -258,6 +289,9 @@
</span> </span>
</div> </div>
<div class="quick-info-content"> <div class="quick-info-content">
<div class="info-item" *ngIf="getRoomImageByName(data.Location)">
<img [src]="getRoomImageByName(data.Location)" alt="room" style="width:100%;max-height:140px;object-fit:cover;border-radius:8px;border:1px solid #e9ecef;" />
</div>
<div class="info-item"> <div class="info-item">
<mat-icon>location_on</mat-icon> <mat-icon>location_on</mat-icon>
<span>{{ data.Location }}</span> <span>{{ data.Location }}</span>
...@@ -276,7 +310,11 @@ ...@@ -276,7 +310,11 @@
</div> </div>
<div class="info-item" *ngIf="data.Attendees"> <div class="info-item" *ngIf="data.Attendees">
<mat-icon>group</mat-icon> <mat-icon>group</mat-icon>
<span>{{ data.Attendees }}</span> <span>{{ data.Attendees }} ({{ data.AttendeesCount || (data.AttendeesList?.length || 0) }} คน)</span>
</div>
<div class="info-item" *ngIf="data.AttendeesList?.length">
<mat-icon>badge</mat-icon>
<span>{{ data.AttendeesList.join(', ') }}</span>
</div> </div>
</div> </div>
<div class="quick-info-actions"> <div class="quick-info-actions">
......
...@@ -72,6 +72,7 @@ import { MeetingRoom, MeetingBooking, BookingTimeSlot, BookingStatistics } from ...@@ -72,6 +72,7 @@ import { MeetingRoom, MeetingBooking, BookingTimeSlot, BookingStatistics } from
}) })
export class MeetingBookingComponent implements OnInit { export class MeetingBookingComponent implements OnInit {
rooms$: Observable<MeetingRoom[]>; rooms$: Observable<MeetingRoom[]>;
private roomsSnapshot: MeetingRoom[] = [];
bookings$: Observable<MeetingBooking[]>; bookings$: Observable<MeetingBooking[]>;
statistics$: Observable<BookingStatistics>; statistics$: Observable<BookingStatistics>;
...@@ -110,6 +111,7 @@ export class MeetingBookingComponent implements OnInit { ...@@ -110,6 +111,7 @@ export class MeetingBookingComponent implements OnInit {
private snackBar: MatSnackBar private snackBar: MatSnackBar
) { ) {
this.rooms$ = this.meetingBookingService.rooms$; this.rooms$ = this.meetingBookingService.rooms$;
this.rooms$.subscribe(r => this.roomsSnapshot = r || []);
this.bookings$ = this.meetingBookingService.bookings$; this.bookings$ = this.meetingBookingService.bookings$;
this.bookingForm = this.fb.group({ this.bookingForm = this.fb.group({
...@@ -118,7 +120,8 @@ export class MeetingBookingComponent implements OnInit { ...@@ -118,7 +120,8 @@ export class MeetingBookingComponent implements OnInit {
description: [''], description: [''],
startDateTime: ['', Validators.required], startDateTime: ['', Validators.required],
endDateTime: ['', Validators.required], endDateTime: ['', Validators.required],
attendees: [[]] attendees: [[]],
attendeeCount: [0, [Validators.min(0)]]
}); });
this.statistics$ = this.meetingBookingService.getBookingStatistics( this.statistics$ = this.meetingBookingService.getBookingStatistics(
...@@ -180,7 +183,7 @@ export class MeetingBookingComponent implements OnInit { ...@@ -180,7 +183,7 @@ export class MeetingBookingComponent implements OnInit {
const value = (event.value || '').trim(); const value = (event.value || '').trim();
if (value) { if (value) {
this.attendees.push(value); this.attendees.push(value);
this.bookingForm.patchValue({ attendees: this.attendees }); this.bookingForm.patchValue({ attendees: this.attendees, attendeeCount: this.attendees.length });
} }
event.chipInput!.clear(); event.chipInput!.clear();
} }
...@@ -189,7 +192,7 @@ export class MeetingBookingComponent implements OnInit { ...@@ -189,7 +192,7 @@ export class MeetingBookingComponent implements OnInit {
const index = this.attendees.indexOf(attendee); const index = this.attendees.indexOf(attendee);
if (index >= 0) { if (index >= 0) {
this.attendees.splice(index, 1); this.attendees.splice(index, 1);
this.bookingForm.patchValue({ attendees: this.attendees }); this.bookingForm.patchValue({ attendees: this.attendees, attendeeCount: this.attendees.length });
} }
} }
...@@ -287,7 +290,9 @@ export class MeetingBookingComponent implements OnInit { ...@@ -287,7 +290,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor: this.getStatusColor(booking.status), CategoryColor: this.getStatusColor(booking.status),
Status: booking.status, Status: booking.status,
Organizer: booking.organizerName, Organizer: booking.organizerName,
Attendees: booking.attendees.map(a => a.userName).join(', ') Attendees: booking.attendees.map(a => a.userName).join(', '),
AttendeesList: booking.attendees.map(a => a.userName),
AttendeesCount: booking.attendees.length
})); }));
} else { } else {
// ถ้าไม่มีข้อมูลจาก service ให้ใช้ข้อมูลตัวอย่าง // ถ้าไม่มีข้อมูลจาก service ให้ใช้ข้อมูลตัวอย่าง
...@@ -384,7 +389,9 @@ export class MeetingBookingComponent implements OnInit { ...@@ -384,7 +389,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor: 'success', CategoryColor: 'success',
Status: 'confirmed', Status: 'confirmed',
Organizer: 'John Doe', Organizer: 'John Doe',
Attendees: 'Jane Smith, Bob Johnson' Attendees: 'Jane Smith, Bob Johnson',
AttendeesList: ['Jane Smith', 'Bob Johnson'],
AttendeesCount: 2
}, },
{ {
Id: 2, Id: 2,
...@@ -397,7 +404,9 @@ export class MeetingBookingComponent implements OnInit { ...@@ -397,7 +404,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor: 'info', CategoryColor: 'info',
Status: 'pending', Status: 'pending',
Organizer: 'Alice Brown', Organizer: 'Alice Brown',
Attendees: 'Charlie Wilson, Diana Lee' Attendees: 'Charlie Wilson, Diana Lee',
AttendeesList: ['Charlie Wilson', 'Diana Lee'],
AttendeesCount: 2
}, },
{ {
Id: 3, Id: 3,
...@@ -410,7 +419,9 @@ export class MeetingBookingComponent implements OnInit { ...@@ -410,7 +419,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor: 'warning', CategoryColor: 'warning',
Status: 'confirmed', Status: 'confirmed',
Organizer: 'Tech Lead', Organizer: 'Tech Lead',
Attendees: 'ทีมพัฒนา' Attendees: 'ทีมพัฒนา',
AttendeesList: ['ทีมพัฒนา'],
AttendeesCount: 1
} }
]; ];
...@@ -512,6 +523,16 @@ export class MeetingBookingComponent implements OnInit { ...@@ -512,6 +523,16 @@ export class MeetingBookingComponent implements OnInit {
return items; return items;
} }
public getRoomImageByName(roomName: string): string | undefined {
const room = this.roomsSnapshot.find(r => r.name === roomName);
return room?.imageUrl;
}
public getSelectedRoomImage(): string | undefined {
const room = this.roomsSnapshot.find(r => r.id === this.bookingForm?.value?.roomId);
return room?.imageUrl;
}
public monthLabel(): string { public monthLabel(): string {
const d = this.selectedDate_schedule; const d = this.selectedDate_schedule;
return `${d.toLocaleString('th-TH', { month: 'long' })} ${d.getFullYear()}`; return `${d.toLocaleString('th-TH', { month: 'long' })} ${d.getFullYear()}`;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment