Phase 2: Convert crypto history and invoice inline styles to CSS classes

Completed conversion of static inline styles in crypto_quotes_history.j2 and invoice.j2:

- Added comprehensive CSS classes for crypto history layout, status notices, and invoice components
- Converted 22 inline style instances to semantic CSS classes
- Improved maintainability while preserving all functionality
- Added status color classes for consistent semantic meaning across templates

Templates updated:
- crypto_quotes_history.j2: Payment cards, status notices, help sections
- invoice.j2: Discount sections, payment status indicators, layout components

CSS classes added: crypto-history-container, crypto-payment-card, status-*-notice,
invoice-*-section, status-success/warning/info/error, and utility classes.
This commit is contained in:
Russell Ballestrini 2025-10-04 13:46:37 -04:00
parent 252d2d056d
commit 618f7f257b
3 changed files with 172 additions and 31 deletions

View file

@ -1401,3 +1401,144 @@ div.message-ribbon {
background-color: red !important;
cursor: not-allowed;
}
/* Phase 2: Static layout and status styling */
/* Crypto history layout classes */
.crypto-history-container {
margin: 20px 0;
}
.crypto-payment-card {
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 15px;
margin-bottom: 15px;
background: #f8f9fa;
}
.crypto-header-grid {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
margin-bottom: 10px;
}
.crypto-header-title {
margin: 0 0 5px 0;
}
.crypto-header-subtitle {
margin: 0;
color: #6c757d;
font-size: 0.9em;
}
.crypto-details-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 15px;
margin: 10px 0;
align-items: start;
}
.crypto-right-align {
text-align: right;
}
.crypto-right-align-justify {
text-align: right;
justify-self: end;
}
.crypto-small-text {
color: #6c757d;
}
/* Status notice classes */
.status-warning-notice {
background: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 3px;
padding: 8px;
margin-top: 10px;
}
.status-error-notice {
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 3px;
padding: 8px;
margin-top: 10px;
}
.status-info-notice {
background: #d1ecf1;
border: 1px solid #bee5eb;
border-radius: 3px;
padding: 8px;
margin-top: 10px;
}
.crypto-help-section {
margin-top: 30px;
padding: 15px;
background: #e9ecef;
border-radius: 4px;
}
.crypto-empty-state {
text-align: center;
padding: 40px;
color: #6c757d;
}
/* Invoice layout classes */
.invoice-right-section {
text-align: right;
margin: 15px 0;
}
.invoice-total-section {
text-align: right;
margin: 20px 0;
font-size: 1.2em;
}
.invoice-payment-box {
background-color: #f0f8ff;
padding: 15px;
border: 1px solid #4169e1;
border-radius: 5px;
margin: 15px 0;
}
.invoice-margin-section {
margin-top: 15px;
}
.invoice-margin-small {
margin: 5px 0;
}
/* Status color classes */
.status-success {
color: #28a745;
}
.status-warning {
color: #ffc107;
}
.status-info {
color: #6c757d;
}
.status-error {
color: #dc3545;
}
.code-monospace {
font-size: 0.9em;
font-family: monospace;
}

View file

