Is hutopy finally trilangual
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "^6.0.5",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@stripe/stripe-js": "^3.0.10",
|
||||
"@tinymce/tinymce-vue": "^6.0.1",
|
||||
@@ -22,12 +23,13 @@
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.4.15",
|
||||
"vue-advanced-cropper": "^2.8.9",
|
||||
"vue-i18n": "^9.14.0",
|
||||
"vue-i18n": "^10.0.7",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue3-google-login": "^2.0.26",
|
||||
"vuetify": "^3.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack-env": "^1.18.8",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"eslint": "^8.57.0",
|
||||
|
||||
4253
frontend/pnpm-lock.yaml
generated
Normal file
4253
frontend/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,21 @@
|
||||
|
||||
<script async setup>
|
||||
import SideBar from "@/views/main/SideBar.vue";
|
||||
import {useLanguageStore} from "@/stores/languageStore.js";
|
||||
import {watch} from "vue";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
// Watch for language changes and update i18n locale
|
||||
const languageStore = useLanguageStore();
|
||||
const { locale } = useI18n();
|
||||
|
||||
// Watch for changes to the language store
|
||||
watch(() => languageStore.locale, (newLocale) => {
|
||||
if (newLocale) {
|
||||
locale.value = newLocale;
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { useSessionStorage } from '@vueuse/core';
|
||||
|
||||
// Get the stored locale or default to 'fr'
|
||||
const storedLocale = useSessionStorage('user-locale', 'fr');
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: storedLocale.value,
|
||||
fallbackLocale: 'en',
|
||||
messages: {
|
||||
en: {},
|
||||
fr: {},
|
||||
es: {}
|
||||
}
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
53
frontend/src/locales/en.json
Normal file
53
frontend/src/locales/en.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
// Common actions
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"create": "Create",
|
||||
"apply": "Apply",
|
||||
"preview": "Preview",
|
||||
"label": "Label",
|
||||
"confirm": "Confirm",
|
||||
"close": "Close",
|
||||
|
||||
// Common status
|
||||
"loading": "Loading...",
|
||||
"error": "Error",
|
||||
"success": "Success",
|
||||
|
||||
// Common messages
|
||||
"changesSaved": "Changes saved successfully",
|
||||
"errorOccurred": "An error occurred",
|
||||
|
||||
// Common fields
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"description": "Description",
|
||||
"title": "Title",
|
||||
"image": "Image",
|
||||
"file": "File",
|
||||
|
||||
// Common validation
|
||||
"required": "This field is required",
|
||||
"invalidEmail": "Invalid email address",
|
||||
"invalidPassword": "Invalid password",
|
||||
|
||||
// Social media
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Website",
|
||||
|
||||
// Errors
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred",
|
||||
"imageLoad": "Error loading image",
|
||||
"imageUpload": "Error uploading image"
|
||||
}
|
||||
}
|
||||
40
frontend/src/locales/es.json
Normal file
40
frontend/src/locales/es.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar",
|
||||
"edit": "Editar",
|
||||
"delete": "Eliminar",
|
||||
"create": "Crear",
|
||||
"apply": "Aplicar",
|
||||
"preview": "Vista previa",
|
||||
"label": "Etiqueta",
|
||||
"confirm": "Confirmar",
|
||||
"close": "Cerrar",
|
||||
"loading": "Cargando...",
|
||||
"error": "Error",
|
||||
"success": "Éxito",
|
||||
"changesSaved": "Cambios guardados con éxito",
|
||||
"errorOccurred": "Ha ocurrido un error",
|
||||
"name": "Nombre",
|
||||
"email": "Correo electrónico",
|
||||
"password": "Contraseña",
|
||||
"description": "Descripción",
|
||||
"title": "Título",
|
||||
"image": "Imagen",
|
||||
"file": "Archivo",
|
||||
"required": "Este campo es obligatorio",
|
||||
"invalidEmail": "Correo electrónico inválido",
|
||||
"invalidPassword": "Contraseña inválida",
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Sitio web",
|
||||
"errors": {
|
||||
"unexpected": "Ha ocurrido un error inesperado",
|
||||
"imageLoad": "Error al cargar la imagen",
|
||||
"imageUpload": "Error al subir la imagen"
|
||||
}
|
||||
}
|
||||
40
frontend/src/locales/fr.json
Normal file
40
frontend/src/locales/fr.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"save": "Enregistrer",
|
||||
"cancel": "Annuler",
|
||||
"edit": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"create": "Créer",
|
||||
"apply": "Appliquer",
|
||||
"preview": "Aperçu",
|
||||
"label": "Étiquette",
|
||||
"confirm": "Confirmer",
|
||||
"close": "Fermer",
|
||||
"loading": "Chargement...",
|
||||
"error": "Erreur",
|
||||
"success": "Succès",
|
||||
"changesSaved": "Modifications enregistrées avec succès",
|
||||
"errorOccurred": "Une erreur est survenue",
|
||||
"name": "Nom",
|
||||
"email": "Email",
|
||||
"password": "Mot de passe",
|
||||
"description": "Description",
|
||||
"title": "Titre",
|
||||
"image": "Image",
|
||||
"file": "Fichier",
|
||||
"required": "Ce champ est requis",
|
||||
"invalidEmail": "Adresse email invalide",
|
||||
"invalidPassword": "Mot de passe invalide",
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Site web",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {createApp} from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router/router.js'
|
||||
import router from '@/router/router.js'
|
||||
import {createPinia} from 'pinia'
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import 'vuetify/styles'
|
||||
@@ -9,7 +9,6 @@ import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
import vueGoogleOauth from 'vue3-google-login'
|
||||
import {useAuthStore} from "@/stores/authStore.js";
|
||||
import i18n from './i18n.js';
|
||||
import {useUserProfileStore} from "@/stores/userProfileStore.js";
|
||||
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
||||
import './assets/main.css'
|
||||
@@ -19,21 +18,34 @@ const vuetify = createVuetify({
|
||||
directives
|
||||
});
|
||||
|
||||
import {createI18n} from 'vue-i18n'
|
||||
import en from '@/locales/en.json'
|
||||
import fr from '@/locales/fr.json'
|
||||
import es from '@/locales/es.json'
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
fallbackLocale: 'en',
|
||||
messages: {
|
||||
en: en,
|
||||
fr: fr,
|
||||
es: es
|
||||
}
|
||||
})
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
const app = createApp(App)
|
||||
.use(createPinia())
|
||||
.use(pinia)
|
||||
.use(vuetify)
|
||||
.use(router)
|
||||
.use(i18n)
|
||||
.use(vueGoogleOauth, {
|
||||
clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
||||
})
|
||||
.use(i18n)
|
||||
});
|
||||
|
||||
// Make $t globally available
|
||||
app.config.globalProperties.$t = i18n.global.t;
|
||||
|
||||
// this force the creation and initialization of the stores
|
||||
useAuthStore()
|
||||
useUserProfileStore()
|
||||
useCreatorProfileStore()
|
||||
useAuthStore();
|
||||
useUserProfileStore();
|
||||
useCreatorProfileStore();
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
export default class UserTransactionsModel
|
||||
{
|
||||
amount = "";
|
||||
currency = "";
|
||||
tipMessage = "";
|
||||
created = "";
|
||||
|
||||
|
||||
static createFromApiResult(apiResult){
|
||||
const userTransactionModel = Object.assign(new UserTransactionsModel(), apiResult)
|
||||
|
||||
const date = new Date(userTransactionModel.created);
|
||||
const options = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: 'America/Montreal'
|
||||
};
|
||||
userTransactionModel.created = new Intl.DateTimeFormat('fr-CA', options).format(date);
|
||||
|
||||
return userTransactionModel;
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,21 @@ 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')
|
||||
|
||||
// Get i18n instance
|
||||
const { locale } = useI18n()
|
||||
|
||||
// Set the initial locale from storage
|
||||
locale.value = storedLocale.value
|
||||
if (locale && storedLocale.value) {
|
||||
locale.value = storedLocale.value
|
||||
}
|
||||
|
||||
function setLocale(newLocale) {
|
||||
locale.value = newLocale
|
||||
if (locale) {
|
||||
locale.value = newLocale
|
||||
}
|
||||
storedLocale.value = newLocale
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
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}`
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Login",
|
||||
"alt": "hutopy login"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Iniciar sesión",
|
||||
"alt": "iniciar sesión hutopy"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Connexion",
|
||||
"alt": "connexion hutopy"
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
import {ref} from 'vue';
|
||||
import {GoogleLogin} from "vue3-google-login";
|
||||
import {useAuthStore} from '@/stores/authStore.js';
|
||||
import {useTranslations} from '@/translations/translations';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const {t} = useI18n();
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
@@ -44,3 +44,20 @@ async function googleCallback(token) {
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Sign in to Hutopy",
|
||||
"alt": "Hutopy Login"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Connectez-vous à Hutopy",
|
||||
"alt": "Connexion Hutopy"
|
||||
},
|
||||
"es": {
|
||||
"title": "Iniciar sesión en Hutopy",
|
||||
"alt": "Inicio de sesión Hutopy"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -45,11 +45,11 @@
|
||||
|
||||
<script setup>
|
||||
import {useRouter, useRoute} from 'vue-router';
|
||||
import {useTranslations} from '@/translations/translations';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
function goBack() {
|
||||
const returnUrl = route.query.returnUrl;
|
||||
@@ -62,6 +62,32 @@ function goBack() {
|
||||
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"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"
|
||||
},
|
||||
"fr": {
|
||||
"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 email.",
|
||||
"continue": "Continuer vers"
|
||||
},
|
||||
"es": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
@apply min-h-screen;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"title": "Payment Failed",
|
||||
"message": "We couldn't process your payment. Please try again or contact support if the problem persists.",
|
||||
"continue": "Return to"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"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 à"
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<p>{{ t('message') }}</p>
|
||||
<div class="card-actions">
|
||||
<button class="action-button" @click="goBack()">
|
||||
{{ t('continue') }}
|
||||
{{ t('retry') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -14,11 +14,11 @@
|
||||
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useTranslations } from '@/translations/translations';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
function goBack() {
|
||||
const returnUrl = route.query.returnUrl;
|
||||
@@ -30,6 +30,26 @@ function goBack() {
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Payment Failed",
|
||||
"message": "We couldn't process your payment.",
|
||||
"retry": "Try Again"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Échec du paiement",
|
||||
"message": "Nous n'avons pas pu traiter votre paiement.",
|
||||
"retry": "Réessayer"
|
||||
},
|
||||
"es": {
|
||||
"title": "Pago fallido",
|
||||
"message": "No pudimos procesar su pago.",
|
||||
"retry": "Intentar de nuevo"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
@apply min-h-screen;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"message": "Message (optional)",
|
||||
"amount": "Amount ($)",
|
||||
"send": "Send"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"message": "Mensaje (opcional)",
|
||||
"amount": "Cantidad ($)",
|
||||
"send": "Enviar"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"message": "Message (facultatif)",
|
||||
"amount": "Montant ($)",
|
||||
"send": "Envoyez"
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
|
||||
<v-row>
|
||||
<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="t('amount')" v-model="price"
|
||||
style="border-radius: 10px; margin-bottom: 10px; color: #a30e79; background-color: #f4f4f4">
|
||||
</v-text-field>
|
||||
</v-row>
|
||||
|
||||
<v-row justify="center">
|
||||
<v-btn @click="goPay()"
|
||||
style="margin-bottom: 10px; width: 200px; background-color: #6b0065; color: white; font-weight: bold;">
|
||||
<v-icon left style="margin-right: 10px;">
|
||||
mdi-gift
|
||||
</v-icon>
|
||||
{{ t('send') }}
|
||||
</v-btn>
|
||||
</v-row>
|
||||
|
||||
<v-dialog v-model="isPaymentDialogActive" max-width="720" persistent>
|
||||
<template v-slot:default>
|
||||
<v-card>
|
||||
<div id="checkout">
|
||||
<!-- Checkout will insert the payment form here -->
|
||||
</div>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn block class="ma-auto" style="width: 200px;" :text="t('cancel')" @click="closeDialog()"></v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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();
|
||||
const price = ref(0);
|
||||
const tipMessage = ref("");
|
||||
const isPaymentDialogActive = ref(false);
|
||||
var checkout;
|
||||
|
||||
onMounted(async () => {
|
||||
stripe = await loadStripe(import.meta.env.VITE_STRIPE_API_KEY);
|
||||
})
|
||||
|
||||
const fetchClientSecret = async () => {
|
||||
const clientSecret = await createCheckoutSession();
|
||||
return clientSecret;
|
||||
};
|
||||
|
||||
async function createCheckoutSession() {
|
||||
let clientSecret = await client.post('/api/Stripe', {
|
||||
amount: (price.value * 100),
|
||||
tipMessage: tipMessage.value,
|
||||
creatorId: props.creatorId
|
||||
});
|
||||
|
||||
let secret = clientSecret["data"];
|
||||
return secret;
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
isPaymentDialogActive.value = false;
|
||||
checkout.destroy();
|
||||
}
|
||||
|
||||
async function goPay() {
|
||||
isPaymentDialogActive.value = true;
|
||||
|
||||
checkout = await stripe.initEmbeddedCheckout({
|
||||
fetchClientSecret,
|
||||
});
|
||||
|
||||
await checkout.mount('#checkout');
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"alt": "Creator banner"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"alt": "Banner del creador"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"alt": "Bannière du créateur"
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
<template>
|
||||
|
||||
<div class="relative">
|
||||
<!-- Banner Container with mouse events -->
|
||||
<div
|
||||
@@ -35,7 +34,6 @@
|
||||
></banner-editor>
|
||||
</template>
|
||||
</v-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -43,11 +41,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';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
// State
|
||||
const showTint = ref(false);
|
||||
@@ -61,12 +59,24 @@ const openBannerEditor = () => {
|
||||
const isCurrentCreator = computed(() => {
|
||||
return authStore.userId === brandingStore.value.id;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.banner {
|
||||
@apply border-b border-solid border-hTertiary;
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"alt": "Creator banner"
|
||||
},
|
||||
"fr": {
|
||||
"alt": "Bannière du créateur"
|
||||
},
|
||||
"es": {
|
||||
"alt": "Banner del creador"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"social": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Website"
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"social": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Sitio Web"
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"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'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const baseURL = window.location.origin;
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
// Gèrer le breakpoint du block information.
|
||||
// Définir un point de rupture pour "moyen" (correspondant à md: de Tailwind)
|
||||
@@ -89,56 +89,56 @@ onUnmounted(() => {
|
||||
<a v-if="brandingStore.value?.socials?.facebookUrl"
|
||||
:href="brandingStore.value?.socials?.facebookUrl"
|
||||
target="_blank"
|
||||
:title="t('social.facebook')">
|
||||
:title="t('facebook')">
|
||||
<facebook class="social-icon"></facebook>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.instagramUrl"
|
||||
:href="brandingStore.value?.socials?.instagramUrl"
|
||||
target="_blank"
|
||||
:title="t('social.instagram')">
|
||||
:title="t('instagram')">
|
||||
<instagram class="social-icon"></instagram>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.linkedInUrl"
|
||||
:href="brandingStore.value?.socials?.linkedInUrl"
|
||||
target="_blank"
|
||||
:title="t('social.linkedin')">
|
||||
:title="t('linkedin')">
|
||||
<linkedin class="social-icon"></linkedin>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.redditUrl"
|
||||
:href="brandingStore.value?.socials?.redditUrl"
|
||||
target="_blank"
|
||||
:title="t('social.reddit')">
|
||||
:title="t('reddit')">
|
||||
<reddit class="social-icon"></reddit>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.tikTokUrl"
|
||||
:href="brandingStore.value?.socials?.tikTokUrl"
|
||||
target="_blank"
|
||||
:title="t('social.tiktok')">
|
||||
:title="t('tiktok')">
|
||||
<tiktok class="social-icon"></tiktok>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.xUrl"
|
||||
:href="brandingStore.value?.socials?.xUrl"
|
||||
target="_blank"
|
||||
:title="t('social.x')">
|
||||
:title="t('x')">
|
||||
<x class="social-icon"></x>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.youtubeUrl"
|
||||
:href="brandingStore.value?.socials?.youtubeUrl"
|
||||
target="_blank"
|
||||
:title="t('social.youtube')">
|
||||
:title="t('youtube')">
|
||||
<youtube class="social-icon"></youtube>
|
||||
</a>
|
||||
|
||||
<a v-if="brandingStore.value?.socials?.websiteUrl"
|
||||
:href="brandingStore.value?.socials?.websiteUrl"
|
||||
target="_blank"
|
||||
:title="t('social.website')">
|
||||
:title="t('website')">
|
||||
<web class="social-icon"></web>
|
||||
</a>
|
||||
|
||||
@@ -166,4 +166,39 @@ onUnmounted(() => {
|
||||
@apply flex flex-col gap-y-4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Website"
|
||||
},
|
||||
"fr": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Site web"
|
||||
},
|
||||
"es": {
|
||||
"facebook": "Facebook",
|
||||
"instagram": "Instagram",
|
||||
"linkedin": "LinkedIn",
|
||||
"reddit": "Reddit",
|
||||
"tiktok": "TikTok",
|
||||
"x": "X (Twitter)",
|
||||
"youtube": "YouTube",
|
||||
"website": "Sitio web"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -72,7 +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'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
@@ -94,7 +94,7 @@ const TARGET_WIDTH = 960
|
||||
const TARGET_HEIGHT = 320
|
||||
|
||||
// Get translations for this component
|
||||
const t = useTranslations()
|
||||
const { t } = useI18n()
|
||||
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value.click()
|
||||
@@ -276,3 +276,20 @@ const cancel = () => {
|
||||
@apply max-h-full;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"chooseImage": "Choose an image",
|
||||
"clickToEdit": "Click to edit"
|
||||
},
|
||||
"fr": {
|
||||
"chooseImage": "Choisir une image",
|
||||
"clickToEdit": "Cliquez pour modifier"
|
||||
},
|
||||
"es": {
|
||||
"chooseImage": "Elegir una imagen",
|
||||
"clickToEdit": "Haga clic para editar"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "Create your Hutopy"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "Crea tu Hutopy"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "Créez votre Hutopy"
|
||||
}
|
||||
@@ -5,7 +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'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const creatorName = ref('');
|
||||
const creatorNameReservationId = ref(undefined);
|
||||
@@ -18,7 +18,7 @@ const router = useRouter();
|
||||
const route = useRoute();
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const userProfileStore = useUserProfileStore();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
function handleCreatorNameReservationIdChanged($event) {
|
||||
creatorNameReservationId.value = $event
|
||||
@@ -112,4 +112,33 @@ async function createAccount() {
|
||||
@apply flex items-center justify-center;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Create your Hutopy",
|
||||
"cancel": "Cancel",
|
||||
"create": "Create Creator Page",
|
||||
"errors": {
|
||||
"unexpected": "An unexpected error occurred"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"title": "Créez votre Hutopy",
|
||||
"cancel": "Annuler",
|
||||
"create": "Créer la page créateur",
|
||||
"errors": {
|
||||
"unexpected": "Une erreur inattendue s'est produite"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"title": "Crea tu Hutopy",
|
||||
"cancel": "Cancelar",
|
||||
"create": "Crear página de creador",
|
||||
"errors": {
|
||||
"unexpected": "Se produjo un error inesperado"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"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 ? t('save') : t('edit') }}
|
||||
{{ isEditMode ? t('common.save') : t('common.edit') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -17,14 +17,14 @@
|
||||
class="secondary"
|
||||
@click="cancelEdit"
|
||||
>
|
||||
{{ t('cancel') }}
|
||||
{{ t('common.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- MainPage -->
|
||||
<div class="flex flex-col mt-4">
|
||||
|
||||
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">{{ t('sections.about.title') }}</h1>
|
||||
<h1 class="flex justify-start text-2xl font-bold text-center mb-4">{{ t('creator.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="t('sections.about.description')"
|
||||
<v-textarea v-if="isEditMode" v-model="editableMainImageText" class="w-full p-2 py-6 " :label="t('creator.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="t('sections.about.mainImage')"
|
||||
:alt="t('creator.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="t('sections.about.mainImage')"
|
||||
:alt="t('creator.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')">
|
||||
{{ t('delete') }}
|
||||
{{ t('common.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="w-1/2 flex flex-col justify-center">
|
||||
<h2 v-if="videoSubtitleMain" class="text-xl font-semibold text-center">
|
||||
{{ t('sections.support.title') }}
|
||||
{{ t('creator.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="t('sections.support.description')"
|
||||
:label="t('creator.sections.support.description')"
|
||||
rows="10"
|
||||
variant="outlined"
|
||||
></v-textarea>
|
||||
@@ -92,7 +92,7 @@
|
||||
<v-text-field
|
||||
v-model="editableVideoSubtitle"
|
||||
class="w-full p-2"
|
||||
:label="t('sections.support.subtitle')"
|
||||
:label="t('creator.sections.support.subtitle')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
</div>
|
||||
@@ -100,7 +100,7 @@
|
||||
<v-textarea v-if="isEditMode"
|
||||
v-model="editableVideoText"
|
||||
class="w-full p-2"
|
||||
:label="t('sections.support.description')"
|
||||
:label="t('creator.sections.support.description')"
|
||||
variant="outlined"
|
||||
></v-textarea>
|
||||
</div>
|
||||
@@ -123,7 +123,7 @@
|
||||
<v-text-field
|
||||
v-model="editableVideoUrlMain"
|
||||
class="w-full p-2 rounded-md"
|
||||
:label="t('fields.videoUrl')"
|
||||
:label="t('creator.fields.videoUrl')"
|
||||
type="text"
|
||||
variant="outlined"
|
||||
/>
|
||||
@@ -141,28 +141,28 @@
|
||||
<!-- Première image -->
|
||||
<div v-if="image1Url" class="relative w-full sm:flex-1 ">
|
||||
<img :src="image1Url"
|
||||
alt="Image 1"
|
||||
:alt="t('creator.sections.about.image1')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</div>
|
||||
|
||||
<!-- Deuxième image -->
|
||||
<div v-if="image2Url" class="relative w-full sm:flex-1 ">
|
||||
<img :src="image2Url"
|
||||
alt="Image 2"
|
||||
:alt="t('creator.sections.about.image2')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</div>
|
||||
|
||||
<!-- Troisième image -->
|
||||
<div v-if="image3Url" class="relative w-full sm:flex-1 ">
|
||||
<img :src="image3Url"
|
||||
alt="Image 3"
|
||||
:alt="t('creator.sections.about.image3')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</div>
|
||||
|
||||
<!-- Quatrième image -->
|
||||
<div v-if="image4Url" class="relative w-full sm:flex-1 ">
|
||||
<img :src="image4Url"
|
||||
alt="Image 4"
|
||||
:alt="t('creator.sections.about.image4')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -173,19 +173,19 @@
|
||||
|
||||
<div v-if="isEditMode" class="rounded-2xl">
|
||||
<!--images-->
|
||||
<div class=" text-2xl pa-2">Images</div>
|
||||
<div class=" text-2xl pa-2">{{ t('creator.sections.about.images') }}</div>
|
||||
<div class="pa-2 grid grid-cols-1 gap-4 md:grid-cols-4">
|
||||
<!-- Première image -->
|
||||
<div class="relative">
|
||||
<label>
|
||||
<input class="hidden" type="file" @change="updateImage('image1Url', $event)"/>
|
||||
<img :src="image1Url || fallbackImage"
|
||||
alt="Image 1"
|
||||
:alt="t('creator.sections.about.image1')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</label>
|
||||
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
|
||||
@click="deleteImage('image1Url')">
|
||||
X
|
||||
{{ t('common.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -194,12 +194,12 @@
|
||||
<label>
|
||||
<input class="hidden" type="file" @change="updateImage('image2Url', $event)"/>
|
||||
<img :src="image2Url || fallbackImage"
|
||||
alt="Image 2"
|
||||
:alt="t('creator.sections.about.image2')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</label>
|
||||
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
|
||||
@click="deleteImage('image2Url')">
|
||||
X
|
||||
{{ t('common.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -208,12 +208,12 @@
|
||||
<label>
|
||||
<input class="hidden" type="file" @change="updateImage('image3Url', $event)"/>
|
||||
<img :src="image3Url || fallbackImage"
|
||||
alt="Image 3"
|
||||
:alt="t('creator.sections.about.image3')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</label>
|
||||
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
|
||||
@click="deleteImage('image3Url')">
|
||||
X
|
||||
{{ t('common.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -222,18 +222,18 @@
|
||||
<label>
|
||||
<input class="hidden" type="file" @change="updateImage('image4Url', $event)"/>
|
||||
<img :src="image4Url || fallbackImage"
|
||||
alt="Image 4"
|
||||
:alt="t('creator.sections.about.image4')"
|
||||
class="rounded-md max-w-full h-auto cursor-pointer"/>
|
||||
</label>
|
||||
<button class="absolute top-2 right-2 px-2 py-1 bg-red-500 text-white hover:bg-red-600"
|
||||
@click="deleteImage('image4Url')">
|
||||
X
|
||||
{{ t('common.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Description-->
|
||||
<div class="text-2xl pa-2"> Description</div>
|
||||
<div class="text-2xl pa-2">{{ t('creator.sections.about.description') }}</div>
|
||||
</div>
|
||||
|
||||
<!--Edit-->
|
||||
@@ -241,14 +241,14 @@
|
||||
<v-text-field
|
||||
v-model="editablePhoneNumber"
|
||||
class="w-full p-2"
|
||||
:label="t('fields.phoneNumber')"
|
||||
:label="t('creator.fields.phoneNumber')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="editableEmail"
|
||||
class="w-full p-2"
|
||||
:label="t('fields.email')"
|
||||
:label="t('creator.fields.email')"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
</div>
|
||||
@@ -284,12 +284,12 @@ 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'
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
const authStore = useAuthStore();
|
||||
const creatorProfileStore = useCreatorProfileStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const authStore = useAuthStore();
|
||||
const t = useTranslations();
|
||||
const client = useClient();
|
||||
|
||||
const isLoading = ref(true);
|
||||
@@ -525,4 +525,105 @@ function cancelEdit() {
|
||||
border: 0;
|
||||
border-radius: 0.5rem; /* Pour les bords arrondis */
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"common": {
|
||||
"save": "Save",
|
||||
"edit": "Edit",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"creator": {
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "About",
|
||||
"description": "Description",
|
||||
"mainImage": "Main image",
|
||||
"image1": "Image 1",
|
||||
"image2": "Image 2",
|
||||
"image3": "Image 3",
|
||||
"image4": "Image 4",
|
||||
"images": "Images"
|
||||
},
|
||||
"support": {
|
||||
"title": "Support",
|
||||
"description": "Description",
|
||||
"subtitle": "Subtitle"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"videoUrl": "Video URL",
|
||||
"phoneNumber": "Phone Number",
|
||||
"email": "Email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"common": {
|
||||
"save": "Enregistrer",
|
||||
"edit": "Modifier",
|
||||
"cancel": "Annuler",
|
||||
"delete": "Supprimer"
|
||||
},
|
||||
"creator": {
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "À propos",
|
||||
"description": "Description",
|
||||
"mainImage": "Image principale",
|
||||
"image1": "Image 1",
|
||||
"image2": "Image 2",
|
||||
"image3": "Image 3",
|
||||
"image4": "Image 4",
|
||||
"images": "Images"
|
||||
},
|
||||
"support": {
|
||||
"title": "Support",
|
||||
"description": "Description",
|
||||
"subtitle": "Sous-titre"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"videoUrl": "URL de la vidéo",
|
||||
"phoneNumber": "Numéro de téléphone",
|
||||
"email": "Email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"common": {
|
||||
"save": "Guardar",
|
||||
"edit": "Editar",
|
||||
"cancel": "Cancelar",
|
||||
"delete": "Eliminar"
|
||||
},
|
||||
"creator": {
|
||||
"sections": {
|
||||
"about": {
|
||||
"title": "Acerca de",
|
||||
"description": "Descripción",
|
||||
"mainImage": "Imagen principal",
|
||||
"image1": "Imagen 1",
|
||||
"image2": "Imagen 2",
|
||||
"image3": "Imagen 3",
|
||||
"image4": "Imagen 4",
|
||||
"images": "Imágenes"
|
||||
},
|
||||
"support": {
|
||||
"title": "Soporte",
|
||||
"description": "Descripción",
|
||||
"subtitle": "Subtítulo"
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"videoUrl": "URL del video",
|
||||
"phoneNumber": "Número de teléfono",
|
||||
"email": "Correo electrónico"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "This Creator page is pending deletion. You can revert the action in your profile."
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "Esta página de creador está pendiente de eliminación. Puede revertir la acción en su perfil."
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"deletion": {
|
||||
"pending": "Cette page de créateur est en attente de suppression. Vous pouvez annuler l'action dans votre profil."
|
||||
}
|
||||
}
|
||||
@@ -3,11 +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'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const creatorName = window.location.pathname.split('/@').pop();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
onMounted(async () => {
|
||||
await brandingStore.updateBrand(creatorName);
|
||||
@@ -25,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">
|
||||
{{ t('deletion.pending') }}
|
||||
{{ t('creator.layout.deletion.pending') }}
|
||||
</div>
|
||||
<banner></banner>
|
||||
<router-view></router-view>
|
||||
@@ -35,3 +35,35 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"creator": {
|
||||
"layout": {
|
||||
"deletion": {
|
||||
"pending": "This creator page is pending deletion"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"creator": {
|
||||
"layout": {
|
||||
"deletion": {
|
||||
"pending": "Cette page créateur est en attente de suppression"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"creator": {
|
||||
"layout": {
|
||||
"deletion": {
|
||||
"pending": "Esta página de creador está pendiente de eliminación"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"alt": "Profile Picture",
|
||||
"edit": "Edit Profile Picture"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"alt": "Foto de perfil",
|
||||
"edit": "Editar foto de perfil"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"alt": "Photo de profil",
|
||||
"edit": "Modifier la photo de profil"
|
||||
}
|
||||
@@ -8,14 +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="t('alt')"
|
||||
:alt="t('logoAlt')"
|
||||
/>
|
||||
|
||||
<!-- Tint Effect -->
|
||||
<div
|
||||
v-if="showTint"
|
||||
class="absolute rounded-full inset-0 bg-black/25 cursor-pointer"
|
||||
:title="t('edit')"
|
||||
:title="t('editLogo')"
|
||||
>
|
||||
<!-- Top-right Icon -->
|
||||
<div
|
||||
@@ -43,11 +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'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
// State
|
||||
const showTint = ref(false);
|
||||
@@ -69,4 +69,21 @@ const isCurrentCreator = computed(() => {
|
||||
@apply border-b-4 border-t-4 border-solid border-hTertiary;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"logoAlt": "Creator logo",
|
||||
"editLogo": "Edit logo"
|
||||
},
|
||||
"fr": {
|
||||
"logoAlt": "Logo du créateur",
|
||||
"editLogo": "Modifier le logo"
|
||||
},
|
||||
"es": {
|
||||
"logoAlt": "Logo del creador",
|
||||
"editLogo": "Editar logo"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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">
|
||||
{{ t('title') }}
|
||||
{{ t('logoTitle') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<p class="card-text">
|
||||
{{ t('description') }}
|
||||
{{ t('logoDescription') }}
|
||||
</p>
|
||||
|
||||
<div class="file-input-container">
|
||||
@@ -75,7 +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'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const props = defineProps({
|
||||
creator: {
|
||||
@@ -96,8 +96,7 @@ const cropper = ref(null)
|
||||
const TARGET_WIDTH = 200
|
||||
const TARGET_HEIGHT = 200
|
||||
|
||||
// Get translations for this component
|
||||
const t = useTranslations()
|
||||
const { t } = useI18n();
|
||||
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value.click()
|
||||
@@ -292,3 +291,26 @@ const cancel = () => {
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"logoTitle": "Edit Logo",
|
||||
"logoDescription": "Choose a logo image for your creator page. The image will be cropped to a circle.",
|
||||
"chooseImage": "Choose Image",
|
||||
"clickToEdit": "Click to edit"
|
||||
},
|
||||
"fr": {
|
||||
"logoTitle": "Modifier le logo",
|
||||
"logoDescription": "Choisissez une image de logo pour votre page de créateur. L'image sera recadrée en cercle.",
|
||||
"chooseImage": "Choisir une image",
|
||||
"clickToEdit": "Cliquez pour modifier"
|
||||
},
|
||||
"es": {
|
||||
"logoTitle": "Editar logo",
|
||||
"logoDescription": "Elige una imagen de logo para tu página de creador. La imagen se recortará en círculo.",
|
||||
"chooseImage": "Elegir imagen",
|
||||
"clickToEdit": "Haz clic para editar"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"isupport": "I Support",
|
||||
"amount": "Amount",
|
||||
"message": "Message",
|
||||
"send": "Send",
|
||||
"cancel": "Cancel",
|
||||
"errors": {
|
||||
"payment": "An error occurred during payment processing"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"isupport": "Apoyo",
|
||||
"amount": "Cantidad",
|
||||
"message": "Mensaje",
|
||||
"send": "Enviar",
|
||||
"cancel": "Cancelar",
|
||||
"errors": {
|
||||
"payment": "Ocurrió un error durante el procesamiento del pago"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"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('isupport') }}
|
||||
{{ t('creator.donation.isupport') }}
|
||||
</button>
|
||||
|
||||
<v-dialog v-model="donationModal">
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ t('isupport') }}
|
||||
{{ t('creator.donation.isupport') }}
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
@@ -20,7 +20,7 @@
|
||||
placeholder="0"
|
||||
:min="0"
|
||||
class="p-2"
|
||||
:label="t('amount')"
|
||||
:label="t('creator.donation.amount')"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<v-textarea
|
||||
v-model="tipMessage"
|
||||
:label="t('message')"
|
||||
:label="t('creator.donation.message')"
|
||||
class="p-2"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
@@ -45,12 +45,12 @@
|
||||
|
||||
<button class="secondary"
|
||||
@click="closeDonationDialog()">
|
||||
{{ t('cancel') }}
|
||||
{{ t('common.cancel') }}
|
||||
</button>
|
||||
|
||||
<button class="primary"
|
||||
@click="goPay()">
|
||||
{{ t('send') }}
|
||||
{{ t('creator.donation.send') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@
|
||||
class="ma-auto"
|
||||
style="width: 200px"
|
||||
@click="closeDialog()"
|
||||
>{{ t('cancel') }}
|
||||
>{{ t('common.cancel') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@@ -84,10 +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'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
creatorId: {default: 'missing-creator-id', required: true},
|
||||
@@ -136,7 +136,7 @@ async function createCheckoutSession() {
|
||||
return clientSecret.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
errorMessage.value = t('errors.payment');
|
||||
errorMessage.value = t('creator.donation.errors.payment');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,3 +185,56 @@ function preventNonNumeric(event) {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"common": {
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "I Support",
|
||||
"amount": "Amount ($)",
|
||||
"message": "Message (optional)",
|
||||
"send": "Send",
|
||||
"errors": {
|
||||
"payment": "An error occurred during payment processing"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"common": {
|
||||
"cancel": "Annuler"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Je Soutiens",
|
||||
"amount": "Montant ($)",
|
||||
"message": "Message (optionnel)",
|
||||
"send": "Envoyer",
|
||||
"errors": {
|
||||
"payment": "Une erreur s'est produite lors du traitement du paiement"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"common": {
|
||||
"cancel": "Cancelar"
|
||||
},
|
||||
"creator": {
|
||||
"donation": {
|
||||
"isupport": "Apoyo",
|
||||
"amount": "Cantidad ($)",
|
||||
"message": "Mensaje (opcional)",
|
||||
"send": "Enviar",
|
||||
"errors": {
|
||||
"payment": "Ocurrió un error durante el procesamiento del pago"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"label": "Page name"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"label": "Nombre de la página"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Nom de la page"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
import {ref, onMounted, onUnmounted} from "vue";
|
||||
import {v7} from "uuid";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
@@ -19,7 +19,7 @@ const emits = defineEmits([
|
||||
]);
|
||||
|
||||
const name = ref(props.name);
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
|
||||
const isOperationPending = ref(false);
|
||||
const reservationState = ref(null);
|
||||
@@ -112,7 +112,7 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
:label="t('label')"
|
||||
:label="t('creator.name.label')"
|
||||
v-model="name"
|
||||
outlined
|
||||
@input="handleInput"
|
||||
@@ -134,4 +134,30 @@ onUnmounted(() => {
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Page name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Nom de la page"
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Nombre de la página"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"verified": "Verified Account"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"verified": "Cuenta Verificada"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"verified": "Compte Vérifié"
|
||||
}
|
||||
@@ -21,8 +21,22 @@
|
||||
<script setup>
|
||||
import IconAccountVerified from "@/components/icons/IconAccountVerified.vue";
|
||||
import {useBrandingStore} from "@/stores/brandingStore.js";
|
||||
import { useTranslations } from '@/translations/translations'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const brandingStore = useBrandingStore();
|
||||
const t = useTranslations();
|
||||
</script>
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"verified": "Verified Account"
|
||||
},
|
||||
"fr": {
|
||||
"verified": "Compte vérifié"
|
||||
},
|
||||
"es": {
|
||||
"verified": "Cuenta verificada"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"helpandcontact": "Help & Contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Creator Guide",
|
||||
"termsandconditions": "Terms & Conditions",
|
||||
"contentpolicy": "Content Policy",
|
||||
"about": "About",
|
||||
"pricing": "Pricing",
|
||||
"allRightsReserved": "All Rights Reserved"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"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,9 +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";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -26,36 +26,36 @@ const t = useTranslations();
|
||||
<div class="footer-links">
|
||||
<router-link to="/documents/helpandcontact"
|
||||
class="link">
|
||||
{{ t('helpandcontact') }}
|
||||
{{ t('footer.helpandcontact') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/faq"
|
||||
class="link">
|
||||
{{ t('faq') }}
|
||||
{{ t('footer.faq') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/guideforcreators"
|
||||
class="link">
|
||||
{{ t('creatorguide') }}
|
||||
{{ t('footer.creatorguide') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/termsandconditions"
|
||||
class="link">
|
||||
{{ t('termsandconditions') }}
|
||||
{{ t('footer.termsandconditions') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/contentpolicy"
|
||||
class="link">
|
||||
{{ t('contentpolicy') }}
|
||||
{{ t('footer.contentpolicy') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/about"
|
||||
class="link">
|
||||
{{ t('about') }}
|
||||
{{ t('footer.about') }}
|
||||
</router-link>
|
||||
<router-link to="/documents/pricing"
|
||||
class="link">
|
||||
{{ t('pricing') }}
|
||||
{{ t('footer.pricing') }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="footer-copyright">
|
||||
Hutopy ©{{ new Date().getFullYear() }} - {{ t('allRightsReserved') }}
|
||||
Hutopy ©{{ new Date().getFullYear() }} - {{ t('footer.allRightsReserved') }}
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
@@ -90,4 +90,45 @@ const t = useTranslations();
|
||||
@apply hover:text-gray-400;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"footer": {
|
||||
"helpandcontact": "Help & Contact",
|
||||
"faq": "FAQ",
|
||||
"creatorguide": "Creator Guide",
|
||||
"termsandconditions": "Terms & Conditions",
|
||||
"contentpolicy": "Content Policy",
|
||||
"about": "About",
|
||||
"pricing": "Pricing",
|
||||
"allRightsReserved": "All Rights Reserved"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"footer": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"footer": {
|
||||
"helpandcontact": "Ayuda y Contacto",
|
||||
"faq": "Preguntas Frecuentes",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,5 +1,8 @@
|
||||
<script setup>
|
||||
import Footer from "@/views/main/Footer.vue";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -17,13 +20,13 @@ import Footer from "@/views/main/Footer.vue";
|
||||
<v-btn
|
||||
class="text-white w-full sm:w-auto inscription-btn-header"
|
||||
to="/login">
|
||||
Inscription
|
||||
{{ t('inscription') }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="w-full sm:w-auto inscription-btn-header-outlined"
|
||||
to="/create-creator"
|
||||
variant="outlined">
|
||||
Créer ma page
|
||||
{{ t('createPage') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
@@ -32,10 +35,10 @@ import Footer from "@/views/main/Footer.vue";
|
||||
|
||||
<div class="support-container flex flex-col items-center space-y-4 md:flex-row md:space-y-0 md:space-x-6">
|
||||
<div class="support-text text-justify md:text-left">
|
||||
<span class="text-white"> Ici, vous <span class="highlight">SOUTENEZ</span> </span><br>
|
||||
<span class="text-white"> les <span class="highlight2">CRÉATEURS</span>, </span><br>
|
||||
<span class="text-white"> les <span class="highlight2">PROJETS</span> </span><br>
|
||||
<span class="text-white"> que vous <span class="highlight">AIMEZ</span> </span>
|
||||
<span class="text-white"> {{ t('support') }} </span><br>
|
||||
<span class="text-white"> {{ t('creators') }} </span><br>
|
||||
<span class="text-white"> {{ t('projects') }} </span><br>
|
||||
<span class="text-white"> {{ t('love') }} </span>
|
||||
</div>
|
||||
<img alt="YourHutopy" class="w-48 h-48 md:w-48 md:h-48 object-contain"
|
||||
src="/images/hutopymedia/banners/heart.png">
|
||||
@@ -45,34 +48,32 @@ import Footer from "@/views/main/Footer.vue";
|
||||
|
||||
<div class="flex flex-col lg:flex-row justify-center items-center lg:space-x-14 space-y-6 lg:space-y-0 pa-1">
|
||||
<div class="bg-hSurface p-4 max-w-md text-center rounded-3xl space-y-8 shadow-xl h-[520px]">
|
||||
<div class="text-xl mb-2 box-text">Je soutiens</div>
|
||||
<div class="text-xl mb-2 box-text">{{ t('supportText') }}</div>
|
||||
<img
|
||||
alt="YourHutopy"
|
||||
class="max-h-56 mx-auto"
|
||||
src="/images/hutopymedia/homepage/hands.png"
|
||||
>
|
||||
<div class="text-md text-justify px-6 ">
|
||||
Soutenez financièrement vos créateurs préférés et participez directement à leur succès. Chaque contribution
|
||||
est un geste fort pour encourager leur talent et leur passion.
|
||||
{{ t('supportDescription') }}
|
||||
</div>
|
||||
<!-- <v-btn>Soutenir</v-btn> -->
|
||||
</div>
|
||||
<div class="bg-hSurface p-4 max-w-md text-center rounded-3xl space-y-8 shadow-xl h-[520px]">
|
||||
<div class="text-xl mb-2 box-text">Je crée</div>
|
||||
<div class="text-xl mb-2 box-text">{{ t('create') }}</div>
|
||||
<img
|
||||
alt="YourHutopy"
|
||||
class="max-h-56 mx-auto"
|
||||
src="/images/hutopymedia/homepage/brain.png"
|
||||
>
|
||||
<div class="text-md text-justify px-6">
|
||||
Offrez à votre communauté l’opportunité de vous soutenir dans vos projets et vos passions. Transformez vos
|
||||
idées en réalité grâce à ceux qui croient en vous.
|
||||
{{ t('creatorDescription') }}
|
||||
</div>
|
||||
<v-btn
|
||||
class="inscription-btn"
|
||||
to="/login"
|
||||
>
|
||||
Inscription
|
||||
{{ t('signup') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
@@ -85,20 +86,19 @@ import Footer from "@/views/main/Footer.vue";
|
||||
<div class="space-y-6">
|
||||
<img alt="YourHutopy" class="w-full mb-6" src="/images/hutopymedia/homepage/votrehutopy.png">
|
||||
<div class="space-y-4">
|
||||
<p class="text-lg leading-relaxed text-justify sm:mx-5 md:mx-1 homepagetext">Hutopy, c'est quoi ?</p>
|
||||
<p class="text-lg leading-relaxed text-justify sm:mx-5 md:mx-1 homepagetext">{{ t('whatIsHutopy') }}</p>
|
||||
<p class="text-lg leading-relaxed text-justify sm:mx-5 md:mx-1 homepagetext">
|
||||
Hutopy est une plateforme québécoise conçue pour mettre en lumière et soutenir financièrement les créateurs, les projets et les organismes d’ici. Que vous soyez humoriste, acteur, cuisinier, écrivain, musicien, artisan, entrepreneur social ou organisme communautaire, Hutopy vous offre un espace 100 % gratuit et accessible pour partager votre mission, bâtir votre communauté et recevoir un soutien financier direct.
|
||||
{{ t('hutopyDescription') }}
|
||||
</p>
|
||||
<p class="text-lg leading-relaxed text-justify sm:mx-5 md:mx-1 homepagetext">
|
||||
Simple, accessible et humain, Hutopy valorise le talent et le soutien, car chaque geste, aussi petit
|
||||
soit-il, peut faire une grande différence dans l’accomplissement de sa propre utopie.
|
||||
{{ t('hutopyValues') }}
|
||||
</p>
|
||||
<div class="flex justify-center">
|
||||
<v-btn
|
||||
class="text-white mt-12 flex items-center justify-center round create-btn"
|
||||
to="/create-creator"
|
||||
>
|
||||
Créer ma page
|
||||
{{ t('createPage') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
@@ -241,4 +241,57 @@ body {
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"inscription": "Sign Up",
|
||||
"createPage": "Create Page",
|
||||
"support": "Support",
|
||||
"creators": "Creators",
|
||||
"projects": "Projects",
|
||||
"love": "Love",
|
||||
"supportText": "Support",
|
||||
"supportDescription": "Support your favorite creators and help them grow. Your contributions make a real difference in their creative journey.",
|
||||
"create": "Create",
|
||||
"creatorDescription": "Create your own page and start your creative journey. Share your passion with the world and build your community.",
|
||||
"signup": "Sign Up",
|
||||
"whatIsHutopy": "What is Hutopy?",
|
||||
"hutopyDescription": "Hutopy is a platform that connects creators with their audience. We provide tools and features to help creators monetize their content and build their community.",
|
||||
"hutopyValues": "Our values are centered around creativity, community, and support. We believe in empowering creators to pursue their passions and build sustainable careers."
|
||||
},
|
||||
"fr": {
|
||||
"inscription": "S'inscrire",
|
||||
"createPage": "Créer une Page",
|
||||
"support": "Soutenir",
|
||||
"creators": "Créateurs",
|
||||
"projects": "Projets",
|
||||
"love": "Passion",
|
||||
"supportText": "Soutenir",
|
||||
"supportDescription": "Soutenez vos créateurs préférés et aidez-les à grandir. Vos contributions font une réelle différence dans leur parcours créatif.",
|
||||
"create": "Créer",
|
||||
"creatorDescription": "Créez votre propre page et commencez votre parcours créatif. Partagez votre passion avec le monde et construisez votre communauté.",
|
||||
"signup": "S'inscrire",
|
||||
"whatIsHutopy": "Qu'est-ce que Hutopy ?",
|
||||
"hutopyDescription": "Hutopy est une plateforme qui connecte les créateurs avec leur audience. Nous fournissons des outils et des fonctionnalités pour aider les créateurs à monétiser leur contenu et à construire leur communauté.",
|
||||
"hutopyValues": "Nos valeurs sont centrées sur la créativité, la communauté et le soutien. Nous croyons en l'autonomisation des créateurs pour poursuivre leurs passions et construire des carrières durables."
|
||||
},
|
||||
"es": {
|
||||
"inscription": "Registrarse",
|
||||
"createPage": "Crear Página",
|
||||
"support": "Apoyar",
|
||||
"creators": "Creadores",
|
||||
"projects": "Proyectos",
|
||||
"love": "Pasión",
|
||||
"supportText": "Apoyar",
|
||||
"supportDescription": "Apoya a tus creadores favoritos y ayúdales a crecer. Tus contribuciones hacen una diferencia real en su viaje creativo.",
|
||||
"create": "Crear",
|
||||
"creatorDescription": "Crea tu propia página y comienza tu viaje creativo. Comparte tu pasión con el mundo y construye tu comunidad.",
|
||||
"signup": "Registrarse",
|
||||
"whatIsHutopy": "¿Qué es Hutopy?",
|
||||
"hutopyDescription": "Hutopy es una plataforma que conecta a los creadores con su audiencia. Proporcionamos herramientas y funciones para ayudar a los creadores a monetizar su contenido y construir su comunidad.",
|
||||
"hutopyValues": "Nuestros valores se centran en la creatividad, la comunidad y el apoyo. Creemos en empoderar a los creadores para perseguir sus pasiones y construir carreras sostenibles."
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"myPage": "my page",
|
||||
"myProfile": "my profile",
|
||||
"reduce": "collapse",
|
||||
"signIn": "login",
|
||||
"signOut": "sign out"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"myPage": "mi página",
|
||||
"myProfile": "mi perfil",
|
||||
"reduce": "reducir",
|
||||
"signIn": "iniciar sesión",
|
||||
"signOut": "cerrar sesión"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"myPage": "ma page",
|
||||
"myProfile": "mon profil",
|
||||
"reduce": "réduire",
|
||||
"signIn": "connexion",
|
||||
"signOut": "se déconnecter"
|
||||
}
|
||||
@@ -3,11 +3,9 @@ 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 t = useTranslations();
|
||||
const {locale, t} = useI18n();
|
||||
const languageStore = useLanguageStore();
|
||||
|
||||
const userProfileStore = useUserProfileStore();
|
||||
@@ -62,13 +60,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('sidebar.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('sidebar.myPage') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -77,7 +75,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('sidebar.myProfile') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -92,7 +90,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('sidebar.signIn') }}</span>
|
||||
</button>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -100,7 +98,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('sidebar.signOut') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -161,4 +159,33 @@ function toggleLanguage() {
|
||||
@apply w-10 h-10 justify-center lg:w-full lg:h-auto lg:justify-normal;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"sidebar": {
|
||||
"myPage": "My Page",
|
||||
"myProfile": "My Profile",
|
||||
"signIn": "Sign In",
|
||||
"signOut": "Sign Out"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"sidebar": {
|
||||
"myPage": "Ma Page",
|
||||
"myProfile": "Mon Profil",
|
||||
"signIn": "Se Connecter",
|
||||
"signOut": "Se Déconnecter"
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"sidebar": {
|
||||
"myPage": "Mi Página",
|
||||
"myProfile": "Mi Perfil",
|
||||
"signIn": "Iniciar Sesión",
|
||||
"signOut": "Cerrar Sesión"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"personal": {
|
||||
"informations": "Personal Information",
|
||||
"fullname": "Full Name",
|
||||
"alias": "Alias",
|
||||
"contact": "Contact Details",
|
||||
"email": "Email"
|
||||
},
|
||||
"creator": {
|
||||
"informations": "Creator Information",
|
||||
"name": "Name",
|
||||
"slug": "URL",
|
||||
"title": "Title",
|
||||
"stripeAccountId": "Stripe Account ID",
|
||||
"socialnetwork": "Social Networks"
|
||||
},
|
||||
"danger": {
|
||||
"title": "Danger Zone",
|
||||
"warning": "WARNING: This will delete your creator page and suspend all tips and donations.",
|
||||
"delete": "DELETE PAGE",
|
||||
"restore": "RESTORE PAGE"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"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",
|
||||
"stripeAccountId": "ID de cuenta Stripe",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"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",
|
||||
"stripeAccountId": "ID du compte Stripe",
|
||||
"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,9 +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";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
const userProfileStore = useUserProfileStore()
|
||||
|
||||
// ### Fullname
|
||||
@@ -134,14 +134,14 @@ const closeDialog = () => {
|
||||
<div class="card">
|
||||
|
||||
<div class="card-title">
|
||||
{{ t('personal.informations') }}
|
||||
{{ t('personalInfo') }}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<button
|
||||
class="action"
|
||||
@click="openEditFullname">
|
||||
<span class="label">{{ t('personal.fullname') }}</span>
|
||||
<span class="label">{{ t('fullName') }}</span>
|
||||
<span class="value">{{ userProfileStore.fullname }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -149,7 +149,7 @@ const closeDialog = () => {
|
||||
<button
|
||||
class="action"
|
||||
@click="openEditAlias">
|
||||
<span class="label">{{ t('personal.alias') }}</span>
|
||||
<span class="label">{{ t('alias') }}</span>
|
||||
<span class="value">{{ userProfileStore.user.alias }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -160,12 +160,12 @@ const closeDialog = () => {
|
||||
<div class="card">
|
||||
|
||||
<div class="card-title">
|
||||
{{ t('personal.contact') }}
|
||||
{{ t('contactInfo') }}
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<button class="action" @click="openDialog('EmailDialog')">
|
||||
<span class="label">{{ t('personal.email') }}</span>
|
||||
<span class="label">{{ t('email') }}</span>
|
||||
<span class="value">{{ userProfileStore.user.email }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -176,33 +176,33 @@ const closeDialog = () => {
|
||||
<template v-if="creatorProfileStore.creator !== undefined">
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ t('creator.informations') }}
|
||||
{{ t('creatorInfo') }}
|
||||
</div>
|
||||
<div class="content">
|
||||
|
||||
<!-- NAME -->
|
||||
<button class="action" @click="openDialog('ChangeNameDialog')">
|
||||
<span class="label">{{ t('creator.name') }}</span>
|
||||
<span class="label">{{ t('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('creator.slug') }}</span>
|
||||
<span class="label">{{ t('username') }}</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('creator.title') }}</span>
|
||||
<span class="label">{{ t('title') }}</span>
|
||||
<span class="value">{{ creatorProfileStore.creator.title }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
|
||||
<!-- STRIPE -->
|
||||
<button class="action" @click="openDialog('ChangeStripeIdDialog')">
|
||||
<span class="label">{{ t('creator.stripeAccountId') }}</span>
|
||||
<span class="label">{{ t('stripeAccountId') }}</span>
|
||||
<span class="value">{{ creatorProfileStore.creator.stripeId }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
@@ -212,7 +212,7 @@ const closeDialog = () => {
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
{{ t('creator.socialnetwork') }}
|
||||
{{ t('socialNetworks') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -248,7 +248,7 @@ const closeDialog = () => {
|
||||
<span class="value">{{ creatorProfileStore.creator.socials?.linkedInUrl }}</span>
|
||||
<span class="chevron"><v-icon>mdi-chevron-right</v-icon></span>
|
||||
</button>
|
||||
|
||||
|
||||
<button class="action" @click="openDialog('SocialsDialog')">
|
||||
<span class="label">
|
||||
<tiktok class="social-icon"></tiktok>
|
||||
@@ -285,20 +285,20 @@ const closeDialog = () => {
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">{{ t('danger.title') }}</div>
|
||||
<div class="card-title">{{ t('dangerZone') }}</div>
|
||||
<div class="content">
|
||||
<p>
|
||||
{{ t('danger.warning') }}
|
||||
{{ t('deleteWarning') }}
|
||||
</p>
|
||||
<button v-if="!creatorProfileStore.creator.isDeleted"
|
||||
class="danger-action"
|
||||
@click="creatorProfileStore.removeCreatorPage()">
|
||||
{{ t('danger.delete') }}
|
||||
{{ t('deleteCreatorPage') }}
|
||||
</button>
|
||||
<button v-else
|
||||
class="safe-action"
|
||||
@click="creatorProfileStore.restoreCreatorPage()">
|
||||
{{ t('danger.restore') }}
|
||||
{{ t('restoreCreatorPage') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,7 +309,6 @@ const closeDialog = () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.card {
|
||||
@apply bg-hBackground rounded-lg p-4 w-full max-w-2xl;
|
||||
}
|
||||
@@ -355,4 +354,42 @@ const closeDialog = () => {
|
||||
@apply mt-4;
|
||||
@apply bg-green-800 hover:bg-green-700 active:bg-green-600;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"personalInfo": "Personal Information",
|
||||
"fullName": "Full Name",
|
||||
"alias": "Alias",
|
||||
"contactInfo": "Contact Information",
|
||||
"email": "Email",
|
||||
"creatorInfo": "Creator Information",
|
||||
"dangerZone": "Danger Zone",
|
||||
"deleteWarning": "Are you sure you want to delete your creator page? This action cannot be undone.",
|
||||
"restoreWarning": "Are you sure you want to restore your creator page? This will make your page visible again."
|
||||
},
|
||||
"fr": {
|
||||
"personalInfo": "Informations Personnelles",
|
||||
"fullName": "Nom Complet",
|
||||
"alias": "Alias",
|
||||
"contactInfo": "Informations de Contact",
|
||||
"email": "Email",
|
||||
"creatorInfo": "Informations du Créateur",
|
||||
"dangerZone": "Zone de Danger",
|
||||
"deleteWarning": "Êtes-vous sûr de vouloir supprimer votre page de créateur ? Cette action est irréversible.",
|
||||
"restoreWarning": "Êtes-vous sûr de vouloir restaurer votre page de créateur ? Cela rendra votre page à nouveau visible."
|
||||
},
|
||||
"es": {
|
||||
"personalInfo": "Información Personal",
|
||||
"fullName": "Nombre Completo",
|
||||
"alias": "Alias",
|
||||
"contactInfo": "Información de Contacto",
|
||||
"email": "Correo Electrónico",
|
||||
"creatorInfo": "Información del Creador",
|
||||
"dangerZone": "Zona de Peligro",
|
||||
"deleteWarning": "¿Estás seguro de que quieres eliminar tu página de creador? Esta acción no se puede deshacer.",
|
||||
"restoreWarning": "¿Estás seguro de que quieres restaurar tu página de creador? Esto hará que tu página sea visible nuevamente."
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Address",
|
||||
"label": "Your address"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Dirección",
|
||||
"label": "Tu dirección"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Adresse",
|
||||
"label": "Votre adresse"
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
const props = defineProps(['address'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
@@ -36,3 +36,20 @@ const address = ref(props.address);
|
||||
const requestClose = () => emit('close')
|
||||
const requestSave = () => emit('save', address.value)
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Address",
|
||||
"label": "Your address"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Adresse",
|
||||
"label": "Votre adresse"
|
||||
},
|
||||
"es": {
|
||||
"title": "Dirección",
|
||||
"label": "Tu dirección"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Alias",
|
||||
"label": "Your alias"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Alias",
|
||||
"label": "Tu alias"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Pseudonyme",
|
||||
"label": "Votre pseudonyme"
|
||||
}
|
||||
@@ -34,9 +34,9 @@
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const { t } = useI18n();
|
||||
const props = defineProps(['alias'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
@@ -46,4 +46,21 @@ const requestClose = () => emit('close')
|
||||
const requestSave = () => emit('save', alias.value)
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Alias",
|
||||
"label": "Your alias"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Alias",
|
||||
"label": "Votre alias"
|
||||
},
|
||||
"es": {
|
||||
"title": "Alias",
|
||||
"label": "Tu alias"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Birthday",
|
||||
"label": "Your birthday"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Fecha de nacimiento",
|
||||
"label": "Tu fecha de nacimiento"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Date de naissance",
|
||||
"label": "Votre date de naissance"
|
||||
}
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
<script setup>
|
||||
import {ref} from 'vue';
|
||||
import { useTranslations } from "@/translations/translations";
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
const t = useTranslations();
|
||||
const {t} = useI18n();
|
||||
const props = defineProps(['birthDate'])
|
||||
const emit = defineEmits(['close', 'save'])
|
||||
|
||||
@@ -36,3 +36,20 @@ const birthDate = ref(props.birthDate)
|
||||
const requestClose = () => emit('close')
|
||||
const requestSave = () => emit('save', birthDate.value)
|
||||
</script>
|
||||
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"title": "Birthday",
|
||||
"label": "Your birthday"
|
||||
},
|
||||
"fr": {
|
||||
"title": "Date de naissance",
|
||||
"label": "Votre date de naissance"
|
||||
},
|
||||
"es": {
|
||||
"title": "Fecha de nacimiento",
|
||||
"label": "Tu fecha de nacimiento"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"title": "Email",
|
||||
"label": "Your email"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user