├── .watchmanconfig ├── assets ├── images │ ├── Crypto.jpg │ ├── icon.png │ ├── sector.jpg │ ├── splash.png │ ├── favicon.png │ ├── iron-man.png │ ├── iconCapital.png │ ├── robot-dev.png │ ├── robot-prod.png │ ├── stockScreen.jpg │ └── marketOverall.jpg └── fonts │ └── SpaceMono-Regular.ttf ├── babel.config.js ├── .gitignore ├── components ├── StyledText.js ├── __tests__ │ ├── StyledText-test.js │ └── __snapshots__ │ │ └── StyledText-test.js.snap ├── TabBarIcon.js ├── Stock │ ├── Input.js │ ├── InfoSlideOne.js │ ├── InfoSlideThree.js │ ├── InfoSlideTwo.js │ └── Chart.js ├── stock │ ├── Input.js │ └── Chart.js ├── Home │ └── StockChart.js ├── Crypto │ └── TreeMap.js ├── Sector │ └── SectorChart.js └── sector │ └── SectorChart.js ├── constants ├── Layout.js └── Colors.js ├── navigation ├── LinkingConfiguration.js └── BottomTabNavigator.js ├── .expo-shared └── assets.json ├── Index.js ├── __tests__ └── App-test.js ├── app.json ├── screens ├── utils.js ├── SectorScreen.js ├── StockScreen.js └── MarketOverview.js ├── README.md ├── hooks └── useCachedResources.js ├── App.js └── package.json /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /assets/images/Crypto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/Crypto.jpg -------------------------------------------------------------------------------- /assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/icon.png -------------------------------------------------------------------------------- /assets/images/sector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/sector.jpg -------------------------------------------------------------------------------- /assets/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/splash.png -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/iron-man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/iron-man.png -------------------------------------------------------------------------------- /assets/images/iconCapital.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/iconCapital.png -------------------------------------------------------------------------------- /assets/images/robot-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/robot-dev.png -------------------------------------------------------------------------------- /assets/images/robot-prod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/robot-prod.png -------------------------------------------------------------------------------- /assets/images/stockScreen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/stockScreen.jpg -------------------------------------------------------------------------------- /assets/images/marketOverall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/images/marketOverall.jpg -------------------------------------------------------------------------------- /assets/fonts/SpaceMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/biill/ReactNativeStockProject/HEAD/assets/fonts/SpaceMono-Regular.ttf -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p8 6 | *.p12 7 | *.key 8 | *.mobileprovision 9 | *.orig.* 10 | web-build/ 11 | 12 | # macOS 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /components/StyledText.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Text } from "react-native"; 3 | 4 | export function MonoText(props) { 5 | return ( 6 | 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /constants/Layout.js: -------------------------------------------------------------------------------- 1 | import { Dimensions } from 'react-native'; 2 | 3 | const width = Dimensions.get('window').width; 4 | const height = Dimensions.get('window').height; 5 | 6 | export default { 7 | window: { 8 | width, 9 | height, 10 | }, 11 | isSmallDevice: width < 375, 12 | }; 13 | -------------------------------------------------------------------------------- /navigation/LinkingConfiguration.js: -------------------------------------------------------------------------------- 1 | import * as Linking from "expo-linking"; 2 | 3 | export default { 4 | prefixes: [Linking.makeUrl("/")], 5 | config: { 6 | Root: { 7 | path: "root", 8 | screens: { 9 | Home: "home", 10 | Links: "links", 11 | }, 12 | }, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true, 3 | "af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true, 4 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 5 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 6 | } 7 | -------------------------------------------------------------------------------- /components/__tests__/StyledText-test.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import renderer from "react-test-renderer"; 3 | 4 | import { MonoText } from "../StyledText"; 5 | 6 | it(`renders correctly`, () => { 7 | const tree = renderer.create(Snapshot test!).toJSON(); 8 | 9 | expect(tree).toMatchSnapshot(); 10 | }); 11 | -------------------------------------------------------------------------------- /components/__tests__/__snapshots__/StyledText-test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders correctly 1`] = ` 4 | 14 | Snapshot test! 15 | 16 | `; 17 | -------------------------------------------------------------------------------- /Index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import store from './stores/store'; 4 | import App from './App'; 5 | 6 | export default class Index extends Component { 7 | render() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /constants/Colors.js: -------------------------------------------------------------------------------- 1 | const tintColor = '#2f95dc'; 2 | 3 | export default { 4 | tintColor, 5 | tabIconDefault: '#ccc', 6 | tabIconSelected: tintColor, 7 | tabBar: '#fefefe', 8 | errorBackground: 'red', 9 | errorText: '#fff', 10 | warningBackground: '#EAEB5E', 11 | warningText: '#666804', 12 | noticeBackground: tintColor, 13 | noticeText: '#fff', 14 | }; 15 | -------------------------------------------------------------------------------- /components/TabBarIcon.js: -------------------------------------------------------------------------------- 1 | import { Ionicons } from "@expo/vector-icons"; 2 | import * as React from "react"; 3 | 4 | import Colors from "../constants/Colors"; 5 | 6 | export default function TabBarIcon(props) { 7 | return ( 8 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import App from '../App'; 4 | import renderer from 'react-test-renderer'; 5 | import NavigationTestUtils from 'react-navigation/NavigationTestUtils'; 6 | 7 | describe('App snapshot', () => { 8 | jest.useFakeTimers(); 9 | beforeEach(() => { 10 | NavigationTestUtils.resetInternalState(); 11 | }); 12 | 13 | it('renders the loading screen', async () => { 14 | const tree = renderer.create().toJSON(); 15 | expect(tree).toMatchSnapshot(); 16 | }); 17 | 18 | it('renders the root without loading screen', async () => { 19 | const tree = renderer.create().toJSON(); 20 | expect(tree).toMatchSnapshot(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "StockProject", 4 | "slug": "StockProject", 5 | "platforms": [ 6 | "ios", 7 | "android", 8 | "web" 9 | ], 10 | "version": "1.0.0", 11 | "orientation": "portrait", 12 | "icon": "./assets/images/icon.png", 13 | "scheme": "myapp", 14 | "splash": { 15 | "image": "./assets/images/splash.png", 16 | "resizeMode": "contain", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "updates": { 20 | "fallbackToCacheTimeout": 0 21 | }, 22 | "assetBundlePatterns": [ 23 | "**/*" 24 | ], 25 | "ios": { 26 | "supportsTablet": true 27 | }, 28 | "web": { 29 | "favicon": "./assets/images/favicon.png" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /screens/utils.js: -------------------------------------------------------------------------------- 1 | export const convertStockData = (res) => { 2 | let result = []; 3 | 4 | if (res) { 5 | const data = res.data["Time Series (Daily)"]; 6 | 7 | Object.entries(data).map((item) => result.push(item)); 8 | } 9 | 10 | return result; 11 | }; 12 | 13 | export const convertCryptoData = (data) => { 14 | let crypto = { name: "crypto", value: 0 }; 15 | data = data 16 | .map((e) => { 17 | return { 18 | name: e["companyName"].slice(0, -3), 19 | value: parseFloat( 20 | (e["bidPrice"] * e["latestVolume"]) / 1000000 21 | ).toFixed(2), 22 | }; 23 | }) 24 | .filter((e) => e.value > 0); 25 | crypto["children"] = data; 26 | crypto.value = parseFloat( 27 | data.reduce((sum, cur) => sum + Number(cur.value), 0) 28 | ).toFixed(2); 29 | 30 | return [crypto]; 31 | }; 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Financial InfoX 2 | 3 | `Tech Used:` React-Native, native-echarts, expo, antd-mobile,react-navigation 4 | 5 | ## Description: 6 | 7 | A mobile app built in 3 days to demonstrate stock market information by using a variety of charts, especially candlestick charts. In addition, used a tree­map (whcih now is not working, need API resource) to illustrate asset value for Cryptocurrency market. 8 | 9 | ## Updated: 10 | Updated In May 2020 to adapt to all new packages and make the project alive again! 11 | 12 | ## Screen Shots demonstration 13 | 14 | 15 | 16 | 17 | 18 | 19 | #### Question? 20 | 21 | Now, if you have question, please let me know. 22 | -------------------------------------------------------------------------------- /hooks/useCachedResources.js: -------------------------------------------------------------------------------- 1 | import { Ionicons } from '@expo/vector-icons'; 2 | import * as Font from 'expo-font'; 3 | import * as SplashScreen from 'expo-splash-screen'; 4 | import * as React from 'react'; 5 | 6 | export default function useCachedResources() { 7 | const [isLoadingComplete, setLoadingComplete] = React.useState(false); 8 | 9 | // Load any resources or data that we need prior to rendering the app 10 | React.useEffect(() => { 11 | async function loadResourcesAndDataAsync() { 12 | try { 13 | SplashScreen.preventAutoHideAsync(); 14 | 15 | // Load fonts 16 | await Font.loadAsync({ 17 | ...Ionicons.font, 18 | 'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'), 19 | }); 20 | } catch (e) { 21 | // We might want to provide this error information to an error reporting service 22 | console.warn(e); 23 | } finally { 24 | setLoadingComplete(true); 25 | SplashScreen.hideAsync(); 26 | } 27 | } 28 | 29 | loadResourcesAndDataAsync(); 30 | }, []); 31 | 32 | return isLoadingComplete; 33 | } 34 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import { NavigationContainer } from '@react-navigation/native'; 2 | import { createStackNavigator } from '@react-navigation/stack'; 3 | import * as React from 'react'; 4 | import { Platform, StatusBar, StyleSheet, View } from 'react-native'; 5 | 6 | import useCachedResources from './hooks/useCachedResources'; 7 | import BottomTabNavigator from './navigation/BottomTabNavigator'; 8 | import LinkingConfiguration from './navigation/LinkingConfiguration'; 9 | 10 | const Stack = createStackNavigator(); 11 | 12 | export default function App(props) { 13 | const isLoadingComplete = useCachedResources(); 14 | 15 | if (!isLoadingComplete) { 16 | return null; 17 | } else { 18 | return ( 19 | 20 | {Platform.OS === 'ios' && } 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | 31 | const styles = StyleSheet.create({ 32 | container: { 33 | flex: 1, 34 | backgroundColor: '#fff', 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "web": "expo start --web", 8 | "eject": "expo eject", 9 | "test": "jest --watchAll" 10 | }, 11 | "jest": { 12 | "preset": "jest-expo" 13 | }, 14 | "dependencies": { 15 | "@expo/vector-icons": "~10.0.6", 16 | "@react-native-community/masked-view": "0.1.6", 17 | "@react-navigation/bottom-tabs": "^5.3.1", 18 | "@react-navigation/native": "^5.2.1", 19 | "@react-navigation/stack": "^5.2.16", 20 | "axios": "^0.19.2", 21 | "expo": "~37.0.9", 22 | "expo-asset": "~8.1.0", 23 | "expo-constants": "~9.0.0", 24 | "expo-font": "~8.1.0", 25 | "expo-linking": "^1.0.1", 26 | "expo-splash-screen": "^0.2.3", 27 | "expo-web-browser": "~8.2.0", 28 | "native-echarts": "^0.5.0", 29 | "react": "~16.9.0", 30 | "react-dom": "~16.9.0", 31 | "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz", 32 | "react-native-best-viewpager": "^1.0.4", 33 | "react-native-elements": "^2.0.0", 34 | "react-native-gesture-handler": "~1.6.0", 35 | "react-native-safe-area-context": "0.7.3", 36 | "react-native-screens": "~2.2.0", 37 | "react-native-vector-icons": "^6.6.0", 38 | "react-native-web": "~0.11.7", 39 | "react-native-webview": "^10.1.1", 40 | "rn-viewpager": "^1.2.9" 41 | }, 42 | "devDependencies": { 43 | "@babel/core": "^7.8.6", 44 | "babel-preset-expo": "~8.1.0", 45 | "jest-expo": "~37.0.0" 46 | }, 47 | "private": true 48 | } 49 | -------------------------------------------------------------------------------- /components/Stock/Input.js: -------------------------------------------------------------------------------- 1 | import React, { Component, useState } from "react"; 2 | import { 3 | StyleSheet, 4 | Text, 5 | View, 6 | ScrollView, 7 | TouchableOpacity, 8 | TextInput, 9 | } from "react-native"; 10 | import { Button, Input } from "react-native-elements"; 11 | import axios from "axios"; 12 | 13 | export default function InputForm({ setSelectedStock, selectedStock }) { 14 | const [searchText, setSearchText] = useState(""); 15 | 16 | const fetchStock = async () => { 17 | try { 18 | const res = await axios.get( 19 | `https://sandbox.iexapis.com/stable/stock/${searchText}/chart/1y?token=Tsk_9b260400520a4d23abfe1ef6cb0d3feb` 20 | ); 21 | const infoRes = await axios.get( 22 | `https://sandbox.iexapis.com/stable/stock/${searchText}/advanced-stats?token=Tsk_9b260400520a4d23abfe1ef6cb0d3feb` 23 | ); 24 | setSelectedStock({ 25 | data: res.data, 26 | info: { ...infoRes.data, symbol: searchText.toUpperCase() }, 27 | }); 28 | } catch (error) { 29 | console.log(error); 30 | } 31 | }; 32 | 33 | const handleSubmit = async () => { 34 | searchText && (await fetchStock(searchText)); 35 | setSearchText(""); 36 | }; 37 | 38 | return ( 39 | 53 | 54 | { 56 | setSearchText(textEntry); 57 | }} 58 | style={{ backgroundColor: "transparent" }} 59 | onSubmitEditing={() => handleSubmit()} 60 | color="white" 61 | placeholder="Please enter a symbol" 62 | placeholderTextColor="white" 63 | selectionColor="white" 64 | value={searchText} 65 | /> 66 | 67 | 68 |