@dhiraj0720/report1chart 2.6.7 → 2.6.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhiraj0720/report1chart",
3
- "version": "2.6.7",
3
+ "version": "2.6.8",
4
4
  "main": "src/index.jsx",
5
5
  "scripts": {
6
6
  "test": "echo 'No tests'"
@@ -1,13 +1,11 @@
1
1
  import React from 'react';
2
2
  import { View, Text, ScrollView, StyleSheet } from 'react-native';
3
3
 
4
- // Helper: Format numbers with commas (e.g., 1083203 → 1,083,203)
5
4
  const formatNumber = (value) => {
6
5
  if (value === null || value === undefined || value === '') return '-';
7
6
  return Number(value).toLocaleString('en-US');
8
7
  };
9
8
 
10
- // Percentage cell with up/down arrow and color
11
9
  const PercentCell = ({ value }) => {
12
10
  if (value === null || value === undefined) return <Text>-</Text>;
13
11
  const positive = value >= 0;
@@ -21,10 +19,10 @@ const PercentCell = ({ value }) => {
21
19
  );
22
20
  };
23
21
 
24
- // Reusable cell component
25
- const Cell = ({ children, bold = false, highlight = false }) => (
22
+ const Cell = ({ children, bold = false, highlight = false, width }) => (
26
23
  <View style={[
27
24
  styles.cell,
25
+ { width }, // dynamic width
28
26
  bold && styles.bold,
29
27
  highlight && styles.highlightCell
30
28
  ]}>
@@ -34,24 +32,24 @@ const Cell = ({ children, bold = false, highlight = false }) => (
34
32
  </View>
35
33
  );
36
34
 
37
- const FrozenTableReport2A = ({ rows = [] }) => {
38
- if (!rows || rows.length === 0) {
39
- return <Text>No data available</Text>;
35
+ const FrozenTableReport2A = ({ rows = [], isFullscreen = false }) => {
36
+ if (!rows.length) {
37
+ return <Text style={{ textAlign: 'center', padding: 20 }}>No data available</Text>;
40
38
  }
41
39
 
40
+ // Dynamic widths based on fullscreen mode
41
+ const frozenColumnWidth = isFullscreen ? 180 : 120;
42
+ const cellWidth = isFullscreen ? 140 : 130;
43
+
42
44
  return (
43
45
  <View style={styles.container}>
44
- {/* Frozen Left Column - AY (Month) */}
45
- <View style={styles.frozenColumn}>
46
- <Cell bold>AY</Cell>
47
- {rows.map((row, index) => {
46
+ {/* Frozen Column */}
47
+ <View style={[styles.frozenColumn, { width: frozenColumnWidth }]}>
48
+ <Cell bold width={frozenColumnWidth}>AY</Cell>
49
+ {rows.map((row, i) => {
48
50
  const isTotal = row.monthLabel === 'Total';
49
51
  return (
50
- <Cell
51
- key={index}
52
- bold={isTotal}
53
- highlight={isTotal}
54
- >
52
+ <Cell key={i} bold={isTotal} highlight={isTotal} width={frozenColumnWidth}>
55
53
  {row.monthLabel}
56
54
  </Cell>
57
55
  );
@@ -61,41 +59,24 @@ const FrozenTableReport2A = ({ rows = [] }) => {
61
59
  {/* Scrollable Columns */}
62
60
  <ScrollView horizontal showsHorizontalScrollIndicator={false}>
63
61
  <View>
64
- {/* Header Row */}
65
62
  <View style={styles.headerRow}>
66
- {[
67
- '2024 TEU', '2025 TEU', 'TEU %',
68
- '2024 Kar', '2025 Kar', 'Kar %',
69
- '2025 Bütçe', 'Bütçe %'
70
- ].map((header) => (
71
- <Cell key={header} bold>
72
- {header}
73
- </Cell>
63
+ {['2024 TEU', '2025 TEU', 'TEU %', '2024 Kar', '2025 Kar', 'Kar %', '2025 Bütçe', 'Bütçe %'].map((h) => (
64
+ <Cell key={h} bold width={cellWidth}>{h}</Cell>
74
65
  ))}
75
66
  </View>
76
67
 
77
- {/* Data Rows */}
78
- {rows.map((row, index) => {
68
+ {rows.map((row, i) => {
79
69
  const isTotal = row.monthLabel === 'Total';
80
-
81
70
  return (
82
- <View key={index} style={styles.dataRow}>
83
- <Cell highlight={isTotal}>{formatNumber(row.teu2024)}</Cell>
84
- <Cell highlight={isTotal}>{formatNumber(row.teu2025)}</Cell>
85
- <Cell highlight={isTotal}>
86
- <PercentCell value={row.teuChangePercent} />
87
- </Cell>
88
-
89
- <Cell highlight={isTotal}>{formatNumber(row.profitUsd2024)}</Cell>
90
- <Cell highlight={isTotal}>{formatNumber(row.profitUsd2025)}</Cell>
91
- <Cell highlight={isTotal}>
92
- <PercentCell value={row.profitChangePercent} />
93
- </Cell>
94
-
95
- <Cell highlight={isTotal}>{formatNumber(row.budgetProfitUsd2025)}</Cell>
96
- <Cell highlight={isTotal}>
97
- <PercentCell value={row.budgetChangePercent} />
98
- </Cell>
71
+ <View key={i} style={styles.dataRow}>
72
+ <Cell highlight={isTotal} width={cellWidth}>{formatNumber(row.teu2024)}</Cell>
73
+ <Cell highlight={isTotal} width={cellWidth}>{formatNumber(row.teu2025)}</Cell>
74
+ <Cell highlight={isTotal} width={cellWidth}><PercentCell value={row.teuChangePercent} /></Cell>
75
+ <Cell highlight={isTotal} width={cellWidth}>{formatNumber(row.profitUsd2024)}</Cell>
76
+ <Cell highlight={isTotal} width={cellWidth}>{formatNumber(row.profitUsd2025)}</Cell>
77
+ <Cell highlight={isTotal} width={cellWidth}><PercentCell value={row.profitChangePercent} /></Cell>
78
+ <Cell highlight={isTotal} width={cellWidth}>{formatNumber(row.budgetProfitUsd2025)}</Cell>
79
+ <Cell highlight={isTotal} width={cellWidth}><PercentCell value={row.budgetChangePercent} /></Cell>
99
80
  </View>
100
81
  );
101
82
  })}
@@ -118,20 +99,13 @@ const styles = StyleSheet.create({
118
99
  backgroundColor: '#fff',
119
100
  },
120
101
  frozenColumn: {
121
- width: 120,
122
102
  backgroundColor: '#f4f6f8',
123
103
  borderRightWidth: 1,
124
104
  borderColor: '#ddd',
125
105
  },
126
- headerRow: {
127
- flexDirection: 'row',
128
- backgroundColor: '#f4f6f8',
129
- },
130
- dataRow: {
131
- flexDirection: 'row',
132
- },
106
+ headerRow: { flexDirection: 'row', backgroundColor: '#f4f6f8' },
107
+ dataRow: { flexDirection: 'row' },
133
108
  cell: {
134
- width: 130,
135
109
  paddingVertical: 10,
136
110
  paddingHorizontal: 6,
137
111
  justifyContent: 'center',
@@ -143,18 +117,8 @@ const styles = StyleSheet.create({
143
117
  textAlign: 'center',
144
118
  color: '#333',
145
119
  },
146
- bold: {
147
- backgroundColor: '#e9f0f8',
148
- },
149
- boldText: {
150
- fontWeight: '700',
151
- },
152
- highlightCell: {
153
- backgroundColor: '#e9f0f8',
154
- },
155
- percentText: {
156
- fontWeight: '700',
157
- fontSize: 12,
158
- textAlign: 'center',
159
- },
120
+ bold: { backgroundColor: '#e9f0f8' },
121
+ boldText: { fontWeight: '700' },
122
+ highlightCell: { backgroundColor: '#e9f0f8' },
123
+ percentText: { fontWeight: '700', fontSize: 12, textAlign: 'center' },
160
124
  });
@@ -93,7 +93,7 @@ const SvgBarLineChartCompact = ({ data }) => {
93
93
  fill="white"
94
94
  fontWeight="700"
95
95
  >
96
- ${formatNumber(val2024)}
96
+ {formatNumber(val2024)}
97
97
  </SvgText>
98
98
  )}
99
99
 
@@ -114,7 +114,7 @@ const SvgBarLineChartCompact = ({ data }) => {
114
114
  fill="white"
115
115
  fontWeight="700"
116
116
  >
117
- ${formatNumber(val2025)}
117
+ {formatNumber(val2025)}
118
118
  </SvgText>
119
119
  )}
120
120
 
@@ -150,7 +150,7 @@ const SvgBarLineChartCompact = ({ data }) => {
150
150
  fill="#333"
151
151
  fontWeight="700"
152
152
  >
153
- ${formatNumber(budget)}
153
+ {formatNumber(budget)}
154
154
  </SvgText>
155
155
 
156
156
  {/* X Axis Label - Rotated */}
@@ -8,7 +8,6 @@ import {
8
8
  Modal,
9
9
  Dimensions,
10
10
  ActivityIndicator,
11
- Alert,
12
11
  } from 'react-native';
13
12
  import Svg, { Path } from 'react-native-svg';
14
13
  import { filterChartByMonths } from '../utils/filterChartByMonths';
@@ -23,7 +22,6 @@ const Report2AScreen = ({ api, token, onBack }) => {
23
22
  const [monthsModal, setMonthsModal] = useState(false);
24
23
  const [divisionModal, setDivisionModal] = useState(false);
25
24
  const [fullscreen, setFullscreen] = useState(false);
26
- const [zoomScale, setZoomScale] = useState(1);
27
25
 
28
26
  const [months, setMonths] = useState([]);
29
27
  const [selectedMonths, setSelectedMonths] = useState([]);
@@ -40,8 +38,7 @@ const Report2AScreen = ({ api, token, onBack }) => {
40
38
  .then((d) => {
41
39
  setDivisions(d);
42
40
  if (d.length > 0) setDivision(d[0].code);
43
- })
44
- .catch(() => Alert.alert('Error', 'Failed to load divisions'));
41
+ });
45
42
  }, [api.divisions, token]);
46
43
 
47
44
  useEffect(() => {
@@ -76,7 +73,6 @@ const Report2AScreen = ({ api, token, onBack }) => {
76
73
  const filteredLine = filterChartByMonths(line, selectedMonths);
77
74
  const filteredBar = filterChartByMonths(bar, selectedMonths);
78
75
 
79
- // Detect landscape
80
76
  const { width, height } = Dimensions.get('window');
81
77
  const isLandscape = width > height;
82
78
 
@@ -93,67 +89,28 @@ const Report2AScreen = ({ api, token, onBack }) => {
93
89
  {/* FILTERS */}
94
90
  <View style={styles.filterBar}>
95
91
  <TouchableOpacity onPress={() => setMonthsModal(true)} style={styles.filterItem}>
96
- {/* FILTER FUNNEL ICON */}
97
92
  <Svg width={22} height={22} viewBox="0 0 24 24" fill="none">
98
- <Path
99
- d="M20 4H4V6.5L12 14.5L20 6.5V4Z"
100
- stroke="#000"
101
- strokeWidth={2}
102
- strokeLinecap="round"
103
- strokeLinejoin="round"
104
- />
105
- <Path
106
- d="M8 11V19L16 19V11"
107
- stroke="#000"
108
- strokeWidth={2}
109
- strokeLinecap="round"
110
- strokeLinejoin="round"
111
- />
93
+ <Path d="M20 4H4V6.5L12 14.5L20 6.5V4Z" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
94
+ <Path d="M8 11V19L16 19V11" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
112
95
  </Svg>
113
96
  <Text style={styles.filterText}>Months ({selectedMonths.length}/{months.length})</Text>
114
97
  </TouchableOpacity>
115
98
 
116
99
  <TouchableOpacity onPress={() => setDivisionModal(true)} style={styles.filterItem}>
117
- {/* SAME FILTER ICON */}
118
100
  <Svg width={22} height={22} viewBox="0 0 24 24" fill="none">
119
- <Path
120
- d="M20 4H4V6.5L12 14.5L20 6.5V4Z"
121
- stroke="#000"
122
- strokeWidth={2}
123
- strokeLinecap="round"
124
- strokeLinejoin="round"
125
- />
126
- <Path
127
- d="M8 11V19L16 19V11"
128
- stroke="#000"
129
- strokeWidth={2}
130
- strokeLinecap="round"
131
- strokeLinejoin="round"
132
- />
101
+ <Path d="M20 4H4V6.5L12 14.5L20 6.5V4Z" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
102
+ <Path d="M8 11V19L16 19V11" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
133
103
  </Svg>
134
104
  <Text style={styles.filterText}>{currentDivisionName}</Text>
135
105
  </TouchableOpacity>
136
106
  </View>
137
107
 
138
108
  <ScrollView style={styles.content}>
139
- {/* FULL SCREEN ICON ABOVE TABLE */}
140
- <TouchableOpacity
141
- onPress={() => {
142
- setFullscreen(true);
143
- setZoomScale(1);
144
- Alert.alert('Tip', 'Rotate your device to landscape for full view');
145
- }}
146
- style={styles.fullScreenBtn}
147
- >
148
- {/* FULL SCREEN EXPAND ICON */}
109
+ {/* FULL SCREEN BUTTON */}
110
+ <TouchableOpacity onPress={() => setFullscreen(true)} style={styles.fullScreenBtn}>
149
111
  <Svg width={28} height={28} viewBox="0 0 24 24" fill="none">
150
- <Path
151
- d="M8 3H5C4.44772 3 4 3.44772 4 4V8M20 8V4C20 3.44772 19.5523 3 19 3H16M16 21H19C19.5523 21 20 20.5523 20 20V16M4 16V20C4 20.5523 4.44772 21 5 21H8"
152
- stroke="#000"
153
- strokeWidth={2}
154
- strokeLinecap="round"
155
- strokeLinejoin="round"
156
- />
112
+ <Path d="M8 3H5C4.44772 3 4 3.44772 4 4V8M20 8V4C20 3.44772 19.5523 3 19 3H16M16 21H19C19.5523 21 20 20.5523 20 20V16M4 16V20C4 20.5523 4.44772 21 5 21H8"
113
+ stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
157
114
  </Svg>
158
115
  <Text style={styles.fullScreenText}>Full Screen Table</Text>
159
116
  </TouchableOpacity>
@@ -169,30 +126,39 @@ const Report2AScreen = ({ api, token, onBack }) => {
169
126
  </View>
170
127
  </ScrollView>
171
128
 
172
- {/* FULL SCREEN MODAL - SIMPLE ZOOM */}
173
- <Modal visible={fullscreen} supportedOrientations={['portrait', 'landscape']}>
129
+ {/* FULL SCREEN MODAL - PERFECT LANDSCAPE FIT + ZOOM */}
130
+ <Modal visible={fullscreen} supportedOrientations={['portrait', 'landscape']} animationType="fade">
174
131
  <View style={styles.fullModal}>
132
+ {/* TOP BAR - ONE LINE */}
175
133
  <View style={styles.fullHeader}>
134
+ <Text style={styles.fullHintText}>
135
+ Rotate device • Pinch to zoom
136
+ </Text>
176
137
  <TouchableOpacity onPress={() => setFullscreen(false)}>
177
- <Text style={styles.closeFull}>✕</Text>
138
+ <Text style={styles.closeBtn}>✕</Text>
178
139
  </TouchableOpacity>
179
- <Text style={styles.fullHint}>Rotate to landscape • Pinch to zoom</Text>
180
140
  </View>
181
141
 
142
+ {/* ZOOMABLE & FIT TABLE */}
182
143
  <ScrollView
183
144
  maximumZoomScale={3}
184
- minimumZoomScale={0.8}
185
- centerContent
186
- contentContainerStyle={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center' }}
145
+ minimumZoomScale={0.7}
146
+ showsHorizontalScrollIndicator={false}
147
+ showsVerticalScrollIndicator={false}
148
+ contentContainerStyle={styles.zoomContent}
149
+ pinchGestureEnabled={true}
150
+ bouncesZoom={true}
187
151
  >
188
- <View style={{ transform: [{ scale: isLandscape ? 1.4 : 1 }] }}>
152
+ <View style={[
153
+ styles.tableWrapper,
154
+ isLandscape && styles.landscapeFit
155
+ ]}>
189
156
  <FrozenTableReport2A rows={table.rows} isFullscreen />
190
157
  </View>
191
158
  </ScrollView>
192
159
  </View>
193
160
  </Modal>
194
161
 
195
- {/* Existing modals */}
196
162
  <MonthFilterModal visible={monthsModal} months={months} selected={selectedMonths} onApply={setSelectedMonths} onClose={() => setMonthsModal(false)} />
197
163
  <DivisionFilterModal visible={divisionModal} divisions={divisions} selected={division} onSelect={setDivision} onClose={() => setDivisionModal(false)} />
198
164
  </View>
@@ -241,9 +207,42 @@ const styles = StyleSheet.create({
241
207
  chartContainer: { borderWidth: 1, borderColor: '#ddd', borderRadius: 10, overflow: 'hidden', marginVertical: 12, backgroundColor: '#fff' },
242
208
 
243
209
  fullModal: { flex: 1, backgroundColor: '#fff' },
244
- fullHeader: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', padding: 16, backgroundColor: '#f8f8f8', position: 'relative' },
245
- closeFull: { position: 'absolute', left: 16, fontSize: 28, color: '#000' },
246
- fullHint: { fontSize: 15, color: '#000' },
210
+ fullHeader: {
211
+ flexDirection: 'row',
212
+ justifyContent: 'center',
213
+ alignItems: 'center',
214
+ paddingVertical: 16,
215
+ paddingHorizontal: 20,
216
+ backgroundColor: '#f8f8f8',
217
+ borderBottomWidth: 1,
218
+ borderColor: '#ddd',
219
+ },
220
+ fullHintText: {
221
+ fontSize: 16,
222
+ color: '#000',
223
+ fontWeight: '600',
224
+ textAlign: 'center',
225
+ flex: 1,
226
+ },
227
+ closeBtn: { fontSize: 28, color: '#000', paddingLeft: 20 },
228
+
229
+ zoomContent: {
230
+ flexGrow: 1,
231
+ justifyContent: 'center',
232
+ alignItems: 'center',
233
+ padding: 20,
234
+ },
235
+ tableWrapper: {
236
+ shadowColor: '#000',
237
+ shadowOffset: { width: 0, height: 2 },
238
+ shadowOpacity: 0.1,
239
+ shadowRadius: 8,
240
+ elevation: 5,
241
+ },
242
+ landscapeFit: {
243
+ transform: [{ scale: 1.4 }], // Perfect fit in landscape
244
+ maxWidth: '100%',
245
+ },
247
246
  });
248
247
 
249
248
  export default Report2AScreen;