@dhiraj0720/report1chart 3.0.8 → 3.0.9
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
|
@@ -17,7 +17,46 @@ const normalizeCell = (value) => {
|
|
|
17
17
|
return { text: String(value), color: '#2b3850', weight: '600' };
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const renderCell = (col, row, rowIndex, compact) => {
|
|
21
|
+
const raw = col.render ? col.render(row) : row[col.key];
|
|
22
|
+
const cell = normalizeCell(raw);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View
|
|
26
|
+
key={`cell-${rowIndex}-${col.key}`}
|
|
27
|
+
style={[
|
|
28
|
+
styles.cell,
|
|
29
|
+
{ width: col.width || (compact ? 110 : 126) },
|
|
30
|
+
col.align === 'right' && styles.alignRight,
|
|
31
|
+
]}
|
|
32
|
+
>
|
|
33
|
+
<Text
|
|
34
|
+
numberOfLines={1}
|
|
35
|
+
ellipsizeMode="tail"
|
|
36
|
+
style={[
|
|
37
|
+
styles.cellText,
|
|
38
|
+
{ color: cell.color, fontWeight: cell.weight },
|
|
39
|
+
col.align === 'right' && styles.textRight,
|
|
40
|
+
col.align === 'center' && styles.textCenter,
|
|
41
|
+
]}
|
|
42
|
+
>
|
|
43
|
+
{cell.text}
|
|
44
|
+
</Text>
|
|
45
|
+
</View>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const ModernDataTable = ({
|
|
50
|
+
title,
|
|
51
|
+
columns = [],
|
|
52
|
+
rows = [],
|
|
53
|
+
compact = false,
|
|
54
|
+
freezeFirstColumn = false,
|
|
55
|
+
}) => {
|
|
56
|
+
const firstColumn = columns[0];
|
|
57
|
+
const scrollColumns = columns.slice(1);
|
|
58
|
+
const shouldFreeze = freezeFirstColumn && columns.length > 1;
|
|
59
|
+
|
|
21
60
|
return (
|
|
22
61
|
<View style={styles.card}>
|
|
23
62
|
<Text style={styles.title}>{title}</Text>
|
|
@@ -26,6 +65,84 @@ const ModernDataTable = ({ title, columns = [], rows = [], compact = false }) =>
|
|
|
26
65
|
<View style={styles.emptyWrap}>
|
|
27
66
|
<Text style={styles.emptyText}>No table data for selected filters.</Text>
|
|
28
67
|
</View>
|
|
68
|
+
) : shouldFreeze ? (
|
|
69
|
+
<View style={styles.freezeWrap}>
|
|
70
|
+
<View style={styles.frozenSide}>
|
|
71
|
+
<View style={styles.headerRow}>
|
|
72
|
+
<View
|
|
73
|
+
style={[
|
|
74
|
+
styles.cell,
|
|
75
|
+
styles.headerCell,
|
|
76
|
+
styles.frozenCell,
|
|
77
|
+
{ width: firstColumn.width || (compact ? 110 : 126) },
|
|
78
|
+
firstColumn.align === 'right' && styles.alignRight,
|
|
79
|
+
]}
|
|
80
|
+
>
|
|
81
|
+
<Text
|
|
82
|
+
style={[
|
|
83
|
+
styles.headerText,
|
|
84
|
+
firstColumn.align === 'right' && styles.textRight,
|
|
85
|
+
firstColumn.align === 'center' && styles.textCenter,
|
|
86
|
+
]}
|
|
87
|
+
>
|
|
88
|
+
{firstColumn.label}
|
|
89
|
+
</Text>
|
|
90
|
+
</View>
|
|
91
|
+
</View>
|
|
92
|
+
|
|
93
|
+
{rows.map((row, rowIndex) => (
|
|
94
|
+
<View
|
|
95
|
+
key={`frozen-row-${rowIndex}`}
|
|
96
|
+
style={[
|
|
97
|
+
styles.dataRow,
|
|
98
|
+
rowIndex % 2 === 0 ? styles.rowEven : styles.rowOdd,
|
|
99
|
+
]}
|
|
100
|
+
>
|
|
101
|
+
{renderCell(firstColumn, row, rowIndex, compact)}
|
|
102
|
+
</View>
|
|
103
|
+
))}
|
|
104
|
+
</View>
|
|
105
|
+
|
|
106
|
+
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
107
|
+
<View>
|
|
108
|
+
<View style={styles.headerRow}>
|
|
109
|
+
{scrollColumns.map((col) => (
|
|
110
|
+
<View
|
|
111
|
+
key={`header-${col.key}`}
|
|
112
|
+
style={[
|
|
113
|
+
styles.cell,
|
|
114
|
+
styles.headerCell,
|
|
115
|
+
{ width: col.width || (compact ? 110 : 126) },
|
|
116
|
+
col.align === 'right' && styles.alignRight,
|
|
117
|
+
]}
|
|
118
|
+
>
|
|
119
|
+
<Text
|
|
120
|
+
style={[
|
|
121
|
+
styles.headerText,
|
|
122
|
+
col.align === 'right' && styles.textRight,
|
|
123
|
+
col.align === 'center' && styles.textCenter,
|
|
124
|
+
]}
|
|
125
|
+
>
|
|
126
|
+
{col.label}
|
|
127
|
+
</Text>
|
|
128
|
+
</View>
|
|
129
|
+
))}
|
|
130
|
+
</View>
|
|
131
|
+
|
|
132
|
+
{rows.map((row, rowIndex) => (
|
|
133
|
+
<View
|
|
134
|
+
key={`row-${rowIndex}`}
|
|
135
|
+
style={[
|
|
136
|
+
styles.dataRow,
|
|
137
|
+
rowIndex % 2 === 0 ? styles.rowEven : styles.rowOdd,
|
|
138
|
+
]}
|
|
139
|
+
>
|
|
140
|
+
{scrollColumns.map((col) => renderCell(col, row, rowIndex, compact))}
|
|
141
|
+
</View>
|
|
142
|
+
))}
|
|
143
|
+
</View>
|
|
144
|
+
</ScrollView>
|
|
145
|
+
</View>
|
|
29
146
|
) : (
|
|
30
147
|
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
31
148
|
<View>
|
|
@@ -61,34 +178,7 @@ const ModernDataTable = ({ title, columns = [], rows = [], compact = false }) =>
|
|
|
61
178
|
rowIndex % 2 === 0 ? styles.rowEven : styles.rowOdd,
|
|
62
179
|
]}
|
|
63
180
|
>
|
|
64
|
-
{columns.map((col) =>
|
|
65
|
-
const raw = col.render ? col.render(row) : row[col.key];
|
|
66
|
-
const cell = normalizeCell(raw);
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<View
|
|
70
|
-
key={`cell-${rowIndex}-${col.key}`}
|
|
71
|
-
style={[
|
|
72
|
-
styles.cell,
|
|
73
|
-
{ width: col.width || (compact ? 110 : 126) },
|
|
74
|
-
col.align === 'right' && styles.alignRight,
|
|
75
|
-
]}
|
|
76
|
-
>
|
|
77
|
-
<Text
|
|
78
|
-
numberOfLines={1}
|
|
79
|
-
ellipsizeMode="tail"
|
|
80
|
-
style={[
|
|
81
|
-
styles.cellText,
|
|
82
|
-
{ color: cell.color, fontWeight: cell.weight },
|
|
83
|
-
col.align === 'right' && styles.textRight,
|
|
84
|
-
col.align === 'center' && styles.textCenter,
|
|
85
|
-
]}
|
|
86
|
-
>
|
|
87
|
-
{cell.text}
|
|
88
|
-
</Text>
|
|
89
|
-
</View>
|
|
90
|
-
);
|
|
91
|
-
})}
|
|
181
|
+
{columns.map((col) => renderCell(col, row, rowIndex, compact))}
|
|
92
182
|
</View>
|
|
93
183
|
))}
|
|
94
184
|
</View>
|
|
@@ -113,6 +203,15 @@ const styles = StyleSheet.create({
|
|
|
113
203
|
color: '#1c2f47',
|
|
114
204
|
marginBottom: 8,
|
|
115
205
|
},
|
|
206
|
+
freezeWrap: {
|
|
207
|
+
flexDirection: 'row',
|
|
208
|
+
},
|
|
209
|
+
frozenSide: {
|
|
210
|
+
borderRightWidth: 1,
|
|
211
|
+
borderRightColor: '#c7d7ef',
|
|
212
|
+
backgroundColor: '#fff',
|
|
213
|
+
zIndex: 2,
|
|
214
|
+
},
|
|
116
215
|
headerRow: {
|
|
117
216
|
flexDirection: 'row',
|
|
118
217
|
backgroundColor: '#1f385a',
|
|
@@ -145,6 +244,9 @@ const styles = StyleSheet.create({
|
|
|
145
244
|
borderRightColor: '#e2ebf7',
|
|
146
245
|
justifyContent: 'center',
|
|
147
246
|
},
|
|
247
|
+
frozenCell: {
|
|
248
|
+
borderRightColor: '#c7d7ef',
|
|
249
|
+
},
|
|
148
250
|
cellText: {
|
|
149
251
|
fontSize: 11.5,
|
|
150
252
|
color: '#2b3850',
|
|
@@ -103,10 +103,6 @@ const Report1ModernScreen = ({ api, token, onBack }) => {
|
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (!force && loadedByTab[tabKey]) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
106
|
setLoading(true);
|
|
111
107
|
setErrorByTab((prev) => ({ ...prev, [tabKey]: null }));
|
|
112
108
|
|
|
@@ -126,7 +122,7 @@ const Report1ModernScreen = ({ api, token, onBack }) => {
|
|
|
126
122
|
} finally {
|
|
127
123
|
setLoading(false);
|
|
128
124
|
}
|
|
129
|
-
}, [endpointByTab,
|
|
125
|
+
}, [endpointByTab, token]);
|
|
130
126
|
|
|
131
127
|
useEffect(() => {
|
|
132
128
|
loadTabData(activeTab);
|
|
@@ -331,6 +327,7 @@ const Report1ModernScreen = ({ api, token, onBack }) => {
|
|
|
331
327
|
|
|
332
328
|
<ModernDataTable
|
|
333
329
|
title="Performance Table"
|
|
330
|
+
freezeFirstColumn
|
|
334
331
|
columns={[
|
|
335
332
|
{ key: 'name', label: 'Activity', width: 150 },
|
|
336
333
|
{ key: 'value2024', label: '2024', width: 120, align: 'right', render: (row) => formatNumber(row.value2024) },
|
|
@@ -27,6 +27,14 @@ const toPercent = (current, previous) => {
|
|
|
27
27
|
return ((current - previous) / Math.abs(previous)) * 100;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const toMonthKey = (value) => {
|
|
31
|
+
return String(value ?? '')
|
|
32
|
+
.trim()
|
|
33
|
+
.toLocaleUpperCase('tr-TR')
|
|
34
|
+
.normalize('NFD')
|
|
35
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
36
|
+
};
|
|
37
|
+
|
|
30
38
|
const TrendBadge = ({ value }) => {
|
|
31
39
|
const positive = value >= 0;
|
|
32
40
|
return (
|
|
@@ -101,7 +109,8 @@ const Report2ModernScreen = ({ api, token, onBack }) => {
|
|
|
101
109
|
if (!preserveSelection) {
|
|
102
110
|
return monthLabels;
|
|
103
111
|
}
|
|
104
|
-
const
|
|
112
|
+
const monthKeys = new Set(monthLabels.map(toMonthKey));
|
|
113
|
+
const kept = prev.filter((month) => monthKeys.has(toMonthKey(month)));
|
|
105
114
|
return kept.length ? kept : monthLabels;
|
|
106
115
|
});
|
|
107
116
|
},
|
|
@@ -147,7 +156,8 @@ const Report2ModernScreen = ({ api, token, onBack }) => {
|
|
|
147
156
|
|
|
148
157
|
const rows = useMemo(() => {
|
|
149
158
|
if (!selectedMonths.length) return [];
|
|
150
|
-
|
|
159
|
+
const selectedKeys = new Set(selectedMonths.map(toMonthKey));
|
|
160
|
+
return baseRows.filter((row) => selectedKeys.has(toMonthKey(row.monthLabel)));
|
|
151
161
|
}, [baseRows, selectedMonths]);
|
|
152
162
|
|
|
153
163
|
const filteredLine = useMemo(() => {
|
|
@@ -298,6 +308,7 @@ const Report2ModernScreen = ({ api, token, onBack }) => {
|
|
|
298
308
|
|
|
299
309
|
<ModernDataTable
|
|
300
310
|
title="Gross Profit Table"
|
|
311
|
+
freezeFirstColumn
|
|
301
312
|
columns={[
|
|
302
313
|
{ key: 'monthLabel', label: 'Month', width: 110 },
|
|
303
314
|
{ key: 'teu2024', label: '2024 TEU', width: 108, align: 'right', render: (row) => formatNumber(row.teu2024) },
|
|
@@ -35,6 +35,14 @@ const percentOf = (part, total) => {
|
|
|
35
35
|
return (part / total) * 100;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
const toMonthKey = (value) => {
|
|
39
|
+
return String(value ?? '')
|
|
40
|
+
.trim()
|
|
41
|
+
.toLocaleUpperCase('tr-TR')
|
|
42
|
+
.normalize('NFD')
|
|
43
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
44
|
+
};
|
|
45
|
+
|
|
38
46
|
const compactNumber = (value) => {
|
|
39
47
|
const num = toNumber(value);
|
|
40
48
|
if (Math.abs(num) >= 1000000000) return `${(num / 1000000000).toFixed(2)}B`;
|
|
@@ -120,7 +128,8 @@ const Report3ModernScreen = ({ api, token, onBack }) => {
|
|
|
120
128
|
const months = lineRes?.labels || [];
|
|
121
129
|
setSelectedMonths((prev) => {
|
|
122
130
|
if (!preserveSelection) return months;
|
|
123
|
-
const
|
|
131
|
+
const monthKeys = new Set(months.map(toMonthKey));
|
|
132
|
+
const kept = prev.filter((month) => monthKeys.has(toMonthKey(month)));
|
|
124
133
|
return kept.length ? kept : months;
|
|
125
134
|
});
|
|
126
135
|
},
|
|
@@ -153,7 +162,8 @@ const Report3ModernScreen = ({ api, token, onBack }) => {
|
|
|
153
162
|
|
|
154
163
|
const rows = useMemo(() => {
|
|
155
164
|
if (!selectedMonths.length) return [];
|
|
156
|
-
|
|
165
|
+
const selectedKeys = new Set(selectedMonths.map(toMonthKey));
|
|
166
|
+
return baseRows.filter((row) => selectedKeys.has(toMonthKey(row.monthLabel)));
|
|
157
167
|
}, [baseRows, selectedMonths]);
|
|
158
168
|
|
|
159
169
|
const filteredLine = useMemo(() => {
|
|
@@ -368,6 +378,7 @@ const Report3ModernScreen = ({ api, token, onBack }) => {
|
|
|
368
378
|
|
|
369
379
|
<ModernDataTable
|
|
370
380
|
title="Transportation Table"
|
|
381
|
+
freezeFirstColumn
|
|
371
382
|
columns={[
|
|
372
383
|
{ key: 'monthLabel', label: 'Month', width: 110 },
|
|
373
384
|
{ key: 'loadCount2024', label: '2024 Load', width: 110, align: 'right', render: (row) => compactNumber(row.loadCount2024) },
|
|
@@ -12,8 +12,17 @@ export const filterChartByMonths = (chart, selectedMonths) => {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
const toMonthKey = (value) => {
|
|
16
|
+
return String(value ?? '')
|
|
17
|
+
.trim()
|
|
18
|
+
.toLocaleUpperCase('tr-TR')
|
|
19
|
+
.normalize('NFD')
|
|
20
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
21
|
+
};
|
|
22
|
+
const selectedKeys = new Set(selectedMonths.map(toMonthKey));
|
|
23
|
+
|
|
15
24
|
const indices = chart.labels
|
|
16
|
-
.map((label, i) => (
|
|
25
|
+
.map((label, i) => (selectedKeys.has(toMonthKey(label)) ? i : -1))
|
|
17
26
|
.filter(i => i !== -1);
|
|
18
27
|
|
|
19
28
|
return {
|