diff --git a/SessionCompanion/SessionCompanion/ClientApp/package-lock.json b/SessionCompanion/SessionCompanion/ClientApp/package-lock.json index b59a411..c6b1e3f 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/package-lock.json +++ b/SessionCompanion/SessionCompanion/ClientApp/package-lock.json @@ -8674,6 +8674,21 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, + "ng-dynamic-component": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ng-dynamic-component/-/ng-dynamic-component-8.0.1.tgz", + "integrity": "sha512-Ak25QTYmjNVxyZ6ywqRDDjoqAJheFeK0XoHsomwVjdHSiLoQcGfNNj5z51pqoRGpjdDZMSV+J2gaCbRNBeiy3g==", + "requires": { + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } + } + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", diff --git a/SessionCompanion/SessionCompanion/ClientApp/package.json b/SessionCompanion/SessionCompanion/ClientApp/package.json index ca095c7..cec8400 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/package.json +++ b/SessionCompanion/SessionCompanion/ClientApp/package.json @@ -32,6 +32,7 @@ "core-js": "^3.3.3", "hammerjs": "^2.0.8", "jquery": "3.4.1", + "ng-dynamic-component": "^8.0.1", "oidc-client": "^1.9.1", "popper.js": "^1.16.0", "rpg-awesome": "^0.2.0", diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts index 85aee6f..5ab0034 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/app.module.ts @@ -27,6 +27,7 @@ import { MatSortModule, MatDialogModule, MatTooltipModule, + MatSnackBarModule, } from '@angular/material'; import { UserService } from '../services/user.service'; import { StoreModule } from '@ngrx/store'; @@ -50,6 +51,10 @@ import { GameMasterMonstersTableComponent } from './components/game-master-monst import { MonsterService } from '../services/monster.service'; import { SpellDetailsDialogComponent } from './components/spell-details-dialog/spell-details-dialog.component'; import { GameMasterShopkeepersTableComponent } from './components/game-master-shopkeepers-table/game-master-shopkeepers-table.component'; +import { SendMessageActionComponent } from './components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component'; +import { DynamicModule } from 'ng-dynamic-component'; +import { SnackbarComponent } from './shared/snackbar/snackbar.component'; +import { MessageDialogComponent } from './shared/message-dialog/message-dialog.component'; import { GameMasterTurntrackerComponent } from './components/game-master-turntracker/game-master-turntracker.component'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.component'; @@ -73,6 +78,9 @@ import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog GameMasterMonstersTableComponent, SpellDetailsDialogComponent, GameMasterShopkeepersTableComponent, + SendMessageActionComponent, + SnackbarComponent, + MessageDialogComponent, GameMasterTurntrackerComponent, ChooseMonsterDialogComponent, ], @@ -103,6 +111,8 @@ import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog MatSortModule, MatTooltipModule, MatRadioModule, + DynamicModule, + MatSnackBarModule, DragDropModule, ], providers: [ @@ -125,6 +135,9 @@ import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog ThrowPrimaryAbilityComponent, SpellDetailsDialogComponent, GameMasterShopkeepersTableComponent, + SendMessageActionComponent, + SnackbarComponent, + MessageDialogComponent, GameMasterTurntrackerComponent, ChooseMonsterDialogComponent, ], diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.css new file mode 100644 index 0000000..66e070b --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.css @@ -0,0 +1,36 @@ +.send-message-main { + display: flex; + flex-wrap: wrap; +} + +.send-message-main > mat-form-field { + margin-left: auto; + margin-right: auto; + width: 80%; +} + +.message-textarea { + height: 150px; +} + +.break { + flex-basis: 100%; + height: 0; +} + +.send-message-actions { + margin-left: auto; +} + +.send-message-actions > button { + margin-right: 20px; + margin-left: 20px; +} + +.no-focus:focus { + outline: none; +} + +.send-button { + color: darkseagreen; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.html new file mode 100644 index 0000000..847acea --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.html @@ -0,0 +1,11 @@ +
+ + Message + + +
+
+ + +
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.ts new file mode 100644 index 0000000..a829ac7 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/actions-components/send-message-action/send-message-action.component.ts @@ -0,0 +1,28 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { GMSignalRService } from '../../../../shared/signalR-service/gm-signalR.service'; + +@Component({ + selector: 'app-send-message-action', + templateUrl: './send-message-action.component.html', + styleUrls: ['./send-message-action.component.css'], +}) +export class SendMessageActionComponent implements OnInit { + @Input() characterId: any; + + @Output() + closeComponent = new EventEmitter(); + + constructor(private signalRService: GMSignalRService) {} + + ngOnInit() {} + + SendMessage(message: string) { + debugger; + this.signalRService.SendMessageToPlayer(this.characterId, message); + this.Close(); + } + + Close() { + this.closeComponent.emit(); + } +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.css index 411b4bb..e179d19 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.css +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.css @@ -10,3 +10,8 @@ box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2), 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 5px 20px 4px #d8d8d8; } + +.after-name-divider { + border-top-width: 3px; + margin-bottom: 20px; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.html index 9445b81..d1c74d5 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.html +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.html @@ -1,5 +1,16 @@

{{characterName}}

+
+
+
+ +
+
+ + +
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.ts index ac8b921..b3f457b 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-character-actions-dialog/game-master-character-actions-dialog.component.ts @@ -1,5 +1,6 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject, Injector, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { SendMessageActionComponent } from './actions-components/send-message-action/send-message-action.component'; @Component({ selector: 'app-game-master-character-actions-dialog', @@ -9,6 +10,17 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; export class GameMasterCharacterActionsDialogComponent implements OnInit { characterId: number; characterName: string; + actionComponentName; + availableActions: { name: string; componentName: string }[] = [ + { + name: 'Send Message', + componentName: 'SendMessageActionComponent', + }, + ]; + inputs: { characterId: number }; + outputs: any = { + closeComponent: () => this.ChangeActionComponent(null), + }; constructor( public dialogRef: MatDialogRef, @@ -18,5 +30,17 @@ export class GameMasterCharacterActionsDialogComponent implements OnInit { ngOnInit() { this.characterId = this.data.characterid; this.characterName = this.data.characterName; + this.inputs = { characterId: this.characterId }; + console.log(this.inputs); + } + + ChangeActionComponent(componentName: string): void { + switch (componentName) { + case 'SendMessageActionComponent': + this.actionComponentName = SendMessageActionComponent; + break; + default: + this.actionComponentName = null; + } } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts index 78f106c..e95e629 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/game-master-dashboard/game-master-dashboard.component.ts @@ -83,7 +83,15 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy { rightSidenavExpanded = false; rightSidenavTextExpanded = false; - loggedCharacters: LoggedCharactersViewModel[]; + loggedCharacters: LoggedCharactersViewModel[] = [ + { + class: 'paladin', + id: 2, + name: 'Test', + currentHealthPoints: 5, + level: 1, + }, + ]; constructor( private store: Store, diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts index 1ed96bf..fd7c631 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/components/player-dashboard/player-dashboard.component.ts @@ -4,9 +4,11 @@ import { first } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from 'src/app/store/models/app-state.model'; import { AbilitiesComponent } from '../abilities/abilities.component'; -import {ClearStore, ClearUserId} from '../../store/actions/app.actions'; +import { ClearStore, ClearUserId } from '../../store/actions/app.actions'; import { Router } from '@angular/router'; -import {ClearCharacterId} from "../../store/actions/player.action"; +import { ClearCharacterId } from '../../store/actions/player.action'; +import { MatSnackBar } from '@angular/material'; +import { SnackbarComponent } from '../../shared/snackbar/snackbar.component'; @Component({ selector: 'app-player-dashboard', @@ -18,17 +20,26 @@ export class PlayerDashboardComponent implements OnInit { isExpanded = false; selected = false; - constructor(private signalRService: PlayerSignalRService, private store: Store, private router: Router) {} + constructor( + private signalRService: PlayerSignalRService, + private store: Store, + private router: Router, + private _snackBar: MatSnackBar + ) {} ngOnInit() { - this.store.select(s => s.playerStore.characterId).pipe(first()).subscribe((id) => { - this.signalRService.Login(id); - this.SwitchMiddleComponent('AbilitiesComponent'); - }); + this.store + .select((s) => s.playerStore.characterId) + .pipe(first()) + .subscribe((id) => { + this.SubscribeToEvents(); + this.signalRService.Login(id); + this.SwitchMiddleComponent('AbilitiesComponent'); + }); } toggle() { - this.isExpanded = !this.isExpanded; + this.isExpanded = !this.isExpanded; } SwitchMiddleComponent(componentName: string) { @@ -43,4 +54,23 @@ export class PlayerDashboardComponent implements OnInit { this.store.dispatch(new ClearStore()); this.router.navigate(['/']); } + + private SubscribeToEvents(): void { + this.signalRService.runMethod.subscribe( + (result: { methodName: string; parameters }) => { + switch (result.methodName) { + case 'MessageFromGameMaster': + this._snackBar.openFromComponent(SnackbarComponent, { + horizontalPosition: 'end', + verticalPosition: 'top', + data: { + message: 'New message from GM', + methodName: result.methodName, + gmMessage: result.parameters.message, + }, + }); + } + } + ); + } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.css new file mode 100644 index 0000000..7ebd57a --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.css @@ -0,0 +1,11 @@ +::ng-deep .mat-dialog-container { + background-color: #4a5867; + color: whitesmoke; + box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2), + 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 5px 20px 4px #d8d8d8; +} + +.message-dialog-title { + font: 15px/20px Roboto, 'Helvetica Neue', sans-serif; + text-align: justify; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.html new file mode 100644 index 0000000..8f5d4ab --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.html @@ -0,0 +1,3 @@ +
+ {{data.message}} +
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.ts new file mode 100644 index 0000000..2d489b1 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/message-dialog/message-dialog.component.ts @@ -0,0 +1,16 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; + +@Component({ + selector: 'app-message-dialog', + templateUrl: './message-dialog.component.html', + styleUrls: ['./message-dialog.component.css'], +}) +export class MessageDialogComponent implements OnInit { + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any + ) {} + + ngOnInit() {} +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts index 08cf425..db03980 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/gm-signalR.service.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@angular/core'; import { SignalRService } from './base/signalR.service'; -import {Subject} from 'rxjs'; +import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class GMSignalRService { @@ -16,16 +16,24 @@ export class GMSignalRService { public Login() { this.signalR.startConnection(); - this.signalR.connectionEstablished$.subscribe(() => { - if (this.signalR.connectionEstablished$.getValue() === true) { - this.signalR.hubConnection.send('GameMasterLogin'); - } - }).unsubscribe(); + this.signalR.connectionEstablished$ + .subscribe(() => { + if (this.signalR.connectionEstablished$.getValue() === true) { + this.signalR.hubConnection.send('GameMasterLogin'); + } + }) + .unsubscribe(); + } + + public SendMessageToPlayer(characterId: number, message: string) { + this.signalR.hubConnection + .send('SendMessageToPlayer', characterId, message) + .catch((err) => console.error(err)); } private registerOnServerEvents(): void { this.signalR.hubConnection.on('Welcome', (message: string) => { - this.message.next('New player connected'); + this.message.next('New player connected'); }); this.signalR.hubConnection.on('GoodBye', (message: string) => { this.message.next('Player disconnected'); diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts index cbe292f..4216e7f 100644 --- a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/signalR-service/player-signalR.service.ts @@ -1,12 +1,15 @@ import { Inject, Injectable } from '@angular/core'; import { SignalRService } from './base/signalR.service'; +import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class PlayerSignalRService { signalR: SignalRService; + runMethod: Subject<{ methodName: string; parameters: {} }>; constructor(@Inject('BASE_URL') baseUrl: string) { this.signalR = new SignalRService(baseUrl); + this.runMethod = new Subject<{ methodName: string; parameters: {} }>(); this.registerOnServerEvents(); } @@ -21,5 +24,14 @@ export class PlayerSignalRService { } private registerOnServerEvents(): void { + this.signalR.hubConnection.on( + 'MessageFromGameMaster', + (message: string) => { + this.runMethod.next({ + methodName: 'MessageFromGameMaster', + parameters: { message: message }, + }); + } + ); } } diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.css b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.css new file mode 100644 index 0000000..c81cb82 --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.css @@ -0,0 +1,5 @@ +.flex { + display: flex; + align-items: baseline; + justify-content: space-between; +} diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.html b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.html new file mode 100644 index 0000000..7a903dc --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.html @@ -0,0 +1,11 @@ +
+
{{message}}
+
+ + +
+
diff --git a/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.ts b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.ts new file mode 100644 index 0000000..3764c7f --- /dev/null +++ b/SessionCompanion/SessionCompanion/ClientApp/src/app/shared/snackbar/snackbar.component.ts @@ -0,0 +1,41 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { + MAT_SNACK_BAR_DATA, + MatDialog, + MatSnackBarRef, +} from '@angular/material'; +import { MessageDialogComponent } from '../message-dialog/message-dialog.component'; + +@Component({ + selector: 'app-snackbar', + templateUrl: './snackbar.component.html', + styleUrls: ['./snackbar.component.css'], +}) +export class SnackbarComponent implements OnInit { + message: string = ''; + constructor( + public snackBarRef: MatSnackBarRef, + @Inject(MAT_SNACK_BAR_DATA) public data: any, + public dialog: MatDialog + ) {} + + ngOnInit() { + this.message = this.data.message; + } + + ClickAction() { + switch (this.data.methodName) { + case 'MessageFromGameMaster': + this.ShowMessageFromGM(); + break; + } + } + + ShowMessageFromGM() { + this.dialog.open(MessageDialogComponent, { + height: '500px', + data: { message: this.data.gmMessage }, + }); + this.snackBarRef.dismiss(); + } +}