// stores/useInvitaAmicoStore.ts import { defineStore } from 'pinia'; import { ref, computed } from 'vue'; import type { InvitoAmicoForm, InvitoAmicoRequest, InvitoAmicoResponse, } from '../types/invita-amico.types.ts'; import { useUserStore } from '../store/index.js'; import { Api } from '../store/Api/index.js'; /** * Store Pinia per la gestione degli inviti amici * Gestisce lo stato, le chiamate API e la cronologia degli inviti */ export const useInvitaAmicoStore = defineStore('invitaAmico', () => { // ========================================== // STATE // ========================================== // Loading state const loading = ref(false); // Errori const error = ref(null); // Ultimo invito inviato con successo const ultimoInvitoInviato = ref<{ email: string; data: Date; successo: boolean; } | null>(null); // Cronologia inviti (ultimi 10) const cronologiaInviti = ref< Array<{ id: string; email: string; usernameInvitante?: string; messaggio?: string; data: Date; successo: boolean; errore?: string; }> >([]); // Contatori const contatoreInvitiRiusciti = ref(0); const contatoreInvitiFalliti = ref(0); // ========================================== // GETTERS // ========================================== /** * Verifica se ci sono inviti in cronologia */ const hasCronologia = computed(() => cronologiaInviti.value.length > 0); /** * Numero totale di inviti */ const totaleInviti = computed( () => contatoreInvitiRiusciti.value + contatoreInvitiFalliti.value ); /** * Percentuale successo inviti */ const percentualeSuccesso = computed(() => { if (totaleInviti.value === 0) return 0; return Math.round((contatoreInvitiRiusciti.value / totaleInviti.value) * 100); }); /** * Ultimi 5 inviti */ const ultimi5Inviti = computed(() => cronologiaInviti.value.slice(0, 5)); /** * Verifica se un'email è già stata invitata (nelle ultime 24h) */ const isEmailGiaInvitata = computed(() => (email: string) => { const now = new Date(); const oreIndietro24 = new Date(now.getTime() - 24 * 60 * 60 * 1000); return cronologiaInviti.value.some( (invito) => invito.email.toLowerCase() === email.toLowerCase() && invito.data > oreIndietro24 && invito.successo ); }); // ========================================== // ACTIONS // ========================================== /** * Invia un invito via email */ const inviaInvitoEmail = async ( idapp: string, emailAmico: string, messaggioPersonalizzato?: string ): Promise => { // Reset errori error.value = null; loading.value = true; const userStore = useUserStore(); let usernameInvitante = userStore.my.username; try { // Validazione email if (!emailAmico || !isValidEmail(emailAmico)) { throw new Error('Email non valida'); } // Check se già invitata recentemente if (isEmailGiaInvitata.value(emailAmico)) { throw new Error('Questa email è già stata invitata nelle ultime 24 ore'); } // Prepara request const requestBody: InvitoAmicoRequest = { emailAmico, messaggioPersonalizzato, usernameInvitante, }; // Chiamata API const response = await Api.SendReq('/inviti/invia-email', 'POST', requestBody); if (!response.data) { throw new Error("Errore durante l'invio"); } const data: InvitoAmicoResponse = response.data; if (data.success) { // Aggiorna stato successo ultimoInvitoInviato.value = { email: emailAmico, data: new Date(), successo: true, }; // Incrementa contatore contatoreInvitiRiusciti.value++; // Aggiungi a cronologia aggiungiACronologia({ email: emailAmico, usernameInvitante, messaggio: messaggioPersonalizzato, successo: true, }); return data; } else { throw new Error(data.message || 'Invio fallito'); } } catch (err) { // Gestione errori const errorMessage = err instanceof Error ? err.message : 'Errore sconosciuto'; error.value = errorMessage; // Incrementa contatore fallimenti contatoreInvitiFalliti.value++; // Aggiungi a cronologia come fallito aggiungiACronologia({ email: emailAmico, usernameInvitante, messaggio: messaggioPersonalizzato, successo: false, errore: errorMessage, }); // Ritorna risposta di errore return { success: false, message: errorMessage, emailInviata: false, }; } finally { loading.value = false; } }; /** * Invia invito via Telegram * (placeholder - integra con la tua logica esistente) */ const inviaInvitoTelegram = async (messaggio?: string): Promise => { loading.value = true; error.value = null; try { // TODO: Integra con la tua logica Telegram esistente // Esempio: // await telegramBotService.sendMessage(messaggio); console.log('Invio via Telegram:', messaggio); // Simula invio await new Promise((resolve) => setTimeout(resolve, 1000)); return true; } catch (err) { error.value = err instanceof Error ? err.message : 'Errore invio Telegram'; return false; } finally { loading.value = false; } }; /** * Aggiunge un invito alla cronologia */ const aggiungiACronologia = (invito: { email: string; usernameInvitante?: string; messaggio?: string; successo: boolean; errore?: string; }) => { const nuovoInvito = { id: generateId(), ...invito, data: new Date(), }; // Aggiungi in testa cronologiaInviti.value.unshift(nuovoInvito); // Mantieni solo gli ultimi 10 if (cronologiaInviti.value.length > 10) { cronologiaInviti.value = cronologiaInviti.value.slice(0, 10); } // Salva in localStorage salvaInLocalStorage(); }; /** * Cancella un invito dalla cronologia */ const rimuoviDaCronologia = (id: string) => { cronologiaInviti.value = cronologiaInviti.value.filter((invito) => invito.id !== id); salvaInLocalStorage(); }; /** * Cancella tutta la cronologia */ const svuotaCronologia = () => { cronologiaInviti.value = []; salvaInLocalStorage(); }; /** * Reset dello stato */ const resetStato = () => { loading.value = false; error.value = null; ultimoInvitoInviato.value = null; }; /** * Reset contatori */ const resetContatori = () => { contatoreInvitiRiusciti.value = 0; contatoreInvitiFalliti.value = 0; localStorage.removeItem('invita-amico-contatori'); }; /** * Carica dati da localStorage */ const caricaDaLocalStorage = () => { try { // Carica cronologia const cronologiaSalvata = localStorage.getItem('invita-amico-cronologia'); if (cronologiaSalvata) { const parsed = JSON.parse(cronologiaSalvata); // Converte stringhe date in oggetti Date cronologiaInviti.value = parsed.map((invito: any) => ({ ...invito, data: new Date(invito.data), })); } // Carica contatori const contatoriSalvati = localStorage.getItem('invita-amico-contatori'); if (contatoriSalvati) { const parsed = JSON.parse(contatoriSalvati); contatoreInvitiRiusciti.value = parsed.riusciti || 0; contatoreInvitiFalliti.value = parsed.falliti || 0; } } catch (err) { console.error('Errore caricamento localStorage:', err); } }; /** * Salva dati in localStorage */ const salvaInLocalStorage = () => { try { // Salva cronologia localStorage.setItem( 'invita-amico-cronologia', JSON.stringify(cronologiaInviti.value) ); // Salva contatori localStorage.setItem( 'invita-amico-contatori', JSON.stringify({ riusciti: contatoreInvitiRiusciti.value, falliti: contatoreInvitiFalliti.value, }) ); } catch (err) { console.error('Errore salvataggio localStorage:', err); } }; // ========================================== // UTILITY // ========================================== /** * Validazione email */ const isValidEmail = (email: string): boolean => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; /** * Genera ID univoco */ const generateId = (): string => { return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; }; // ========================================== // INIZIALIZZAZIONE // ========================================== // Carica dati all'avvio caricaDaLocalStorage(); // ========================================== // RETURN // ========================================== return { // State loading, error, ultimoInvitoInviato, cronologiaInviti, contatoreInvitiRiusciti, contatoreInvitiFalliti, // Getters hasCronologia, totaleInviti, percentualeSuccesso, ultimi5Inviti, isEmailGiaInvitata, // Actions inviaInvitoEmail, inviaInvitoTelegram, aggiungiACronologia, rimuoviDaCronologia, svuotaCronologia, resetStato, resetContatori, caricaDaLocalStorage, salvaInLocalStorage, // Utility isValidEmail, }; });