Add optional slug field to business registration form
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -50,6 +50,7 @@ export type BusinessRegistrationRequest = {
|
||||
export type CreateBusinessRegistrationPayload = {
|
||||
title: string;
|
||||
categoryId: string;
|
||||
slug?: string;
|
||||
description?: string;
|
||||
contactPhone?: string;
|
||||
address?: string;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/** Simple slug for API (latin, hyphen-separated). */
|
||||
export function slugify(value: string): string {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/[^a-z0-9-]/g, '')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
}
|
||||
|
||||
const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
||||
|
||||
export function isValidSlug(slug: string): boolean {
|
||||
return SLUG_PATTERN.test(slug);
|
||||
}
|
||||
|
||||
export function optionalSlug(value: string): string | undefined {
|
||||
const trimmed = value.trim();
|
||||
return trimmed || undefined;
|
||||
}
|
||||
@@ -37,7 +37,16 @@
|
||||
</div>
|
||||
|
||||
<form v-if="showForm" class="space-y-4" @submit.prevent="onSubmit">
|
||||
<AppInput id="bizTitle" v-model="form.title" label="نام کسبوکار" required />
|
||||
<AppInput id="bizTitle" v-model="form.title" label="نام کسبوکار" required @blur="maybeSlug" />
|
||||
|
||||
<AppInput
|
||||
id="bizSlug"
|
||||
v-model="form.slug"
|
||||
label="اسلاگ (انگلیسی)"
|
||||
ltr
|
||||
placeholder="اختیاری — از عنوان ساخته میشود"
|
||||
@input="slugTouched = true"
|
||||
/>
|
||||
|
||||
<div class="space-y-1.5">
|
||||
<label for="bizCategory" class="block text-sm font-medium text-muted">دسته</label>
|
||||
@@ -93,6 +102,7 @@ import AppButton from '@/components/ui/AppButton.vue';
|
||||
import AppInput from '@/components/ui/AppInput.vue';
|
||||
import WebAppLayout from '@/layouts/WebAppLayout.vue';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { isValidSlug, optionalSlug, slugify } from '@/utils/slug';
|
||||
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
@@ -100,11 +110,13 @@ const auth = useAuthStore();
|
||||
const loading = ref(true);
|
||||
const saving = ref(false);
|
||||
const error = ref('');
|
||||
const slugTouched = ref(false);
|
||||
const categories = ref<BusinessCategory[]>([]);
|
||||
const requests = ref<BusinessRegistrationRequest[]>([]);
|
||||
|
||||
const form = ref({
|
||||
title: '',
|
||||
slug: '',
|
||||
categoryId: '',
|
||||
description: '',
|
||||
contactPhone: '',
|
||||
@@ -148,17 +160,29 @@ onMounted(async () => {
|
||||
}
|
||||
});
|
||||
|
||||
function maybeSlug() {
|
||||
if (!slugTouched.value && !form.value.slug.trim()) {
|
||||
form.value.slug = slugify(form.value.title);
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!form.value.title.trim() || !form.value.categoryId) {
|
||||
error.value = 'نام و دسته را وارد کنید.';
|
||||
return;
|
||||
}
|
||||
const slug = optionalSlug(form.value.slug);
|
||||
if (slug && !isValidSlug(slug)) {
|
||||
error.value = 'اسلاگ فقط حروف کوچک انگلیسی و خط تیره باشد.';
|
||||
return;
|
||||
}
|
||||
saving.value = true;
|
||||
error.value = '';
|
||||
try {
|
||||
await submitBusinessRegistration({
|
||||
title: form.value.title.trim(),
|
||||
categoryId: form.value.categoryId,
|
||||
...(slug ? { slug } : {}),
|
||||
description: form.value.description.trim() || undefined,
|
||||
contactPhone: form.value.contactPhone.trim() || undefined,
|
||||
address: form.value.address.trim() || undefined,
|
||||
|
||||
Reference in New Issue
Block a user