Skip to content

Commit ec25ea8

Browse files
Remove dependency on external API for data, add mock dependency
1 parent 9d33aae commit ec25ea8

File tree

7 files changed

+163
-10844
lines changed

7 files changed

+163
-10844
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"name": "learn-react-app",
33
"version": "0.1.0",
44
"private": true,
5-
"proxy": "https://financialmodelingprep.com",
65
"dependencies": {
76
"@material-ui/core": "^3.9.0",
87
"@material-ui/icons": "^3.0.2",

src/api/CompanyDataGenerator.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { sample } from 'lodash';
2+
3+
const PRICE = { MIN: 25, MAX: 250 };
4+
const BETA = { MIN: 1, MAX: 2 };
5+
const VOLAVG = { MIN: 10000, MAX: 1000000 };
6+
const MKTCAP = { MIN: 10000000, MAX: 50000000000 };
7+
const LASTDIV_PERC = { MIN: 0, MAX: 0.03 };
8+
const RANGESPREAD_PERC = { MIN: 0.02, MAX: 0.05 };
9+
const CHANGESPERC = { MIN: 0.01, MAX: 0.05 };
10+
11+
const SECTOR_INDUSTRY = {
12+
'Technology': ['Computer Hardware', 'Online Media', 'SemiConductor', 'Application Software'],
13+
'Consumer': ['Restaurant', 'Utilities', 'Retail', 'Entertainment', 'Apparel'],
14+
'Health Care': ['Medical Device'],
15+
'Industrial': ['Airlines', 'Manufacturing'],
16+
'Financial Services': ['Brokers & Exchanges', 'Banks']
17+
};
18+
19+
const EXCHANGE = ['NASDAQ', 'NYSE'];
20+
21+
class CompanyDataGenerator {
22+
constructor() {
23+
24+
}
25+
26+
getPrice() {
27+
return getRandomNumberBetween(PRICE.MIN, PRICE.MAX);
28+
}
29+
30+
getBeta() {
31+
return getRandomNumberBetween(BETA.MIN, BETA.MAX, true);
32+
}
33+
34+
getVolAvg() {
35+
return `${getRandomNumberBetween(VOLAVG.MIN, VOLAVG.MAX).toLocaleString('US')}`;
36+
}
37+
38+
getMktCap() {
39+
return `$${getRandomNumberBetween(MKTCAP.MIN, MKTCAP.MAX).toLocaleString('US')}`;
40+
}
41+
42+
getLastDiv(price) {
43+
return (price * getRandomNumberBetween(LASTDIV_PERC.MIN, LASTDIV_PERC.MAX, true)).toFixed(2);
44+
}
45+
46+
getRange(price) {
47+
return `$${(price - price * RANGESPREAD_PERC.MIN).toFixed(2)}
48+
- $${(price + price * RANGESPREAD_PERC.MAX).toFixed(2)}`
49+
}
50+
51+
getChangePerc() {
52+
return getRandomNumberBetween(CHANGESPERC.MIN, CHANGESPERC.MAX, true);
53+
}
54+
55+
getChange(price, changePerc) {
56+
return (price * changePerc).toFixed(2);
57+
}
58+
59+
getCompanyFinancial() {
60+
const Price = this.getPrice();
61+
const Beta = this.getBeta();
62+
const VolAvg = this.getVolAvg();
63+
const MktCap = this.getMktCap();
64+
const LastDiv = this.getLastDiv(Price);
65+
const Range = this.getRange(Price);
66+
const ChangePerc = this.getChangePerc();
67+
const Change = this.getChange(Price, ChangePerc);
68+
return {
69+
Price: `$${Price}`,
70+
Beta,
71+
VolAvg,
72+
MktCap,
73+
LastDiv,
74+
Range,
75+
ChangePerc: `${ChangePerc * 100}%`,
76+
Change
77+
}
78+
}
79+
80+
getDescription(name, sector) {
81+
const randomYear = getRandomNumberBetween(5, 50);
82+
return `${name} is an excellent company in ${sector} sector for past ${randomYear} years producing outstanding results for it's shareholders.`
83+
}
84+
85+
getExchange() {
86+
return sample(EXCHANGE);
87+
}
88+
89+
getIndustry(sector) {
90+
return sample(SECTOR_INDUSTRY[sector]);
91+
}
92+
93+
getSector() {
94+
return sample(Object.keys(SECTOR_INDUSTRY));
95+
}
96+
97+
getWebsite(ticker) {
98+
return `http://www.${ticker.toLowerCase()}.com`
99+
}
100+
101+
getCompanyProfile(ticker) {
102+
const companyName = ticker.toUpperCase();
103+
const exchange = this.getExchange();
104+
const sector = this.getSector();
105+
const industry = this.getIndustry(sector);
106+
const website = this.getWebsite(ticker);
107+
const description = this.getDescription(companyName, sector);
108+
return {
109+
companyName,
110+
description,
111+
exchange,
112+
industry,
113+
sector,
114+
website
115+
}
116+
}
117+
}
118+
119+
function getRandomNumberBetween(min, max, floatResult) {
120+
if (floatResult) {
121+
return (Math.random() * (max - min) + min).toFixed(2);
122+
}
123+
return Math.floor(min + (max - min + 1) * Math.random());
124+
}
125+
126+
export default new CompanyDataGenerator();

src/api/DataApi.js

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,34 @@
1-
import pick from 'lodash/pick';
1+
import CompanyDataGenerator from './CompanyDataGenerator';
22

3-
const COMPANY_FINANCIAL_FIELDS = [
4-
'Price', 'Beta', 'VolAvg', 'MktCap', 'LastDiv', 'Range', 'Changes', 'ChangesPerc'
5-
]
6-
7-
const COMPANY_PROFILE_FIELDS = [
8-
'companyName', 'description', 'exchange', 'industry', 'website', 'sector'
9-
]
10-
11-
const API_BASE = `/api/company/profile`;
123
export default class DataApi {
134
static async getCompanyProfile(company) {
14-
return DataApi.getFullCompanyProfile(company)
15-
.then(res => pick(res, COMPANY_PROFILE_FIELDS));
5+
return new Promise((resolve, reject) => {
6+
if (!company || company.trim().length !== 3) {
7+
reject('Ticker cannot be empty and must be 3 character long');
8+
}
9+
try {
10+
const result = CompanyDataGenerator.getCompanyProfile(company);
11+
resolve(result);
12+
} catch(e) {
13+
console.error(e);
14+
reject(e);
15+
}
16+
})
1617
}
1718

1819
static async getCompanyFinancial(company) {
19-
return DataApi.getFullCompanyProfile(company)
20-
.then(res => pick(res, COMPANY_FINANCIAL_FIELDS));
21-
}
22-
23-
static async getFullCompanyProfile(company) {
24-
return fetch(`${API_BASE}/${company.trim()}`, {mode: 'cors', headers: { 'Content-Type': 'application/json'}})
25-
.then(res => {
26-
if (!res.ok) {
27-
throw new Error('error when fetching data');
28-
}
29-
return res.text()
30-
})
31-
.then(textRes => textRes.replace(/<pre>/g, '').replace(/<\/pre>/g, ''))
32-
.then(res => JSON.parse(res))
33-
.then(res => res[company.trim()]);
20+
return new Promise((resolve, reject) => {
21+
if (!company || company.trim().length !== 3) {
22+
reject('Ticker cannot be empty and must be 3 character long');
23+
}
24+
try {
25+
const result = CompanyDataGenerator.getCompanyFinancial(company);
26+
resolve(result);
27+
} catch(e) {
28+
console.error(e);
29+
reject(e);
30+
}
31+
})
3432
}
3533
}
3634

src/exercise/06-LifecycleMethods.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class CompanyProfile extends Component {
7272
* the output of this code is displayed on the browser
7373
*/
7474
const Usage = (props) => {
75-
return <CompanyProfile stockTicker={'AMZN'} />
75+
return <CompanyProfile stockTicker={'AMZ'} />
7676
}
7777

7878
export default Usage;

src/exercise/solution/06-LifecycleMethods-solution.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CompanyProfile extends Component {
4545
* the output of this code is displayed on the browser
4646
*/
4747
const Usage = (props) => {
48-
return <CompanyProfile stockTicker={'AMZN'} />
48+
return <CompanyProfile stockTicker={'AMZ'} />
4949
}
5050

5151
export default Usage;

src/tutorial/09-Capstone.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
Now that you have mastered the fundamentals of React, we will build something that brings together the concepts we have learned throughout this tutorial.
22

33
#### Project Description
4-
For this capstone project will build a simple feature that will allow users to search for a publicly traded company using their "stock ticker" (ex - AAPL for Apple, FB for Facebook, GOOGL for Google etc). Once the user clicks the "Search" button, we will then display the company profile and company financial.
4+
For this capstone project will build a simple feature that will allow users to search for a publicly traded company using their "stock ticker". Once the user clicks the "Search" button, we will then display the company profile and company financial.
55

6-
Below on the left is your solution, and on the right is the final solution. Try a ticker like `AIR` on the right-hand side and click `Search` to see the expected behavior of this component.
6+
**Note: The API provided here uses a random data generator to generate company profile and the financial information.
7+
Please do not rely on the accuracy of the data because it is guaranteed to be inaccurate (it's random).
8+
The API expects the ticker to be *3 characters* long. It will give you results if the ticker is 3 characters long and it will throw an error if the ticker is less than or greater than 3 characters.
9+
It also does not check if the ticker is actually a valid ticker. So any random 3 character would work.**
10+
11+
Below on the left is your solution, and on the right is the final solution. Try a ticker like `XYZ` on the right-hand side and click `Search` to see the expected behavior of this component.
712

813
<!--exercise-->
914

1015
Don't worry about styling, it's already provided for you.
1116

1217
There's also an API provided to you that has two methods -
13-
- `getCompanyProfile(ticker)` - Returns a `Promise` that resolves to the company profile information for the ticker you passed. It has fields like - CEO, description, exchange, industry etc.
18+
- `getCompanyProfile(ticker)` - Returns a `Promise` that resolves to the company profile information for the ticker you passed. It has fields like - description, exchange, industry, sector etc.
1419
- `getCompanyFinancial(ticker)` - Returns a `Promise` that resolves to the financial information for the ticker you passed. The response has fields like - price, beta, volAvg, MktCap etc.
1520

16-
For this project, the component skeleton is provided inside the 'src/capstone' folder, and as always, the files are heavily commented to guide you with the tasks. Please start with the `Capstone.js` file and you can go to any of the other files next. The final solution is provided in the solution folder (src/capstone/solution), however, I strongly recommend you to try on your own before looking at the solution. If you don't remember some of the concepts, feel free to go back and refer to the appropriate tutorial page.
21+
For this project, the component skeleton is provided inside the 'src/capstone' folder, and as always, the files are heavily commented to guide you with the tasks. Please start with the `Capstone.js` file and you can go to any of the other files next. The final solution is provided in the solution folder (src/capstone/solution), however, I strongly recommend you to try on your own before looking at the solution. If you don't remember some of the concepts, please feel free to go back and refer to the appropriate tutorial page.
1722

1823
There are four components in this project. Just a brief word on what those components are used for:
1924

2025
- `Capstone` - Just named Capstone to signify that this component encapsulates our entire project. We import and use below components inside this to build our feature.
2126
- `Search` - This component has search input and the search button.
2227
- `CompanyProfile` - This component renders company profile. It takes a company ticker as props and fetches the profile data from the API and renders that data.
2328
- `CompanyFinancial` - This component renders company financial information. It takes a company ticker as props and fetches the financial information data from the API and renders it.
24-
- `DataAPI` - This is the API used to fetch the required data. You don't need to change anything on this API. Under the hood, it uses a [free API](https://financialmodelingprep.com/developer/docs) to fetch the actual data for the given ticker. You don't need to worry about any of the details on this API. Just assume it gives right result when called.
29+
- `DataAPI` - This is the API used to fetch the required data. You don't need to change anything on this API. Under the hood it uses a random data generator so please do not rely on the accuracy of the data. Like mentioned above, this API will give you results as long as the ticker is 3 characters long and it will throw an error if the ticker is longer than or shorter than 3 characters. It also does not check whether or not the ticker is valid. In real life this would call an actual API that will fetch actual data, but as long as the data structure doesn't change our React code would not change. So don't worry about the API not giving actual data. It's not relevant for us to complete the task at hand.
2530

2631
#### Disclaimer
2732
How we break down components to build this feature is not set in stone. The component decomposition is more often art than science. We can most definitely build this feature with just one component instead of four, or we could easily break these components into more granular pieces. Please read this [excellent article](https://reactjs.org/docs/thinking-in-react.html) on how to think about components in React.

0 commit comments

Comments
 (0)