From 20ada53e0e992ee3e5c9c4b00d1e19fa9e9dcef6 Mon Sep 17 00:00:00 2001 From: mansurskTarento Date: Fri, 14 Feb 2025 18:15:35 +0530 Subject: [PATCH] events timpicker issue fixes, added rejection and prewview in progress --- .../create-event/create-event.component.html | 17 +- .../create-event/create-event.component.ts | 39 ++- .../event-basic-details.component.html | 20 +- .../event-basic-details.component.scss | 8 + .../event-basic-details.component.ts | 93 ++++++- .../events-list/events-list.component.spec.ts | 245 ++++++++++++++++-- .../events-list/events-list.component.ts | 23 +- .../speakers/speakers.component.html | 12 +- .../speakers/speakers.component.scss | 3 +- .../components/speakers/speakers.component.ts | 18 +- .../add-speakers/add-speakers.component.html | 5 +- .../add-speakers/add-speakers.component.ts | 9 +- .../basic-info/basic-info.component.html | 2 +- .../basic-info/basic-info.component.ts | 4 +- .../rejection-reason.component.html | 10 + .../rejection-reason.component.scss | 16 ++ .../rejection-reason.component.spec.ts | 21 ++ .../rejection-reason.component.ts | 24 ++ .../home/routes/events-2/events-2.module.ts | 6 +- 19 files changed, 512 insertions(+), 63 deletions(-) create mode 100644 project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.html create mode 100644 project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.scss create mode 100644 project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.spec.ts create mode 100644 project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.ts diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.html index 2eaafdc0..2ee1f473 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.html +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.html @@ -11,14 +11,14 @@ - + - + @@ -45,13 +45,22 @@ Add Competency - + + + + + + Preview + + + \ No newline at end of file diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.ts index a9ef0301..c789219a 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/create-event/create-event.component.ts @@ -57,7 +57,7 @@ export class CreateEventComponent implements OnInit, AfterViewInit { startDate: new FormControl('', [Validators.required]), startTime: new FormControl('', [Validators.required]), endTime: new FormControl('', [Validators.required]), - resourceUrl: new FormControl(''), + resourceUrl: new FormControl('', [Validators.required]), // uploadUrl: new FormControl(''), appIcon: new FormControl('', [Validators.required]), }) @@ -110,7 +110,6 @@ export class CreateEventComponent implements OnInit, AfterViewInit { //#region (ui interactions) onSelectionChange(event: StepperSelectionEvent) { this.currentStepperIndex = event.selectedIndex - this.showPreview = false } navigateBack() { @@ -118,6 +117,8 @@ export class CreateEventComponent implements OnInit, AfterViewInit { } moveToNextForm() { + this.eventDetailsForm.markAllAsTouched() + this.eventDetailsForm.updateValueAndValidity() if (this.canMoveToNext || this.openMode === 'view') { this.currentStepperIndex = this.currentStepperIndex + 1 } @@ -125,12 +126,16 @@ export class CreateEventComponent implements OnInit, AfterViewInit { preview() { this.showPreview = true - this.updatedEventDetails = this.getFormBodyOfEvent() + this.updatedEventDetails = this.getFormBodyOfEvent(this.eventDetails['status']) + setTimeout(() => { + this.currentStepperIndex = 4 + }, 100) } publish() { - this.eventDetails['status'] = 'SentToPublish' - this.saveAndExit() + if (this.canPublish) { + this.saveAndExit('SentToPublish') + } } get canMoveToNext() { @@ -151,15 +156,22 @@ export class CreateEventComponent implements OnInit, AfterViewInit { return currentFormIsValid } - get showPublish(): boolean { + get canPublish(): boolean { if (this.currentStepperIndex === 3) { if (this.eventDetailsForm.invalid) { + this.openSnackBar('Please fill mandatory fields in basic details') return false } if (!(this.speakersList && this.speakersList.length)) { + this.openSnackBar('Please add atleast one speaker') return false } if (!(this.materialsList && this.materialsList.length)) { + this.openSnackBar('Please add atleast one material') + return false + } + if (!(this.competencies && this.competencies.length)) { + this.openSnackBar('Please add atleast one competency') return false } return true @@ -171,19 +183,18 @@ export class CreateEventComponent implements OnInit, AfterViewInit { this.competencies = competencies } - saveAndExit(navigateBack = true) { + saveAndExit(status = 'Draft') { const formBody = { request: { - event: this.getFormBodyOfEvent() + event: this.getFormBodyOfEvent(status) } } this.eventSvc.updateEvent(formBody, this.eventId).subscribe({ next: res => { if (res) { - this.openSnackBar('Event details saved successfully') - if (navigateBack) { - this.navigateBack() - } + const successMessage = status === 'Draft' ? 'Event details saved successfully' : 'Event details sent for approval successfully' + this.openSnackBar(successMessage) + this.navigateBack() } }, error: (error: HttpErrorResponse) => { @@ -193,7 +204,7 @@ export class CreateEventComponent implements OnInit, AfterViewInit { }) } - getFormBodyOfEvent() { + getFormBodyOfEvent(status: string) { const eventDetails: any = JSON.parse(JSON.stringify(this.eventDetails)) const eventBaseDetails = this.eventDetailsForm.value let startTime = '' @@ -224,6 +235,8 @@ export class CreateEventComponent implements OnInit, AfterViewInit { eventDetails['competencies_v6'] = this.competencies } + eventDetails['status'] = status + return eventDetails } diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.html index 4cf824ac..f2b7b00e 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.html +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.html @@ -20,7 +20,7 @@ (change)="onFileSelected(file.files);">
icon - Upload Images * + Upload Image * Supported file types: PNG, JPG Max Size - 400MB
@@ -53,7 +53,7 @@
-
+
upload from URL
@@ -96,7 +96,7 @@
-
+
Date
@@ -114,10 +114,12 @@
Start Time
- - + + - + start time is mandatory @@ -128,9 +130,11 @@ End Time
- + - + start time is mandatory diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.scss b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.scss index 95ae1cc1..98d988ce 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.scss +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.scss @@ -102,3 +102,11 @@ display: none; } } + +::ng-deep ngx-material-timepicker-content{ + --button-color: #1B4CA1 !important; + --dial-background-color: #1B4CA1 !important; + --dial-editable-active-color: #1B4CA1 !important; + --clock-hand-color: #1B4CA1 !important; +} + diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.ts index 9d3e17b9..8ee5a955 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/event-basic-details/event-basic-details.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core' +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core' import { FormGroup } from '@angular/forms' import { MatLegacySnackBar } from '@angular/material/legacy-snack-bar' import * as _ from 'lodash' @@ -7,13 +7,14 @@ import { EventsService } from '../../services/events.service' import { map, mergeMap } from 'rxjs/operators' import { environment } from '../../../../../../../../../../../src/environments/environment' import { HttpErrorResponse } from '@angular/common/http' +import moment from 'moment' @Component({ selector: 'ws-app-event-basic-details', templateUrl: './event-basic-details.component.html', styleUrls: ['./event-basic-details.component.scss'] }) -export class EventBasicDetailsComponent implements OnInit { +export class EventBasicDetailsComponent implements OnInit, OnChanges { //#region (global variables) @Input() eventDetails!: FormGroup @@ -22,6 +23,11 @@ export class EventBasicDetailsComponent implements OnInit { evntCategorysList = ['Webinar', 'Karmayogi Talks', 'Karmayogi Saptah'] todayDate = new Date() + + maxTimeToStart = '11:30 pm' + minTimeToEnd = '12:30 am' + timeGap = 15 + //#endregion constructor( @@ -29,7 +35,70 @@ export class EventBasicDetailsComponent implements OnInit { private eventSvc: EventsService ) { } + ngOnChanges(changes: SimpleChanges): void { + if (changes.eventDetails) { + const startTime = _.get(this.eventDetails, 'value.startTime') + if (startTime) { + this.eventDetails.controls.startTime.patchValue(this.convertTo12HourFormat(startTime)) + } + + const endTime = _.get(this.eventDetails, 'value.endTime') + if (endTime) { + this.eventDetails.controls.endTime.patchValue(this.convertTo12HourFormat(endTime)) + } + } + } + + convertTo12HourFormat(timeWithTimezone: string): string { + const time = timeWithTimezone.split('+')[0] + const [hours, minutes] = time.split(':') + let hour = parseInt(hours) + let period = 'AM' + if (hour >= 12) { + period = 'PM' + if (hour > 12) { + hour -= 12 + } + } else if (hour === 0) { + hour = 12 + } + const formattedTime = `${hour}:${minutes} ${period}` + return formattedTime + } + ngOnInit(): void { + if (this.eventDetails.controls.startTime) { + this.eventDetails.controls.startTime.valueChanges.subscribe((time) => { + this.generatMinTimeToEnd(time) + }) + } + } + + + generatMinTimeToEnd(time: string) { + let [timePart, period] = time.split(' ') + let [hours, minutes] = timePart.split(':').map(Number) + minutes += this.timeGap + if (minutes >= 60) { + minutes -= 60 + hours += 1 + } + if (hours > 12) { + hours -= 12 + if (period === 'AM') { + period = 'PM' + } else { + period = 'AM' + } + } + if (hours === 12 && minutes === 0) { + period = period === 'AM' ? 'PM' : 'AM' + } + const formattedTime = `${hours}:${minutes < 10 ? '0' + minutes : minutes} ${period}` + this.minTimeToEnd = formattedTime + if (this.eventDetails.controls.startTime) { + this.eventDetails.controls.endTime.patchValue('') + } } get appIconName(): string { @@ -142,6 +211,26 @@ export class EventBasicDetailsComponent implements OnInit { return showMsg } + onStartTimeChange(event: any) { + const startTime = event ? event.formatted : '' + if (startTime) { + const minEndTime = this.calculateMinEndTime(startTime) + this.minTimeToEnd = minEndTime + if (this.eventDetails) { + const endTimeControl = this.eventDetails.get('endTime') + if (endTimeControl) { + endTimeControl.setValue('') + } + } + } + } + + calculateMinEndTime(startTime: string): string { + const startMoment = moment(startTime, 'HH:mm') + const minEndTimeMoment = startMoment.add(30, 'minutes') + return minEndTimeMoment.format('HH:mm') + } + private openSnackBar(message: string) { this.matSnackBar.open(message) } diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.spec.ts b/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.spec.ts index 7ce60a1b..685520cd 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.spec.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.spec.ts @@ -1,21 +1,234 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { EventsListComponent } from './events-list.component' +import { HttpErrorResponse } from '@angular/common/http' +import { of, throwError } from 'rxjs' -import { EventsListComponent } from './events-list.component'; +// Mock interfaces and types +interface MockMatSnackBar { + open: jest.Mock +} + +interface MockEventsService { + getEvents: jest.Mock + updateEvent: jest.Mock +} + +interface MockRouter { + navigate: jest.Mock +} + +interface MockDialog { + open: jest.Mock +} describe('EventsListComponent', () => { - let component: EventsListComponent; - let fixture: ComponentFixture; + let component: any + let mockMatSnackBar: MockMatSnackBar + let mockEventsService: MockEventsService + let mockRouter: MockRouter + let mockDialog: MockDialog beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [EventsListComponent] - }); - fixture = TestBed.createComponent(EventsListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + // Initialize mocks + mockMatSnackBar = { + open: jest.fn() + } + + mockEventsService = { + getEvents: jest.fn(), + updateEvent: jest.fn() + } + + mockRouter = { + navigate: jest.fn() + } + + mockDialog = { + open: jest.fn() + } + + // Create component instance with mocked dependencies + component = new EventsListComponent( + mockEventsService as any, + mockMatSnackBar as any, + { snapshot: { url: [{ path: 'upcoming' }] } } as any, + mockRouter as any, + mockDialog as any + ) + }) + + describe('createEventRequest', () => { + it('should create correct request object for upcoming events', () => { + // Mock date for consistent testing + const mockDate = new Date('2024-02-14') + jest.spyOn(global, 'Date').mockImplementation(() => mockDate) + + component.pathUrl = 'upcoming' + const request = component['createEventRequest']() + + expect(request).toEqual({ + locale: ['en'], + request: { + query: '', + limit: 20, + offset: 0, + filters: { + status: ['Live'], + contentType: 'Event', + endDate: { '>=': '2024-02-14' } + }, + sort_by: { lastUpdatedOn: 'desc' } + } + }) + }) + + it('should throw error for invalid path URL', () => { + component.pathUrl = 'invalid-path' + expect(() => component['createEventRequest']()).toThrow('Invalid path URL: invalid-path') + }) + }) + + describe('contentEvents', () => { + const mockEventRow = { + identifier: 'test-id', + versionKey: 'v1' + } + + it('should handle view action correctly', () => { + component.contentEvents({ action: 'view', rows: mockEventRow }) + expect(mockRouter.navigate).toHaveBeenCalledWith( + ['/app/home/events/edit-event', 'test-id'], + expect.any(Object) + ) + }) + + it('should handle cancel action correctly', () => { + mockEventsService.updateEvent.mockReturnValue(of({ success: true })) + component.contentEvents({ action: 'cancel', rows: mockEventRow }) + expect(mockEventsService.updateEvent).toHaveBeenCalledWith( + { + request: { + event: { + identifier: 'test-id', + versionKey: 'v1', + status: 'Cancelled' + } + } + }, + 'test-id' + ) + }) + + it('should handle remarks action for event with reject comment', () => { + const eventWithRemarks = { + ...mockEventRow, + rejectComment: 'Test rejection reason' + } + + component.contentEvents({ action: 'remarks', rows: eventWithRemarks }) + expect(mockDialog.open).toHaveBeenCalled() + }) + + it('should not call any handler for unknown action', () => { + component.contentEvents({ action: 'unknown', rows: mockEventRow }) + expect(mockRouter.navigate).not.toHaveBeenCalled() + expect(mockEventsService.updateEvent).not.toHaveBeenCalled() + expect(mockDialog.open).not.toHaveBeenCalled() + }) + }) + + describe('handleError', () => { + it('should show error message from response', () => { + const error = new HttpErrorResponse({ + error: { message: 'Test error message' } + }) + + component['handleError'](error) + expect(mockMatSnackBar.open).toHaveBeenCalledWith( + 'Test error message', + 'Close', + expect.any(Object) + ) + }) + + it('should show default error message when no error message in response', () => { + const error = new HttpErrorResponse({}) + + component['handleError'](error) + expect(mockMatSnackBar.open).toHaveBeenCalledWith( + 'Something went wrong', + 'Close', + expect.any(Object) + ) + }) + }) + + describe('cancelEvent', () => { + const mockEvent = { + identifier: 'test-id', + versionKey: 'v1' + } + + it('should successfully cancel event and show success message', () => { + mockEventsService.updateEvent.mockReturnValue(of({ success: true })) + mockEventsService.getEvents.mockReturnValue(of([])) + + component.cancelEvent(mockEvent) + + expect(mockEventsService.updateEvent).toHaveBeenCalledWith( + expect.objectContaining({ + request: { + event: { + identifier: 'test-id', + versionKey: 'v1', + status: 'Cancelled' + } + } + }), + 'test-id' + ) + expect(mockMatSnackBar.open).toHaveBeenCalledWith( + 'event is cancelled successfully', + 'Close', + expect.any(Object) + ) + }) + + it('should handle error when cancelling event', () => { + const error = new HttpErrorResponse({ + error: { message: 'Cancel failed' } + }) + mockEventsService.updateEvent.mockReturnValue(throwError(() => error)) + + component.cancelEvent(mockEvent) + + expect(mockMatSnackBar.open).toHaveBeenCalledWith( + 'Cancel failed', + 'Close', + expect.any(Object) + ) + }) + }) + + describe('openRejectionPopup', () => { + it('should open dialog when rejection comment exists', () => { + const mockEvent = { + identifier: 'test-id', + versionKey: 'v1', + rejectComment: 'Test rejection reason' + } + + component.openRejectionPopup(mockEvent) + expect(mockDialog.open).toHaveBeenCalled() + }) + + it('should not open dialog when no rejection comment', () => { + const mockEvent = { + identifier: 'test-id', + versionKey: 'v1' + } + + component.openRejectionPopup(mockEvent) + expect(mockDialog.open).not.toHaveBeenCalled() + }) + }) +}) \ No newline at end of file diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.ts index 0ec2bc16..7e2e9005 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/events-list/events-list.component.ts @@ -6,6 +6,8 @@ import { Subscription } from 'rxjs' import { events } from '../../models/events.model' import { EventsService } from '../../services/events.service' import * as _ from 'lodash' +import { MatLegacyDialog } from '@angular/material/legacy-dialog' +import { RejectionReasonComponent } from '../../dialogs/rejection-reason/rejection-reason.component' @Component({ selector: 'ws-app-events-list', @@ -29,7 +31,8 @@ export class EventsListComponent implements OnInit, OnDestroy { private eventSvc: EventsService, private matSnackBar: MatSnackBar, private activatedRoute: ActivatedRoute, - private route: Router + private route: Router, + private dialog: MatLegacyDialog ) { } //#endregion @@ -302,6 +305,7 @@ export class EventsListComponent implements OnInit, OnDestroy { this.cancelEvent(events.rows) break case 'remarks': + this.openRejectionPopup(events.rows) break case 'broadcast': break @@ -322,13 +326,13 @@ export class EventsListComponent implements OnInit, OnDestroy { const requestBody = { request: { event: { + identifier: rowData.identifier, versionKey: rowData.versionKey, - status: 'Cancelled', - identifier: rowData.identifier + status: 'Cancelled' } } } - this.eventSvc.publishEvent(rowData.identifier, requestBody).subscribe({ + this.eventSvc.updateEvent(requestBody, rowData.identifier).subscribe({ next: res => { if (res) { this.openSnackBar('event is cancelled successfully') @@ -342,6 +346,17 @@ export class EventsListComponent implements OnInit, OnDestroy { }) } + openRejectionPopup(rowData: any) { + const remarks = _.get(rowData, 'rejectComment') + if (remarks) { + this.dialog.open(RejectionReasonComponent, { + minHeight: '200px', + minWidth: '400px', + data: remarks + }) + } + } + //#endregion private openSnackBar(message: string) { diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.html index 2cbf2d1e..57fef5c8 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.html +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.html @@ -25,11 +25,13 @@ {{ speaker.name ? speaker.name : '-' }} {{ speaker.email ? speaker.email : '-' }} {{ speaker.description ? speaker.description : '-' }} - - edit - - delete - + +
+ edit + + delete + +
diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.scss b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.scss index 5772133e..75cce172 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.scss +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.scss @@ -38,11 +38,12 @@ } .speaker-table-cell{ - height: 35px; + min-height: 35px; border: 1px solid #00000014; margin-top: -1px; font: 400 12px Inter; padding-left: 10px; + height: fit-content; } .edit-icon { diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.ts index c788b641..1b767e20 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/components/speakers/speakers.component.ts @@ -2,6 +2,7 @@ import { Component, Input } from '@angular/core' import { speaker } from '../../models/events.model' import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog' import { AddSpeakersComponent } from '../../dialogs/add-speakers/add-speakers.component' +import { MatLegacySnackBar } from '@angular/material/legacy-snack-bar' @Component({ selector: 'ws-app-speakers', @@ -15,6 +16,7 @@ export class SpeakersComponent { constructor( private dialog: MatDialog, + private matSnackBar: MatLegacySnackBar, ) { } openAddSpeakerPopu() { @@ -28,7 +30,11 @@ export class SpeakersComponent { dialogRef.afterClosed().subscribe((speakerDetails: speaker) => { if (speakerDetails) { - this.speakersList.push(speakerDetails) + if (this.speakersList.find((addedSpeaker: any) => addedSpeaker.email.toLowerCase() === speakerDetails.email.toLocaleLowerCase())) { + this.speakersList.push(speakerDetails) + } else { + this.openSnackBar('There is already a speaker with the same email. Please add the speaker with a different email.') + } } }) } @@ -46,7 +52,11 @@ export class SpeakersComponent { dialogRef.afterClosed().subscribe((speakerDetails: speaker) => { if (speakerDetails) { - this.speakersList[index] = speakerDetails + if (this.speakersList.find((addedSpeaker: any) => addedSpeaker.email.toLowerCase() === speakerDetails.email.toLocaleLowerCase())) { + this.speakersList[index] = speakerDetails + } else { + this.openSnackBar('There is already a speaker with the same email. Please update speaker with a different email.') + } } }) } @@ -57,4 +67,8 @@ export class SpeakersComponent { this.speakersList.splice(index, 1) } } + + private openSnackBar(message: string) { + this.matSnackBar.open(message) + } } diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.html index 2b10f327..74c6426e 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.html +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.html @@ -41,9 +41,12 @@ + + name is mandatory +
-
+
Description
diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.ts index 8a89966e..a6ca2bcb 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/add-speakers/add-speakers.component.ts @@ -33,7 +33,7 @@ export class AddSpeakersComponent implements OnInit { ngOnInit(): void { this.speakerForm = this.formBuilder.group({ email: new FormControl(_.get(this.speakerDetails, 'email', ''), [Validators.required, Validators.pattern(EMAIL_PATTERN)]), - name: new FormControl(_.get(this.speakerDetails, 'name', '')), + name: new FormControl(_.get(this.speakerDetails, 'name', ''), [Validators.required]), description: new FormControl(_.get(this.speakerDetails, 'description', '')) }) @@ -96,8 +96,11 @@ export class AddSpeakersComponent implements OnInit { } addSpeaker() { - if (this.speakerForm && this.speakerForm.valid) { - this.dialogRef.close(this.speakerForm.value) + if (this.speakerForm) { + if (this.speakerForm.valid) { + this.dialogRef.close(this.speakerForm.value) + } + this.speakerForm.markAllAsTouched } } diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.html index 2b3dfd5e..bab2e9d7 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.html +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.html @@ -63,7 +63,7 @@
icon - Upload Images * + Upload Image * Supported file types: PNG, JPG Max Size - 400MB
diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.ts index c9bc724e..b8ed0cb6 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/basic-info/basic-info.component.ts @@ -59,7 +59,7 @@ export class BasicInfoComponent implements OnInit { const reader = new FileReader() this.imagePath = files[0] if (this.imagePath && this.imagePath.size > events.IMAGE_MAX_SIZE) { - this.openSnackBar('Selected image size is more') + this.openSnackBar('Please select an image with a size of less than 400MB.') this.imagePath = '' return } @@ -72,6 +72,8 @@ export class BasicInfoComponent implements OnInit { onSave() { if (this.eventForm.valid && this.imgURL) { this.saveImage() + } else if (this.eventForm.valid && !this.imgURL) { + this.openSnackBar('please upload image') } } diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.html b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.html new file mode 100644 index 00000000..2eec00a1 --- /dev/null +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.html @@ -0,0 +1,10 @@ +
+
+
Remarks
+ clear +
+ +
+ {{rejectReason}} +
+
\ No newline at end of file diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.scss b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.scss new file mode 100644 index 00000000..0c291ebd --- /dev/null +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.scss @@ -0,0 +1,16 @@ +.closIcon { + margin-right: -12px; + color: #666666; +} + +.remarks { + /* stylelint-disable */ + font: 600 17px Lato; + /* stylelint-enable */ +} + +.rejectReason { + /* stylelint-disable */ + font: 400 14px Lato; + /* stylelint-enable */ +} diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.spec.ts b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.spec.ts new file mode 100644 index 00000000..398f6779 --- /dev/null +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RejectionReasonComponent } from './rejection-reason.component'; + +describe('RejectionReasonComponent', () => { + let component: RejectionReasonComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [RejectionReasonComponent] + }); + fixture = TestBed.createComponent(RejectionReasonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.ts b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.ts new file mode 100644 index 00000000..7952ef35 --- /dev/null +++ b/project/ws/app/src/lib/routes/home/routes/events-2/dialogs/rejection-reason/rejection-reason.component.ts @@ -0,0 +1,24 @@ +import { Component, Inject } from '@angular/core' +import { MAT_LEGACY_DIALOG_DATA, MatLegacyDialogRef } from '@angular/material/legacy-dialog' + +@Component({ + selector: 'ws-app-rejection-reason', + templateUrl: './rejection-reason.component.html', + styleUrls: ['./rejection-reason.component.scss'] +}) +export class RejectionReasonComponent { + + rejectReason: any + + constructor( + private dialogRef: MatLegacyDialogRef, + @Inject(MAT_LEGACY_DIALOG_DATA) data: any + ) { + this.rejectReason = data + } + + closeDialog() { + this.dialogRef.close() + } + +} diff --git a/project/ws/app/src/lib/routes/home/routes/events-2/events-2.module.ts b/project/ws/app/src/lib/routes/home/routes/events-2/events-2.module.ts index 6c95c1e2..e439d70d 100644 --- a/project/ws/app/src/lib/routes/home/routes/events-2/events-2.module.ts +++ b/project/ws/app/src/lib/routes/home/routes/events-2/events-2.module.ts @@ -41,7 +41,8 @@ import { YoutubePlayerComponent } from './dialogs/youtube-player/youtube-player. import { MatLegacyTabsModule } from '@angular/material/legacy-tabs' import { CardCompetencyComponent } from './components/card-competency/card-competency.component' import { WidgetResolverModule } from '@sunbird-cb/resolver' -import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker' +import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker'; +import { RejectionReasonComponent } from './dialogs/rejection-reason/rejection-reason.component' // import { MatTimepickerModule } from 'mat-timepicker' @@ -61,7 +62,8 @@ import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker' AddCompetencyComponent, EventsPreviewComponent, YoutubePlayerComponent, - CardCompetencyComponent + CardCompetencyComponent, + RejectionReasonComponent ], imports: [ CommonModule,