@dhiraj0720/report1chart 1.0.5 → 2.1.0

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/src/index.jsx CHANGED
@@ -1,1338 +1,18 @@
1
- import React, { useState } from 'react';
2
- import {
3
- View,
4
- Text,
5
- StyleSheet,
6
- TouchableOpacity,
7
- ScrollView,
8
- ActivityIndicator,
9
- Dimensions,
10
- } from 'react-native';
1
+ import React from 'react';
2
+ import ReportDashboard from './screens/ReportDashboard';
11
3
 
12
4
  const ReportChart = ({
5
+ reports = [],
13
6
  onReportSelect,
14
- onClose,
15
- reports = [],
16
- onFetchReportData
7
+ onClose
17
8
  }) => {
18
- const [selectedReport, setSelectedReport] = useState(null);
19
- const [reportData, setReportData] = useState(null);
20
- const [loading, setLoading] = useState(false);
21
- const [error, setError] = useState(null);
22
-
23
- // Default reports if none provided
24
- const defaultReports = [
25
- {
26
- id: 1,
27
- name: 'Report 1',
28
- title: 'Revenue Trend',
29
- type: 'line',
30
- description: 'Monthly revenue analysis'
31
- },
32
- {
33
- id: 2,
34
- name: 'Report 2',
35
- title: 'Revenue by Mode',
36
- type: 'bar',
37
- description: 'Revenue distribution across modes'
38
- },
39
- {
40
- id: 3,
41
- name: 'Report 3',
42
- title: 'Shipment by Direction',
43
- type: 'pie',
44
- description: 'Shipment direction analysis'
45
- },
46
- ];
47
-
48
- const reportList = reports.length > 0 ? reports : defaultReports;
49
-
50
- const handleReportClick = async (report) => {
51
- setLoading(true);
52
- setError(null);
53
- setReportData(null);
54
- setSelectedReport(report);
55
-
56
- try {
57
- // Call the parent function to fetch data
58
- if (onFetchReportData) {
59
- const data = await onFetchReportData(report);
60
- if (data) {
61
- setReportData({
62
- ...data,
63
- title: report.title || report.name,
64
- type: report.type || 'bar',
65
- });
66
- }
67
- }
68
-
69
- // Callback to parent
70
- if (onReportSelect) {
71
- onReportSelect(report.name);
72
- }
73
- } catch (err) {
74
- setError(err.message || 'Failed to fetch report data');
75
- } finally {
76
- setLoading(false);
77
- }
78
- };
79
-
80
- // Add currency formatter
81
- const formatCurrency = (value) => {
82
- const num = Number(value);
83
- if (isNaN(num)) return '0';
84
-
85
- if (num >= 1000000) {
86
- return `${(num / 1000000).toFixed(1)}M`;
87
- } else if (num >= 1000) {
88
- return `${(num / 1000).toFixed(1)}K`;
89
- }
90
- return num.toString();
91
- };
92
-
93
- const renderChart = () => {
94
- if (!reportData || !reportData.data) {
95
- return (
96
- <View style={styles.noDataContainer}>
97
- <Text style={styles.noDataText}>No data available for this report</Text>
98
- </View>
99
- );
100
- }
101
-
102
- const { type, subType, data } = reportData;
103
-
104
- if (type === 'table') {
105
- switch (subType) {
106
- case 'compact': // Report 1A
107
- return renderCompactTable(data);
108
- case 'freeze': // Report 1B
109
- return renderFreezeTable(data);
110
- case 'default': // Report 1
111
- default:
112
- return renderTable(data); // Original table
113
- }
114
- }
115
-
116
- switch (type) {
117
- case 'line':
118
- return renderLineChart(data);
119
- case 'bar':
120
- return renderBarChart(data);
121
- case 'pie':
122
- return renderPieChart(data);
123
- default:
124
- return renderBarChart(data);
125
- }
126
- };
127
-
128
-
129
- const renderLineChart = (data) => {
130
- // Handle both formats: { labels, values } or array format
131
- const values = data.values || data.map(d => d.value || d.revenue || d.shipments || 0);
132
- const labels = data.labels || data.map(d => d.label || d.month || d.mode || d.direction || '');
133
-
134
- const maxValue = Math.max(...values, 1);
135
- const chartHeight = 200;
136
- const chartWidth = Dimensions.get('window').width - 64;
137
- const barWidth = (chartWidth / values.length) - 10;
138
-
139
- return (
140
- <View style={styles.chartContainer}>
141
- <Text style={styles.chartTitle}>{reportData.title}</Text>
142
- <ScrollView horizontal showsHorizontalScrollIndicator={false}>
143
- <View style={[styles.chart, { height: chartHeight, width: chartWidth }]}>
144
- {values.map((value, index) => {
145
- const height = (value / maxValue) * chartHeight;
146
- const label = labels[index] || `M${index + 1}`;
147
-
148
- return (
149
- <View key={index} style={styles.linePointWrapper}>
150
- <View style={[styles.linePoint, {
151
- height: Math.max(height, 2),
152
- width: barWidth
153
- }]} />
154
- <View style={styles.lineConnector} />
155
- <Text style={styles.lineLabel} numberOfLines={1}>{label}</Text>
156
- <Text style={styles.valueText}>{formatNumber(value)}</Text>
157
- </View>
158
- );
159
- })}
160
- </View>
161
- </ScrollView>
162
- </View>
163
- );
164
- };
165
-
166
- const renderBarChart = (data) => {
167
- // Handle array format or object format
168
- const isArray = Array.isArray(data);
169
- const values = isArray ? data.map(d => d.revenue || d.value || d.shipments || 0) : data.values;
170
- const labels = isArray ? data.map(d => d.mode || d.label || '') : data.labels;
171
-
172
- const maxValue = Math.max(...values, 1);
173
- const chartHeight = 200;
174
- const chartWidth = Dimensions.get('window').width - 64;
175
- const barWidth = Math.min(40, (chartWidth / values.length) - 10);
176
-
177
- return (
178
- <View style={styles.chartContainer}>
179
- <Text style={styles.chartTitle}>{reportData.title}</Text>
180
- <ScrollView horizontal showsHorizontalScrollIndicator={false}>
181
- <View style={[styles.chart, { height: chartHeight, width: chartWidth }]}>
182
- {values.map((value, index) => {
183
- const height = (value / maxValue) * chartHeight;
184
- const label = labels?.[index] || `Item ${index + 1}`;
185
-
186
- return (
187
- <View key={index} style={styles.barWrapper}>
188
- <View style={[styles.bar, {
189
- height,
190
- width: barWidth,
191
- backgroundColor: getColor(index)
192
- }]} />
193
- <Text style={styles.barLabel} numberOfLines={1}>{label}</Text>
194
- <Text style={styles.valueText}>{formatNumber(value)}</Text>
195
- </View>
196
- );
197
- })}
198
- </View>
199
- </ScrollView>
200
- </View>
201
- );
202
- };
203
-
204
- const renderTable = (data) => {
205
- if (!Array.isArray(data) || data.length === 0) {
206
- return (
207
- <View style={styles.noDataContainer}>
208
- <Text style={styles.noDataText}>No data available for this report</Text>
209
- </View>
210
- );
211
- }
212
-
213
- return (
214
- <ScrollView horizontal showsHorizontalScrollIndicator={true}>
215
- <View style={styles.table}>
216
- {/* Table Header */}
217
- <View style={styles.tableHeader}>
218
- <View style={[styles.headerCell, styles.firstColumn]}>
219
- <Text style={styles.headerText}>FALİYET KAR/ZARAR</Text>
220
- </View>
221
- <View style={styles.headerCell}>
222
- <Text style={styles.headerText}>2024 Fiili</Text>
223
- </View>
224
- <View style={styles.headerCell}>
225
- <Text style={styles.headerText}>2025 Fiili</Text>
226
- </View>
227
- <View style={styles.headerCell}>
228
- <Text style={styles.headerText}>Fiili Artış %</Text>
229
- </View>
230
- <View style={styles.headerCell}>
231
- <Text style={styles.headerText}>2025 Bütçe</Text>
232
- </View>
233
- <View style={styles.headerCell}>
234
- <Text style={styles.headerText}>Sapma %</Text>
235
- </View>
236
- <View style={styles.headerCell}>
237
- <Text style={styles.headerText}>FALİYET GİD.</Text>
238
- <Text style={styles.headerText}>/ BRÜT KAR %</Text>
239
- </View>
240
- </View>
241
-
242
- {/* Table Rows */}
243
- {data.map((item, index) => (
244
- <View
245
- key={index}
246
- style={[
247
- styles.tableRow,
248
- item.isTotal ? styles.totalRow : (index % 2 === 0 ? styles.evenRow : styles.oddRow)
249
- ]}
250
- >
251
- <View style={[styles.cell, styles.firstColumn]}>
252
- <Text style={item.isTotal ? styles.totalText : styles.cellText}>
253
- {item.name}
254
- </Text>
255
- </View>
256
-
257
- <View style={styles.cell}>
258
- <Text style={styles.numberText}>
259
- {formatCurrency(item.actual2024)}
260
- </Text>
261
- </View>
262
-
263
- <View style={styles.cell}>
264
- <Text style={styles.numberText}>
265
- {formatCurrency(item.actual2025)}
266
- </Text>
267
- </View>
268
-
269
- <View style={styles.cell}>
270
- <Text style={[
271
- styles.percentText,
272
- item.yoYChangePercent >= 0 ? styles.positive : styles.negative
273
- ]}>
274
- {item.yoYChangePercent >= 0 ? '↑' : '↓'} {Math.abs(item.yoYChangePercent)}%
275
- </Text>
276
- </View>
277
-
278
- <View style={styles.cell}>
279
- <Text style={styles.numberText}>
280
- {formatCurrency(item.budget2025)}
281
- </Text>
282
- </View>
283
-
284
- <View style={styles.cell}>
285
- <Text style={[
286
- styles.percentText,
287
- item.budgetVariancePercent >= 0 ? styles.positive : styles.negative
288
- ]}>
289
- {item.budgetVariancePercent >= 0 ? '↑' : '↓'} {Math.abs(item.budgetVariancePercent)}%
290
- </Text>
291
- </View>
292
-
293
- <View style={styles.cell}>
294
- <Text style={[
295
- styles.percentText,
296
- styles.grossMargin
297
- ]}>
298
- {item.grossMarginPercent}%
299
- </Text>
300
- </View>
301
- </View>
302
- ))}
303
- </View>
304
- </ScrollView>
305
- );
306
- };
307
-
308
- const renderCompactTable = (data) => {
309
- if (!Array.isArray(data) || data.length === 0) {
310
- return (
311
- <View style={styles.noDataContainer}>
312
- <Text style={styles.noDataText}>No data available for this report</Text>
313
- </View>
314
- );
315
- }
316
-
317
- return (
318
- <ScrollView style={styles.compactContainer}>
319
- {data.map((item, index) => (
320
- <View
321
- key={index}
322
- style={[
323
- styles.compactCard,
324
- item.isTotal && styles.compactTotalCard,
325
- index % 2 === 0 ? styles.evenCard : styles.oddCard
326
- ]}
327
- >
328
- {/* Card Header */}
329
- <View style={styles.compactHeader}>
330
- <Text style={[
331
- styles.compactTitle,
332
- item.isTotal && styles.totalTitle
333
- ]}>
334
- {item.name}
335
- </Text>
336
- <Text style={[
337
- styles.compactGrossMargin,
338
- item.grossMarginPercent >= 0 ? styles.positive : styles.negative
339
- ]}>
340
- Brüt Kar: {item.grossMarginPercent}%
341
- </Text>
342
- </View>
343
-
344
- {/* Card Body - Grid Layout */}
345
- <View style={styles.compactGrid}>
346
- {/* Column 1 */}
347
- <View style={styles.compactColumn}>
348
- <Text style={styles.compactLabel}>2024 Fiili</Text>
349
- <Text style={styles.compactValue}>
350
- {formatCurrency(item.actual2024)}
351
- </Text>
352
- </View>
353
-
354
- {/* Column 2 */}
355
- <View style={styles.compactColumn}>
356
- <Text style={styles.compactLabel}>2025 Fiili</Text>
357
- <Text style={styles.compactValue}>
358
- {formatCurrency(item.actual2025)}
359
- </Text>
360
- </View>
361
-
362
- {/* Column 3 */}
363
- <View style={styles.compactColumn}>
364
- <Text style={styles.compactLabel}>Fiili Artış</Text>
365
- <View style={styles.percentBadge}>
366
- <Text style={[
367
- styles.percentText,
368
- item.yoYChangePercent >= 0 ? styles.positive : styles.negative
369
- ]}>
370
- {item.yoYChangePercent >= 0 ? '↑' : '↓'} {Math.abs(item.yoYChangePercent)}%
371
- </Text>
372
- </View>
373
- </View>
374
-
375
- {/* Column 4 */}
376
- <View style={styles.compactColumn}>
377
- <Text style={styles.compactLabel}>2025 Bütçe</Text>
378
- <Text style={styles.compactValue}>
379
- {formatCurrency(item.budget2025)}
380
- </Text>
381
- </View>
382
-
383
- {/* Column 5 */}
384
- <View style={styles.compactColumn}>
385
- <Text style={styles.compactLabel}>Sapma</Text>
386
- <View style={styles.percentBadge}>
387
- <Text style={[
388
- styles.percentText,
389
- item.budgetVariancePercent >= 0 ? styles.positive : styles.negative
390
- ]}>
391
- {item.budgetVariancePercent >= 0 ? '↑' : '↓'} {Math.abs(item.budgetVariancePercent)}%
392
- </Text>
393
- </View>
394
- </View>
395
- </View>
396
-
397
- {/* Status Indicator */}
398
- <View style={styles.statusIndicator}>
399
- <View style={[
400
- styles.statusDot,
401
- (item.yoYChangePercent >= 0 && item.budgetVariancePercent >= 0)
402
- ? styles.statusGood
403
- : styles.statusWarning
404
- ]} />
405
- <Text style={styles.statusText}>
406
- {item.yoYChangePercent >= 0 && item.budgetVariancePercent >= 0
407
- ? 'Performans İyi'
408
- : 'İnceleme Gerekli'}
409
- </Text>
410
- </View>
411
- </View>
412
- ))}
413
- </ScrollView>
414
- );
415
- };
416
-
417
- // Report 1B: Freeze First Column Table
418
- const renderFreezeTable = (data) => {
419
- if (!Array.isArray(data) || data.length === 0) {
420
- return (
421
- <View style={styles.noDataContainer}>
422
- <Text style={styles.noDataText}>No data available for this report</Text>
423
- </View>
424
- );
425
- }
426
-
427
- return (
428
- <View style={styles.freezeContainer}>
429
- {/* Fixed First Column */}
430
- <View style={styles.freezeColumn}>
431
- <View style={[styles.freezeHeader, styles.freezeFirstCell]}>
432
- <Text style={styles.freezeHeaderText}>FALİYET KAR/ZARAR</Text>
433
- </View>
434
- {data.map((item, index) => (
435
- <View
436
- key={index}
437
- style={[
438
- styles.freezeRow,
439
- item.isTotal && styles.freezeTotalRow,
440
- index % 2 === 0 ? styles.evenRow : styles.oddRow
441
- ]}
442
- >
443
- <Text style={[
444
- styles.freezeCellText,
445
- item.isTotal && styles.freezeTotalText
446
- ]}>
447
- {item.name}
448
- </Text>
449
- </View>
450
- ))}
451
- </View>
452
-
453
- {/* Scrollable Data Columns */}
454
- <ScrollView horizontal showsHorizontalScrollIndicator={true}>
455
- <View style={styles.scrollableColumns}>
456
- {/* Headers for scrollable columns */}
457
- <View style={styles.freezeHeaderRow}>
458
- {['2024 Fiili', '2025 Fiili', 'Fiili Artış %', '2025 Bütçe', 'Sapma %', 'BRÜT KAR %'].map((header, idx) => (
459
- <View key={idx} style={styles.freezeHeader}>
460
- <Text style={styles.freezeHeaderText}>{header}</Text>
461
- </View>
462
- ))}
463
- </View>
464
-
465
- {/* Data rows for scrollable columns */}
466
- {data.map((item, rowIndex) => (
467
- <View
468
- key={rowIndex}
469
- style={[
470
- styles.freezeDataRow,
471
- item.isTotal && styles.freezeTotalDataRow,
472
- rowIndex % 2 === 0 ? styles.evenRow : styles.oddRow
473
- ]}
474
- >
475
- <View style={styles.freezeDataCell}>
476
- <Text style={styles.freezeDataText}>
477
- {formatCurrency(item.actual2024)}
478
- </Text>
479
- </View>
480
-
481
- <View style={styles.freezeDataCell}>
482
- <Text style={styles.freezeDataText}>
483
- {formatCurrency(item.actual2025)}
484
- </Text>
485
- </View>
486
-
487
- <View style={styles.freezeDataCell}>
488
- <Text style={[
489
- styles.freezePercent,
490
- item.yoYChangePercent >= 0 ? styles.positive : styles.negative
491
- ]}>
492
- {item.yoYChangePercent >= 0 ? '↑' : '↓'} {Math.abs(item.yoYChangePercent)}%
493
- </Text>
494
- </View>
495
-
496
- <View style={styles.freezeDataCell}>
497
- <Text style={styles.freezeDataText}>
498
- {formatCurrency(item.budget2025)}
499
- </Text>
500
- </View>
501
-
502
- <View style={styles.freezeDataCell}>
503
- <Text style={[
504
- styles.freezePercent,
505
- item.budgetVariancePercent >= 0 ? styles.positive : styles.negative
506
- ]}>
507
- {item.budgetVariancePercent >= 0 ? '↑' : '↓'} {Math.abs(item.budgetVariancePercent)}%
508
- </Text>
509
- </View>
510
-
511
- <View style={styles.freezeDataCell}>
512
- <Text style={[
513
- styles.freezePercent,
514
- styles.grossMargin
515
- ]}>
516
- {item.grossMarginPercent}%
517
- </Text>
518
- </View>
519
- </View>
520
- ))}
521
- </View>
522
- </ScrollView>
523
- </View>
524
- );
525
- };
526
-
527
-
528
- const renderPieChart = (data) => {
529
- // Data should be array of objects with label and value
530
- const total = data.reduce((sum, item) => sum + (item.shipments || item.revenue || item.value || 0), 0);
531
-
532
- return (
533
- <View style={styles.chartContainer}>
534
- <Text style={styles.chartTitle}>{reportData.title}</Text>
535
- <View style={styles.pieContainer}>
536
- {data.map((item, index) => {
537
- const value = item.shipments || item.revenue || item.value || 0;
538
- const label = item.direction || item.mode || item.label || `Item ${index + 1}`;
539
- const percentage = total > 0 ? ((value / total) * 100).toFixed(1) : '0';
540
-
541
- return (
542
- <View key={index} style={styles.pieItem}>
543
- <View style={[styles.pieColor, { backgroundColor: getColor(index) }]} />
544
- <Text style={styles.pieLabel}>{label}:</Text>
545
- <Text style={styles.pieValue}>
546
- {formatNumber(value)} ({percentage}%)
547
- </Text>
548
- </View>
549
- );
550
- })}
551
- </View>
552
- {total > 0 && (
553
- <Text style={styles.totalText}>Total: {formatNumber(total)}</Text>
554
- )}
555
- </View>
556
- );
557
- };
558
-
559
- const formatNumber = (num) => {
560
- return num.toLocaleString();
561
- };
562
-
563
- const getColor = (index) => {
564
- const colors = ['#4CAF50', '#2196F3', '#FF9800', '#E91E63', '#9C27B0', '#00BCD4'];
565
- return colors[index % colors.length];
566
- };
567
-
568
- const handleClose = () => {
569
- setSelectedReport(null);
570
- setReportData(null);
571
- if (onClose) onClose();
572
- };
573
-
574
- if (selectedReport) {
575
- return (
576
- <View style={styles.container}>
577
- <View style={styles.header}>
578
- <TouchableOpacity
579
- style={styles.backButton}
580
- onPress={() => {
581
- setSelectedReport(null);
582
- setReportData(null);
583
- }}
584
- >
585
- <Text style={styles.backText}>‹</Text>
586
- <Text style={styles.backButtonText}>Back</Text>
587
- </TouchableOpacity>
588
- <Text style={styles.headerTitle} numberOfLines={1}>
589
- {selectedReport.title || selectedReport.name}
590
- </Text>
591
- <TouchableOpacity onPress={handleClose} style={styles.closeButton}>
592
- <Text style={styles.closeText}>×</Text>
593
- </TouchableOpacity>
594
- </View>
595
-
596
- {loading ? (
597
- <View style={styles.loadingContainer}>
598
- <ActivityIndicator size="large" color="#4CAF50" />
599
- <Text style={styles.loadingText}>Loading report data...</Text>
600
- </View>
601
- ) : error ? (
602
- <View style={styles.errorContainer}>
603
- <Text style={styles.errorText}>Error: {error}</Text>
604
- <TouchableOpacity
605
- style={styles.retryButton}
606
- onPress={() => handleReportClick(selectedReport)}
607
- >
608
- <Text style={styles.retryText}>Retry</Text>
609
- </TouchableOpacity>
610
- </View>
611
- ) : (
612
- <ScrollView style={styles.chartView}>
613
- {renderChart()}
614
-
615
- {reportData && reportData.data && (
616
- <View style={styles.dataInfo}>
617
- <Text style={styles.infoTitle}>Report Information</Text>
618
- <Text style={styles.infoText}>
619
- {selectedReport.description || 'Detailed analysis report'}
620
- </Text>
621
- <Text style={styles.dataSource}>
622
- Data points: {Array.isArray(reportData.data) ? reportData.data.length :
623
- reportData.data.values?.length || reportData.data.labels?.length || 'N/A'}
624
- </Text>
625
- </View>
626
- )}
627
- </ScrollView>
628
- )}
629
- </View>
630
- );
631
- }
632
-
633
9
  return (
634
- <View style={styles.container}>
635
- <View style={styles.header}>
636
- <Text style={styles.headerTitle}>Reports Dashboard</Text>
637
- <TouchableOpacity onPress={handleClose} style={styles.closeButton}>
638
- <Text style={styles.closeText}>×</Text>
639
- </TouchableOpacity>
640
- </View>
641
-
642
- <ScrollView style={styles.reportsList}>
643
- {reportList.map((report) => (
644
- <TouchableOpacity
645
- key={report.id}
646
- style={styles.reportCard}
647
- onPress={() => handleReportClick(report)}
648
- >
649
- <View style={[styles.reportIcon, { backgroundColor: getColor(report.id) }]}>
650
- <Text style={styles.reportIconText}>{report.id}</Text>
651
- </View>
652
- <View style={styles.reportInfo}>
653
- <Text style={styles.reportName}>{report.name}</Text>
654
- <Text style={styles.reportTitle}>{report.title}</Text>
655
- <Text style={styles.reportDesc}>{report.description}</Text>
656
- </View>
657
- <Text style={styles.arrow}>›</Text>
658
- </TouchableOpacity>
659
- ))}
660
- </ScrollView>
661
- </View>
10
+ <ReportDashboard
11
+ reports={reports}
12
+ onReportSelect={onReportSelect}
13
+ onClose={onClose}
14
+ />
662
15
  );
663
16
  };
