@dhiraj0720/report1chart 2.2.3 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/report1Fetcher.jsx +27 -0
- package/src/components/ProgressBar.jsx +27 -0
- package/src/components/Report1Card.jsx +99 -0
- package/src/index.jsx +2 -17
- package/src/screens/Report1Screen.jsx +80 -0
- package/src/api/fetcher.jsx +0 -70
- package/src/components/ChartRenderer.jsx +0 -388
- package/src/components/ReportList.jsx +0 -135
- package/src/components/ReportView.jsx +0 -93
- package/src/components/TableRenderer.jsx +0 -647
- package/src/screens/ReportScreen.jsx +0 -417
package/package.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
const fetchReport1 = async (apiEndpoint, apiToken) => {
|
|
4
|
+
try {
|
|
5
|
+
const response = await axios.get(apiEndpoint, {
|
|
6
|
+
headers: {
|
|
7
|
+
Authorization: apiToken,
|
|
8
|
+
Accept: 'application/json',
|
|
9
|
+
},
|
|
10
|
+
timeout: 15000,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!response.data || !response.data.rows) {
|
|
14
|
+
throw new Error('Invalid API response');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return response.data.rows;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
error?.response?.data?.message ||
|
|
21
|
+
error.message ||
|
|
22
|
+
'Failed to fetch report'
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default fetchReport1;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const ProgressBar = ({ value }) => {
|
|
5
|
+
const width = Math.min(Math.max(value || 0, 0), 100);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<View style={styles.track}>
|
|
9
|
+
<View style={[styles.fill, { width: `${width}%` }]} />
|
|
10
|
+
</View>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default ProgressBar;
|
|
15
|
+
|
|
16
|
+
const styles = StyleSheet.create({
|
|
17
|
+
track: {
|
|
18
|
+
height: 6,
|
|
19
|
+
backgroundColor: '#e0e0e0',
|
|
20
|
+
borderRadius: 4,
|
|
21
|
+
overflow: 'hidden',
|
|
22
|
+
},
|
|
23
|
+
fill: {
|
|
24
|
+
height: '100%',
|
|
25
|
+
backgroundColor: '#f57c00',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import ProgressBar from './ProgressBar';
|
|
4
|
+
|
|
5
|
+
const format = (num) => (num ?? 0).toLocaleString();
|
|
6
|
+
|
|
7
|
+
const Trend = ({ value }) => {
|
|
8
|
+
const positive = value >= 0;
|
|
9
|
+
return (
|
|
10
|
+
<Text style={[styles.trend, positive ? styles.up : styles.down]}>
|
|
11
|
+
{positive ? '↑' : '↓'} {Math.abs(value)}%
|
|
12
|
+
</Text>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const Report1Card = ({ item }) => {
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.card}>
|
|
19
|
+
<Text style={styles.title}>{item.name}</Text>
|
|
20
|
+
|
|
21
|
+
<Row label="2024 Actual" value={format(item.actual2024)} />
|
|
22
|
+
<Row label="2025 Actual" value={format(item.actual2025)} />
|
|
23
|
+
|
|
24
|
+
<View style={styles.row}>
|
|
25
|
+
<Text style={styles.label}>Change YoY</Text>
|
|
26
|
+
<Trend value={item.actualChangePercent} />
|
|
27
|
+
</View>
|
|
28
|
+
|
|
29
|
+
<Row label="2025 Budget" value={format(item.budget2025)} />
|
|
30
|
+
|
|
31
|
+
<View style={styles.row}>
|
|
32
|
+
<Text style={styles.label}>Budget Variance</Text>
|
|
33
|
+
<Trend value={item.budgetVariancePercent} />
|
|
34
|
+
</View>
|
|
35
|
+
|
|
36
|
+
{item.opexToGrossProfitPercent !== undefined && (
|
|
37
|
+
<>
|
|
38
|
+
<View style={styles.row}>
|
|
39
|
+
<Text style={styles.label}>OPEX / Gross Profit</Text>
|
|
40
|
+
<Text style={styles.value}>
|
|
41
|
+
{item.opexToGrossProfitPercent}%
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
<ProgressBar value={item.opexToGrossProfitPercent} />
|
|
45
|
+
</>
|
|
46
|
+
)}
|
|
47
|
+
</View>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const Row = ({ label, value }) => (
|
|
52
|
+
<View style={styles.row}>
|
|
53
|
+
<Text style={styles.label}>{label}</Text>
|
|
54
|
+
<Text style={styles.value}>{value}</Text>
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export default Report1Card;
|
|
59
|
+
|
|
60
|
+
const styles = StyleSheet.create({
|
|
61
|
+
card: {
|
|
62
|
+
backgroundColor: '#fff',
|
|
63
|
+
borderRadius: 12,
|
|
64
|
+
padding: 16,
|
|
65
|
+
marginBottom: 12,
|
|
66
|
+
borderWidth: 1,
|
|
67
|
+
borderColor: '#e0e0e0',
|
|
68
|
+
},
|
|
69
|
+
title: {
|
|
70
|
+
fontSize: 16,
|
|
71
|
+
fontWeight: '700',
|
|
72
|
+
marginBottom: 12,
|
|
73
|
+
color: '#000',
|
|
74
|
+
},
|
|
75
|
+
row: {
|
|
76
|
+
flexDirection: 'row',
|
|
77
|
+
justifyContent: 'space-between',
|
|
78
|
+
marginBottom: 6,
|
|
79
|
+
},
|
|
80
|
+
label: {
|
|
81
|
+
fontSize: 13,
|
|
82
|
+
color: '#666',
|
|
83
|
+
},
|
|
84
|
+
value: {
|
|
85
|
+
fontSize: 13,
|
|
86
|
+
fontWeight: '600',
|
|
87
|
+
color: '#000',
|
|
88
|
+
},
|
|
89
|
+
trend: {
|
|
90
|
+
fontSize: 13,
|
|
91
|
+
fontWeight: '700',
|
|
92
|
+
},
|
|
93
|
+
up: {
|
|
94
|
+
color: '#2e7d32',
|
|
95
|
+
},
|
|
96
|
+
down: {
|
|
97
|
+
color: '#d32f2f',
|
|
98
|
+
},
|
|
99
|
+
});
|
package/src/index.jsx
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import ReportScreen from './screens/ReportScreen';
|
|
1
|
+
import Report1Screen from './screens/Report1Screen';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
onReportSelect,
|
|
6
|
-
onClose,
|
|
7
|
-
reports = []
|
|
8
|
-
}) => {
|
|
9
|
-
return (
|
|
10
|
-
<ReportScreen
|
|
11
|
-
reports={reports}
|
|
12
|
-
onReportSelect={onReportSelect}
|
|
13
|
-
onClose={onClose}
|
|
14
|
-
/>
|
|
15
|
-
);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default ReportChart;
|
|
3
|
+
export default Report1Screen;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
ScrollView,
|
|
6
|
+
ActivityIndicator,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import fetchReport1 from '../api/report1Fetcher';
|
|
10
|
+
import Report1Card from '../components/Report1Card';
|
|
11
|
+
|
|
12
|
+
const Report1Screen = ({ apiEndpoint, apiToken }) => {
|
|
13
|
+
const [loading, setLoading] = useState(true);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const [rows, setRows] = useState([]);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const loadData = async () => {
|
|
19
|
+
try {
|
|
20
|
+
const data = await fetchReport1(apiEndpoint, apiToken);
|
|
21
|
+
setRows(data);
|
|
22
|
+
} catch (e) {
|
|
23
|
+
setError(e.message);
|
|
24
|
+
} finally {
|
|
25
|
+
setLoading(false);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
loadData();
|
|
30
|
+
}, [apiEndpoint, apiToken]);
|
|
31
|
+
|
|
32
|
+
if (loading) {
|
|
33
|
+
return (
|
|
34
|
+
<View style={styles.center}>
|
|
35
|
+
<ActivityIndicator size="large" />
|
|
36
|
+
<Text style={styles.info}>Loading report...</Text>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (error) {
|
|
42
|
+
return (
|
|
43
|
+
<View style={styles.center}>
|
|
44
|
+
<Text style={styles.error}>{error}</Text>
|
|
45
|
+
</View>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<ScrollView style={styles.container}>
|
|
51
|
+
{rows.map((item, index) => (
|
|
52
|
+
<Report1Card key={index} item={item} />
|
|
53
|
+
))}
|
|
54
|
+
</ScrollView>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default Report1Screen;
|
|
59
|
+
|
|
60
|
+
const styles = StyleSheet.create({
|
|
61
|
+
container: {
|
|
62
|
+
backgroundColor: '#f5f5f5',
|
|
63
|
+
padding: 16,
|
|
64
|
+
},
|
|
65
|
+
center: {
|
|
66
|
+
flex: 1,
|
|
67
|
+
justifyContent: 'center',
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
padding: 20,
|
|
70
|
+
},
|
|
71
|
+
info: {
|
|
72
|
+
marginTop: 12,
|
|
73
|
+
color: '#666',
|
|
74
|
+
},
|
|
75
|
+
error: {
|
|
76
|
+
fontSize: 16,
|
|
77
|
+
color: '#d32f2f',
|
|
78
|
+
textAlign: 'center',
|
|
79
|
+
},
|
|
80
|
+
});
|
package/src/api/fetcher.jsx
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
|
|
3
|
-
export class ApiFetcher {
|
|
4
|
-
static async fetchReportData(reportConfig) {
|
|
5
|
-
try {
|
|
6
|
-
console.log('Fetching report data from:', reportConfig.apiConfig.url);
|
|
7
|
-
|
|
8
|
-
const headers = {
|
|
9
|
-
'Content-Type': 'application/json',
|
|
10
|
-
'Accept': 'application/json'
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Add token if provided
|
|
14
|
-
if (reportConfig.apiConfig.token) {
|
|
15
|
-
headers['Authorization'] = `Bearer ${reportConfig.apiConfig.token}`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const response = await axios.get(reportConfig.apiConfig.url, {
|
|
19
|
-
timeout: 15000,
|
|
20
|
-
headers: headers
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
console.log('API Response received:', response.status);
|
|
24
|
-
|
|
25
|
-
// Transform data based on report type
|
|
26
|
-
return this.transformData(response.data, reportConfig);
|
|
27
|
-
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error('API Fetch Error:', error);
|
|
30
|
-
throw new Error(`Failed to fetch report: ${error.message}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static transformData(data, reportConfig) {
|
|
35
|
-
// For performance reports (type 1, 1.1, 1.2)
|
|
36
|
-
if (reportConfig.id === 1 || reportConfig.id === 1.1 || reportConfig.id === 1.2) {
|
|
37
|
-
return {
|
|
38
|
-
data: data.data || [],
|
|
39
|
-
title: reportConfig.title,
|
|
40
|
-
type: 'table',
|
|
41
|
-
subType: reportConfig.subType
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// For report 2 (Revenue by Mode)
|
|
46
|
-
if (reportConfig.id === 2) {
|
|
47
|
-
return {
|
|
48
|
-
data: Array.isArray(data) ? data : data.data || [],
|
|
49
|
-
title: reportConfig.title,
|
|
50
|
-
type: 'bar'
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// For report 3 (Shipment by Direction)
|
|
55
|
-
if (reportConfig.id === 3) {
|
|
56
|
-
return {
|
|
57
|
-
data: Array.isArray(data) ? data : data.data || [],
|
|
58
|
-
title: reportConfig.title,
|
|
59
|
-
type: 'pie'
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Default transformation
|
|
64
|
-
return {
|
|
65
|
-
data: data,
|
|
66
|
-
title: reportConfig.title,
|
|
67
|
-
type: reportConfig.type || 'bar'
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|