Skip to content

Commit fde74a2

Browse files
committed
Refactored CSV export to reuse utils functions across ActivityExportOptions and ActivityToCsv
1 parent 1532d8f commit fde74a2

File tree

3 files changed

+130
-217
lines changed

3 files changed

+130
-217
lines changed

utils/ActivityCsvUtils.ts

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import RNFS from 'react-native-fs';
2+
import { Platform } from 'react-native';
3+
4+
// Keys for CSV export.
5+
export const CSV_KEYS = {
6+
invoice: [
7+
{ label: 'Amount Paid (sat)', value: 'getAmount' },
8+
{ label: 'Payment Request', value: 'getPaymentRequest' },
9+
{ label: 'Payment Hash', value: 'getRHash' },
10+
{ label: 'Memo', value: 'getMemo' },
11+
{ label: 'Note', value: 'getNote' },
12+
{ label: 'Creation Date', value: 'getCreationDate' },
13+
{ label: 'Expiry', value: 'formattedTimeUntilExpiry' }
14+
],
15+
payment: [
16+
{ label: 'Destination', value: 'getDestination' },
17+
{ label: 'Payment Request', value: 'getPaymentRequest' },
18+
{ label: 'Payment Hash', value: 'paymentHash' },
19+
{ label: 'Amount Paid (sat)', value: 'getAmount' },
20+
{ label: 'Memo', value: 'getMemo' },
21+
{ label: 'Note', value: 'getNote' },
22+
{ label: 'Creation Date', value: 'getDate' }
23+
],
24+
transaction: [
25+
{ label: 'Transaction Hash', value: 'tx' },
26+
{ label: 'Amount (sat)', value: 'getAmount' },
27+
{ label: 'Total Fees (sat)', value: 'getFee' },
28+
{ label: 'Note', value: 'getNote' },
29+
{ label: 'Timestamp', value: 'getDate' }
30+
]
31+
};
32+
33+
// Generates a formatted timestamp string for file naming.
34+
export const getFormattedDateTime = (): string => {
35+
const now = new Date();
36+
const year = now.getFullYear();
37+
const month = (now.getMonth() + 1).toString().padStart(2, '0');
38+
const day = now.getDate().toString().padStart(2, '0');
39+
const hours = now.getHours().toString().padStart(2, '0');
40+
const minutes = now.getMinutes().toString().padStart(2, '0');
41+
const seconds = now.getSeconds().toString().padStart(2, '0');
42+
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
43+
};
44+
45+
// Converts activity data into a CSV string.
46+
export const convertActivityToCsv = async (
47+
data: Array<any>,
48+
keysToInclude: Array<{ label: string; value: string }>
49+
): Promise<string> => {
50+
if (!data || data.length === 0) return '';
51+
52+
try {
53+
const header = keysToInclude.map((field) => field.label).join(',');
54+
const rows = data
55+
.map((item) =>
56+
keysToInclude
57+
.map((field) => `"${item[field.value] || ''}"`)
58+
.join(',')
59+
)
60+
.join('\n');
61+
62+
return `${header}\n${rows}`;
63+
} catch (err) {
64+
console.error(err);
65+
return '';
66+
}
67+
};
68+
69+
//Saves CSV file to the device.
70+
export const saveCsvFile = async (fileName: string, csvData: string) => {
71+
try {
72+
const filePath =
73+
Platform.OS === 'android'
74+
? `${RNFS.DownloadDirectoryPath}/${fileName}`
75+
: `${RNFS.DocumentDirectoryPath}/${fileName}`;
76+
77+
console.log(`Saving file to: ${filePath}`);
78+
await RNFS.writeFile(filePath, csvData, 'utf8');
79+
} catch (err) {
80+
console.error('Failed to save CSV file:', err);
81+
throw err;
82+
}
83+
};

views/Activity/ActivityToCsv.tsx

+31-110
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import React, { useState } from 'react';
2-
import { StyleSheet, View, Platform, Alert, Modal } from 'react-native';
3-
import RNFS from 'react-native-fs';
4-
import Button from '../../components/Button';
5-
import TextInput from '../../components/TextInput';
6-
import { localeString } from '../../utils/LocaleUtils';
7-
import { themeColor } from '../../utils/ThemeUtils';
2+
import { StyleSheet, View, Alert, Modal } from 'react-native';
3+
84
import Invoice from '../../models/Invoice';
95
import Payment from '../../models/Payment';
106
import Transaction from '../../models/Transaction';
7+
8+
import Button from '../../components/Button';
9+
import TextInput from '../../components/TextInput';
1110
import LoadingIndicator from '../../components/LoadingIndicator';
1211

