Skip to content

Commit

Permalink
feat: next meeting create (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
lwestfall committed Jan 5, 2024
1 parent 3886ba0 commit ed8f35b
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 33 deletions.
1 change: 1 addition & 0 deletions src/Client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { BookRecommendationForMeetingDto } from './models/book-recommendation-fo
export { BookVoteDto } from './models/book-vote-dto';
export { CreateBookDto } from './models/create-book-dto';
export { CreateBookVoteDto } from './models/create-book-vote-dto';
export { CreateMeetingDto } from './models/create-meeting-dto';
export { MeetingDto } from './models/meeting-dto';
export { MeetingSimpleDto } from './models/meeting-simple-dto';
export { MeetingUserStateDto } from './models/meeting-user-state-dto';
Expand Down
6 changes: 6 additions & 0 deletions src/Client/src/app/api/models/create-meeting-dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* tslint:disable */
/* eslint-disable */
export interface CreateMeetingDto {
dateTime: string;
previousMeetingId?: string | null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,31 +71,48 @@ <h4 class="display-4">And the winner is...</h4>
[book]="meeting.winningBook"
[ripple]="true"></app-book-card>
</div>
<div class="d-flex flex-column align-items-center">
<h6 class="display-6 text-center">Recommendations</h6>
<app-meeting-recommendations
[bookRecommendations]="meeting.bookRecommendations"
[presenterMode]="presenterMode"
[noRipple]="true"
[myRecommendedBookId]="
myRecommendedBookId
"></app-meeting-recommendations>
</div>
}
<div class="d-flex flex-column align-items-center">
<h6 class="display-6 text-center">Recommendations</h6>
<app-meeting-recommendations
[bookRecommendations]="meeting.bookRecommendations"
[presenterMode]="presenterMode"
[noRipple]="true"
[myRecommendedBookId]="
myRecommendedBookId
"></app-meeting-recommendations>
</div>
}
}
</div>
<div class="justify-content-end" *ngIf="presenterMode && isAdmin">
<div class="d-flex flex-column align-items-center gap-2">
<div class="d-flex flex-column align-items-center">
<h5 class="display-5">Join!</h5>
<qrcode
[qrdata]="routeUrl.toString()"
imageSrc="./assets/lemon.png"
[imageHeight]="60"
[imageWidth]="60"
[width]="200"
lightColor="var(--bg-color)"></qrcode>
@if (meeting.status !== MeetingState.Closed) {
<h5 class="display-5 text-center">Join!</h5>
<qrcode
[qrdata]="routeUrl.toString()"
imageSrc="./assets/lemon.png"
[imageHeight]="60"
[imageWidth]="60"
[width]="200"
lightColor="var(--bg-color)"></qrcode>
} @else {
@if (nextMeeting$ | async; as nextMeeting) {
<h6 class="display-6 text-center">Next Meeting</h6>
<app-meeting-card [meeting]="nextMeeting"></app-meeting-card>
} @else {
<h6 class="display-6 text-center">Let's do it again!</h6>
<ngb-datepicker [(ngModel)]="nextMeetingDate"></ngb-datepicker>
<ngb-timepicker [(ngModel)]="nextMeetingTime" [meridian]="true" />
<button
type="button"
class="btn btn-success"
(click)="scheduleNextMeeting()">
Schedule Next Meeting
</button>
}
}
</div>
<div class="text-center">
<h4 class="display-5">Roll Call!</h4>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap';
import { Store } from '@ngrx/store';
import moment from 'moment';
import { Observable, Subscription } from 'rxjs';
import { BookDto, MeetingDto } from '../../api/models';
import { BookDto, CreateMeetingDto, MeetingDto } from '../../api/models';
import { AppState } from '../../app-state';
import { selectMyRecommendations } from '../../books/state/books.selectors';
import { LiveMeetingService } from '../../services/websockets/live-meeting.service';
Expand All @@ -13,6 +15,7 @@ import { MeetingState } from '../state/meetings.reducer';
import {
selectLiveMeetingConnected,
selectMeetingState,
selectNextMeeting,
} from '../state/meetings.selectors';

@Component({
Expand All @@ -26,6 +29,8 @@ export class LiveMeetingComponent implements OnInit, OnDestroy {
liveMeetingConnected$: Observable<boolean> = this.store.select(
selectLiveMeetingConnected
);
nextMeeting$: Observable<MeetingDto | null> =
this.store.select(selectNextMeeting);
lastBook: BookDto | null = null;
MeetingState = MeetingStatus;

Expand All @@ -36,6 +41,9 @@ export class LiveMeetingComponent implements OnInit, OnDestroy {
myRecommendedBookId?: string;
routeUrl: URL;

nextMeetingDate: NgbDateStruct;
nextMeetingTime: NgbTimeStruct = { hour: 18, minute: 0, second: 0 };

constructor(
private liveMeetingSvc: LiveMeetingService,
private store: Store<AppState>,
Expand Down Expand Up @@ -77,6 +85,13 @@ export class LiveMeetingComponent implements OnInit, OnDestroy {
this.myRecommendedBookId = myRecommendation?.book.id;
})
);

const nextDate = moment().add(5, 'weeks');
this.nextMeetingDate = {
year: nextDate.year(),
month: nextDate.month() + 1,
day: nextDate.date(),
};
}

ngOnInit() {
Expand Down Expand Up @@ -146,4 +161,21 @@ export class LiveMeetingComponent implements OnInit, OnDestroy {
console.log('Winner announced', meeting.winningBook?.title);
this.store.dispatch(handleMeetingUpdate({ meeting }));
}

scheduleNextMeeting() {
if (!this.meetingId) {
return;
}

const nextMeetingDateTime = moment(
`${this.nextMeetingDate.year}-${this.nextMeetingDate.month}-${this.nextMeetingDate.day} ${this.nextMeetingTime.hour}:${this.nextMeetingTime.minute}`
);

const newMeeting: CreateMeetingDto = {
dateTime: nextMeetingDateTime.toISOString(),
previousMeetingId: this.meetingId,
};

this.liveMeetingSvc.createNextMeeting(newMeeting);
}
}
10 changes: 10 additions & 0 deletions src/Client/src/app/meetings/meetings.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import {
NgbDatepickerModule,
NgbModule,
NgbTimepickerModule,
} from '@ng-bootstrap/ng-bootstrap';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { QRCodeModule } from 'angularx-qrcode';
Expand All @@ -24,6 +30,10 @@ import { meetingsReducer } from './state/meetings.reducer';
BooksModule,
DndModule,
QRCodeModule,
NgbModule,
NgbTimepickerModule,
NgbDatepickerModule,
FormsModule,
],
declarations: [
MeetingCountdownComponent,
Expand Down
33 changes: 28 additions & 5 deletions src/Client/src/app/meetings/state/meetings.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ export const meetingsReducer = createReducer(
meetingsActions.handleMeetingUpdate,
(state, action): MeetingsState => ({
...state,
allMeetingStates: state.allMeetingStates.map(meetingState =>
meetingState.meeting.id === action.meeting.id
? { meeting: action.meeting, error: null }
: meetingState
),
allMeetingStates: handleMeetingUpdate(state, action),
})
),
on(
Expand All @@ -80,3 +76,30 @@ export const meetingsReducer = createReducer(
})
)
);

