// RideWidget.ts import { defineComponent, ref, computed, onMounted, watch } from 'vue'; import { useRouter } from 'vue-router'; import { Api } from '@api'; import type { Ride, ContribType } from '../../types/trasporti.types'; interface WidgetStats { offers: number; requests: number; matches: number; } interface WidgetData { stats: WidgetStats; recentRides: Ride[]; myActiveRides: Ride[]; pendingRequests: number; unreadMessages: number; } export default defineComponent({ name: 'RideWidget', props: { // Se vuoi che il widget parta espanso defaultExpanded: { type: Boolean, default: false }, // Numero massimo di ride da mostrare maxRides: { type: Number, default: 3 }, // Auto-refresh interval in ms (0 = disabled) refreshInterval: { type: Number, default: 60000 // 1 minuto } }, emits: ['loaded', 'error'], setup(props, { emit }) { const router = useRouter(); // State const isExpanded = ref(props.defaultExpanded); const loading = ref(false); const stats = ref({ offers: 0, requests: 0, matches: 0 }); const recentRides = ref([]); const myActiveRides = ref([]); const pendingRequests = ref(0); const unreadMessages = ref(0); // Computed const totalCount = computed(() => stats.value.offers + stats.value.requests); // Methods const toggleExpand = () => { isExpanded.value = !isExpanded.value; if (isExpanded.value && recentRides.value.length === 0) { loadWidgetData(); } }; const loadWidgetData = async () => { loading.value = true; try { const response = await Api.SendReqWithData('/api/trasporti/widget/data', 'GET', {}); if (response.success) { const data: WidgetData = response.data; stats.value = data.stats || { offers: 0, requests: 0, matches: 0 }; recentRides.value = data.recentRides || []; myActiveRides.value = data.myActiveRides || []; pendingRequests.value = data.pendingRequests || 0; unreadMessages.value = data.unreadMessages || 0; emit('loaded', data); } } catch (error) { console.error('Errore caricamento widget trasporti:', error); emit('error', error); } finally { loading.value = false; } }; const loadStats = async () => { try { const response = await Api.SendReqWithData('/api/trasporti/stats/summary', 'GET'); if (response.success) { stats.value = response.data; } } catch (error) { console.error('Errore caricamento stats:', error); } }; const formatDate = (date: string | Date): string => { const d = new Date(date); const now = new Date(); const diff = d.getTime() - now.getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) { return `Oggi, ${d.toLocaleTimeString('it-IT', { hour: '2-digit', minute: '2-digit' })}`; } else if (days === 1) { return `Domani, ${d.toLocaleTimeString('it-IT', { hour: '2-digit', minute: '2-digit' })}`; } else if (days > 1 && days <= 6) { return d.toLocaleDateString('it-IT', { weekday: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } else { return d.toLocaleDateString('it-IT', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }); } }; const getContribIcon = (contribution: any): string => { if (!contribution?.types?.length) return '💶'; const iconMap: Record = { 'Dono': '🎁', 'Offerta Libera': '💸', 'Baratto': '🤝', 'Scambio Lavoro': '💪', 'Monete Alternative': '🪙', 'RIS': '🍚', 'Euro': '💶', 'Bitcoin': '₿', 'Banca del Tempo': '⏳' }; const firstType = contribution.types[0]; return iconMap[firstType?.label] || '💶'; }; const getContribLabel = (contribution: any): string => { if (!contribution?.types?.length) return 'Gratuito'; const labels = contribution.types.map((t: ContribType) => t.label); return labels.join(', '); }; const getStatusColor = (status: string): string => { const colors: Record = { 'active': 'positive', 'pending': 'warning', 'completed': 'info', 'cancelled': 'negative' }; return colors[status] || 'grey'; }; const getStatusLabel = (status: string): string => { const labels: Record = { 'active': 'Attivo', 'pending': 'In attesa', 'completed': 'Completato', 'cancelled': 'Annullato' }; return labels[status] || status; }; // Navigation const goToCreate = (type: 'offer' | 'request') => { router.push({ path: '/trasporti/crea', query: { type } }); }; const goToList = () => { router.push('/trasporti'); }; const goToRide = (rideId: string) => { router.push(`/trasporti/ride/${rideId}`); }; const goToMyRides = () => { router.push('/trasporti/rides/my'); }; const goToSearch = () => { router.push('/trasporti/cerca'); }; const goToMap = () => { router.push('/trasporti/mappa'); }; const goToHistory = () => { router.push('/trasporti/storico'); }; const goToChat = () => { router.push('/trasporti/chat'); }; // Auto-refresh let refreshTimer: ReturnType | null = null; const startAutoRefresh = () => { if (props.refreshInterval > 0) { refreshTimer = setInterval(() => { if (isExpanded.value) { loadWidgetData(); } else { loadStats(); } }, props.refreshInterval); } }; const stopAutoRefresh = () => { if (refreshTimer) { clearInterval(refreshTimer); refreshTimer = null; } }; // Lifecycle onMounted(() => { loadStats(); if (props.defaultExpanded) { loadWidgetData(); } startAutoRefresh(); }); // Cleanup watch(() => props.refreshInterval, () => { stopAutoRefresh(); startAutoRefresh(); }); return { // State isExpanded, loading, stats, recentRides, myActiveRides, pendingRequests, unreadMessages, // Computed totalCount, // Methods toggleExpand, formatDate, getContribIcon, getContribLabel, getStatusColor, getStatusLabel, // Navigation goToCreate, goToList, goToRide, goToMyRides, goToSearch, goToMap, goToHistory, goToChat }; } });