664
17
 
665
- const styles = StyleSheet.create({
666
- container: {
667
- flex: 1,
668
- backgroundColor: '#f8f9fa',
669
- },
670
- header: {
671
- flexDirection: 'row',
672
- alignItems: 'center',
673
- justifyContent: 'space-between',
674
- backgroundColor: '#fff',
675
- paddingHorizontal: 16,
676
- paddingVertical: 12,
677
- borderBottomWidth: 1,
678
- borderBottomColor: '#e0e0e0',
679
- },
680
- headerTitle: {
681
- fontSize: 18,
682
- fontWeight: '700',
683
- color: '#000',
684
- flex: 1,
685
- textAlign: 'center',
686
- },
687
- backButton: {
688
- flexDirection: 'row',
689
- alignItems: 'center',
690
- padding: 8,
691
- },
692
- backText: {
693
- fontSize: 24,
694
- color: '#4CAF50',
695
- marginRight: 4,
696
- },
697
- backButtonText: {
698
- fontSize: 16,
699
- color: '#4CAF50',
700
- fontWeight: '600',
701
- },
702
- closeButton: {
703
- width: 32,
704
- height: 32,
705
- borderRadius: 16,
706
- backgroundColor: '#f0f0f0',
707
- justifyContent: 'center',
708
- alignItems: 'center',
709
- },
710
- closeText: {
711
- fontSize: 20,
712
- color: '#666',
713
- fontWeight: '300',
714
- },
715
- reportsList: {
716
- flex: 1,
717
- padding: 16,
718
- },
719
- reportCard: {
720
- flexDirection: 'row',
721
- alignItems: 'center',
722
- backgroundColor: '#fff',
723
- borderRadius: 12,
724
- padding: 16,
725
- marginBottom: 12,
726
- borderWidth: 1,
727
- borderColor: '#e8e8e8',
728
- shadowColor: '#000',
729
- shadowOffset: { width: 0, height: 1 },
730
- shadowOpacity: 0.05,
731
- shadowRadius: 2,
732
- elevation: 2,
733
- },
734
- reportIcon: {
735
- width: 44,
736
- height: 44,
737
- borderRadius: 22,
738
- justifyContent: 'center',
739
- alignItems: 'center',
740
- marginRight: 12,
741
- },
742
- reportIconText: {
743
- fontSize: 18,
744
- fontWeight: '700',
745
- color: '#fff',
746
- },
747
- reportInfo: {
748
- flex: 1,
749
- },
750
- reportName: {
751
- fontSize: 16,
752
- fontWeight: '600',
753
- color: '#000',
754
- marginBottom: 2,
755
- },
756
- reportTitle: {
757
- fontSize: 14,
758
- fontWeight: '500',
759
- color: '#4CAF50',
760
- marginBottom: 4,
761
- },
762
- reportDesc: {
763
- fontSize: 13,
764
- color: '#666',
765
- lineHeight: 18,
766
- },
767
- arrow: {
768
- fontSize: 24,
769
- color: '#ccc',
770
- fontWeight: '300',
771
- },
772
- chartView: {
773
- flex: 1,
774
- padding: 16,
775
- },
776
- chartContainer: {
777
- backgroundColor: '#fff',
778
- borderRadius: 12,
779
- padding: 16,
780
- marginBottom: 16,
781
- borderWidth: 1,
782
- borderColor: '#e8e8e8',
783
- shadowColor: '#000',
784
- shadowOffset: { width: 0, height: 1 },
785
- shadowOpacity: 0.05,
786
- shadowRadius: 2,
787
- elevation: 2,
788
- },
789
- chartTitle: {
790
- fontSize: 18,
791
- fontWeight: '700',
792
- color: '#000',
793
- marginBottom: 20,
794
- textAlign: 'center',
795
- },
796
- chart: {
797
- flexDirection: 'row',
798
- alignItems: 'flex-end',
799
- justifyContent: 'space-between',
800
- paddingHorizontal: 8,
801
- },
802
- barWrapper: {
803
- alignItems: 'center',
804
- marginHorizontal: 4,
805
- },
806
- bar: {
807
- borderRadius: 4,
808
- },
809
- barLabel: {
810
- marginTop: 8,
811
- fontSize: 11,
812
- color: '#666',
813
- textAlign: 'center',
814
- width: 60,
815
- },
816
- linePointWrapper: {
817
- alignItems: 'center',
818
- marginHorizontal: 4,
819
- },
820
- linePoint: {
821
- backgroundColor: '#2196F3',
822
- borderRadius: 2,
823
- },
824
- lineConnector: {
825
- width: 2,
826
- backgroundColor: '#2196F3',
827
- opacity: 0.3,
828
- marginVertical: 2,
829
- flex: 1,
830
- },
831
- lineLabel: {
832
- marginTop: 8,
833
- fontSize: 11,
834
- color: '#666',
835
- textAlign: 'center',
836
- width: 60,
837
- },
838
- valueText: {
839
- fontSize: 10,
840
- color: '#999',
841
- marginTop: 4,
842
- fontWeight: '500',
843
- },
844
- pieContainer: {
845
- padding: 10,
846
- },
847
- pieItem: {
848
- flexDirection: 'row',
849
- alignItems: 'center',
850
- marginBottom: 12,
851
- padding: 8,
852
- backgroundColor: '#f9f9f9',
853
- borderRadius: 8,
854
- },
855
- pieColor: {
856
- width: 16,
857
- height: 16,
858
- borderRadius: 8,
859
- marginRight: 12,
860
- },
861
- pieLabel: {
862
- fontSize: 15,
863
- fontWeight: '600',
864
- color: '#000',
865
- flex: 1,
866
- },
867
- pieValue: {
868
- fontSize: 14,
869
- color: '#666',
870
- fontWeight: '500',
871
- },
872
- totalText: {
873
- fontSize: 16,
874
- fontWeight: '700',
875
- color: '#4CAF50',
876
- textAlign: 'center',
877
- marginTop: 16,
878
- paddingTop: 16,
879
- borderTopWidth: 1,
880
- borderTopColor: '#eee',
881
- },
882
- dataInfo: {
883
- backgroundColor: '#e8f5e9',
884
- borderRadius: 12,
885
- padding: 16,
886
- marginTop: 8,
887
- },
888
- infoTitle: {
889
- fontSize: 16,
890
- fontWeight: '700',
891
- color: '#2e7d32',
892
- marginBottom: 8,
893
- },
894
- infoText: {
895
- fontSize: 14,
896
- color: '#555',
897
- lineHeight: 20,
898
- marginBottom: 8,
899
- },
900
- dataSource: {
901
- fontSize: 13,
902
- color: '#777',
903
- fontStyle: 'italic',
904
- },
905
- loadingContainer: {
906
- flex: 1,
907
- justifyContent: 'center',
908
- alignItems: 'center',
909
- padding: 40,
910
- },
911
- loadingText: {
912
- marginTop: 16,
913
- fontSize: 16,
914
- color: '#666',
915
- },
916
- errorContainer: {
917
- flex: 1,
918
- justifyContent: 'center',
919
- alignItems: 'center',
920
- padding: 40,
921
- },
922
- errorText: {
923
- fontSize: 16,
924
- color: '#d32f2f',
925
- textAlign: 'center',
926
- marginBottom: 20,
927
- },
928
- retryButton: {
929
- backgroundColor: '#4CAF50',
930
- paddingHorizontal: 24,
931
- paddingVertical: 12,
932
- borderRadius: 8,
933
- },
934
- retryText: {
935
- color: '#fff',
936
- fontSize: 16,
937
- fontWeight: '600',
938
- },
939
- noDataContainer: {
940
- padding: 40,
941
- alignItems: 'center',
942
- },
943
- noDataText: {
944
- fontSize: 16,
945
- color: '#999',
946
- textAlign: 'center',
947
- },
948
-
949
- // Table Styles
950
- table: {
951
- minWidth: 700,
952
- marginBottom: 20,
953
- },
954
- tableHeader: {
955
- flexDirection: 'row',
956
- backgroundColor: '#2c3e50',
957
- borderBottomWidth: 1,
958
- borderBottomColor: '#ddd',
959
- },
960
- headerCell: {
961
- flex: 1,
962
- padding: 10,
963
- minWidth: 100,
964
- justifyContent: 'center',
965
- alignItems: 'center',
966
- borderRightWidth: 1,
967
- borderRightColor: '#444',
968
- },
969
- firstColumn: {
970
- flex: 1.5,
971
- minWidth: 180,
972
- },
973
- headerText: {
974
- color: '#fff',
975
- fontWeight: '600',
976
- fontSize: 11,
977
- textAlign: 'center',
978
- },
979
- tableRow: {
980
- flexDirection: 'row',
981
- borderBottomWidth: 1,
982
- borderBottomColor: '#eee',
983
- minHeight: 40,
984
- },
985
- evenRow: {
986
- backgroundColor: '#fff',
987
- },
988
- oddRow: {
989
- backgroundColor: '#f9f9f9',
990
- },
991
- totalRow: {
992
- backgroundColor: '#e8f5e9',
993
- borderTopWidth: 2,
994
- borderTopColor: '#4CAF50',
995
- borderBottomWidth: 2,
996
- borderBottomColor: '#4CAF50',
997
- },
998
- cell: {
999
- flex: 1,
1000
- padding: 8,
1001
- minWidth: 100,
1002
- justifyContent: 'center',
1003
- alignItems: 'center',
1004
- borderRightWidth: 1,
1005
- borderRightColor: '#eee',
1006
- },
1007
- cellText: {
1008
- fontSize: 12,
1009
- color: '#333',
1010
- textAlign: 'center',
1011
- },
1012
- totalText: {
1013
- fontSize: 12,
1014
- fontWeight: '700',
1015
- color: '#2c3e50',
1016
- textAlign: 'center',
1017
- },
1018
- numberText: {
1019
- fontSize: 11,
1020
- fontWeight: '500',
1021
- fontFamily: 'monospace',
1022
- color: '#333',
1023
- },
1024
- percentText: {
1025
- fontSize: 12,
1026
- fontWeight: '600',
1027
- fontFamily: 'monospace',
1028
- },
1029
- positive: {
1030
- color: '#27ae60',
1031
- },
1032
- negative: {
1033
- color: '#e74c3c',
1034
- },
1035
- grossMargin: {
1036
- color: '#2c3e50',
1037
- fontWeight: '700',
1038
- },
1039
-
1040
- compactContainer: {
1041
- flex: 1,
1042
- paddingHorizontal: 8,
1043
- },
1044
- compactCard: {
1045
- backgroundColor: '#fff',
1046
- borderRadius: 12,
1047
- marginBottom: 12,
1048
- padding: 16,
1049
- borderWidth: 1,
1050
- borderColor: '#e8e8e8',
1051
- shadowColor: '#000',
1052
- shadowOffset: { width: 0, height: 2 },
1053
- shadowOpacity: 0.1,
1054
- shadowRadius: 3,
1055
- elevation: 2,
1056
- },
1057
- compactTotalCard: {
1058
- backgroundColor: '#e8f5e9',
1059
- borderColor: '#4CAF50',
1060
- borderWidth: 2,
1061
- },
1062
- evenCard: {
1063
- backgroundColor: '#fff',
1064
- },
1065
- oddCard: {
1066
- backgroundColor: '#f9f9f9',
1067
- },
1068
- compactHeader: {
1069
- flexDirection: 'row',
1070
- justifyContent: 'space-between',
1071
- alignItems: 'center',
1072
- marginBottom: 12,
1073
- paddingBottom: 12,
1074
- borderBottomWidth: 1,
1075
- borderBottomColor: '#eee',
1076
- },
1077
- compactTitle: {
1078
- fontSize: 14,
1079
- fontWeight: '600',
1080
- color: '#2c3e50',
1081
- flex: 1,
1082
- },
1083
- totalTitle: {
1084
- fontWeight: '700',
1085
- color: '#2c3e50',
1086
- fontSize: 15,
1087
- },
1088
- compactGrossMargin: {
1089
- fontSize: 13,
1090
- fontWeight: '600',
1091
- paddingHorizontal: 8,
1092
- paddingVertical: 4,
1093
- borderRadius: 6,
1094
- backgroundColor: '#f0f0f0',
1095
- },
1096
- compactGrid: {
1097
- flexDirection: 'row',
1098
- flexWrap: 'wrap',
1099
- justifyContent: 'space-between',
1100
- },
1101
- compactColumn: {
1102
- width: '48%',
1103
- marginBottom: 12,
1104
- backgroundColor: '#f8f9fa',
1105
- padding: 10,
1106
- borderRadius: 8,
1107
- alignItems: 'center',
1108
- },
1109
- compactLabel: {
1110
- fontSize: 11,
1111
- color: '#666',
1112
- marginBottom: 4,
1113
- textAlign: 'center',
1114
- },
1115
- compactValue: {
1116
- fontSize: 13,
1117
- fontWeight: '600',
1118
- color: '#2c3e50',
1119
- fontFamily: 'monospace',
1120
- },
1121
- percentBadge: {
1122
- backgroundColor: '#fff',
1123
- paddingHorizontal: 10,
1124
- paddingVertical: 4,
1125
- borderRadius: 12,
1126
- borderWidth: 1,
1127
- borderColor: '#e0e0e0',
1128
- },
1129
- statusIndicator: {
1130
- flexDirection: 'row',
1131
- alignItems: 'center',
1132
- marginTop: 12,
1133
- paddingTop: 12,
1134
- borderTopWidth: 1,
1135
- borderTopColor: '#eee',
1136
- },
1137
- statusDot: {
1138
- width: 8,
1139
- height: 8,
1140
- borderRadius: 4,
1141
- marginRight: 8,
1142
- },
1143
- statusGood: {
1144
- backgroundColor: '#4CAF50',
1145
- },
1146
- statusWarning: {
1147
- backgroundColor: '#FF9800',
1148
- },
1149
- statusText: {
1150
- fontSize: 12,
1151
- color: '#666',
1152
- },
1153
-
1154
- // Report 1B: Freeze First Column Styles
1155
- freezeContainer: {
1156
- flex: 1,
1157
- flexDirection: 'row',
1158
- },
1159
- freezeColumn: {
1160
- width: 180,
1161
- borderRightWidth: 2,
1162
- borderRightColor: '#ddd',
1163
- backgroundColor: '#fff',
1164
- },
1165
- freezeFirstCell: {
1166
- backgroundColor: '#2c3e50',
1167
- justifyContent: 'center',
1168
- alignItems: 'center',
1169
- },
1170
- freezeHeader: {
1171
- height: 50,
1172
- justifyContent: 'center',
1173
- alignItems: 'center',
1174
- backgroundColor: '#2c3e50',
1175
- borderBottomWidth: 1,
1176
- borderBottomColor: '#444',
1177
- borderRightWidth: 1,
1178
- borderRightColor: '#444',
1179
- minWidth: 120,
1180
- },
1181
- freezeHeaderRow: {
1182
- flexDirection: 'row',
1183
- },
1184
- freezeHeaderText: {
1185
- color: '#fff',
1186
- fontWeight: '600',
1187
- fontSize: 12,
1188
- textAlign: 'center',
1189
- },
1190
- freezeRow: {
1191
- height: 45,
1192
- justifyContent: 'center',
1193
- paddingHorizontal: 10,
1194
- borderBottomWidth: 1,
1195
- borderBottomColor: '#eee',
1196
- },
1197
- freezeTotalRow: {
1198
- backgroundColor: '#e8f5e9',
1199
- borderTopWidth: 2,
1200
- borderTopColor: '#4CAF50',
1201
- borderBottomWidth: 2,
1202
- borderBottomColor: '#4CAF50',
1203
- },
1204
- freezeCellText: {
1205
- fontSize: 12,
1206
- color: '#333',
1207
- fontWeight: '500',
1208
- },
1209
- freezeTotalText: {
1210
- fontWeight: '700',
1211
- color: '#2c3e50',
1212
- },
1213
- scrollableColumns: {
1214
- flex: 1,
1215
- },
1216
- freezeDataRow: {
1217
- flexDirection: 'row',
1218
- height: 45,
1219
- borderBottomWidth: 1,
1220
- borderBottomColor: '#eee',
1221
- },
1222
- freezeTotalDataRow: {
1223
- backgroundColor: '#e8f5e9',
1224
- },
1225
- freezeDataCell: {
1226
- minWidth: 120,
1227
- justifyContent: 'center',
1228
- alignItems: 'center',
1229
- borderRightWidth: 1,
1230
- borderRightColor: '#eee',
1231
- paddingHorizontal: 8,
1232
- },
1233
- freezeDataText: {
1234
- fontSize: 12,
1235
- fontWeight: '500',
1236
- fontFamily: 'monospace',
1237
- color: '#333',
1238
- },
1239
- freezePercent: {
1240
- fontSize: 12,
1241
- fontWeight: '600',
1242
- fontFamily: 'monospace',
1243
- },
1244
-
1245
- // Add view type selector for performance reports
1246
- viewTypeSelector: {
1247
- flexDirection: 'row',
1248
- backgroundColor: '#f0f0f0',
1249
- borderRadius: 8,
1250
- padding: 4,
1251
- marginBottom: 16,
1252
- alignSelf: 'center',
1253
- },
1254
- viewTypeButton: {
1255
- paddingHorizontal: 16,
1256
- paddingVertical: 8,
1257
- borderRadius: 6,
1258
- marginHorizontal: 2,
1259
- },
1260
- activeViewType: {
1261
- backgroundColor: '#fff',
1262
- shadowColor: '#000',
1263
- shadowOffset: { width: 0, height: 1 },
1264
- shadowOpacity: 0.1,
1265
- shadowRadius: 2,
1266
- elevation: 2,
1267
- },
1268
- viewTypeText: {
1269
- fontSize: 13,
1270
- fontWeight: '500',
1271
- color: '#666',
1272
- },
1273
- activeViewTypeText: {
1274
- color: '#4CAF50',
1275
- fontWeight: '600',
1276
- },
1277
- });
1278
-
1279
- // Add view type selector component in the chart view
1280
- {selectedReport && (selectedReport.id === 1 || selectedReport.id === 1.1 || selectedReport.id === 1.2) && (
1281
- <View style={styles.viewTypeSelector}>
1282
- <TouchableOpacity
1283
- style={[
1284
- styles.viewTypeButton,
1285
- reportData?.subType === 'default' && styles.activeViewType
1286
- ]}
1287
- onPress={() => {
1288
- setReportData({
1289
- ...reportData,
1290
- subType: 'default'
1291
- });
1292
- }}
1293
- >
1294
- <Text style={[
1295
- styles.viewTypeText,
1296
- reportData?.subType === 'default' && styles.activeViewTypeText
1297
- ]}>Varsayılan</Text>
1298
- </TouchableOpacity>
1299
-
1300
- <TouchableOpacity
1301
- style={[
1302
- styles.viewTypeButton,
1303
- reportData?.subType === 'compact' && styles.activeViewType
1304
- ]}
1305
- onPress={() => {
1306
- setReportData({
1307
- ...reportData,
1308
- subType: 'compact'
1309
- });
1310
- }}
1311
- >
1312
- <Text style={[
1313
- styles.viewTypeText,
1314
- reportData?.subType === 'compact' && styles.activeViewTypeText
1315
- ]}>Kompakt</Text>
1316
- </TouchableOpacity>
1317
-
1318
- <TouchableOpacity
1319
- style={[
1320
- styles.viewTypeButton,
1321
- reportData?.subType === 'freeze' && styles.activeViewType
1322
- ]}
1323
- onPress={() => {
1324
- setReportData({
1325
- ...reportData,
1326
- subType: 'freeze'
1327
- });
1328
- }}
1329
- >
1330
- <Text style={[
1331
- styles.viewTypeText,
1332
- reportData?.subType === 'freeze' && styles.activeViewTypeText
1333
- ]}>Sabit Kolon</Text>
1334
- </TouchableOpacity>
1335
- </View>
1336
- )}
1337
-
1338
18
  export default ReportChart;