This commit is contained in:
parent
33c68c2f44
commit
749f525f83
44 changed files with 5380 additions and 3532 deletions
|
|
@ -804,11 +804,11 @@ SafeHtml RenderCheckoutForm(const Product& product,
|
|||
R"(bank transfer. Handled by Mollie.</span></label>)"
|
||||
R"(<label class="pay-option">)"
|
||||
R"(<input type="radio" name="pay"{}{}>)"
|
||||
R"(<span><strong>Cryptocurrency</strong> — Bitcoin and Lightning, )"
|
||||
R"(stablecoins and the other coins CoinGate lists. You pay the euro )"
|
||||
R"(total at the exchange rate CoinGate locks when you open the )"
|
||||
R"(invoice; crypto invoices expire quickly, so pay soon after )"
|
||||
R"(ordering or simply order again.</span></label>)"
|
||||
R"(<span><strong>Cryptocurrency</strong> — EURC, a euro )"
|
||||
R"(stablecoin, paid from your own wallet. The amount to send is the )"
|
||||
R"(euro total exactly, no exchange rate; the receiving address and )"
|
||||
R"(the networks it takes appear on the order page, and stay reserved )"
|
||||
R"(for about a day.</span></label>)"
|
||||
R"({})"
|
||||
R"(</fieldset>)",
|
||||
Attr("value", std::string(Form::kPayBank)),
|
||||
|
|
@ -1242,18 +1242,86 @@ export RenderedPage RenderOrderStatus(const OrderView& o, std::string_view indic
|
|||
// the payment on arrival. Reaching it means they abandoned the payment,
|
||||
// so it reads as "resume", not as an alarming limbo.
|
||||
SafeHtml payBlock;
|
||||
if (awaiting && !o.payUrl.empty()) {
|
||||
// Self-hosted crypto first: its payUrl is this very page, so the button
|
||||
// branch would render a link to where the buyer already stands.
|
||||
if (awaiting && o.cryptoPay) {
|
||||
const OrderCryptoPay& pay = *o.cryptoPay;
|
||||
|
||||
// One list item per network, in the given order — the first entry is
|
||||
// the recommendation, which is how "cheapest chain first" reaches the
|
||||
// buyer as layout rather than as a lecture.
|
||||
std::vector<SafeHtml> items;
|
||||
for (const OrderCryptoPay::Chain& c : pay.chains) {
|
||||
std::string label = c.name;
|
||||
if (!label.empty() && label[0] >= 'a' && label[0] <= 'z') {
|
||||
label[0] = static_cast<char>(label[0] - 'a' + 'A');
|
||||
}
|
||||
items.push_back(Format(
|
||||
R"(<li><strong>{}</strong>{}{}<br>)"
|
||||
R"(<small>EURC contract <code>{}</code></small></li>)",
|
||||
Escape(label),
|
||||
c.note.empty() ? SafeHtml{} : Format(" — {}", Escape(c.note)),
|
||||
c.link.empty() ? SafeHtml{}
|
||||
: Format(R"( · <a{}>open in your wallet</a>)",
|
||||
Url("href", c.link)),
|
||||
Escape(c.contract)));
|
||||
}
|
||||
|
||||
// The window line tells the truth for both signs of minutesLeft. A
|
||||
// closed window does NOT mean sent money is gone — the address stays
|
||||
// ours — so the copy says where it went instead of leaving a buyer
|
||||
// staring at money that "vanished".
|
||||
const SafeHtml windowLine = pay.minutesLeft > 0
|
||||
? Format(
|
||||
R"(<p class="order__note">This address is reserved for this order )"
|
||||
R"(for about {} more {}. This page checks automatically and )"
|
||||
R"(confirms once the full amount has arrived.</p>)",
|
||||
Num(pay.minutesLeft >= 120 ? pay.minutesLeft / 60 : pay.minutesLeft),
|
||||
pay.minutesLeft >= 120 ? Raw("hours") : Raw("minutes"))
|
||||
: Raw(R"(<p class="order__note">The payment window for this order has )"
|
||||
R"(closed and the order will lapse. If you already sent EURC it )"
|
||||
R"(is not lost — it arrived at the address above; contact )"
|
||||
R"(<a href="mailto:info@catcrafts.net">info@catcrafts.net</a> )"
|
||||
R"(and it will be settled by hand.</p>)");
|
||||
|
||||
SafeHtml indicativeLine = indicative.empty() ? SafeHtml{} : Format(
|
||||
R"(<p class="order__indicative">{}, indicative only. The charge is )"
|
||||
R"(the euro amount above.</p>)",
|
||||
Escape(indicative));
|
||||
|
||||
payBlock = Format(
|
||||
R"(<section class="section">)"
|
||||
R"(<h2 class="section__title">Pay with EURC</h2>)"
|
||||
R"(<p>Send <strong>{} EURC</strong> to this address — one )"
|
||||
R"(network, one payment:</p>)"
|
||||
R"(<p><code class="order__address">{}</code></p>)"
|
||||
R"(<ul class="order__chains">{}</ul>)"
|
||||
R"({})"
|
||||
R"(<p class="order__note">EURC is pegged to the euro, so the amount )"
|
||||
R"(is exactly the euro total — no exchange rate. Send EURC only, )"
|
||||
R"(and only on a network listed above. If your exchange deducts a )"
|
||||
R"(withdrawal fee, send the missing rest to the same address; the )"
|
||||
R"(order confirms once the full amount sits on one network. Your )"
|
||||
R"(order reference is <strong>{}</strong>.</p>)"
|
||||
R"({})"
|
||||
R"(</section>)",
|
||||
Escape(pay.amount),
|
||||
Escape(pay.address),
|
||||
Join(items),
|
||||
indicativeLine,
|
||||
Escape(o.reference),
|
||||
windowLine);
|
||||
} else if (awaiting && !o.payUrl.empty()) {
|
||||
const bool crypto = o.payChoice == Form::kPayCrypto;
|
||||
SafeHtml indicativeLine = indicative.empty() ? SafeHtml{} : Format(
|
||||
R"(<p class="order__indicative">{}, indicative only. The charge is )"
|
||||
R"(the euro amount above; your bank or card sets the actual conversion )"
|
||||
R"(rate.</p>)",
|
||||
Escape(indicative));
|
||||
// What is waiting behind the button differs by rail, and so does what
|
||||
// "left uncompleted" costs the buyer: a Mollie payment can be resumed
|
||||
// for a good while, a crypto invoice expires in hours or minutes. A
|
||||
// page that promised the crypto buyer their link would keep would be
|
||||
// lying to exactly the person most likely to come back to it late.
|
||||
// What is waiting behind the button differs by rail. The real crypto
|
||||
// rail never reaches this branch (its instructions render above); a
|
||||
// crypto choice here means a hosted stand-in — the fake rail in tests
|
||||
// — so its copy stays generic rather than naming coins.
|
||||
payBlock = Format(
|
||||
R"(<section class="section">)"
|
||||
R"(<h2 class="section__title">Complete your payment</h2>)"
|
||||
|
|
@ -1265,13 +1333,10 @@ export RenderedPage RenderOrderStatus(const OrderView& o, std::string_view indic
|
|||
R"(</section>)",
|
||||
indicativeLine,
|
||||
Url("href", o.payUrl), Escape(Money::FormatEuro(o.totalMinor)),
|
||||
crypto ? Raw("The invoice takes Bitcoin, Lightning, stablecoins and the "
|
||||
"other coins CoinGate lists;")
|
||||
crypto ? Raw("The payment page completes your crypto payment;")
|
||||
: Raw("The payment page offers iDEAL, cards and a bank transfer;"),
|
||||
Escape(o.reference),
|
||||
crypto ? Raw("Crypto invoices expire quickly — if this one has, "
|
||||
"the order simply lapses and you can order again.")
|
||||
: Raw("A payment left uncompleted simply lapses the order."));
|
||||
Raw("A payment left uncompleted simply lapses the order."));
|
||||
} else if (o.status == "paid") {
|
||||
payBlock = Format(
|
||||
R"(<section class="section"><h2 class="section__title">What happens now</h2>)"
|
||||
|
|
|
|||
Loading…
Reference in a new issue