12+
import { localeString } from '../../utils/LocaleUtils';
13+
import { themeColor } from '../../utils/ThemeUtils';
14+
import {
15+
getFormattedDateTime,
16+
convertActivityToCsv,
17+
saveCsvFile,
18+
CSV_KEYS
19+
} from '../../utils/ActivityCsvUtils';
20+
1321
interface ActivityProps {
1422
filteredActivity: Array<Invoice | Payment | Transaction>;
1523
isVisible: boolean;
@@ -29,87 +37,22 @@ const ActivityToCsv: React.FC<ActivityProps> = ({
2937
closeModal();
3038
};
3139

32-
const getFormattedDateTime = () => {
33-
const now = new Date();
34-
const year = now.getFullYear();
35-
const month = (now.getMonth() + 1).toString().padStart(2, '0');
36-
const day = now.getDate().toString().padStart(2, '0');
37-
const hours = now.getHours().toString().padStart(2, '0');
38-
const minutes = now.getMinutes().toString().padStart(2, '0');
39-
const seconds = now.getSeconds().toString().padStart(2, '0');
40-
41-
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
42-
};
43-
44-
const convertActivityToCsv = async (
45-
data: Array<Invoice | Payment | Transaction>,
46-
keysToInclude: Array<any>
47-
) => {
48-
if (!data || data.length === 0) {
49-
return '';
50-
}
51-
52-
try {
53-
const header = keysToInclude.map((field) => field.label).join(',');
54-
const rows = data
55-
?.map((item: any) =>
56-
keysToInclude
57-
.map((field) => `"${item[field.value]}"` || '')
58-
.join(',')
59-
)
60-
.join('\n');
61-
62-
return `${header}\n${rows}`;
63-
} catch (err) {
64-
console.error(err);
65-
return '';
66-
}
67-
};
68-
6940
const downloadCsv = async () => {
7041
setIsLoading(true);
7142
setTimeout(async () => {
72-
const invoiceKeys = [
73-
{ label: 'Amount Paid (sat)', value: 'getAmount' },
74-
{ label: 'Payment Request', value: 'getPaymentRequest' },
75-
{ label: 'Payment Hash', value: 'getRHash' },
76-
{ label: 'Memo', value: 'getMemo' },
77-
{ label: 'Note', value: 'getNote' },
78-
{ label: 'Creation Date', value: 'getCreationDate' },
79-
{ label: 'Expiry', value: 'formattedTimeUntilExpiry' }
80-
];
81-
82-
const paymentKeys = [
83-
{ label: 'Destination', value: 'getDestination' },
84-
{ label: 'Payment Request', value: 'getPaymentRequest' },
85-
{ label: 'Payment Hash', value: 'paymentHash' },
86-
{ label: 'Amount Paid (sat)', value: 'getAmount' },
87-
{ label: 'Memo', value: 'getMemo' },
88-
{ label: 'Note', value: 'getNote' },
89-
{ label: 'Creation Date', value: 'getDate' }
90-
];
91-
92-
const transactionKeys = [
93-
{ label: 'Transaction Hash', value: 'tx' },
94-
{ label: 'Amount (sat)', value: 'getAmount' },
95-
{ label: 'Total Fees (sat)', value: 'getFee' },
96-
{ label: 'Note', value: 'getNote' },
97-
{ label: 'Timestamp', value: 'getDate' }
98-
];
99-
10043
const invoiceCsv = await convertActivityToCsv(
10144
filteredActivity.filter((item: any) => item instanceof Invoice),
102-
invoiceKeys
45+
CSV_KEYS.invoice
10346
);
10447
const paymentCsv = await convertActivityToCsv(
10548
filteredActivity.filter((item: any) => item instanceof Payment),
106-
paymentKeys
49+
CSV_KEYS.payment
10750
);
10851
const transactionCsv = await convertActivityToCsv(
10952
filteredActivity.filter(
11053
(item: any) => item instanceof Transaction
11154
),
112-
transactionKeys
55+
CSV_KEYS.transaction
11356
);
11457

11558
if (!invoiceCsv && !paymentCsv && !transactionCsv) {
@@ -120,43 +63,21 @@ const ActivityToCsv: React.FC<ActivityProps> = ({
12063
try {
12164
const dateTime = getFormattedDateTime();
12265
const baseFileName = customFileName || `zeus_${dateTime}`;
123-
const invoiceFileName = `${baseFileName}_ln_invoices.csv`;
124-
const paymentFileName = `${baseFileName}_ln_payments.csv`;
125-
const transactionFileName = `${baseFileName}_onchain.csv`;
126-
127-
const invoiceFilePath =
128-
Platform.OS === 'android'
129-
? `${RNFS.DownloadDirectoryPath}/${invoiceFileName}`
130-
: `${RNFS.DocumentDirectoryPath}/${invoiceFileName}`;
131-
132-
const paymentFilePath =
133-
Platform.OS === 'android'
134-
? `${RNFS.DownloadDirectoryPath}/${paymentFileName}`
135-
: `${RNFS.DocumentDirectoryPath}/${paymentFileName}`;
136-
137-
const transactionFilePath =
138-
Platform.OS === 'android'
139-
? `${RNFS.DownloadDirectoryPath}/${transactionFileName}`
140-
: `${RNFS.DocumentDirectoryPath}/${transactionFileName}`;
141-
142-
if (invoiceCsv) {
143-
console.log('invoiceFilePath', invoiceFilePath);
144-
await RNFS.writeFile(invoiceFilePath, invoiceCsv, 'utf8');
145-
}
146-
147-
if (paymentCsv) {
148-
console.log('paymentFilePath', paymentFilePath);
149-
await RNFS.writeFile(paymentFilePath, paymentCsv, 'utf8');
150-
}
151-
152-
if (transactionCsv) {
153-
console.log('transactionFilePath', transactionFilePath);
154-
await RNFS.writeFile(
155-
transactionFilePath,
156-
transactionCsv,
157-
'utf8'
66+
if (invoiceCsv)
67+
await saveCsvFile(
68+
`${baseFileName}_ln_invoices.csv`,
69+
invoiceCsv
70+
);
71+
if (paymentCsv)
72+
await saveCsvFile(
73+
`${baseFileName}_ln_payments.csv`,
74+
paymentCsv
75+
);
76+
if (transactionCsv)
77+
await saveCsvFile(
78+
`${baseFileName}_onchain.csv`,
79+
transactionCsv
15880
);
159-
}
16081

16182
Alert.alert(
16283
localeString('general.success'),

0 commit comments

Comments
 (0)