Files
myprojplanet_vite/src/modules/trasporti/components/widgets/RideWidget.ts
2025-12-22 23:39:42 +01:00

287 lines
6.9 KiB
TypeScript

// 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<WidgetStats>({
offers: 0,
requests: 0,
matches: 0
});
const recentRides = ref<Ride[]>([]);
const myActiveRides = ref<Ride[]>([]);
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<string, string> = {
'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<string, string> = {
'active': 'positive',
'pending': 'warning',
'completed': 'info',
'cancelled': 'negative'
};
return colors[status] || 'grey';
};
const getStatusLabel = (status: string): string => {
const labels: Record<string, string> = {
'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<typeof setInterval> | 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
};
}
});