diff --git a/js/languages/en-US.json b/js/languages/en-US.json index 5ad44b1f1..27922e1b6 100644 --- a/js/languages/en-US.json +++ b/js/languages/en-US.json @@ -603,8 +603,7 @@ "formats": { "PHYSICAL_GOOD": "Physical Good", "DIGITAL_GOOD": "Digital Good", - "SERVICE": "Service", - "CROWD_FUND": "Crowd fund" + "SERVICE": "Service" }, "conditionTypes": { "NEW": "New", @@ -1073,7 +1072,7 @@ "noteFromLabel": "Note from %{store}:", "copyLink": "Copy", "digitalReadyForDlHeading": "Digital files are ready for download!", - "digitalReadyForDlText": "The files have been delivered. DOwnload when you're ready.", + "digitalReadyForDlText": "The files have been delivered. Download when you're ready.", "urlLabel": "File URL", "passwordLabel": "Password" }, @@ -1095,6 +1094,39 @@ "heading": "Order Complete", "reviewLabel": "%{name}'s Review:" }, + "disputeStarted": { + "heading": "Dispute Started", + "partyIsDisputing": "%{name} is disputing the order:", + "resolveBtn": "Resolve Dispute", + "genericIsDisputed": "The order is being disputed:", + "noReasonProvided": "No reason was provided." + }, + "disputePayout": { + "heading": "Dispute Payout", + "buyerHeading": "Buyer", + "buyerHeadingWithName": "%{name} (buyer)", + "vendorHeading": "Vendor", + "vendorHeadingWithName": "%{name} (vendor)", + "moderatorHeading": "Moderator", + "moderatorHeadingWithName": "%{name} (moderator)", + "noteFromHeading": "Note from moderator:", + "noteFromHeadingWithName": "Note from %{name}:", + "btnAcceptPayout": "Accept Payout", + "acceptPayoutConfirm": { + "title": "Are you sure?", + "body": "Once accepted, the payout will process immediately", + "btnCancel": "Cancel", + "btnConfirm": "Yes, Accept" + } + }, + "disputeAcceptance": { + "heading": "Dispute Closed", + "genericBuyerAcceptedPayout": "The buyer accepted the dispute payout", + "genericVendorAcceptedPayout": "The vendor accepted the dispute payout", + "userAcceptedPayout": "%{name} accepted the dispute payout", + "orderCompleteWhenYouReview": "The order will be complete when you leave a review.", + "orderCompleteWhenBuyerReviews": "The order will be complete when the buyer leaves a review." + }, "orderDetails": { "progressBarStates": { "paid": "Paid", @@ -1116,9 +1148,6 @@ "moderatorHeading": "Moderator", "copyAddress": "Copy", "viewOnMap": "View on map" - }, - "payForOrder": { - "heading": "Pay for your order" } }, "fulfillOrderTab": { @@ -1136,6 +1165,33 @@ "noteHelperTextDigital": "The buyer will receive a notification containing the file information", "btnCancel": "Cancel", "btnSubmit": "Submit" + }, + "resolveDisputeTab": { + "heading": "Resolve Dispute", + "buyerAmountLabel": "Buyer Amount", + "vendorAmountLabel": "Vendor Amount", + "commentLabel": "Comment", + "commentPlaceholder": "Explain your decision...", + "btnCancel": "Cancel", + "btnSubmit": "Submit", + "resolveConfirm": { + "title": "Are you sure?", + "body": "Please double check everything looks good", + "btnCancel": "Cancel", + "btnSubmit": "Submit" + } + }, + "disputeOrderTab": { + "heading": "Dispute Order", + "moderatorLabel": "Moderator", + "reasonLabel": "Reason", + "reasonPlaceholder": "Please explain your reason for opening a dispute…", + "reasonHelperText": "Opening a dispute will notify and invite the moderator into the order to help resolve any conflicts", + "btnCancel": "Cancel", + "btnSubmit": "Submit" + }, + "actionBar": { + "disputeOrderBtn": "Dispute Order" } }, "orderUtil": { @@ -1144,7 +1200,10 @@ "failedCancelHeading": "There was an error canceling the order.", "failedFulfillHeading": "There was an error fulfilling the order.", "failedRefundHeading": "There was an error refunding the order.", - "failedCompleteHeading": "There was an error completing the order." + "failedCompleteHeading": "There was an error completing the order.", + "failedOpenDisputeHeading": "There was an error completing the order.", + "failedResolveHeading": "There was an error resolving the order.", + "failedAcceptPayoutHeading": "There was an error accepting the payout." }, "exchangeRatesSyncer": { "fetchingRatesStatusMsg": "Fetching exchange rates…", @@ -1304,6 +1363,14 @@ "provideReview": "Please provide a review.", "provideRating": "Please select a rating." }, + "resolveDisputeModelErrors": { + "provideAmount": "Please provide an amount.", + "percentageOutOfRange": "The amount must be between 0 and 100.", + "providePercentageAsNumber": "Please provide a vendor amount as a number.", + "totalPercentageOutOfRange": "The sum of the buyer and vendor amounts cannot exceed 100.", + "totalPercentageTooLow": "The sum of the buyer and vendor amounts must add up to 100.", + "provideResolution": "Please explain your decision." + }, "bitcoinCurrencyUnits": { "BTC": "BTC", "MBTC": "mBTC", diff --git a/js/models/listing/Metadata.js b/js/models/listing/Metadata.js index 619f98071..d9e269b40 100644 --- a/js/models/listing/Metadata.js +++ b/js/models/listing/Metadata.js @@ -17,7 +17,6 @@ export default class extends BaseModel { 'PHYSICAL_GOOD', 'DIGITAL_GOOD', 'SERVICE', - 'CROWD_FUND', ]; } diff --git a/js/models/order/Case.js b/js/models/order/Case.js index a9dc83cae..6c2468ad4 100644 --- a/js/models/order/Case.js +++ b/js/models/order/Case.js @@ -40,6 +40,38 @@ export default class extends BaseModel { // convert price fields response.vendorContract.buyerOrder.payment.amount = integerToDecimal(response.vendorContract.buyerOrder.payment.amount, true); + + if (response.resolution) { + response.resolution.payout.buyerOutput = + response.resolution.payout.buyerOutput || {}; + response.resolution.payout.vendorOutput = + response.resolution.payout.vendorOutput || {}; + response.resolution.payout.moderatorOutput = + response.resolution.payout.moderatorOutput || {}; + + // Temporary to account for server bug: + // https://github.com/OpenBazaar/openbazaar-go/issues/548 + // Sometimes the payment amounts are coming back as enormously inflated strings. + // For now, we'll just make them dummy values. + if (typeof response.resolution.payout.buyerOutput.amount === 'string') { + response.resolution.payout.buyerOutput.amount = 25000; + } + + if (typeof response.resolution.payout.vendorOutput.amount === 'string') { + response.resolution.payout.vendorOutput.amount = 12000; + } + + if (typeof response.resolution.payout.moderatorOutput.amount === 'string') { + response.resolution.payout.moderatorOutput.amount = 6000; + } + + response.resolution.payout.buyerOutput.amount = + integerToDecimal(response.resolution.payout.buyerOutput.amount || 0, true); + response.resolution.payout.vendorOutput.amount = + integerToDecimal(response.resolution.payout.vendorOutput.amount || 0, true); + response.resolution.payout.moderatorOutput.amount = + integerToDecimal(response.resolution.payout.moderatorOutput.amount || 0, true); + } } return response; diff --git a/js/models/order/Contract.js b/js/models/order/Contract.js index 1b11db17d..081ef88ab 100644 --- a/js/models/order/Contract.js +++ b/js/models/order/Contract.js @@ -15,6 +15,17 @@ export default class extends BaseModel { .get('contractType'); } + get isLocalPickup() { + const buyerOrder = this.get('buyerOrder'); + + if (buyerOrder && buyerOrder.items && buyerOrder.items[0] && + buyerOrder.items[0].shippingOption) { + return buyerOrder.items[0].shippingOption.service === ''; + } + + return false; + } + parse(response) { return { ...response, diff --git a/js/models/order/Order.js b/js/models/order/Order.js index 7478a8844..9d3216bc0 100644 --- a/js/models/order/Order.js +++ b/js/models/order/Order.js @@ -47,6 +47,41 @@ export default class extends BaseModel { // convert price fields response.contract.buyerOrder.payment.amount = integerToDecimal(response.contract.buyerOrder.payment.amount, true); + + if (response.contract.disputeResolution) { + response.contract.disputeResolution.payout.buyerOutput = + response.contract.disputeResolution.payout.buyerOutput || {}; + response.contract.disputeResolution.payout.vendorOutput = + response.contract.disputeResolution.payout.vendorOutput || {}; + response.contract.disputeResolution.payout.moderatorOutput = + response.contract.disputeResolution.payout.moderatorOutput || {}; + + // Temporary to account for server bug: + // https://github.com/OpenBazaar/openbazaar-go/issues/548 + // Sometimes the payment amounts are coming back as enormously inflated strings. + // For now, we'll just make them dummy values. + if (typeof response.contract.disputeResolution.payout.buyerOutput.amount === 'string') { + response.contract.disputeResolution.payout.buyerOutput.amount = 25000; + } + + if (typeof response.contract.disputeResolution.payout.vendorOutput.amount === 'string') { + response.contract.disputeResolution.payout.vendorOutput.amount = 12000; + } + + if (typeof response.contract.disputeResolution.payout.moderatorOutput.amount === 'string') { + response.contract.disputeResolution.payout.moderatorOutput.amount = 6000; + } + + response.contract.disputeResolution.payout.buyerOutput.amount = + integerToDecimal( + response.contract.disputeResolution.payout.buyerOutput.amount || 0, true); + response.contract.disputeResolution.payout.vendorOutput.amount = + integerToDecimal( + response.contract.disputeResolution.payout.vendorOutput.amount || 0, true); + response.contract.disputeResolution.payout.moderatorOutput.amount = + integerToDecimal( + response.contract.disputeResolution.payout.moderatorOutput.amount || 0, true); + } } response.paymentAddressTransactions = response.paymentAddressTransactions || []; diff --git a/js/models/order/OrderDispute.js b/js/models/order/OrderDispute.js new file mode 100644 index 000000000..7b97ae06f --- /dev/null +++ b/js/models/order/OrderDispute.js @@ -0,0 +1,26 @@ +import app from '../../app'; +import BaseModel from '../BaseModel'; + +export default class extends BaseModel { + defaults() { + return { + claim: '', + }; + } + + url() { + return app.getServerUrl('ob/opendispute/'); + } + + get idAttribute() { + return 'orderId'; + } + + sync(method, model, options) { + if (method === 'create' || method === 'update') { + options.type = 'POST'; + } + + return super.sync(method, model, options); + } +} diff --git a/js/models/order/ResolveDispute.js b/js/models/order/ResolveDispute.js new file mode 100644 index 000000000..50c454bda --- /dev/null +++ b/js/models/order/ResolveDispute.js @@ -0,0 +1,83 @@ +import app from '../../app'; +import BaseModel from '../BaseModel'; + +export default class extends BaseModel { + defaults() { + return { + resolution: '', + }; + } + + url() { + return app.getServerUrl('ob/closedispute/'); + } + + get idAttribute() { + return 'orderId'; + } + + validate(attrs) { + const errObj = {}; + + const addError = (fieldName, error) => { + errObj[fieldName] = errObj[fieldName] || []; + errObj[fieldName].push(error); + }; + + let vendorPercentageOk = false; + let buyerPercentageOk = false; + + if (typeof attrs.vendorPercentage === 'undefined' || attrs.vendorPercentage === '') { + addError('vendorPercentage', + app.polyglot.t('resolveDisputeModelErrors.provideAmount')); + } else if (typeof attrs.vendorPercentage !== 'number') { + addError('vendorPercentage', + app.polyglot.t('resolveDisputeModelErrors.providePercentageAsNumber')); + } else if (attrs.vendorPercentage < 0 || attrs.vendorPercentage > 100) { + addError('vendorPercentage', + app.polyglot.t('resolveDisputeModelErrors.vendorPercentageOutOfRange')); + } else { + vendorPercentageOk = true; + } + + if (typeof attrs.buyerPercentage === 'undefined' || attrs.buyerPercentage === '') { + addError('buyerPercentage', + app.polyglot.t('resolveDisputeModelErrors.provideAmount')); + } else if (typeof attrs.buyerPercentage !== 'number') { + addError('buyerPercentage', + app.polyglot.t('resolveDisputeModelErrors.providePercentageAsNumber')); + } else if (attrs.buyerPercentage < 0 || attrs.buyerPercentage > 100) { + addError('buyerPercentage', + app.polyglot.t('resolveDisputeModelErrors.buyerPercentageOutOfRange')); + } else { + buyerPercentageOk = true; + } + + if (vendorPercentageOk && buyerPercentageOk) { + if (attrs.buyerPercentage + attrs.vendorPercentage > 100) { + addError('buyerPercentage', + app.polyglot.t('resolveDisputeModelErrors.totalPercentageOutOfRange')); + } else if (attrs.buyerPercentage + attrs.vendorPercentage < 100) { + addError('buyerPercentage', + app.polyglot.t('resolveDisputeModelErrors.totalPercentageTooLow')); + } + } + + if (!attrs.resolution) { + addError('resolution', + app.polyglot.t('resolveDisputeModelErrors.provideResolution')); + } + + if (Object.keys(errObj).length) return errObj; + + return undefined; + } + + sync(method, model, options) { + if (method === 'create' || method === 'update') { + options.type = 'POST'; + } + + return super.sync(method, model, options); + } +} diff --git a/js/models/order/orderFulfillment/OrderFulfillment.js b/js/models/order/orderFulfillment/OrderFulfillment.js index 0e2b8ddcb..5be8995da 100644 --- a/js/models/order/orderFulfillment/OrderFulfillment.js +++ b/js/models/order/orderFulfillment/OrderFulfillment.js @@ -9,19 +9,25 @@ export default class extends BaseModel { throw new Error('Please provide the contract type.'); } + if (typeof options.isLocalPickup !== 'boolean') { + throw new Error('Please provide a boolean indicating whether the item is to ' + + 'be picked up locally.'); + } + // Since the contract type is not available on this when // the defaults are initially called, we need to set the // initial contract type dependant attributes here. We also // set them in defaults, so if the model is reset, they'll // be restored properly. if (options.contractType === 'DIGITAL_GOOD') { - attrs.digitalDelivery = new DigitalDelivery(); - } else if (options.contractType === 'PHYSICAL_GOOD') { - attrs.physicalDelivery = new PhysicalDelivery(); + attrs.digitalDelivery = new DigitalDelivery(attrs.digitalDelivery || {}); + } else if (options.contractType === 'PHYSICAL_GOOD' && !options.isLocalPickup) { + attrs.physicalDelivery = new PhysicalDelivery(attrs.physicalDelivery || {}); } super(attrs, options); this.contractType = options.contractType; + this.isLocalPickup = options.isLocalPickup; } defaults() { @@ -29,7 +35,7 @@ export default class extends BaseModel { if (this.contractType === 'DIGITAL_GOOD') { defaults.digitalDelivery = new DigitalDelivery(); - } else if (this.contractType === 'PHYSICAL_GOOD') { + } else if (this.contractType === 'PHYSICAL_GOOD' && !this.isLocalPickup) { defaults.physicalDelivery = new PhysicalDelivery(); } diff --git a/js/templates/modals/orderDetail/actionBar.html b/js/templates/modals/orderDetail/actionBar.html new file mode 100644 index 000000000..9c9e6c887 --- /dev/null +++ b/js/templates/modals/orderDetail/actionBar.html @@ -0,0 +1,6 @@ +<% if (ob.showDisputeOrderButton) { %> + <%= ob.processingButton({ + className: 'flex btn clrErr clrBrDec1 clrTOnEmph js-openDispute', + btnText: ob.polyT('orderDetail.actionBar.disputeOrderBtn'), + }) %> +<% } %> \ No newline at end of file diff --git a/js/templates/modals/orderDetail/disputeOrder.html b/js/templates/modals/orderDetail/disputeOrder.html new file mode 100644 index 000000000..b11eb682c --- /dev/null +++ b/js/templates/modals/orderDetail/disputeOrder.html @@ -0,0 +1,35 @@ +
+
+ <%= ob.polyT(`orderDetail.backToSummary`) %> +
+
<%= ob.polyT(`orderDetail.disputeOrderTab.heading`) %>
+
+
+
+
+
+
<%= ob.polyT(`orderDetail.disputeOrderTab.moderatorLabel`) %>
+
+
+
+
+
+
+
+ +
+
+ <% if (ob.errors['claim']) print(ob.formErrorTmpl({ errors: ob.errors['claim'] })) %> + +
<%= ob.polyT(`orderDetail.disputeOrderTab.reasonHelperText`) %>
+
+
+
+
+
+ <%= ob.polyT(`orderDetail.fulfillOrderTab.btnCancel`) %> + <%= ob.processingButton({ + className: `btn clrBAttGrad clrBrDec1 clrTOnEmph js-submit ${ob.openingDispute ? 'processing' : ''}`, + btnText: ob.polyT(`orderDetail.fulfillOrderTab.btnSubmit`), + }) %> +
\ No newline at end of file diff --git a/js/templates/modals/orderDetail/fulfillOrder.html b/js/templates/modals/orderDetail/fulfillOrder.html index 76955cf4a..de35fbf1d 100644 --- a/js/templates/modals/orderDetail/fulfillOrder.html +++ b/js/templates/modals/orderDetail/fulfillOrder.html @@ -6,7 +6,7 @@
- <% if (ob.contractType === 'PHYSICAL_GOOD') { %> + <% if (ob.contractType === 'PHYSICAL_GOOD' && !ob.isLocalPickup) { %>
diff --git a/js/templates/modals/orderDetail/modFragment.html b/js/templates/modals/orderDetail/modFragment.html new file mode 100644 index 000000000..ff2789401 --- /dev/null +++ b/js/templates/modals/orderDetail/modFragment.html @@ -0,0 +1,11 @@ +<% + let modLink = + `${ob.handle && `@${ob.handle}` || `${ob.peerId.slice(0, ob.maxPeerIdLength)}…`}`; +%> + +
+ <% if (ob.showAvatar) { %> +
+ <% } %> +
<%= ob.name %><% print(modLink ? ` ${modLink}` : '') %>
+
diff --git a/js/templates/modals/orderDetail/orderDetail.html b/js/templates/modals/orderDetail/orderDetail.html index 5859b9321..98afc61bc 100644 --- a/js/templates/modals/orderDetail/orderDetail.html +++ b/js/templates/modals/orderDetail/orderDetail.html @@ -33,6 +33,7 @@

<%= ob.polyT('tabMenuHeading') %>

btnText: 'Accept Order', }) %>
+
@@ -52,5 +53,5 @@

<%= ob.polyT('tabMenuHeading') %>

<% } %>
-
+ \ No newline at end of file diff --git a/js/templates/modals/orderDetail/resolveDispute.html b/js/templates/modals/orderDetail/resolveDispute.html new file mode 100644 index 000000000..ce94a490a --- /dev/null +++ b/js/templates/modals/orderDetail/resolveDispute.html @@ -0,0 +1,63 @@ +
+ +
<%= ob.polyT(`orderDetail.resolveDisputeTab.heading`) %>
+
+
+ +
+
+ +
<%= ob.buyerName %>
+
+
+ <% if (ob.errors['buyerPercentage']) print(ob.formErrorTmpl({ errors: ob.errors['buyerPercentage'] })) %> +
+ +
+
+
+
+
+
+ +
<%= ob.vendorName %>
+
+
+ <% if (ob.errors['vendorPercentage']) print(ob.formErrorTmpl({ errors: ob.errors['vendorPercentage'] })) %> +
+ +
+
+
+
+
+
+ +
+
+ <% if (ob.errors['resolution']) print(ob.formErrorTmpl({ errors: ob.errors['resolution'] })) %> + +
+
+
+
+
+ <%= ob.polyT(`orderDetail.resolveDisputeTab.btnCancel`) %> +
+ <%= ob.processingButton({ + className: `btn clrBAttGrad clrBrDec1 clrTOnEmph js-submit ${ob.resolvingDispute ? 'processing' : ''}`, + btnText: ob.polyT(`orderDetail.resolveDisputeTab.btnSubmit`), + }) %> +
+
<%= ob.polyT('orderDetail.resolveDisputeTab.resolveConfirm.title') %>
+

