From b5acc0e0474fea95d6215ae360f13e9ecdbb1d54 Mon Sep 17 00:00:00 2001 From: Vaz-Tiago Date: Sun, 15 May 2022 19:20:01 -0300 Subject: [PATCH] add fetch data on component --- .env.example | 1 + package-lock.json | 173 ++++++++++++++++++++- package.json | 4 +- src/components.d.ts | 2 + src/components/stock-price/stock-price.css | 7 + src/components/stock-price/stock-price.tsx | 68 ++++++-- src/index.html | 2 +- stencil.config.ts | 2 + 8 files changed, 239 insertions(+), 20 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..78e79b4 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +AV_TOKEN= diff --git a/package-lock.json b/package-lock.json index 55a5a46..5ae55c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,11 @@ }, "devDependencies": { "@types/jest": "^27.0.3", + "@types/node": "^17.0.33", "jest": "^27.4.5", "jest-cli": "^27.4.5", - "puppeteer": "^10.0.0" + "puppeteer": "^10.0.0", + "rollup-plugin-dotenv": "^0.3.0" } }, "node_modules/@ampproject/remapping": { @@ -872,6 +874,36 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -952,6 +984,12 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1699,6 +1737,15 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.137", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", @@ -1803,6 +1850,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3151,6 +3204,15 @@ "node": ">=10" } }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3748,6 +3810,35 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "2.73.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.73.0.tgz", + "integrity": "sha512-h/UngC3S4Zt28mB3g0+2YCMegT5yoftnQplwzPqGZcKvlld5e+kT/QRmJiL+qxGyZKOYpgirWGdLyEO1b0dpLQ==", + "dev": true, + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-dotenv": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dotenv/-/rollup-plugin-dotenv-0.3.0.tgz", + "integrity": "sha512-gI6Bo85j20DXyxV358ZtugBRTukmomRFtP9b2LOQrlsZwn9W536fBw5CfYnt137JUIeWZg52hdimO4IRqz0MTw==", + "dev": true, + "dependencies": { + "@rollup/plugin-replace": "^2.3.2", + "dotenv": "^8.2.0" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -3842,6 +3933,12 @@ "source-map": "^0.6.0" } }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5084,6 +5181,27 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -5154,6 +5272,12 @@ "@babel/types": "^7.3.0" } }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -5730,6 +5854,12 @@ } } }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true + }, "electron-to-chromium": { "version": "1.4.137", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", @@ -5803,6 +5933,12 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6825,6 +6961,15 @@ "yallist": "^4.0.0" } }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -7267,6 +7412,26 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "2.73.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.73.0.tgz", + "integrity": "sha512-h/UngC3S4Zt28mB3g0+2YCMegT5yoftnQplwzPqGZcKvlld5e+kT/QRmJiL+qxGyZKOYpgirWGdLyEO1b0dpLQ==", + "dev": true, + "peer": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-dotenv": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-dotenv/-/rollup-plugin-dotenv-0.3.0.tgz", + "integrity": "sha512-gI6Bo85j20DXyxV358ZtugBRTukmomRFtP9b2LOQrlsZwn9W536fBw5CfYnt137JUIeWZg52hdimO4IRqz0MTw==", + "dev": true, + "requires": { + "@rollup/plugin-replace": "^2.3.2", + "dotenv": "^8.2.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7343,6 +7508,12 @@ "source-map": "^0.6.0" } }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index ac2bb3b..c26e10f 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,11 @@ }, "devDependencies": { "@types/jest": "^27.0.3", + "@types/node": "^17.0.33", "jest": "^27.4.5", "jest-cli": "^27.4.5", - "puppeteer": "^10.0.0" + "puppeteer": "^10.0.0", + "rollup-plugin-dotenv": "^0.3.0" }, "license": "MIT" } diff --git a/src/components.d.ts b/src/components.d.ts index 49fcbe1..3b95d9f 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -12,6 +12,7 @@ export namespace Components { "titleMenu": string; } interface VazStockPrice { + "stockSymbol": string; } interface VazTooltip { "opened": boolean; @@ -50,6 +51,7 @@ declare namespace LocalJSX { "titleMenu"?: string; } interface VazStockPrice { + "stockSymbol"?: string; } interface VazTooltip { "opened"?: boolean; diff --git a/src/components/stock-price/stock-price.css b/src/components/stock-price/stock-price.css index a3d2a00..e292b65 100644 --- a/src/components/stock-price/stock-price.css +++ b/src/components/stock-price/stock-price.css @@ -36,3 +36,10 @@ form button:active { color: var(--color-orange-hovered); border-color: var(--color-orange-hovered); } + +form button:disabled { + background: #ccc; + border-color: #ccc; + color: var(--color-blue); + cursor: not-allowed; +} diff --git a/src/components/stock-price/stock-price.tsx b/src/components/stock-price/stock-price.tsx index 9a697ff..9e72fc5 100644 --- a/src/components/stock-price/stock-price.tsx +++ b/src/components/stock-price/stock-price.tsx @@ -1,4 +1,4 @@ -import { Component, h, State } from '@stencil/core'; +import { Component, Element, h, Prop, State } from '@stencil/core'; @Component({ tag: 'vaz-stock-price', @@ -6,31 +6,65 @@ import { Component, h, State } from '@stencil/core'; shadow: true, }) export class StockPrice { + stockInput: HTMLInputElement; + + @Element() el: HTMLElement; + + @Prop() stockSymbol: string; + @State() fetchedPrice: number; + @State() stockUserInput: string; + @State() stockInputValid = false; + @State() error: string; + @State() loading: boolean; + + onStockUserInput(event: Event) { + this.stockUserInput = (event.target as HTMLInputElement).value; + this.stockInputValid = this.stockUserInput.trim() !== ''; + } - onFetchStockPrice(event: Event) { + async onFetchStockPrice(event: Event) { event.preventDefault(); - fetch(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=MSFT&apikey=demo`) - .then(res => { - return res.json(); - }) - .then(parsedRes => { - this.fetchedPrice = +parsedRes['Global Quote']['05. price']; - }) - .catch(err => console.error(err)); + // const stockSymbol = (this.el.shadowRoot.querySelector('#stock-symbol') as HTMLInputElement)?.value; + const stockSymbol = this.stockInput.value; + await this.fetchStockPrice(stockSymbol); } - render() { - console.log(this.fetchedPrice); + async componentDidLoad() { + if (this.stockSymbol) { + this.stockInputValid = true; + this.stockUserInput = this.stockSymbol; + await this.fetchStockPrice(this.stockSymbol); + } + } + async fetchStockPrice(stockSymbol: string) { + this.loading = true; + try { + const apiResponse = await fetch(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${stockSymbol}&apikey=${process.env.AV_TOKEN}`); + const parsedRes = await apiResponse.json(); + if (!parsedRes['Global Quote']['05. price']) throw new Error('Invalid stock symbol'); + this.fetchedPrice = +parsedRes['Global Quote']['05. price']; + this.error = null; + } catch (err) { + this.fetchedPrice = null; + this.error = err.message; + } + this.loading = false; + } + + render() { + let dataContent =

Pleas enter a symbol

; + if (this.error) dataContent =

{this.error}

; + if (this.fetchedPrice) dataContent =

Price: ${this.fetchedPrice}

; return [
- - + (this.stockInput = el)} value={this.stockUserInput} onInput={this.onStockUserInput.bind(this)} /> +
, -
-

Price: ${this.fetchedPrice}

-
, +
{this.loading ?

Fetching Data...

: dataContent}
, ]; } } diff --git a/src/index.html b/src/index.html index 10112e7..77a8856 100644 --- a/src/index.html +++ b/src/index.html @@ -20,6 +20,6 @@ - + diff --git a/stencil.config.ts b/stencil.config.ts index ba6582b..17f9101 100644 --- a/stencil.config.ts +++ b/stencil.config.ts @@ -1,4 +1,5 @@ import { Config } from '@stencil/core'; +import dotenvPlugin from 'rollup-plugin-dotenv'; export const config: Config = { namespace: 'stencil', @@ -18,4 +19,5 @@ export const config: Config = { serviceWorker: null, // disable service workers }, ], + plugins: [dotenvPlugin()], };