- invita amico

This commit is contained in:
Surya Paolo
2025-11-19 10:09:45 +01:00
parent 05dc22dac6
commit 05a3617103
10 changed files with 1496 additions and 1211 deletions

View File

@@ -1202,7 +1202,10 @@
</CShareSocial>
</q-dialog>
<q-dialog v-model="mostraInviti" maximized>
<q-card style="min-width: 350px; max-width: 600px">
<q-card :style="{
minWidth: '350px',
maxWidth: $q.screen.lt.sm ? '100vw' : '800px',
}">
<!-- Header con bottone chiudi -->
<q-bar class="bg-primary text-white">
<q-space />

View File

@@ -4,6 +4,7 @@
justify-content: center;
min-height: 120vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@media (max-width: $breakpoint-sm-max) {
min-height: 100vh;
}
@@ -52,20 +53,17 @@
overflow: hidden;
}
// Bottoni selezione metodo
.selection-buttons {
display: flex;
gap: 16px;
gap: 12px;
flex-wrap: wrap;
@media (max-width: $breakpoint-xs-max) {
flex-direction: column;
}
justify-content: stretch;
}
.selection-btn {
flex: 1;
min-height: 180px;
flex: 0 1 calc(33.33% - 8px); // Desktop: max 1/3 dello spazio, non cresce
min-width: 140px;
min-height: 140px;
border-radius: 12px;
border: 2px solid #e0e0e0;
background: white;
@@ -82,7 +80,8 @@
}
@media (max-width: $breakpoint-xs-max) {
min-height: 120px;
flex: 0 1 calc(50% - 6px); // Mobile: max 50%, 2 per riga
min-height: 130px;
}
}
@@ -91,10 +90,7 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px;
padding: 8px;
width: 100%;
text-align: center;
@media (max-width: 768px) {
padding: 8px 24px;
}
}

View File

