feat: payment status badge in listing-card, webhook debug info, UX fixes
This commit is contained in:
@@ -27,7 +27,14 @@ $invoiceId = $payload['invoiceId'] ?? null;
|
|||||||
|
|
||||||
if (!$type || !$invoiceId) {
|
if (!$type || !$invoiceId) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'Missing type or invoiceId']);
|
echo json_encode([
|
||||||
|
'error' => 'Missing type or invoiceId',
|
||||||
|
'received' => [
|
||||||
|
'type' => $type,
|
||||||
|
'invoiceId' => $invoiceId,
|
||||||
|
'keys' => array_keys($payload ?: []),
|
||||||
|
],
|
||||||
|
]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ let cachedRates = null
|
|||||||
|
|
||||||
class ListingCard extends HTMLElement {
|
class ListingCard extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['listing-id', 'title', 'price', 'currency', 'location', 'image', 'owner-id']
|
return ['listing-id', 'title', 'price', 'currency', 'location', 'image', 'owner-id', 'payment-status']
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -129,6 +129,13 @@ class ListingCard extends HTMLElement {
|
|||||||
</a>
|
</a>
|
||||||
` : ''
|
` : ''
|
||||||
|
|
||||||
|
const paymentStatus = this.getAttribute('payment-status')
|
||||||
|
const paymentBadge = paymentStatus === 'processing'
|
||||||
|
? /* html */`<span class="payment-badge payment-processing"><span class="pulse-dot"></span>${t('payment.awaitingConfirmation')}</span>`
|
||||||
|
: paymentStatus === 'pending'
|
||||||
|
? /* html */`<span class="payment-badge payment-pending">${t('payment.pending')}</span>`
|
||||||
|
: ''
|
||||||
|
|
||||||
this.innerHTML = /* html */`
|
this.innerHTML = /* html */`
|
||||||
${ownerBadge}
|
${ownerBadge}
|
||||||
<a href="#/listing/${escapeHTML(id)}" class="listing-link">
|
<a href="#/listing/${escapeHTML(id)}" class="listing-link">
|
||||||
@@ -136,6 +143,7 @@ class ListingCard extends HTMLElement {
|
|||||||
${image
|
${image
|
||||||
? `<img src="${escapeHTML(image)}" alt="${escapeHTML(title)}" loading="lazy">`
|
? `<img src="${escapeHTML(image)}" alt="${escapeHTML(title)}" loading="lazy">`
|
||||||
: placeholderSvg}
|
: placeholderSvg}
|
||||||
|
${paymentBadge}
|
||||||
</div>
|
</div>
|
||||||
<div class="listing-info">
|
<div class="listing-info">
|
||||||
<h3 class="listing-title">${escapeHTML(title)}</h3>
|
<h3 class="listing-title">${escapeHTML(title)}</h3>
|
||||||
@@ -220,6 +228,45 @@ style.textContent = /* css */`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
listing-card .payment-badge {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: var(--space-xs) var(--space-sm);
|
||||||
|
font-size: var(--font-size-xs);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
listing-card .payment-processing {
|
||||||
|
background: rgba(230, 167, 0, 0.9);
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
listing-card .payment-pending {
|
||||||
|
background: rgba(230, 167, 0, 0.9);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
listing-card .pulse-dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
background: #fff;
|
||||||
|
animation: card-pulse 1.5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes card-pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.3; }
|
||||||
}
|
}
|
||||||
|
|
||||||
listing-card .listing-image img {
|
listing-card .listing-image img {
|
||||||
|
|||||||
@@ -744,7 +744,25 @@ class PageCreate extends HTMLElement {
|
|||||||
})
|
})
|
||||||
|
|
||||||
clearPendingInvoice(listingId)
|
clearPendingInvoice(listingId)
|
||||||
router.navigate(`/listing/${listingId}`)
|
this.showPaymentSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
showPaymentSuccess() {
|
||||||
|
this.innerHTML = /* html */`
|
||||||
|
<div class="create-page">
|
||||||
|
<div class="payment-success">
|
||||||
|
<div class="success-icon">
|
||||||
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="12" cy="12" r="10"></circle>
|
||||||
|
<polyline points="12 6 12 12 16 14"></polyline>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h2>${t('payment.processing')}</h2>
|
||||||
|
<p>${t('payment.awaitingHint')}</p>
|
||||||
|
<a href="#/my-listings" class="btn btn-primary">${t('profile.myListings')}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
showError(message) {
|
showError(message) {
|
||||||
@@ -993,5 +1011,28 @@ style.textContent = /* css */`
|
|||||||
page-create .btn-link:hover {
|
page-create .btn-link:hover {
|
||||||
color: var(--color-primary-hover);
|
color: var(--color-primary-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page-create .payment-success {
|
||||||
|
text-align: center;
|
||||||
|
padding: var(--space-3xl) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
page-create .success-icon {
|
||||||
|
color: var(--color-warning, #e6a700);
|
||||||
|
margin-bottom: var(--space-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
page-create .payment-success h2 {
|
||||||
|
margin-bottom: var(--space-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
page-create .payment-success p {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: var(--space-xl);
|
||||||
|
max-width: 400px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
document.head.appendChild(style)
|
document.head.appendChild(style)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class PageListing extends HTMLElement {
|
|||||||
? new Date(this.listing.date_created).toLocaleDateString()
|
? new Date(this.listing.date_created).toLocaleDateString()
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
this.innerHTML = /* html */`
|
this.innerHTML = /* html */`
|
||||||
<article class="listing-detail">
|
<article class="listing-detail">
|
||||||
<!-- Two Column Layout -->
|
<!-- Two Column Layout -->
|
||||||
<div class="listing-layout">
|
<div class="listing-layout">
|
||||||
@@ -1000,7 +1000,7 @@ style.textContent = /* css */`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Payment Processing Badge */
|
/* Payment Processing Badge (sidebar) */
|
||||||
page-listing .payment-processing-card {
|
page-listing .payment-processing-card {
|
||||||
background: var(--color-bg-secondary);
|
background: var(--color-bg-secondary);
|
||||||
border: 1px solid var(--color-warning, #e6a700);
|
border: 1px solid var(--color-warning, #e6a700);
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ class PageMyListings extends HTMLElement {
|
|||||||
document.querySelector('auth-modal')?.show()
|
document.querySelector('auth-modal')?.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getStatusBadge(listing) {
|
||||||
|
if (listing.status === 'archived') {
|
||||||
|
return `<span class="status-badge status-archived">${t('myListings.status.archived')}</span>`
|
||||||
|
}
|
||||||
|
if (listing.status === 'draft' && listing.payment_status !== 'processing' && listing.payment_status !== 'pending') {
|
||||||
|
return `<span class="status-badge status-draft">${t('myListings.status.draft')}</span>`
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.innerHTML = /* html */`
|
this.innerHTML = /* html */`
|
||||||
<div class="my-listings-page">
|
<div class="my-listings-page">
|
||||||
@@ -136,9 +146,7 @@ class PageMyListings extends HTMLElement {
|
|||||||
const imageId = listing.images?.[0]?.directus_files_id?.id || listing.images?.[0]?.directus_files_id
|
const imageId = listing.images?.[0]?.directus_files_id?.id || listing.images?.[0]?.directus_files_id
|
||||||
const imageUrl = imageId ? directus.getThumbnailUrl(imageId, 300) : ''
|
const imageUrl = imageId ? directus.getThumbnailUrl(imageId, 300) : ''
|
||||||
const locationName = listing.location?.name || ''
|
const locationName = listing.location?.name || ''
|
||||||
const statusBadge = listing.status !== 'published'
|
const statusBadge = this.getStatusBadge(listing)
|
||||||
? `<span class="status-badge status-${listing.status}">${t(`myListings.status.${listing.status}`)}</span>`
|
|
||||||
: ''
|
|
||||||
|
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<div class="listing-wrapper">
|
<div class="listing-wrapper">
|
||||||
@@ -151,6 +159,7 @@ class PageMyListings extends HTMLElement {
|
|||||||
location="${escapeHTML(locationName)}"
|
location="${escapeHTML(locationName)}"
|
||||||
image="${imageUrl}"
|
image="${imageUrl}"
|
||||||
owner-id="${listing.user_created || ''}"
|
owner-id="${listing.user_created || ''}"
|
||||||
|
payment-status="${listing.payment_status || ''}"
|
||||||
></listing-card>
|
></listing-card>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -327,6 +327,7 @@ class DirectusService {
|
|||||||
'price',
|
'price',
|
||||||
'currency',
|
'currency',
|
||||||
'condition',
|
'condition',
|
||||||
|
'payment_status',
|
||||||
'date_created',
|
'date_created',
|
||||||
'user_created',
|
'user_created',
|
||||||
'images.directus_files_id.id',
|
'images.directus_files_id.id',
|
||||||
@@ -379,6 +380,7 @@ class DirectusService {
|
|||||||
'shipping',
|
'shipping',
|
||||||
'shipping_cost',
|
'shipping_cost',
|
||||||
'views',
|
'views',
|
||||||
|
'payment_status',
|
||||||
'expires_at',
|
'expires_at',
|
||||||
'monero_address',
|
'monero_address',
|
||||||
'date_created',
|
'date_created',
|
||||||
|
|||||||
Reference in New Issue
Block a user