diff options
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> + // ); } /** * |