- Sistemato INVITI alla App

- Completamento Profilo
- Registrazione tramite Invito, senza richiedere conferma email.
This commit is contained in:
Surya Paolo
2025-11-18 23:56:08 +01:00
parent fc569192e7
commit 4985e7565d
98 changed files with 2209 additions and 3595720 deletions

View File

@@ -2,17 +2,21 @@
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
min-height: 120vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@media (max-width: $breakpoint-sm-max) {
min-height: 100vh;
}
}
.invita-amico-card {
max-width: 600px;
max-width: 800px;
width: 100%;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
@media (max-width: $breakpoint-sm-max) {
max-width: 600px;
margin: 0;
border-radius: 0;
}
@@ -47,3 +51,50 @@
border-radius: 8px;
overflow: hidden;
}
// Bottoni selezione metodo
.selection-buttons {
display: flex;
gap: 16px;
flex-wrap: wrap;
@media (max-width: $breakpoint-xs-max) {
flex-direction: column;
}
}
.selection-btn {
flex: 1;
min-height: 180px;
border-radius: 12px;
border: 2px solid #e0e0e0;
background: white;
transition: all 0.3s ease;
&:hover {
border-color: var(--q-primary);
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.2);
transform: translateY(-4px);
}
&:active {
transform: translateY(-2px);
}
@media (max-width: $breakpoint-xs-max) {
min-height: 120px;
}
}
.selection-btn-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px;
width: 100%;
text-align: center;
@media (max-width: 768px) {
padding: 8px 24px;
}
}

View File

