diff --git a/src/app/account/user.ts b/src/app/account/user.ts index 423f82b..15be229 100644 --- a/src/app/account/user.ts +++ b/src/app/account/user.ts @@ -1,5 +1,6 @@ export class User { id: number; + character: string; username: string; email: string; token: string; diff --git a/src/app/game/chat/chat.component.css b/src/app/chat/chat.component.css similarity index 100% rename from src/app/game/chat/chat.component.css rename to src/app/chat/chat.component.css diff --git a/src/app/chat/chat.component.html b/src/app/chat/chat.component.html new file mode 100644 index 0000000..7ae3abf --- /dev/null +++ b/src/app/chat/chat.component.html @@ -0,0 +1,10 @@ +
+
+
+ + +
+
+
+ + diff --git a/src/app/game/chat/chat.component.spec.ts b/src/app/chat/chat.component.spec.ts similarity index 100% rename from src/app/game/chat/chat.component.spec.ts rename to src/app/chat/chat.component.spec.ts diff --git a/src/app/chat/chat.component.ts b/src/app/chat/chat.component.ts new file mode 100644 index 0000000..683ea04 --- /dev/null +++ b/src/app/chat/chat.component.ts @@ -0,0 +1,53 @@ +import { Component, OnInit } from '@angular/core'; + +import { Message } from './message'; +import { SystemMessage } from './entry/entry'; +import { Messages } from './entry/messages/messages'; +import { SocketService } from '../socket/socket.service'; + +@Component({ + selector: 'app-chat', + templateUrl: './chat.component.html', + styleUrls: ['./chat.component.css'] +}) +export class ChatComponent implements OnInit { + + entries = new Array(); + + public addMessage(message: Message): void { + if ((this.entries.length > 0) + && (this.entries[this.entries.length - 1].type === 'messages')) { + let entry = this.entries[this.entries.length - 1] as Messages; + if (entry.character == message.character) { + entry.messages.push(message); + } else { + this.entries.push(new Messages(message)); + } + } else { + this.entries.push(new Messages(message)); + } + window.setTimeout(ChatComponent.scrollToBottom, 5); + } + + public addSystemMessage(message: SystemMessage): void { + this.entries.push(message); + } + + static scrollToBottom() { + const chatLog = document.getElementById('chat-log'); + chatLog.scrollTop = chatLog.scrollHeight; + } + + constructor(private socketService: SocketService) { + socketService.onPublicMessage().subscribe((message: Message) => { + this.addMessage(message); + }); + socketService.onSystemMessage().subscribe((message: SystemMessage) => { + this.addSystemMessage(message); + }) + } + + ngOnInit(): void { + } + +} diff --git a/src/app/chat/chat.module.ts b/src/app/chat/chat.module.ts new file mode 100644 index 0000000..1f50911 --- /dev/null +++ b/src/app/chat/chat.module.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { MatCardModule } from '@angular/material/card'; +import { MatInputModule } from '@angular/material/input'; + +import { ChatComponent } from './chat.component'; +import { SystemMessageComponent } from './entry/system-message/system-message.component'; +import { MessagesComponent } from './entry/messages/messages.component'; +import { InputComponent } from './input/input.component'; + + +@NgModule({ + declarations: [ + ChatComponent, + InputComponent, + MessagesComponent, + SystemMessageComponent + ], + exports: [ + ChatComponent, + ], + imports: [ + CommonModule, + MatCardModule, + MatInputModule + ] +}) +export class ChatModule { } diff --git a/src/app/game/chat/entry/entry.component.css b/src/app/chat/entry/entry.component.css similarity index 100% rename from src/app/game/chat/entry/entry.component.css rename to src/app/chat/entry/entry.component.css diff --git a/src/app/game/chat/entry/entry.spec.ts b/src/app/chat/entry/entry.spec.ts similarity index 50% rename from src/app/game/chat/entry/entry.spec.ts rename to src/app/chat/entry/entry.spec.ts index 40475b1..b89e854 100644 --- a/src/app/game/chat/entry/entry.spec.ts +++ b/src/app/chat/entry/entry.spec.ts @@ -1,7 +1,7 @@ -import { Entry } from './entry'; +import { Messages } from './entry'; describe('Entry', () => { it('should create an instance', () => { - expect(new Entry()).toBeTruthy(); + expect(new Messages()).toBeTruthy(); }); }); diff --git a/src/app/chat/entry/entry.ts b/src/app/chat/entry/entry.ts new file mode 100644 index 0000000..5a4bb8b --- /dev/null +++ b/src/app/chat/entry/entry.ts @@ -0,0 +1,25 @@ +export abstract class Entry { + public timestamp; + + protected constructor() { + this.timestamp = new Date(); + } +} + +export class SystemMessage extends Entry { + + constructor(public message: string, + public severity: SeverityEnum) { + super(); + } + + public get type(): string { + return 'system' + } +} + +export enum SeverityEnum { + info = 'info', + warning = 'warning', + error = 'error', +} diff --git a/src/app/chat/entry/messages/messages.component.css b/src/app/chat/entry/messages/messages.component.css new file mode 100644 index 0000000..7b4953b --- /dev/null +++ b/src/app/chat/entry/messages/messages.component.css @@ -0,0 +1,6 @@ +.eye { + margin-right: 4px; + padding-left: 2px; + padding-right: 2px; + border: solid 1px; +} diff --git a/src/app/game/chat/entry/entry.component.html b/src/app/chat/entry/messages/messages.component.html similarity index 51% rename from src/app/game/chat/entry/entry.component.html rename to src/app/chat/entry/messages/messages.component.html index 767cfd3..e466a56 100644 --- a/src/app/game/chat/entry/entry.component.html +++ b/src/app/chat/entry/messages/messages.component.html @@ -3,13 +3,14 @@
{{entry.character}} -
23:31
+
{{entry.timestamp | date:'HH:mm' }}
- played by {{entry.user}} + {{entry.user}}
- {{message}} +
{{message.message}}
+ {{eye}}→ {{message.result}}
diff --git a/src/app/game/chat/entry/entry.component.spec.ts b/src/app/chat/entry/messages/messages.component.spec.ts similarity index 61% rename from src/app/game/chat/entry/entry.component.spec.ts rename to src/app/chat/entry/messages/messages.component.spec.ts index 50b9247..1683295 100644 --- a/src/app/game/chat/entry/entry.component.spec.ts +++ b/src/app/chat/entry/messages/messages.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { EntryComponent } from './entry.component'; +import { MessagesComponent } from './messages.component'; describe('EntryComponent', () => { - let component: EntryComponent; - let fixture: ComponentFixture; + let component: MessagesComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ EntryComponent ] + declarations: [ MessagesComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(EntryComponent); + fixture = TestBed.createComponent(MessagesComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/chat/entry/messages/messages.component.ts b/src/app/chat/entry/messages/messages.component.ts new file mode 100644 index 0000000..af49633 --- /dev/null +++ b/src/app/chat/entry/messages/messages.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Messages } from './messages'; + +@Component({ + selector: 'app-entry', + templateUrl: './messages.component.html', + styleUrls: ['../entry.component.css', './messages.component.css'] +}) +export class MessagesComponent implements OnInit { + + @Input() entry: Messages; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/chat/entry/messages/messages.spec.ts b/src/app/chat/entry/messages/messages.spec.ts new file mode 100644 index 0000000..1511ef0 --- /dev/null +++ b/src/app/chat/entry/messages/messages.spec.ts @@ -0,0 +1,7 @@ +import { Messages } from './messages'; + +describe('Messages', () => { + it('should create an instance', () => { + expect(new Messages()).toBeTruthy(); + }); +}); diff --git a/src/app/chat/entry/messages/messages.ts b/src/app/chat/entry/messages/messages.ts new file mode 100644 index 0000000..1faa535 --- /dev/null +++ b/src/app/chat/entry/messages/messages.ts @@ -0,0 +1,23 @@ +import { Entry } from '../entry'; +import { Message } from '../../message'; + +export class Messages extends Entry { + public messages: Array = new Array(); + + constructor(message: Message) { + super(); + this.messages.push(message); + } + + public get character(): string { + return this.messages[0].character; + } + + public get type(): string { + return 'messages' + } + + public get user(): string { + return this.messages[0].user; + } +} diff --git a/src/app/chat/entry/system-message/system-message.component.css b/src/app/chat/entry/system-message/system-message.component.css new file mode 100644 index 0000000..edf44af --- /dev/null +++ b/src/app/chat/entry/system-message/system-message.component.css @@ -0,0 +1,3 @@ +.system-avatar { + background-size: cover; +} diff --git a/src/app/chat/entry/system-message/system-message.component.html b/src/app/chat/entry/system-message/system-message.component.html new file mode 100644 index 0000000..18d52e5 --- /dev/null +++ b/src/app/chat/entry/system-message/system-message.component.html @@ -0,0 +1,15 @@ + + +
+ +
+ + {{entry.severity | titlecase}} +
{{entry.timestamp | date:'HH:mm' }}
+
+ System +
+ + {{entry.message}} + +
diff --git a/src/app/chat/entry/system-message/system-message.component.spec.ts b/src/app/chat/entry/system-message/system-message.component.spec.ts new file mode 100644 index 0000000..7d284ce --- /dev/null +++ b/src/app/chat/entry/system-message/system-message.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SystemMessageComponent } from './system-message.component'; + +describe('SystemEntryComponent', () => { + let component: SystemMessageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SystemMessageComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SystemMessageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/chat/entry/system-message/system-message.component.ts b/src/app/chat/entry/system-message/system-message.component.ts new file mode 100644 index 0000000..d5a5e9c --- /dev/null +++ b/src/app/chat/entry/system-message/system-message.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { SystemMessage } from '../entry'; + +@Component({ + selector: 'app-system-entry', + templateUrl: './system-message.component.html', + styleUrls: ['../entry.component.css'] +}) +export class SystemMessageComponent implements OnInit { + + @Input() entry: SystemMessage; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/game/chat/input/input.component.css b/src/app/chat/input/input.component.css similarity index 100% rename from src/app/game/chat/input/input.component.css rename to src/app/chat/input/input.component.css diff --git a/src/app/game/chat/input/input.component.html b/src/app/chat/input/input.component.html similarity index 100% rename from src/app/game/chat/input/input.component.html rename to src/app/chat/input/input.component.html diff --git a/src/app/game/chat/input/input.component.spec.ts b/src/app/chat/input/input.component.spec.ts similarity index 100% rename from src/app/game/chat/input/input.component.spec.ts rename to src/app/chat/input/input.component.spec.ts diff --git a/src/app/chat/input/input.component.ts b/src/app/chat/input/input.component.ts new file mode 100644 index 0000000..efbe7f6 --- /dev/null +++ b/src/app/chat/input/input.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit } from '@angular/core'; + +import { Message } from '../message'; +import { Events } from '../../socket/events-enum'; +import { SocketService } from '../../socket/socket.service'; +import { AccountService } from '../../account/account.service'; + +@Component({ + selector: 'app-input', + templateUrl: './input.component.html', + styleUrls: ['./input.component.css'] +}) +export class InputComponent implements OnInit { + + onEnter(value: string): void { + if (value.length > 0) { + const user = this.accountService.userValue; + const message = new Message(user.character, user.username, value); + this.socketService.send(Events.publicMessage, message); + } + } + + constructor(private accountService: AccountService, + private socketService: SocketService) { } + + ngOnInit(): void { + } + +} diff --git a/src/app/game/chat/message.spec.ts b/src/app/chat/message.spec.ts similarity index 100% rename from src/app/game/chat/message.spec.ts rename to src/app/chat/message.spec.ts diff --git a/src/app/chat/message.ts b/src/app/chat/message.ts new file mode 100644 index 0000000..55c80ca --- /dev/null +++ b/src/app/chat/message.ts @@ -0,0 +1,12 @@ +export class Message { + + public eyes?: Array; + + public result?: number; + + constructor(public character: string, + public user: string, + public message: string) { + + } +} diff --git a/src/app/game/chat/chat.component.html b/src/app/game/chat/chat.component.html deleted file mode 100644 index ac14ea7..0000000 --- a/src/app/game/chat/chat.component.html +++ /dev/null @@ -1,7 +0,0 @@ -
- - -
- - diff --git a/src/app/game/chat/chat.component.ts b/src/app/game/chat/chat.component.ts deleted file mode 100644 index 32d0bc8..0000000 --- a/src/app/game/chat/chat.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { Entry } from './entry/entry'; -import { Message } from './message'; -import { SocketService } from '../../socket/socket.service'; - -@Component({ - selector: 'app-chat', - templateUrl: './chat.component.html', - styleUrls: ['./chat.component.css'] -}) -export class ChatComponent implements OnInit { - - entries = new Array(); - - public addMessage(message: Message): void { - if ((this.entries.length > 0) - && (this.entries[this.entries.length - 1].character == message.sender)) { - this.entries[this.entries.length - 1].messages.push(message.message); - } else { - this.entries.push(new Entry(message.sender, 'Aangular User', message.message)); - } - window.setTimeout(ChatComponent.scrollToBottom, 5); - } - - static scrollToBottom() { - const chatLog = document.getElementById('chat-log'); - chatLog.scrollTop = chatLog.scrollHeight; - } - - constructor(private socketService: SocketService) { - socketService.onTestMessage().subscribe((message: Message) => { - console.log(message); - this.addMessage(message); - }); - } - - ngOnInit(): void { - } - -} diff --git a/src/app/game/chat/entry/entry.component.ts b/src/app/game/chat/entry/entry.component.ts deleted file mode 100644 index cbfb0eb..0000000 --- a/src/app/game/chat/entry/entry.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { Entry } from './entry'; - -@Component({ - selector: 'app-entry', - templateUrl: './entry.component.html', - styleUrls: ['./entry.component.css'] -}) -export class EntryComponent implements OnInit { - - @Input() entry: Entry; - - constructor() { } - - ngOnInit(): void { - } - -} diff --git a/src/app/game/chat/entry/entry.ts b/src/app/game/chat/entry/entry.ts deleted file mode 100644 index 2e61534..0000000 --- a/src/app/game/chat/entry/entry.ts +++ /dev/null @@ -1,10 +0,0 @@ -export class Entry { - - public messages: Array = new Array(); - - constructor(public character: string, - public user: string, - message: string) { - this.messages.push(message); - } -} diff --git a/src/app/game/chat/input/input.component.ts b/src/app/game/chat/input/input.component.ts deleted file mode 100644 index 89aec71..0000000 --- a/src/app/game/chat/input/input.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Message } from '../message'; -import { Events } from '../../../socket/events-enum'; -import { SocketService } from '../../../socket/socket.service'; - -@Component({ - selector: 'app-input', - templateUrl: './input.component.html', - styleUrls: ['./input.component.css'] -}) -export class InputComponent implements OnInit { - - onEnter(value: string): void { - const message = new Message('Aangular Frontend', value); - this.socketService.send(Events.publicMessage, message); - } - - constructor(private socketService: SocketService) { } - - ngOnInit(): void { - } - -} diff --git a/src/app/game/chat/message.ts b/src/app/game/chat/message.ts deleted file mode 100644 index 79860a7..0000000 --- a/src/app/game/chat/message.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class Message { - - constructor(public sender: string, - public message: string) { - - } -} diff --git a/src/app/game/game.module.ts b/src/app/game/game.module.ts index 41d6f36..7fd1b1b 100644 --- a/src/app/game/game.module.ts +++ b/src/app/game/game.module.ts @@ -6,21 +6,16 @@ import { MatCardModule } from '@angular/material/card'; import { GameRoutingModule } from './game-routing.module'; import { GameComponent } from './game.component'; -import { ChatComponent } from './chat/chat.component'; -import { EntryComponent } from './chat/entry/entry.component'; -import { InputComponent } from './chat/input/input.component'; import { NavbarComponent } from './navbar/navbar.component'; import { TestComponent } from './test/test.component'; +import { ChatModule } from '../chat/chat.module'; @NgModule({ declarations: [ GameComponent, NavbarComponent, - ChatComponent, TestComponent, - EntryComponent, - InputComponent, ], exports: [ NavbarComponent @@ -30,6 +25,7 @@ import { TestComponent } from './test/test.component'; GameRoutingModule, FlexModule, MatCardModule, + ChatModule, ] }) export class GameModule { } diff --git a/src/app/socket/events-enum.ts b/src/app/socket/events-enum.ts index f20dfb3..d05b0c2 100644 --- a/src/app/socket/events-enum.ts +++ b/src/app/socket/events-enum.ts @@ -1,3 +1,4 @@ export enum Events { - publicMessage = 'public message' + publicMessage = 'public message', + systemMessage = 'system message', } diff --git a/src/app/socket/socket.service.ts b/src/app/socket/socket.service.ts index 9010f3b..34adbbf 100644 --- a/src/app/socket/socket.service.ts +++ b/src/app/socket/socket.service.ts @@ -3,6 +3,8 @@ import { Observable } from 'rxjs'; import * as socketIo from 'socket.io-client'; import { Events } from './events-enum'; +import { SystemMessage } from '../chat/entry/entry'; +import { Message } from '../chat/message'; const SERVER_URL = 'http://localhost:5005' @@ -26,12 +28,21 @@ export class SocketService implements OnInit { this.socket.emit(event, message); } - public onTestMessage(): Observable { - return new Observable(observer => { + public onPublicMessage(): Observable { + return new Observable(observer => { this.socket.on(Events.publicMessage, (data) => observer.next(data)); }); } + public onSystemMessage(): Observable { + return new Observable(observer => { + this.socket.on(Events.systemMessage, (data: SystemMessage) => { + data = Object.assign(SystemMessage, data); + observer.next(new SystemMessage(data.message, data.severity)); + }); + }); + } + constructor() { this.initSocket(); } diff --git a/src/app/utils/fake-backend.ts b/src/app/utils/fake-backend.ts index dc0a847..782e197 100644 --- a/src/app/utils/fake-backend.ts +++ b/src/app/utils/fake-backend.ts @@ -38,6 +38,7 @@ export class FakeBackend implements HttpInterceptor { return ok({ id: user.id, username: user.username, + character: user.character, token: 'fake-jwt-token', }); } @@ -50,6 +51,7 @@ export class FakeBackend implements HttpInterceptor { } user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1; + user.character = 'placeholder'; users.push(user); localStorage.setItem('users', JSON.stringify(users)); console.log('Register user: ' + user);