summaryrefslogtreecommitdiff
path: root/packages/frontend/src/paths/instance/orders/details
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/paths/instance/orders/details')
-rw-r--r--packages/frontend/src/paths/instance/orders/details/DetailPage.tsx171
-rw-r--r--packages/frontend/src/paths/instance/orders/details/Timeline.tsx5
2 files changed, 96 insertions, 80 deletions
diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
index be05b43..9f148b6 100644
--- a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
+++ b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
@@ -19,6 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
+import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { format } from "date-fns";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
@@ -29,7 +30,7 @@ import { InputDate } from "../../../../components/form/InputDate";
import { InputDuration } from "../../../../components/form/InputDuration";
import { InputGroup } from "../../../../components/form/InputGroup";
import { InputLocation } from "../../../../components/form/InputLocation";
-import { NotificationCard } from "../../../../components/menu";
+import { TextField } from "../../../../components/form/TextField";
import { ProductList } from "../../../../components/product/ProductList";
import { MerchantBackend } from "../../../../declaration";
import { Translate, useTranslator } from "../../../../i18n";
@@ -52,6 +53,35 @@ type Unpaid = MerchantBackend.Orders.CheckPaymentUnpaidResponse
type Claimed = MerchantBackend.Orders.CheckPaymentClaimedResponse
+function ContractTerms({ value }: { value: CT }) {
+ const i18n = useTranslator()
+
+ return <InputGroup name="contract_terms" label={i18n`Contract Terms`}>
+ <FormProvider<CT> object={value} valueHandler={null} >
+ <Input<CT> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} />
+ <InputCurrency<CT> readonly name="amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} />
+ {value.fulfillment_url &&
+ <Input<CT> readonly name="fulfillment_url" label={i18n`Fulfillment URL`} tooltip={i18n`URL for this purchase`} />
+ }
+ <Input<CT> readonly name="max_fee" label={i18n`Max fee`} tooltip={i18n`maximum total deposit fee accepted by the merchant for this contract`} />
+ <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire fee`} tooltip={i18n`maximum wire fee accepted by the merchant`} />
+ <Input<CT> readonly name="wire_fee_amortization" label={i18n`Wire fee amortization`} tooltip={i18n`over how many customer transactions does the merchant expect to amortize wire fees on average`} />
+ <InputDate<CT> readonly name="timestamp" label={i18n`Created at`} tooltip={i18n`time when this contract was generated`} />
+ <InputDate<CT> readonly name="refund_deadline" label={i18n`Refund deadline`} tooltip={i18n`after this deadline has passed no refunds will be accepted`} />
+ <InputDate<CT> readonly name="pay_deadline" label={i18n`Payment deadline`} tooltip={i18n`after this deadline, the merchant won't accept payments for the contract`} />
+ <InputDate<CT> readonly name="wire_transfer_deadline" label={i18n`Wire transfer deadline`} tooltip={i18n`transfer deadline for the exchange`} />
+ <InputDate<CT> readonly name="delivery_date" label={i18n`Delivery date`} tooltip={i18n`time indicating when the order should be delivered`} />
+ {value.delivery_date &&
+ <InputGroup name="delivery_location" label={i18n`Location`} tooltip={i18n`where the order will be delivered`} >
+ <InputLocation name="payments.delivery_location" />
+ </InputGroup>
+ }
+ <InputDuration<CT> readonly name="auto_refund" label={i18n`Auto-refund delay`} tooltip={i18n`how long the wallet should try to get an automatic refund for the purchase`} />
+ <Input<CT> readonly name="extra" label={i18n`Extra info`} tooltip={i18n`extra data that is only interpreted by the merchant frontend`} />
+ </FormProvider>
+ </InputGroup>
+}
+
function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders.CheckPaymentClaimedResponse }) {
const events: Event[] = []
events.push({
@@ -126,11 +156,8 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders.
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
- // maxWidth: '100%',
}}>
- {/* <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a> */}
- <p><Translate>pay at</Translate>: <b>missing value, there is no order_status_url</b></p>
- <p><Translate>created at</Translate>: {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
+ <p><b><Translate>claimed at</Translate>:</b> {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
</div>
</div>
</div>
@@ -155,18 +182,12 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders.
</div>
</section>
- {order.contract_terms.products.length > 0 &&
- <section class="section">
- <div class="columns">
- <div class="column is-12" >
- <div class="title"><Translate>Product list</Translate></div>
- <ProductList list={order.contract_terms.products} />
- </div>
- <div class="column" />
- </div>
- </section>
- }
+ {order.contract_terms.products.length ? <Fragment>
+ <div class="title"><Translate>Product list</Translate></div>
+ <ProductList list={order.contract_terms.products} />
+ </Fragment> : undefined}
+ {value.contract_terms && <ContractTerms value={value.contract_terms} />}
</div>
<div class="column" />
</div>
@@ -207,19 +228,43 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend.
type: 'refund',
})
})
- order.wire_details.forEach(e => {
- events.push({
- when: new Date(e.execution_time.t_ms),
- description: `wired`,
- type: 'wired',
- })
- })
- if (order.contract_terms.wire_transfer_deadline.t_ms !== 'never' &&
- order.contract_terms.wire_transfer_deadline.t_ms < new Date().getTime()) events.push({
- when: new Date(order.contract_terms.wire_transfer_deadline.t_ms - 1000 * 10),
- description: `wired (faked)`,
- type: 'wired',
- })
+ if (order.wire_details && order.wire_details.length) {
+ if (order.wire_details.length > 1) {
+ let last: MerchantBackend.Orders.TransactionWireTransfer | null = null
+ let first: MerchantBackend.Orders.TransactionWireTransfer | null = null
+ let total: AmountJson | null = null
+
+ order.wire_details.forEach(w => {
+ if (last === null || last.execution_time.t_ms < w.execution_time.t_ms) {
+ last = w
+ }
+ if (first === null || first.execution_time.t_ms > w.execution_time.t_ms) {
+ first = w
+ }
+ total = total === null ? Amounts.parseOrThrow(w.amount) : Amounts.add(total, Amounts.parseOrThrow(w.amount)).amount
+ })
+ events.push({
+ when: new Date(last!.execution_time.t_ms),
+ description: `wired ${Amounts.stringify(total!)}`,
+ type: 'wired-range',
+ })
+ events.push({
+ when: new Date(first!.execution_time.t_ms),
+ description: `wire transfer started...`,
+ type: 'wired-range',
+ })
+ } else {
+ order.wire_details.forEach(e => {
+ events.push({
+ when: new Date(e.execution_time.t_ms),
+ description: `wired ${e.amount}`,
+ type: 'wired',
+ })
+ })
+
+ }
+
+ }
const [value, valueHandler] = useState<Partial<Paid>>(order)
@@ -261,10 +306,9 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend.
<div class="level-item">
<h1 class="title">
<div class="buttons">
- {refundable && <button class="button is-danger" onClick={() => onRefund(id)}><Translate>refund</Translate></button>}
- <button class="button is-info" onClick={() => {
- if (order.contract_terms.fulfillment_url) copyToClipboard(order.contract_terms.fulfillment_url)
- }}><Translate>copy url</Translate></button>
+ <span class="has-tooltip-left" data-tooltip={refundable ? i18n`refund order`: i18n`not refundable`}>
+ <button class="button is-danger" disabled={!refundable} onClick={() => onRefund(id)}><Translate>refund</Translate></button>
+ </span>
</div>
</h1>
</div>
@@ -301,53 +345,23 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend.
<InputCurrency<Paid> name="deposit_total" readonly label={i18n`Deposit total`} />
{order.refunded && <InputCurrency<Paid> name="refund_amount" readonly label={i18n`Refunded amount`} />}
<Input<Paid> name="order_status" readonly label={i18n`Order status`} />
- {order.order_status_url && <Input<Paid> name="order_status_url" readonly label={i18n`Status URL`} />}
+ <TextField<Paid> name="order_status_url" label={i18n`Status URL`} >
+ <a target="_blank" href={order.order_status_url}>
+ {order.order_status_url}
+ </a>
+ </TextField>
</FormProvider>
</div>
</div>
</section>
- {value.contract_terms && <section class="section">
- <div class="columns">
- <div class="column is-12" >
- <div class="title"><Translate>Contract Terms</Translate></div>
- <FormProvider<CT> object={value.contract_terms} valueHandler={null} >
- <Input<CT> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} />
- <InputCurrency<CT> readonly name="amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} />
- {value.contract_terms.fulfillment_url &&
- <Input<CT> readonly name="fulfillment_url" label={i18n`Fulfillment URL`} tooltip={i18n`URL for this purchase`} />
- }
- <Input<CT> readonly name="max_fee" label={i18n`Max fee`} tooltip={i18n`maximum total deposit fee accepted by the merchant for this contract`} />
- <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire fee`} tooltip={i18n`maximum wire fee accepted by the merchant`} />
- <Input<CT> readonly name="wire_fee_amortization" label={i18n`Wire fee amortization`} tooltip={i18n`over how many customer transactions does the merchant expect to amortize wire fees on average`} />
- <InputDate<CT> readonly name="timestamp" label={i18n`Created at`} tooltip={i18n`time when this contract was generated`} />
- <InputDate<CT> readonly name="refund_deadline" label={i18n`Refund deadline`} tooltip={i18n`after this deadline has passed no refunds will be accepted`} />
- <InputDate<CT> readonly name="pay_deadline" label={i18n`Payment deadline`} tooltip={i18n`after this deadline, the merchant won't accept payments for the contract`} />
- <InputDate<CT> readonly name="wire_transfer_deadline" label={i18n`Wire transfer deadline`} tooltip={i18n`transfer deadline for the exchange`} />
- <InputDate<CT> readonly name="delivery_date" label={i18n`Delivery date`} tooltip={i18n`time indicating when the order should be delivered`} />
- {value.contract_terms.delivery_date &&
- <InputGroup name="delivery_location" label={i18n`Location`} tooltip={i18n`where the order will be delivered`} >
- <InputLocation name="payments.delivery_location" />
- </InputGroup>
- }
- <InputDuration<CT> readonly name="auto_refund" label={i18n`Auto-refund delay`} tooltip={i18n`how long the wallet should try to get an automatic refund for the purchase`} />
- <Input<CT> readonly name="extra" label={i18n`Extra info`} tooltip={i18n`extra data that is only interpreted by the merchant frontend`} />
- </FormProvider>
- </div>
- <div class="column" />
- </div>
- </section>}
- {order.contract_terms.products.length ? <section class="section">
- <div class="columns">
- <div class="column is-12" >
- <div class="title"><Translate>Product list</Translate></div>
- <ProductList list={order.contract_terms.products} />
- </div>
- <div class="column" />
- </div>
- </section> : undefined}
+ {order.contract_terms.products.length ? <Fragment>
+ <div class="title"><Translate>Product list</Translate></div>
+ <ProductList list={order.contract_terms.products} />
+ </Fragment> : undefined}
+ {value.contract_terms && <ContractTerms value={value.contract_terms} />}
</div>
<div class="column" />
</div>
@@ -380,10 +394,9 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
- // maxWidth: '100%',
}}>
- <p><Translate>pay at</Translate>: <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p>
- <p><Translate>created at</Translate>: <b>missing value, there is no contract term yet</b></p>
+ <p><b><Translate>pay at</Translate>:</b> <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p>
+ <p><b><Translate>created at</Translate>:</b> {format(new Date(order.creation_time.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
</div>
</div>
</div>
@@ -394,8 +407,10 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C
<section class="section is-main-section">
<div class="columns">
<div class="column" />
- <div class="column is-6">
+ <div class="column is-four-fifths">
<FormProvider<Unpaid> object={value} valueHandler={valueHandler} >
+ <Input<Unpaid> readonly name="summary" label={i18n`Summary`} tooltip={i18n`human-readable description of the whole purchase`} />
+ <InputCurrency<Unpaid> readonly name="total_amount" label={i18n`Amount`} tooltip={i18n`total price for the transaction`} />
<Input<Unpaid> name="order_status" readonly label={i18n`Order status`} />
<Input<Unpaid> name="order_status_url" readonly label={i18n`Order status URL`} />
<Input<Unpaid> name="taler_pay_uri" readonly label={i18n`Payment URI`} />
@@ -432,7 +447,7 @@ export function DetailPage({ id, selected, onRefund, onBack }: Props): VNode {
/>}
<div class="columns">
<div class="column" />
- <div class="column is-two-thirds">
+ <div class="column is-four-fifths">
<div class="buttons is-right mt-5">
<button class="button" onClick={onBack}><Translate>Back</Translate></button>
</div>
diff --git a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
index d4f17c4..16adbcb 100644
--- a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
+++ b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
@@ -47,7 +47,7 @@ export function Timeline({ events:e }: Props) {
}
})
return <div class="timeline">
- {events.map((e,i) => {
+ {state.map((e,i) => {
return <div key={i} class="timeline-item">
{(() => {
switch (e.type) {
@@ -55,6 +55,7 @@ export function Timeline({ events:e }: Props) {
case "delivery": return <div class="timeline-marker is-icon "><i class="mdi mdi-delivery" /></div>
case "start": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-flag " /></div>
case "wired": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-cash" /></div>
+ case "wired-range": return <div class="timeline-marker is-icon is-success"><i class="mdi mdi-cash" /></div>
case "refund": return <div class="timeline-marker is-icon is-danger"><i class="mdi mdi-cash" /></div>
case "now": return <div class="timeline-marker is-icon is-info"><i class="mdi mdi-clock" /></div>
}
@@ -71,5 +72,5 @@ export function Timeline({ events:e }: Props) {
export interface Event {
when: Date;
description: string;
- type: 'start' | 'refund' | 'wired' | 'deadline' | 'delivery' | 'now'
+ type: 'start' | 'refund' | 'wired' | 'wired-range' |'deadline' | 'delivery' | 'now'
}