@dhiraj0720/report1chart 2.2.2 → 2.2.3
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 +2 -6
- package/src/api/fetcher.jsx +70 -0
- package/src/components/ChartRenderer.jsx +388 -0
- package/src/components/ReportList.jsx +135 -0
- package/src/components/ReportView.jsx +93 -0
- package/src/components/TableRenderer.jsx +647 -0
- package/src/index.jsx +4 -4
- package/src/screens/ReportScreen.jsx +417 -0
- package/src/api/ApiService.jsx +0 -138
- package/src/components/charts/BarChart.jsx +0 -116
- package/src/components/charts/LineChart.jsx +0 -134
- package/src/components/charts/PieChart.jsx +0 -120
- package/src/components/common/ErrorDisplay.jsx +0 -51
- package/src/components/common/LoadingSpinner.jsx +0 -32
- package/src/components/common/ReportCard.jsx +0 -84
- package/src/components/tables/CompactTable.jsx +0 -194
- package/src/components/tables/DefaultTable.jsx +0 -221
- package/src/components/tables/FreezeTable.jsx +0 -250
- package/src/screens/ReportDashboard.jsx +0 -121
- package/src/screens/ReportDetail.jsx +0 -222
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhiraj0720/report1chart",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"main": "src/index.jsx",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo 'No tests'"
|
|
@@ -22,9 +22,5 @@
|
|
|
22
22
|
"author": "Dhiraj",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"description": "A simple report chart and table package for React Native",
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"@babel/core": "^7.28.5",
|
|
27
|
-
"@babel/preset-env": "^7.28.5",
|
|
28
|
-
"@babel/preset-react": "^7.28.5"
|
|
29
|
-
}
|
|
25
|
+
"devDependencies": {}
|
|
30
26
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
ScrollView,
|
|
6
|
+
Dimensions,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
|
|
10
|
+
const { width: screenWidth } = Dimensions.get('window');
|
|
11
|
+
|
|
12
|
+
// Helper functions
|
|
13
|
+
export const formatNumber = (num) => {
|
|
14
|
+
return num.toLocaleString();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getColor = (index) => {
|
|
18
|
+
const colors = ['#4CAF50', '#2196F3', '#FF9800', '#E91E63', '#9C27B0', '#00BCD4'];
|
|
19
|
+
return colors[index % colors.length];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const renderLineChart = (data, title) => {
|
|
23
|
+
// Extract values and labels from data
|
|
24
|
+
const values = data.values || (Array.isArray(data) ? data.map(d => d.value || d.revenue || d.shipments || 0) : []);
|
|
25
|
+
const labels = data.labels || (Array.isArray(data) ? data.map(d => d.label || d.month || d.mode || d.direction || '') : []);
|
|
26
|
+
|
|
27
|
+
if (values.length === 0) {
|
|
28
|
+
return (
|
|
29
|
+
<View style={styles.noDataContainer}>
|
|
30
|
+
<Text style={styles.noDataText}>No data available for this report</Text>
|
|
31
|
+
</View>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const maxValue = Math.max(...values, 1);
|
|
36
|
+
const chartHeight = 200;
|
|
37
|
+
const chartWidth = Math.max(screenWidth - 64, values.length * 60);
|
|
38
|
+
const barWidth = Math.max(20, (chartWidth / values.length) - 10);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<View style={styles.chartContainer}>
|
|
42
|
+
<Text style={styles.chartTitle}>{title || ''}</Text>
|
|
43
|
+
<ScrollView
|
|
44
|
+
horizontal
|
|
45
|
+
showsHorizontalScrollIndicator={false}
|
|
46
|
+
contentContainerStyle={{ width: chartWidth }}
|
|
47
|
+
>
|
|
48
|
+
<View style={[styles.chart, { height: chartHeight }]}>
|
|
49
|
+
{values.map((value, index) => {
|
|
50
|
+
const height = (value / maxValue) * chartHeight;
|
|
51
|
+
const label = labels[index] || `Item ${index + 1}`;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<View key={index} style={[styles.linePointWrapper, { width: barWidth + 10 }]}>
|
|
55
|
+
<View style={[styles.linePoint, {
|
|
56
|
+
height: Math.max(height, 2),
|
|
57
|
+
width: barWidth
|
|
58
|
+
}]} />
|
|
59
|
+
<View style={styles.lineConnector} />
|
|
60
|
+
<Text style={styles.lineLabel} numberOfLines={1}>{label}</Text>
|
|
61
|
+
<Text style={styles.valueText}>{formatNumber(value)}</Text>
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
})}
|
|
65
|
+
</View>
|
|
66
|
+
</ScrollView>
|
|
67
|
+
</View>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const renderBarChart = (data, title) => {
|
|
72
|
+
// Extract values and labels from data
|
|
73
|
+
const isArray = Array.isArray(data);
|
|
74
|
+
const values = isArray ? data.map(d => d.revenue || d.value || d.shipments || 0) : (data.values || []);
|
|
75
|
+
const labels = isArray ? data.map(d => d.mode || d.label || '') : (data.labels || []);
|
|
76
|
+
|
|
77
|
+
if (values.length === 0) {
|
|
78
|
+
return (
|
|
79
|
+
<View style={styles.noDataContainer}>
|
|
80
|
+
<Text style={styles.noDataText}>No data available for this report</Text>
|
|
81
|
+
</View>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const maxValue = Math.max(...values, 1);
|
|
86
|
+
const chartHeight = 200;
|
|
87
|
+
const chartWidth = Math.max(screenWidth - 64, values.length * 60);
|
|
88
|
+
const barWidth = Math.min(40, Math.max(20, (chartWidth / values.length) - 10));
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<View style={styles.chartContainer}>
|
|
92
|
+
<Text style={styles.chartTitle}>{title || ''}</Text>
|
|
93
|
+
<ScrollView
|
|
94
|
+
horizontal
|
|
95
|
+
showsHorizontalScrollIndicator={false}
|
|
96
|
+
contentContainerStyle={{ width: chartWidth }}
|
|
97
|
+
>
|
|
98
|
+
<View style={[styles.chart, { height: chartHeight }]}>
|
|
99
|
+
{values.map((value, index) => {
|
|
100
|
+
const height = (value / maxValue) * chartHeight;
|
|
101
|
+
const label = labels?.[index] || `Item ${index + 1}`;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<View key={index} style={[styles.barWrapper, { width: barWidth + 20 }]}>
|
|
105
|
+
<View style={[styles.bar, {
|
|
106
|
+
height,
|
|
107
|
+
width: barWidth,
|
|
108
|
+
backgroundColor: getColor(index)
|
|
109
|
+
}]} />
|
|
110
|
+
<Text style={styles.barLabel} numberOfLines={1}>{label}</Text>
|
|
111
|
+
<Text style={styles.valueText}>{formatNumber(value)}</Text>
|
|
112
|
+
</View>
|
|
113
|
+
);
|
|
114
|
+
})}
|
|
115
|
+
</View>
|
|
116
|
+
</ScrollView>
|
|
117
|
+
</View>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const renderPieChart = (data, title) => {
|
|
122
|
+
// Ensure data is an array
|
|
123
|
+
const dataArray = Array.isArray(data) ? data : [];
|
|
124
|
+
|
|
125
|
+
if (dataArray.length === 0) {
|
|
126
|
+
return (
|
|
127
|
+
<View style={styles.noDataContainer}>
|
|
128
|
+
<Text style={styles.noDataText}>No data available for this report</Text>
|
|
129
|
+
</View>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const total = dataArray.reduce((sum, item) => {
|
|
134
|
+
const value = item.shipments || item.revenue || item.value || 0;
|
|
135
|
+
return sum + value;
|
|
136
|
+
}, 0);
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<View style={styles.chartContainer}>
|
|
140
|
+
<Text style={styles.chartTitle}>{title || ''}</Text>
|
|
141
|
+
<View style={styles.pieContainer}>
|
|
142
|
+
{dataArray.map((item, index) => {
|
|
143
|
+
const value = item.shipments || item.revenue || item.value || 0;
|
|
144
|
+
const label = item.direction || item.mode || item.label || `Item ${index + 1}`;
|
|
145
|
+
const percentage = total > 0 ? ((value / total) * 100).toFixed(1) : '0';
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<View key={index} style={styles.pieItem}>
|
|
149
|
+
<View style={[styles.pieColor, { backgroundColor: getColor(index) }]} />
|
|
150
|
+
<Text style={styles.pieLabel}>{label}:</Text>
|
|
151
|
+
<Text style={styles.pieValue}>
|
|
152
|
+
{formatNumber(value)} ({percentage}%)
|
|
153
|
+
</Text>
|
|
154
|
+
</View>
|
|
155
|
+
);
|
|
156
|
+
})}
|
|
157
|
+
</View>
|
|
158
|
+
{total > 0 && (
|
|
159
|
+
<Text style={styles.totalText}>Total: {formatNumber(total)}</Text>
|
|
160
|
+
)}
|
|
161
|
+
</View>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Additional chart renderer for Revenue Trend (line chart with different style)
|
|
166
|
+
export const renderRevenueTrendChart = (data, title) => {
|
|
167
|
+
// Handle different data formats
|
|
168
|
+
let values = [];
|
|
169
|
+
let labels = [];
|
|
170
|
+
|
|
171
|
+
if (data.values && data.labels) {
|
|
172
|
+
values = data.values;
|
|
173
|
+
labels = data.labels;
|
|
174
|
+
} else if (Array.isArray(data)) {
|
|
175
|
+
values = data.map(d => d.revenue || d.value || 0);
|
|
176
|
+
labels = data.map(d => d.month || d.label || '');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (values.length === 0) {
|
|
180
|
+
return (
|
|
181
|
+
<View style={styles.noDataContainer}>
|
|
182
|
+
<Text style={styles.noDataText}>No data available for this report</Text>
|
|
183
|
+
</View>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const maxValue = Math.max(...values, 1);
|
|
188
|
+
const chartHeight = 200;
|
|
189
|
+
const chartWidth = Math.max(screenWidth - 64, values.length * 80);
|
|
190
|
+
const pointWidth = 8;
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<View style={styles.chartContainer}>
|
|
194
|
+
<Text style={styles.chartTitle}>{title || 'Revenue Trend'}</Text>
|
|
195
|
+
<ScrollView
|
|
196
|
+
horizontal
|
|
197
|
+
showsHorizontalScrollIndicator={false}
|
|
198
|
+
contentContainerStyle={{ width: chartWidth }}
|
|
199
|
+
>
|
|
200
|
+
<View style={[styles.chart, { height: chartHeight, justifyContent: 'space-around' }]}>
|
|
201
|
+
{values.map((value, index) => {
|
|
202
|
+
const height = (value / maxValue) * chartHeight;
|
|
203
|
+
const label = labels[index] || `Period ${index + 1}`;
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<View key={index} style={styles.trendPointWrapper}>
|
|
207
|
+
<View style={styles.trendValueContainer}>
|
|
208
|
+
<Text style={styles.trendValueText}>{formatNumber(value)}</Text>
|
|
209
|
+
</View>
|
|
210
|
+
<View style={[styles.trendPoint, {
|
|
211
|
+
height: Math.max(height, 2),
|
|
212
|
+
width: pointWidth,
|
|
213
|
+
backgroundColor: '#4CAF50'
|
|
214
|
+
}]} />
|
|
215
|
+
<View style={styles.trendLine} />
|
|
216
|
+
<Text style={styles.trendLabel} numberOfLines={1}>{label}</Text>
|
|
217
|
+
</View>
|
|
218
|
+
);
|
|
219
|
+
})}
|
|
220
|
+
</View>
|
|
221
|
+
</ScrollView>
|
|
222
|
+
</View>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const styles = StyleSheet.create({
|
|
227
|
+
chartContainer: {
|
|
228
|
+
backgroundColor: '#fff',
|
|
229
|
+
borderRadius: 12,
|
|
230
|
+
padding: 16,
|
|
231
|
+
marginBottom: 16,
|
|
232
|
+
borderWidth: 1,
|
|
233
|
+
borderColor: '#e8e8e8',
|
|
234
|
+
shadowColor: '#000',
|
|
235
|
+
shadowOffset: { width: 0, height: 1 },
|
|
236
|
+
shadowOpacity: 0.05,
|
|
237
|
+
shadowRadius: 2,
|
|
238
|
+
elevation: 2,
|
|
239
|
+
},
|
|
240
|
+
chartTitle: {
|
|
241
|
+
fontSize: 18,
|
|
242
|
+
fontWeight: '700',
|
|
243
|
+
color: '#000',
|
|
244
|
+
marginBottom: 20,
|
|
245
|
+
textAlign: 'center',
|
|
246
|
+
},
|
|
247
|
+
chart: {
|
|
248
|
+
flexDirection: 'row',
|
|
249
|
+
alignItems: 'flex-end',
|
|
250
|
+
paddingHorizontal: 8,
|
|
251
|
+
},
|
|
252
|
+
barWrapper: {
|
|
253
|
+
alignItems: 'center',
|
|
254
|
+
marginHorizontal: 4,
|
|
255
|
+
},
|
|
256
|
+
bar: {
|
|
257
|
+
borderRadius: 4,
|
|
258
|
+
},
|
|
259
|
+
barLabel: {
|
|
260
|
+
marginTop: 8,
|
|
261
|
+
fontSize: 11,
|
|
262
|
+
color: '#666',
|
|
263
|
+
textAlign: 'center',
|
|
264
|
+
width: 60,
|
|
265
|
+
},
|
|
266
|
+
linePointWrapper: {
|
|
267
|
+
alignItems: 'center',
|
|
268
|
+
marginHorizontal: 4,
|
|
269
|
+
},
|
|
270
|
+
linePoint: {
|
|
271
|
+
backgroundColor: '#2196F3',
|
|
272
|
+
borderRadius: 2,
|
|
273
|
+
},
|
|
274
|
+
lineConnector: {
|
|
275
|
+
width: 2,
|
|
276
|
+
backgroundColor: '#2196F3',
|
|
277
|
+
opacity: 0.3,
|
|
278
|
+
marginVertical: 2,
|
|
279
|
+
flex: 1,
|
|
280
|
+
minHeight: 20,
|
|
281
|
+
},
|
|
282
|
+
lineLabel: {
|
|
283
|
+
marginTop: 8,
|
|
284
|
+
fontSize: 11,
|
|
285
|
+
color: '#666',
|
|
286
|
+
textAlign: 'center',
|
|
287
|
+
width: 60,
|
|
288
|
+
},
|
|
289
|
+
trendPointWrapper: {
|
|
290
|
+
alignItems: 'center',
|
|
291
|
+
marginHorizontal: 12,
|
|
292
|
+
},
|
|
293
|
+
trendPoint: {
|
|
294
|
+
borderRadius: 4,
|
|
295
|
+
},
|
|
296
|
+
trendLine: {
|
|
297
|
+
width: 2,
|
|
298
|
+
backgroundColor: '#4CAF50',
|
|
299
|
+
opacity: 0.5,
|
|
300
|
+
marginVertical: 2,
|
|
301
|
+
flex: 1,
|
|
302
|
+
minHeight: 20,
|
|
303
|
+
},
|
|
304
|
+
trendLabel: {
|
|
305
|
+
marginTop: 8,
|
|
306
|
+
fontSize: 11,
|
|
307
|
+
color: '#666',
|
|
308
|
+
textAlign: 'center',
|
|
309
|
+
width: 80,
|
|
310
|
+
},
|
|
311
|
+
trendValueContainer: {
|
|
312
|
+
backgroundColor: 'rgba(76, 175, 80, 0.1)',
|
|
313
|
+
paddingHorizontal: 6,
|
|
314
|
+
paddingVertical: 2,
|
|
315
|
+
borderRadius: 4,
|
|
316
|
+
marginBottom: 4,
|
|
317
|
+
},
|
|
318
|
+
trendValueText: {
|
|
319
|
+
fontSize: 10,
|
|
320
|
+
color: '#4CAF50',
|
|
321
|
+
fontWeight: '600',
|
|
322
|
+
},
|
|
323
|
+
valueText: {
|
|
324
|
+
fontSize: 10,
|
|
325
|
+
color: '#999',
|
|
326
|
+
marginTop: 4,
|
|
327
|
+
fontWeight: '500',
|
|
328
|
+
},
|
|
329
|
+
pieContainer: {
|
|
330
|
+
padding: 10,
|
|
331
|
+
},
|
|
332
|
+
pieItem: {
|
|
333
|
+
flexDirection: 'row',
|
|
334
|
+
alignItems: 'center',
|
|
335
|
+
marginBottom: 12,
|
|
336
|
+
padding: 8,
|
|
337
|
+
backgroundColor: '#f9f9f9',
|
|
338
|
+
borderRadius: 8,
|
|
339
|
+
},
|
|
340
|
+
pieColor: {
|
|
341
|
+
width: 16,
|
|
342
|
+
height: 16,
|
|
343
|
+
borderRadius: 8,
|
|
344
|
+
marginRight: 12,
|
|
345
|
+
},
|
|
346
|
+
pieLabel: {
|
|
347
|
+
fontSize: 15,
|
|
348
|
+
fontWeight: '600',
|
|
349
|
+
color: '#000',
|
|
350
|
+
flex: 1,
|
|
351
|
+
},
|
|
352
|
+
pieValue: {
|
|
353
|
+
fontSize: 14,
|
|
354
|
+
color: '#666',
|
|
355
|
+
fontWeight: '500',
|
|
356
|
+
},
|
|
357
|
+
totalText: {
|
|
358
|
+
fontSize: 16,
|
|
359
|
+
fontWeight: '700',
|
|
360
|
+
color: '#4CAF50',
|
|
361
|
+
textAlign: 'center',
|
|
362
|
+
marginTop: 16,
|
|
363
|
+
paddingTop: 16,
|
|
364
|
+
borderTopWidth: 1,
|
|
365
|
+
borderTopColor: '#eee',
|
|
366
|
+
},
|
|
367
|
+
noDataContainer: {
|
|
368
|
+
padding: 40,
|
|
369
|
+
alignItems: 'center',
|
|
370
|
+
justifyContent: 'center',
|
|
371
|
+
minHeight: 200,
|
|
372
|
+
},
|
|
373
|
+
noDataText: {
|
|
374
|
+
fontSize: 16,
|
|
375
|
+
color: '#999',
|
|
376
|
+
textAlign: 'center',
|
|
377
|
+
fontStyle: 'italic',
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
export default {
|
|
382
|
+
renderLineChart,
|
|
383
|
+
renderBarChart,
|
|
384
|
+
renderPieChart,
|
|
385
|
+
renderRevenueTrendChart,
|
|
386
|
+
getColor,
|
|
387
|
+
formatNumber
|
|
388
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
ScrollView,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
|
|
10
|
+
const ReportList = ({ reports, onReportClick, getColor }) => {
|
|
11
|
+
// Default reports if none provided
|
|
12
|
+
const defaultReports = [
|
|
13
|
+
{
|
|
14
|
+
id: 1,
|
|
15
|
+
name: 'Performance Report',
|
|
16
|
+
title: 'PERFORMANS RAPORU (USD)',
|
|
17
|
+
type: 'table',
|
|
18
|
+
description: 'Fallyet Kar/Zarar tablosu - Varsayılan Görünüm'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 1.1,
|
|
22
|
+
name: 'Performance Report A',
|
|
23
|
+
title: 'PERFORMANS RAPORU (USD)',
|
|
24
|
+
type: 'table',
|
|
25
|
+
description: 'Fallyet Kar/Zarar tablosu - Kompakt Görünüm'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 1.2,
|
|
29
|
+
name: 'Performance Report B',
|
|
30
|
+
title: 'PERFORMANS RAPORU (USD)',
|
|
31
|
+
type: 'table',
|
|
32
|
+
description: 'Fallyet Kar/Zarar tablosu - Sabit Kolonlu Görünüm'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 2,
|
|
36
|
+
name: 'Revenue by Mode',
|
|
37
|
+
title: 'Revenue by Mode',
|
|
38
|
+
type: 'bar',
|
|
39
|
+
description: 'Revenue distribution across modes'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 3,
|
|
43
|
+
name: 'Shipment by Direction',
|
|
44
|
+
title: 'Shipment by Direction',
|
|
45
|
+
type: 'pie',
|
|
46
|
+
description: 'Shipment direction analysis'
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const reportList = reports.length > 0 ? reports : defaultReports;
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<ScrollView style={styles.reportsList}>
|
|
54
|
+
{reportList.map((report) => (
|
|
55
|
+
<TouchableOpacity
|
|
56
|
+
key={report.id}
|
|
57
|
+
style={styles.reportCard}
|
|
58
|
+
onPress={() => onReportClick(report)}
|
|
59
|
+
>
|
|
60
|
+
<View style={[styles.reportIcon, { backgroundColor: getColor(report.id) }]}>
|
|
61
|
+
<Text style={styles.reportIconText}>{report.id}</Text>
|
|
62
|
+
</View>
|
|
63
|
+
<View style={styles.reportInfo}>
|
|
64
|
+
<Text style={styles.reportName}>{report.name}</Text>
|
|
65
|
+
<Text style={styles.reportTitle}>{report.title}</Text>
|
|
66
|
+
<Text style={styles.reportDesc}>{report.description}</Text>
|
|
67
|
+
</View>
|
|
68
|
+
<Text style={styles.arrow}>›</Text>
|
|
69
|
+
</TouchableOpacity>
|
|
70
|
+
))}
|
|
71
|
+
</ScrollView>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const styles = StyleSheet.create({
|
|
76
|
+
reportsList: {
|
|
77
|
+
flex: 1,
|
|
78
|
+
padding: 16,
|
|
79
|
+
},
|
|
80
|
+
reportCard: {
|
|
81
|
+
flexDirection: 'row',
|
|
82
|
+
alignItems: 'center',
|
|
83
|
+
backgroundColor: '#fff',
|
|
84
|
+
borderRadius: 12,
|
|
85
|
+
padding: 16,
|
|
86
|
+
marginBottom: 12,
|
|
87
|
+
borderWidth: 1,
|
|
88
|
+
borderColor: '#e8e8e8',
|
|
89
|
+
shadowColor: '#000',
|
|
90
|
+
shadowOffset: { width: 0, height: 1 },
|
|
91
|
+
shadowOpacity: 0.05,
|
|
92
|
+
shadowRadius: 2,
|
|
93
|
+
elevation: 2,
|
|
94
|
+
},
|
|
95
|
+
reportIcon: {
|
|
96
|
+
width: 44,
|
|
97
|
+
height: 44,
|
|
98
|
+
borderRadius: 22,
|
|
99
|
+
justifyContent: 'center',
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
marginRight: 12,
|
|
102
|
+
},
|
|
103
|
+
reportIconText: {
|
|
104
|
+
fontSize: 18,
|
|
105
|
+
fontWeight: '700',
|
|
106
|
+
color: '#fff',
|
|
107
|
+
},
|
|
108
|
+
reportInfo: {
|
|
109
|
+
flex: 1,
|
|
110
|
+
},
|
|
111
|
+
reportName: {
|
|
112
|
+
fontSize: 16,
|
|
113
|
+
fontWeight: '600',
|
|
114
|
+
color: '#000',
|
|
115
|
+
marginBottom: 2,
|
|
116
|
+
},
|
|
117
|
+
reportTitle: {
|
|
118
|
+
fontSize: 14,
|
|
119
|
+
fontWeight: '500',
|
|
120
|
+
color: '#4CAF50',
|
|
121
|
+
marginBottom: 4,
|
|
122
|
+
},
|
|
123
|
+
reportDesc: {
|
|
124
|
+
fontSize: 13,
|
|
125
|
+
color: '#666',
|
|
126
|
+
lineHeight: 18,
|
|
127
|
+
},
|
|
128
|
+
arrow: {
|
|
129
|
+
fontSize: 24,
|
|
130
|
+
color: '#ccc',
|
|
131
|
+
fontWeight: '300',
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
export default ReportList;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
ScrollView,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
|
|
10
|
+
const ReportView = ({ reportData, viewType, onBack, onClose }) => {
|
|
11
|
+
if (!reportData) {
|
|
12
|
+
return (
|
|
13
|
+
<View style={styles.container}>
|
|
14
|
+
<Text style={styles.noDataText}>No report data available</Text>
|
|
15
|
+
</View>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<View style={styles.container}>
|
|
21
|
+
<View style={styles.header}>
|
|
22
|
+
<TouchableOpacity style={styles.backButton} onPress={onBack}>
|
|
23
|
+
<Text style={styles.backText}>‹ Back</Text>
|
|
24
|
+
</TouchableOpacity>
|
|
25
|
+
<Text style={styles.headerTitle}>{reportData.title}</Text>
|
|
26
|
+
<TouchableOpacity style={styles.closeButton} onPress={onClose}>
|
|
27
|
+
<Text style={styles.closeText}>×</Text>
|
|
28
|
+
</TouchableOpacity>
|
|
29
|
+
</View>
|
|
30
|
+
|
|
31
|
+
<ScrollView style={styles.content}>
|
|
32
|
+
{/* Report content will be rendered here by parent component */}
|
|
33
|
+
</ScrollView>
|
|
34
|
+
</View>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const styles = StyleSheet.create({
|
|
39
|
+
container: {
|
|
40
|
+
flex: 1,
|
|
41
|
+
backgroundColor: '#f8f9fa',
|
|
42
|
+
},
|
|
43
|
+
header: {
|
|
44
|
+
flexDirection: 'row',
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
justifyContent: 'space-between',
|
|
47
|
+
backgroundColor: '#fff',
|
|
48
|
+
paddingHorizontal: 16,
|
|
49
|
+
paddingVertical: 12,
|
|
50
|
+
borderBottomWidth: 1,
|
|
51
|
+
borderBottomColor: '#e0e0e0',
|
|
52
|
+
},
|
|
53
|
+
headerTitle: {
|
|
54
|
+
fontSize: 18,
|
|
55
|
+
fontWeight: '700',
|
|
56
|
+
color: '#000',
|
|
57
|
+
flex: 1,
|
|
58
|
+
textAlign: 'center',
|
|
59
|
+
},
|
|
60
|
+
backButton: {
|
|
61
|
+
padding: 8,
|
|
62
|
+
},
|
|
63
|
+
backText: {
|
|
64
|
+
fontSize: 16,
|
|
65
|
+
color: '#4CAF50',
|
|
66
|
+
fontWeight: '600',
|
|
67
|
+
},
|
|
68
|
+
closeButton: {
|
|
69
|
+
width: 32,
|
|
70
|
+
height: 32,
|
|
71
|
+
borderRadius: 16,
|
|
72
|
+
backgroundColor: '#f0f0f0',
|
|
73
|
+
justifyContent: 'center',
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
},
|
|
76
|
+
closeText: {
|
|
77
|
+
fontSize: 20,
|
|
78
|
+
color: '#666',
|
|
79
|
+
fontWeight: '300',
|
|
80
|
+
},
|
|
81
|
+
content: {
|
|
82
|
+
flex: 1,
|
|
83
|
+
padding: 16,
|
|
84
|
+
},
|
|
85
|
+
noDataText: {
|
|
86
|
+
fontSize: 16,
|
|
87
|
+
color: '#999',
|
|
88
|
+
textAlign: 'center',
|
|
89
|
+
padding: 40,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export default ReportView;
|