Add localization support for various components, including dialogs and views, in English, Spanish, and French. Implemented translations for user profile management, payment processes, and creator functionalities. Updated existing components to utilize the new translation system.
This commit is contained in:
13
.idea/.gitignore
generated
vendored
Normal file
13
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/projectSettingsUpdater.xml
|
||||
/modules.xml
|
||||
/contentModel.xml
|
||||
/.idea.hutopy.iml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
8
.idea/indexLayout.xml
generated
Normal file
8
.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,15 +1,18 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import en from './locales/en.json';
|
||||
import fr from './locales/fr.json';
|
||||
import { useSessionStorage } from '@vueuse/core';
|
||||
|
||||
// Get the stored locale or default to 'fr'
|
||||
const storedLocale = useSessionStorage('user-locale', 'fr');
|
||||
|
||||
const messages = {
|
||||
en,
|
||||
fr,
|
||||
};
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'fr',
|
||||
locale: storedLocale.value,
|
||||
fallbackLocale: 'en',
|
||||
messages,
|
||||
messages: {
|
||||
en: {},
|
||||
fr: {},
|
||||
es: {}
|
||||
}
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
{
|
||||
"general": {
|
||||
"yes": "yes",
|
||||
"no": "no"
|
||||
},
|
||||
"banner": {
|
||||
"subscription": "Subscriptions"
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "All rights reserved",
|
||||
"helpandcontact": "Help and contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Creator guide",
|
||||
"termsandconditions": "Terms and conditions",
|
||||
"contentpolicy": "Content policy",
|
||||
"about": "About",
|
||||
"pricing": "Pricing"
|
||||
},
|
||||
"subscribebutton": {
|
||||
"subscribe": "Subscribe",
|
||||
"unsubscribe": "Unsubscribe"
|
||||
},
|
||||
"profilemenu": {
|
||||
"manageyouraccount": "Manage your Hutopy account",
|
||||
"creator": "Creator",
|
||||
"user": "User"
|
||||
},
|
||||
"header": {
|
||||
"wallet": "Wallet"
|
||||
},
|
||||
"message": {
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"report": "Report",
|
||||
"yourcomment": "Your comment..."
|
||||
},
|
||||
"contentCard": {
|
||||
"commenttitle": "comments",
|
||||
"edit": "Edit",
|
||||
"delete": "delete",
|
||||
"report": "report",
|
||||
"deletecontenttitle": "Delete this content?",
|
||||
"deeletecontentwarning": "Are you sure you want to delete the content?"
|
||||
},
|
||||
"time": {
|
||||
"seconds": "seconds",
|
||||
"1minuteago": "1 minute ago",
|
||||
"1minutefromnow": "1 minute from now",
|
||||
"minutes": "minutes",
|
||||
"1hourago": "1 hour ago",
|
||||
"1hourfromnow": "1 hour from now",
|
||||
"hours": "hours",
|
||||
"yesterday": "Yesterday",
|
||||
"tomorrow": "Tomorrow",
|
||||
"days": "days",
|
||||
"lastweek": "Last week",
|
||||
"nextweek": "Next week",
|
||||
"weeks": "weeks",
|
||||
"lastmonth": "Last month",
|
||||
"nextmonth": "Next month",
|
||||
"months": "months",
|
||||
"lastyear": "Last year",
|
||||
"nextyear": "Next year",
|
||||
"years": "years",
|
||||
"lastcentury": "Last century",
|
||||
"nextcentury": "Next century",
|
||||
"centuries": "centuries",
|
||||
"ago": "ago"
|
||||
},
|
||||
"personnalinformation": {
|
||||
"informations": "Informations",
|
||||
"title": "Personal information",
|
||||
"profilepicture": "Profile picture",
|
||||
"fullname": "Name",
|
||||
"firstname": "Firstname",
|
||||
"lastname": "Lastname",
|
||||
"alias": "Alias",
|
||||
"dob": "Date of birth",
|
||||
"gender": "Gender",
|
||||
"contactdetails": "Contact details",
|
||||
"email": "Email",
|
||||
"phone": "Phone",
|
||||
"addresses": "Addresses",
|
||||
"home": "Home",
|
||||
"work": "Work"
|
||||
},
|
||||
"creatorinfopage": {
|
||||
"informations": "Informations",
|
||||
"name": "Name",
|
||||
"title": "Title",
|
||||
"slug": "Slug",
|
||||
"description": "Description",
|
||||
"banner&profile": "Banner and profile picture",
|
||||
"borderpicturecolor": "Profile picture border",
|
||||
"menucolor": "Menu color",
|
||||
"pageinformation": "Your page information",
|
||||
"socialnetwork": "Social Network"
|
||||
},
|
||||
"accountmanagement": {
|
||||
"accounts": "Account",
|
||||
"accountmanagement": "Account Management",
|
||||
"pageid": "Page ID",
|
||||
"addaccount": "Add Account",
|
||||
"authoritygranted": "Granted Permissions"
|
||||
},
|
||||
"security": {
|
||||
"title": "Security",
|
||||
"howtoconnect": "How to connect to Hutopy",
|
||||
"password": "Password",
|
||||
"recoverybyemail": "Recovery by Email",
|
||||
"recoverybymobile": "Recovery by Mobile"
|
||||
},
|
||||
"isupportbtn": {
|
||||
"isupport": "I support",
|
||||
"amount": "amount",
|
||||
"message": "Message (optional)",
|
||||
"send": "send"
|
||||
},
|
||||
"paymentConfirmation": {
|
||||
"success": {
|
||||
"title": "Payment completed",
|
||||
"message": "Your payment was successful. Thank you for supporting ",
|
||||
"usernameDefault": "this user.",
|
||||
"receipt": "A receipt has been sent to your email address.",
|
||||
"continue": "Continue"
|
||||
},
|
||||
"failure": {
|
||||
"title": "Payment cancelled",
|
||||
"message": "The payment was cancelled. If you did not intend to cancel, please try again.",
|
||||
"thanks": "Thank you for supporting",
|
||||
"tryAgain": "Try again",
|
||||
"return": "Return to the profile of "
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
{
|
||||
"general": {
|
||||
"yes": "oui",
|
||||
"no": "non"
|
||||
},
|
||||
"banner": {
|
||||
"subscription": "Abonnés"
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "Tout droits réservés",
|
||||
"helpandcontact": "Aide & Contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Guide pour les créateurs",
|
||||
"termsandconditions": "Termes et conditions",
|
||||
"contentpolicy": "Politique de contenu",
|
||||
"about": "À propos",
|
||||
"pricing": "Frais"
|
||||
},
|
||||
"subscribebutton": {
|
||||
"subscribe": "S'abonner",
|
||||
"unsubscribe": "Se désabonner"
|
||||
},
|
||||
"profilemenu": {
|
||||
"manageyouraccount": "Gérer votre compte Hutopy",
|
||||
"creator": "Créateur",
|
||||
"user": "utilisateur"
|
||||
},
|
||||
"header": {
|
||||
"wallet": "PorteFeuille"
|
||||
},
|
||||
"message": {
|
||||
"edit": "Modifier",
|
||||
"delete": "Effacer",
|
||||
"report": "Signaler",
|
||||
"yourcomment": "Votre commentaire..."
|
||||
},
|
||||
"contentCard": {
|
||||
"commenttitle": "commentaires",
|
||||
"edit": "Modifier",
|
||||
"delete": "Effacer",
|
||||
"report": "signaler",
|
||||
"deletecontenttitle": " Supprimer ce contenu?",
|
||||
"deeletecontentwarning": "Êtes-vous sûr de vouloir supprimer le contenu?"
|
||||
},
|
||||
"time": {
|
||||
"seconds": "secondes",
|
||||
"1minuteago": "Il y a 1 minute",
|
||||
"1minutefromnow": "dans 1 minute",
|
||||
"minutes": "minutes",
|
||||
"1hourago": "Il y a 1 heure",
|
||||
"1hourfromnow": "dans 1 heure",
|
||||
"hours": "heures",
|
||||
"yesterday": "hier",
|
||||
"tomorrow": "demain",
|
||||
"days": "jours",
|
||||
"lastweek": "La semaine dernière.",
|
||||
"nextweek": "La semaine prochaine",
|
||||
"weeks": "semaines",
|
||||
"lastmonth": "Le mois dernier",
|
||||
"nextmonth": "Le mois prochain",
|
||||
"months": "mois",
|
||||
"lastyear": "L'année dernière",
|
||||
"nextyear": "L'année prochaine",
|
||||
"years": "années",
|
||||
"lastcentury": "Le siècle dernier",
|
||||
"nextcentury": "Le siècle prochain",
|
||||
"centuries": "siècles",
|
||||
"ago": ""
|
||||
},
|
||||
"personnalinformation": {
|
||||
"informations": "Informations",
|
||||
"title": "Informations personnelles",
|
||||
"profilepicture": "Photo de profil",
|
||||
"fullname": "Nom",
|
||||
"firstname": "Prénom",
|
||||
"lastname": "Nom",
|
||||
"alias": "Pseudonyme",
|
||||
"dob": "Date de naissance",
|
||||
"gender": "Genre",
|
||||
"contactdetails": "Coordonnées",
|
||||
"email": "Email",
|
||||
"phone": "Téléphone",
|
||||
"addresses": "Adresses",
|
||||
"home": "Domicile",
|
||||
"work": "Travail"
|
||||
},
|
||||
"creatorinfopage": {
|
||||
"informations": "Informations",
|
||||
"name": "Nom",
|
||||
"title": "Titre",
|
||||
"slug": "Slug",
|
||||
"description": "Description",
|
||||
"banner&profile": "Bannière et photo de profil",
|
||||
"borderpicturecolor": "Bordure de la photo de profil",
|
||||
"menucolor": "Couleur des menus",
|
||||
"pageinformation": "Informations de votre page",
|
||||
"socialnetwork": "Réseaux sociaux"
|
||||
},
|
||||
"accountmanagement": {
|
||||
"accounts": "comptes",
|
||||
"accountmanagement": "Gestion des comptes",
|
||||
"pageid": "ID de la page",
|
||||
"addaccount": "Ajouter un compte",
|
||||
"authoritygranted": "Autorisations accordées"
|
||||
},
|
||||
"security": {
|
||||
"title": "Sécurité",
|
||||
"howtoconnect": "Comment vous connecter à Hutopy",
|
||||
"password": "Mot de passe",
|
||||
"recoverybyemail": "Récupération par email",
|
||||
"recoverybymobile": "Récupération par mobile"
|
||||
},
|
||||
"isupportbtn": {
|
||||
"isupport": "Je soutiens",
|
||||
"amount": "Montant",
|
||||
"message": "Message (facultatif)",
|
||||
"send": "Envoyez"
|
||||
},
|
||||
"paymentConfirmation": {
|
||||
"success": {
|
||||
"title": "Paiement complété",
|
||||
"message": "Votre paiement a été effectué avec succès. Merci de soutenir ",
|
||||
"usernameDefault": "cet utilisateur.",
|
||||
"receipt": "Un reçu a été envoyé à votre adresse courriel.",
|
||||
"continue": "Continuer"
|
||||
},
|
||||
"failure": {
|
||||
"title": "Paiement annulé",
|
||||
"message": "Le paiement a été annulé. Si vous n'aviez pas l'intention d'annuler, veuillez réessayer.",
|
||||
"thanks": "Merci de supporter",
|
||||
"tryAgain": "Réessayer",
|
||||
"return": "Retour au profil de "
|
||||
}
|
||||
}
|
||||
}
|
||||
26
frontend/src/stores/languageStore.js
Normal file
26
frontend/src/stores/languageStore.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { useSessionStorage } from '@vueuse/core'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
export const useLanguageStore = defineStore(
|
||||
'language',
|
||||
() => {
|
||||
const { locale } = useI18n()
|
||||
|
||||
// Initialize with the stored value or default to 'fr'
|
||||
const storedLocale = useSessionStorage('user-locale', 'fr')
|
||||
|
||||
// Set the initial locale from storage
|
||||
locale.value = storedLocale.value
|
||||
|
||||
function setLocale(newLocale) {
|
||||
locale.value = newLocale
|
||||
storedLocale.value = newLocale
|
||||
}
|
||||
|
||||
return {
|
||||
locale: storedLocale,
|
||||
setLocale
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -65,6 +65,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changeFullname(firstname, lastname) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/fullname`,
|
||||
{
|
||||
@@ -80,6 +81,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changeAlias(alias) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/alias`,
|
||||
{
|
||||
@@ -93,6 +95,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changeBirthday(birthdate) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/birthdate`,
|
||||
{
|
||||
@@ -106,6 +109,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changePhone(phoneNumber) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/phone`,
|
||||
{
|
||||
@@ -119,6 +123,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changeEmail(email) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/email`,
|
||||
{
|
||||
@@ -132,6 +137,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changeAddress(address) {
|
||||
try {
|
||||
const client = useClient()
|
||||
await client.post(
|
||||
`/api/users/address`,
|
||||
{
|
||||
@@ -145,6 +151,7 @@ export const useUserProfileStore = defineStore(
|
||||
|
||||
async function changePortrait(selectedFile) {
|
||||
try {
|
||||
const client = useClient()
|
||||
const formData = new FormData();
|
||||
formData.append('file', selectedFile)
|
||||
|
||||
|
||||
15
frontend/src/translations/common.en.json
Normal file
15
frontend/src/translations/common.en.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"create": "Create",
|
||||
"apply": "Apply",
|
||||
"preview": "Preview",
|
||||
"label": "Label",
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred",
|
||||
"imageLoad": "Error loading image",
|
||||
"imageUpload": "Error uploading image"
|
||||
}
|
||||
}
|
||||
15
frontend/src/translations/common.es.json
Normal file
15
frontend/src/translations/common.es.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar",
|
||||
"edit": "Editar",
|
||||
"delete": "Eliminar",
|
||||
"create": "Crear",
|
||||
"apply": "Aplicar",
|
||||
"preview": "Vista previa",
|
||||
"label": "Etiqueta",
|
||||
"errors": {
|
||||
"unexpected": "Se produjo un error inesperado",
|
||||
"imageLoad": "Error al cargar la imagen",
|
||||
"imageUpload": "Error al subir la imagen"
|
||||
}
|
||||
}
|
||||
15
frontend/src/translations/common.fr.json
Normal file
15
frontend/src/translations/common.fr.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"save": "Enregistrer",
|
||||
"cancel": "Annuler",
|
||||
"edit": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"create": "Créer",
|
||||
"apply": "Appliquer",
|
||||
"preview": "Aperçu",
|
||||
"label": "Étiquette",
|
||||
"errors": {
|
||||
"unexpected": "Une erreur inattendue s'est produite",
|
||||
"imageLoad": "Erreur lors du chargement de l'image",
|
||||
"imageUpload": "Erreur lors du téléchargement de l'image"
|
||||
}
|
||||
}
|
||||
95
frontend/src/translations/translations.js
Normal file
95
frontend/src/translations/translations.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
// Helper function to get component path from stack trace
|
||||
function getComponentPath() {
|
||||
const stack = new Error().stack
|
||||
const stackLines = stack.split('\n')
|
||||
|
||||
// Find the first line that contains a .vue file
|
||||
const vueFileLine = stackLines.find(line => line.includes('.vue'))
|
||||
if (!vueFileLine) return null
|
||||
|
||||
// Extract the file path
|
||||
const match = vueFileLine.match(/\/src\/(.*?\.vue)/)
|
||||
if (!match) return null
|
||||
|
||||
// Return the full path without the .vue extension
|
||||
return match[1].replace(/\.vue$/, '')
|
||||
}
|
||||
|
||||
// Helper function to get nested value from an object using dot notation
|
||||
function getNestedValue(obj, path) {
|
||||
return path.split('.').reduce((current, key) => {
|
||||
return current && current[key] !== undefined ? current[key] : null
|
||||
}, obj)
|
||||
}
|
||||
|
||||
export function useTranslations() {
|
||||
const { locale } = useI18n()
|
||||
const componentPath = ref(getComponentPath())
|
||||
const componentTranslations = ref({})
|
||||
const commonTranslations = ref({})
|
||||
|
||||
// Load translations when locale changes
|
||||
const loadTranslations = async () => {
|
||||
// Load component translations
|
||||
if (componentPath.value) {
|
||||
try {
|
||||
// The translation files are in the same directory as the Vue components
|
||||
const importPath = `../${componentPath.value}.${locale.value}.json`
|
||||
const translations = await import(importPath)
|
||||
componentTranslations.value = translations.default
|
||||
} catch (e) {
|
||||
try {
|
||||
const importPath = `../${componentPath.value}.en.json`
|
||||
const translations = await import(importPath)
|
||||
componentTranslations.value = translations.default
|
||||
} catch (e) {
|
||||
componentTranslations.value = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load common translations
|
||||
try {
|
||||
const importPath = `./common.${locale.value}.json`
|
||||
const translations = await import(importPath)
|
||||
commonTranslations.value = translations.default
|
||||
} catch (e) {
|
||||
try {
|
||||
const importPath = './common.en.json'
|
||||
const translations = await import(importPath)
|
||||
commonTranslations.value = translations.default
|
||||
} catch (e) {
|
||||
commonTranslations.value = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load translations immediately
|
||||
loadTranslations()
|
||||
|
||||
// Watch for locale changes
|
||||
watch(locale, () => {
|
||||
loadTranslations()
|
||||
})
|
||||
|
||||
// Return synchronous translation function
|
||||
return (key) => {
|
||||
// Try to get the translation from component translations first
|
||||
const componentValue = getNestedValue(componentTranslations.value, key)
|
||||
if (componentValue !== null) {
|
||||
return componentValue
|
||||
}
|
||||
|
||||
// Then try common translations
|
||||
const commonValue = getNestedValue(commonTranslations.value, key)
|
||||
if (commonValue !== null) {
|
||||
return commonValue
|
||||
}
|
||||
|
||||
// If not found, return the key with MISSING prefix
|
||||
return `MISSING: ${key}`
|
||||
}
|
||||
}
|
||||
4
frontend/src/views/LoginView.en.json
Normal file
4
frontend/src/views/LoginView.en.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Login",
|
||||
"alt": "hutopy login"
|
||||
}
|
||||
4
frontend/src/views/LoginView.es.json
Normal file
4
frontend/src/views/LoginView.es.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Iniciar sesión",
|
||||
"alt": "iniciar sesión hutopy"
|
||||
}
|
||||
4
frontend/src/views/LoginView.fr.json
Normal file
4
frontend/src/views/LoginView.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Connexion",
|
||||
"alt": "connexion hutopy"
|
||||
}
|
||||
@@ -2,11 +2,9 @@
|
||||
import {ref} from 'vue';
|
||||
import {GoogleLogin} from "vue3-google-login";
|
||||
import {useAuthStore} from '@/stores/authStore.js';
|
||||
import {useTranslations} from '@/translations/translations';
|
||||
|
||||
import {useFacebookLogin} from "@/composables/useFacebookLogin";
|
||||
import Facebook from "@/views/svg/Facebook.vue";
|
||||
|
||||
const {loginWithFacebook} = useFacebookLogin();
|
||||
const t = useTranslations();
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
@@ -22,21 +20,14 @@ async function googleCallback(token) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div class="flex min-h-full justify-center items-center p-20 w-full">
|
||||
|
||||
<div class="card justify-items-center">
|
||||
|
||||
<img alt="hutopy login"
|
||||
<img :alt="t('alt')"
|
||||
src="/images/hutopymedia/loginpage/hutopylogin.svg"/>
|
||||
|
||||
|
||||
<div class="flex flex-col gap-10">
|
||||
|
||||
<h1 class="text-2xl font-bold login-text text-center ">
|
||||
Connexion
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<google-login :callback="googleCallback"
|
||||
popup-type="TOKEN">
|
||||
@@ -45,24 +36,11 @@ async function googleCallback(token) {
|
||||
Google
|
||||
</button>
|
||||
</google-login>
|
||||
<!-- <button class="secondary"-->
|
||||
<!-- @click="loginWithFacebook">-->
|
||||
<!-- <facebook class="social-icon"></facebook>-->
|
||||
<!-- Facebook-->
|
||||
<!-- </button>-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.social-icon {
|
||||
@apply w-5 h-5;
|
||||
@apply text-base;
|
||||
}
|
||||
</style>
|
||||
|
||||
7
frontend/src/views/PaymentCompleted.en.json
Normal file
7
frontend/src/views/PaymentCompleted.en.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Payment Successful!",
|
||||
"message": "Your payment has been processed successfully.",
|
||||
"usernameDefault": "the creator",
|
||||
"receipt": "A receipt has been sent to your email.",
|
||||
"continue": "Continue to"
|
||||
}
|
||||
7
frontend/src/views/PaymentCompleted.es.json
Normal file
7
frontend/src/views/PaymentCompleted.es.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "¡Pago exitoso!",
|
||||
"message": "Su pago ha sido procesado con éxito.",
|
||||
"usernameDefault": "el creador",
|
||||
"receipt": "Se ha enviado un recibo a su correo electrónico.",
|
||||
"continue": "Continuar a"
|
||||
}
|
||||
7
frontend/src/views/PaymentCompleted.fr.json
Normal file
7
frontend/src/views/PaymentCompleted.fr.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Paiement réussi !",
|
||||
"message": "Votre paiement a été traité avec succès.",
|
||||
"usernameDefault": "le créateur",
|
||||
"receipt": "Un reçu a été envoyé à votre adresse e-mail.",
|
||||
"continue": "Continuer vers"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="card">
|
||||
|
||||
<h1>
|
||||
{{ $t('paymentConfirmation.success.title') }}
|
||||
{{ t('title') }}
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
@@ -13,28 +13,28 @@
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ $t('paymentConfirmation.success.message') }}
|
||||
{{ t('message') }}
|
||||
|
||||
<span v-if="creatorUserName">
|
||||
{{ creatorUserName }}
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ $t('paymentConfirmation.success.usernameDefault') }}
|
||||
{{ t('usernameDefault') }}
|
||||
</span>
|
||||
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ $t('paymentConfirmation.success.receipt') }}
|
||||
{{ t('receipt') }}
|
||||
</p>
|
||||
|
||||
<!-- Continue Button -->
|
||||
<div class="card-actions">
|
||||
<button
|
||||
class="action-button"
|
||||
@click="router.push({ path: `/@${creatorUserName}` })">
|
||||
{{ $t('paymentConfirmation.success.continue') }}
|
||||
@click="goBack()">
|
||||
{{ t('continue') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -44,25 +44,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useClient} from '@/plugins/api.js';
|
||||
import {onBeforeMount, ref} from 'vue';
|
||||
import {useRoute, useRouter} from 'vue-router';
|
||||
import {useRouter, useRoute} from 'vue-router';
|
||||
import {useTranslations} from '@/translations/translations';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const client = useClient();
|
||||
const t = useTranslations();
|
||||
|
||||
const creatorId = route.params.creatorId;
|
||||
const creatorUserName = ref('');
|
||||
|
||||
onBeforeMount(async () => {
|
||||
try {
|
||||
const response = await client.get(`/api/creators/${creatorId}`);
|
||||
creatorUserName.value = response.data.name;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch creator data:', error);
|
||||
function goBack() {
|
||||
const returnUrl = route.query.returnUrl;
|
||||
if (returnUrl) {
|
||||
router.push(returnUrl);
|
||||
} else {
|
||||
router.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
5
frontend/src/views/PaymentFailed.en.json
Normal file
5
frontend/src/views/PaymentFailed.en.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Payment Failed",
|
||||
"message": "We couldn't process your payment. Please try again or contact support if the problem persists.",
|
||||
"continue": "Return to"
|
||||
}
|
||||
5
frontend/src/views/PaymentFailed.es.json
Normal file
5
frontend/src/views/PaymentFailed.es.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Pago fallido",
|
||||
"message": "No pudimos procesar su pago. Por favor, inténtelo de nuevo o contacte con soporte si el problema persiste.",
|
||||
"continue": "Volver a"
|
||||
}
|
||||
5
frontend/src/views/PaymentFailed.fr.json
Normal file
5
frontend/src/views/PaymentFailed.fr.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "Échec du paiement",
|
||||
"message": "Nous n'avons pas pu traiter votre paiement. Veuillez réessayer ou contacter le support si le problème persiste.",
|
||||
"continue": "Retourner à"
|
||||
}
|
||||
@@ -1,29 +1,11 @@
|
||||
<template>
|
||||
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
|
||||
<h1>
|
||||
{{ $t('paymentConfirmation.failure.title') }}
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<v-icon size="120" color="error">
|
||||
mdi-close-circle
|
||||
</v-icon>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ $t('paymentConfirmation.failure.message') }}
|
||||
</p>
|
||||
|
||||
<h1>{{ t('title') }}</h1>
|
||||
<p>{{ t('message') }}</p>
|
||||
<div class="card-actions">
|
||||
<button
|
||||
class="action-button"
|
||||
@click="router.push({ path: `/@${creatorUserName}` })"
|
||||
>
|
||||
{{ $t('paymentConfirmation.success.continue') }}
|
||||
{{ creatorUserName }}
|
||||
<button class="action-button" @click="goBack()">
|
||||
{{ t('continue') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,25 +13,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useClient} from '@/plugins/api.js';
|
||||
import {onBeforeMount, ref} from 'vue';
|
||||
import {useRoute, useRouter} from 'vue-router';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useTranslations } from '@/translations/translations';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const client = useClient();
|
||||
const t = useTranslations();
|
||||
|
||||
const creatorId = route.params.creatorId;
|
||||
const creatorUserName = ref('');
|
||||
|
||||
onBeforeMount(async () => {
|
||||
try {
|
||||
const response = await client.get(`/api/creators/${creatorId}`);
|
||||
creatorUserName.value = response.data.name;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch creator data:', error);
|
||||
function goBack() {
|
||||
const returnUrl = route.query.returnUrl;
|
||||
if (returnUrl) {
|
||||
router.push(returnUrl);
|
||||
} else {
|
||||
router.back();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
5
frontend/src/views/StripePayment.en.json
Normal file
5
frontend/src/views/StripePayment.en.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"message": "Message (optional)",
|
||||
"amount": "Amount ($)",
|
||||
"send": "Send"
|
||||
}
|
||||
5
frontend/src/views/StripePayment.es.json
Normal file
5
frontend/src/views/StripePayment.es.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"message": "Mensaje (opcional)",
|
||||
"amount": "Cantidad ($)",
|
||||
"send": "Enviar"
|
||||
}
|
||||
5
frontend/src/views/StripePayment.fr.json
Normal file
5
frontend/src/views/StripePayment.fr.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"message": "Message (facultatif)",
|
||||
"amount": "Montant ($)",
|
||||
"send": "Envoyez"
|
||||
}
|
||||
@@ -2,13 +2,13 @@
|
||||
<v-container>
|
||||
|
||||
<v-row>
|
||||
<v-text-field label="Message (facultatif)" v-model="tipMessage"
|
||||
<v-text-field :label="t('message')" v-model="tipMessage"
|
||||
style="border-radius: 10px; margin-top: 10px; margin-bottom: 10px; color: #a30e79; background-color: #f4f4f4">
|
||||
</v-text-field>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-text-field label="Montant ($)" v-model="price"
|
||||
<v-text-field :label="t('amount')" v-model="price"
|
||||
style="border-radius: 10px; margin-bottom: 10px; color: #a30e79; background-color: #f4f4f4">
|
||||
</v-text-field>
|
||||
</v-row>
|
||||
@@ -19,7 +19,7 @@
|
||||
<v-icon left style="margin-right: 10px;">
|
||||
mdi-gift
|
||||
</v-icon>
|
||||
Envoyez
|
||||
{{ t('send') }}
|
||||
</v-btn>
|
||||
</v-row>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</div>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn block class="ma-auto" style="width: 200px;" text="Annuler" @click="closeDialog()"></v-btn>
|
||||
<v-btn block class="ma-auto" style="width: 200px;" :text="t('cancel')" @click="closeDialog()"></v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
@@ -44,8 +44,10 @@
|
||||
import { useClient } from '@/plugins/api.js';
|
||||
import { loadStripe } from '@stripe/stripe-js';
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useTranslations } from '@/translations/translations';
|
||||
|
||||
const props = defineProps(['creatorId'])
|
||||
const t = useTranslations();
|
||||
|
||||
let stripe = null;
|
||||
const client = useClient();
|
||||
|
||||
3
frontend/src/views/creators/ActualBanner.en.json
Normal file
3
frontend/src/views/creators/ActualBanner.en.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"alt": "Creator banner"
|
||||
}
|
||||
3
frontend/src/views/creators/ActualBanner.es.json
Normal file
3
frontend/src/views/creators/ActualBanner.es.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"alt": "Banner del creador"
|
||||
}
|
||||
3
frontend/src/views/creators/ActualBanner.fr.json
Normal file
3
frontend/src/views/creators/ActualBanner.fr.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"alt": "Bannière du créateur"
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<img
|
||||
class="w-[990px] h-[330px] banner object-cover"
|
||||
:src="brandingStore.value?.images?.banner ?? '/images/placeholders/banner.png'"
|
||||
alt="Profile Banner"
|
||||
:alt="t('alt')"
|
||||
>
|
||||
<!-- Tint Effect -->
|
||||
<div
|
||||
@@ -43,9 +43,11 @@ import BannerEditor from "@/views/creators/BannerEditor.vue";
|
||||
import {computed, ref} from "vue";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import { useTranslations } from '@/translations/translations';
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
|
||||
// State
|
||||
const showTint = ref(false);
|
||||
|
||||
12
frontend/src/views/creators/BannerActions.en.json
Normal file
12
frontend/src/views/creators/BannerActions.en.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"social": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Website"
|
||||
}
|
||||
}
|
||||
12
frontend/src/views/creators/BannerActions.es.json
Normal file
12
frontend/src/views/creators/BannerActions.es.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"social": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Sitio Web"
|
||||
}
|
||||
}
|
||||
12
frontend/src/views/creators/BannerActions.fr.json
Normal file
12
frontend/src/views/creators/BannerActions.fr.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"social": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Site Web"
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,11 @@ import Tiktok from "@/views/svg/Tiktok.vue";
|
||||
import Reddit from "@/views/svg/Reddit.vue";
|
||||
import Youtube from "@/views/svg/Youtube.vue";
|
||||
import Web from "@/views/svg/Web.vue";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const baseURL = window.location.origin;
|
||||
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
// Gèrer le breakpoint du block information.
|
||||
// Définir un point de rupture pour "moyen" (correspondant à md: de Tailwind)
|
||||
@@ -88,49 +88,57 @@ onUnmounted(() => {
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.facebookUrl"
|
||||
:href="brandingStore.value?.socials?.facebookUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.facebook')">
|
||||
<facebook class="social-icon"></facebook>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.instagramUrl"
|
||||
:href="brandingStore.value?.socials?.instagramUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.instagram')">
|
||||
<instagram class="social-icon"></instagram>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.linkedInUrl"
|
||||
:href="brandingStore.value?.socials?.linkedInUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.linkedin')">
|
||||
<linkedin class="social-icon"></linkedin>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.redditUrl"
|
||||
:href="brandingStore.value?.socials?.redditUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.reddit')">
|
||||
<reddit class="social-icon"></reddit>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.tikTokUrl"
|
||||
:href="brandingStore.value?.socials?.tikTokUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.tiktok')">
|
||||
<tiktok class="social-icon"></tiktok>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.xUrl"
|
||||
:href="brandingStore.value?.socials?.xUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.x')">
|
||||
<x class="social-icon"></x>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.youtubeUrl"
|
||||
:href="brandingStore.value?.socials?.youtubeUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.youtube')">
|
||||
<youtube class="social-icon"></youtube>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.websiteUrl"
|
||||
:href="brandingStore.value?.socials?.websiteUrl"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
:title="t('social.website')">
|
||||
<web class="social-icon"></web>
|
||||
</a>
|
||||
|
||||
|
||||
7
frontend/src/views/creators/BannerEditor.en.json
Normal file
7
frontend/src/views/creators/BannerEditor.en.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Choose your Banner",
|
||||
"description": "The banner must have a 3:1 ratio. Target dimensions are 960 x 320.",
|
||||
"chooseImage": "Choose an image...",
|
||||
"clickToEdit": "Click to edit",
|
||||
"preview": "Banner preview"
|
||||
}
|
||||
7
frontend/src/views/creators/BannerEditor.es.json
Normal file
7
frontend/src/views/creators/BannerEditor.es.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Elige tu Banner",
|
||||
"description": "El banner debe tener una relación de 3:1. Las dimensiones objetivo son 960 x 320.",
|
||||
"chooseImage": "Elegir una imagen...",
|
||||
"clickToEdit": "Clic para editar",
|
||||
"preview": "Vista previa del banner"
|
||||
}
|
||||
7
frontend/src/views/creators/BannerEditor.fr.json
Normal file
7
frontend/src/views/creators/BannerEditor.fr.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Choisissez votre Bannière",
|
||||
"description": "La bannière doit avoir un ratio de 3:1. Les dimensions cibles sont 960 x 320.",
|
||||
"chooseImage": "Choisir une image...",
|
||||
"clickToEdit": "Cliquez pour modifier",
|
||||
"preview": "Aperçu de la bannière"
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
Choisissez votre Bannière
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<p class="card-text">
|
||||
La bannière doit avoir un ratio de 3:1. Les dimensions cibles sont 960 x 320.
|
||||
{{ t('description') }}
|
||||
</p>
|
||||
|
||||
<div class="file-input-container">
|
||||
@@ -21,7 +21,7 @@
|
||||
class="choose-file-button"
|
||||
@click="triggerFileInput"
|
||||
>
|
||||
Choisir une image...
|
||||
{{ t('chooseImage') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -44,11 +44,11 @@
|
||||
<div v-else class="image-preview-container" @click="startEditing">
|
||||
<img
|
||||
:src="fileUrl || fallbackUrl"
|
||||
alt="Aperçu de la bannière"
|
||||
:alt="t('preview')"
|
||||
class="preview-image"
|
||||
/>
|
||||
<div class="edit-overlay">
|
||||
<span class="edit-text">Cliquez pour modifier</span>
|
||||
<span class="edit-text">{{ t('clickToEdit') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,12 +56,12 @@
|
||||
<div class="card-actions">
|
||||
<button class="secondary"
|
||||
@click="cancel">
|
||||
Annuler
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary"
|
||||
@click="showCropper ? applyCrop() : publish()"
|
||||
:disabled="!selectedFile">
|
||||
{{ showCropper ? 'Appliquer' : 'Enregistrer' }}
|
||||
{{ showCropper ? t('apply') : t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,6 +72,7 @@ import {ref} from 'vue'
|
||||
import {useClient} from '@/plugins/api.js'
|
||||
import { Cropper } from 'vue-advanced-cropper'
|
||||
import 'vue-advanced-cropper/dist/style.css'
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
@@ -92,6 +93,9 @@ const cropper = ref(null)
|
||||
const TARGET_WIDTH = 960
|
||||
const TARGET_HEIGHT = 320
|
||||
|
||||
// Get translations for this component
|
||||
const t = useTranslations()
|
||||
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value.click()
|
||||
}
|
||||
@@ -126,7 +130,7 @@ const startEditing = () => {
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading image for editing:', error)
|
||||
errorMessage.value = 'Une erreur est survenue lors du chargement de l\'image'
|
||||
errorMessage.value = t('errors.imageLoad')
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -162,7 +166,7 @@ const publish = async () => {
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
errorMessage.value = 'Une erreur est survenue lors de l\'envoi de l\'image'
|
||||
errorMessage.value = t('errors.imageUpload')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
frontend/src/views/creators/CreateCreator.en.json
Normal file
3
frontend/src/views/creators/CreateCreator.en.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"title": "Create your Hutopy"
|
||||
}
|
||||
3
frontend/src/views/creators/CreateCreator.es.json
Normal file
3
frontend/src/views/creators/CreateCreator.es.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"title": "Crea tu Hutopy"
|
||||
}
|
||||
3
frontend/src/views/creators/CreateCreator.fr.json
Normal file
3
frontend/src/views/creators/CreateCreator.fr.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"title": "Créez votre Hutopy"
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import {useRouter, useRoute} from "vue-router";
|
||||
import NameEditor from "@/views/creators/NameEditor.vue";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const creatorName = ref('');
|
||||
const creatorNameReservationId = ref(undefined);
|
||||
@@ -17,6 +18,7 @@ const router = useRouter();
|
||||
const route = useRoute();
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const userProfileStore = useUserProfileStore();
|
||||
const t = useTranslations();
|
||||
|
||||
function handleCreatorNameReservationIdChanged($event) {
|
||||
creatorNameReservationId.value = $event
|
||||
@@ -48,9 +50,9 @@ async function createAccount() {
|
||||
await router.push(`/@${creatorProfileStore.creator.slug}`);
|
||||
} catch (error) {
|
||||
if (error?.response?.data?.errors) {
|
||||
errorMessage.value = error.response.data.errors[0]?.['reason'] || 'An unexpected error occurred.';
|
||||
errorMessage.value = error.response.data.errors[0]?.['reason'] || t('errors.unexpected');
|
||||
} else {
|
||||
errorMessage.value = error?.response?.data?.message || error.message || 'An unexpected error occurred.';
|
||||
errorMessage.value = error?.response?.data?.message || error.message || t('errors.unexpected');
|
||||
}
|
||||
} finally {
|
||||
isOperationPending.value = false;
|
||||
@@ -64,7 +66,7 @@ async function createAccount() {
|
||||
<div class="card">
|
||||
|
||||
<div class="card-title">
|
||||
Créez votre Hutopy.
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
@@ -79,13 +81,13 @@ async function createAccount() {
|
||||
<button
|
||||
class="secondary"
|
||||
@click="cancel">
|
||||
Cancel
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button
|
||||
class="primary"
|
||||
:disabled="!canSave || isOperationPending"
|
||||
@click="createAccount">
|
||||
Créer
|
||||
{{ t('create') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
19
frontend/src/views/creators/CreatorHome.en.json
Normal file
19
frontend/src/views/creators/CreatorHome.en.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "About Us",
|
||||
"description": "Description",
|
||||
"mainImage": "Main image"
|
||||
},
|
||||
"support": {
|
||||
"title": "Why Support Us",
|
||||
"description": "Description",
|
||||
"subtitle": "Subtitle"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"phoneNumber": "Phone Number",
|
||||
"email": "Email Address",
|
||||
"videoUrl": "Video URL"
|
||||
}
|
||||
}
|
||||
19
frontend/src/views/creators/CreatorHome.es.json
Normal file
19
frontend/src/views/creators/CreatorHome.es.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "Quiénes Somos",
|
||||
"description": "Descripción",
|
||||
"mainImage": "Imagen principal"
|
||||
},
|
||||
"support": {
|
||||
"title": "Por Qué Apoyarnos",
|
||||
"description": "Descripción",
|
||||
"subtitle": "Subtítulo"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"phoneNumber": "Número de Teléfono",
|
||||
"email": "Dirección de Correo",
|
||||
"videoUrl": "URL del Video"
|
||||
}
|
||||
}
|
||||
19
frontend/src/views/creators/CreatorHome.fr.json
Normal file
19
frontend/src/views/creators/CreatorHome.fr.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "Qui sommes-nous",
|
||||
"description": "Description",
|
||||
"mainImage": "Image principale"
|
||||
},
|
||||
"support": {
|
||||
"title": "Pourquoi nous supporter",
|
||||
"description": "Description",
|
||||
"subtitle": "Sous-titre"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"phoneNumber": "Numéro de Téléphone",
|
||||
"email": "Adresse Email",
|
||||
"videoUrl": "URL Vidéo"
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
class="primary"
|
||||
@click="isEditMode ? saveChanges() : toggleEditMode()"
|
||||
>
|
||||
{{ isEditMode ? 'Enregistrer' : 'Éditer la page' }}
|
||||
{{ isEditMode ? t('save') : t('edit') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -17,14 +17,14 @@
|
||||
class="secondary"
|
||||
@click="cancelEdit"
|
||||
>
|
||||
Annuler
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- MainPage -->
|
||||
<div class="flex flex-col mt-4">
|
||||
|
||||
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">Qui sommes-nous</h1>
|
||||
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">{{ t('sections.about.title') }}</h1>
|
||||
|
||||
<div>
|
||||
<!-- Main image Bloc D'information-->
|
||||
@@ -35,7 +35,7 @@
|
||||
{{ mainImageText }}
|
||||
</p>
|
||||
</div>
|
||||
<v-textarea v-if="isEditMode" v-model="editableMainImageText" class="w-full p-2 py-6 " label="Description"
|
||||
<v-textarea v-if="isEditMode" v-model="editableMainImageText" class="w-full p-2 py-6 " :label="t('sections.about.description')"
|
||||
variant="outlined"></v-textarea>
|
||||
|
||||
<div class="flex flex-row items-center space-x-4">
|
||||
@@ -44,26 +44,26 @@
|
||||
<img
|
||||
v-if="mainImageUrl"
|
||||
:src="mainImageUrl"
|
||||
alt="Image principale"
|
||||
:alt="t('sections.about.mainImage')"
|
||||
class="max-w-full h-auto cursor-pointer"/>
|
||||
</div>
|
||||
<div v-if="isEditMode" class="relative flex justify-center">
|
||||
<label>
|
||||
<input class="hidden" type="file" @change="updateImage('mainImageUrl', $event)"/>
|
||||
<img :src="mainImageUrl || fallbackImage"
|
||||
alt="Image principale"
|
||||
:alt="t('sections.about.mainImage')"
|
||||
class=" max-w-full h-auto cursor-pointer max-h-96"/>
|
||||
</label>
|
||||
<button v-if="isEditMode"
|
||||
class="absolute top-10 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
|
||||
@click="deleteImage('mainImageUrl')">
|
||||
X
|
||||
{{ t('delete') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2 flex flex-col justify-center">
|
||||
<h2 v-if="videoSubtitleMain" class="text-xl font-semibold text-center">
|
||||
Pourquoi nous supporter
|
||||
{{ t('sections.support.title') }}
|
||||
</h2>
|
||||
|
||||
<div v-if="!isEditMode">
|
||||
@@ -76,7 +76,7 @@
|
||||
<v-textarea
|
||||
v-model="editableMainVideoText"
|
||||
class="p-2 rounded-md mt-4"
|
||||
label="Description"
|
||||
:label="t('sections.support.description')"
|
||||
rows="10"
|
||||
variant="outlined"
|
||||
></v-textarea>
|
||||
@@ -92,23 +92,17 @@
|
||||
<v-text-field
|
||||
v-model="editableVideoSubtitle"
|
||||
class="w-full p-2"
|
||||
label="Titre"
|
||||
:label="t('sections.support.subtitle')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<v-textarea v-if="isEditMode"
|
||||
v-model="editableImagesText"
|
||||
class="w-full p-2 border rounded-md"
|
||||
rows="10"
|
||||
variant="outlined">
|
||||
</v-textarea>
|
||||
|
||||
<div v-if="!isEditMode">
|
||||
<p v-if="imagesText" class="text-lg text-justify">
|
||||
{{ imagesText }}
|
||||
</p>
|
||||
</div>
|
||||
v-model="editableVideoText"
|
||||
class="w-full p-2"
|
||||
:label="t('sections.support.description')"
|
||||
variant="outlined"
|
||||
></v-textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -127,10 +121,9 @@
|
||||
|
||||
<div v-if="isEditMode">
|
||||
<v-text-field
|
||||
v-if="isEditMode"
|
||||
v-model="editableVideoUrlMain"
|
||||
class="w-full p-2 rounded-md"
|
||||
label="URL Video"
|
||||
:label="t('fields.videoUrl')"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
/>
|
||||
@@ -248,14 +241,14 @@
|
||||
<v-text-field
|
||||
v-model="editablePhoneNumber"
|
||||
class="w-full p-2"
|
||||
label="Numéro de Téléphone"
|
||||
:label="t('fields.phoneNumber')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="editableEmail"
|
||||
class="w-full p-2"
|
||||
label="Adresse Email"
|
||||
:label="t('fields.email')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
</div>
|
||||
@@ -290,9 +283,13 @@ import {onMounted, ref} from "vue";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import {useTranslations} from '@/translations/translations'
|
||||
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const authStore = useAuthStore();
|
||||
const t = useTranslations();
|
||||
const client = useClient();
|
||||
|
||||
const isLoading = ref(true);
|
||||
|
||||
5
frontend/src/views/creators/CreatorLayout.en.json
Normal file
5
frontend/src/views/creators/CreatorLayout.en.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "This Creator page is pending deletion. You can revert the action in your profile."
|
||||
}
|
||||
}
|
||||
5
frontend/src/views/creators/CreatorLayout.es.json
Normal file
5
frontend/src/views/creators/CreatorLayout.es.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "Esta página de creador está pendiente de eliminación. Puede revertir la acción en su perfil."
|
||||
}
|
||||
}
|
||||
5
frontend/src/views/creators/CreatorLayout.fr.json
Normal file
5
frontend/src/views/creators/CreatorLayout.fr.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "Cette page de créateur est en attente de suppression. Vous pouvez annuler l'action dans votre profil."
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,11 @@ import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import {onMounted} from "vue";
|
||||
import Banner from "@/views/creators/Banner.vue";
|
||||
import Footer from "@/views/main/Footer.vue";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const creatorName = window.location.pathname.split('/@').pop();
|
||||
const t = useTranslations();
|
||||
|
||||
onMounted(async () => {
|
||||
await brandingStore.updateBrand(creatorName);
|
||||
@@ -23,7 +25,7 @@ onMounted(async () => {
|
||||
<div v-else>
|
||||
<div v-if="brandingStore.value.isDeleted"
|
||||
class="bg-red-500 p-2 m-4 text-center font-semibold">
|
||||
This Creator page is pending deletion. You can revert the action in your profile.
|
||||
{{ t('deletion.pending') }}
|
||||
</div>
|
||||
<banner></banner>
|
||||
<router-view></router-view>
|
||||
|
||||
4
frontend/src/views/creators/CreatorLogo.en.json
Normal file
4
frontend/src/views/creators/CreatorLogo.en.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"alt": "Profile Picture",
|
||||
"edit": "Edit Profile Picture"
|
||||
}
|
||||
4
frontend/src/views/creators/CreatorLogo.es.json
Normal file
4
frontend/src/views/creators/CreatorLogo.es.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"alt": "Foto de perfil",
|
||||
"edit": "Editar foto de perfil"
|
||||
}
|
||||
4
frontend/src/views/creators/CreatorLogo.fr.json
Normal file
4
frontend/src/views/creators/CreatorLogo.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"alt": "Photo de profil",
|
||||
"edit": "Modifier la photo de profil"
|
||||
}
|
||||
@@ -8,13 +8,14 @@
|
||||
<img
|
||||
class="shadow-2xl object-cover rounded-full border-solid border-hSecondary border-102 w-[200px] h-[200px] logo-image"
|
||||
:src="brandingStore.value.images?.logo ?? '/images/placeholders/profile.png'"
|
||||
alt="Profile Picture"
|
||||
:alt="t('alt')"
|
||||
/>
|
||||
|
||||
<!-- Tint Effect -->
|
||||
<div
|
||||
v-if="showTint"
|
||||
class="absolute rounded-full inset-0 bg-black/25 cursor-pointer"
|
||||
:title="t('edit')"
|
||||
>
|
||||
<!-- Top-right Icon -->
|
||||
<div
|
||||
@@ -42,9 +43,11 @@ import {useAuthStore} from "@/stores/authStore.js";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import CreatorLogoEditor from "@/views/creators/CreatorLogoEditor.vue";
|
||||
import {computed, ref} from "vue";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
|
||||
// State
|
||||
const showTint = ref(false);
|
||||
|
||||
7
frontend/src/views/creators/CreatorLogoEditor.en.json
Normal file
7
frontend/src/views/creators/CreatorLogoEditor.en.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Choose your Logo",
|
||||
"description": "The logo must be square. Recommended dimensions are 200 x 200 pixels.",
|
||||
"chooseImage": "Choose an image...",
|
||||
"clickToEdit": "Click to edit",
|
||||
"preview": "Logo preview"
|
||||
}
|
||||
7
frontend/src/views/creators/CreatorLogoEditor.es.json
Normal file
7
frontend/src/views/creators/CreatorLogoEditor.es.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Elige tu Logo",
|
||||
"description": "El logo debe ser cuadrado. Las dimensiones recomendadas son 200 x 200 píxeles.",
|
||||
"chooseImage": "Elegir una imagen...",
|
||||
"clickToEdit": "Clic para editar",
|
||||
"preview": "Vista previa del logo"
|
||||
}
|
||||
7
frontend/src/views/creators/CreatorLogoEditor.fr.json
Normal file
7
frontend/src/views/creators/CreatorLogoEditor.fr.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "Choisissez votre Logo",
|
||||
"description": "Le logo doit être carré. Les dimensions recommandées sont 200 x 200 pixels.",
|
||||
"chooseImage": "Choisir une image...",
|
||||
"clickToEdit": "Cliquez pour modifier",
|
||||
"preview": "Aperçu du logo"
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
Choisissez votre Logo
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<p class="card-text">
|
||||
Le logo doit être carré. Les dimensions recommandées sont 200 x 200 pixels.
|
||||
{{ t('description') }}
|
||||
</p>
|
||||
|
||||
<div class="file-input-container">
|
||||
@@ -21,7 +21,7 @@
|
||||
class="choose-file-button"
|
||||
@click="triggerFileInput"
|
||||
>
|
||||
Choisir une image...
|
||||
{{ t('chooseImage') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
<div class="circular-preview">
|
||||
<img
|
||||
:src="fileUrl || fallbackUrl"
|
||||
alt="Aperçu du logo"
|
||||
:alt="t('preview')"
|
||||
class="preview-image"
|
||||
/>
|
||||
<div class="edit-overlay">
|
||||
<span class="edit-text">Cliquez pour modifier</span>
|
||||
<span class="edit-text">{{ t('clickToEdit') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,12 +59,12 @@
|
||||
<div class="card-actions">
|
||||
<button class="secondary"
|
||||
@click="cancel">
|
||||
Annuler
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary"
|
||||
@click="showCropper ? applyCrop() : publish()"
|
||||
:disabled="!selectedFile">
|
||||
{{ showCropper ? 'Appliquer' : 'Enregistrer' }}
|
||||
{{ showCropper ? t('apply') : t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,6 +75,7 @@ import {ref} from 'vue'
|
||||
import {useClient} from '@/plugins/api.js'
|
||||
import { Cropper, CircleStencil } from 'vue-advanced-cropper'
|
||||
import 'vue-advanced-cropper/dist/style.css'
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
@@ -95,6 +96,9 @@ const cropper = ref(null)
|
||||
const TARGET_WIDTH = 200
|
||||
const TARGET_HEIGHT = 200
|
||||
|
||||
// Get translations for this component
|
||||
const t = useTranslations()
|
||||
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value.click()
|
||||
}
|
||||
@@ -129,7 +133,7 @@ const startEditing = () => {
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading image for editing:', error)
|
||||
errorMessage.value = 'Une erreur est survenue lors du chargement de l\'image'
|
||||
errorMessage.value = t('errors.imageLoad')
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -165,7 +169,7 @@ const publish = async () => {
|
||||
emits('closeRequested')
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
errorMessage.value = 'Une erreur est survenue lors de l\'envoi de l\'image'
|
||||
errorMessage.value = t('errors.imageUpload')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
frontend/src/views/creators/DonationButtonBanner.en.json
Normal file
10
frontend/src/views/creators/DonationButtonBanner.en.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"isupport": "I Support",
|
||||
"amount": "Amount",
|
||||
"message": "Message",
|
||||
"send": "Send",
|
||||
"cancel": "Cancel",
|
||||
"errors": {
|
||||
"payment": "An error occurred during payment processing"
|
||||
}
|
||||
}
|
||||
10
frontend/src/views/creators/DonationButtonBanner.es.json
Normal file
10
frontend/src/views/creators/DonationButtonBanner.es.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"isupport": "Apoyo",
|
||||
"amount": "Cantidad",
|
||||
"message": "Mensaje",
|
||||
"send": "Enviar",
|
||||
"cancel": "Cancelar",
|
||||
"errors": {
|
||||
"payment": "Ocurrió un error durante el procesamiento del pago"
|
||||
}
|
||||
}
|
||||
10
frontend/src/views/creators/DonationButtonBanner.fr.json
Normal file
10
frontend/src/views/creators/DonationButtonBanner.fr.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"isupport": "Je Soutiens",
|
||||
"amount": "Montant",
|
||||
"message": "Message",
|
||||
"send": "Envoyer",
|
||||
"cancel": "Annuler",
|
||||
"errors": {
|
||||
"payment": "Une erreur s'est produite lors du traitement du paiement"
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
class="secondary donation-action"
|
||||
@click="openDonationDialog()"
|
||||
>
|
||||
{{ $t('isupportbtn.isupport') }}
|
||||
{{ t('isupport') }}
|
||||
</button>
|
||||
|
||||
<v-dialog v-model="donationModal">
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ $t('isupportbtn.isupport') }}
|
||||
{{ t('isupport') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
@@ -20,7 +20,7 @@
|
||||
placeholder="0"
|
||||
:min="0"
|
||||
class="p-2"
|
||||
:label="`${$t('isupportbtn.amount')}`"
|
||||
:label="t('amount')"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<v-textarea
|
||||
v-model="tipMessage"
|
||||
:label="`${$t('isupportbtn.message')}`"
|
||||
:label="t('message')"
|
||||
class="p-2"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
@@ -45,12 +45,12 @@
|
||||
|
||||
<button class="secondary"
|
||||
@click="closeDonationDialog()">
|
||||
Cancel
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
|
||||
<button class="primary"
|
||||
@click="goPay()">
|
||||
{{ $t('isupportbtn.send') }}
|
||||
{{ t('send') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@
|
||||
class="ma-auto"
|
||||
style="width: 200px"
|
||||
@click="closeDialog()"
|
||||
>Annuler
|
||||
>{{ t('cancel') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@@ -84,8 +84,10 @@ import {useClient} from '@/plugins/api.js';
|
||||
import {useBrandingStore} from '@/stores/brandingStore.js';
|
||||
import {loadStripe} from '@stripe/stripe-js';
|
||||
import {onMounted, ref} from 'vue';
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
|
||||
const props = defineProps({
|
||||
creatorId: {default: 'missing-creator-id', required: true},
|
||||
@@ -134,7 +136,7 @@ async function createCheckoutSession() {
|
||||
return clientSecret.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
errorMessage.value = 'Une erreur est survenue. Veuillez réessayer.';
|
||||
errorMessage.value = t('errors.payment');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
frontend/src/views/creators/NameEditor.en.json
Normal file
3
frontend/src/views/creators/NameEditor.en.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"label": "Page name"
|
||||
}
|
||||
3
frontend/src/views/creators/NameEditor.es.json
Normal file
3
frontend/src/views/creators/NameEditor.es.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"label": "Nombre de la página"
|
||||
}
|
||||
4
frontend/src/views/creators/NameEditor.fr.json
Normal file
4
frontend/src/views/creators/NameEditor.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Nom de la page"
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import {ref, onMounted, onUnmounted} from "vue";
|
||||
import {v7} from "uuid";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
@@ -18,6 +19,7 @@ const emits = defineEmits([
|
||||
]);
|
||||
|
||||
const name = ref(props.name);
|
||||
const t = useTranslations();
|
||||
|
||||
const isOperationPending = ref(false);
|
||||
const reservationState = ref(null);
|
||||
@@ -110,7 +112,7 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
label="Nom de la page"
|
||||
:label="t('label')"
|
||||
v-model="name"
|
||||
outlined
|
||||
@input="handleInput"
|
||||
|
||||
3
frontend/src/views/creators/NameTitle.en.json
Normal file
3
frontend/src/views/creators/NameTitle.en.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"verified": "Verified Account"
|
||||
}
|
||||
3
frontend/src/views/creators/NameTitle.es.json
Normal file
3
frontend/src/views/creators/NameTitle.es.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"verified": "Cuenta Verificada"
|
||||
}
|
||||
3
frontend/src/views/creators/NameTitle.fr.json
Normal file
3
frontend/src/views/creators/NameTitle.fr.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"verified": "Compte Vérifié"
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<template>
|
||||
|
||||
<div v-show="brandingStore.value.verified"
|
||||
class="text-blue m-4">
|
||||
class="text-blue m-4"
|
||||
:title="t('verified')">
|
||||
<icon-account-verified></icon-account-verified>
|
||||
</div>
|
||||
|
||||
@@ -20,5 +21,8 @@
|
||||
<script setup>
|
||||
import IconAccountVerified from "@/components/icons/IconAccountVerified.vue";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
</script>
|
||||
10
frontend/src/views/main/Footer.en.json
Normal file
10
frontend/src/views/main/Footer.en.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"helpandcontact": "Help & Contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Creator Guide",
|
||||
"termsandconditions": "Terms & Conditions",
|
||||
"contentpolicy": "Content Policy",
|
||||
"about": "About",
|
||||
"pricing": "Pricing",
|
||||
"allRightsReserved": "All Rights Reserved"
|
||||
}
|
||||
10
frontend/src/views/main/Footer.es.json
Normal file
10
frontend/src/views/main/Footer.es.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"helpandcontact": "Ayuda y Contacto",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Guía del Creador",
|
||||
"termsandconditions": "Términos y Condiciones",
|
||||
"contentpolicy": "Política de Contenido",
|
||||
"about": "Acerca de",
|
||||
"pricing": "Precios",
|
||||
"allRightsReserved": "Todos los Derechos Reservados"
|
||||
}
|
||||
10
frontend/src/views/main/Footer.fr.json
Normal file
10
frontend/src/views/main/Footer.fr.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"helpandcontact": "Aide & Contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Guide du Créateur",
|
||||
"termsandconditions": "Conditions Générales",
|
||||
"contentpolicy": "Politique de Contenu",
|
||||
"about": "À Propos",
|
||||
"pricing": "Tarifs",
|
||||
"allRightsReserved": "Tous Droits Réservés"
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
import Instagram from "@/views/svg/Instagram.vue";
|
||||
import Facebook from "@/views/svg/Facebook.vue";
|
||||
import X from "@/views/svg/X.vue";
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
|
||||
const t = useTranslations();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -23,36 +26,36 @@ import X from "@/views/svg/X.vue";
|
||||
<div class="footer-links">
|
||||
<router-link to="/documents/helpandcontact"
|
||||
class="link">
|
||||
{{ $t('footer.helpandcontact') }}
|
||||
{{ t('helpandcontact') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/faq"
|
||||
class="link">
|
||||
{{ $t('footer.faq') }}
|
||||
{{ t('faq') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/guideforcreators"
|
||||
class="link">
|
||||
{{ $t('footer.creatorguide') }}
|
||||
{{ t('creatorguide') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/termsandconditions"
|
||||
class="link">
|
||||
{{ $t('footer.termsandconditions') }}
|
||||
{{ t('termsandconditions') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/contentpolicy"
|
||||
class="link">
|
||||
{{ $t('footer.contentpolicy') }}
|
||||
{{ t('contentpolicy') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/about"
|
||||
class="link">
|
||||
{{ $t('footer.about') }}
|
||||
{{ t('about') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/pricing"
|
||||
class="link">
|
||||
{{ $t('footer.pricing') }}
|
||||
{{ t('pricing') }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="footer-copyright">
|
||||
Hutopy ©{{ new Date().getFullYear() }} - {{ $t('footer.allRightsReserved') }}
|
||||
Hutopy ©{{ new Date().getFullYear() }} - {{ t('allRightsReserved') }}
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
|
||||
7
frontend/src/views/main/SideBar.en.json
Normal file
7
frontend/src/views/main/SideBar.en.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"myPage": "my page",
|
||||
"myProfile": "my profile",
|
||||
"reduce": "collapse",
|
||||
"signIn": "login",
|
||||
"signOut": "sign out"
|
||||
}
|
||||
7
frontend/src/views/main/SideBar.es.json
Normal file
7
frontend/src/views/main/SideBar.es.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"myPage": "mi página",
|
||||
"myProfile": "mi perfil",
|
||||
"reduce": "reducir",
|
||||
"signIn": "iniciar sesión",
|
||||
"signOut": "cerrar sesión"
|
||||
}
|
||||
7
frontend/src/views/main/SideBar.fr.json
Normal file
7
frontend/src/views/main/SideBar.fr.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"myPage": "ma page",
|
||||
"myProfile": "mon profil",
|
||||
"reduce": "réduire",
|
||||
"signIn": "connexion",
|
||||
"signOut": "se déconnecter"
|
||||
}
|
||||
@@ -1,35 +1,24 @@
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
||||
import {useUserProfileStore} from "@/stores/userProfileStore.js";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
import {useLanguageStore} from "@/stores/languageStore.js";
|
||||
|
||||
const {locale} = useI18n();
|
||||
const translations = {
|
||||
en: {
|
||||
myPage: "my page",
|
||||
myProfile: "my profile",
|
||||
reduce: "collapse",
|
||||
signIn: "login",
|
||||
signOut: "sign out"
|
||||
},
|
||||
fr: {
|
||||
myPage: "ma page",
|
||||
myProfile: "mon profil",
|
||||
reduce: "réduire",
|
||||
signIn: "connexion",
|
||||
signOut: "se déconnecter"
|
||||
}
|
||||
};
|
||||
const t = computed(() => translations[locale.value] || translations["en"]);
|
||||
const t = useTranslations();
|
||||
const languageStore = useLanguageStore();
|
||||
|
||||
const userProfileStore = useUserProfileStore();
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
function toggleLanguage() {
|
||||
locale.value = locale.value === 'fr' ? 'en' : 'fr';
|
||||
const languages = ['fr', 'en', 'es'];
|
||||
const currentIndex = languages.indexOf(locale.value);
|
||||
const nextIndex = (currentIndex + 1) % languages.length;
|
||||
languageStore.setLocale(languages[nextIndex]);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -73,13 +62,13 @@ function toggleLanguage() {
|
||||
<router-link v-if="creatorProfileStore.hasCreator" :to="`/@${creatorProfileStore.creator.slug}`">
|
||||
<button class="menu-item-action">
|
||||
<i class="mdi mdi-file-account-outline"></i>
|
||||
<span class="label">{{ t.myPage }}</span>
|
||||
<span class="label">{{ t('myPage') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
<router-link v-else to="/create-creator">
|
||||
<button class="menu-item-action">
|
||||
<i class="mdi mdi-file-account-outline"></i>
|
||||
<span class="label">{{ t.myPage }}</span>
|
||||
<span class="label">{{ t('myPage') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -88,7 +77,7 @@ function toggleLanguage() {
|
||||
<router-link to="/profile">
|
||||
<button class="menu-item-action">
|
||||
<i class="mdi mdi-account"></i>
|
||||
<span class="label">{{ t.myProfile }}</span>
|
||||
<span class="label">{{ t('myProfile') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -103,7 +92,7 @@ function toggleLanguage() {
|
||||
<router-link to="/login">
|
||||
<button class="menu-item-action">
|
||||
<i class="mdi mdi-login"></i>
|
||||
<span class="label">{{ t.signIn }}</span>
|
||||
<span class="label">{{ t('signIn') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -111,7 +100,7 @@ function toggleLanguage() {
|
||||
<button class="menu-item-action"
|
||||
@click="authStore.logout">
|
||||
<i class="mdi mdi-logout"></i>
|
||||
<span class="label">{{ t.signOut }}</span>
|
||||
<span class="label">{{ t('signOut') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -163,10 +152,10 @@ function toggleLanguage() {
|
||||
}
|
||||
|
||||
.menu-item-action {
|
||||
/* FIXME: The hover value is not semantically correct */
|
||||
@apply bg-hBackground hover:bg-hSurface;
|
||||
@apply capitalize;
|
||||
@apply flex items-center gap-4 py-2 rounded;
|
||||
/* FIXME: The hover value is not semantically correct */
|
||||
@apply mx-2 lg:mx-0;
|
||||
@apply lg:px-4;
|
||||
@apply w-10 h-10 justify-center lg:w-full lg:h-auto lg:justify-normal;
|
||||
|
||||
22
frontend/src/views/profile/ProfilePage.en.json
Normal file
22
frontend/src/views/profile/ProfilePage.en.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"personal": {
|
||||
"informations": "Personal Information",
|
||||
"fullname": "Full Name",
|
||||
"alias": "Alias",
|
||||
"contact": "Contact Details",
|
||||
"email": "Email"
|
||||
},
|
||||
"creator": {
|
||||
"informations": "Creator Information",
|
||||
"name": "Name",
|
||||
"slug": "URL",
|
||||
"title": "Title",
|
||||
"socialnetwork": "Social Networks"
|
||||
},
|
||||
"danger": {
|
||||
"title": "Danger Zone",
|
||||
"warning": "CAUTION: This will delete your creator page and suspend all tips and donations.",
|
||||
"delete": "DELETE PAGE",
|
||||
"restore": "RESTORE PAGE"
|
||||
}
|
||||
}
|
||||
22
frontend/src/views/profile/ProfilePage.es.json
Normal file
22
frontend/src/views/profile/ProfilePage.es.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"personal": {
|
||||
"informations": "Información personal",
|
||||
"fullname": "Nombre completo",
|
||||
"alias": "Alias",
|
||||
"contact": "Detalles de contacto",
|
||||
"email": "Correo electrónico"
|
||||
},
|
||||
"creator": {
|
||||
"informations": "Información del creador",
|
||||
"name": "Nombre",
|
||||
"slug": "URL",
|
||||
"title": "Título",
|
||||
"socialnetwork": "Redes sociales"
|
||||
},
|
||||
"danger": {
|
||||
"title": "Zona de peligro",
|
||||
"warning": "PRECAUCIÓN: Esto eliminará tu página de creador y suspenderá todos los propinas y donaciones.",
|
||||
"delete": "ELIMINAR PÁGINA",
|
||||
"restore": "RESTAURAR PÁGINA"
|
||||
}
|
||||
}
|
||||
22
frontend/src/views/profile/ProfilePage.fr.json
Normal file
22
frontend/src/views/profile/ProfilePage.fr.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"personal": {
|
||||
"informations": "Informations personnelles",
|
||||
"fullname": "Nom complet",
|
||||
"alias": "Pseudonyme",
|
||||
"contact": "Coordonnées",
|
||||
"email": "Email"
|
||||
},
|
||||
"creator": {
|
||||
"informations": "Informations du créateur",
|
||||
"name": "Nom",
|
||||
"slug": "URL",
|
||||
"title": "Titre",
|
||||
"socialnetwork": "Réseaux sociaux"
|
||||
},
|
||||
"danger": {
|
||||
"title": "Zone de danger",
|
||||
"warning": "ATTENTION : Cela supprimera votre page de créateur et suspendra tous les pourboires et dons.",
|
||||
"delete": "SUPPRIMER LA PAGE",
|
||||
"restore": "RESTAURER LA PAGE"
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ import Linkedin from "@/views/svg/Linkedin.vue";
|
||||
import Tiktok from "@/views/svg/Tiktok.vue";
|
||||
import Instagram from "@/views/svg/Instagram.vue";
|
||||
import Facebook from "@/views/svg/Facebook.vue";
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
|
||||
const t = useTranslations();
|
||||
const userProfileStore = useUserProfileStore()
|
||||
|
||||
// ### Fullname
|
||||
@@ -131,14 +133,14 @@ const closeDialog = () => {
|
||||
<div class="card">
|
||||
|
||||
<div class="card-title">
|
||||
{{ $t('personnalinformation.informations') }}
|
||||
{{ t('personal.informations') }}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<button
|
||||
class="action"
|
||||
@click="openEditFullname">
|
||||
<span class="label">{{ $t('personnalinformation.fullname') }}</span>
|
||||
<span class="label">{{ t('personal.fullname') }}</span>
|
||||
<span class="value">{{ userProfileStore.fullname }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -146,7 +148,7 @@ const closeDialog = () => {
|
||||
<button
|
||||
class="action"
|
||||
@click="openEditAlias">
|
||||
<span class="label">{{ $t('personnalinformation.alias') }}</span>
|
||||
<span class="label">{{ t('personal.alias') }}</span>
|
||||
<span class="value">{{ userProfileStore.user.alias }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -157,12 +159,12 @@ const closeDialog = () => {
|
||||
<div class="card">
|
||||
|
||||
<div class="card-title">
|
||||
{{ $t('personnalinformation.contactdetails') }}
|
||||
{{ t('personal.contact') }}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<button class="action" @click="openDialog('EmailDialog')">
|
||||
<span class="label">{{ $t('personnalinformation.email') }}</span>
|
||||
<span class="label">{{ t('personal.email') }}</span>
|
||||
<span class="value">{{ userProfileStore.user.email }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -173,26 +175,26 @@ const closeDialog = () => {
|
||||
<template v-if="creatorProfileStore.creator !== undefined">
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ $t('creatorinfopage.informations') }}
|
||||
{{ t('creator.informations') }}
|
||||
</div>
|
||||
<div class="content">
|
||||
|
||||
<!-- NAME -->
|
||||
<button class="action" @click="openDialog('ChangeNameDialog')">
|
||||
<span class="label">{{ $t('creatorinfopage.name') }}</span>
|
||||
<span class="label">{{ t('creator.name') }}</span>
|
||||
<span class="value">{{ creatorProfileStore.creator.name }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
|
||||
<button class="action" @click="openDialog('ChangeSlugDialog')">
|
||||
<span class="label">{{ $t('creatorinfopage.slug') }}</span>
|
||||
<span class="label">{{ t('creator.slug') }}</span>
|
||||
<span class="value">@{{ creatorProfileStore.creator.slug }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
|
||||
<!-- TITLE -->
|
||||
<button class="action" @click="openDialog('ChangeTitleDialog')">
|
||||
<span class="label">{{ $t('creatorinfopage.title') }}</span>
|
||||
<span class="label">{{ t('creator.title') }}</span>
|
||||
<span class="value">{{ creatorProfileStore.creator.title }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -209,7 +211,7 @@ const closeDialog = () => {
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ $t('creatorinfopage.socialnetwork') }}
|
||||
{{ t('creator.socialnetwork') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -282,20 +284,20 @@ const closeDialog = () => {
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">Danger Zone</div>
|
||||
<div class="card-title">{{ t('danger.title') }}</div>
|
||||
<div class="content">
|
||||
<p>
|
||||
CAUTION: This will delete your creator page and suspend all tips and donations.
|
||||
{{ t('danger.warning') }}
|
||||
</p>
|
||||
<button v-if="!creatorProfileStore.creator.isDeleted"
|
||||
class="danger-action"
|
||||
@click="creatorProfileStore.removeCreatorPage()">
|
||||
DELETE PAGE
|
||||
{{ t('danger.delete') }}
|
||||
</button>
|
||||
<button v-else
|
||||
class="safe-action"
|
||||
@click="creatorProfileStore.restoreCreatorPage()">
|
||||
RESTORE PAGE
|
||||
{{ t('danger.restore') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -307,12 +309,38 @@ const closeDialog = () => {
|
||||
|
||||
<style scoped>
|
||||
|
||||
.card {
|
||||
@apply bg-hBackground rounded-lg p-4 w-full max-w-2xl;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@apply text-hOnBackground text-lg font-bold mb-4;
|
||||
}
|
||||
|
||||
.content {
|
||||
@apply flex flex-col gap-2;
|
||||
}
|
||||
|
||||
.action {
|
||||
@apply p-2 flex items-center w-full mb-2;
|
||||
@apply font-sans text-base;
|
||||
@apply rounded-md;
|
||||
@apply transition duration-200 ease-in-out;
|
||||
@apply hover:bg-hutopyPrimary active:bg-hutopySecondary;
|
||||
@apply flex flex-row items-center justify-between w-full p-2 rounded-lg;
|
||||
@apply hover:bg-hSurface;
|
||||
}
|
||||
|
||||
.label {
|
||||
@apply text-hOnBackground;
|
||||
}
|
||||
|
||||
.value {
|
||||
@apply text-hOnBackground opacity-70;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
@apply text-hOnBackground opacity-70;
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
@apply fill-current w-6 h-6;
|
||||
@apply text-hOnBackground;
|
||||
}
|
||||
|
||||
.danger-action {
|
||||
@@ -326,22 +354,4 @@ const closeDialog = () => {
|
||||
@apply mt-4;
|
||||
@apply bg-green-800 hover:bg-green-700 active:bg-green-600;
|
||||
}
|
||||
|
||||
.label {
|
||||
@apply flex-none min-w-40 text-left;
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
@apply w-6 h-6;
|
||||
}
|
||||
|
||||
.value {
|
||||
@apply flex-auto text-left pr-6;
|
||||
@apply break-words overflow-auto;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
@apply flex-none;
|
||||
}
|
||||
|
||||
</style>
|
||||
4
frontend/src/views/profile/account/AddressDialog.en.json
Normal file
4
frontend/src/views/profile/account/AddressDialog.en.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Address",
|
||||
"label": "Your address"
|
||||
}
|
||||
4
frontend/src/views/profile/account/AddressDialog.es.json
Normal file
4
frontend/src/views/profile/account/AddressDialog.es.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Dirección",
|
||||
"label": "Tu dirección"
|
||||
}
|
||||
4
frontend/src/views/profile/account/AddressDialog.fr.json
Normal file
4
frontend/src/views/profile/account/AddressDialog.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Adresse",
|
||||
"label": "Votre adresse"
|
||||
}
|
||||
@@ -1,31 +1,33 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
Adresse
|
||||
</v-card-title>
|
||||
<div class="card dialog">
|
||||
<div class="card-title">
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="m-4">
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="address"
|
||||
label="Votre adresse"
|
||||
:label="t('label')"
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn variant="plain" @click="requestClose">
|
||||
Annuler
|
||||
</v-btn>
|
||||
<v-btn color="#A6147D" @click="requestSave">
|
||||
Enregistrer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<div class="card-actions">
|
||||
<button class="secondary" @click="requestClose">
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary" @click="requestSave">
|
||||
{{ t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
|
||||
const t = useTranslations();
|
||||
const props = defineProps(['address'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
|
||||
4
frontend/src/views/profile/account/AliasDialog.en.json
Normal file
4
frontend/src/views/profile/account/AliasDialog.en.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Alias",
|
||||
"label": "Your alias"
|
||||
}
|
||||
4
frontend/src/views/profile/account/AliasDialog.es.json
Normal file
4
frontend/src/views/profile/account/AliasDialog.es.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Alias",
|
||||
"label": "Tu alias"
|
||||
}
|
||||
4
frontend/src/views/profile/account/AliasDialog.fr.json
Normal file
4
frontend/src/views/profile/account/AliasDialog.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Pseudonyme",
|
||||
"label": "Votre pseudonyme"
|
||||
}
|
||||
@@ -3,14 +3,14 @@
|
||||
<div class="card dialog">
|
||||
|
||||
<div class="card-title">
|
||||
{{ $t('personnalinformation.alias') }}
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="alias"
|
||||
:label="$t('personnalinformation.alias')"
|
||||
:label="t('label')"
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
<button class="secondary"
|
||||
@click="requestClose">
|
||||
Annuler
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
|
||||
<button class="primary"
|
||||
@click="requestSave">
|
||||
Enregistrer
|
||||
{{ t('save') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -34,7 +34,9 @@
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
|
||||
const t = useTranslations();
|
||||
const props = defineProps(['alias'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Birthday",
|
||||
"label": "Your birthday"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Fecha de nacimiento",
|
||||
"label": "Tu fecha de nacimiento"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Date de naissance",
|
||||
"label": "Votre date de naissance"
|
||||
}
|
||||
@@ -1,31 +1,33 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
Date de naissance
|
||||
</v-card-title>
|
||||
<div class="card dialog">
|
||||
<div class="card-title">
|
||||
{{ t('title') }}
|
||||
</div>
|
||||
|
||||
<div class="m-4">
|
||||
<div class="card-content">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
v-model="birthDate"
|
||||
label="AAAA-MM-JJ"
|
||||
:label="t('label')"
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn variant="plain" @click="requestClose">
|
||||
Annuler
|
||||
</v-btn>
|
||||
<v-btn color="#A6147D" @click="requestSave">
|
||||
Enregistrer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<div class="card-actions">
|
||||
<button class="secondary" @click="requestClose">
|
||||
{{ t('cancel') }}
|
||||
</button>
|
||||
<button class="primary" @click="requestSave">
|
||||
{{ t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
|
||||
const t = useTranslations();
|
||||
const props = defineProps(['birthDate'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
|
||||
4
frontend/src/views/profile/account/EmailDialog.en.json
Normal file
4
frontend/src/views/profile/account/EmailDialog.en.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Email",
|
||||
"label": "Your email"
|
||||
}
|
||||
4
frontend/src/views/profile/account/EmailDialog.es.json
Normal file
4
frontend/src/views/profile/account/EmailDialog.es.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Correo electrónico",
|
||||
"label": "Tu correo electrónico"
|
||||
}
|
||||
4
frontend/src/views/profile/account/EmailDialog.fr.json
Normal file
4
frontend/src/views/profile/account/EmailDialog.fr.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Email",
|
||||
"label": "Votre email"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user