@@ -3,6 +3,7 @@ import { useQuasar } from 'quasar';
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';
// Chiave localStorage
const MESSAGGIO_STORAGE_KEY = 'invita-amico-messaggio-personalizzato';
@@ -15,10 +16,12 @@ export default defineComponent({
setup(props, { emit }) {
// Composables
const $q = useQuasar();
const { t } = useI18n();
const invitaStore = useInvitaAmicoStore();
// State
const mostraCronologia = ref(false);
const metodoSelezionato = ref<'email' | 'telegram' | null>(null);
const form = reactive<InvitoAmicoForm & { usernameInvitante?: string }>({
email: '',
messaggio: '',
@@ -29,6 +32,20 @@ export default defineComponent({
// METHODS
// ==========================================
/**
* Seleziona il metodo di invio (email o telegram)
*/
const selezionaMetodo = (metodo: 'email' | 'telegram') => {
metodoSelezionato.value = metodo;
};
/**
* Torna alla schermata di scelta iniziale
*/
const tornaAllaScelta = () => {
metodoSelezionato.value = null;
};
/**
* Invia invito via email usando lo store Pinia
*/
@@ -51,7 +68,7 @@ export default defineComponent({
message: 'Invito inviato con successo! 🎉',
caption: `L'email è stata inviata a ${form.email}`,
icon: 'check_circle',
timeout: 3000,
timeout: 7000,
actions: [
{
label: 'Vedi cronologia',
@@ -86,14 +103,14 @@ export default defineComponent({
const onInviaTelegram = async () => {
emit('telegram-click');
const success = await invitaStore.inviaInvitoTelegram(form.messaggio);
const success = await invitaStore.inviaInvitoTelegram($q, t);
if (success) {
$q.notify({
type: 'positive',
message: 'Messaggio inviato via Telegram! ✈️',
icon: 'telegram',
timeout: 2000,
timeout: 4000,
});
} else {
$q.notify({
@@ -122,7 +139,7 @@ export default defineComponent({
type: 'info',
message: 'Cronologia cancellata',
icon: 'delete',
timeout: 2000,
timeout: 3000,
});
});
};
@@ -168,6 +185,9 @@ export default defineComponent({
// RETURN
return {
mostraCronologia,
metodoSelezionato,
selezionaMetodo,
tornaAllaScelta,
form,
onInviaEmail,
onInviaTelegram,

View File

@@ -12,47 +12,78 @@
/>
Invita un Amico
</div>
<div class="text-subtitle2">Condividi la nostra app con i tuoi amici!</div>
<!-- Stats Badge -->
<div
v-if="invitaStore.totaleInviti > 0"
class="stats-badge q-mt-md"
>
<q-chip
color="white"
text-color="primary"
icon="email"
class="q-mx-xs"
>
{{ invitaStore.contatoreInvitiRiusciti }} inviati
</q-chip>
<!--<q-chip
v-if="invitaStore.percentualeSuccesso > 0"
color="white"
text-color="primary"
icon="trending_up"
class="q-mx-xs"
>
{{ invitaStore.percentualeSuccesso }}% successo
</q-chip>-->
</div>
<div class="text-subtitle2">Condividi la app con i tuoi amici!</div>
</q-card-section>
<q-separator />
<!-- Form Section -->
<q-card-section>
<q-form
@submit="onInviaEmail"
class="q-gutter-md"
>
<!-- 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>
<div class="selection-buttons">
<q-btn
@click="selezionaMetodo('email')"
class="selection-btn"
unelevated
no-caps
>
<div class="selection-btn-content">
<q-icon
name="email"
size="48px"
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>
</q-btn>
<q-btn
@click="selezionaMetodo('telegram')"
class="selection-btn"
unelevated
no-caps
>
<div class="selection-btn-content">
<q-icon
name="telegram"
size="48px"
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>
</q-btn>
</div>
</q-card-section>
<!-- Sezione Email (mostrata solo se selezionata) -->
<q-card-section v-if="metodoSelezionato === 'email'">
<div class="q-mb-md">
<q-btn
flat
dense
icon="arrow_back"
label="Cambia metodo"
color="grey-7"
size="sm"
@click="tornaAllaScelta"
/>
</div>
<q-form @submit="onInviaEmail">
<!-- Email Input -->
<q-input
v-model="form.email"
type="email"
label="Email del tuo amico *"
hint="Inserisci l'indirizzo email della persona che vuoi invitare"
label="Email della tua persona amica *"
lazy-rules
:rules="[
(val) => !!val || 'L\'email è obbligatoria',
@@ -86,10 +117,9 @@
<q-input
v-model="form.messaggio"
type="textarea"
label="Messaggio personalizzato (opzionale)"
hint="Aggiungi un messaggio personale al tuo invito"
label="Messaggio personale (opzionale)"
outlined
rows="3"
:rows="tools.isMobile() ? 6 : 9"
counter
maxlength="500"
:disable="invitaStore.loading"
@@ -113,17 +143,6 @@
<q-icon name="message" />
</template>
</q-input>
<!-- Info che viene salvato -->
<div
v-if="form.messaggio"
class="text-caption text-grey-6"
>
<q-icon
name="info"
size="xs"
/>
Questo messaggio sarà riutilizzato nei prossimi inviti
</div>
<!-- Alert errore -->
<q-banner
@@ -145,23 +164,31 @@
icon="email"
color="primary"
size="lg"
class="full-width"
class="full-width q-mt-md"
outline
:loading="invitaStore.loading"
:disable="invitaStore.loading || !form.email"
unelevated
/>
</q-form>
</q-card-section>
<q-separator inset />
<!-- Sezione Telegram -->
<q-card-section>
<!-- Sezione Telegram (mostrata solo se selezionata) -->
<q-card-section v-if="metodoSelezionato === 'telegram'">
<div class="q-mb-md">
<q-btn
dense
icon="arrow_back"
label="Cambia metodo"
size="sm"
outline
@click="tornaAllaScelta"
/>
</div>
<div class="text-center q-mb-md">
<div class="text-subtitle1 text-grey-8 q-mb-xs">
Oppure invita tramite Telegram
Invita tramite Telegram
</div>
<div class="text-caption text-grey-6">
<div class="text-caption text-grey-7">
Genera un messaggio da condividere su Telegram
</div>
</div>
@@ -178,8 +205,11 @@
/>
</q-card-section>
<!-- Info Section -->
<q-card-section class="bg-blue-1">
<!-- Info Section (solo per Telegram) -->
<q-card-section
v-if="metodoSelezionato === 'telegram'"
class="bg-blue-1"
>
<div class="text-center">
<q-icon
name="info"
@@ -188,7 +218,8 @@
class="q-mr-xs"
/>
<span class="text-grey-8">
Riceverai sul {{ tools.getBotName() }} il messaggio da inoltrare alla persona amica.
Riceverai sul {{ tools.getBotName() }} il messaggio da inoltrare alla
persona amica.
</span>
</div>
</q-card-section>
@@ -266,6 +297,29 @@
</div>
</q-card-section>
<!-- Stats Badge -->
<div
v-if="invitaStore.totaleInviti > 0"
class="stats-badge q-mt-md"
>
<q-chip
color="white"
text-color="primary"
icon="email"
class="q-mx-xs"
>
{{ invitaStore.contatoreInvitiRiusciti }} inviati
</q-chip>
<!--<q-chip
v-if="invitaStore.percentualeSuccesso > 0"
color="white"
text-color="primary"
icon="trending_up"
class="q-mx-xs"
>
{{ invitaStore.percentualeSuccesso }}% successo
</q-chip>-->
</div>
<!-- Bottone per mostrare cronologia -->
<q-card-section v-if="invitaStore.hasCronologia && !mostraCronologia">
<q-btn