@ -7,26 +7,26 @@
<p>Your complete crypto payment history including all attempts, successful payments, and failed transactions.</p>
{% if payments %}
<div style="margin: 20px 0;">
<div class="crypto-history-container">
{% for payment in payments %}
<div style="border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #f8f9fa;">
<div style="display: grid; grid-template-columns: 1fr auto; align-items: start; margin-bottom: 10px;">
<div class="crypto-payment-card">
<div class="crypto-header-grid">
<div>
<h4 style="margin: 0 0 5px 0;">
<h4 class="crypto-header-title">
{{ payment.coin_name }} ({{ payment.coin_type }}) Payment
</h4>
<p style="margin: 0; color: #6c757d; font-size: 0.9em;">
<p class="crypto-header-subtitle">
{{ payment.shop_name }} • {{ payment.created_formatted }}
</p>
</div>
<div style="text-align: right;">
<div class="crypto-right-align">
<span style="background: {{ payment.status_color }}; color: white; padding: 4px 8px; border-radius: 3px; font-size: 0.85em; {% if payment.status != 'no-refund' %}font-weight: bold;{% endif %}">
{{ payment.status_label }}
</span>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 15px; margin: 10px 0; align-items: start;">
<div class="crypto-details-grid">
<div>
<strong>Expected Amount:</strong><br>
{% if payment.coin_type == 'XMR' %}
@ -35,7 +35,7 @@
{{ '%.8f' % payment.amount_crypto }} {{ payment.coin_type }}
{% endif %}
<br>
<small style="color: #6c757d;">${{ '%.2f' % payment.usd_total }} USD</small>
<small class="crypto-small-text">${{ '%.2f' % payment.usd_total }} USD</small>
</div>
{% if payment.received_crypto > 0 %}
@ -47,17 +47,17 @@
{{ '%.8f' % payment.received_crypto }} {{ payment.coin_type }}
{% endif %}
<br>
<small style="color: #6c757d;">${{ '%.2f' % (payment.received_crypto * (payment.rate_usd_per_coin|float)) }} USD</small>
<small class="crypto-small-text">${{ '%.2f' % (payment.received_crypto * (payment.rate_usd_per_coin|float)) }} USD</small>
{% if payment.confirmations > 0 %}
<br>
<small style="color: #6c757d;">{{ payment.confirmations }}/{{ payment.confirmations_required }} confirmations</small>
<small class="crypto-small-text">{{ payment.confirmations }}/{{ payment.confirmations_required }} confirmations</small>
{% endif %}
</div>
{% else %}
<div></div>
{% endif %}
<div style="text-align: right; justify-self: end;">
<div class="crypto-right-align-justify">
{% if payment.status == 'confirmed' or payment.status == 'confirmed-complete' or payment.status == 'confirmed-overpay' or payment.status == 'confirmed-overpay-refunded' or payment.status == 'confirmed-overpay-refunded-complete' %}
{% if payment.has_invoice %}
<a href="{{ request.route_url('view_invoice', invoice_id=payment.invoice_id) }}" class="mps-button mps-button-small mps-button-green">
@ -74,7 +74,7 @@
</a>
{% else %}
<!-- Terminal failed states -->
<small style="color: #6c757d;">
<small class="crypto-small-text">
Payment ID: {{ payment.id[:8] }}...
</small>
{% endif %}
@ -82,7 +82,7 @@
</div>
{% if payment.status == 'expired' or payment.status == 'cancelled' %}
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 3px; padding: 8px; margin-top: 10px;">
<div class="status-warning-notice">
<small>
{% if payment.status == 'expired' %}
⏰ This quote expired before payment was received.
@ -92,7 +92,7 @@
</small>
</div>
{% elif payment.status.endswith('-not-refunded') %}
<div style="background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 3px; padding: 8px; margin-top: 10px;">
<div class="status-error-notice">
<small>
❌ No refund possible:
{% if payment.refund_reason %}
@ -103,7 +103,7 @@
</small>
</div>
{% elif payment.status.endswith('-refunded') %}
<div style="background: #d1ecf1; border: 1px solid #bee5eb; border-radius: 3px; padding: 8px; margin-top: 10px;">
<div class="status-info-notice">
<small>
{% if payment.refund_tx_hash %}
💸 This payment was automatically refunded.
@ -123,7 +123,7 @@
</small>
</div>
{% elif payment.status == 'no-refund' %}
<div style="background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 3px; padding: 8px; margin-top: 10px;">
<div class="status-error-notice">
<small>
❌ No refund possible:
{% if payment.refund_reason %}
@ -138,9 +138,9 @@
{% endfor %}
</div>
<div style="margin-top: 30px; padding: 15px; background: #e9ecef; border-radius: 4px;">
<div class="crypto-help-section">
<h4>💡 About Crypto Payment History</h4>
<ul style="margin: 10px 0;">
<ul class="notice-list">
<li><strong>Successful payments</strong> create invoices and unlock your purchased products</li>
<li><strong>Failed payments</strong> are automatically refunded when possible (9% restocking fee applies)</li>
<li><strong>Out-of-stock refunds</strong> are issued in full since it wasn't your fault</li>
@ -149,7 +149,7 @@
</ul>
</div>
{% else %}
<div style="text-align: center; padding: 40px; color: #6c757d;">
<div class="crypto-empty-state">
<h3>No crypto payment history yet</h3>
<p>When you attempt crypto payments, they'll show up here.</p>
<a href="/" class="mps-button mps-button-blue">Start Shopping</a>

