@dhiraj0720/report1chart 2.2.6 → 2.2.8

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 CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@dhiraj0720/report1chart",
3
- "version": "2.2.6",
3
+ "version": "2.2.8",
4
4
  "main": "src/index.jsx",
5
5
  "scripts": {
6
6
  "test": "echo 'No tests'"
7
7
  },
8
8
  "dependencies": {
9
- "axios": "^1.13.2"
9
+ "axios": "^1.13.2",
10
+ "react-native-svg": "^15.15.1"
10
11
  },
11
12
  "peerDependencies": {
12
13
  "react": ">=16.8.0",
@@ -21,6 +22,5 @@
21
22
  ],
22
23
  "author": "Dhiraj",
23
24
  "license": "MIT",
24
- "description": "A simple report chart and table package for React Native",
25
- "devDependencies": {}
25
+ "description": "A simple report chart and table package for React Native"
26
26
  }
@@ -0,0 +1,22 @@
1
+ import axios from 'axios';
2
+
3
+ export const fetchReport3Table = async (url, token) => {
4
+ const res = await axios.get(url, {
5
+ headers: { Authorization: token },
6
+ });
7
+ return res.data;
8
+ };
9
+
10
+ export const fetchReport3Line = async (url, token) => {
11
+ const res = await axios.get(url, {
12
+ headers: { Authorization: token },
13
+ });
14
+ return res.data;
15
+ };
16
+
17
+ export const fetchReport3Bar = async (url, token) => {
18
+ const res = await axios.get(url, {
19
+ headers: { Authorization: token },
20
+ });
21
+ return res.data;
22
+ };
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import { View, Text, StyleSheet } from 'react-native';
3
+
4
+ const BarLineChart = ({ data }) => {
5
+ if (!data?.series?.length) return null;
6
+
7
+ const max = Math.max(...data.series.flatMap(s => s.data));
8
+
9
+ return (
10
+ <View style={styles.container}>
11
+ <Text style={styles.title}>{data.title}</Text>
12
+
13
+ <View style={styles.chart}>
14
+ {data.labels.map((label, i) => (
15
+ <View key={label} style={styles.group}>
16
+ {data.series.map((s, idx) => {
17
+ const height = (s.data[i] / max) * 120;
18
+ return (
19
+ <View
20
+ key={idx}
21
+ style={[
22
+ styles.bar,
23
+ {
24
+ height,
25
+ backgroundColor:
26
+ idx === 0
27
+ ? '#FB8C00'
28
+ : idx === 1
29
+ ? '#1E88E5'
30
+ : '#90CAF9',
31
+ },
32
+ ]}
33
+ />
34
+ );
35
+ })}
36
+ <Text style={styles.label}>{label}</Text>
37
+ </View>
38
+ ))}
39
+ </View>
40
+
41
+ <View style={styles.legend}>
42
+ {data.series.map(s => (
43
+ <Text key={s.name} style={styles.legendText}>
44
+ ■ {s.name}
45
+ </Text>
46
+ ))}
47
+ </View>
48
+ </View>
49
+ );
50
+ };
51
+
52
+ export default BarLineChart;
53
+
54
+ const styles = StyleSheet.create({
55
+ container: {
56
+ backgroundColor: '#fff',
57
+ padding: 12,
58
+ borderRadius: 12,
59
+ marginVertical: 12,
60
+ },
61
+ title: {
62
+ fontWeight: '700',
63
+ marginBottom: 8,
64
+ textAlign: 'center',
65
+ },
66
+ chart: {
67
+ flexDirection: 'row',
68
+ alignItems: 'flex-end',
69
+ justifyContent: 'space-around',
70
+ height: 160,
71
+ },
72
+ group: {
73
+ alignItems: 'center',
74
+ flexDirection: 'row',
75
+ },
76
+ bar: {
77
+ width: 10,
78
+ marginHorizontal: 2,
79
+ borderRadius: 2,
80
+ },
81
+ label: {
82
+ fontSize: 10,
83
+ marginTop: 4,
84
+ position: 'absolute',
85
+ bottom: -16,
86
+ },
87
+ legend: {
88
+ flexDirection: 'row',
89
+ justifyContent: 'center',
90
+ marginTop: 16,
91
+ },
92
+ legendText: {
93
+ fontSize: 12,
94
+ marginHorizontal: 8,
95
+ },
96
+ });
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ScrollView, Text, TouchableOpacity, StyleSheet } from 'react-native';
2
+ import { ScrollView, TouchableOpacity, Text, StyleSheet } from 'react-native';
3
3
 
