- Implementazione TRASPORTI ! Passo 1
This commit is contained in:
286
src/modules/trasporti/components/widgets/RideWidget.ts
Normal file
286
src/modules/trasporti/components/widgets/RideWidget.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
// 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.SendReq('/api/trasporti/widget/data', 'GET', {});
|
||||
|
||||
if (response.success) {
|
||||
const data: WidgetData = response.data.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.SendReq('/api/trasporti/stats/summary', 'GET');
|
||||
|
||||
if (response.success) {
|
||||
stats.value = response.data.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
|
||||
};
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user