@dhiraj0720/report1chart 3.0.1 → 3.0.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhiraj0720/report1chart",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "main": "src/index.jsx",
5
5
  "scripts": {
6
6
  "test": "echo 'No tests'"
@@ -1,8 +1,7 @@
1
- import React, { useMemo } from 'react';
2
- import { ScrollView, StyleSheet, Text, View, useWindowDimensions } from 'react-native';
3
- import { formatNumber } from '../utils/formatNumber';
1
+ import React from 'react';
2
+ import { View, Text, ScrollView, StyleSheet } from 'react-native';
4
3
 
5
- const TAB_TABLE_CONFIG = {
4
+ const TABLE_CONFIG = {
6
5
  kumule: {
7
6
  title: '2025 YILI ŞİRKET ve İŞTİPİ BAZINDA BRÜT KAR & FAALİYET KAR PERFORMANS TABLOSU',
8
7
  columns: [
@@ -71,222 +70,182 @@ const TAB_TABLE_CONFIG = {
71
70
  },
72
71
  };
73
72
 
74
- const trendUi = (trendValue) => {
75
- if (trendValue === 1) {
76
- return { icon: '', color: '#2e7d32' };
73
+ const formatNumber = (value) => {
74
+ if (value === null || value === undefined || value === '') {
75
+ return '-';
77
76
  }
78
77
 
79
- if (trendValue === 2) {
80
- return { icon: '↓', color: '#c62828' };
81
- }
78
+ return Number(value).toLocaleString('en-US');
79
+ };
82
80
 
83
- if (trendValue === 0) {
84
- return { icon: '●', color: '#c62828' };
81
+ const isTotalRow = (row) => row?.rowType === 1 || row?.rowType === 3;
82
+
83
+ const trendFromValue = (value) => {
84
+ if (value === null || value === undefined) {
85
+ return 0;
85
86
  }
86
87
 
87
- return { icon: '●', color: '#e65100' };
88
+ return value >= 0 ? 1 : 2;
88
89
  };
89
90
 
90
- const ratioTrend = (ratioValue) => {
91
- if (ratioValue === null || ratioValue === undefined) {
92
- return null;
91
+ const ratioTrend = (value) => {
92
+ if (value === null || value === undefined) {
93
+ return 0;
93
94
  }
94
95
 
95
- if (ratioValue < 0) {
96
+ if (value < 0) {
96
97
  return 0;
97
98
  }
98
99
 
99
- if (ratioValue <= 50) {
100
+ if (value <= 50) {
100
101
  return 1;
101
102
  }
102
103
 
103
104
  return 2;
104
105
  };
105
106
 
106
- const formatPercent = (value) => {
107
+ const PercentCell = ({ value, trend }) => {
107
108
  if (value === null || value === undefined) {
108
- return '-';
109
+ return <Text>-</Text>;
109
110
  }
110
111
 
111
- return Number(value).toLocaleString('en-US');
112
+ const resolvedTrend = trend || trendFromValue(value);
113
+ const isUp = resolvedTrend === 1;
114
+
115
+ return (
116
+ <Text
117
+ style={[
118
+ styles.percentText,
119
+ isUp ? styles.percentUp : styles.percentDown,
120
+ ]}
121
+ numberOfLines={1}
122
+ adjustsFontSizeToFit
123
+ minimumFontScale={0.8}
124
+ >
125
+ {isUp ? '↑' : '↓'} {Math.abs(value)}%
126
+ </Text>
127
+ );
112
128
  };
113
129
 
114
- const formatRatio = (value) => {
130
+ const RatioCell = ({ value }) => {
115
131
  if (value === null || value === undefined) {
116
- return '-';
132
+ return <Text>-</Text>;
117
133
  }
118
134
 
119
- if (value < 0) {
120
- return `-%${Math.abs(value)}`;
121
- }
135
+ const trend = ratioTrend(value);
136
+ const isUp = trend === 1;
122
137
 
123
- return `%${value}`;
138
+ return (
139
+ <Text
140
+ style={[
141
+ styles.percentText,
142
+ isUp ? styles.percentUp : styles.percentDown,
143
+ ]}
144
+ numberOfLines={1}
145
+ adjustsFontSizeToFit
146
+ minimumFontScale={0.8}
147
+ >
148
+ {isUp ? '↑' : '↓'} %{value}
149
+ </Text>
150
+ );
124
151
  };
125
152
 
126
- const DataCell = ({ children, rowStyle, cellStyle }) => (
127
- <View style={[styles.dataCell, rowStyle, cellStyle]}>
128
- {children}
153
+ const Cell = ({ children, bold = false, highlight = false, width = 100 }) => (
154
+ <View
155
+ style={[
156
+ styles.cell,
157
+ { width },
158
+ bold && styles.boldCell,
159
+ highlight && styles.highlightCell,
160
+ ]}
161
+ >
162
+ <Text
163
+ style={[
164
+ styles.cellText,
165
+ bold && styles.boldText,
166
+ ]}
167
+ numberOfLines={1}
168
+ ellipsizeMode="tail"
169
+ adjustsFontSizeToFit
170
+ minimumFontScale={0.72}
171
+ >
172
+ {children}
173
+ </Text>
129
174
  </View>
130
175
  );
131
176
 
132
- const TrendValue = ({ value, trend }) => {
133
- const trendStyle = trendUi(trend);
134
-
135
- return (
136
- <View style={styles.trendWrapper}>
137
- <Text style={[styles.trendIcon, { color: trendStyle.color }]}>
138
- {trendStyle.icon}
139
- </Text>
140
- <Text numberOfLines={1} style={styles.dataCellText}>
141
- {value}
142
- </Text>
143
- </View>
144
- );
145
- };
146
-
147
- const renderCellValue = (row, column) => {
177
+ const renderDataCell = (row, column, isTotal) => {
148
178
  if (column.type === 'number') {
149
- return <Text style={styles.dataCellText}>{formatNumber(row[column.key])}</Text>;
179
+ return <Cell key={column.key} highlight={isTotal}>{formatNumber(row[column.key])}</Cell>;
150
180
  }
151
181
 
152
182
  if (column.type === 'trendPercent') {
153
183
  return (
154
- <TrendValue
155
- value={formatPercent(row[column.key])}
156
- trend={row[column.trendKey]}
157
- />
184
+ <Cell key={column.key} highlight={isTotal}>
185
+ <PercentCell value={row[column.key]} trend={row[column.trendKey]} />
186
+ </Cell>
158
187
  );
159
188
  }
160
189
 
161
190
  if (column.type === 'ratio') {
162
191
  return (
163
- <TrendValue
164
- value={formatRatio(row[column.key])}
165
- trend={ratioTrend(row[column.key])}
166
- />
192
+ <Cell key={column.key} highlight={isTotal}>
193
+ <RatioCell value={row[column.key]} />
194
+ </Cell>
167
195
  );
168
196
  }
169
197
 
170
- return <Text style={styles.dataCellText}>-</Text>;
171
- };
172
-
173
- const rowTypeStyle = (row, index) => {
174
- if (row.rowType === 1 || row.rowType === 3) {
175
- return styles.totalRow;
176
- }
177
-
178
- return index % 2 === 0 ? styles.evenRow : styles.oddRow;
198
+ return <Cell key={column.key} highlight={isTotal}>-</Cell>;
179
199
  };
180
200
 
181
- const FrozenTableReport4A = ({ rows = [], tabKey = 'kumule', isFullscreen = false }) => {
182
- const { width: screenWidth } = useWindowDimensions();
183
- const config = TAB_TABLE_CONFIG[tabKey] || TAB_TABLE_CONFIG.kumule;
184
-
185
- const layout = useMemo(() => {
186
- const safeWidth = Math.max(280, screenWidth - (isFullscreen ? 32 : 24));
187
-
188
- const frozenColumnWidth = isFullscreen
189
- ? Math.max(160, Math.min(220, safeWidth * 0.3))
190
- : Math.max(128, Math.min(156, safeWidth * 0.38));
191
-
192
- const dataColumnWidth = isFullscreen
193
- ? Math.max(96, Math.min(142, safeWidth * 0.18))
194
- : Math.max(92, Math.min(116, (safeWidth - frozenColumnWidth) / 2));
201
+ const FrozenTableReport4A = ({ rows = [], tabKey = 'kumule' }) => {
202
+ const config = TABLE_CONFIG[tabKey] || TABLE_CONFIG.kumule;
195
203
 
196
- return {
197
- frozenColumnWidth,
198
- dataColumnWidth,
199
- rowHeight: isFullscreen ? 42 : 38,
200
- headerHeight: isFullscreen ? 54 : 46,
201
- };
202
- }, [isFullscreen, screenWidth]);
203
-
204
- if (!rows.length) {
205
- return <Text style={styles.noData}>No data available</Text>;
204
+ if (!rows || rows.length === 0) {
205
+ return (
206
+ <Text style={styles.emptyText}>
207
+ No data available
208
+ </Text>
209
+ );
206
210
  }
207
211
 
208
212
  return (
209
- <View style={[styles.wrapper, isFullscreen && styles.wrapperFullscreen]}>
210
- <Text style={styles.tableTitle}>{config.title}</Text>
211
-
212
- <View style={styles.tableContainer}>
213
- <View style={[styles.frozenColumn, { width: layout.frozenColumnWidth }]}>
214
- <View
215
- style={[
216
- styles.nameCell,
217
- styles.headerCell,
218
- { height: layout.headerHeight },
219
- ]}
220
- >
221
- <Text style={styles.headerText}>ŞİRKET / İŞTİPİ</Text>
222
- </View>
213
+ <View>
214
+ <Text style={styles.title}>{config.title}</Text>
223
215
 
216
+ <View style={styles.container}>
217
+ <View style={styles.frozenColumn}>
218
+ <Cell bold width={180}>ŞİRKET / İŞTİPİ</Cell>
224
219
  {rows.map((row, index) => {
225
- const isTotal = row.rowType === 1 || row.rowType === 3;
220
+ const total = isTotalRow(row);
226
221
  return (
227
- <View
228
- key={`name-${row.sortOrder || index}`}
229
- style={[
230
- styles.nameCell,
231
- rowTypeStyle(row, index),
232
- { height: layout.rowHeight },
233
- ]}
222
+ <Cell
223
+ key={`${row.sortOrder || index}-name`}
224
+ bold={total}
225
+ highlight={total}
226
+ width={180}
234
227
  >
235
- <View style={styles.nameCellContent}>
236
- <Text style={styles.star}>{isTotal ? '★' : ''}</Text>
237
- <Text
238
- numberOfLines={1}
239
- adjustsFontSizeToFit
240
- minimumFontScale={0.78}
241
- style={styles.nameText}
242
- >
243
- {row.name}
244
- </Text>
245
- </View>
246
- </View>
228
+ {row.name}
229
+ </Cell>
247
230
  );
248
231
  })}
249
232
  </View>
250
233
 
251
234
  <ScrollView horizontal showsHorizontalScrollIndicator={false}>
252
235
  <View>
253
- <View style={styles.row}>
236
+ <View style={styles.headerRow}>
254
237
  {config.columns.map((column) => (
255
- <View
256
- key={column.key}
257
- style={[
258
- styles.dataCell,
259
- styles.headerCell,
260
- {
261
- width: layout.dataColumnWidth,
262
- height: layout.headerHeight,
263
- },
264
- ]}
265
- >
266
- <Text numberOfLines={2} style={styles.headerText}>
267
- {column.label}
268
- </Text>
269
- </View>
238
+ <Cell key={column.key} bold>
239
+ {column.label}
240
+ </Cell>
270
241
  ))}
271
242
  </View>
272
243
 
273
244
  {rows.map((row, index) => {
274
- const rowStyle = rowTypeStyle(row, index);
275
-
245
+ const total = isTotalRow(row);
276
246
  return (
277
- <View key={`row-${row.sortOrder || index}`} style={styles.row}>
278
- {config.columns.map((column) => (
279
- <DataCell
280
- key={`${row.sortOrder || index}-${column.key}`}
281
- rowStyle={rowStyle}
282
- cellStyle={{
283
- width: layout.dataColumnWidth,
284
- height: layout.rowHeight,
285
- }}
286
- >
287
- {renderCellValue(row, column)}
288
- </DataCell>
289
- ))}
247
+ <View key={`${row.sortOrder || index}-row`} style={styles.dataRow}>
248
+ {config.columns.map((column) => renderDataCell(row, column, total))}
290
249
  </View>
291
250
  );
292
251
  })}
@@ -300,105 +259,72 @@ const FrozenTableReport4A = ({ rows = [], tabKey = 'kumule', isFullscreen = fals
300
259
  export default FrozenTableReport4A;
301
260
 
302
261
  const styles = StyleSheet.create({
303
- wrapper: {
304
- backgroundColor: '#f4f7fb',
305
- borderRadius: 10,
306
- borderWidth: 1,
307
- borderColor: '#ccd8e4',
308
- padding: 6,
309
- },
310
- wrapperFullscreen: {
311
- padding: 8,
312
- },
313
- tableTitle: {
262
+ title: {
314
263
  textAlign: 'center',
315
- fontSize: 14,
264
+ fontSize: 16,
316
265
  fontWeight: '700',
317
- color: '#223648',
318
- marginBottom: 6,
266
+ color: '#2e2e2e',
267
+ marginBottom: 8,
268
+ marginTop: 4,
319
269
  },
320
- tableContainer: {
270
+ container: {
321
271
  flexDirection: 'row',
322
272
  borderWidth: 1,
323
- borderColor: '#b8c6d4',
324
- borderRadius: 8,
273
+ borderColor: '#ddd',
274
+ borderRadius: 10,
325
275
  overflow: 'hidden',
326
- backgroundColor: '#e7edf3',
276
+ marginVertical: 12,
277
+ backgroundColor: '#fff',
327
278
  },
328
279
  frozenColumn: {
280
+ width: 180,
281
+ backgroundColor: '#f4f6f8',
329
282
  borderRightWidth: 1,
330
- borderRightColor: '#ecf1f6',
283
+ borderColor: '#ddd',
331
284
  },
332
- row: {
285
+ headerRow: {
333
286
  flexDirection: 'row',
287
+ backgroundColor: '#4E79A7',
334
288
  },
335
- nameCell: {
336
- justifyContent: 'center',
337
- borderBottomWidth: 1,
338
- borderBottomColor: '#edf2f7',
339
- paddingHorizontal: 6,
340
- },
341
- nameCellContent: {
289
+ dataRow: {
342
290
  flexDirection: 'row',
343
- alignItems: 'center',
344
- },
345
- nameText: {
346
- flex: 1,
347
- fontSize: 11.5,
348
- color: '#203040',
349
- },
350
- star: {
351
- width: 14,
352
- textAlign: 'center',
353
- color: '#b7791f',
354
- fontSize: 13,
355
- marginRight: 2,
356
291
  },
357
- dataCell: {
292
+ cell: {
293
+ width: 100,
294
+ paddingVertical: 12,
295
+ paddingHorizontal: 8,
358
296
  justifyContent: 'center',
359
- alignItems: 'center',
360
- paddingHorizontal: 4,
361
297
  borderBottomWidth: 1,
362
- borderBottomColor: '#edf2f7',
298
+ borderColor: '#e0e0e0',
363
299
  },
364
- dataCellText: {
365
- fontSize: 11.5,
366
- color: '#2b3d4e',
300
+ cellText: {
301
+ fontSize: 12,
367
302
  textAlign: 'center',
303
+ color: '#333',
368
304
  },
369
- headerCell: {
370
- backgroundColor: '#5f7f9f',
305
+ boldCell: {
306
+ backgroundColor: '#e9f0f8',
371
307
  },
372
- headerText: {
373
- color: '#ffffff',
308
+ boldText: {
374
309
  fontWeight: '700',
375
- textAlign: 'center',
376
- fontSize: 11,
377
310
  },
378
- evenRow: {
379
- backgroundColor: '#e6eaef',
311
+ highlightCell: {
312
+ backgroundColor: '#e9f0f8',
380
313
  },
381
- oddRow: {
382
- backgroundColor: '#dde3e9',
314
+ percentText: {
315
+ fontWeight: '700',
316
+ fontSize: 12,
317
+ textAlign: 'center',
383
318
  },
384
- totalRow: {
385
- backgroundColor: '#a7bdd2',
319
+ percentUp: {
320
+ color: '#2e7d32',
386
321
  },
387
- trendWrapper: {
388
- flexDirection: 'row',
389
- alignItems: 'center',
390
- justifyContent: 'center',
391
- },
392
- trendIcon: {
393
- fontSize: 13,
394
- fontWeight: '700',
395
- marginRight: 3,
396
- marginTop: -1,
322
+ percentDown: {
323
+ color: '#d32f2f',
397
324
  },
398
- noData: {
325
+ emptyText: {
399
326
  textAlign: 'center',
327
+ padding: 20,
400
328
  color: '#666',
401
- paddingVertical: 20,
402
- fontSize: 14,
403
329
  },
404
330
  });
@@ -11,6 +11,7 @@ import {
11
11
  } from 'react-native';
12
12
  import fetchReport4 from '../api/report4Fetcher';
13
13
  import FrozenTableReport4A from '../components/FrozenTableReport4A';
14
+ import Report1Card from '../components/Report1Card';
14
15
 
15
16
  const TABS = [
16
17
  { key: 'kumule', label: 'KÜMÜLE' },
@@ -18,6 +19,42 @@ const TABS = [
18
19
  { key: 'fg', label: 'FG / BRÜT KAR ORANI' },
19
20
  ];
20
21
 
22
+ const mapRowToCardItem = (row, tabKey) => {
23
+ if (tabKey === 'faaliyet') {
24
+ return {
25
+ name: row.name,
26
+ actual2024: row.fk2024,
27
+ actual2025: row.fk2025,
28
+ actualChangePercent: row.changePercent ?? 0,
29
+ budget2025: row.budget2025,
30
+ budgetVariancePercent: row.budgetVariancePercent ?? 0,
31
+ };
32
+ }
33
+
34
+ if (tabKey === 'fg') {
35
+ const ratioDiff = (row.ratio2025 ?? 0) - (row.ratio2024 ?? 0);
36
+ return {
37
+ name: row.name,
38
+ actual2024: row.gross2024,
39
+ actual2025: row.gross2025,
40
+ actualChangePercent: ratioDiff,
41
+ budget2025: row.fk2025,
42
+ budgetVariancePercent: ratioDiff,
43
+ opexToGrossProfitPercent: row.ratio2025,
44
+ };
45
+ }
46
+
47
+ return {
48
+ name: row.name,
49
+ actual2024: row.gross2024,
50
+ actual2025: row.gross2025,
51
+ actualChangePercent: row.grossChangePercent ?? 0,
52
+ budget2025: row.budgetGross2025,
53
+ budgetVariancePercent: row.budgetGrossVariancePercent ?? 0,
54
+ opexToGrossProfitPercent: row.ratio2025,
55
+ };
56
+ };
57
+
21
58
  const Report4AScreen = ({ api, token, onBack }) => {
22
59
  const { width, height } = useWindowDimensions();
23
60
  const [activeTab, setActiveTab] = useState('kumule');
@@ -85,7 +122,7 @@ const Report4AScreen = ({ api, token, onBack }) => {
85
122
  <TouchableOpacity onPress={onBack} style={styles.backButton}>
86
123
  <Text style={styles.backIcon}>‹</Text>
87
124
  </TouchableOpacity>
88
- <Text style={styles.headerTitle}>New report Formate</Text>
125
+ <Text style={styles.headerTitle}>Performans Raporu (USD) - NEW</Text>
89
126
  </View>
90
127
 
91
128
  <View style={styles.tabsContainer}>
@@ -138,6 +175,14 @@ const Report4AScreen = ({ api, token, onBack }) => {
138
175
  </View>
139
176
 
140
177
  <FrozenTableReport4A rows={activeRows} tabKey={activeTab} />
178
+
179
+ <Text style={styles.sectionTitle}>Individual Reports</Text>
180
+ {activeRows.map((row, index) => (
181
+ <Report1Card
182
+ key={`card-${row.sortOrder || index}`}
183
+ item={mapRowToCardItem(row, activeTab)}
184
+ />
185
+ ))}
141
186
  </ScrollView>
142
187
  ) : null}
143
188
  </View>
@@ -279,6 +324,13 @@ const styles = StyleSheet.create({
279
324
  marginTop: 8,
280
325
  marginBottom: 6,
281
326
  },
327
+ sectionTitle: {
328
+ fontSize: 16,
329
+ fontWeight: '700',
330
+ marginTop: 8,
331
+ marginBottom: 14,
332
+ color: '#111',
333
+ },
282
334
  fullViewButton: {
283
335
  backgroundColor: '#4E79A7',
284
336
  borderRadius: 7,
@@ -8,16 +8,11 @@ import {
8
8
  } from 'react-native';
9
9
 
10
10
  const REPORTS = [
11
-
12
- {
13
- id: '1A',
14
- title: 'Performans Raporu (USD)',
15
- desc: 'Option 1',
16
- },
11
+
17
12
  {
18
- id: 1,
19
- title: 'Performans Raporu (USD)',
20
- desc: 'Option 2',
13
+ id: '4A',
14
+ title: 'Performans Raporu (USD) - NEW',
15
+ desc: 'New report formate',
21
16
  },
22
17
 
23
18
  {
@@ -41,11 +36,18 @@ const REPORTS = [
41
36
  title: 'Transportation Business Analysis',
42
37
  desc: 'Option 2',
43
38
  },
39
+
44
40
  {
45
- id: '4A',
46
- title: 'New performance Report',
47
- desc: 'New report formate',
41
+ id: '1A',
42
+ title: 'Performans Raporu (USD) - OLD',
43
+ desc: 'Option 1',
48
44
  },
45
+ {
46
+ id: 1,
47
+ title: 'Performans Raporu (USD) - OLD',
48
+ desc: 'Option 2',
49
+ },
50
+
49
51
  ];
50
52
 
51
53
  const ReportListScreen = ({ onSelect, onExit }) => {