From b8687e7fb6ec51f1863967b3c8147d542249128b Mon Sep 17 00:00:00 2001 From: Craig Shearer Date: Sat, 3 Jun 2023 15:56:43 +1200 Subject: [PATCH] Messages working Change inline style language to scss to make styling work! --- apps/fe-demo/project.json | 1 + libs/main-ui/src/lib/demo.component.ts | 80 ++++++++++----------- libs/main-ui/src/lib/messenger.component.ts | 38 ++++++++-- libs/rest/.eslintrc.json | 33 +++++++++ libs/rest/README.md | 7 ++ libs/rest/jest.config.ts | 22 ++++++ libs/rest/project.json | 31 ++++++++ libs/rest/src/index.ts | 2 + libs/rest/src/lib/message.service.ts | 29 ++++++++ libs/rest/src/lib/rest.module.ts | 7 ++ libs/rest/src/test-setup.ts | 8 +++ libs/rest/tsconfig.json | 29 ++++++++ libs/rest/tsconfig.lib.json | 12 ++++ libs/rest/tsconfig.spec.json | 11 +++ tsconfig.base.json | 1 + 15 files changed, 264 insertions(+), 47 deletions(-) create mode 100644 libs/rest/.eslintrc.json create mode 100644 libs/rest/README.md create mode 100644 libs/rest/jest.config.ts create mode 100644 libs/rest/project.json create mode 100644 libs/rest/src/index.ts create mode 100644 libs/rest/src/lib/message.service.ts create mode 100644 libs/rest/src/lib/rest.module.ts create mode 100644 libs/rest/src/test-setup.ts create mode 100644 libs/rest/tsconfig.json create mode 100644 libs/rest/tsconfig.lib.json create mode 100644 libs/rest/tsconfig.spec.json diff --git a/apps/fe-demo/project.json b/apps/fe-demo/project.json index 7fd843b..262b407 100644 --- a/apps/fe-demo/project.json +++ b/apps/fe-demo/project.json @@ -14,6 +14,7 @@ "index": "apps/fe-demo/src/index.html", "main": "apps/fe-demo/src/main.ts", "polyfills": ["zone.js"], + "inlineStyleLanguage": "scss", "tsConfig": "apps/fe-demo/tsconfig.app.json", "assets": ["apps/fe-demo/src/favicon.ico", "apps/fe-demo/src/assets"], "styles": ["@angular/material/prebuilt-themes/deeppurple-amber.css", "apps/fe-demo/src/styles.css"], diff --git a/libs/main-ui/src/lib/demo.component.ts b/libs/main-ui/src/lib/demo.component.ts index 13fc82f..99699ad 100644 --- a/libs/main-ui/src/lib/demo.component.ts +++ b/libs/main-ui/src/lib/demo.component.ts @@ -1,17 +1,17 @@ import { CommonModule } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatToolbarModule } from '@angular/material/toolbar'; import { ComponentStore } from '@ngrx/component-store'; import { Message } from '@rxjs-ws-demo/api-interfaces'; import { SocketService, SocketStatsStore } from '@rxjs-ws-demo/web-sockets'; -import { Observable, Subject, skip, switchMap, takeUntil, tap } from 'rxjs'; -import { ConnectionStatusComponent } from './connection-status.component'; -import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; +import { Observable, Subject, skip, tap } from 'rxjs'; import { ClientConnectionWatcherComponent } from './client-connection-watcher.component'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { FormsModule } from '@angular/forms'; +import { ConnectionStatusComponent } from './connection-status.component'; import { MessengerComponent } from './messenger.component'; interface DemoState { @@ -172,39 +172,39 @@ export class DemoComponent extends ComponentStore { ), ); - readonly subscribe = this.effect((trigger$) => - trigger$.pipe( - switchMap(() => { - return this.socketService.subscribeToEventType('message').pipe( - takeUntil(this.endSub$), - tap((data) => { - console.log('data - via WS event', data); - }), - ); - }), - ), - ); - - readonly subscribeConnects = this.effect((trigger$) => - trigger$.pipe( - switchMap(() => { - return this.socketService.subscribeToEventType('connect').pipe( - takeUntil(this.endSub$), - tap((data) => { - console.log('connect event', data); - }), - ); - }), - ), - ); - - readonly postMessage = this.effect((trigger$) => - trigger$.pipe( - switchMap(() => { - return this.http.post('/api/message', { - message: 'Hello from Angular', - }); - }), - ), - ); + // readonly subscribe = this.effect((trigger$) => + // trigger$.pipe( + // switchMap(() => { + // return this.socketService.subscribeToEventType('message').pipe( + // takeUntil(this.endSub$), + // tap((data) => { + // console.log('data - via WS event', data); + // }), + // ); + // }), + // ), + // ); + + // readonly subscribeConnects = this.effect((trigger$) => + // trigger$.pipe( + // switchMap(() => { + // return this.socketService.subscribeToEventType('connect').pipe( + // takeUntil(this.endSub$), + // tap((data) => { + // console.log('connect event', data); + // }), + // ); + // }), + // ), + // ); + + // readonly postMessage = this.effect((trigger$) => + // trigger$.pipe( + // switchMap(() => { + // return this.http.post('/api/message', { + // message: 'Hello from Angular', + // }); + // }), + // ), + // ); } diff --git a/libs/main-ui/src/lib/messenger.component.ts b/libs/main-ui/src/lib/messenger.component.ts index 9ada96c..0fd687c 100644 --- a/libs/main-ui/src/lib/messenger.component.ts +++ b/libs/main-ui/src/lib/messenger.component.ts @@ -10,6 +10,7 @@ import { ComponentStore } from '@ngrx/component-store'; import { SocketService } from '@rxjs-ws-demo/web-sockets'; import { Observable, switchMap, tap, withLatestFrom } from 'rxjs'; import { MatInputModule } from '@angular/material/input'; +import { MessageService } from '@rxjs-ws-demo/rest'; type MessengerState = { messages: string[]; @@ -44,7 +45,7 @@ const MAX_MESSAGES = 100;