4
4
  const DivisionSelector = ({ divisions, selected, onSelect }) => (
5
5
  <ScrollView horizontal showsHorizontalScrollIndicator={false}>
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { View, Text, ScrollView, StyleSheet } from 'react-native';
3
+
4
+ const Cell = ({ children, bold }) => (
5
+ <Text style={[styles.cell, bold && styles.bold]}>{children}</Text>
6
+ );
7
+
8
+ const FrozenTableReport2 = ({ rows }) => (
9
+ <View style={styles.container}>
10
+ <View style={styles.frozen}>
11
+ <Cell bold>AY</Cell>
12
+ {rows.map((r, i) => (
13
+ <Cell key={i} bold={r.monthLabel === 'Total'}>{r.monthLabel}</Cell>
14
+ ))}
15
+ </View>
16
+
17
+ <ScrollView horizontal>
18
+ <View>
19
+ <View style={styles.headerRow}>
20
+ {[
21
+ '2024 TEU','2025 TEU','TEU %',
22
+ '2024 Kar','2025 Kar','Kar %',
23
+ '2025 Bütçe','Bütçe %'
24
+ ].map(h => <Cell key={h} bold>{h}</Cell>)}
25
+ </View>
26
+
27
+ {rows.map((r, i) => (
28
+ <View key={i} style={styles.row}>
29
+ <Cell>{r.teu2024}</Cell>
30
+ <Cell>{r.teu2025}</Cell>
31
+ <Cell>{r.teuChangePercent}%</Cell>
32
+ <Cell>{r.profitUsd2024}</Cell>
33
+ <Cell>{r.profitUsd2025}</Cell>
34
+ <Cell>{r.profitChangePercent}%</Cell>
35
+ <Cell>{r.budgetProfitUsd2025}</Cell>
36
+ <Cell>{r.budgetChangePercent}%</Cell>
37
+ </View>
38
+ ))}
39
+ </View>
40
+ </ScrollView>
41
+ </View>
42
+ );
43
+
44
+ export default FrozenTableReport2;
45
+
46
+ const styles = StyleSheet.create({
47
+ container: { flexDirection: 'row' },
48
+ frozen: { width: 90, backgroundColor: '#f4f4f4' },
49
+ headerRow: { flexDirection: 'row', backgroundColor: '#f4f4f4' },
50
+ row: { flexDirection: 'row' },
51
+ cell: {
52
+ width: 90,
53
+ padding: 8,
54
+ textAlign: 'center',
55
+ borderBottomWidth: 1,
56
+ borderColor: '#ddd',
57
+ },
58
+ bold: { fontWeight: '700' },
59
+ });
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { View, Text, ScrollView, StyleSheet } from 'react-native';
3
+
4
+ const Cell = ({ children, bold }) => (
5
+ <Text style={[styles.cell, bold && styles.bold]}>{children}</Text>
6
+ );
7
+
8
+ const FrozenTableReport3 = ({ rows }) => (
9
+ <View style={styles.container}>
10
+ <View style={styles.frozen}>
11
+ <Cell bold>AY</Cell>
12
+ {rows.map((r, i) => (
13
+ <Cell key={i} bold={r.monthLabel === 'Total'}>{r.monthLabel}</Cell>
14
+ ))}
15
+ </View>
16
+
17
+ <ScrollView horizontal>
18
+ <View>
19
+ <View style={styles.headerRow}>
20
+ {[
21
+ '2024 Yük','2025 Yük','Yük %',
22
+ '2024 Gelir','2025 Gelir','Gelir %',
23
+ '2025 Bütçe','Bütçe %'
24
+ ].map(h => <Cell key={h} bold>{h}</Cell>)}
25
+ </View>
26
+
27
+ {rows.map((r, i) => (
28
+ <View key={i} style={styles.row}>
29
+ <Cell>{r.loadCount2024}</Cell>
30
+ <Cell>{r.loadCount2025}</Cell>
31
+ <Cell>{r.loadCountChangePercent}%</Cell>
32
+ <Cell>{r.revenueTl2024}</Cell>
33
+ <Cell>{r.revenueTl2025}</Cell>
34
+ <Cell>{r.revenueChangePercent}%</Cell>
35
+ <Cell>{r.budgetRevenueTl2025}</Cell>
36
+ <Cell>{r.budgetChangePercent}%</Cell>
37
+ </View>
38
+ ))}
39
+ </View>
40
+ </ScrollView>
41
+ </View>
42
+ );
43
+
44
+ export default FrozenTableReport3;
45
+
46
+ const styles = StyleSheet.create({
47
+ container: { flexDirection: 'row' },
48
+ frozen: { width: 90, backgroundColor: '#f4f4f4' },
49
+ headerRow: { flexDirection: 'row', backgroundColor: '#f4f4f4' },
50
+ row: { flexDirection: 'row' },
51
+ cell: {
52
+ width: 100,
53
+ padding: 8,
54
+ textAlign: 'center',
55
+ borderBottomWidth: 1,
56
+ borderColor: '#ddd',
57
+ },
58
+ bold: { fontWeight: '700' },
59
+ });
@@ -1,35 +1,47 @@
1
1
  import React from 'react';
2
- import { View, Text, ScrollView, StyleSheet } from 'react-native';
2
+ import { View, Text, StyleSheet } from 'react-native';
3
3
 
4
4
  const LineChart = ({ data }) => {
5
- if (!data?.series) return null;
5
+ if (!data?.series?.length) return null;
6
6
 
7
7
  const max = Math.max(...data.series.flatMap(s => s.data));
8
8
 
9
9
  return (
10
10
  <View style={styles.container}>
11
11
  <Text style={styles.title}>{data.title}</Text>
12
- <ScrollView horizontal>
13
- <View style={styles.chart}>
14
- {data.labels.map((label, i) => (
15
- <View key={i} style={styles.column}>
16
- {data.series.map((s, idx) => (
17
- <View
18
- key={idx}
19
- style={[
20
- styles.bar,
21
- {
22
- height: (s.data[i] / max) * 120,
23
- backgroundColor: idx === 0 ? '#2962FF' : '#9E9E9E'
24
- }
25
- ]}
26
- />
27
- ))}
28
- <Text style={styles.label}>{label}</Text>
12
+
13
+ <View style={styles.chart}>
14
+ {data.labels.map((label, i) => (
15
+ <View key={label} style={styles.column}>
16
+ <View style={styles.lines}>
17
+ {data.series.map((s, idx) => {
18
+ const height = (s.data[i] / max) * 120;
19
+ return (
20
+ <View
21
+ key={idx}
22
+ style={[
23
+ styles.point,
24
+ {
25
+ bottom: height,
26
+ backgroundColor: idx === 0 ? '#FB8C00' : '#1E88E5',
27
+ },
28
+ ]}
29
+ />
30
+ );
31
+ })}
29
32
  </View>
30
- ))}
31
- </View>
32
- </ScrollView>
33
+ <Text style={styles.label}>{label}</Text>
34
+ </View>
35
+ ))}
36
+ </View>
37
+
38
+ <View style={styles.legend}>
39
+ {data.series.map((s, i) => (
40
+ <Text key={s.name} style={styles.legendText}>
41
+ ● {s.name}
42
+ </Text>
43
+ ))}
44
+ </View>
33
45
  </View>
34
46
  );
35
47
  };
@@ -37,10 +49,47 @@ const LineChart = ({ data }) => {
37
49
  export default LineChart;
38
50
 
39
51
  const styles = StyleSheet.create({
40
- container: { marginVertical: 12 },
41
- title: { fontWeight: '700', marginBottom: 8 },
42
- chart: { flexDirection: 'row', alignItems: 'flex-end' },
43
- column: { alignItems: 'center', marginHorizontal: 6 },
44
- bar: { width: 8, marginHorizontal: 1, borderRadius: 2 },
45
- label: { fontSize: 10, marginTop: 4 }
52
+ container: {
53
+ backgroundColor: '#fff',
54
+ padding: 12,
55
+ borderRadius: 12,
56
+ marginVertical: 12,
57
+ },
58
+ title: {
59
+ fontWeight: '700',
60
+ marginBottom: 8,
61
+ textAlign: 'center',
62
+ },
63
+ chart: {
64
+ flexDirection: 'row',
65
+ justifyContent: 'space-around',
66
+ height: 160,
67
+ },
68
+ column: {
69
+ alignItems: 'center',
70
+ width: 40,
71
+ },
72
+ lines: {
73
+ flex: 1,
74
+ justifyContent: 'flex-end',
75
+ },
76
+ point: {
77
+ width: 8,
78
+ height: 8,
79
+ borderRadius: 4,
80
+ position: 'absolute',
81
+ },
82
+ label: {
83
+ fontSize: 10,
84
+ marginTop: 4,
85
+ },
86
+ legend: {
87
+ flexDirection: 'row',
88
+ justifyContent: 'center',
89
+ marginTop: 8,
90
+ },
91
+ legendText: {
92
+ fontSize: 12,
93
+ marginHorizontal: 8,
94
+ },
46
95
  });
@@ -1,17 +1,22 @@
1
1
  import React from 'react';
2
- import { ScrollView, Text, TouchableOpacity, StyleSheet } from 'react-native';
2
+ import { ScrollView, TouchableOpacity, Text, StyleSheet } from 'react-native';
3
3
 
4
4
  const MonthSelector = ({ months, selected, onSelect }) => (
5
- <ScrollView horizontal showsHorizontalScrollIndicator={false}>
5
+ <ScrollView horizontal showsHorizontalScrollIndicator={false} style={styles.row}>
6
+ <TouchableOpacity
7
+ style={[styles.btn, selected === 'ALL' && styles.active]}
8
+ onPress={() => onSelect('ALL')}
9
+ >
10
+ <Text style={styles.text}>Select all</Text>
11
+ </TouchableOpacity>
12
+
6
13
  {months.map(m => (
7
14
  <TouchableOpacity
8
15
  key={m}
9
- style={[styles.card, selected === m && styles.active]}
16
+ style={[styles.btn, selected === m && styles.active]}
10
17
  onPress={() => onSelect(m)}
11
18
  >
12
- <Text style={[styles.text, selected === m && styles.activeText]}>
13
- {m}
14
- </Text>
19
+ <Text style={styles.text}>{m}</Text>
15
20
  </TouchableOpacity>
16
21
  ))}
17
22
  </ScrollView>
@@ -20,15 +25,14 @@ const MonthSelector = ({ months, selected, onSelect }) => (
20
25
  export default MonthSelector;
21
26
 
22
27
  const styles = StyleSheet.create({
23
- card: {
28
+ row: { paddingVertical: 10 },
29
+ btn: {
24
30
  paddingHorizontal: 14,
25
31
  paddingVertical: 8,
26
32
  borderRadius: 16,
27
- borderWidth: 1,
28
- borderColor: '#ccc',
33
+ backgroundColor: '#eef2f7',
29
34
  marginRight: 8,
30
35
  },
31
- active: { backgroundColor: '#000' },
32
- text: { fontSize: 13 },
33
- activeText: { color: '#fff', fontWeight: '700' },
36
+ active: { backgroundColor: '#0f172a' },
37
+ text: { color: '#000', fontWeight: '600' },
34
38
  });
@@ -23,6 +23,6 @@ const styles = StyleSheet.create({
23
23
  },
24
24
  fill: {
25
25
  height: '100%',
26
- backgroundColor: '#f57c00', // orange like original
26
+ backgroundColor: '#f57c00',
27
27
  },
28
28
  });
@@ -2,13 +2,13 @@ import React from 'react';
2
2
  import { View, Text, StyleSheet } from 'react-native';
3
3
  import ProgressBar from './ProgressBar';
4
4
 
5
- const format = (num) => (num ?? 0).toLocaleString();
5
+ const format = n => (n ?? 0).toLocaleString();
6
6
 
7
7
  const Trend = ({ value }) => {
8
- const positive = value >= 0;
8
+ const up = value >= 0;
9
9
  return (
10
- <Text style={[styles.trend, positive ? styles.up : styles.down]}>
11
- {positive ? '↑' : '↓'} {Math.abs(value)}%
10
+ <Text style={[styles.trend, up ? styles.up : styles.down]}>
11
+ {up ? '↑' : '↓'} {Math.abs(value)}%
12
12
  </Text>
13
13
  );
14
14
  };
@@ -23,10 +23,8 @@ const Row = ({ label, value }) => (
23
23
  const Report1Card = ({ item }) => {
24
24
  return (
25
25
  <View style={styles.card}>
26
- {/* TITLE */}
27
26
  <Text style={styles.title}>{item.name}</Text>
28
27
 
29
- {/* VALUES */}
30
28
  <Row label="2024 Actual" value={format(item.actual2024)} />
31
29
  <Row label="2025 Actual" value={format(item.actual2025)} />
32
30
 
@@ -42,16 +40,14 @@ const Report1Card = ({ item }) => {
42
40
  <Trend value={item.budgetVariancePercent} />
43
41
  </View>
44
42
 
45
- {/* OPEX / GROSS PROFIT */}
46
43
  {item.opexToGrossProfitPercent !== undefined && (
47
44
  <>
48
45
  <View style={styles.row}>
49
- <Text style={styles.label}>OPEX / Gross Profit</Text>
46
+ <Text style={styles.label}>Faaliyet Gid. / Brüt Kar</Text>
50
47
  <Text style={styles.value}>
51
48
  {item.opexToGrossProfitPercent}%
52
49
  </Text>
53
50
  </View>
54
-
55
51
  <ProgressBar value={item.opexToGrossProfitPercent} />
56
52
  </>
57
53
  )}
@@ -74,7 +70,6 @@ const styles = StyleSheet.create({
74
70
  fontSize: 16,
75
71
  fontWeight: '700',
76
72
  marginBottom: 12,
77
- color: '#000',
78
73
  },
79
74
  row: {
80
75
  flexDirection: 'row',
@@ -88,16 +83,11 @@ const styles = StyleSheet.create({
88
83
  value: {
89
84
  fontSize: 13,
90
85
  fontWeight: '600',
91
- color: '#000',
92
86
  },
93
87
  trend: {
94
88
  fontSize: 13,
95
89
  fontWeight: '700',
96
90
  },
97
- up: {
98
- color: '#2e7d32',
99
- },
100
- down: {
101
- color: '#d32f2f',
102
- },
91
+ up: { color: '#2e7d32' },
92
+ down: { color: '#d32f2f' },
103
93
  });
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { View, Text } from 'react-native';
3
+ import Svg, { Rect, Polyline, Circle, Text as SvgText } from 'react-native-svg';
4
+
5
+ const SvgBarLineChart = ({ data }) => {
6
+ if (!data?.series?.length) return null;
7
+
8
+ const width = 360;
9
+ const height = 190;
10
+ const padding = 30;
11
+ const barWidth = 12;
12
+
13
+ const max = Math.max(...data.series.flatMap(s => s.data));
14
+
15
+ const scaleX = i =>
16
+ padding + i * ((width - padding * 2) / data.labels.length);
17
+
18
+ const scaleY = v =>
19
+ height - padding - (v / max) * (height - padding * 2);
20
+
21
+ return (
22
+ <View style={{ backgroundColor: '#fff', padding: 12, borderRadius: 12 }}>
23
+ <Text style={{ fontWeight: '700', textAlign: 'center', marginBottom: 8 }}>
24
+ {data.title}
25
+ </Text>
26
+
27
+ <Svg width={width} height={height}>
28
+ {/* Bars */}
29
+ {data.labels.map((_, i) =>
30
+ data.series.slice(0, 2).map((s, idx) => (
31
+ <Rect
32
+ key={`${i}-${idx}`}
33
+ x={scaleX(i) + idx * (barWidth + 4)}
34
+ y={scaleY(s.data[i])}
35
+ width={barWidth}
36
+ height={height - padding - scaleY(s.data[i])}
37
+ fill={idx === 0 ? '#FB8C00' : '#1E88E5'}
38
+ rx="2"
39
+ />
40
+ ))
41
+ )}
42
+
43
+ {/* Budget dotted line */}
44
+ {data.series[2] && (
45
+ <>
46
+ <Polyline
47
+ points={data.series[2].data
48
+ .map((v, i) => `${scaleX(i) + barWidth},${scaleY(v)}`)
49
+ .join(' ')}
50
+ fill="none"
51
+ stroke="#90CAF9"
52
+ strokeWidth="2"
53
+ strokeDasharray="4,4"
54
+ />
55
+
56
+ {data.series[2].data.map((v, i) => (
57
+ <Circle
58
+ key={i}
59
+ cx={scaleX(i) + barWidth}
60
+ cy={scaleY(v)}
61
+ r="4"
62
+ fill="#90CAF9"
63
+ />
64
+ ))}
65
+ </>
66
+ )}
67
+
68
+ {/* Value labels */}
69
+ {data.series[2]?.data.map((v, i) => (
70
+ <SvgText
71
+ key={i}
72
+ x={scaleX(i) + barWidth}
73
+ y={scaleY(v) - 8}
74
+ fontSize="9"
75
+ fill="#333"
76
+ textAnchor="middle"
77
+ >
78
+ {(v / 1_000_000).toFixed(0)}M
79
+ </SvgText>
80
+ ))}
81
+ </Svg>
82
+ </View>
83
+ );
84
+ };
85
+
86
+ export default SvgBarLineChart;
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { View, Text } from 'react-native';
3
+ import Svg, { Polyline, Circle, Line, Text as SvgText } from 'react-native-svg';
4
+
5
+ const SvgLineChart = ({ data }) => {
6
+ if (!data?.series?.length) return null;
7
+
8
+ const width = 340;
9
+ const height = 180;
10
+ const padding = 30;
11
+
12
+ const allValues = data.series.flatMap(s => s.data);
13
+ const max = Math.max(...allValues);
14
+ const min = Math.min(...allValues);
15
+
16
+ const scaleX = i =>
17
+ padding + (i * (width - padding * 2)) / (data.labels.length - 1);
18
+
19
+ const scaleY = v =>
20
+ height - padding - ((v - min) / (max - min)) * (height - padding * 2);
21
+
22
+ return (
23
+ <View style={{ backgroundColor: '#fff', padding: 12, borderRadius: 12 }}>
24
+ <Text style={{ fontWeight: '700', textAlign: 'center', marginBottom: 8 }}>
25
+ {data.title}
26
+ </Text>
27
+
28
+ <Svg width={width} height={height}>
29
+ {/* Grid */}
30
+ {[0.25, 0.5, 0.75].map(p => (
31
+ <Line
32
+ key={p}
33
+ x1={padding}
34
+ x2={width - padding}
35
+ y1={padding + p * (height - padding * 2)}
36
+ y2={padding + p * (height - padding * 2)}
37
+ stroke="#e0e0e0"
38
+ strokeDasharray="4,4"
39
+ />
40
+ ))}
41
+
42
+ {/* Lines */}
43
+ {data.series.map((s, idx) => {
44
+ const points = s.data
45
+ .map((v, i) => `${scaleX(i)},${scaleY(v)}`)
46
+ .join(' ');
47
+
48
+ return (
49
+ <Polyline
50
+ key={s.name}
51
+ points={points}
52
+ fill="none"
53
+ stroke={idx === 0 ? '#FB8C00' : '#1E88E5'}
54
+ strokeWidth="2"
55
+ />
56
+ );
57
+ })}
58
+
59
+ {/* Points + Labels */}
60
+ {data.series.map((s, idx) =>
61
+ s.data.map((v, i) => (
62
+ <React.Fragment key={`${idx}-${i}`}>
63
+ <Circle
64
+ cx={scaleX(i)}
65
+ cy={scaleY(v)}
66
+ r="4"
67
+ fill={idx === 0 ? '#FB8C00' : '#1E88E5'}
68
+ />
69
+ <SvgText
70
+ x={scaleX(i)}
71
+ y={scaleY(v) - 8}
72
+ fontSize="9"
73
+ fill="#333"
74
+ textAnchor="middle"
75
+ >
76
+ {v}
77
+ </SvgText>
78
+ </React.Fragment>
79
+ ))
80
+ )}
81
+ </Svg>
82
+ </View>
83
+ );
84
+ };
85
+
86
+ export default SvgLineChart;
package/src/index.jsx CHANGED
@@ -1,22 +1,48 @@
1
1
  import React, { useState } from 'react';
2
- import ReportsHome from './screens/ReportsHome';
2
+
3
+ import ReportListScreen from './screens/ReportListScreen';
3
4
  import Report1Screen from './screens/Report1Screen';
4
5
  import Report2Screen from './screens/Report2Screen';
5
6
  import Report3Screen from './screens/Report3Screen';
6
7
 
7
- const AnalyticsReports = (props) => {
8
+ const AnalyticsReports = ({ config }) => {
8
9
  const [active, setActive] = useState(null);
9
10
 
10
- if (active === 1)
11
- return <Report1Screen {...props} onBack={() => setActive(null)} />;
11
+ if (!active) {
12
+ return <ReportListScreen onSelect={setActive} />;
13
+ }
14
+
15
+ if (active === 1) {
16
+ return (
17
+ <Report1Screen
18
+ endpoint={config.report1.url}
19
+ token={config.token}
20
+ onBack={() => setActive(null)}
21
+ />
22
+ );
23
+ }
12
24
 
13
- if (active === 2)
14
- return <Report2Screen {...props} onBack={() => setActive(null)} />;
25
+ if (active === 2) {
26
+ return (
27
+ <Report2Screen
28
+ api={config.report2}
29
+ token={config.token}
30
+ onBack={() => setActive(null)}
31
+ />
32
+ );
33
+ }
15
34
 
16
- if (active === 3)
17
- return <Report3Screen onBack={() => setActive(null)} />;
35
+ if (active === 3) {
36
+ return (
37
+ <Report3Screen
38
+ api={config.report3}
39
+ token={config.token}
40
+ onBack={() => setActive(null)}
41
+ />
42
+ );
43
+ }
18
44
 
19
- return <ReportsHome onSelect={setActive} />;
45
+ return null;
20
46
  };
21
47
 
22
48
  export default AnalyticsReports;
@@ -3,18 +3,22 @@ import { ScrollView, Text, ActivityIndicator } from 'react-native';
3
3
  import fetchReport1 from '../api/report1Fetcher';
4
4
  import Report1Card from '../components/Report1Card';
5
5
 
6
- const Report1Screen = ({ report1Endpoint, token, onBack }) => {
6
+ const Report1Screen = ({ endpoint, token, onBack }) => {
7
7
  const [rows, setRows] = useState(null);
8
8
 
9
9
  useEffect(() => {
10
- fetchReport1(report1Endpoint, token).then(setRows);
10
+ fetchReport1(endpoint, token).then(setRows);
11
11
  }, []);
12
12
 
13
13
  if (!rows) return <ActivityIndicator />;
14
14
 
15
15
  return (
16
- <ScrollView>
17
- <Text onPress={onBack}>‹ Back</Text>
16
+ <ScrollView style={{ padding: 16 }}>
17
+ <Text onPress={onBack} style={{ marginBottom: 12 }}>‹ Back</Text>
18
+ <Text style={{ fontSize: 18, fontWeight: '700', marginBottom: 12 }}>
19
+ PERFORMANS RAPORU (USD)
20
+ </Text>
21
+
18
22
  {rows.map((r, i) => (
19
23
  <Report1Card key={i} item={r} />
20
24
  ))}
@@ -1,27 +1,23 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { ScrollView, Text, ActivityIndicator } from 'react-native';
3
- import {
4
- getDivisions,
5
- getTable,
6
- getLine,
7
- getBar,
8
- } from '../api/report2Fetcher';
3
+
4
+ import { getDivisions, getTable, getLine, getBar } from '../api/report2Fetcher';
9
5
  import MonthSelector from '../components/MonthSelector';
10
6
  import DivisionSelector from '../components/DivisionSelector';
11
- import FrozenTable from '../components/FrozenTable';
12
- import LineChart from '../components/LineChart';
13
- import BarChart from '../components/BarChart';
7
+ import FrozenTableReport2 from '../components/FrozenTableReport2';
8
+ import SvgLineChart from '../components/SvgLineChart';
9
+ import SvgBarLineChart from '../components/SvgBarLineChart';
14
10
 
15
- const Report2Screen = ({ report2, token, onBack }) => {
11
+ const Report2Screen = ({ api, token, onBack }) => {
16
12
  const [divisions, setDivisions] = useState([]);
17
13
  const [division, setDivision] = useState(null);
14
+ const [month, setMonth] = useState('ALL');
18
15
  const [table, setTable] = useState(null);
19
16
  const [line, setLine] = useState(null);
20
17
  const [bar, setBar] = useState(null);
21
- const [month, setMonth] = useState(null);
22
18
 
23
19
  useEffect(() => {
24
- getDivisions(report2.divisions, token).then(d => {
20
+ getDivisions(api.divisions, token).then(d => {
25
21
  setDivisions(d);
26
22
  setDivision(d[0]?.code);
27
23
  });
@@ -30,37 +26,42 @@ const Report2Screen = ({ report2, token, onBack }) => {
30
26
  useEffect(() => {
31
27
  if (!division) return;
32
28
  Promise.all([
33
- getTable(report2.table, division, token),
34
- getLine(report2.lineChart, division, token),
35
- getBar(report2.barChart, division, token)
29
+ getTable(api.table, division, token),
30
+ getLine(api.line, division, token),
31
+ getBar(api.bar, division, token),
36
32
  ]).then(([t, l, b]) => {
37
33
  setTable(t);
38
34
  setLine(l);
39
35
  setBar(b);
40
- setMonth(null);
36
+ setMonth('ALL');
41
37
  });
42
38
  }, [division]);
43
39
 
44
40
  if (!table || !line || !bar) return <ActivityIndicator />;
45
41
 
46
- const rows = month
47
- ? table.rows.filter(r => r.monthLabel === month)
48
- : table.rows;
42
+ const rows =
43
+ month === 'ALL'
44
+ ? table.rows
45
+ : table.rows.filter(r => r.monthLabel === month);
49
46
 
50
47
  return (
51
- <ScrollView>
48
+ <ScrollView style={{ padding: 16 }}>
52
49
  <Text onPress={onBack}>‹ Back</Text>
53
50
 
51
+ <Text style={{ fontSize: 18, fontWeight: '700', marginVertical: 12 }}>
52
+ {table.title}
53
+ </Text>
54
+
54
55
  <MonthSelector
55
56
  months={line.labels}
56
57
  selected={month}
57
58
  onSelect={setMonth}
58
59
  />
59
60
 
60
- <FrozenTable rows={rows} />
61
+ <FrozenTableReport2 rows={rows} />
61
62
 
62
- <LineChart data={line} />
63
- <BarChart data={bar} />
63
+ <SvgLineChart data={line} />
64
+ <SvgBarLineChart data={bar} />
64
65
 
65
66
  <DivisionSelector
66
67
  divisions={divisions}
@@ -1,13 +1,58 @@
1
- import React from 'react';
2
- import { View, Text } from 'react-native';
3
-
4
- const Report3Screen = ({ onBack }) => (
5
- <View style={{ padding: 16 }}>
6
- <Text onPress={onBack}>‹ Back</Text>
7
- <Text style={{ marginTop: 20, fontSize: 16 }}>
8
- Report 3 – Coming Soon
9
- </Text>
10
- </View>
11
- );
1
+ import React, { useEffect, useState } from 'react';
2
+ import { ScrollView, Text, ActivityIndicator } from 'react-native';
3
+
4
+ import {
5
+ fetchReport3Table,
6
+ fetchReport3Line,
7
+ fetchReport3Bar,
8
+ } from '../api/report3Fetcher';
9
+
10
+ import MonthSelector from '../components/MonthSelector';
11
+ import FrozenTableReport3 from '../components/FrozenTableReport3';
12
+ import SvgLineChart from '../components/SvgLineChart';
13
+ import SvgBarLineChart from '../components/SvgBarLineChart';
14
+
15
+ const Report3Screen = ({ api, token, onBack }) => {
16
+ const [table, setTable] = useState(null);
17
+ const [line, setLine] = useState(null);
18
+ const [bar, setBar] = useState(null);
19
+ const [month, setMonth] = useState('ALL');
20
+
21
+ useEffect(() => {
22
+ fetchReport3Table(api.table, token).then(setTable);
23
+ fetchReport3Line(api.line, token).then(setLine);
24
+ fetchReport3Bar(api.bar, token).then(setBar);
25
+ }, []);
26
+
27
+ if (!table || !line || !bar) return <ActivityIndicator />;
28
+
29
+ const months = table.rows.filter(r => r.month !== 99).map(r => r.monthLabel);
30
+
31
+ const rows =
32
+ month === 'ALL'
33
+ ? table.rows
34
+ : table.rows.filter(r => r.monthLabel === month);
35
+
36
+ return (
37
+ <ScrollView style={{ padding: 16 }}>
38
+ <Text onPress={onBack}>‹ Back</Text>
39
+
40
+ <Text style={{ fontSize: 18, fontWeight: '700', marginVertical: 12 }}>
41
+ {table.title}
42
+ </Text>
43
+
44
+ <MonthSelector
45
+ months={months}
46
+ selected={month}
47
+ onSelect={setMonth}
48
+ />
49
+
50
+ <FrozenTableReport3 rows={rows} />
51
+
52
+ <SvgLineChart data={line} />
53
+ <SvgBarLineChart data={bar} />
54
+ </ScrollView>
55
+ );
56
+ };
12
57
 
13
58
  export default Report3Screen;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import ReportCard from '../components/ReportCard';
4
+
5
+ const ReportListScreen = ({ onSelect }) => {
6
+ return (
7
+ <View style={{ padding: 16 }}>
8
+ <ReportCard title="Report 1" onPress={() => onSelect(1)} />
9
+ <ReportCard title="Report 2" onPress={() => onSelect(2)} />
10
+ <ReportCard title="Report 3" onPress={() => onSelect(3)} />
11
+ </View>
12
+ );
13
+ };
14
+
15
+ export default ReportListScreen;
@@ -1,48 +0,0 @@
1
- import React from 'react';
2
- import { View, Text, ScrollView, StyleSheet } from 'react-native';
3
-
4
- const BarChart = ({ data }) => {
5
- if (!data?.series) return null;
6
-
7
- const max = Math.max(...data.series.flatMap(s => s.data));
8
-
9
- const colors = ['#FB8C00', '#1E88E5', '#9E9E9E'];
10
-
11
- return (
12
- <View style={styles.container}>
13
- <Text style={styles.title}>{data.title}</Text>
14
- <ScrollView horizontal>
15
- <View style={styles.chart}>
16
- {data.labels.map((label, i) => (
17
- <View key={i} style={styles.group}>
18
- {data.series.map((s, idx) => (
19
- <View
20
- key={idx}
21
- style={[
22
- styles.bar,
23
- {
24
- height: (s.data[i] / max) * 120,
25
- backgroundColor: colors[idx]
26
- }
27
- ]}
28
- />
29
- ))}
30
- <Text style={styles.label}>{label}</Text>
31
- </View>
32
- ))}
33
- </View>
34
- </ScrollView>
35
- </View>
36
- );
37
- };
38
-
39
- export default BarChart;
40
-
41
- const styles = StyleSheet.create({
42
- container: { marginVertical: 12 },
43
- title: { fontWeight: '700', marginBottom: 8 },
44
- chart: { flexDirection: 'row', alignItems: 'flex-end' },
45
- group: { flexDirection: 'row', alignItems: 'flex-end', marginHorizontal: 6 },
46
- bar: { width: 10, marginHorizontal: 2, borderRadius: 2 },
47
- label: { fontSize: 10, marginTop: 4, textAlign: 'center', width: 40 }
48
- });
@@ -1,71 +0,0 @@
1
- import React from 'react';
2
- import { View, Text, ScrollView, StyleSheet } from 'react-native';
3
-
4
- const Cell = ({ children, bold }) => (
5
- <View style={styles.cell}>
6
- <Text style={[styles.text, bold && styles.bold]}>{children}</Text>
7
- </View>
8
- );
9
-
10
- const FrozenTable = ({ rows = [] }) => {
11
- if (!rows.length) {
12
- return <Text style={styles.noData}>No data available</Text>;
13
- }
14
-
15
- return (
16
- <View style={styles.container}>
17
- {/* Frozen Column */}
18
- <View style={styles.frozen}>
19
- <Cell bold>AY</Cell>
20
- {rows.map((r, i) => (
21
- <Cell key={i} bold={r.monthLabel === 'Total'}>
22
- {r.monthLabel}
23
- </Cell>
24
- ))}
25
- </View>
26
-
27
- {/* Scrollable Columns */}
28
- <ScrollView horizontal>
29
- <View>
30
- <View style={styles.headerRow}>
31
- <Cell bold>2024 TEU</Cell>
32
- <Cell bold>2025 TEU</Cell>
33
- <Cell bold>TEU %</Cell>
34
- </View>
35
-
36
- {rows.map((r, i) => (
37
- <View key={i} style={styles.row}>
38
- <Cell>{r.teu2024}</Cell>
39
- <Cell>{r.teu2025}</Cell>
40
- <Cell style={r.teuChangePercent < 0 ? styles.down : styles.up}>
41
- {r.teuChangePercent}%
42
- </Cell>
43
- </View>
44
- ))}
45
- </View>
46
- </ScrollView>
47
- </View>
48
- );
49
- };
50
-
51
- export default FrozenTable;
52
-
53
- const styles = StyleSheet.create({
54
- container: { flexDirection: 'row', marginVertical: 12 },
55
- frozen: { width: 90, backgroundColor: '#f4f4f4' },
56
- headerRow: { flexDirection: 'row', backgroundColor: '#f4f4f4' },
57
- row: { flexDirection: 'row' },
58
- cell: {
59
- width: 90,
60
- padding: 8,
61
- borderBottomWidth: 1,
62
- borderColor: '#ddd',
63
- justifyContent: 'center',
64
- alignItems: 'center'
65
- },
66
- text: { fontSize: 12 },
67
- bold: { fontWeight: '700' },
68
- up: { color: 'green' },
69
- down: { color: 'red' },
70
- noData: { textAlign: 'center', padding: 16 }
71
- });
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- import { View, StyleSheet } from 'react-native';
3
- import ReportCard from '../components/ReportCard';
4
-
5
- const ReportsHome = ({ onSelect }) => (
6
- <View style={styles.container}>
7
- <ReportCard title="Report 1 – Operating Profit" onPress={() => onSelect(1)} />
8
- <ReportCard title="Report 2 – TEU & Profit" onPress={() => onSelect(2)} />
9
- <ReportCard title="Report 3 – Coming Soon" onPress={() => onSelect(3)} />
10
- </View>
11
- );
12
-
13
- export default ReportsHome;
14
-
15
- const styles = StyleSheet.create({
16
- container: { padding: 16 },
17
- });