Skip to content

Commit

Permalink
Various fixes to history export and QRCodeOverlay
Browse files Browse the repository at this point in the history
- Properly escape commas in CSV message field
- Set a good filename for exported CSV files
- Fix design of year selector
- Fix broken QR code layout in QRCode Overlay on iOS 16
  • Loading branch information
sisou committed Nov 25, 2022
1 parent be3cfae commit 5ffcc52
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 22 deletions.
53 changes: 45 additions & 8 deletions src/components/modals/HistoryExportModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,23 @@ export default defineComponent({
internal: [] as string[],
external: [] as string[],
};
let filename = '';
if (props.type === 'address') {
const { activeCurrency } = useAccountStore();
if (activeCurrency.value === CryptoCurrency.NIM) {
const address = useAddressStore().state.activeAddress;
if (!address) return;
nimAddresses = [address];
const addressInfo = useAddressStore().activeAddressInfo.value;
if (!addressInfo) return;
nimAddresses = [addressInfo.address];
filename = `Nimiq-Wallet-Address-Export-${addressInfo.label.replace(/\s/g, '-')}`;
} else if (activeCurrency.value === CryptoCurrency.BTC) {
btcAddresses = activeAccountInfo.value.btcAddresses;
filename = `Nimiq-Wallet-BTC-Export-${activeAccountInfo.value.label.replace(/\s/g, '-')}`;
}
} else {
nimAddresses = activeAccountInfo.value.addresses;
btcAddresses = activeAccountInfo.value.btcAddresses;
filename = `Nimiq-Wallet-Account-Export-${activeAccountInfo.value.label.replace(/\s/g, '-')}`;
}
isExporting.value = true;
Expand All @@ -87,6 +91,7 @@ export default defineComponent({
btcAddresses,
parseInt(selectedYear.value, 10),
format.value,
filename,
);
isExporting.value = false;
Expand Down Expand Up @@ -153,11 +158,43 @@ export default defineComponent({
}
}
select.nq-input {
padding: 0.75rem 1.5rem;
border-radius: 5rem;
font-size: var(--small-size);
font-weight: 600;
// select.nq-input {
// padding: 0.75rem 1.5rem;
// border-radius: 5rem;
// font-size: var(--small-size);
// font-weight: 600;
// }
select {
font-size: var(--body-size);
font-family: inherit;
font-weight: bold;
line-height: inherit;
color: inherit;
border: none;
appearance: none;
cursor: pointer;
box-shadow: inset 0 0 0 1.5px var(--text-16);
border-radius: 2.5rem;
padding: {
top: 0.625rem;
bottom: 0.875rem;
left: 2rem;
right: 3.5rem;
}
background-color: transparent;
background-image: url('../../assets/arrow-down.svg');
background-size: 1.25rem;
background-repeat: no-repeat;
background-position-x: calc(100% - 1.75rem);
background-position-y: 55%;
// &:disabled {
// opacity: .5;
// cursor: default;
// }
}
.page-footer .nq-button {
Expand Down
2 changes: 2 additions & 0 deletions src/components/modals/overlays/QrCodeOverlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export default defineComponent({
// why we use negative margins on all sides (130px = 260px / 2).
transform: scale(0.5);
margin: -130px;
height: 520px; // Must set fixed height for iOS 16 to display correctly
}
.qr-info-text {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/export/BlockpitAppFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Transaction as NimTx } from '../../stores/Transactions';
import { Transaction as BtcTx } from '../../stores/BtcTransactions';
import { Format } from './Format';
import { useAddressStore } from '../../stores/Address';
import { ExportFormat } from './TransactionExport';

/* eslint-disable class-methods-use-this */

Expand Down Expand Up @@ -34,7 +35,7 @@ export class BlockpitAppFormat extends Format {
public override transactions: (NimTx | BtcTx)[],
public override year: number,
) {
super(BlockpitAppFormat.HEADERS, nimAddresses, btcAddresses, transactions, year);
super(ExportFormat.BLOCKPIT, BlockpitAppFormat.HEADERS, nimAddresses, btcAddresses, transactions, year);

if (
this.nimAddresses.length === 1
Expand Down
36 changes: 26 additions & 10 deletions src/lib/export/Format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { Transaction as BtcTx, useBtcTransactionsStore } from '../../stores/BtcT
import { parseData } from '../DataFormatting';
import { isProxyData, ProxyType } from '../ProxyDetection';
import { useSwapsStore } from '../../stores/Swaps';
import { ExportFormat } from './TransactionExport';

/* eslint-disable class-methods-use-this */

export abstract class Format {
protected rows: string[][] = [];

constructor(
private format: ExportFormat,
private headers: string[],
public nimAddresses: string[],
public btcAddresses: { internal: string[], external: string[] },
Expand Down Expand Up @@ -47,22 +49,36 @@ export abstract class Format {
}

protected formatNimiqData(transaction: NimTx, isIncoming: boolean) {
let message = '';
if (isProxyData(transaction.data.raw, ProxyType.CASHLINK)) {
const { state: proxies$ } = useProxyStore();
const cashlinkAddress = isIncoming ? transaction.sender : transaction.recipient;
const hubCashlink = proxies$.hubCashlinks[cashlinkAddress];
if (hubCashlink && hubCashlink.message) return hubCashlink.message;
if (hubCashlink && hubCashlink.message) {
message = hubCashlink.message;
}
} else if ('hashRoot' in transaction.data) {
message = 'HTLC Creation';
} else if ('hashRoot' in transaction.proof) {
message = 'HTLC Settlement';
} else if ('creator' in transaction.proof) {
message = 'HTLC Refund';
} else {
message = parseData(transaction.data.raw);
}

// TODO: Handle swaps with proper message
if ('hashRoot' in transaction.data) return 'HTLC Creation';
if ('hashRoot' in transaction.proof) return 'HTLC Settlement';
if ('creator' in transaction.proof) return 'HTLC Refund';
// Escape message for use in CSV
if (message.includes(',')) {
// Escape any double quotes inside the message
message = message.replace(/"/g, '""');
// Then enclose the message in double quotes
message = `"${message}"`;
}

return parseData(transaction.data.raw);
return message;
}

public export() {
public export(filename?: string) {
const alreadyProcessedTransactionHashes: string[] = [];

for (const tx of this.transactions) {
Expand Down Expand Up @@ -129,7 +145,7 @@ export abstract class Format {
}
}

this.download();
this.download(filename);
}

protected abstract addRow(
Expand All @@ -138,7 +154,7 @@ export abstract class Format {
messageOverride?: string,
): void

protected download() {
protected download(filename?: string) {
const file = [
this.headers,
...this.rows,
Expand All @@ -153,7 +169,7 @@ export abstract class Format {
// Create a link to download it
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `Nimiq-Wallet-History-Export-${this.year}.csv`);
link.setAttribute('download', `${filename || 'Nimiq-Wallet-History-Export'}.${this.format}.${this.year}.csv`);
link.click();
}

Expand Down
3 changes: 2 additions & 1 deletion src/lib/export/GenericFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useFiatStore } from '../../stores/Fiat';
import { Transaction as NimTx } from '../../stores/Transactions';
import { Transaction as BtcTx } from '../../stores/BtcTransactions';
import { Format } from './Format';
import { ExportFormat } from './TransactionExport';

/* eslint-disable class-methods-use-this */

Expand Down Expand Up @@ -34,7 +35,7 @@ export class GenericFormat extends Format {
public override transactions: (NimTx | BtcTx)[],
public override year: number,
) {
super(GenericFormat.HEADERS, nimAddresses, btcAddresses, transactions, year);
super(ExportFormat.GENERIC, GenericFormat.HEADERS, nimAddresses, btcAddresses, transactions, year);

this.referenceAsset = useFiatStore().state.currency;
this.referenceDecimals = new CurrencyInfo(this.referenceAsset.toUpperCase()).decimals;
Expand Down
5 changes: 3 additions & 2 deletions src/lib/export/TransactionExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function exportTransactions(
btcAddresses: { internal: string[], external: string[] },
year: number,
format: ExportFormat,
filename?: string,
) {
const startDate = new Date();
startDate.setFullYear(year, 0, 1);
Expand Down Expand Up @@ -110,9 +111,9 @@ export async function exportTransactions(

switch (format) {
case ExportFormat.GENERIC:
new GenericFormat(nimAddresses, btcAddresses, transactions, year).export(); break;
new GenericFormat(nimAddresses, btcAddresses, transactions, year).export(filename); break;
case ExportFormat.BLOCKPIT:
new BlockpitAppFormat(nimAddresses, btcAddresses, transactions, year).export(); break;
new BlockpitAppFormat(nimAddresses, btcAddresses, transactions, year).export(filename); break;
default:
throw new Error('Unknown export format');
}
Expand Down

0 comments on commit 5ffcc52

Please sign in to comment.