View file

@ -36,48 +36,48 @@
</table>
{% if invoice.coupon_redemptions and invoice.discount_amount_in_cents > 0 %}
<div style="text-align: right; margin: 15px 0;">
<div class="invoice-right-section">
{% for redemption in invoice.coupon_redemptions %}
<p style="color: #28a745; margin: 5px 0;">
<p class="status-success invoice-margin-small">
<strong>{{ redemption.coupon.code }}:</strong> {{ redemption.coupon.description }}
</p>
{% endfor %}
<p style="color: #28a745; margin: 5px 0;">
<p class="status-success invoice-margin-small">
<strong>Total Discounts: -${{ '%.2f' % (invoice.discount_amount_in_cents / 100) }}</strong>
</p>
</div>
{% endif %}
<div style="text-align: right; margin: 20px 0; font-size: 1.2em;">
<div class="invoice-total-section">
<strong>Invoice Total: ${{ '%.2f' % invoice.total }}</strong>
</div>
{% if invoice.crypto_payment and invoice.crypto_payment|length > 0 %}
{% set crypto_pay = invoice.crypto_payment[0] %}
<!-- Crypto Payment Details -->
<div style="background-color: #f0f8ff; padding: 15px; border: 1px solid #4169e1; border-radius: 5px; margin: 15px 0;">
<div class="invoice-payment-box">
<h3>Crypto Payment Information</h3>
<p><strong>Currency:</strong> {{ crypto_pay.coin_type }}</p>
<p><strong>Expected Amount:</strong> {{ '%.12f'|format(crypto_pay.expected_amount / (10**12 if crypto_pay.coin_type == 'XMR' else 10**8)) }} {{ crypto_pay.coin_type }}</p>
<p><strong>Received Amount:</strong> {{ '%.12f'|format(crypto_pay.received_amount / (10**12 if crypto_pay.coin_type == 'XMR' else 10**8)) }} {{ crypto_pay.coin_type }}</p>
{% if crypto_pay.status in ['confirmed', 'confirmed_overpaid'] %}
<p style="color: #28a745;"><strong>✓ Payment Confirmed</strong></p>
<p class="status-success"><strong>✓ Payment Confirmed</strong></p>
{% elif crypto_pay.status == 'received' %}
<p style="color: #ffc107;"><strong>⏳ Awaiting Confirmations ({{ crypto_pay.current_confirmations }}/{{ crypto_pay.confirmations_required }})</strong></p>
<p class="status-warning"><strong>⏳ Awaiting Confirmations ({{ crypto_pay.current_confirmations }}/{{ crypto_pay.confirmations_required }})</strong></p>
{% elif crypto_pay.status == 'pending' %}
<p style="color: #6c757d;"><strong>⏳ Waiting for Payment</strong></p>
<p class="status-info"><strong>⏳ Waiting for Payment</strong></p>
{% elif crypto_pay.status == 'expired' %}
<p style="color: #dc3545;"><strong>❌ Payment Expired</strong></p>
<p class="status-error"><strong>❌ Payment Expired</strong></p>
{% elif crypto_pay.status == 'underpaid_refunded' %}
<p style="color: #dc3545;"><strong>❌ Underpaid - Refunded</strong></p>
<p class="status-error"><strong>❌ Underpaid - Refunded</strong></p>
{% endif %}
{% if crypto_pay.tx_hashes and crypto_pay.tx_hashes != '[]' %}
<p><strong>Transaction(s):</strong> <code style="font-size: 0.9em; font-family: monospace;">{{ crypto_pay.tx_hashes }}</code></p>
<p><strong>Transaction(s):</strong> <code class="code-monospace">{{ crypto_pay.tx_hashes }}</code></p>
{% endif %}
<p style="margin-top: 15px;">
<p class="invoice-margin-section">
<strong>Payment ID:</strong> <a href="{{ request.route_url('crypto_quote', payment_id=crypto_pay.id) }}">{{ crypto_pay.id }}</a>
</p>
</div>