├── .expo-shared
└── assets.json
├── .gitignore
├── App.js
├── Todo.js
├── app.json
├── assets
├── favicon.png
├── icon.png
└── splash.png
├── babel.config.js
├── package-lock.json
└── package.json
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { StyleSheet, Dimensions, ScrollView, Text, TextInput, Button, View, SafeAreaView } from 'react-native';
3 | import Todo from './Todo';
4 | import {BarChart, LineChart} from "react-native-chart-kit";
5 | import moment from 'moment';
6 |
7 | const App = () => {
8 | const [description, setDescription] = useState('');
9 | const [amount, setAmount] = useState('');
10 | const [total, setTotal] = useState(0);
11 | const [data, setData] = useState([
12 | { date: moment().format('LL'), amount: 2000 },
13 | { date: moment().subtract(1, 'days').format('LL'), amount: 2500 },
14 | { date: moment().subtract(1, 'days').format('LL'), amount: 3500 },
15 | { date: moment().subtract(1, 'days').format('LL'), amount: 3500 },
16 | { date: moment().subtract(1, 'days').format('LL'), amount: 3500 },
17 | { date: moment().subtract(7, 'days').format('LL'), amount: 3500 },
18 | { date: moment().subtract(6, 'days').format('LL'), amount: 3500 },
19 | { date: moment().subtract(5, 'days').format('LL'), amount: 3500 },
20 | { date: moment().subtract(4, 'days').format('LL'), amount: 3500 },
21 | { date: moment().subtract(3, 'days').format('LL'), amount: 4500 },
22 | { date: moment().subtract(2, 'days').format('LL'), amount: 5500 },
23 | { date: moment().subtract(2, 'days').format('LL'), amount: 5500 },
24 | ])
25 | const [transformedData, setTransformedData] = useState([]);
26 |
27 | useEffect(() => {
28 | setTransformedData(transformData(groupBy(data, 'date')));
29 | }, [data])
30 |
31 | const groupBy = (array, key) =>
32 | array.reduce((rv, x) => {
33 | (rv[x[key]] = rv[x[key]] || []).push(x);
34 | return rv;
35 | }, {});
36 |
37 | const [gigs, setGigs] = useState([
38 | {
39 | description: 'Freelance job with Qazi',
40 | amount: 499.99,
41 | timestamp: new Date()
42 | }
43 | ]);
44 |
45 | const getDates = () => transformedData.map(pair => pair.date);
46 | const getAmounts = () => transformedData.map(pair => pair.amount);
47 | const transformData = (groupedData) => {
48 | const transformedArray = [];
49 |
50 | Object.entries(groupedData).forEach(entry => {
51 | const total = entry[1].reduce((total, pair) => total + pair.amount, 0)
52 | transformedArray.push({ date: moment(entry[0]).format('MM/DD'), amount: total })
53 | })
54 |
55 | const sortedArray = transformedArray.sort((a, b) => moment(a['date']).diff(moment(b['date'])))
56 |
57 | return sortedArray;
58 | }
59 |
60 | console.log('DEBUG 🔥', data)
61 | console.log('The Dates ⏲️', getDates())
62 | console.log('The Amounts ⏲️', getAmounts())
63 | console.log('The GROUPED values are ⏲️', Object.entries(groupBy(data, 'date')))
64 | console.log('The Total grouped value 👽', transformData(groupBy(data, 'date')))
65 |
66 | useEffect(() => {
67 | setTotal(gigs.reduce((total, gig) => total+Number(gig.amount), 0));
68 | }, [gigs])
69 |
70 | const addGig = () => {
71 | setGigs([...gigs, {
72 | description: description,
73 | amount: amount
74 | }]);
75 |
76 | setData([
77 | ...data,
78 | {
79 | date: moment().format('LL'),
80 | amount: Number(amount)
81 | }
82 | ]);
83 |
84 | setDescription('');
85 | setAmount('');
86 | }
87 |
88 | return (
89 |
90 |
91 |
92 | Let's build a React Native App for Freelance Devs to Track Income 🚀 🚀 🚀
93 |
94 |
95 | Bezier Line Chart
96 | `rgba(255, 255, 255, ${opacity})`,
115 | labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
116 | style: {
117 | borderRadius: 16
118 | },
119 | propsForDots: {
120 | r: "6",
121 | strokeWidth: "2",
122 | stroke: "#ffa726"
123 | }
124 | }}
125 | bezier
126 | style={{
127 | marginVertical: 8,
128 | borderRadius: 16
129 | }}
130 | />
131 |
132 | Total Income: ${total}
133 | setDescription(text)}
138 | />
139 | setAmount(text)}
145 | />
146 |
147 |
148 | {gigs.map(gig => (
149 |
150 | {gig.description}
151 | ${gig.amount}
152 |
153 | ))}
154 |
155 |
156 |
157 | );
158 | }
159 |
160 | const styles = StyleSheet.create({
161 | input: {
162 | marginTop: 20,
163 | height: 40,
164 | borderColor: 'red',
165 | borderWidth: 1
166 | },
167 | titleText: {
168 | // backgroundColor: 'red',
169 | fontSize: 30,
170 | fontWeight: "bold",
171 | },
172 | });
173 |
174 | export default App;
--------------------------------------------------------------------------------
/Todo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { StyleSheet, Text, View } from 'react-native'
3 |
4 | const Todo = ({ title }) => {
5 | return (
6 |
7 | ✅ {title}
8 |
9 | )
10 | }
11 |
12 | export default Todo
13 |
14 | const styles = StyleSheet.create({})
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "first-react-native",
4 | "slug": "first-react-native",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "contain",
11 | "backgroundColor": "#ffffff"
12 | },
13 | "updates": {
14 | "fallbackToCacheTimeout": 0
15 | },
16 | "assetBundlePatterns": [
17 | "**/*"
18 | ],
19 | "ios": {
20 | "supportsTablet": true
21 | },
22 | "web": {
23 | "favicon": "./assets/favicon.png"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CleverProgrammers/Income-tracking-app/9daeb42f4a025f82205ba290fb92982c8211baf9/assets/favicon.png
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CleverProgrammers/Income-tracking-app/9daeb42f4a025f82205ba290fb92982c8211baf9/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CleverProgrammers/Income-tracking-app/9daeb42f4a025f82205ba290fb92982c8211baf9/assets/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/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 | },
10 | "dependencies": {
11 | "expo": "~39.0.2",
12 | "expo-status-bar": "~1.0.2",
13 | "moment": "^2.29.1",
14 | "react": "16.13.1",
15 | "react-dom": "16.13.1",
16 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.4.tar.gz",
17 | "react-native-chart-kit": "^6.6.1",
18 | "react-native-svg": "^12.1.0",
19 | "react-native-web": "~0.13.12"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "~7.9.0"
23 | },
24 | "private": true
25 | }
26 |
--------------------------------------------------------------------------------