diff --git a/js/components/pages/page-create.js b/js/components/pages/page-create.js index f3f43d3..3fecba8 100644 --- a/js/components/pages/page-create.js +++ b/js/components/pages/page-create.js @@ -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 { ${t('create.shippingAvailable')} - + +
+ + +
+
{ 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) { diff --git a/js/components/pages/page-listing.js b/js/components/pages/page-listing.js index 4ea58d8..50f7efc 100644 --- a/js/components/pages/page-listing.js +++ b/js/components/pages/page-listing.js @@ -193,6 +193,7 @@ class PageListing extends HTMLElement { ${this.listing.condition ? `${this.getConditionLabel(this.listing.condition)}` : ''} ${this.listing.shipping ? `📦 ${t('listing.shippingAvailable')}` : ''} 👁 ${this.formatViews(this.listing.views || 0)} + ${this.listing.expires_at ? `${this.formatExpiresAt(this.listing.expires_at)}` : ''} ${t('listing.postedOn')} ${createdDate}
@@ -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')}` diff --git a/locales/de.json b/locales/de.json index fb370b9..cc90532 100644 --- a/locales/de.json +++ b/locales/de.json @@ -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", diff --git a/locales/en.json b/locales/en.json index 607276f..b15b81a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -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", diff --git a/locales/fr.json b/locales/fr.json index 4553094..acbc0b0 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -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", diff --git a/service-worker.js b/service-worker.js index 7f37169..e0059a0 100644 --- a/service-worker.js +++ b/service-worker.js @@ -1,4 +1,4 @@ -const CACHE_NAME = 'dgray-v32'; +const CACHE_NAME = 'dgray-v34'; const STATIC_ASSETS = [ '/', '/index.html',