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 @@
+
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();
+ }
+}