@@ -108,76 +108,121 @@
-
-
+
+
- Shipping & Contact
- Select shipping and provide your contact details
+ Shipping Information
+ Select your shipping zone
-
+
-
-
-
-
-
-
-
{{ zone.name }}
-
- {{ zone.countries?.join(', ') || 'Available' }}
-
- • No shipping required
-
-
-
- {{ zone.description }}
-
-
-
-
- {{ formatPrice(zone.cost, checkoutCart.currency) }}
-
-
shipping
-
+
+
+
+
+
{{ zone.name }}
+
+ {{ zone.countries?.join(', ') || 'Available' }}
+
+ • No shipping required
+
+
+
+ {{ zone.description }}
+
+
+
+
+ {{ formatPrice(zone.cost, checkoutCart.currency) }}
+
+
shipping
-
-
+
+
This merchant hasn't configured shipping zones yet.
Please contact the merchant for shipping information.
-
-
+
+
+
+
+
+
-
-
-
-
-
Required for physical delivery
+
+
+
+ Contact & Payment Information
+ Provide your details for order processing
+
+
+
+
+
+
+
+
Merchant may not use email
+
+
+
+
+
+
Different Npub for communication
+
+
+
+
+
+
+
+ {{ selectedShippingZone?.requiresPhysicalShipping !== false
+ ? 'Required for physical delivery'
+ : 'Optional for digital items or pickup' }}
+
-
-
-
-
-
-
- Additional contact info (optional)
-
-
-
-
-
-
-
Optional for digital items or pickup
+
+
+
+
+
-
-
-
-
-
-
Merchant may not use email
-
-
-
-
-
-
Different Npub for communication
-
-
-
-
-
-
-
- ⚡
- Payment via Lightning Network
+
-
-
- {{ orderValidationMessage }}
+
+ Shipping address is required for physical delivery
@@ -266,12 +279,12 @@ import { useRoute } from 'vue-router'
import { useMarketStore } from '@/modules/market/stores/market'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import { auth } from '@/composables/useAuthService'
-import {
- Card,
- CardHeader,
- CardTitle,
- CardDescription,
- CardContent
+import {
+ Card,
+ CardHeader,
+ CardTitle,
+ CardDescription,
+ CardContent
} from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
@@ -280,14 +293,8 @@ import { Label } from '@/components/ui/label'
import ProgressiveImage from '@/components/ui/image/ProgressiveImage.vue'
import {
Package,
- CheckCircle,
- ChevronDown
+ CheckCircle
} from 'lucide-vue-next'
-import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger
-} from '@/components/ui/collapsible'
const route = useRoute()
const marketStore = useMarketStore()
@@ -296,10 +303,11 @@ const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
// State
const isLoading = ref(true)
const error = ref
(null)
+const orderConfirmed = ref(false)
const orderPlaced = ref(false)
const isPlacingOrder = ref(false)
const selectedShippingZone = ref(null)
-const showOptionalContact = ref(false)
+const paymentMethod = ref('ln')
// Form data
const contactData = ref({
@@ -309,7 +317,12 @@ const contactData = ref({
message: ''
})
-// TODO: Add BTC Onchain and Cashu payment options in the future
+// Payment methods
+const paymentMethods = [
+ { label: 'Lightning Network', value: 'ln' },
+ { label: 'BTC Onchain', value: 'btc' },
+ { label: 'Cashu', value: 'cashu' }
+]
// Computed
const stallId = computed(() => route.params.stallId as string)
@@ -328,7 +341,7 @@ const currentStall = computed(() => {
const orderSubtotal = computed(() => {
if (!checkoutCart.value?.products) return 0
- return checkoutCart.value.products.reduce((total, item) =>
+ return checkoutCart.value.products.reduce((total, item) =>
total + (item.product.price * item.quantity), 0
)
})
@@ -342,22 +355,22 @@ const orderTotal = computed(() => {
// Get shipping zones from the current stall
const availableShippingZones = computed(() => {
if (!currentStall.value) return []
-
+
// Use standardized shipping property from domain model
const zones = currentStall.value.shipping || []
-
+
// Ensure zones have required properties and determine shipping requirements
return zones.map(zone => {
const zoneName = zone.name || 'Shipping Zone'
const lowerName = zoneName.toLowerCase()
-
+
// Determine if this zone requires physical shipping
- const requiresPhysicalShipping = zone.requiresPhysicalShipping !== false &&
- !lowerName.includes('digital') &&
- !lowerName.includes('pickup') &&
- !lowerName.includes('download') &&
+ const requiresPhysicalShipping = zone.requiresPhysicalShipping !== false &&
+ !lowerName.includes('digital') &&
+ !lowerName.includes('pickup') &&
+ !lowerName.includes('download') &&
zone.cost > 0 // Free usually means digital or pickup
-
+
return {
id: zone.id || zoneName.toLowerCase().replace(/\s+/g, '-'),
name: zoneName,
@@ -370,41 +383,26 @@ const availableShippingZones = computed(() => {
})
})
-// Determine if shipping address is required
-const requiresShippingAddress = computed(() => {
- return selectedShippingZone.value?.requiresPhysicalShipping !== false
-})
-
-// Validation for placing order
-const canPlaceOrder = computed(() => {
- // Must select shipping zone if zones are available
- if (availableShippingZones.value.length > 0 && !selectedShippingZone.value) {
- return false
- }
- // Must provide address if physical shipping is required
- if (requiresShippingAddress.value && !contactData.value.address) {
- return false
- }
- return true
-})
-
-const orderValidationMessage = computed(() => {
- if (availableShippingZones.value.length > 0 && !selectedShippingZone.value) {
- return 'Please select a shipping zone'
- }
- if (requiresShippingAddress.value && !contactData.value.address) {
- return 'Shipping address is required for physical delivery'
- }
- return ''
-})
-
// Methods
const selectShippingZone = (zone: any) => {
selectedShippingZone.value = zone
}
+const confirmOrder = () => {
+ // Allow proceeding if no shipping zones are available (e.g., for digital goods)
+ if (availableShippingZones.value.length > 0 && !selectedShippingZone.value) {
+ error.value = 'Please select a shipping zone'
+ return
+ }
+ orderConfirmed.value = true
+}
+
const placeOrder = async () => {
- if (!canPlaceOrder.value) {
+ // Only require shipping address if selected zone requires physical shipping
+ const requiresShippingAddress = selectedShippingZone.value?.requiresPhysicalShipping !== false
+
+ if (requiresShippingAddress && !contactData.value.address) {
+ error.value = 'Shipping address is required for this delivery method'
return
}
@@ -428,14 +426,14 @@ const placeOrder = async () => {
hasPubkey: !!authService.user.value?.pubkey,
nostrPubkey: authService.user.value?.pubkey
})
-
+
// Try to get pubkey from main auth first, fallback to auth service
const userPubkey = auth.currentUser.value?.pubkey || authService.user.value?.pubkey
-
+
if (!auth.isAuthenticated.value) {
throw new Error('You must be logged in to place an order')
}
-
+
if (!userPubkey) {
throw new Error('Nostr identity required: Please configure your Nostr public key in your profile settings to place orders.')
}
@@ -466,7 +464,7 @@ const placeOrder = async () => {
currency: checkoutCart.value.currency,
requiresPhysicalShipping: false
},
- paymentMethod: 'lightning' as const,
+ paymentMethod: paymentMethod.value === 'ln' ? 'lightning' as const : 'btc_onchain' as const,
subtotal: orderSubtotal.value,
shippingCost: selectedShippingZone.value?.cost || 0,
total: orderTotal.value,
@@ -475,13 +473,13 @@ const placeOrder = async () => {
}
console.log('Creating order:', orderData)
-
+
// Create and place the order via the market store
const order = await marketStore.createAndPlaceOrder(orderData)
-
+
console.log('Order placed successfully:', order)
orderPlaced.value = true
-
+
} catch (err) {
console.error('Failed to place order:', err)
error.value = err instanceof Error ? err.message : 'Failed to place order'
@@ -507,12 +505,12 @@ onMounted(() => {
if (!cart || cart.id !== stallId.value) {
error.value = 'No checkout data found for this stall'
}
-
+
// Auto-select shipping zone if there's only one
if (availableShippingZones.value.length === 1) {
selectedShippingZone.value = availableShippingZones.value[0]
}
-
+
isLoading.value = false
})
-
+
\ No newline at end of file
diff --git a/src/modules/market/views/MarketDashboard.vue b/src/modules/market/views/MarketDashboard.vue
index 44aac34..0a2b0f7 100644
--- a/src/modules/market/views/MarketDashboard.vue
+++ b/src/modules/market/views/MarketDashboard.vue
@@ -62,7 +62,6 @@