@@ -4,9 +4,11 @@ import { useInvitaAmicoStore } from '../../stores/useInvitaAmicoStore';
import type { InvitoAmicoForm } from '../../types/invita-amico.types.ts';
import { tools } from 'app/src/store/Modules/tools';
import { useI18n } from 'vue-i18n';
import { shared_consts } from '@src/common/shared_vuejs';
// Chiave localStorage
const MESSAGGIO_STORAGE_KEY = 'invita-amico-messaggio-personalizzato';
const MESSAGGIO_STORAGE_KEY = 'invita-amico-email';
const MESSAGGIO_STORAGE_KEY_WHATSAPP = 'invita-amico-whatsapp';
export default defineComponent({
name: 'InvitaAmico',
@@ -19,9 +21,12 @@ export default defineComponent({
const { t } = useI18n();
const invitaStore = useInvitaAmicoStore();
const rismsgShareLink = ref({ body: '', title: '' });
// State
const mostraCronologia = ref(false);
const metodoSelezionato = ref<'email' | 'telegram' | null>(null);
const metodoSelezionato = ref<'email' | 'telegram' | 'whatsapp' | null>(null);
const form = reactive<InvitoAmicoForm & { usernameInvitante?: string }>({
email: '',
messaggio: '',
@@ -122,6 +127,72 @@ export default defineComponent({
}
};
/**
* Gestione invio WhatsApp (con Share API fallback)
*/
const onInviaWhatsApp = async () => {
const messaggioBase = form.messaggio;
if (form.messaggio) {
localStorage.setItem(MESSAGGIO_STORAGE_KEY_WHATSAPP, form.messaggio.trim());
}
// Prova prima con Share API (mobile)
if (navigator.share) {
try {
await navigator.share({
title: 'Progetto RISO',
text: messaggioBase,
});
$q.notify({
type: 'positive',
message: 'Messaggio condiviso! 📤',
icon: 'share',
timeout: 2000,
});
return;
} catch (err) {
// Utente ha annullato o errore, prova WhatsApp diretto
}
}
// Fallback: apri WhatsApp diretto
const messaggioCodificato = encodeURIComponent(messaggioBase);
window.open(`https://wa.me/?text=${messaggioCodificato}`, '_blank');
$q.notify({
type: 'positive',
message: 'WhatsApp aperto! 💬',
icon: 'whatsapp',
timeout: 2000,
});
};
/**
* Copia messaggio negli appunti
*/
const copiaMessaggio = async () => {
const messaggioDaCopiare = form.messaggio;
try {
await navigator.clipboard.writeText(messaggioDaCopiare);
$q.notify({
type: 'positive',
message: 'Messaggio copiato! 📋',
caption: 'Ora incollalo dove preferisci',
icon: 'content_copy',
timeout: 2000,
});
} catch (err) {
$q.notify({
type: 'negative',
message: 'Errore nella copia',
icon: 'error',
timeout: 2000,
});
}
};
/**
* Conferma eliminazione cronologia
*/
@@ -168,19 +239,68 @@ export default defineComponent({
};
// Carica messaggio all'apertura
onMounted(() => {
onMounted(async () => {
// ricevi il msg
rismsgShareLink.value = await invitaStore.ottieniMsg(
shared_consts.TypeMsgTemplate.MSG_INVITE_WHATSAPP
);
const salvato = localStorage.getItem(MESSAGGIO_STORAGE_KEY);
const salvatowa = localStorage.getItem(MESSAGGIO_STORAGE_KEY_WHATSAPP);
if (salvato) {
form.messaggio = salvato;
if (metodoSelezionato.value === 'whatsapp') {
form.messaggio = salvatowa;
} else {
form.messaggio = salvato;
}
} else {
if (rismsgShareLink.value) {
form.messaggio = rismsgShareLink.value.body;
}
}
});
// Cancella
const cancellaMessaggioSalvato = () => {
localStorage.removeItem(MESSAGGIO_STORAGE_KEY);
form.messaggio = '';
if (metodoSelezionato.value === 'whatsapp') {
localStorage.removeItem(MESSAGGIO_STORAGE_KEY_WHATSAPP);
} else {
localStorage.removeItem(MESSAGGIO_STORAGE_KEY);
}
$q.notify({ type: 'info', message: 'Messaggio cancellato' });
};
const ripristinaMessaggioStandard = () => {
$q.dialog({
title: 'Conferma',
message: 'Vuoi ripristinare il messaggio standard?',
persistent: false,
ok: {
label: 'Sì',
color: 'primary',
},
cancel: {
label: 'No',
flat: true,
},
}).onOk(() => {
form.messaggio = '';
if (metodoSelezionato.value === 'whatsapp') {
localStorage.removeItem(MESSAGGIO_STORAGE_KEY_WHATSAPP);
if (rismsgShareLink.value) {
form.messaggio = rismsgShareLink.value.body;
}
} else {
localStorage.removeItem(MESSAGGIO_STORAGE_KEY);
}
$q.notify({
type: 'info',
message: 'Messaggio standard ripristinato',
icon: 'restore',
});
});
};
// RETURN
return {
@@ -191,10 +311,13 @@ export default defineComponent({
form,
onInviaEmail,
onInviaTelegram,
onInviaWhatsApp,
copiaMessaggio,
confermaEliminaCronologia,
formatDate,
invitaStore,
cancellaMessaggioSalvato,
ripristinaMessaggioStandard,
tools,
};
},

View File

@@ -20,7 +20,7 @@
<!-- Schermata Selezione Metodo -->
<q-card-section v-if="!metodoSelezionato">
<div class="text-center q-mb-lg">
<div class="text-h6 text-grey-8 q-mb-xs">Come vuoi invitare?</div>
<div class="text-h7 text-grey-8 q-mb-xs">Come vuoi invitare?</div>
</div>
<div class="selection-buttons">
@@ -33,13 +33,10 @@
<div class="selection-btn-content">
<q-icon
name="email"
size="48px"
size="40px"
color="primary"
/>
<div class="text-h6 q-mt-xs text-grey-9">Email</div>
<div class="text-caption text-grey-7">
Invia un invito diretto via email
</div>
<div class="text-h7 q-mt-xs text-grey-9">Email</div>
</div>
</q-btn>
@@ -52,13 +49,25 @@
<div class="selection-btn-content">
<q-icon
name="telegram"
size="48px"
size="40px"
color="blue-9"
/>
<div class="text-h6 q-mt-md text-grey-9">Telegram</div>
<div class="text-caption text-grey-7">
Condividi tramite Telegram
</div>
<div class="text-h7 q-mt-md text-grey-9">Telegram</div>
</div>
</q-btn>
<q-btn
@click="selezionaMetodo('whatsapp')"
class="selection-btn"
unelevated
no-caps
>
<div class="selection-btn-content">
<q-icon
name="fab fa-whatsapp"
size="40px"
color="green-7"
/>
<div class="text-h7 q-mt-md text-grey-9">WhatsApp o altri</div>
</div>
</q-btn>
</div>
@@ -68,8 +77,8 @@
<q-card-section v-if="metodoSelezionato === 'email'">
<div class="q-mb-md">
<q-btn
flat
dense
outline
icon="arrow_back"
label="Cambia metodo"
color="grey-7"
@@ -121,7 +130,7 @@
outlined
:rows="tools.isMobile() ? 6 : 9"
counter
maxlength="500"
maxlength="2000"
:disable="invitaStore.loading"
>
<!-- Bottone per cancellare messaggio salvato -->
@@ -164,7 +173,7 @@
icon="email"
color="primary"
size="lg"
class="full-width q-mt-md"
class="full-width q-my-md"
outline
:loading="invitaStore.loading"
:disable="invitaStore.loading || !form.email"
@@ -185,12 +194,7 @@
/>
</div>
<div class="text-center q-mb-md">
<div class="text-subtitle1 text-grey-8 q-mb-xs">
Invita tramite Telegram
</div>
<div class="text-caption text-grey-7">
Genera un messaggio da condividere su Telegram
</div>
<div class="text-subtitle1 text-grey-8 q-mb-xs">Invita tramite Telegram</div>
</div>
<q-btn
@@ -199,12 +203,92 @@
icon="telegram"
color="blue-9"
size="lg"
class="full-width"
class="full-width q-my-sm"
outline
:disable="invitaStore.loading"
/>
</q-card-section>
<!-- Sezione WhatsApp (mostrata solo se selezionata) -->
<q-card-section v-if="metodoSelezionato === 'whatsapp'">
<div class="q-mb-md">
<q-btn
outline
dense
icon="arrow_back"
label="Cambia metodo"
color="grey-7"
size="sm"
@click="tornaAllaScelta"
/>
</div>
<div class="text-center q-mb-md">
<div class="text-subtitle1 text-grey-8 q-mb-xs">Invita tramite WhatsApp</div>
</div>
<!-- Messaggio Personalizzato (opzionale) -->
<q-input
v-model="form.messaggio"
type="textarea"
label="Messaggio personalizzato (opzionale)"
hint="Aggiungi un messaggio personale al tuo invito"
outlined
:rows="tools.isMobile() ? 6 : 9"
counter
maxlength="2000"
>
<!-- Bottone per cancellare messaggio salvato -->
<template
v-slot:append
>
<q-btn
v-if="form.messaggio"
flat
dense
round
icon="clear"
@click.stop="cancellaMessaggioSalvato"
>
<q-tooltip>Cancella messaggio salvato</q-tooltip>
</q-btn>
<q-btn
dense
round
icon="undo"
@click.stop="ripristinaMessaggioStandard"
>
<q-tooltip>Ripristina messaggio standard</q-tooltip>
</q-btn>
</template>
<template v-slot:prepend>
<q-icon name="message" />
</template>
</q-input>
<!-- Bottone WhatsApp principale -->
<q-btn
@click="onInviaWhatsApp"
label="Apri WhatsApp"
icon="fab fa-whatsapp"
color="green-7"
class="full-width q-my-sm"
unelevated
:disable="invitaStore.loading || !form.messaggio"
/>
<!-- Bottone alternativo: Copia -->
<q-btn
@click="copiaMessaggio"
label="Copia messaggio"
icon="content_copy"
color="primary"
size="md"
class="full-width"
outline
/>
</q-card-section>
<!-- Info Section (solo per Telegram) -->
<q-card-section
v-if="metodoSelezionato === 'telegram'"
@@ -225,7 +309,11 @@
</q-card-section>
<!-- Cronologia Inviti (opzionale) -->
<q-card-section v-if="invitaStore.hasCronologia && mostraCronologia">
<q-card-section
v-if="
metodoSelezionato === 'email' && invitaStore.hasCronologia && mostraCronologia
"
>
<div class="text-subtitle2 text-grey-8 q-mb-sm">
<q-icon
name="history"
@@ -299,7 +387,7 @@
<!-- Stats Badge -->
<div
v-if="invitaStore.totaleInviti > 0"
v-if="metodoSelezionato === 'email' && invitaStore.totaleInviti > 0"
class="stats-badge q-mt-md"
>
<q-chip
@@ -321,7 +409,13 @@
</q-chip>-->
</div>
<!-- Bottone per mostrare cronologia -->
<q-card-section v-if="invitaStore.hasCronologia && !mostraCronologia">
<q-card-section
v-if="
metodoSelezionato === 'email' &&
invitaStore.hasCronologia &&
!mostraCronologia
"
>
<q-btn
flat
dense