<%= ob.polyT('orderDetail.resolveDisputeTab.resolveConfirm.body') %>

+
+ +
+
+
\ No newline at end of file diff --git a/js/templates/modals/orderDetail/summaryTab/completeOrderForm.html b/js/templates/modals/orderDetail/summaryTab/completeOrderForm.html index 4463e33de..29e365038 100644 --- a/js/templates/modals/orderDetail/summaryTab/completeOrderForm.html +++ b/js/templates/modals/orderDetail/summaryTab/completeOrderForm.html @@ -22,7 +22,8 @@

<%= ob.polyT('orderDetail.summaryTab.completeOrderForm.h name="anonymous" id="completeOrderAnon" class="centerLabel" - <% if (ob.anonymous) print('checked') %>> + data-var-type="boolean" + <% if (!ob.anonymous) print('checked') %>> diff --git a/js/templates/modals/orderDetail/summaryTab/disputeAcceptance.html b/js/templates/modals/orderDetail/summaryTab/disputeAcceptance.html new file mode 100644 index 000000000..337e27ca2 --- /dev/null +++ b/js/templates/modals/orderDetail/summaryTab/disputeAcceptance.html @@ -0,0 +1,31 @@ +

<%= ob.polyT('orderDetail.summaryTab.disputeAcceptance.heading') %>

+<% if (ob.timestamp) { %> +<%= ob.moment(ob.timestamp).format('lll') %> +<% } %> + +
+
+
+
+ <% + let introLine; + + if (ob.closerName) { + introLine = ob.polyT('orderDetail.summaryTab.disputeAcceptance.userAcceptedPayout', { + name: ob.closerName, + }); + } else { + introLine = ob.acceptedByBuyer ? + ob.polyT('orderDetail.summaryTab.disputeAcceptance.genericBuyerAcceptedPayout') : + ob.polyT('orderDetail.summaryTab.disputeAcceptance.genericVendorAcceptedPayout'); + } + + const subText = ob.buyerViewing ? + ob.polyT('orderDetail.summaryTab.disputeAcceptance.orderCompleteWhenYouReview') : + ob.polyT('orderDetail.summaryTab.disputeAcceptance.orderCompleteWhenBuyerReviews'); + %> +
<%= introLine %>
+
<%= subText %>
+
+
+
\ No newline at end of file diff --git a/js/templates/modals/orderDetail/summaryTab/disputePayout.html b/js/templates/modals/orderDetail/summaryTab/disputePayout.html new file mode 100644 index 000000000..e3f2a52d6 --- /dev/null +++ b/js/templates/modals/orderDetail/summaryTab/disputePayout.html @@ -0,0 +1,86 @@ +<% + let priceLines = {}; + let partyHeadings = {}; + + ['buyer', 'vendor', 'moderator'].forEach(type => { + priceLines[type] = ob.convertAndFormatCurrency(ob.payout[`${type}Output`].amount, + 'BTC', ob.userCurrency, { useBtcSymbol: false }); + + if (ob.userCurrency !== 'BTC') { + priceLines[type] = ob.polyT('fiatBtcPairing', { + fiatAmount: priceLines[type], + btcAmount: ob.formatCurrency(ob.payout[`${type}Output`].amount, 'BTC', { useBtcSymbol: false }), + }); + } + + partyHeadings[type] = ob[`${type}Name`] ? + ob.polyT(`orderDetail.summaryTab.disputePayout.${type}HeadingWithName`, { name: ob[`${type}Name`] }) : + ob.polyT(`orderDetail.summaryTab.disputePayout.${type}Heading`); + }); +%> +

<%= ob.polyT('orderDetail.summaryTab.disputePayout.heading') %>

+<% if (ob.timestamp) { %> +<%= ob.moment(ob.timestamp).format('lll') %> +<% } %> + +
+
+
+
+
+
+
<%= partyHeadings.buyer %>
+
<%= priceLines.buyer %>
+
+
+
+
+
+
<%= partyHeadings.vendor %>
+
<%= priceLines.vendor %>
+
+
+
+
+
+
<%= partyHeadings.moderator %>
+
<%= priceLines.moderator %>
+
+
+
+
+
+ <% if (ob.showAcceptButton) { %> + <%= ob.processingButton({ + className: `btn clrBAttGrad clrBrDec1 clrTOnEmph tx5b js-acceptPayout ${ob.acceptInProgress ? 'processing' : ''} ${ob.acceptConfirmOn ? 'disabled' : '' }`, + btnText: ob.polyT('orderDetail.summaryTab.disputePayout.btnAcceptPayout') + }) %> + <% } %> + <% if (ob.acceptConfirmOn) { %> +
+
<%= ob.polyT('orderDetail.summaryTab.disputePayout.acceptPayoutConfirm.title') %>
+

<%= ob.polyT('orderDetail.summaryTab.disputePayout.acceptPayoutConfirm.body') %>

+
+ +
+ <% } %> +
+
+
+
+ + +
+ <% + const noteFromHeading = ob.moderatorName ? + ob.polyT('orderDetail.summaryTab.disputePayout.noteFromHeadingWithName', { name: ob.moderatorName }) : + ob.polyT('orderDetail.summaryTab.disputePayout.noteFromHeading'); + %> +
<%= noteFromHeading %>
+
<%= ob.resolution %>
+
+
+
\ No newline at end of file diff --git a/js/templates/modals/orderDetail/summaryTab/disputeStarted.html b/js/templates/modals/orderDetail/summaryTab/disputeStarted.html new file mode 100644 index 000000000..4b0005f57 --- /dev/null +++ b/js/templates/modals/orderDetail/summaryTab/disputeStarted.html @@ -0,0 +1,27 @@ +

<%= ob.polyT('orderDetail.summaryTab.disputeStarted.heading') %>

+<% if (ob.timestamp) { %> +<%= ob.moment(ob.timestamp).format('lll') %> +<% } %> + +
+
+
+
+ <% + let introLine = ob.disputerName ? + ob.polyT('orderDetail.summaryTab.disputeStarted.partyIsDisputing', { name: ob.disputerName }) : + ob.polyT('orderDetail.summaryTab.disputeStarted.genericIsDisputed'); + %> +
<%= introLine %>
+
<%= ob.claim || ob.polyT('orderDetail.summaryTab.disputeStarted.noReasonProvided') %>
+
+
+ <% if (ob.showResolveButton) { %> + <%= ob.processingButton({ + className: `btn clrBAttGrad clrBrDec1 clrTOnEmph tx5b js-resolveDispute`, + btnText: ob.polyT('orderDetail.summaryTab.disputeStarted.resolveBtn') + }) %> + <% } %> +
+
+
\ No newline at end of file diff --git a/js/templates/modals/orderDetail/summaryTab/fulfilled.html b/js/templates/modals/orderDetail/summaryTab/fulfilled.html index d7de2b72e..32754248a 100644 --- a/js/templates/modals/orderDetail/summaryTab/fulfilled.html +++ b/js/templates/modals/orderDetail/summaryTab/fulfilled.html @@ -9,14 +9,16 @@

<%= ob.polyT('orderDetail.summaryTab.fulfilled.heading') <% const physicalDelivery = ob.physicalDelivery && ob.physicalDelivery[0] || {}; %>
-
<%= ob.polyT('orderDetail.summaryTab.fulfilled.shippedByLabel') %> <%= physicalDelivery.shipper %>
-
- <%= ob.polyT('orderDetail.summaryTab.fulfilled.trackingNumberLabel') %> <%= physicalDelivery.trackingNumber || ob.polyT('orderDetail.summaryTab.notApplicable') %> - <% if (physicalDelivery.trackingNumber) { %> - <%= ob.polyT('orderDetail.summaryTab.fulfilled.copyLink') %> - <%= ob.polyT('copiedToClipboard') %> - <% } %> -
+ <% if (!ob.isLocalPickup) { %> +
<%= ob.polyT('orderDetail.summaryTab.fulfilled.shippedByLabel') %> <%= physicalDelivery.shipper %>
+
+ <%= ob.polyT('orderDetail.summaryTab.fulfilled.trackingNumberLabel') %> <%= physicalDelivery.trackingNumber || ob.polyT('orderDetail.summaryTab.notApplicable') %> + <% if (physicalDelivery.trackingNumber) { %> + <%= ob.polyT('orderDetail.summaryTab.fulfilled.copyLink') %> + <%= ob.polyT('copiedToClipboard') %> + <% } %> +
+ <% } %>
<%= ob.polyT('orderDetail.summaryTab.fulfilled.noteFromLabel', { store: ob.storeName }) %>
<%= ob.note ? ob.parseEmojis(ob.note) : ob.polyT('orderDetail.summaryTab.notApplicable') %>
diff --git a/js/templates/modals/orderDetail/summaryTab/orderDetails.html b/js/templates/modals/orderDetail/summaryTab/orderDetails.html index 6ca5f3ea3..353b1a8d2 100644 --- a/js/templates/modals/orderDetail/summaryTab/orderDetails.html +++ b/js/templates/modals/orderDetail/summaryTab/orderDetails.html @@ -22,14 +22,14 @@ // first item. var item = ob.order.items[0]; - var priceText = ob.convertAndFormatCurrency(ob.listing.item.price, - ob.listing.metadata.pricingCurrency, ob.userCurrency, { useBtcSymbol: false }); + var priceText = ob.formatCurrency(ob.order.payment.amount, 'BTC', + { useBtcSymbol: false }); if (ob.userCurrency !== 'BTC') { priceText = ob.polyT('fiatBtcPairing', { - fiatAmount: priceText, - btcAmount: ob.convertAndFormatCurrency(ob.listing.item.price, - ob.listing.metadata.pricingCurrency, 'BTC', { useBtcSymbol: false }), + fiatAmount: ob.convertAndFormatCurrency(ob.order.payment.amount, 'BTC', + ob.userCurrency), + btcAmount: priceText, }); } %> @@ -95,7 +95,11 @@

<%= ob.polyT('orderDetail.summaryTab.orderDetails.headin
<%= ob.polyT('orderDetail.summaryTab.orderDetails.moderatorHeading') %>
-
+ <% if (ob.isModerated) { %> +
+ <% } else { %> + <%= ob.polyT('orderDetail.summaryTab.notApplicable') %> + <% } %>
<%= ob.polyT('orderDetail.summaryTab.orderDetails.totalHeading') %>
diff --git a/js/templates/modals/orderDetail/summaryTab/orderDetailsModerator.html b/js/templates/modals/orderDetail/summaryTab/orderDetailsModerator.html deleted file mode 100644 index 4a76dd7ec..000000000 --- a/js/templates/modals/orderDetail/summaryTab/orderDetailsModerator.html +++ /dev/null @@ -1,9 +0,0 @@ -<% if (ob.peerId) { %> - <% - let modLink = - `${ob.handle || `${ob.peerId.slice(0, 8)}…`}`; - %> -
<%= ob.name %><% print(modLink ? ` ${modLink}` : '') %>
-<% } else { %> - <%= ob.polyT('orderDetail.summaryTab.notApplicable') %> -<% } %> \ No newline at end of file diff --git a/js/templates/modals/orderDetail/summaryTab/payment.html b/js/templates/modals/orderDetail/summaryTab/payment.html index 8e5b5c273..21b1fee92 100644 --- a/js/templates/modals/orderDetail/summaryTab/payment.html +++ b/js/templates/modals/orderDetail/summaryTab/payment.html @@ -70,9 +70,7 @@

<%= heading %>

<% - let subText = ''; - - subText = ob.polyT('orderDetail.summaryTab.payment.paidInFull'); + let subText = ob.polyT('orderDetail.summaryTab.payment.paidInFull'); if (ob.amountShort > 0) { subText = diff --git a/js/templates/modals/orderDetail/summaryTab/stateProgressBar.html b/js/templates/modals/orderDetail/summaryTab/stateProgressBar.html index 2c88826d7..b3dcb4756 100644 --- a/js/templates/modals/orderDetail/summaryTab/stateProgressBar.html +++ b/js/templates/modals/orderDetail/summaryTab/stateProgressBar.html @@ -12,7 +12,7 @@
<%= state %>
<% if (ob.disputeState === index + 1) { %>
- +
<% } %>
diff --git a/js/templates/modals/orderDetail/summaryTab/summary.html b/js/templates/modals/orderDetail/summaryTab/summary.html index 1598d9458..a9eda7fea 100644 --- a/js/templates/modals/orderDetail/summaryTab/summary.html +++ b/js/templates/modals/orderDetail/summaryTab/summary.html @@ -23,13 +23,5 @@

<%= ob.polyT('orderDetail.summaryTab.payment.firstPaymen <% } %> -<% if (ob.shouldShowPayForOrderSection) { %> -
-

<%= ob.polyT('orderDetail.summaryTab.payForOrder.heading') %>

-
-

Section under construction

-

<%= ob.paymentAddress %> needs to be funded with <%= ob.upToFixed(ob.balanceRemaining, 8) %> BTC.

-
-
-<% } %> +
diff --git a/js/templates/modals/purchase/confirmWallet.html b/js/templates/modals/purchase/confirmWallet.html index 0503f37aa..3ed529f69 100644 --- a/js/templates/modals/purchase/confirmWallet.html +++ b/js/templates/modals/purchase/confirmWallet.html @@ -20,7 +20,7 @@

const msg = ob.displayCurrency === 'BTC' ? 'payBTC' : 'payFiat'; if (requiredTotal && fundGap <= 0) { %> - <%= ob.polyT(`purchase.pendingSection.confirmWallet.${msg}`, { amountBTC: ob.amountBTC, amountFiat }) %> + <%= ob.polyT(`purchase.pendingSection.confirmWallet.${msg}`, { amountBTC: ob.formatCurrency(ob.amount, 'BTC'), amountFiat }) %> <% } else { %> <%= ob.polyT('purchase.pendingSection.confirmWallet.insufficientFundsMsg1', { funds: fundsBTC }) %>

@@ -31,7 +31,7 @@

<% if (requiredTotal && fundGap > 0) { %>

- <%= ob.polyT('purchase.pendingSection.confirmWallet.insufficientFundsNote', { amount: ob.amountBTC, fee: feeBTC }) %> + <%= ob.polyT('purchase.pendingSection.confirmWallet.insufficientFundsNote', { amount: ob.formatCurrency(ob.amount, 'BTC'), fee: feeBTC }) %>

<% } %> diff --git a/js/templates/modals/purchase/payment.html b/js/templates/modals/purchase/payment.html index 5c7d98724..522a95e07 100644 --- a/js/templates/modals/purchase/payment.html +++ b/js/templates/modals/purchase/payment.html @@ -1,14 +1,16 @@ -
-
- + +
+
+
-
+
- - <%= ob.polyT('purchase.pendingSection.pay', { amountBTC: ob.amountBTC }) %> - + <%= ob.amountDueLine %>