Improve the name-editor
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
VITE_API_URL=https://localhost:5001/
|
||||
VITE_APP_BASE_URL=http://localhost:5173
|
||||
VITE_APP_API_URL=http://localhost:5173/api
|
||||
VITE_STRIPE_API_KEY=pk_test_51OoveVDrRyqXtNdB2st1NgA8WQA9rhgGaf3q7bCpAOoQyyRS30HMCzGeHba7meVGCSPfb1BVWmOTmFOcr9MkKf5H00bLu5MqsS
|
||||
VITE_GOOGLE_CLIENT_ID=213344094492-9dbaet2gaschju3hj1sgv1umk0qpd833.apps.googleusercontent.com
|
||||
VITE_FACEBOOK_APP_ID
|
||||
@@ -1,4 +1,6 @@
|
||||
VITE_API_URL=https://hutopy-backend-api.azurewebsites.net
|
||||
VITE_APP_BASE_URL=https://hutopy.ca
|
||||
VITE_APP_API_URL=https://hutopy.ca/api
|
||||
VITE_STRIPE_API_KEY=51OoveVDrRyqXtNdBAxIo183PujtqFyU0xUMK9YNtIijcHeDlcLN6pqkZWHbgaBA0FHrwLMSoy3yVLN33NX8ExOxL00MSZwgJN7
|
||||
VITE_GOOGLE_CLIENT_ID=213344094492-7c83lqoh7mnjgadpeqo2lcs1krhbsnnd.apps.googleusercontent.com
|
||||
AZURE_SUBSCRIPTION_ID=46feb20f-3ae1-495a-830b-a31f7b76483d
|
||||
|
||||
7
frontend/src/config.js
Normal file
7
frontend/src/config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// Environment-specific configuration
|
||||
const config = {
|
||||
baseUrl: import.meta.env.VITE_APP_BASE_URL || 'https://hutopy.ca',
|
||||
apiUrl: import.meta.env.VITE_APP_API_URL || 'https://hutopy.ca/api',
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -2,7 +2,8 @@
|
||||
import {ref, onMounted, onUnmounted, computed} from "vue";
|
||||
import {v7} from "uuid";
|
||||
import {useClient} from "@/plugins/api.js";
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import config from '@/config';
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
@@ -23,10 +24,11 @@ const emits = defineEmits([
|
||||
]);
|
||||
|
||||
const name = ref(props.name);
|
||||
const { t } = useI18n();
|
||||
const {t} = useI18n();
|
||||
|
||||
const isOperationPending = ref(false);
|
||||
const reservationState = ref(null);
|
||||
const validationError = ref('');
|
||||
|
||||
// Use the reservationId from props if provided, otherwise generate a new one
|
||||
const reservationId = ref(props.creatorNameReservationId || v7());
|
||||
@@ -36,6 +38,27 @@ const isCurrentSlug = computed(() => {
|
||||
return props.originalSlug && name.value === props.originalSlug;
|
||||
});
|
||||
|
||||
// Base URL for display
|
||||
const baseUrl = computed(() => `${config.baseUrl}/@`);
|
||||
|
||||
// Validation function for the slug
|
||||
const validateSlug = (slug) => {
|
||||
if (!slug) {
|
||||
validationError.value = t('creator.name.errors.required');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow letters, numbers, and hyphens
|
||||
const validSlugRegex = /^[a-zA-Z0-9-]+$/;
|
||||
if (!validSlugRegex.test(slug)) {
|
||||
validationError.value = t('creator.name.errors.invalid');
|
||||
return false;
|
||||
}
|
||||
|
||||
validationError.value = '';
|
||||
return true;
|
||||
};
|
||||
|
||||
// Ensure we emit the reservationId on mount if we generated a new one
|
||||
onMounted(() => {
|
||||
if (!props.creatorNameReservationId) {
|
||||
@@ -68,6 +91,12 @@ const handleInput = () => {
|
||||
return; // Skip if we've already processed this exact name
|
||||
}
|
||||
|
||||
// Validate the slug
|
||||
if (!validateSlug(currentName)) {
|
||||
reservationState.value = "unavailable";
|
||||
return;
|
||||
}
|
||||
|
||||
// If the name is the same as the original slug, set reservation state to "reserved"
|
||||
if (props.originalSlug && currentName === props.originalSlug) {
|
||||
reservationState.value = "reserved";
|
||||
@@ -100,9 +129,9 @@ const checkNameAvailability = async (nameToCheck) => {
|
||||
currentController = controller;
|
||||
|
||||
await client.post(
|
||||
`/api/creators/@${encodeURIComponent(nameToCheck)}/reserve`,
|
||||
{ reservationId: reservationId.value },
|
||||
{ signal: controller.signal }
|
||||
`/api/creators/@${encodeURIComponent(nameToCheck)}/reserve`,
|
||||
{reservationId: reservationId.value},
|
||||
{signal: controller.signal}
|
||||
);
|
||||
|
||||
// Only process the response if this is still the current request
|
||||
@@ -137,9 +166,13 @@ onUnmounted(() => {
|
||||
variant="outlined"
|
||||
:label="t('creator.name.label')"
|
||||
v-model="name"
|
||||
outlined
|
||||
@input="handleInput"
|
||||
:error-messages="validationError"
|
||||
>
|
||||
<template #prepend-inner>
|
||||
<span class="text-gray-400 font-sans">{{ baseUrl }}</span>
|
||||
</template>
|
||||
|
||||
<template #append-inner>
|
||||
<v-progress-circular
|
||||
v-if="reservationState === 'loading'"
|
||||
@@ -164,21 +197,33 @@ onUnmounted(() => {
|
||||
"en": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Your creator handle"
|
||||
"label": "Your creator handle",
|
||||
"errors": {
|
||||
"required": "Creator handle is required",
|
||||
"invalid": "Only letters, numbers, and hyphens are allowed"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Votre identifiant de créateur"
|
||||
"label": "Votre identifiant de créateur",
|
||||
"errors": {
|
||||
"required": "L'identifiant est requis",
|
||||
"invalid": "Seules les lettres, chiffres et tirets sont autorisés"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"creator": {
|
||||
"name": {
|
||||
"label": "Tu identificador de creador"
|
||||
"label": "Tu identificador de creador",
|
||||
"errors": {
|
||||
"required": "El identificador es obligatorio",
|
||||
"invalid": "Solo se permiten letras, números y guiones"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user