fix: auto-set expires_at to 30 days, add expiry display on listing page, add shipping_cost field

This commit is contained in:
2026-02-04 15:15:23 +01:00
parent 71d59f274c
commit 3a7413e59a
6 changed files with 72 additions and 6 deletions

View File

@@ -34,6 +34,7 @@ class PageCreate extends HTMLElement {
condition: 'good',
location: '',
shipping: false,
shipping_cost: '',
moneroAddress: ''
}
}
@@ -103,6 +104,7 @@ class PageCreate extends HTMLElement {
condition: listing.condition || 'good',
location: listing.location?.id || listing.location || '',
shipping: listing.shipping || false,
shipping_cost: listing.shipping_cost?.toString() || '',
moneroAddress: listing.monero_address || '',
status: listing.status || 'published'
}
@@ -286,7 +288,21 @@ class PageCreate extends HTMLElement {
<span>${t('create.shippingAvailable')}</span>
</label>
</div>
<div class="form-group shipping-cost-group" id="shipping-cost-group" style="display: ${this.formData.shipping ? 'block' : 'none'}">
<label class="label" for="shipping_cost">${t('create.shippingCost')}</label>
<input
type="number"
class="input"
id="shipping_cost"
name="shipping_cost"
min="0"
step="0.01"
value="${this.formData.shipping_cost || ''}"
placeholder="${t('create.shippingCostPlaceholder')}"
>
</div>
<div class="form-group">
<label class="label" for="location" data-i18n="create.location">${t('create.location')}</label>
<location-picker
@@ -375,10 +391,14 @@ class PageCreate extends HTMLElement {
})
})
// Checkbox handler
// Checkbox handler with shipping cost toggle
const shippingCheckbox = this.querySelector('#shipping')
const shippingCostGroup = this.querySelector('#shipping-cost-group')
shippingCheckbox?.addEventListener('change', (e) => {
this.formData.shipping = e.target.checked
if (shippingCostGroup) {
shippingCostGroup.style.display = e.target.checked ? 'block' : 'none'
}
this.saveDraft()
})
@@ -488,6 +508,7 @@ class PageCreate extends HTMLElement {
category: form.querySelector('#category')?.value || '',
condition: form.querySelector('#condition')?.value || 'good',
shipping: form.querySelector('#shipping')?.checked || false,
shipping_cost: form.querySelector('#shipping_cost')?.value || '',
moneroAddress: form.querySelector('#moneroAddress')?.value || ''
}
@@ -540,7 +561,18 @@ class PageCreate extends HTMLElement {
if (formElements.category) listingData.category = formElements.category
if (formElements.condition) listingData.condition = formElements.condition
listingData.shipping = formElements.shipping
if (formElements.shipping && formElements.shipping_cost) {
listingData.shipping_cost = parseFloat(formElements.shipping_cost)
}
if (formElements.moneroAddress) listingData.monero_address = formElements.moneroAddress
// Calculate expires_at (only on create) - 30 days for regular users, 60 for power users
if (!this.editMode) {
const days = 30 // TODO: 60 for power users
const expiresAt = new Date()
expiresAt.setDate(expiresAt.getDate() + days)
listingData.expires_at = expiresAt.toISOString()
}
// Handle location - find or create in locations collection
if (this.formData.locationData) {

View File

@@ -193,6 +193,7 @@ class PageListing extends HTMLElement {
${this.listing.condition ? `<span class="meta-item">${this.getConditionLabel(this.listing.condition)}</span>` : ''}
${this.listing.shipping ? `<span class="meta-item">📦 ${t('listing.shippingAvailable')}</span>` : ''}
<span class="meta-item views-item"><span class="views-icon">👁</span> ${this.formatViews(this.listing.views || 0)}</span>
${this.listing.expires_at ? `<span class="meta-item expires-item">${this.formatExpiresAt(this.listing.expires_at)}</span>` : ''}
<span class="meta-item meta-date">${t('listing.postedOn')} ${createdDate}</span>
</div>
</header>
@@ -527,6 +528,24 @@ class PageListing extends HTMLElement {
return labels[condition] || condition
}
formatExpiresAt(expiresAt) {
const expires = new Date(expiresAt)
const now = new Date()
const diffMs = expires - now
if (diffMs <= 0) {
return `${t('listing.expired')}`
}
const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24))
if (diffDays === 1) {
return `${t('listing.expiresIn1Day')}`
}
return `${t('listing.expiresInDays', { days: diffDays })}`
}
formatViews(count) {
if (count === 1) {
return `1 ${t('listing.viewSingular')}`

View File

@@ -140,7 +140,10 @@
"share": "Teilen",
"report": "Melden",
"moreFromSeller": "Weitere Anzeigen des Anbieters",
"edit": "Bearbeiten"
"edit": "Bearbeiten",
"expired": "Abgelaufen",
"expiresIn1Day": "Noch 1 Tag gültig",
"expiresInDays": "Noch {{days}} Tage gültig"
},
"chat": {
"title": "Nachricht senden",
@@ -169,6 +172,8 @@
"priceModeXmr": "XMR-Preis fix",
"priceModeHint": "Fiat-fix: Der Fiat-Betrag bleibt gleich. XMR-fix: Der XMR-Betrag bleibt gleich.",
"shippingAvailable": "Versand möglich",
"shippingCost": "Versandkosten",
"shippingCostPlaceholder": "z.B. 5.00",
"location": "Standort",
"locationPlaceholder": "Stadt, PLZ oder Adresse",
"locationHint": "Wähle den Standort für deine Anzeige",

View File

@@ -140,7 +140,10 @@
"share": "Share",
"report": "Report",
"moreFromSeller": "More from this seller",
"edit": "Edit"
"edit": "Edit",
"expired": "Expired",
"expiresIn1Day": "1 day left",
"expiresInDays": "{{days}} days left"
},
"chat": {
"title": "Send Message",
@@ -169,6 +172,8 @@
"priceModeXmr": "XMR price fixed",
"priceModeHint": "Fiat-fixed: The fiat amount stays the same. XMR-fixed: The XMR amount stays the same.",
"shippingAvailable": "Shipping available",
"shippingCost": "Shipping cost",
"shippingCostPlaceholder": "e.g. 5.00",
"location": "Location",
"locationPlaceholder": "City, ZIP or address",
"locationHint": "Choose the location for your listing",

View File

@@ -140,7 +140,10 @@
"share": "Partager",
"report": "Signaler",
"moreFromSeller": "Autres annonces du vendeur",
"edit": "Modifier"
"edit": "Modifier",
"expired": "Expiré",
"expiresIn1Day": "Encore 1 jour",
"expiresInDays": "Encore {{days}} jours"
},
"chat": {
"title": "Envoyer un message",
@@ -169,6 +172,8 @@
"priceModeXmr": "Prix XMR fixe",
"priceModeHint": "Fiat-fixe: Le montant fiat reste le même. XMR-fixe: Le montant XMR reste le même.",
"shippingAvailable": "Livraison disponible",
"shippingCost": "Frais de livraison",
"shippingCostPlaceholder": "ex. 5.00",
"location": "Emplacement",
"locationPlaceholder": "Ville, code postal ou adresse",
"locationHint": "Choisissez l'emplacement de votre annonce",

View File

@@ -1,4 +1,4 @@
const CACHE_NAME = 'dgray-v32';
const CACHE_NAME = 'dgray-v34';
const STATIC_ASSETS = [
'/',
'/index.html',