Implemented features.

This commit is contained in:
Daniel Scheidle
2022-11-09 19:13:18 +01:00
parent 843def9ecd
commit 5f46bd167f
34 changed files with 460 additions and 104 deletions

View File

@@ -0,0 +1,12 @@
.mat-card {
margin: 1rem 0;
height: 14rem;
line-height: 2rem;
font-size: 16px;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto;
padding: 10px;
}

View File

@@ -0,0 +1,21 @@
<mat-card *ngIf="loaded; else loading">
<ng-container>
<mat-card-title>{{company.description}} ({{company.symbol}})</mat-card-title>
<mat-card-content>
<div class="grid-container content">
<div class="grid-item" *ngFor="let insiderSentiment of insiderSentiments ">
<app-sentiment [month]="insiderSentiment.month"
[change]="insiderSentiment.change"
[mspr]="insiderSentiment.mspr"></app-sentiment>
</div>
</div>
</mat-card-content>
</ng-container>
</mat-card>
<ng-template #loading>
<mat-card>
<mat-card-title>Loading...</mat-card-title>
<mat-card-content></mat-card-content>
</mat-card>
</ng-template>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SentimentCardComponent } from './sentiment-card.component';
describe('SentimentCardComponent', () => {
let component: SentimentCardComponent;
let fixture: ComponentFixture<SentimentCardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SentimentCardComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(SentimentCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,46 @@
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {Company, InsiderSentimentData} from "../../model/company-data";
import {FinnhubService} from "../../services/finnhub.service";
import {Subscription} from "rxjs";
@Component({
selector: 'app-sentiment-card',
templateUrl: './sentiment-card.component.html',
styleUrls: ['./sentiment-card.component.css']
})
export class SentimentCardComponent implements OnInit, OnDestroy {
@Input()
symbol = '';
loaded = false;
company!: Company;
insiderSentiments!: Array<InsiderSentimentData>;
private loadedSubs = 0;
private subs: Subscription[] = [];
constructor(private finnhubService: FinnhubService) {
}
ngOnInit(): void {
this.subs.push(this.finnhubService.getCompany(this.symbol).subscribe(value => {
this.company = value;
this.loaded = ++this.loadedSubs == this.subs.length;
}));
let current = new Date()
let from = new Date(current.getFullYear(), current.getMonth() - 3, 1);
let to = new Date(current.getFullYear(), current.getMonth() - 1, 1);
this.subs.push(this.finnhubService.getInsideSentiment(this.symbol, from, to).subscribe(value => {
this.insiderSentiments = value.data;
this.loaded = ++this.loadedSubs == this.subs.length;
}));
}
ngOnDestroy(): void {
this.subs.forEach(s => s.unsubscribe());
}
}

View File

@@ -0,0 +1,10 @@
.grid-container {
display: grid;
grid-template-columns: auto auto;
padding: 10px;
}
.grid-item .label {
font-weight: bold;
margin: 1rem;
}

View File

@@ -0,0 +1,11 @@
<div class="grid-container ">
<div class="grid-item">
<p><span class="label">{{month | month }}</span></p>
<p><span class="label">Change:</span><span class="value">{{change | number: '1.0-0'}}</span></p>
<p><span class="label">MSPR:</span><span class="value">{{mspr | number: '1.2-2'}}</span></p>
</div>
<div class="grid-item">
<app-tendency [value]="change"></app-tendency>
</div>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SentimentComponent } from './sentiment.component';
describe('SentinmentComponent', () => {
let component: SentimentComponent;
let fixture: ComponentFixture<SentimentComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SentimentComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(SentimentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,25 @@
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-sentiment',
templateUrl: './sentiment.component.html',
styleUrls: ['./sentiment.component.css']
})
export class SentimentComponent implements OnInit {
@Input()
month!: number;
@Input()
change!: number;
@Input()
mspr!: number;
constructor() { }
ngOnInit(): void {
}
}

View File

@@ -1,16 +1,24 @@
.mat-card {
margin: 1rem;
margin: 1rem 0;
height: 14rem;
line-height: 2rem;
font-size: 16px;
}
.mat-card-title .mat-icon {
a.remove {
cursor: pointer;
float: right;
}
.mat-grid-tile .mat-icon {
font-size: 4rem;
height: 4rem;
width: 4rem;
.grid-container {
display: grid;
grid-template-columns: auto auto;
padding: 10px;
}
.grid-item .label {
font-weight: bold;
margin: 1rem;
}

View File

@@ -1,27 +1,54 @@
<mat-card>
<mat-card *ngIf="loaded; else loading">
<mat-card-title>{{company.description}} ({{company.symbol}})
<mat-icon (click)="remove()" fontIcon="close"></mat-icon>
<a (click)="remove()" id="{{'remove'+ company.symbol}}" class="remove">
<mat-icon fontIcon="close"></mat-icon>
</a>
</mat-card-title>
<mat-card-content>
<ng-container *ngIf="getQuote() | async; let quote">
<mat-grid-list cols="4" rowHeight="4:1">
<mat-grid-tile colspan="2"></mat-grid-tile>
<mat-grid-tile colspan="2" rowspan="3">
<mat-icon *ngIf="quote.dp>0" color="primary" fontIcon="arrow_upward"></mat-icon>
<mat-icon *ngIf="quote.dp<0" color="warn" fontIcon="arrow_downward"></mat-icon>
<mat-icon *ngIf="quote.dp==0" fontIcon="east"></mat-icon>
</mat-grid-tile>
<div class="grid-container content">
<div class="grid-item">
<div class="grid-container values">
<div class="grid-item">
<span class="label">Change today:</span>
<span class="value">{{quote.dp / 100 | percent: '1.1-1'}}</span>
</div>
<div class="grid-item">
<span class="label">Opening price:</span>
<span class="value">{{quote.o | currency: 'USD'}}</span>
</div>
<div class="grid-item">
<span class="label">Current price:</span>
<span class="value">{{quote.c | currency: 'USD'}}</span>
</div>
<div class="grid-item">
<span class="label">High price:</span>
<span class="value">{{quote.h | currency: 'USD'}}</span>
</div>
<mat-grid-tile><p>Change today: {{quote.dp / 100 | percent: '1.1-1'}}</p></mat-grid-tile>
<mat-grid-tile><p>Opening price: {{quote.o | currency: 'USD'}}</p></mat-grid-tile>
<mat-grid-tile><p>Current price: {{quote.c | currency: 'USD'}}</p></mat-grid-tile>
<mat-grid-tile><p>High price: {{quote.h | currency: 'USD'}}</p></mat-grid-tile>
</mat-grid-list>
</ng-container>
</div>
</div>
<div class="grid-item">
<app-tendency [value]="quote.dp"></app-tendency>
</div>
</div>
</mat-card-content>
<mat-card-actions align="end">
<button mat-button [routerLink]="'/sentiment/' + company.symbol">Go to social sentiment details</button>
<button mat-button
id="{{'sentiment'+ company.symbol}}"
[routerLink]="'/sentiment/' + symbol">Go to social sentiment details
</button>
</mat-card-actions>
</mat-card>
<ng-template #loading>
<mat-card>
<mat-card-title>Loading...</mat-card-title>
<mat-card-content></mat-card-content>
</mat-card>
</ng-template>

View File

@@ -1,7 +1,7 @@
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {FinnhubService} from "../../services/finnhub.service";
import {Company, QuoteResponse} from "../../model/company-data";
import {Subject, Subscription} from "rxjs";
import {Subscription} from "rxjs";
import {StorageService} from "../../services/storage.service";
@Component({
@@ -12,9 +12,14 @@ import {StorageService} from "../../services/storage.service";
export class StockCardComponent implements OnInit, OnDestroy {
@Input()
company = {} as Company;
symbol = '';
private _quote$ = new Subject<QuoteResponse>();
loaded = false;
company!: Company;
quote!: QuoteResponse;
private loadedSubs = 0;
private subs: Subscription[] = [];
constructor(public finnhubService: FinnhubService,
@@ -22,19 +27,22 @@ export class StockCardComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
this.subs.push(this.finnhubService.getQuote(this.company.symbol).subscribe(value => this._quote$.next(value)));
this.subs.push(this.finnhubService.getCompany(this.symbol).subscribe(value => {
this.company = value;
this.loaded = ++this.loadedSubs == this.subs.length;
}));
this.subs.push(this.finnhubService.getQuote(this.symbol).subscribe(value => {
this.quote = value;
this.loaded = ++this.loadedSubs == this.subs.length;
}));
}
getQuote(): Subject<QuoteResponse> {
return this._quote$;
}
ngOnDestroy(): void {
this.subs.forEach(s => s.unsubscribe());
this._quote$.complete();
}
remove() {
this.storageService.remove(this.company.symbol);
this.storageService.remove(this.symbol);
}
}

View File

@@ -0,0 +1,6 @@
.mat-icon {
font-size: 6rem;
height: 100%;
width: 100%;
text-align: center;
}

View File

@@ -0,0 +1,3 @@
<mat-icon *ngIf="value>0" color="primary" fontIcon="arrow_upward"></mat-icon>
<mat-icon *ngIf="value<0" color="warn" fontIcon="arrow_downward"></mat-icon>
<mat-icon *ngIf="value==0" fontIcon="east"></mat-icon>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TendencyComponent } from './tendency.component';
describe('TendencyComponent', () => {
let component: TendencyComponent;
let fixture: ComponentFixture<TendencyComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TendencyComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TendencyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,19 @@
import {Component, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-tendency',
templateUrl: './tendency.component.html',
styleUrls: ['./tendency.component.css']
})
export class TendencyComponent implements OnInit {
@Input()
value!: number;
constructor() { }
ngOnInit(): void {
}
}