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',