@dhiraj0720/report1chart 2.9.2 → 2.9.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
CHANGED
|
@@ -1,68 +1,78 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View, Text, ScrollView, StyleSheet } from 'react-native';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
// Format numbers with commas: 1234567 → 1,234,567
|
|
5
|
+
const formatNumber = (value) => {
|
|
6
|
+
if (value === null || value === undefined || value === '') return '-';
|
|
7
|
+
return Number(value).toLocaleString('en-US');
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Percentage cell with arrow and color
|
|
11
|
+
const PercentCell = ({ value }) => {
|
|
12
|
+
if (value === null || value === undefined) return <Text>-</Text>;
|
|
13
|
+
const positive = value >= 0;
|
|
14
|
+
return (
|
|
15
|
+
<Text style={[
|
|
16
|
+
styles.percentText,
|
|
17
|
+
{ color: positive ? '#2e7d32' : '#d32f2f' }
|
|
18
|
+
]}>
|
|
19
|
+
{positive ? '↑' : '↓'} {Math.abs(value)}%
|
|
20
|
+
</Text>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ellipsizeMode="tail"
|
|
25
|
-
style={[
|
|
26
|
-
styles.text,
|
|
27
|
-
bold && styles.bold,
|
|
28
|
-
]}
|
|
29
|
-
>
|
|
24
|
+
// Reusable Cell
|
|
25
|
+
const Cell = ({ children, bold = false, highlight = false, isFrozen = false }) => (
|
|
26
|
+
<View style={[
|
|
27
|
+
styles.cell,
|
|
28
|
+
isFrozen && styles.frozenCell,
|
|
29
|
+
bold && styles.bold,
|
|
30
|
+
highlight && styles.highlightCell
|
|
31
|
+
]}>
|
|
32
|
+
<Text style={[styles.cellText, bold && styles.boldText]}>
|
|
30
33
|
{children}
|
|
31
34
|
</Text>
|
|
32
35
|
</View>
|
|
33
36
|
);
|
|
34
37
|
|
|
35
|
-
const FrozenTableReport1A = ({ rows }) => {
|
|
38
|
+
const FrozenTableReport1A = ({ rows = [], isFullscreen = false }) => {
|
|
39
|
+
if (!rows.length) {
|
|
40
|
+
return <Text style={{ textAlign: 'center', padding: 20, color: '#666' }}>No data available</Text>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Wider frozen column in fullscreen
|
|
44
|
+
const frozenColumnWidth = isFullscreen ? 180 : 150;
|
|
45
|
+
|
|
36
46
|
return (
|
|
37
47
|
<View style={styles.container}>
|
|
38
|
-
{/*
|
|
39
|
-
<View style={styles.
|
|
40
|
-
<Cell bold
|
|
41
|
-
{rows.map((
|
|
42
|
-
<Cell key={i}
|
|
43
|
-
{
|
|
48
|
+
{/* Frozen Left Column - FAALİYET */}
|
|
49
|
+
<View style={[styles.frozenColumn, { width: frozenColumnWidth }]}>
|
|
50
|
+
<Cell bold isFrozen>FAALİYET</Cell>
|
|
51
|
+
{rows.map((row, i) => (
|
|
52
|
+
<Cell key={i} bold isFrozen>
|
|
53
|
+
{row.name}
|
|
44
54
|
</Cell>
|
|
45
55
|
))}
|
|
46
56
|
</View>
|
|
47
57
|
|
|
48
|
-
{/*
|
|
58
|
+
{/* Scrollable Columns */}
|
|
49
59
|
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
50
60
|
<View>
|
|
61
|
+
{/* Header Row */}
|
|
51
62
|
<View style={styles.headerRow}>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<Cell bold>2025 Bütçe</Cell>
|
|
56
|
-
<Cell bold>Sapma %</Cell>
|
|
63
|
+
{['2024', '2025', 'Artış %', '2025 Bütçe', 'Sapma %'].map((header) => (
|
|
64
|
+
<Cell key={header} bold>{header}</Cell>
|
|
65
|
+
))}
|
|
57
66
|
</View>
|
|
58
67
|
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<Cell>{
|
|
63
|
-
<Cell
|
|
64
|
-
<Cell
|
|
65
|
-
<Cell
|
|
68
|
+
{/* Data Rows */}
|
|
69
|
+
{rows.map((row, i) => (
|
|
70
|
+
<View key={i} style={styles.dataRow}>
|
|
71
|
+
<Cell>{formatNumber(row.actual2024)}</Cell>
|
|
72
|
+
<Cell>{formatNumber(row.actual2025)}</Cell>
|
|
73
|
+
<Cell><PercentCell value={row.actualChangePercent} /></Cell>
|
|
74
|
+
<Cell>{formatNumber(row.budget2025)}</Cell>
|
|
75
|
+
<Cell><PercentCell value={row.budgetVariancePercent} /></Cell>
|
|
66
76
|
</View>
|
|
67
77
|
))}
|
|
68
78
|
</View>
|
|
@@ -73,9 +83,6 @@ const FrozenTableReport1A = ({ rows }) => {
|
|
|
73
83
|
|
|
74
84
|
export default FrozenTableReport1A;
|
|
75
85
|
|
|
76
|
-
/* ======================
|
|
77
|
-
STYLES (COMPACT)
|
|
78
|
-
====================== */
|
|
79
86
|
const styles = StyleSheet.create({
|
|
80
87
|
container: {
|
|
81
88
|
flexDirection: 'row',
|
|
@@ -83,57 +90,51 @@ const styles = StyleSheet.create({
|
|
|
83
90
|
borderColor: '#ddd',
|
|
84
91
|
borderRadius: 8,
|
|
85
92
|
overflow: 'hidden',
|
|
93
|
+
marginVertical: 12,
|
|
86
94
|
backgroundColor: '#fff',
|
|
87
95
|
},
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
frozenCell: {
|
|
95
|
-
alignItems: 'flex-start',
|
|
96
|
-
paddingHorizontal: 8,
|
|
96
|
+
frozenColumn: {
|
|
97
|
+
backgroundColor: '#f4f6f8',
|
|
98
|
+
borderRightWidth: 1,
|
|
99
|
+
borderColor: '#ddd',
|
|
97
100
|
},
|
|
98
|
-
|
|
99
101
|
headerRow: {
|
|
100
102
|
flexDirection: 'row',
|
|
101
|
-
backgroundColor: '#
|
|
103
|
+
backgroundColor: '#f4f6f8',
|
|
102
104
|
},
|
|
103
|
-
|
|
104
|
-
row: {
|
|
105
|
+
dataRow: {
|
|
105
106
|
flexDirection: 'row',
|
|
106
107
|
},
|
|
107
|
-
|
|
108
108
|
cell: {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
borderBottomWidth: 1,
|
|
113
|
-
borderColor: '#eee',
|
|
109
|
+
minWidth: 110,
|
|
110
|
+
paddingHorizontal: 14, // +7 left/right for spacious feel
|
|
111
|
+
paddingVertical: 12,
|
|
114
112
|
justifyContent: 'center',
|
|
115
113
|
alignItems: 'center',
|
|
114
|
+
borderBottomWidth: 1,
|
|
115
|
+
borderColor: '#e0e0e0',
|
|
116
116
|
},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
frozenCell: {
|
|
118
|
+
justifyContent: 'flex-start',
|
|
119
|
+
paddingLeft: 18,
|
|
120
|
+
},
|
|
121
|
+
cellText: {
|
|
122
|
+
fontSize: 12.5,
|
|
123
|
+
textAlign: 'center',
|
|
124
|
+
color: '#333',
|
|
121
125
|
},
|
|
122
|
-
|
|
123
126
|
bold: {
|
|
124
|
-
|
|
127
|
+
backgroundColor: '#e9f0f8',
|
|
125
128
|
},
|
|
126
|
-
|
|
127
|
-
arrow: {
|
|
128
|
-
fontSize: 12,
|
|
129
|
+
boldText: {
|
|
129
130
|
fontWeight: '700',
|
|
130
131
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
color: '#2e7d32',
|
|
132
|
+
highlightCell: {
|
|
133
|
+
backgroundColor: '#e9f0f8',
|
|
134
134
|
},
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
percentText: {
|
|
136
|
+
fontWeight: '700',
|
|
137
|
+
fontSize: 12.5,
|
|
138
|
+
textAlign: 'center',
|
|
138
139
|
},
|
|
139
|
-
});
|
|
140
|
+
});
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ScrollView,
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
View,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
Modal,
|
|
9
|
+
Dimensions,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import Svg, { Path } from 'react-native-svg';
|
|
3
12
|
import fetchReport1 from '../api/report1Fetcher';
|
|
4
13
|
import FrozenTableReport1A from '../components/FrozenTableReport1A';
|
|
5
14
|
import Report1Card from '../components/Report1Card';
|
|
6
|
-
import FullScreenTableModal from '../components/FullScreenTableModal';
|
|
7
15
|
|
|
8
16
|
const Report1AScreen = ({ endpoint, token, onBack }) => {
|
|
9
17
|
const [rows, setRows] = useState([]);
|
|
@@ -11,44 +19,42 @@ const Report1AScreen = ({ endpoint, token, onBack }) => {
|
|
|
11
19
|
|
|
12
20
|
useEffect(() => {
|
|
13
21
|
fetchReport1(endpoint, token).then(setRows);
|
|
14
|
-
}, []);
|
|
22
|
+
}, [endpoint, token]);
|
|
23
|
+
|
|
24
|
+
const { width, height } = Dimensions.get('window');
|
|
25
|
+
const isLandscape = width > height;
|
|
15
26
|
|
|
16
27
|
return (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
</Text>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<TouchableOpacity
|
|
36
|
-
onPress={() => setFullscreen(true)}
|
|
37
|
-
style={{
|
|
38
|
-
alignSelf: 'flex-end',
|
|
39
|
-
marginBottom: 8,
|
|
40
|
-
padding: 6,
|
|
41
|
-
}}
|
|
42
|
-
>
|
|
43
|
-
<Text style={{ fontWeight: '700' }}>⤢ Full Screen</Text>
|
|
28
|
+
<View style={styles.container}>
|
|
29
|
+
{/* FULL-WIDTH BLUE HEADER */}
|
|
30
|
+
<View style={styles.header}>
|
|
31
|
+
<TouchableOpacity onPress={onBack} style={styles.backButton}>
|
|
32
|
+
<Text style={styles.backIcon}>←</Text>
|
|
33
|
+
</TouchableOpacity>
|
|
34
|
+
<Text style={styles.headerTitle}>PERFORMANS RAPORU (USD)</Text>
|
|
35
|
+
</View>
|
|
36
|
+
|
|
37
|
+
{/* FILTER BAR - DIVISION + FULL SCREEN */}
|
|
38
|
+
<View style={styles.filterBar}>
|
|
39
|
+
{/* DIVISION FILTER - LEFT */}
|
|
40
|
+
<TouchableOpacity style={styles.filterItemLeft}>
|
|
41
|
+
<Svg width={22} height={22} viewBox="0 0 24 24" fill="none">
|
|
42
|
+
<Path d="M20 4H4V6.5L12 14.5L20 6.5V4Z" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
|
|
43
|
+
<Path d="M8 11V19L16 19V11" stroke="#000" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" />
|
|
44
|
+
</Svg>
|
|
45
|
+
<Text style={styles.filterText}>Division Filter</Text>
|
|
44
46
|
</TouchableOpacity>
|
|
45
47
|
|
|
48
|
+
{/* FULL SCREEN - RIGHT */}
|
|
49
|
+
<TouchableOpacity onPress={() => setFullscreen(true)} style={styles.filterItemRight}>
|
|
50
|
+
<Text style={styles.fullScreenFilterText}>⤢ Full Screen</Text>
|
|
51
|
+
</TouchableOpacity>
|
|
52
|
+
</View>
|
|
53
|
+
|
|
54
|
+
<ScrollView style={styles.content}>
|
|
46
55
|
<FrozenTableReport1A rows={rows} />
|
|
47
56
|
|
|
48
|
-
{
|
|
49
|
-
<Text style={{ marginVertical: 12, fontWeight: '700' }}>
|
|
50
|
-
Individual Reports
|
|
51
|
-
</Text>
|
|
57
|
+
<Text style={styles.sectionTitle}>Individual Reports</Text>
|
|
52
58
|
|
|
53
59
|
{rows.map((r, i) => (
|
|
54
60
|
<Report1Card key={i} item={r} />
|
|
@@ -56,41 +62,144 @@ const Report1AScreen = ({ endpoint, token, onBack }) => {
|
|
|
56
62
|
</ScrollView>
|
|
57
63
|
|
|
58
64
|
{/* FULL SCREEN MODAL */}
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
<Modal visible={fullscreen} supportedOrientations={['portrait', 'landscape']} animationType="fade">
|
|
66
|
+
<View style={styles.fullModal}>
|
|
67
|
+
<View style={styles.fullHeader}>
|
|
68
|
+
<Text style={styles.fullHintText}>Rotate device • Pinch to zoom</Text>
|
|
69
|
+
<TouchableOpacity onPress={() => setFullscreen(false)}>
|
|
70
|
+
<Text style={styles.closeBtn}>✕</Text>
|
|
71
|
+
</TouchableOpacity>
|
|
72
|
+
</View>
|
|
73
|
+
|
|
74
|
+
<ScrollView
|
|
75
|
+
maximumZoomScale={3}
|
|
76
|
+
minimumZoomScale={0.7}
|
|
77
|
+
showsHorizontalScrollIndicator={false}
|
|
78
|
+
showsVerticalScrollIndicator={false}
|
|
79
|
+
contentContainerStyle={styles.zoomContent}
|
|
80
|
+
pinchGestureEnabled={true}
|
|
81
|
+
bouncesZoom={true}
|
|
82
|
+
>
|
|
83
|
+
<View style={[styles.tableWrapper, isLandscape && styles.landscapeFit]}>
|
|
84
|
+
<FrozenTableReport1A rows={rows} isFullscreen />
|
|
85
|
+
</View>
|
|
86
|
+
</ScrollView>
|
|
87
|
+
</View>
|
|
88
|
+
</Modal>
|
|
89
|
+
</View>
|
|
65
90
|
);
|
|
66
91
|
};
|
|
67
92
|
|
|
68
|
-
// ONLY ADDED THIS STYLES PART — NOTHING ELSE CHANGED
|
|
69
93
|
const styles = StyleSheet.create({
|
|
94
|
+
container: { flex: 1, backgroundColor: '#f8f9fa' },
|
|
70
95
|
|
|
71
|
-
|
|
72
|
-
|
|
96
|
+
// FULL-WIDTH BLUE HEADER
|
|
97
|
+
header: {
|
|
73
98
|
flexDirection: 'row',
|
|
74
99
|
alignItems: 'center',
|
|
75
|
-
paddingHorizontal: 16,
|
|
76
100
|
paddingVertical: 18,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
paddingHorizontal: 16,
|
|
102
|
+
backgroundColor: '#1565c0', // Deep blue
|
|
103
|
+
},
|
|
104
|
+
backButton: {
|
|
105
|
+
padding: 8,
|
|
80
106
|
},
|
|
81
107
|
backIcon: {
|
|
82
108
|
fontSize: 32,
|
|
83
|
-
color: '#
|
|
84
|
-
|
|
85
|
-
fontWeight: '700',
|
|
109
|
+
color: '#ffffff',
|
|
110
|
+
fontWeight: '300',
|
|
86
111
|
},
|
|
87
112
|
headerTitle: {
|
|
88
113
|
fontSize: 19,
|
|
89
114
|
fontWeight: '700',
|
|
90
|
-
color: '#
|
|
115
|
+
color: '#ffffff',
|
|
116
|
+
flex: 1,
|
|
117
|
+
textAlign: 'center',
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// FILTER BAR - LEFT & RIGHT ALIGNED
|
|
121
|
+
filterBar: {
|
|
122
|
+
flexDirection: 'row',
|
|
123
|
+
justifyContent: 'space-between',
|
|
124
|
+
alignItems: 'center',
|
|
125
|
+
paddingHorizontal: 16,
|
|
126
|
+
paddingVertical: 14,
|
|
127
|
+
backgroundColor: '#fff',
|
|
128
|
+
borderBottomWidth: 1,
|
|
129
|
+
borderColor: '#eee',
|
|
130
|
+
},
|
|
131
|
+
filterItemLeft: {
|
|
132
|
+
flexDirection: 'row',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
},
|
|
135
|
+
filterItemRight: {
|
|
136
|
+
flexDirection: 'row',
|
|
137
|
+
alignItems: 'center',
|
|
138
|
+
},
|
|
139
|
+
filterText: {
|
|
140
|
+
fontSize: 16,
|
|
141
|
+
color: '#000',
|
|
142
|
+
fontWeight: '600',
|
|
143
|
+
marginLeft: 8,
|
|
144
|
+
},
|
|
145
|
+
fullScreenFilterText: {
|
|
146
|
+
fontSize: 16,
|
|
147
|
+
color: '#000',
|
|
148
|
+
fontWeight: '700',
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
content: {
|
|
91
152
|
flex: 1,
|
|
153
|
+
paddingHorizontal: 12,
|
|
154
|
+
paddingTop: 12,
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
sectionTitle: {
|
|
158
|
+
fontSize: 16,
|
|
159
|
+
fontWeight: '700',
|
|
160
|
+
marginVertical: 16,
|
|
161
|
+
color: '#111',
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
fullModal: { flex: 1, backgroundColor: '#fff' },
|
|
165
|
+
fullHeader: {
|
|
166
|
+
flexDirection: 'row',
|
|
167
|
+
justifyContent: 'center',
|
|
168
|
+
alignItems: 'center',
|
|
169
|
+
paddingVertical: 16,
|
|
170
|
+
paddingHorizontal: 20,
|
|
171
|
+
backgroundColor: '#f8f8f8',
|
|
172
|
+
borderBottomWidth: 1,
|
|
173
|
+
borderColor: '#ddd',
|
|
174
|
+
},
|
|
175
|
+
fullHintText: {
|
|
176
|
+
fontSize: 16,
|
|
177
|
+
color: '#000',
|
|
178
|
+
fontWeight: '600',
|
|
92
179
|
textAlign: 'center',
|
|
180
|
+
flex: 1,
|
|
181
|
+
},
|
|
182
|
+
closeBtn: { fontSize: 28, color: '#000', paddingLeft: 20 },
|
|
183
|
+
|
|
184
|
+
zoomContent: {
|
|
185
|
+
flexGrow: 1,
|
|
186
|
+
justifyContent: 'center',
|
|
187
|
+
alignItems: 'center',
|
|
188
|
+
padding: 20,
|
|
189
|
+
},
|
|
190
|
+
tableWrapper: {
|
|
191
|
+
backgroundColor: '#fff',
|
|
192
|
+
borderRadius: 12,
|
|
193
|
+
overflow: 'hidden',
|
|
194
|
+
shadowColor: '#000',
|
|
195
|
+
shadowOffset: { width: 0, height: 4 },
|
|
196
|
+
shadowOpacity: 0.15,
|
|
197
|
+
shadowRadius: 10,
|
|
198
|
+
elevation: 8,
|
|
199
|
+
},
|
|
200
|
+
landscapeFit: {
|
|
201
|
+
transform: [{ scale: 1.45 }],
|
|
93
202
|
},
|
|
94
203
|
});
|
|
95
204
|
|
|
96
|
-
export default Report1AScreen;
|
|
205
|
+
export default Report1AScreen;
|