function handleMeetingUpdate(
state: MeetingsState,
action: {
meeting: MeetingDto;
}
): MeetingState[] {
const existingMeetingState = state.allMeetingStates.find(
ms => ms.meeting.id === action.meeting.id
);

if (!existingMeetingState) {
return [
...state.allMeetingStates,
{
meeting: action.meeting,
error: null,
},
];
}

return state.allMeetingStates.map(meetingState =>
meetingState.meeting.id === action.meeting.id
? { meeting: action.meeting, error: null }
: meetingState
);
}
4 changes: 2 additions & 2 deletions src/Client/src/app/navbar/navbar.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
</ul>
@if ((verified$ | async) && (nextMeeting$ | async); as nextMeeting) {
<div *ngIf="!nextMeeting.status" class="ms-auto me-auto">
<span
<small
>Next meeting in
<app-meeting-countdown
[meeting]="nextMeeting"></app-meeting-countdown
>!</span
>!</small
>
</div>
}
Expand Down
10 changes: 9 additions & 1 deletion src/Client/src/app/services/websockets/live-meeting.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { CreateBookVoteDto, MeetingDto } from '../../api/models';
import {
CreateBookVoteDto,
CreateMeetingDto,
MeetingDto,
} from '../../api/models';
import { AppState } from '../../app-state';
import * as actions from '../../meetings/state/meetings.actions';
import { SignalRService } from './signal-r.service';
Expand Down Expand Up @@ -79,4 +83,8 @@ export class LiveMeetingService extends SignalRService {
async resetMeeting(meetingId: string): Promise<void> {
await this.connection.invoke('ResetMeeting', meetingId);
}

async createNextMeeting(meeting: CreateMeetingDto): Promise<void> {
await this.connection.invoke('CreateNextMeeting', meeting);
}
}
2 changes: 1 addition & 1 deletion src/Server/WebApi/Dtos/CreateMeetingDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Cbc.WebApi.Dtos;

public class CreateMeetingDto : IMapTo<Meeting>
{
public Guid PreviousMeetingId { get; set; }
public Guid? PreviousMeetingId { get; set; }

public DateTime DateTime { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class AdditionalSchemaDefinitionsDocumentFilter : IDocumentFilter
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
// add types to this list to expose them in the swagger doc when they aren't used in any controllers
var types = new[] { typeof(CreateBookVoteDto) };
var types = new[] { typeof(CreateBookVoteDto), typeof(CreateMeetingDto) };

foreach (var type in types)
{
Expand Down
15 changes: 11 additions & 4 deletions src/Server/WebApi/Hubs/LiveMeetingHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ await this.Clients
[Authorize(Roles = "Admin")]
public async Task CreateNextMeeting(CreateMeetingDto meetingDto)
{
var previousMeeting = await dbContext.Meetings.FindAsync(meetingDto.PreviousMeetingId);
if (!meetingDto.PreviousMeetingId.HasValue)
{
await this.Error($"Previous meeting id is required.");
return;
}

var previousMeeting = await LiveMeetingHubExtensions.GetMeeting(dbContext, meetingDto.PreviousMeetingId.Value);

if (previousMeeting is null)
{
Expand All @@ -109,15 +115,16 @@ public async Task CreateNextMeeting(CreateMeetingDto meetingDto)
dbContext.Meetings.Add(meeting);
await dbContext.SaveChangesAsync();

var meetingResponseDto = mapper.Map<MeetingDto>(meeting);
var previousMeetingDto = mapper.Map<MeetingDto>(previousMeeting);
var newMeetingDto = mapper.Map<MeetingDto>(meeting);

await this.Clients
.All
.SendAsync(ClientMethods.MeetingUpdate, previousMeeting, this.Context.ConnectionId);
.SendAsync(ClientMethods.MeetingUpdate, previousMeetingDto, this.Context.ConnectionId);

await this.Clients
.All
.SendAsync(ClientMethods.MeetingUpdate, meetingResponseDto, this.Context.ConnectionId);
.SendAsync(ClientMethods.MeetingUpdate, newMeetingDto, this.Context.ConnectionId);
}

[Authorize(Roles = "Admin")]
Expand Down

0 comments on commit ed8f35b

Please sign in to comment.