- aggiornata la grafica della Home di RISO
- Profilo Completition - Email Verificata - Invita un Amico (invio di email)
This commit is contained in:
37
src/components/InviteFriend/InviteFriend.scss
Normal file
37
src/components/InviteFriend/InviteFriend.scss
Normal file
@@ -0,0 +1,37 @@
|
||||
.invita-amico-page {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.invita-amico-card {
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
|
||||
|
||||
@media (max-width: $breakpoint-sm-max) {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.q-card__section--vert {
|
||||
padding: 24px;
|
||||
|
||||
@media (max-width: $breakpoint-xs-max) {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// Animazioni
|
||||
.q-btn {
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
96
src/components/InviteFriend/InviteFriend.ts
Normal file
96
src/components/InviteFriend/InviteFriend.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { ref, reactive } from 'vue';
|
||||
import { useQuasar } from 'quasar';
|
||||
import type { InvitoAmicoForm, InvitoAmicoResponse } from './invita-amico.types';
|
||||
|
||||
// Composables
|
||||
const $q = useQuasar();
|
||||
|
||||
// State
|
||||
const loading = ref(false);
|
||||
const form = reactive<InvitoAmicoForm>({
|
||||
email: '',
|
||||
messaggio: ''
|
||||
});
|
||||
|
||||
// Emit events (se necessario per comunicare con il parent component)
|
||||
const emit = defineEmits<{
|
||||
(e: 'invito-inviato', data: InvitoAmicoResponse): void;
|
||||
(e: 'telegram-click'): void;
|
||||
}>();
|
||||
|
||||
// Validation
|
||||
const isValidEmail = (email: string): boolean => {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
};
|
||||
|
||||
// Invia invito via email
|
||||
const onInviaEmail = async () => {
|
||||
if (!form.email || !isValidEmail(form.email)) {
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: 'Inserisci un\'email valida',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await fetch('/inviti/invia-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
emailAmico: form.email,
|
||||
messaggioPersonalizzato: form.messaggio || undefined
|
||||
})
|
||||
});
|
||||
|
||||
const data: InvitoAmicoResponse = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Invito inviato con successo! 🎉',
|
||||
caption: `L'email è stata inviata a ${form.email}`,
|
||||
icon: 'check_circle',
|
||||
timeout: 3000
|
||||
});
|
||||
|
||||
// Reset form
|
||||
form.email = '';
|
||||
form.messaggio = '';
|
||||
|
||||
// Emit event
|
||||
emit('invito-inviato', data);
|
||||
} else {
|
||||
throw new Error(data.message || 'Errore nell\'invio dell\'invito');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Errore invio invito:', error);
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: 'Errore nell\'invio dell\'invito',
|
||||
caption: error instanceof Error ? error.message : 'Riprova più tardi',
|
||||
icon: 'error',
|
||||
timeout: 5000
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Gestione click Telegram (usa la funzione esistente del parent)
|
||||
const onInviaTelegram = () => {
|
||||
emit('telegram-click');
|
||||
|
||||
$q.notify({
|
||||
type: 'info',
|
||||
message: 'Apertura Telegram...',
|
||||
icon: 'telegram',
|
||||
timeout: 2000
|
||||
});
|
||||
};
|
||||
121
src/components/InviteFriend/InviteFriend.vue
Normal file
121
src/components/InviteFriend/InviteFriend.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<q-page class="invita-amico-page">
|
||||
<div class="q-pa-md">
|
||||
<q-card class="invita-amico-card">
|
||||
<!-- Header -->
|
||||
<q-card-section class="bg-primary text-white text-center">
|
||||
<div class="text-h5 q-mb-xs">
|
||||
<q-icon name="person_add" size="md" class="q-mr-sm" />
|
||||
Invita un Amico
|
||||
</div>
|
||||
<div class="text-subtitle2">
|
||||
Condividi la nostra app con i tuoi amici!
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator />
|
||||
|
||||
<!-- Form Section -->
|
||||
<q-card-section>
|
||||
<q-form @submit="onInviaEmail" class="q-gutter-md">
|
||||
<!-- 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"
|
||||
lazy-rules
|
||||
:rules="[
|
||||
val => !!val || 'L\'email è obbligatoria',
|
||||
val => isValidEmail(val) || 'Inserisci un\'email valida'
|
||||
]"
|
||||
outlined
|
||||
:disable="loading"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="email" />
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<!-- 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="3"
|
||||
counter
|
||||
maxlength="500"
|
||||
:disable="loading"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="message" />
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<!-- Bottone Invio Email -->
|
||||
<q-btn
|
||||
type="submit"
|
||||
label="Invia Invito via Email"
|
||||
icon="send"
|
||||
color="primary"
|
||||
size="lg"
|
||||
class="full-width"
|
||||
:loading="loading"
|
||||
:disable="loading || !form.email"
|
||||
unelevated
|
||||
/>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator inset />
|
||||
|
||||
<!-- Sezione Telegram -->
|
||||
<q-card-section>
|
||||
<div class="text-center q-mb-md">
|
||||
<div class="text-subtitle1 text-grey-8 q-mb-xs">
|
||||
Oppure invita tramite Telegram
|
||||
</div>
|
||||
<div class="text-caption text-grey-6">
|
||||
Genera un messaggio da condividere su Telegram
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-btn
|
||||
@click="onInviaTelegram"
|
||||
label="Invia via Telegram"
|
||||
icon="telegram"
|
||||
color="blue-9"
|
||||
size="lg"
|
||||
class="full-width"
|
||||
outline
|
||||
:disable="loading"
|
||||
>
|
||||
<template v-slot:default>
|
||||
<q-icon name="img:/images/telegram-icon.svg" size="24px" class="q-mr-sm" />
|
||||
Invia via Telegram
|
||||
</template>
|
||||
</q-btn>
|
||||
</q-card-section>
|
||||
|
||||
<!-- Info Section -->
|
||||
<q-card-section class="bg-blue-1">
|
||||
<div class="text-center">
|
||||
<q-icon name="info" color="primary" size="sm" class="q-mr-xs" />
|
||||
<span class="text-caption text-grey-8">
|
||||
Il tuo amico riceverà un link per registrarsi all'app
|
||||
</span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" src="./InviteFriend.ts">
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './InviteFriend.scss';
|
||||
</style>
|
||||
1
src/components/InviteFriend/index.ts
Normal file
1
src/components/InviteFriend/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {default as InviteFriend} from './InviteFriend.vue'
|
||||
Reference in New Issue
Block a user