Fully fleshed out download client-side experience for downloading txns. Now we can actually implement the downloading part
This commit is contained in:
parent
d635ae0cbf
commit
3f884f0923
|
@ -1,111 +0,0 @@
|
||||||
import React from 'jsx-dom'; // necessary for react to work
|
|
||||||
import { Event, ClientEvents } from './events';
|
|
||||||
import * as background from './background';
|
|
||||||
import { Account } from '../landsbankinn/models';
|
|
||||||
import $ from 'cash-dom';
|
|
||||||
|
|
||||||
interface AccountListProps {
|
|
||||||
accounts: Array<Account>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatAccountNumber = (accountNumber: string) => accountNumber.substring(0, 4) + '-' + accountNumber.substring(4, 6) + '-' + accountNumber.substring(6, 12);
|
|
||||||
|
|
||||||
function AccountList(props: AccountListProps) {
|
|
||||||
const boxStyle = { display: 'inline-block', width: "100%", cursor: 'pointer' };
|
|
||||||
|
|
||||||
const selectAllHandler = () => {
|
|
||||||
$(`#check-all`).prop('checked', !$('#check-all').prop('checked'));
|
|
||||||
const checked = $('#check-all').prop('checked');
|
|
||||||
$('#account-export-list input[type="checkbox"]').prop('checked', checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectAccountHandler = (accountNumber: string) => () =>
|
|
||||||
$(`#export-${accountNumber}`)
|
|
||||||
.prop('checked', !$(`#export-${accountNumber}`).prop('checked'));
|
|
||||||
|
|
||||||
const accountList = props.accounts.map(acct =>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input id={`export-${acct.accountNumber}`} type="checkbox" />
|
|
||||||
</td>
|
|
||||||
<td onClick={selectAccountHandler(acct.accountNumber)}>
|
|
||||||
<span style={boxStyle}>
|
|
||||||
{formatAccountNumber(acct.accountNumber)}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td onClick={selectAccountHandler(acct.accountNumber)}>
|
|
||||||
<span style={boxStyle}>
|
|
||||||
{acct.name}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr >
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id="account-export-list">
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="colgroup">Select</th>
|
|
||||||
<th scope="colgroup">Account Number</th>
|
|
||||||
<th scope="colgroup">Account Name</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input id="check-all" type="checkbox" onClick={selectAllHandler} />
|
|
||||||
</td>
|
|
||||||
<td onClick={selectAllHandler}>
|
|
||||||
<span style={boxStyle}>Select All</span>
|
|
||||||
</td>
|
|
||||||
<td onClick={selectAllHandler}>
|
|
||||||
<span style={boxStyle}>
|
|
||||||
N/A (Selects all accounts below)
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{accountList}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div >
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ExportDiv(props: AccountListProps) {
|
|
||||||
return (
|
|
||||||
<div id="account-export" class="content-box fill shadow ui-form" >
|
|
||||||
<h2>Download Transaction Statements</h2>
|
|
||||||
<p>
|
|
||||||
Here, you can export statements from one or more of your accounts
|
|
||||||
over a specified date range.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<label htmlFor="export-date-from">Date From</label>
|
|
||||||
<input id="export-date-from" type="date" />
|
|
||||||
|
|
||||||
<label htmlFor="export-date-to">Date From</label>
|
|
||||||
<input id="export-date-to" type="date" />
|
|
||||||
|
|
||||||
<div class="row-column">
|
|
||||||
<div class="column-span2 column-span2--base">
|
|
||||||
<AccountList accounts={props.accounts} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', async () => {
|
|
||||||
ClientEvents.on(Event.StatePopulated, async () => {
|
|
||||||
const response = await background.getAccounts();
|
|
||||||
|
|
||||||
if (response.error == null) {
|
|
||||||
const exportDiv = <ExportDiv accounts={response.accounts} />;
|
|
||||||
const contentDiv = document.querySelector(
|
|
||||||
'div[class="table-data content-box fill shadow"]'
|
|
||||||
);
|
|
||||||
contentDiv?.prepend(exportDiv);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
import React, { FormEventHandler } from 'jsx-dom'; // necessary for react to work
|
||||||
|
import { Account } from '../../landsbankinn/models';
|
||||||
|
import $ from 'cash-dom';
|
||||||
|
|
||||||
|
interface AccountListProps {
|
||||||
|
accounts: Array<Account>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatAccountNumber = (accountNumber: string) =>
|
||||||
|
accountNumber.substring(0, 4) + '-' +
|
||||||
|
accountNumber.substring(4, 6) + '-' +
|
||||||
|
accountNumber.substring(6, 12);
|
||||||
|
|
||||||
|
//getValues extracts the account numbers and date range for
|
||||||
|
//transactions to download. Basically the "submit button."
|
||||||
|
//TODO why not use an actual form...
|
||||||
|
const getValues = (exportDiv: HTMLElement): Array<string> =>
|
||||||
|
//@ts-expect-error
|
||||||
|
$(`#${exportDiv.id} input[type="checkbox"]`)
|
||||||
|
.filter('[data-checkbox-type="account"]:checked')
|
||||||
|
//@ts-expect-error
|
||||||
|
.map((_, el) => (el as HTMLInputElement).name).get();
|
||||||
|
|
||||||
|
const SelectAllRow = () => {
|
||||||
|
const boxStyle = { display: 'inline-block', width: "100%", cursor: 'pointer' };
|
||||||
|
|
||||||
|
const selectAllHandler = (e: MouseEvent) => {
|
||||||
|
const currentlyChecked = $('#check-all').prop('checked');
|
||||||
|
|
||||||
|
//@ts-expect-error
|
||||||
|
if ($(e.currentTarget).is($('#check-all')) == false) {
|
||||||
|
//The checkbox can toggle itself, by itself. Only toggle
|
||||||
|
//from other clicks
|
||||||
|
$(`#check-all`).prop('checked', !currentlyChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checked = $('#check-all').prop('checked');
|
||||||
|
$('#account-export-list input[type="checkbox"]').prop('checked', checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input id="check-all" type="checkbox" data-checkbox-type="select-all"
|
||||||
|
onClick={selectAllHandler} />
|
||||||
|
</td>
|
||||||
|
<td onClick={selectAllHandler}>
|
||||||
|
<span style={boxStyle}>Select All</span>
|
||||||
|
</td>
|
||||||
|
<td onClick={selectAllHandler}>
|
||||||
|
<span style={boxStyle}>
|
||||||
|
N/A (Selects all accounts below)
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccountRow = (props: { accountNumber: string; name: string; }) => {
|
||||||
|
const boxStyle = { display: 'inline-block', width: "100%", cursor: 'pointer' };
|
||||||
|
|
||||||
|
const selectAccountHandler = (accountNumber: string) => () =>
|
||||||
|
$(`#export-${accountNumber}`)
|
||||||
|
.prop('checked', !$(`#export-${accountNumber}`).prop('checked'));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input id={`export-${props.accountNumber}`}
|
||||||
|
data-checkbox-type="account"
|
||||||
|
type="checkbox" name={props.accountNumber} />
|
||||||
|
</td>
|
||||||
|
<td onClick={selectAccountHandler(props.accountNumber)}>
|
||||||
|
<span style={boxStyle}>
|
||||||
|
{formatAccountNumber(props.accountNumber)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td onClick={selectAccountHandler(props.accountNumber)}>
|
||||||
|
<span style={boxStyle}>
|
||||||
|
{props.name}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccountList = (props: AccountListProps) => {
|
||||||
|
const accountList = props.accounts.map(acct =>
|
||||||
|
<AccountRow accountNumber={acct.accountNumber} name={acct.name} />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="account-export-list">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="colgroup">Select</th>
|
||||||
|
<th scope="colgroup">Account Number</th>
|
||||||
|
<th scope="colgroup">Account Name</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<SelectAllRow />
|
||||||
|
{accountList}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const datePickerID = (label: string) => `export-date-${label}`;
|
||||||
|
|
||||||
|
const DatePicker = (props: { label: string; }) => (
|
||||||
|
<div style={{ display: 'inline-block' }}>
|
||||||
|
<label htmlFor={datePickerID(props.label)}>{props.label}</label>
|
||||||
|
<input id={datePickerID(props.label)} type="date" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const DownloadButton = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'inline-block' }}>
|
||||||
|
<button>Download Transactions</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExportDivProps {
|
||||||
|
fromLabel: string;
|
||||||
|
toLabel: string;
|
||||||
|
accounts: Account[];
|
||||||
|
onDownload: (accountNumbers: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ExportDiv = (props: ExportDivProps) => {
|
||||||
|
const submitHandler = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const accountNumbers = getValues($('#account-export').get(0)!);
|
||||||
|
props.onDownload(accountNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="account-export" class="content-box fill shadow ui-form" >
|
||||||
|
<h2>Download Transaction Statements</h2>
|
||||||
|
<p>
|
||||||
|
Here, you can export statements from one or more of your accounts
|
||||||
|
over a specified date range.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form id="export-transaction-form" onSubmit={submitHandler}>
|
||||||
|
<div id="export-date-pickers">
|
||||||
|
<DatePicker label={props.fromLabel} />
|
||||||
|
<DatePicker label={props.toLabel} />
|
||||||
|
<DownloadButton />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row-column">
|
||||||
|
<div class="column-span2 column-span2--base">
|
||||||
|
<AccountList accounts={props.accounts} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React from 'jsx-dom'; // necessary for react to work
|
||||||
|
import { Event, ClientEvents } from '../events';
|
||||||
|
import * as background from '../background';
|
||||||
|
import { ExportDiv } from './components';
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
ClientEvents.on(Event.StatePopulated, async () => {
|
||||||
|
const response = await background.getAccounts();
|
||||||
|
|
||||||
|
const downloadHandler = (accountNumbers: string[]) => {
|
||||||
|
console.log('downloading txns for', accountNumbers);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (response.error == null) {
|
||||||
|
const exportDiv = (
|
||||||
|
<ExportDiv accounts={response.accounts}
|
||||||
|
fromLabel="From" toLabel="To" onDownload={downloadHandler} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const contentDiv = document.querySelector(
|
||||||
|
'div[class="table-data content-box fill shadow"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
contentDiv?.prepend(exportDiv);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -22,7 +22,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"matches": ["https://netbanki.landsbankinn.is/Ebli/Statements/ClientSummary.aspx"],
|
"matches": ["https://netbanki.landsbankinn.is/Ebli/Statements/ClientSummary.aspx"],
|
||||||
"js": ["content-scripts/statement-page.tsx"],
|
"js": ["content-scripts/statement-page/index.tsx"],
|
||||||
"run_at": "document_start"
|
"run_at": "document_start"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue