@dhiraj0720/report1chart 2.6.3 → 2.6.5

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.3",
3
+ "version": "2.6.5",
4
4
  "main": "src/index.jsx",
5
5
  "scripts": {
6
6
  "test": "echo 'No tests'"
@@ -1,33 +1,42 @@
1
1
  import React from 'react';
2
- import { View, Text, ScrollView, StyleSheet, Dimensions } from 'react-native';
3
-
4
- const { width, height } = Dimensions.get('window');
2
+ import { View, Text, ScrollView, StyleSheet } from 'react-native';
5
3
 
6
4
  const Arrow = ({ value }) => (
7
- <Text style={[styles.arrow, value >= 0 ? styles.up : styles.down]}>
5
+ <Text
6
+ style={[
7
+ styles.arrow,
8
+ value >= 0 ? styles.up : styles.down,
9
+ ]}
10
+ >
8
11
  {value >= 0 ? '↑' : '↓'} {Math.abs(value)}%
9
12
  </Text>
10
13
  );
11
14
 
12
15
  const Cell = ({ children, bold, frozen }) => (
13
- <View style={[styles.cell, frozen && styles.frozenCell]}>
14
- <Text style={[styles.text, bold && styles.bold]} numberOfLines={1}>
16
+ <View
17
+ style={[
18
+ styles.cell,
19
+ frozen && styles.frozenCell,
20
+ ]}
21
+ >
22
+ <Text
23
+ numberOfLines={1}
24
+ ellipsizeMode="tail"
25
+ style={[
26
+ styles.text,
27
+ bold && styles.bold,
28
+ ]}
29
+ >
15
30
  {children}
16
31
  </Text>
17
32
  </View>
18
33
  );
19
34
 
20
- const FrozenTableReport1A = ({ rows, isFullscreen = false }) => {
21
- const isLandscape = width > height;
22
-
23
- // Auto-adjust cell width in fullscreen landscape
24
- const cellWidth = isFullscreen && isLandscape ? 160 : 110;
25
- const frozenWidth = isFullscreen && isLandscape ? 200 : 150;
26
- const fontSize = isFullscreen ? 14 : 12;
27
-
35
+ const FrozenTableReport1A = ({ rows }) => {
28
36
  return (
29
37
  <View style={styles.container}>
30
- <View style={[styles.frozen, { width: frozenWidth }]}>
38
+ {/* LEFT FROZEN COLUMN */}
39
+ <View style={styles.frozen}>
31
40
  <Cell bold frozen>FAALİYET</Cell>
32
41
  {rows.map((r, i) => (
33
42
  <Cell key={i} frozen bold>
@@ -36,6 +45,7 @@ const FrozenTableReport1A = ({ rows, isFullscreen = false }) => {
36
45
  ))}
37
46
  </View>
38
47
 
48
+ {/* SCROLLABLE COLUMNS */}
39
49
  <ScrollView horizontal showsHorizontalScrollIndicator={false}>
40
50
  <View>
41
51
  <View style={styles.headerRow}>
@@ -48,10 +58,10 @@ const FrozenTableReport1A = ({ rows, isFullscreen = false }) => {
48
58
 
49
59
  {rows.map((r, i) => (
50
60
  <View key={i} style={styles.row}>
51
- <Cell>{r.actual2024?.toLocaleString()}</Cell>
52
- <Cell>{r.actual2025?.toLocaleString()}</Cell>
61
+ <Cell>{r.actual2024}</Cell>
62
+ <Cell>{r.actual2025}</Cell>
53
63
  <Cell><Arrow value={r.actualChangePercent} /></Cell>
54
- <Cell>{r.budget2025?.toLocaleString()}</Cell>
64
+ <Cell>{r.budget2025}</Cell>
55
65
  <Cell><Arrow value={r.budgetVariancePercent} /></Cell>
56
66
  </View>
57
67
  ))}
@@ -61,6 +71,11 @@ const FrozenTableReport1A = ({ rows, isFullscreen = false }) => {
61
71
  );
62
72
  };
63
73
 
74
+ export default FrozenTableReport1A;
75
+
76
+ /* ======================
77
+ STYLES (COMPACT)
78
+ ====================== */
64
79
  const styles = StyleSheet.create({
65
80
  container: {
66
81
  flexDirection: 'row',
@@ -70,24 +85,55 @@ const styles = StyleSheet.create({
70
85
  overflow: 'hidden',
71
86
  backgroundColor: '#fff',
72
87
  },
73
- frozen: { backgroundColor: '#f5f7fa' },
74
- frozenCell: { alignItems: 'flex-start', paddingHorizontal: 10 },
75
- headerRow: { flexDirection: 'row', backgroundColor: '#f0f0f0' },
76
- row: { flexDirection: 'row' },
88
+
89
+ frozen: {
90
+ width: 150, // 👈 fixed width
91
+ backgroundColor: '#f5f7fa',
92
+ },
93
+
94
+ frozenCell: {
95
+ alignItems: 'flex-start',
96
+ paddingHorizontal: 8,
97
+ },
98
+
99
+ headerRow: {
100
+ flexDirection: 'row',
101
+ backgroundColor: '#f0f0f0',
102
+ },
103
+
104
+ row: {
105
+ flexDirection: 'row',
106
+ },
107
+
77
108
  cell: {
78
- width: 110,
79
- paddingVertical: 8,
109
+ width: 110, // 👈 compact width
110
+ paddingVertical: 6, // 👈 reduced height
80
111
  paddingHorizontal: 6,
81
112
  borderBottomWidth: 1,
82
113
  borderColor: '#eee',
83
114
  justifyContent: 'center',
84
115
  alignItems: 'center',
85
116
  },
86
- text: { fontSize: 12, color: '#222' },
87
- bold: { fontWeight: '700' },
88
- arrow: { fontSize: 12, fontWeight: '700' },
89
- up: { color: '#2e7d32' },
90
- down: { color: '#d32f2f' },
91
- });
92
117
 
93
- export default FrozenTableReport1A;
118
+ text: {
119
+ fontSize: 12, // 👈 smaller text
120
+ color: '#222',
121
+ },
122
+
123
+ bold: {
124
+ fontWeight: '700',
125
+ },
126
+
127
+ arrow: {
128
+ fontSize: 12,
129
+ fontWeight: '700',
130
+ },
131
+
132
+ up: {
133
+ color: '#2e7d32',
134
+ },
135
+
136
+ down: {
137
+ color: '#d32f2f',
138
+ },
139
+ });
@@ -1,52 +1,45 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import {
3
- ScrollView,
4
- Text,
5
- TouchableOpacity,
6
- Modal,
7
- View,
8
- StyleSheet,
9
- Dimensions,
10
- Alert,
11
- } from 'react-native';
12
- import { PinchGestureHandler, State } from 'react-native-gesture-handler';
2
+ import { ScrollView, Text, TouchableOpacity } from 'react-native';
13
3
  import fetchReport1 from '../api/report1Fetcher';
14
4
  import FrozenTableReport1A from '../components/FrozenTableReport1A';
15
5
  import Report1Card from '../components/Report1Card';
6
+ import FullScreenTableModal from '../components/FullScreenTableModal';
16
7
 
17
8
  const Report1AScreen = ({ endpoint, token, onBack }) => {
18
9
  const [rows, setRows] = useState([]);
19
10
  const [fullscreen, setFullscreen] = useState(false);
20
- const [scale, setScale] = useState(1);
21
11
 
22
12
  useEffect(() => {
23
13
  fetchReport1(endpoint, token).then(setRows);
24
- }, [endpoint, token]);
25
-
26
- const openFullscreen = () => {
27
- setFullscreen(true);
28
- setScale(1);
29
- };
30
-
31
- const closeFullscreen = () => {
32
- setFullscreen(false);
33
- setScale(1);
34
- };
14
+ }, []);
35
15
 
36
16
  return (
37
17
  <>
38
- <ScrollView style={{ padding: 16, backgroundColor: '#f8f9fa' }}>
39
- <Text onPress={onBack} style={styles.backButton}>‹ Back</Text>
40
-
41
- <Text style={styles.title}>PERFORMANS RAPORU (USD)</Text>
42
-
43
- <TouchableOpacity onPress={openFullscreen} style={styles.fullscreenBtn}>
44
- <Text style={styles.fullscreenText}>⤢ Full Screen</Text>
18
+ <ScrollView style={{ padding: 16 }}>
19
+ <Text onPress={onBack} style={{ marginBottom: 12 }}>‹ Back</Text>
20
+
21
+ <Text style={{ fontSize: 18, fontWeight: '700', marginBottom: 12 }}>
22
+ PERFORMANS RAPORU (USD)
23
+ </Text>
24
+
25
+ {/* FULLSCREEN BUTTON */}
26
+ <TouchableOpacity
27
+ onPress={() => setFullscreen(true)}
28
+ style={{
29
+ alignSelf: 'flex-end',
30
+ marginBottom: 8,
31
+ padding: 6,
32
+ }}
33
+ >
34
+ <Text style={{ fontWeight: '700' }}>⤢ Full Screen</Text>
45
35
  </TouchableOpacity>
46
36
 
47
37
  <FrozenTableReport1A rows={rows} />
48
38
 
49
- <Text style={styles.sectionTitle}>Individual Reports</Text>
39
+ {/* BELOW TABLE → CARDS */}
40
+ <Text style={{ marginVertical: 12, fontWeight: '700' }}>
41
+ Individual Reports
42
+ </Text>
50
43
 
51
44
  {rows.map((r, i) => (
52
45
  <Report1Card key={i} item={r} />
@@ -54,85 +47,13 @@ const Report1AScreen = ({ endpoint, token, onBack }) => {
54
47
  </ScrollView>
55
48
 
56
49
  {/* FULL SCREEN MODAL */}
57
- <Modal
50
+ <FullScreenTableModal
58
51
  visible={fullscreen}
59
- supportedOrientations={['portrait', 'landscape']}
60
- onRequestClose={closeFullscreen}
61
- >
62
- <View style={styles.modalContainer}>
63
- {/* Header */}
64
- <View style={styles.modalHeader}>
65
- <TouchableOpacity
66
- onPress={() =>
67
- Alert.alert(
68
- 'Rotate Device',
69
- 'For best view, please rotate your device to landscape mode ↻',
70
- [{ text: 'OK' }]
71
- )
72
- }
73
- >
74
- <Text style={styles.rotateHint}>↻ Rotate Device</Text>
75
- </TouchableOpacity>
76
-
77
- <TouchableOpacity onPress={closeFullscreen}>
78
- <Text style={styles.closeBtn}>✕ Close</Text>
79
- </TouchableOpacity>
80
- </View>
81
-
82
- {/* Zoomable Table */}
83
- <PinchGestureHandler
84
- onGestureEvent={(e) => setScale(e.nativeEvent.scale)}
85
- onHandlerStateChange={(e) => {
86
- if (e.nativeEvent.state === State.END) {
87
- let newScale = e.nativeEvent.scale;
88
- newScale = Math.max(0.8, Math.min(newScale, 3));
89
- setScale(newScale);
90
- }
91
- }}
92
- >
93
- <View style={styles.zoomContainer}>
94
- <View style={{ transform: [{ scale }] }}>
95
- <FrozenTableReport1A rows={rows} isFullscreen />
96
- </View>
97
- </View>
98
- </PinchGestureHandler>
99
- </View>
100
- </Modal>
52
+ rows={rows}
53
+ onClose={() => setFullscreen(false)}
54
+ />
101
55
  </>
102
56
  );
103
57
  };
104
58
 
105
- const styles = StyleSheet.create({
106
- backButton: { fontSize: 20, color: '#1e88e5', marginBottom: 16, fontWeight: '600' },
107
- title: { fontSize: 18, fontWeight: '700', textAlign: 'center', marginVertical: 16 },
108
- fullscreenBtn: {
109
- alignSelf: 'flex-end',
110
- backgroundColor: '#1e88e5',
111
- paddingHorizontal: 16,
112
- paddingVertical: 10,
113
- borderRadius: 8,
114
- marginBottom: 16,
115
- },
116
- fullscreenText: { color: '#fff', fontWeight: '700' },
117
- sectionTitle: { fontSize: 16, fontWeight: '700', marginVertical: 16 },
118
-
119
- modalContainer: { flex: 1, backgroundColor: '#000' },
120
- modalHeader: {
121
- flexDirection: 'row',
122
- justifyContent: 'space-between',
123
- alignItems: 'center',
124
- padding: 16,
125
- backgroundColor: '#111',
126
- borderBottomWidth: 1,
127
- borderColor: '#333',
128
- },
129
- rotateHint: { color: '#fff', fontSize: 16, fontWeight: '700' },
130
- closeBtn: { color: '#fff', fontSize: 28, fontWeight: '300' },
131
- zoomContainer: {
132
- flex: 1,
133
- justifyContent: 'center',
134
- alignItems: 'center',
135
- },
136
- });
137
-
138
- export default Report1AScreen;
59
+ export default Report1AScreen;
@@ -1,12 +1,11 @@
1
- // src/screens/Report2AScreen.jsx
2
1
  import React, { useEffect, useState } from 'react';
3
2
  import {
4
3
  ScrollView,
5
4
  Text,
6
5
  TouchableOpacity,
7
6
  View,
8
- ActivityIndicator,
9
7
  StyleSheet,
8
+ ActivityIndicator,
10
9
  } from 'react-native';
11
10
  import { filterChartByMonths } from '../utils/filterChartByMonths';
12
11
  import { getDivisions, getTable, getLine, getBar } from '../api/report2Fetcher';
@@ -16,6 +15,19 @@ import FrozenTableReport2A from '../components/FrozenTableReport2A';
16
15
  import SvgLineChartCompact from '../components/SvgLineChartCompact';
17
16
  import SvgBarLineChartCompact from '../components/SvgBarLineChartCompact';
18
17
 
18
+ // Proper SVG Funnel Icon Component (clean black filter icon)
19
+ const FunnelIcon = () => (
20
+ <View style={styles.funnelIcon}>
21
+ <View style={styles.funnelTop} />
22
+ <View style={styles.funnelBody} />
23
+ <View style={styles.funnelLines}>
24
+ <View style={styles.line1} />
25
+ <View style={styles.line2} />
26
+ <View style={styles.line3} />
27
+ </View>
28
+ </View>
29
+ );
30
+
19
31
  const Report2AScreen = ({ api, token, onBack }) => {
20
32
  const [monthsModal, setMonthsModal] = useState(false);
21
33
  const [divisionModal, setDivisionModal] = useState(false);
@@ -31,25 +43,18 @@ const Report2AScreen = ({ api, token, onBack }) => {
31
43
  const [loading, setLoading] = useState(true);
32
44
  const [error, setError] = useState(null);
33
45
 
34
- // Fetch divisions
35
46
  useEffect(() => {
36
47
  if (!api?.divisions || !token) return;
37
48
 
38
49
  getDivisions(api.divisions, token)
39
50
  .then((d) => {
40
51
  setDivisions(d);
41
- if (d.length > 0) {
42
- setDivision(d[0].code);
43
- }
52
+ if (d.length > 0) setDivision(d[0].code);
44
53
  })
45
- .catch((err) => {
46
- console.error('Failed to load divisions:', err);
47
- setError('Failed to load divisions');
48
- setLoading(false);
49
- });
54
+ .catch(() => setError('Failed to load divisions'))
55
+ .finally(() => setLoading(false));
50
56
  }, [api?.divisions, token]);
51
57
 
52
- // Fetch data when division changes
53
58
  useEffect(() => {
54
59
  if (!division || !api || !token) return;
55
60
 
@@ -57,106 +62,100 @@ const Report2AScreen = ({ api, token, onBack }) => {
57
62
  setError(null);
58
63
 
59
64
  Promise.all([
60
- getTable(api.table, division, token).catch(() => null),
61
- getLine(api.line, division, token).catch(() => null),
62
- getBar(api.bar, division, token).catch(() => null),
65
+ getTable(api.table, division, token),
66
+ getLine(api.line, division, token),
67
+ getBar(api.bar, division, token),
63
68
  ])
64
69
  .then(([t, l, b]) => {
65
- if (!t || !l || !b) {
66
- setError('Failed to load report data');
67
- return;
68
- }
69
-
70
70
  setTable(t);
71
71
  setLine(l);
72
72
  setBar(b);
73
73
  setMonths(l.labels || []);
74
74
  setSelectedMonths(l.labels || []);
75
75
  })
76
- .catch((err) => {
77
- console.error('Data fetch error:', err);
78
- setError('Network error or data unavailable');
79
- })
80
- .finally(() => {
81
- setLoading(false);
82
- });
76
+ .catch(() => setError('Failed to load data'))
77
+ .finally(() => setLoading(false));
83
78
  }, [division, api, token]);
84
79
 
85
- // Loading State
86
80
  if (loading) {
87
81
  return (
88
82
  <View style={styles.center}>
89
- <ActivityIndicator size="large" color="#1e88e5" />
90
- <Text style={styles.loadingText}>Loading Report 2A...</Text>
83
+ <ActivityIndicator size="large" color="#000" />
84
+ <Text style={styles.loadingText}>Loading...</Text>
91
85
  </View>
92
86
  );
93
87
  }
94
88
 
95
- // Error State
96
89
  if (error) {
97
90
  return (
98
91
  <View style={styles.center}>
99
92
  <Text style={styles.errorText}>{error}</Text>
100
93
  <TouchableOpacity onPress={onBack}>
101
- <Text style={styles.backLink}>← Go Back</Text>
94
+ <Text style={styles.backLink}>← Back to Reports</Text>
102
95
  </TouchableOpacity>
103
96
  </View>
104
97
  );
105
98
  }
106
99
 
107
- // Safety check
108
100
  if (!table || !line || !bar || !division) {
109
- return (
110
- <View style={styles.center}>
111
- <Text>No data available</Text>
112
- </View>
113
- );
101
+ return <View style={styles.center}><Text>No data available</Text></View>;
114
102
  }
115
103
 
116
- const filteredRows = table.rows.filter((r) =>
117
- selectedMonths.includes(r.monthLabel)
118
- );
104
+ const currentDivisionName = divisions.find(d => d.code === division)?.displayName || 'Division';
119
105
 
106
+ const filteredRows = table.rows.filter(r => selectedMonths.includes(r.monthLabel));
120
107
  const filteredLine = filterChartByMonths(line, selectedMonths);
121
108
  const filteredBar = filterChartByMonths(bar, selectedMonths);
122
109
 
123
110
  return (
124
- <ScrollView style={styles.container}>
125
- {/* Header */}
126
- <Text onPress={onBack} style={styles.backButton}>
127
- Back
128
- </Text>
129
-
130
- {/* Filters */}
131
- <View style={styles.filterRow}>
132
- <TouchableOpacity onPress={() => setMonthsModal(true)}>
133
- <Text style={styles.filterText}>Months ⛃</Text>
111
+ <View style={styles.container}>
112
+ {/* HEADER WITH BACK ICON + HEADING */}
113
+ <View style={styles.header}>
114
+ <TouchableOpacity onPress={onBack} style={styles.backButton}>
115
+ <Text style={styles.backIcon}>←</Text>
116
+ </TouchableOpacity>
117
+
118
+ <Text style={styles.headerTitle}>
119
+ {currentDivisionName} Transportation
120
+ </Text>
121
+ </View>
122
+
123
+ {/* FILTERS - BLACK TEXT + PROPER FUNNEL ICON */}
124
+ <View style={styles.filterBar}>
125
+ <TouchableOpacity
126
+ onPress={() => setMonthsModal(true)}
127
+ style={styles.filterItem}
128
+ >
129
+ <FunnelIcon />
130
+ <Text style={styles.filterText}>
131
+ Months ({selectedMonths.length}/{months.length})
132
+ </Text>
134
133
  </TouchableOpacity>
135
134
 
136
135
  <TouchableOpacity
137
136
  onPress={() => setDivisionModal(true)}
138
- style={{ marginLeft: 20 }}
137
+ style={styles.filterItem}
139
138
  >
139
+ <FunnelIcon />
140
140
  <Text style={styles.filterText}>
141
- Division: {divisions.find((d) => d.code === division)?.displayName || division}
141
+ {currentDivisionName}
142
142
  </Text>
143
143
  </TouchableOpacity>
144
144
  </View>
145
145
 
146
- {/* Table */}
147
- <FrozenTableReport2A rows={filteredRows} />
146
+ <ScrollView style={styles.content}>
147
+ <FrozenTableReport2A rows={filteredRows} />
148
148
 
149
- {/* Line Chart */}
150
- <View style={styles.chartContainer}>
151
- <SvgLineChartCompact data={filteredLine} />
152
- </View>
149
+ <View style={styles.chartContainer}>
150
+ <SvgLineChartCompact data={filteredLine} />
151
+ </View>
153
152
 
154
- {/* Bar + Budget Chart */}
155
- <View style={styles.chartContainer}>
156
- <SvgBarLineChartCompact data={filteredBar} />
157
- </View>
153
+ <View style={styles.chartContainer}>
154
+ <SvgBarLineChartCompact data={filteredBar} />
155
+ </View>
156
+ </ScrollView>
158
157
 
159
- {/* Modals */}
158
+ {/* MODALS */}
160
159
  <MonthFilterModal
161
160
  visible={monthsModal}
162
161
  months={months}
@@ -172,50 +171,91 @@ const Report2AScreen = ({ api, token, onBack }) => {
172
171
  onSelect={setDivision}
173
172
  onClose={() => setDivisionModal(false)}
174
173
  />
175
- </ScrollView>
174
+ </View>
176
175
  );
177
176
  };
178
177
 
179
178
  const styles = StyleSheet.create({
180
- container: { padding: 12, backgroundColor: '#f8f9fa' },
181
- center: {
182
- flex: 1,
183
- justifyContent: 'center',
179
+ container: { flex: 1, backgroundColor: '#f8f9fa' },
180
+ center: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 },
181
+ loadingText: { marginTop: 12, fontSize: 16, color: '#000' },
182
+ errorText: { fontSize: 16, color: '#d32f2f', textAlign: 'center', marginBottom: 20 },
183
+ backLink: { fontSize: 18, color: '#000', fontWeight: '600' },
184
+
185
+ header: {
186
+ flexDirection: 'row',
184
187
  alignItems: 'center',
185
- padding: 20,
186
- },
187
- loadingText: {
188
- marginTop: 12,
189
- fontSize: 16,
190
- color: '#555',
188
+ paddingHorizontal: 16,
189
+ paddingVertical: 18,
190
+ backgroundColor: '#fff',
191
+ borderBottomWidth: 1,
192
+ borderColor: '#eee',
191
193
  },
192
- errorText: {
193
- fontSize: 16,
194
- color: '#d32f2f',
194
+ backButton: { paddingRight: 12 },
195
+ backIcon: { fontSize: 28, color: '#000', fontWeight: '300' },
196
+ headerTitle: {
197
+ fontSize: 19,
198
+ fontWeight: '700',
199
+ color: '#000',
200
+ flex: 1,
195
201
  textAlign: 'center',
196
- marginBottom: 20,
197
- },
198
- backLink: {
199
- fontSize: 18,
200
- color: '#1e88e5',
201
- fontWeight: '600',
202
202
  },
203
- backButton: {
204
- fontSize: 20,
205
- color: '#1e88e5',
206
- marginBottom: 16,
207
- fontWeight: '600',
203
+
204
+ filterBar: {
205
+ flexDirection: 'row',
206
+ justifyContent: 'space-around',
207
+ paddingVertical: 14,
208
+ backgroundColor: '#fff',
209
+ borderBottomWidth: 1,
210
+ borderColor: '#eee',
208
211
  },
209
- filterRow: {
212
+ filterItem: {
210
213
  flexDirection: 'row',
211
214
  alignItems: 'center',
212
- marginVertical: 12,
215
+ paddingHorizontal: 16,
216
+ paddingVertical: 8,
213
217
  },
214
218
  filterText: {
215
219
  fontSize: 16,
216
- color: '#1e88e5',
220
+ color: '#000',
217
221
  fontWeight: '600',
222
+ marginLeft: 8,
218
223
  },
224
+
225
+ // Proper Funnel Icon (SVG-style with Views)
226
+ funnelIcon: {
227
+ width: 20,
228
+ height: 20,
229
+ justifyContent: 'center',
230
+ alignItems: 'center',
231
+ },
232
+ funnelTop: {
233
+ width: 16,
234
+ height: 4,
235
+ backgroundColor: '#000',
236
+ borderRadius: 2,
237
+ },
238
+ funnelBody: {
239
+ width: 10,
240
+ height: 10,
241
+ borderLeftWidth: 4,
242
+ borderRightWidth: 4,
243
+ borderBottomWidth: 8,
244
+ borderColor: 'transparent',
245
+ borderBottomColor: '#000',
246
+ marginTop: -2,
247
+ },
248
+ funnelLines: {
249
+ position: 'absolute',
250
+ top: 6,
251
+ left: 4,
252
+ right: 4,
253
+ },
254
+ line1: { height: 1, backgroundColor: '#000', marginVertical: 2 },
255
+ line2: { height: 1, backgroundColor: '#000', marginVertical: 2 },
256
+ line3: { height: 1, backgroundColor: '#000', marginVertical: 2 },
257
+
258
+ content: { flex: 1, padding: 12 },
219
259
  chartContainer: {
220
260
  borderWidth: 1,
221
261
  borderColor: '#ddd',