feat: Add contact information section to AboutCreator.vue and integrate phone/email updates in ProfilePage.vue

This commit is contained in:
2025-04-24 04:08:25 -04:00
parent c1c1f30b37
commit cc3df49848
2 changed files with 124 additions and 15 deletions

View File

@@ -100,6 +100,19 @@
'rounded-xl': !videoUrl && !isEditMode 'rounded-xl': !videoUrl && !isEditMode
}]" }]"
/> />
<!-- Contact Information Section -->
<div v-if="phoneNumber || email" class="contact-info mt-6">
<!-- Phone Number -->
<div v-if="phoneNumber" class="contact-item">
{{ phoneNumber }}
</div>
<!-- Email -->
<div v-if="email" class="contact-item">
{{ email }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -127,6 +140,8 @@ const showEditButtons = ref(false);
// Variables réactives pour les données // Variables réactives pour les données
const description = ref(""); const description = ref("");
const videoUrl = ref(""); const videoUrl = ref("");
const phoneNumber = ref("");
const email = ref("");
const imageUrls = ref([]); const imageUrls = ref([]);
const albumId = ref(null); const albumId = ref(null);
const originalPhotos = ref([]); const originalPhotos = ref([]);
@@ -134,6 +149,8 @@ const originalPhotos = ref([]);
// Editable fields // Editable fields
const editableDescription = ref(""); const editableDescription = ref("");
const editableVideoUrl = ref(""); const editableVideoUrl = ref("");
const editablePhoneNumber = ref("");
const editableEmail = ref("");
const videoUrlError = ref(""); const videoUrlError = ref("");
// Computed property to check if there are images // Computed property to check if there are images
@@ -176,6 +193,8 @@ function toggleEditMode() {
// Charger les valeurs pour l'édition // Charger les valeurs pour l'édition
editableDescription.value = description.value; editableDescription.value = description.value;
editableVideoUrl.value = videoUrl.value; editableVideoUrl.value = videoUrl.value;
editablePhoneNumber.value = phoneNumber.value;
editableEmail.value = email.value;
videoUrlError.value = ""; videoUrlError.value = "";
} }
} }
@@ -215,6 +234,8 @@ onMounted(async () => {
description.value = brandingStore.value.presentation.description || ""; description.value = brandingStore.value.presentation.description || "";
videoUrl.value = brandingStore.value.presentation.videoUrl || ""; videoUrl.value = brandingStore.value.presentation.videoUrl || "";
phoneNumber.value = brandingStore.value.presentation.phoneNumber || "";
email.value = brandingStore.value.presentation.email || "";
// Fetch album data // Fetch album data
await fetchAlbumData(); await fetchAlbumData();
@@ -244,13 +265,17 @@ async function saveChanges() {
`/api/creators/${creatorProfileStore.creator.id}/presentation-infos`, `/api/creators/${creatorProfileStore.creator.id}/presentation-infos`,
{ {
description: editableDescription.value || "", description: editableDescription.value || "",
videoUrl: editableVideoUrl.value || "" videoUrl: editableVideoUrl.value || "",
phoneNumber: editablePhoneNumber.value || "",
email: editableEmail.value || ""
} }
); );
// Mettre à jour les valeurs locales pour refléter les changements // Mettre à jour les valeurs locales pour refléter les changements
description.value = editableDescription.value; description.value = editableDescription.value;
videoUrl.value = extractVideoId(editableVideoUrl.value) || ""; videoUrl.value = extractVideoId(editableVideoUrl.value) || "";
phoneNumber.value = editablePhoneNumber.value;
email.value = editableEmail.value;
// Save album photos if they've changed // Save album photos if they've changed
if (imageUrls.value.length > 0) { if (imageUrls.value.length > 0) {
@@ -329,6 +354,8 @@ function cancelEdit() {
// Restaurer les valeurs d'origine // Restaurer les valeurs d'origine
editableDescription.value = description.value; editableDescription.value = description.value;
editableVideoUrl.value = videoUrl.value; editableVideoUrl.value = videoUrl.value;
editablePhoneNumber.value = phoneNumber.value;
editableEmail.value = email.value;
// Désactiver le mode édition // Désactiver le mode édition
isEditMode.value = false; isEditMode.value = false;
@@ -371,6 +398,14 @@ function cancelEdit() {
max-height: 38vh; max-height: 38vh;
} }
} }
.contact-info {
@apply flex flex-col items-center;
}
.contact-item {
@apply text-lg text-center mb-2 font-semibold;
}
</style> </style>
<i18n> <i18n>
@@ -383,7 +418,8 @@ function cancelEdit() {
"sections": { "sections": {
"about": { "about": {
"title": "About", "title": "About",
"description": "Description" "description": "Description",
"contactInfo": "Contact Information"
}, },
"photos": { "photos": {
"title": "Photos", "title": "Photos",
@@ -391,7 +427,9 @@ function cancelEdit() {
} }
}, },
"fields": { "fields": {
"videoUrl": "Video URL" "videoUrl": "Video URL",
"phoneNumber": "Phone Number",
"email": "Email"
}, },
"validation": { "validation": {
"invalidYoutubeUrl": "Please enter a valid YouTube URL or video ID" "invalidYoutubeUrl": "Please enter a valid YouTube URL or video ID"
@@ -406,7 +444,8 @@ function cancelEdit() {
"sections": { "sections": {
"about": { "about": {
"title": "À propos", "title": "À propos",
"description": "Description" "description": "Description",
"contactInfo": "Informations de contact"
}, },
"photos": { "photos": {
"title": "Photos", "title": "Photos",
@@ -414,7 +453,9 @@ function cancelEdit() {
} }
}, },
"fields": { "fields": {
"videoUrl": "URL de la vidéo" "videoUrl": "URL de la vidéo",
"phoneNumber": "Numéro de téléphone",
"email": "Email"
}, },
"validation": { "validation": {
"invalidYoutubeUrl": "Veuillez entrer une URL YouTube ou un ID de vidéo valide" "invalidYoutubeUrl": "Veuillez entrer une URL YouTube ou un ID de vidéo valide"
@@ -429,7 +470,8 @@ function cancelEdit() {
"sections": { "sections": {
"about": { "about": {
"title": "Acerca de", "title": "Acerca de",
"description": "Descripción" "description": "Descripción",
"contactInfo": "Información de contacto"
}, },
"photos": { "photos": {
"title": "Fotos", "title": "Fotos",
@@ -437,7 +479,9 @@ function cancelEdit() {
} }
}, },
"fields": { "fields": {
"videoUrl": "URL del video" "videoUrl": "URL del video",
"phoneNumber": "Número de teléfono",
"email": "Correo electrónico"
}, },
"validation": { "validation": {
"invalidYoutubeUrl": "Por favor, introduce una URL de YouTube o un ID de video válido" "invalidYoutubeUrl": "Por favor, introduce una URL de YouTube o un ID de video válido"

View File

@@ -2,6 +2,7 @@
import {ref, markRaw} from 'vue'; import {ref, markRaw} from 'vue';
import {useCreatorProfileStore} from '@/stores/creatorProfileStore.js'; import {useCreatorProfileStore} from '@/stores/creatorProfileStore.js';
import {useUserProfileStore} from "@/stores/userProfileStore.js"; import {useUserProfileStore} from "@/stores/userProfileStore.js";
import {useClient} from '@/plugins/api.js';
import SocialsDialog from './creators/SocialsDialog.vue'; import SocialsDialog from './creators/SocialsDialog.vue';
import AliasDialog from "@/views/profile/account/AliasDialog.vue"; import AliasDialog from "@/views/profile/account/AliasDialog.vue";
import FullnameDialog from "@/views/profile/account/FullnameDialog.vue"; import FullnameDialog from "@/views/profile/account/FullnameDialog.vue";
@@ -10,6 +11,8 @@ import ChangeStripeIdDialog from '@/views/profile/creators/ChangeStripeIdDialog.
import ChangeNameDialog from '@/views/profile/creators/ChangeNameDialog.vue'; import ChangeNameDialog from '@/views/profile/creators/ChangeNameDialog.vue';
import ChangeSlugDialog from '@/views/profile/creators/ChangeSlugDialog.vue'; import ChangeSlugDialog from '@/views/profile/creators/ChangeSlugDialog.vue';
import ChangeTitleDialog from '@/views/profile/creators/ChangeTitleDialog.vue'; import ChangeTitleDialog from '@/views/profile/creators/ChangeTitleDialog.vue';
import ChangePhoneDialog from '@/views/profile/creators/ChangePhoneDialog.vue';
import ChangeEmailDialog from '@/views/profile/creators/ChangeEmailDialog.vue';
import Youtube from "@/views/svg/Youtube.vue"; import Youtube from "@/views/svg/Youtube.vue";
import Web from "@/views/svg/Web.vue"; import Web from "@/views/svg/Web.vue";
import Reddit from "@/views/svg/Reddit.vue"; import Reddit from "@/views/svg/Reddit.vue";
@@ -25,6 +28,7 @@ const {t} = useI18n();
const userProfileStore = useUserProfileStore() const userProfileStore = useUserProfileStore()
const creatorProfileStore = useCreatorProfileStore(); const creatorProfileStore = useCreatorProfileStore();
const baseURL = window.location.origin; const baseURL = window.location.origin;
const client = useClient();
// ### Fullname // ### Fullname
const dialogEditFullnameShown = ref(false) const dialogEditFullnameShown = ref(false)
@@ -86,6 +90,8 @@ const componentsMap = {
ChangeNameDialog: markRaw(ChangeNameDialog), ChangeNameDialog: markRaw(ChangeNameDialog),
ChangeTitleDialog: markRaw(ChangeTitleDialog), ChangeTitleDialog: markRaw(ChangeTitleDialog),
ChangeStripeIdDialog: markRaw(ChangeStripeIdDialog), ChangeStripeIdDialog: markRaw(ChangeStripeIdDialog),
ChangePhoneDialog: markRaw(ChangePhoneDialog),
ChangeEmailDialog: markRaw(ChangeEmailDialog),
}; };
function requestCancel() { function requestCancel() {
@@ -178,6 +184,17 @@ function downloadQRCode() {
console.error('Error in downloadQRCode:', error); console.error('Error in downloadQRCode:', error);
} }
} }
async function deconfigureStripe() {
try {
await client.post(`/api/membership/stripe-account`, {
stripeAccountId: '',
});
await creatorProfileStore.fetchCreatorProfile();
} catch (error) {
console.error('Error deconfiguring stripe:', error);
}
}
</script> </script>
<template> <template>
@@ -246,6 +263,23 @@ function downloadQRCode() {
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span> <span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
</button> </button>
<!-- PHONE NUMBER -->
<button class="action" @click="openDialog('ChangePhoneDialog')">
<span class="label">{{ t('phoneNumber') }}</span>
<span class="value" :class="{ 'not-set': !creatorProfileStore.creator.presentation?.phoneNumber }">
{{ creatorProfileStore.creator.presentation?.phoneNumber || t('notSet') }}
</span>
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
</button>
<!-- EMAIL -->
<button class="action" @click="openDialog('ChangeEmailDialog')">
<span class="label">{{ t('email') }}</span>
<span class="value" :class="{ 'not-set': !creatorProfileStore.creator.presentation?.email }">
{{ creatorProfileStore.creator.presentation?.email || t('notSet') }}
</span>
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
</button>
</div> </div>
</div> </div>
@@ -262,10 +296,18 @@ function downloadQRCode() {
<span class="value" :class="{ 'configured': creatorProfileStore.creator.acceptDonation }"> <span class="value" :class="{ 'configured': creatorProfileStore.creator.acceptDonation }">
{{ creatorProfileStore.creator.acceptDonation ? t('configured') : t('notConfigured') }} {{ creatorProfileStore.creator.acceptDonation ? t('configured') : t('notConfigured') }}
</span> </span>
<button class="configure-stripe-button" @click="openDialog('ChangeStripeIdDialog')"> <div class="stripe-actions">
<v-icon>mdi-credit-card</v-icon> <button class="configure-stripe-button" @click="openDialog('ChangeStripeIdDialog')">
{{ t('configureStripe') }} <v-icon>mdi-credit-card</v-icon>
</button> {{ t('configureStripe') }}
</button>
<button v-if="creatorProfileStore.creator.acceptDonation"
class="deconfigure-stripe-button"
@click="deconfigureStripe">
<v-icon>mdi-credit-card-off</v-icon>
{{ t('deconfigureStripe') }}
</button>
</div>
</div> </div>
</div> </div>
@@ -485,6 +527,10 @@ function downloadQRCode() {
@apply flex items-center justify-center; @apply flex items-center justify-center;
} }
.value.not-set {
@apply text-gray-400;
}
.chevron { .chevron {
@apply text-hOnBackground w-[40px] text-right; @apply text-hOnBackground w-[40px] text-right;
@apply flex items-center justify-end; @apply flex items-center justify-end;
@@ -539,12 +585,22 @@ function downloadQRCode() {
@apply text-green-500; @apply text-green-500;
} }
.stripe-actions {
@apply flex items-center gap-2 ml-4;
}
.configure-stripe-button { .configure-stripe-button {
@apply flex items-center justify-center gap-2 px-4 py-2 rounded-lg; @apply flex items-center justify-center gap-2 px-4 py-2 rounded-lg;
@apply bg-hutopyPrimary text-hOnPrimary; @apply bg-hutopyPrimary text-hOnPrimary;
@apply hover:bg-hutopySecondary; @apply hover:bg-hutopySecondary;
@apply transition-colors duration-300; @apply transition-colors duration-300;
@apply ml-4; }
.deconfigure-stripe-button {
@apply flex items-center justify-center gap-2 px-4 py-2 rounded-lg;
@apply bg-red-600 text-white;
@apply hover:bg-red-700;
@apply transition-colors duration-300;
} }
</style> </style>
@@ -573,7 +629,10 @@ function downloadQRCode() {
"configured": "Configured", "configured": "Configured",
"notConfigured": "Not Configured", "notConfigured": "Not Configured",
"notSet": "Not Set", "notSet": "Not Set",
"configureStripe": "Configure Stripe Account" "configureStripe": "Configure Stripe",
"phoneNumber": "Phone Number",
"title": "Title",
"deconfigureStripe": "Remove Stripe"
}, },
"fr": { "fr": {
"personalInfo": "Informations Personnelles", "personalInfo": "Informations Personnelles",
@@ -598,7 +657,10 @@ function downloadQRCode() {
"configured": "Configuré", "configured": "Configuré",
"notConfigured": "Non Configuré", "notConfigured": "Non Configuré",
"notSet": "Non Défini", "notSet": "Non Défini",
"configureStripe": "Configurer le Compte Stripe" "configureStripe": "Configurer Stripe",
"phoneNumber": "Numéro de téléphone",
"title": "Titre",
"deconfigureStripe": "Retirer Stripe"
}, },
"es": { "es": {
"personalInfo": "Información Personal", "personalInfo": "Información Personal",
@@ -623,7 +685,10 @@ function downloadQRCode() {
"configured": "Configurado", "configured": "Configurado",
"notConfigured": "No Configurado", "notConfigured": "No Configurado",
"notSet": "No Establecido", "notSet": "No Establecido",
"configureStripe": "Configurar Cuenta Stripe" "configureStripe": "Configurar Stripe",
"phoneNumber": "Número de teléfono",
"title": "Título",
"deconfigureStripe": "Eliminar Stripe"
} }
} }
</i18n> </i18n>