- Introduce chat module with components, services, and composables for real-time messaging. - Implement events module with API service, components, and ticket purchasing functionality. - Update app configuration to include new modules and their respective settings. - Refactor existing components to integrate with the new chat and events features. - Enhance market store and services to support new functionalities and improve order management. - Update routing to accommodate new views for chat and events, ensuring seamless navigation.
311 lines
11 KiB
Vue
311 lines
11 KiB
Vue
<template>
|
|
<div class="space-y-6">
|
|
<!-- Stats Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<!-- Total Orders -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-muted-foreground">Total Orders</p>
|
|
<p class="text-2xl font-bold text-foreground">{{ orderStats.total }}</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-primary/10 rounded-lg flex items-center justify-center">
|
|
<Package class="w-6 h-6 text-primary" />
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<div class="flex items-center text-sm text-muted-foreground">
|
|
<span>{{ orderStats.pending }} pending</span>
|
|
<span class="mx-2">•</span>
|
|
<span>{{ orderStats.paid }} paid</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pending Payments -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-muted-foreground">Pending Payments</p>
|
|
<p class="text-2xl font-bold text-foreground">{{ orderStats.pendingPayments }}</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-yellow-500/10 rounded-lg flex items-center justify-center">
|
|
<DollarSign class="w-6 h-6 text-yellow-500" />
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<div class="flex items-center text-sm text-muted-foreground">
|
|
<span>Total: {{ formatPrice(orderStats.pendingAmount, 'sat') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Sales (Merchant) -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-muted-foreground">Recent Sales</p>
|
|
<p class="text-2xl font-bold text-foreground">{{ orderStats.recentSales }}</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-green-500/10 rounded-lg flex items-center justify-center">
|
|
<Store class="w-6 h-6 text-green-500" />
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<div class="flex items-center text-sm text-muted-foreground">
|
|
<span>Last 7 days</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Market Activity -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-muted-foreground">Market Activity</p>
|
|
<p class="text-2xl font-bold text-foreground">{{ orderStats.active }}</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-purple-500/10 rounded-lg flex items-center justify-center">
|
|
<BarChart3 class="w-6 h-6 text-purple-500" />
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<div class="flex items-center text-sm text-muted-foreground">
|
|
<span>{{ orderStats.connected ? 'Connected' : 'Disconnected' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Customer Actions -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<h3 class="text-lg font-semibold text-foreground mb-4 flex items-center gap-2">
|
|
<ShoppingCart class="w-5 h-5 text-primary" />
|
|
Customer Actions
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<Button
|
|
@click="navigateToMarket"
|
|
variant="default"
|
|
class="w-full justify-start"
|
|
>
|
|
<Store class="w-4 h-4 mr-2" />
|
|
Browse Market
|
|
</Button>
|
|
<Button
|
|
@click="navigateToOrders"
|
|
variant="outline"
|
|
class="w-full justify-start"
|
|
>
|
|
<Package class="w-4 h-4 mr-2" />
|
|
View All Orders
|
|
</Button>
|
|
<Button
|
|
@click="navigateToCart"
|
|
variant="outline"
|
|
class="w-full justify-start"
|
|
>
|
|
<ShoppingCart class="w-4 h-4 mr-2" />
|
|
Shopping Cart
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Merchant Actions -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<h3 class="text-lg font-semibold text-foreground mb-4 flex items-center gap-2">
|
|
<Store class="w-5 h-5 text-green-500" />
|
|
Merchant Actions
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<Button
|
|
@click="navigateToStore"
|
|
variant="default"
|
|
class="w-full justify-start"
|
|
>
|
|
<Store class="w-4 h-4 mr-2" />
|
|
Manage Store
|
|
</Button>
|
|
<Button
|
|
@click="navigateToProducts"
|
|
variant="outline"
|
|
class="w-full justify-start"
|
|
>
|
|
<Package class="w-4 h-4 mr-2" />
|
|
Manage Products
|
|
</Button>
|
|
<Button
|
|
@click="navigateToOrders"
|
|
variant="outline"
|
|
class="w-full justify-start"
|
|
>
|
|
<Package class="w-4 h-4 mr-2" />
|
|
View Orders
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Activity -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<h3 class="text-lg font-semibold text-foreground mb-4">Recent Activity</h3>
|
|
<div v-if="recentActivity.length > 0" class="space-y-3">
|
|
<div
|
|
v-for="activity in recentActivity"
|
|
:key="activity.id"
|
|
class="flex items-center justify-between p-3 bg-muted rounded-lg"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-8 h-8 bg-primary/10 rounded-full flex items-center justify-center">
|
|
<component :is="getActivityIcon(activity.type)" class="w-4 h-4 text-primary" />
|
|
</div>
|
|
<div>
|
|
<p class="text-sm font-medium text-foreground">{{ activity.title }}</p>
|
|
<p class="text-xs text-muted-foreground">{{ formatDate(activity.timestamp) }}</p>
|
|
</div>
|
|
</div>
|
|
<Badge :variant="getActivityVariant(activity.type)">
|
|
{{ activity.status }}
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
<div v-else class="text-center py-8 text-muted-foreground">
|
|
<Package class="w-12 h-12 mx-auto mb-3 text-muted-foreground/50" />
|
|
<p>No recent activity</p>
|
|
<p class="text-sm">Start shopping or selling to see activity here</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Market Status -->
|
|
<div class="bg-card p-6 rounded-lg border shadow-sm">
|
|
<h3 class="text-lg font-semibold text-foreground mb-4">Market Status</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-3 h-3 rounded-full"
|
|
:class="orderEvents.isSubscribed ? 'bg-green-500' : 'bg-yellow-500'"
|
|
></div>
|
|
<span class="text-sm text-muted-foreground">
|
|
Order Events: {{ orderEvents.isSubscribed ? 'Connected' : 'Connecting...' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-3 h-3 rounded-full"
|
|
:class="isConnected ? 'bg-green-500' : 'bg-red-500'"
|
|
></div>
|
|
<span class="text-sm text-muted-foreground">
|
|
Market: {{ isConnected ? 'Connected' : 'Disconnected' }}
|
|
</span>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<div
|
|
class="w-3 h-3 rounded-full"
|
|
:class="auth.isAuthenticated ? 'bg-green-500' : 'bg-red-500'"
|
|
></div>
|
|
<span class="text-sm text-muted-foreground">
|
|
Auth: {{ auth.isAuthenticated ? 'Authenticated' : 'Not Authenticated' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useMarketStore } from '@/stores/market'
|
|
import { useAuth } from '@/composables/useAuth'
|
|
import { useMarket } from '@/composables/useMarket'
|
|
import { useOrderEvents } from '@/composables/useOrderEvents'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Badge } from '@/components/ui/badge'
|
|
import {
|
|
Package,
|
|
Store,
|
|
ShoppingCart,
|
|
DollarSign,
|
|
BarChart3,
|
|
Clock
|
|
} from 'lucide-vue-next'
|
|
|
|
const router = useRouter()
|
|
const marketStore = useMarketStore()
|
|
const auth = useAuth()
|
|
const { isConnected } = useMarket()
|
|
const orderEvents = useOrderEvents()
|
|
|
|
// Computed properties
|
|
const orderStats = computed(() => {
|
|
const orders = Object.values(marketStore.orders)
|
|
const now = Date.now() / 1000
|
|
const sevenDaysAgo = now - (7 * 24 * 60 * 60)
|
|
|
|
return {
|
|
total: orders.length,
|
|
pending: orders.filter(o => o.status === 'pending').length,
|
|
paid: orders.filter(o => o.status === 'paid').length,
|
|
pendingPayments: orders.filter(o => o.paymentStatus === 'pending').length,
|
|
pendingAmount: orders
|
|
.filter(o => o.paymentStatus === 'pending')
|
|
.reduce((sum, o) => sum + o.total, 0),
|
|
recentSales: orders.filter(o =>
|
|
o.status === 'paid' && o.createdAt > sevenDaysAgo
|
|
).length,
|
|
active: orders.filter(o =>
|
|
['pending', 'paid', 'processing'].includes(o.status)
|
|
).length,
|
|
connected: false
|
|
}
|
|
})
|
|
|
|
const recentActivity = computed(() => {
|
|
const orders = Object.values(marketStore.orders)
|
|
const now = Date.now() / 1000
|
|
const recentOrders = orders
|
|
.filter(o => o.updatedAt > now - (24 * 60 * 60)) // Last 24 hours
|
|
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
.slice(0, 5)
|
|
|
|
return recentOrders.map(order => ({
|
|
id: order.id,
|
|
type: 'order',
|
|
title: `Order ${order.id.slice(-8)} - ${order.status}`,
|
|
status: order.status,
|
|
timestamp: order.updatedAt
|
|
}))
|
|
})
|
|
|
|
// Methods
|
|
const formatPrice = (price: number, currency: string) => {
|
|
return `${price} ${currency}`
|
|
}
|
|
|
|
const formatDate = (timestamp: number) => {
|
|
return new Date(timestamp * 1000).toLocaleString()
|
|
}
|
|
|
|
const getActivityIcon = (type: string) => {
|
|
switch (type) {
|
|
case 'order': return Package
|
|
default: return Clock
|
|
}
|
|
}
|
|
|
|
const getActivityVariant = (type: string) => {
|
|
switch (type) {
|
|
case 'order': return 'secondary'
|
|
default: return 'outline'
|
|
}
|
|
}
|
|
|
|
const navigateToMarket = () => router.push('/market')
|
|
const navigateToOrders = () => router.push('/market-dashboard?tab=orders')
|
|
const navigateToCart = () => router.push('/cart')
|
|
const navigateToStore = () => router.push('/market-dashboard?tab=store')
|
|
const navigateToProducts = () => router.push('/market-dashboard?tab=store')
|
|
</script>
|
|
|