Sender

- + Message @@ -88,13 +89,33 @@ const MAX_MESSAGES = 100; > div { flex: 1; } + + form.message-form { + width: 100%; + display: flex; + align-items: baseline; + gap: 8px; + } + + h2 { + margin: 0; + margin-bottom: 8px; + + font-size: 1rem; + font-weight: 500; + } + + .no-messages { + font-size: 0.8rem; + opacity: 0.8; + } } - } - button#close-button { - position: absolute; - right: 0; - top: 0; + button#close-button { + position: absolute; + right: 0; + top: 0; + } } `, ], @@ -102,6 +123,7 @@ const MAX_MESSAGES = 100; }) export class MessengerComponent extends ComponentStore { protected socketService = inject(SocketService); + private messageService = inject(MessageService); @Output() closed = new EventEmitter(); @@ -126,7 +148,7 @@ export class MessengerComponent extends ComponentStore { readonly sendMessage = this.effect((message$: Observable) => message$.pipe( tap((message) => { - console.log('Sending message', message); + this.messageService.sendMessage(message); }), ), ); @@ -135,5 +157,7 @@ export class MessengerComponent extends ComponentStore { super({ messages: [], }); + + this.listenForMessages(); } } diff --git a/libs/rest/.eslintrc.json b/libs/rest/.eslintrc.json new file mode 100644 index 0000000..e36f04c --- /dev/null +++ b/libs/rest/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "rxjsWsDemo", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "rxjs-ws-demo", + "style": "kebab-case" + } + ] + }, + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"] + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/libs/rest/README.md b/libs/rest/README.md new file mode 100644 index 0000000..9f16d3b --- /dev/null +++ b/libs/rest/README.md @@ -0,0 +1,7 @@ +# rest + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test rest` to execute the unit tests. diff --git a/libs/rest/jest.config.ts b/libs/rest/jest.config.ts new file mode 100644 index 0000000..c39b521 --- /dev/null +++ b/libs/rest/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'rest', + preset: '../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../coverage/libs/rest', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/libs/rest/project.json b/libs/rest/project.json new file mode 100644 index 0000000..8700232 --- /dev/null +++ b/libs/rest/project.json @@ -0,0 +1,31 @@ +{ + "name": "rest", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/rest/src", + "prefix": "rxjs-ws-demo", + "tags": [], + "projectType": "library", + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/rest/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/rest/**/*.ts", "libs/rest/**/*.html"] + } + } + } +} diff --git a/libs/rest/src/index.ts b/libs/rest/src/index.ts new file mode 100644 index 0000000..8a34b42 --- /dev/null +++ b/libs/rest/src/index.ts @@ -0,0 +1,2 @@ +export * from './lib/rest.module'; +export * from './lib/message.service'; diff --git a/libs/rest/src/lib/message.service.ts b/libs/rest/src/lib/message.service.ts new file mode 100644 index 0000000..cc2fe69 --- /dev/null +++ b/libs/rest/src/lib/message.service.ts @@ -0,0 +1,29 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable, inject } from '@angular/core'; +import { ComponentStore } from '@ngrx/component-store'; +import { Observable, switchMap } from 'rxjs'; + +type MessageServiceState = { + messageCount: number; +}; + +@Injectable({ + providedIn: 'root', +}) +export class MessageService extends ComponentStore { + private http = inject(HttpClient); + + readonly sendMessage = this.effect((message$: Observable) => + message$.pipe( + switchMap((message) => { + return this.http.post('/api/message', { message }); + }), + ), + ); + + constructor() { + super({ + messageCount: 0, + }); + } +} diff --git a/libs/rest/src/lib/rest.module.ts b/libs/rest/src/lib/rest.module.ts new file mode 100644 index 0000000..a342e80 --- /dev/null +++ b/libs/rest/src/lib/rest.module.ts @@ -0,0 +1,7 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [CommonModule], +}) +export class RestModule {} diff --git a/libs/rest/src/test-setup.ts b/libs/rest/src/test-setup.ts new file mode 100644 index 0000000..b2dd6e9 --- /dev/null +++ b/libs/rest/src/test-setup.ts @@ -0,0 +1,8 @@ +// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment +globalThis.ngJest = { + testEnvironmentOptions: { + errorOnUnknownElements: true, + errorOnUnknownProperties: true, + }, +}; +import 'jest-preset-angular/setup-jest'; diff --git a/libs/rest/tsconfig.json b/libs/rest/tsconfig.json new file mode 100644 index 0000000..bd46556 --- /dev/null +++ b/libs/rest/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/libs/rest/tsconfig.lib.json b/libs/rest/tsconfig.lib.json new file mode 100644 index 0000000..3d5a9aa --- /dev/null +++ b/libs/rest/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/libs/rest/tsconfig.spec.json b/libs/rest/tsconfig.spec.json new file mode 100644 index 0000000..457941b --- /dev/null +++ b/libs/rest/tsconfig.spec.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 59823e9..58e2591 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -17,6 +17,7 @@ "paths": { "@rxjs-ws-demo/api-interfaces": ["libs/api-interfaces/src/index.ts"], "@rxjs-ws-demo/main-ui": ["libs/main-ui/src/index.ts"], + "@rxjs-ws-demo/rest": ["libs/rest/src/index.ts"], "@rxjs-ws-demo/utils": ["libs/utils/src/index.ts"], "@rxjs-ws-demo/web-sockets": ["libs/web-sockets/src/index.ts"] }