aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-core/src/util/denominations.ts109
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts30
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx97
3 files changed, 138 insertions, 98 deletions
diff --git a/packages/taler-wallet-core/src/util/denominations.ts b/packages/taler-wallet-core/src/util/denominations.ts
index c05df6c6e..639f53895 100644
--- a/packages/taler-wallet-core/src/util/denominations.ts
+++ b/packages/taler-wallet-core/src/util/denominations.ts
@@ -93,93 +93,96 @@ export function createPairTimeline(
left: FeeDescription[],
right: FeeDescription[],
): FeeDescriptionPair[] {
+ //FIXME: we need to create a copy of the array because
+ //this algorithm is using splice, remove splice and
+ //remove this array duplication
+ left = [...left]
+ right = [...right]
+
//both list empty, discarded
if (left.length === 0 && right.length === 0) return [];
const pairList: FeeDescriptionPair[] = [];
- let li = 0;
- let ri = 0;
+ let li = 0; //left list index
+ let ri = 0; //right list index
while (li < left.length && ri < right.length) {
- const currentGroup =
- left[li].group < right[ri].group ? left[li].group : right[ri].group;
+ const currentGroup = Number.parseFloat(left[li].group) < Number.parseFloat(right[ri].group) ? left[li].group : right[ri].group;
+ const lgs = li; //left group start index
+ const rgs = ri; //right group start index
- let ll = 0; //left length (until next value)
- while (li + ll < left.length && left[li + ll].group === currentGroup) {
- ll++;
+ let lgl = 0; //left group length (until next value)
+ while (li + lgl < left.length && left[li + lgl].group === currentGroup) {
+ lgl++;
}
- let rl = 0; //right length (until next value)
- while (ri + rl < right.length && right[ri + rl].group === currentGroup) {
- rl++;
+ let rgl = 0; //right group length (until next value)
+ while (ri + rgl < right.length && right[ri + rgl].group === currentGroup) {
+ rgl++;
}
- const leftIsEmpty = ll === 0;
- const rightIsEmpty = rl === 0;
+ const leftGroupIsEmpty = lgl === 0;
+ const rightGroupIsEmpty = rgl === 0;
//check which start after, add gap so both list starts at the same time
// one list may be empty
- const leftStarts: AbsoluteTime = leftIsEmpty
+ const leftStartTime: AbsoluteTime = leftGroupIsEmpty
? { t_ms: "never" }
: left[li].from;
- const rightStarts: AbsoluteTime = rightIsEmpty
+ const rightStartTime: AbsoluteTime = rightGroupIsEmpty
? { t_ms: "never" }
: right[ri].from;
//first time cut is the smallest time
- let timeCut: AbsoluteTime = leftStarts;
+ let timeCut: AbsoluteTime = leftStartTime;
- if (AbsoluteTime.cmp(leftStarts, rightStarts) < 0) {
- const ends = rightIsEmpty ? left[li + ll - 1].until : right[0].from;
+ if (AbsoluteTime.cmp(leftStartTime, rightStartTime) < 0) {
+ const ends = rightGroupIsEmpty ? left[li + lgl - 1].until : right[0].from;
right.splice(ri, 0, {
- from: leftStarts,
+ from: leftStartTime,
until: ends,
group: left[li].group,
});
- rl++;
+ rgl++;
- timeCut = leftStarts;
+ timeCut = leftStartTime;
}
- if (AbsoluteTime.cmp(leftStarts, rightStarts) > 0) {
- const ends = leftIsEmpty ? right[ri + rl - 1].until : left[0].from;
+ if (AbsoluteTime.cmp(leftStartTime, rightStartTime) > 0) {
+ const ends = leftGroupIsEmpty ? right[ri + rgl - 1].until : left[0].from;
left.splice(li, 0, {
- from: rightStarts,
+ from: rightStartTime,
until: ends,
group: right[ri].group,
});
- ll++;
+ lgl++;
- timeCut = rightStarts;
+ timeCut = rightStartTime;
}
//check which ends sooner, add gap so both list ends at the same time
// here both list are non empty
- const leftEnds: AbsoluteTime = left[li + ll - 1].until;
- const rightEnds: AbsoluteTime = right[ri + rl - 1].until;
+ const leftEndTime: AbsoluteTime = left[li + lgl - 1].until;
+ const rightEndTime: AbsoluteTime = right[ri + rgl - 1].until;
- if (AbsoluteTime.cmp(leftEnds, rightEnds) > 0) {
- right.splice(ri + rl, 0, {
- from: rightEnds,
- until: leftEnds,
+ if (AbsoluteTime.cmp(leftEndTime, rightEndTime) > 0) {
+ right.splice(ri + rgl, 0, {
+ from: rightEndTime,
+ until: leftEndTime,
group: left[0].group,
});
- rl++;
+ rgl++;
}
- if (AbsoluteTime.cmp(leftEnds, rightEnds) < 0) {
- left.splice(li + ll, 0, {
- from: leftEnds,
- until: rightEnds,
+ if (AbsoluteTime.cmp(leftEndTime, rightEndTime) < 0) {
+ left.splice(li + lgl, 0, {
+ from: leftEndTime,
+ until: rightEndTime,
group: right[0].group,
});
- ll++;
+ lgl++;
}
//now both lists are non empty and (starts,ends) at the same time
- while (
- li < left.length &&
- ri < right.length &&
- left[li].group === right[ri].group
- ) {
+ while (li < (lgs + lgl) && ri < (rgs + rgl)) {
if (
AbsoluteTime.cmp(left[li].from, timeCut) !== 0 &&
AbsoluteTime.cmp(right[ri].from, timeCut) !== 0
@@ -215,22 +218,22 @@ export function createPairTimeline(
}
pairList[pairList.length - 1].until = timeCut;
- if (
- li < left.length &&
- left[li].group !== pairList[pairList.length - 1].group
- ) {
- //value changed, should break
- //this if will catch when both (left and right) change at the same time
- //if just one side changed it will catch in the while condition
- break;
- }
+ // if (
+ // (li < left.length && left[li].group !== currentGroup) ||
+ // (ri < right.length && right[ri].group !== currentGroup)
+ // ) {
+ // //value changed, should break
+ // //this if will catch when both (left and right) change at the same time
+ // //if just one side changed it will catch in the while condition
+ // break;
+ // }
}
}
//one of the list left or right can still have elements
if (li < left.length) {
let timeCut =
pairList.length > 0 &&
- pairList[pairList.length - 1].group === left[li].group
+ pairList[pairList.length - 1].group === left[li].group
? pairList[pairList.length - 1].until
: left[li].from;
while (li < left.length) {
@@ -248,7 +251,7 @@ export function createPairTimeline(
if (ri < right.length) {
let timeCut =
pairList.length > 0 &&
- pairList[pairList.length - 1].group === right[ri].group
+ pairList[pairList.length - 1].group === right[ri].group
? pairList[pairList.length - 1].until
: right[ri].from;
while (ri < right.length) {
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
index 0a66dc381..39fbb6ce2 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
@@ -38,30 +38,34 @@ export function useComponentState(
}
const [value, setValue] = useState(String(initialValue));
+ const selectedIdx = parseInt(value, 10);
+ const selectedExchange =
+ exchanges.length == 0 ? undefined : exchanges[selectedIdx];
+
+ const comparingExchanges = selectedIdx !== initialValue;
+
+ const initialExchange =
+ comparingExchanges ? exchanges[initialValue] : undefined;
+
const hook = useAsyncAsHook(async () => {
- const selectedIdx = parseInt(value, 10);
- const selectedExchange =
- exchanges.length == 0 ? undefined : exchanges[selectedIdx];
const selected = !selectedExchange
? undefined
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, {
- exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
- });
+ exchangeBaseUrl: selectedExchange.exchangeBaseUrl,
+ });
- const initialExchange =
- selectedIdx === initialValue ? undefined : exchanges[initialValue];
const original = !initialExchange
? undefined
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, {
- exchangeBaseUrl: initialExchange.exchangeBaseUrl,
- });
+ exchangeBaseUrl: initialExchange.exchangeBaseUrl,
+ });
return {
exchanges,
selected: selected?.exchange,
original: original?.exchange,
};
- }, [value]);
+ }, [selectedExchange, initialExchange]);
const [showingTos, setShowingTos] = useState<string | undefined>(undefined);
const [showingPrivacy, setShowingPrivacy] = useState<string | undefined>(
@@ -83,8 +87,7 @@ export function useComponentState(
const { selected, original } = hook.response;
- if (!selected) {
- //!selected <=> exchanges.length === 0
+ if (selectedExchange === undefined || !selected) {
return {
status: "no-exchange",
error: undefined,
@@ -118,7 +121,7 @@ export function useComponentState(
};
}
- if (!original) {
+ if (!comparingExchanges || !original) {
// !original <=> selected == original
return {
status: "ready",
@@ -147,6 +150,7 @@ export function useComponentState(
};
}
+ //this may be expensive, useMemo
const pairTimeline: DenomOperationMap<FeeDescription[]> = {
deposit: createPairTimeline(
selected.denomFees.deposit,
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
index be059630f..95ab55261 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
@@ -262,7 +262,10 @@ export function ComparingView({
<i18n.Translate>Denomination</i18n.Translate>
</th>
<th class="fee">
- <i18n.Translate>Fee</i18n.Translate>
+ <i18n.Translate>Current</i18n.Translate>
+ </th>
+ <th class="fee">
+ <i18n.Translate>Selected</i18n.Translate>
</th>
<th>
<i18n.Translate>Until</i18n.Translate>
@@ -270,7 +273,10 @@ export function ComparingView({
</tr>
</thead>
<tbody>
- <RenderFeePairByValue list={pairTimeline.deposit} />
+ <RenderFeePairByValue
+ list={pairTimeline.deposit}
+ sorting={(a, b) => Number(a) - Number(b)}
+ />
</tbody>
</FeeDescriptionTable>
<p>
@@ -292,7 +298,10 @@ export function ComparingView({
</tr>
</thead>
<tbody>
- <RenderFeePairByValue list={pairTimeline.withdraw} />
+ <RenderFeePairByValue
+ list={pairTimeline.withdraw}
+ sorting={(a, b) => Number(a) - Number(b)}
+ />
</tbody>
</FeeDescriptionTable>
<p>
@@ -314,7 +323,10 @@ export function ComparingView({
</tr>
</thead>
<tbody>
- <RenderFeePairByValue list={pairTimeline.refund} />
+ <RenderFeePairByValue
+ list={pairTimeline.refund}
+ sorting={(a, b) => Number(a) - Number(b)}
+ />
</tbody>
</FeeDescriptionTable>{" "}
<p>
@@ -336,7 +348,10 @@ export function ComparingView({
</tr>
</thead>
<tbody>
- <RenderFeePairByValue list={pairTimeline.refresh} />
+ <RenderFeePairByValue
+ list={pairTimeline.refresh}
+ sorting={(a, b) => Number(a) - Number(b)}
+ />
</tbody>
</FeeDescriptionTable>{" "}
</section>
@@ -689,7 +704,7 @@ function FeePairRowsGroup({ infos }: { infos: FeeDescriptionPair[] }): VNode {
<td class="icon">
{hasMoreInfo && main ? (
<SvgIcon
- title="Select this contact"
+ title="Expand"
dangerouslySetInnerHTML={{ __html: arrowDown }}
color="currentColor"
transform={expanded ? "" : "rotate(-90deg)"}
@@ -708,7 +723,7 @@ function FeePairRowsGroup({ infos }: { infos: FeeDescriptionPair[] }): VNode {
<td class="fee"> --- </td>
)}
<td class="expiration">
- <Time timestamp={info.until} format="dd-MMM-yyyy" />
+ <Time timestamp={info.until} format="dd-MMM-yyyy HH:mm:ss" />
</td>
</tr>
);
@@ -722,35 +737,53 @@ function FeePairRowsGroup({ infos }: { infos: FeeDescriptionPair[] }): VNode {
* @param param0
* @returns
*/
-function RenderFeePairByValue({ list }: { list: FeeDescriptionPair[] }): VNode {
- return (
- <Fragment>
- {
- list.reduce(
- (prev, info, idx) => {
- const next = idx >= list.length - 1 ? undefined : list[idx + 1];
+function RenderFeePairByValue({
+ list,
+ sorting,
+}: {
+ list: FeeDescriptionPair[];
+ sorting?: (a: string, b: string) => number;
+}): VNode {
+ const grouped = list.reduce((prev, cur) => {
+ if (!prev[cur.group]) {
+ prev[cur.group] = [];
+ }
+ prev[cur.group].push(cur);
+ return prev;
+ }, {} as Record<string, FeeDescriptionPair[]>);
+ const p = Object.keys(grouped)
+ .sort(sorting)
+ .map((i, idx) => <FeePairRowsGroup key={idx} infos={grouped[i]} />);
+ return <Fragment>{p}</Fragment>;
- const nextIsMoreInfo =
- next !== undefined && next.group === info.group;
+ // return (
+ // <Fragment>
+ // {
+ // list.reduce(
+ // (prev, info, idx) => {
+ // const next = idx >= list.length - 1 ? undefined : list[idx + 1];
- prev.rows.push(info);
+ // const nextIsMoreInfo =
+ // next !== undefined && next.group === info.group;
- if (nextIsMoreInfo) {
- return prev;
- }
+ // prev.rows.push(info);
- // prev.rows = [];
- prev.views.push(<FeePairRowsGroup infos={prev.rows} />);
- return prev;
- },
- { rows: [], views: [] } as {
- rows: FeeDescriptionPair[];
- views: h.JSX.Element[];
- },
- ).views
- }
- </Fragment>
- );
+ // if (nextIsMoreInfo) {
+ // return prev;
+ // }
+
+ // // prev.rows = [];
+ // prev.views.push(<FeePairRowsGroup infos={prev.rows} />);
+ // return prev;
+ // },
+ // { rows: [], views: [] } as {
+ // rows: FeeDescriptionPair[];
+ // views: h.JSX.Element[];
+ // },
+ // ).views
+ // }
+ // </Fragment>
+ // );
}
/**
*