diff --git a/VirtualMind.Application/Queries/GetCurrencyExchangeQuery.cs b/VirtualMind.Application/Queries/GetCurrencyExchangeQuery.cs index cd6a3b0..b655001 100644 --- a/VirtualMind.Application/Queries/GetCurrencyExchangeQuery.cs +++ b/VirtualMind.Application/Queries/GetCurrencyExchangeQuery.cs @@ -1,17 +1,16 @@ -using MediatR; -using System.Collections.Generic; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using VirtualMind.Application.DTOs; +using MediatR; namespace VirtualMind.Application.Queries { - public class GetCurrencyExchangeQuery : IRequest> + public class GetCurrencyExchangeQuery : IRequest { public string CurrencyType { get; set; } } - public class GetCurrencyExchangeHandler : IRequestHandler> + public class GetCurrencyExchangeHandler : IRequestHandler { private readonly ICurrencyExchangeFactory CurrencyExchangeFactory; @@ -20,19 +19,16 @@ public GetCurrencyExchangeHandler(ICurrencyExchangeFactory currencyExchangeFacto CurrencyExchangeFactory = currencyExchangeFactory; } - public async Task> Handle(GetCurrencyExchangeQuery request, CancellationToken cancellationToken) + public async Task Handle(GetCurrencyExchangeQuery request, CancellationToken cancellationToken) { var result = await CurrencyExchangeFactory.GetExchangeRate(request.CurrencyType); - var exchangeList = new List + var exchangeList = new ExchangeRateDTO { - new ExchangeRateDTO - { - Purchase = result[0], - Sale = result[1], - LastUpdate = result[2] - } - }; + Purchase = result[0], + Sale = result[1], + LastUpdate = result[2] + }; return exchangeList; } diff --git a/VirtualMind.WebApp/ClientApp/package-lock.json b/VirtualMind.WebApp/ClientApp/package-lock.json index 9d17c94..6b84f2a 100644 --- a/VirtualMind.WebApp/ClientApp/package-lock.json +++ b/VirtualMind.WebApp/ClientApp/package-lock.json @@ -2566,6 +2566,21 @@ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", "dev": true }, + "@ngrx/store": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-10.1.2.tgz", + "integrity": "sha512-FUjN786ch4Qt9WgJ78ef7Yquq3mPCekgcWgZrs4ycZw1f+KdfTHLTk1bGDtO8A8CzOya5yTT7KhxbdVjbOS5ng==", + "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==" + } + } + }, "@ngtools/webpack": { "version": "8.3.26", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.26.tgz", diff --git a/VirtualMind.WebApp/ClientApp/package.json b/VirtualMind.WebApp/ClientApp/package.json index f90b3e6..56ffeea 100644 --- a/VirtualMind.WebApp/ClientApp/package.json +++ b/VirtualMind.WebApp/ClientApp/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser-dynamic": "8.2.12", "@angular/platform-server": "8.2.12", "@angular/router": "8.2.12", + "@ngrx/store": "^10.1.2", "@nguniversal/module-map-ngfactory-loader": "8.1.1", "aspnet-prerendering": "^3.0.1", "bootstrap": "^4.3.1", diff --git a/VirtualMind.WebApp/ClientApp/src/app/app.module.ts b/VirtualMind.WebApp/ClientApp/src/app/app.module.ts index 908d0c7..1d957ec 100644 --- a/VirtualMind.WebApp/ClientApp/src/app/app.module.ts +++ b/VirtualMind.WebApp/ClientApp/src/app/app.module.ts @@ -6,16 +6,15 @@ import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { NavMenuComponent } from './nav-menu/nav-menu.component'; -import { HomeComponent } from './home/home.component'; -import { CounterComponent } from './counter/counter.component'; import { FetchDataComponent } from './fetch-data/fetch-data.component'; +import { StoreModule } from '@ngrx/store'; +import { QuoteReducer } from './store/quote/quoteReducer'; + @NgModule({ declarations: [ AppComponent, - NavMenuComponent, - HomeComponent, - CounterComponent, + NavMenuComponent, FetchDataComponent ], imports: [ @@ -23,10 +22,12 @@ import { FetchDataComponent } from './fetch-data/fetch-data.component'; HttpClientModule, FormsModule, RouterModule.forRoot([ - { path: '', component: HomeComponent, pathMatch: 'full' }, - { path: 'counter', component: CounterComponent }, - { path: 'fetch-data', component: FetchDataComponent }, - ]) + { path: '', component: FetchDataComponent }, + { path: 'quote', component: FetchDataComponent }, + ]), + StoreModule.forRoot({ + quotes: QuoteReducer + }) ], providers: [], bootstrap: [AppComponent] diff --git a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.html b/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.html deleted file mode 100644 index 89b9c80..0000000 --- a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.html +++ /dev/null @@ -1,7 +0,0 @@ -

Counter

- -

This is a simple example of an Angular component.

- -

Current count: {{ currentCount }}

- - diff --git a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.spec.ts b/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.spec.ts deleted file mode 100644 index 026a91a..0000000 --- a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CounterComponent } from './counter.component'; - -describe('CounterComponent', () => { - let component: CounterComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ CounterComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(CounterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should display a title', async(() => { - const titleText = fixture.nativeElement.querySelector('h1').textContent; - expect(titleText).toEqual('Counter'); - })); - - it('should start with count 0, then increments by 1 when clicked', async(() => { - const countElement = fixture.nativeElement.querySelector('strong'); - expect(countElement.textContent).toEqual('0'); - - const incrementButton = fixture.nativeElement.querySelector('button'); - incrementButton.click(); - fixture.detectChanges(); - expect(countElement.textContent).toEqual('1'); - })); -}); diff --git a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.ts b/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.ts deleted file mode 100644 index 1f336aa..0000000 --- a/VirtualMind.WebApp/ClientApp/src/app/counter/counter.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-counter-component', - templateUrl: './counter.component.html' -}) -export class CounterComponent { - public currentCount = 0; - - public incrementCounter() { - this.currentCount++; - } -} diff --git a/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.html b/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.html index 19b3835..d4fa69e 100644 --- a/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.html +++ b/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.html @@ -1,24 +1,29 @@ -

Weather forecast

+

Quotes

-

This component demonstrates fetching data from the server.

+

Look the quotation of the day

-

Loading...

+
+

DOLAR (USD)

+
+
    +
  • Purchase Value: {{ dolar.purchase }}
  • +
  • Sale Value: {{ dolar.sale }}
  • +
  • Last Update: {{ dolar.lastUpdate }}
  • +
+
+
+ + +
+

REAL (BRL)

+
+
    +
  • Purchase Value: {{ real.purchase }}
  • +
  • Sale Value: {{ real.sale }}
  • +
  • Last Update: {{ real.lastUpdate }}
  • +
+
+
+ + - - - - - - - - - - - - - - - - - -
DateTemp. (C)Temp. (F)Summary
{{ forecast.date }}{{ forecast.temperatureC }}{{ forecast.temperatureF }}{{ forecast.summary }}
diff --git a/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.ts b/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.ts index 9b81e1b..4ebf8c7 100644 --- a/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.ts +++ b/VirtualMind.WebApp/ClientApp/src/app/fetch-data/fetch-data.component.ts @@ -1,23 +1,54 @@ import { Component, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { Store, select } from '@ngrx/store'; +import { quote } from '../models/quote.model'; +import QuoteState from '../store/quote/quoteState'; +import { getDolar, getReal } from '../store/quote/quoteAction'; +import { map } from 'rxjs/operators'; @Component({ selector: 'app-fetch-data', templateUrl: './fetch-data.component.html' }) export class FetchDataComponent { - public forecasts: WeatherForecast[]; - constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) { - http.get(baseUrl + 'weatherforecast').subscribe(result => { - this.forecasts = result; + quote$: Observable; + dolar: quote; + real: quote; + + constructor(private http: HttpClient, + @Inject('BASE_URL') private baseUrl: string, + private store: Store<{ quotes: QuoteState }>) { + this.quote$ = this.store.pipe(select((state: any) => state.quotes)); + this.getAllQuote(); + } + + ngOnInit() { + this.quote$.pipe( + map(x => { + this.dolar = x.dolar; + this.real = x.real; + }) + ) + .subscribe(); + } + + getAllQuote() { + console.log('fetching cote'); + this.getDollarQuote(); + this.getRealQuote(); + } + + getDollarQuote() { + this.http.get(this.baseUrl + 'exchange?currencyType=USD').subscribe(result => { + this.store.dispatch(getDolar({payload: result})); }, error => console.error(error)); } -} -interface WeatherForecast { - date: string; - temperatureC: number; - temperatureF: number; - summary: string; + getRealQuote() { + this.http.get(this.baseUrl + 'exchange?currencyType=BRL').subscribe(result => { + this.store.dispatch(getReal({payload: result})); + }, error => console.error(error)); + } } diff --git a/VirtualMind.WebApp/ClientApp/src/app/home/home.component.html b/VirtualMind.WebApp/ClientApp/src/app/home/home.component.html deleted file mode 100644 index f74c2e7..0000000 --- a/VirtualMind.WebApp/ClientApp/src/app/home/home.component.html +++ /dev/null @@ -1,14 +0,0 @@ -

Hello, world!

-

Welcome to your new single-page application, built with:

- -

To help you get started, we've also set up:

-
    -
  • Client-side navigation. For example, click Counter then Back to return here.
  • -
  • Angular CLI integration. In development mode, there's no need to run ng serve. It runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
  • -
  • Efficient production builds. In production mode, development-time features are disabled, and your dotnet publish configuration automatically invokes ng build to produce minified, ahead-of-time compiled JavaScript files.
  • -
-

The ClientApp subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng command (e.g., ng test), or use npm to install extra packages into it.

diff --git a/VirtualMind.WebApp/ClientApp/src/app/home/home.component.ts b/VirtualMind.WebApp/ClientApp/src/app/home/home.component.ts deleted file mode 100644 index 2747b30..0000000 --- a/VirtualMind.WebApp/ClientApp/src/app/home/home.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-home', - templateUrl: './home.component.html', -}) -export class HomeComponent { -} diff --git a/VirtualMind.WebApp/ClientApp/src/app/models/quote.model.ts b/VirtualMind.WebApp/ClientApp/src/app/models/quote.model.ts new file mode 100644 index 0000000..ee8e042 --- /dev/null +++ b/VirtualMind.WebApp/ClientApp/src/app/models/quote.model.ts @@ -0,0 +1,5 @@ +export interface quote { + purchase: string; + sale: string; + lastUpdate: string; +} \ No newline at end of file diff --git a/VirtualMind.WebApp/ClientApp/src/app/nav-menu/nav-menu.component.html b/VirtualMind.WebApp/ClientApp/src/app/nav-menu/nav-menu.component.html index 5acf5f4..0beb532 100644 --- a/VirtualMind.WebApp/ClientApp/src/app/nav-menu/nav-menu.component.html +++ b/VirtualMind.WebApp/ClientApp/src/app/nav-menu/nav-menu.component.html @@ -26,17 +26,7 @@ [routerLinkActiveOptions]="{ exact: true }" > Home - - - + diff --git a/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteAction.ts b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteAction.ts new file mode 100644 index 0000000..e072996 --- /dev/null +++ b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteAction.ts @@ -0,0 +1,17 @@ +import { Action, createAction, props, createReducer, on } from '@ngrx/store'; +import { quote } from '../../models/quote.model'; + +enum ActionTypes { + GetDolar = 'GetDolar', + GetReal = 'GetReal' +} + +export const getDolar = createAction( + ActionTypes.GetDolar, + props<{payload: quote}>() +) + +export const getReal = createAction( + ActionTypes.GetReal, + props<{payload: quote}>() +) \ No newline at end of file diff --git a/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteReducer.ts b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteReducer.ts new file mode 100644 index 0000000..138f11b --- /dev/null +++ b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteReducer.ts @@ -0,0 +1,22 @@ +import { Action, createReducer, on } from '@ngrx/store'; +import * as QuoteActions from './quoteAction'; +import { quote } from '../../models/quote.model'; +import QuoteState, { initializeState } from './quoteState'; + +export const intialState = initializeState(); + +export const reducer = createReducer( + intialState, + on(QuoteActions.getDolar, (state, action) => ({ + ...state, + dolar: action.payload + })), + on(QuoteActions.getReal, (state, action) => ({ + ...state, + real: action.payload + })) +) + +export function QuoteReducer(state: QuoteState, action: Action) { + return reducer(state, action); +} diff --git a/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteState.ts b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteState.ts new file mode 100644 index 0000000..fe1076b --- /dev/null +++ b/VirtualMind.WebApp/ClientApp/src/app/store/quote/quoteState.ts @@ -0,0 +1,16 @@ +import { quote } from '../../models/quote.model'; + +export default class QuoteState { + dolar: quote; + real: quote; +} + +let initial: quote = { + lastUpdate: "", + purchase: "0", + sale: "0" +} + +export const initializeState = (): QuoteState => { + return { dolar: initial, real: initial }; +}; \ No newline at end of file diff --git a/VirtualMind.WebApp/Controllers/ExchangeController.cs b/VirtualMind.WebApp/Controllers/ExchangeController.cs index 0e6fe57..3474fbc 100644 --- a/VirtualMind.WebApp/Controllers/ExchangeController.cs +++ b/VirtualMind.WebApp/Controllers/ExchangeController.cs @@ -21,7 +21,7 @@ public ExchangeController(IMediator mediator) } [HttpGet] - public async Task> GetExchangeRate([FromQuery]GetCurrencyExchangeQuery getCurrencyExchange) + public async Task GetExchangeRate([FromQuery]GetCurrencyExchangeQuery getCurrencyExchange) { return await _mediator.Send(getCurrencyExchange); }