Add optional slug field to business registration form

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-24 15:58:52 +03:30
co-authored by Cursor
parent f043b75b98
commit 4f3d461dcf
3 changed files with 47 additions and 1 deletions
+1
View File
@@ -50,6 +50,7 @@ export type BusinessRegistrationRequest = {
export type CreateBusinessRegistrationPayload = { export type CreateBusinessRegistrationPayload = {
title: string; title: string;
categoryId: string; categoryId: string;
slug?: string;
description?: string; description?: string;
contactPhone?: string; contactPhone?: string;
address?: string; address?: string;
+21
View File
@@ -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;
}
+25 -1
View File
@@ -37,7 +37,16 @@
</div> </div>
<form v-if="showForm" class="space-y-4" @submit.prevent="onSubmit"> <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"> <div class="space-y-1.5">
<label for="bizCategory" class="block text-sm font-medium text-muted">دسته</label> <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 AppInput from '@/components/ui/AppInput.vue';
import WebAppLayout from '@/layouts/WebAppLayout.vue'; import WebAppLayout from '@/layouts/WebAppLayout.vue';
import { useAuthStore } from '@/stores/auth'; import { useAuthStore } from '@/stores/auth';
import { isValidSlug, optionalSlug, slugify } from '@/utils/slug';
const router = useRouter(); const router = useRouter();
const auth = useAuthStore(); const auth = useAuthStore();
@@ -100,11 +110,13 @@ const auth = useAuthStore();
const loading = ref(true); const loading = ref(true);
const saving = ref(false); const saving = ref(false);
const error = ref(''); const error = ref('');
const slugTouched = ref(false);
const categories = ref<BusinessCategory[]>([]); const categories = ref<BusinessCategory[]>([]);
const requests = ref<BusinessRegistrationRequest[]>([]); const requests = ref<BusinessRegistrationRequest[]>([]);
const form = ref({ const form = ref({
title: '', title: '',
slug: '',
categoryId: '', categoryId: '',
description: '', description: '',
contactPhone: '', 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() { async function onSubmit() {
if (!form.value.title.trim() || !form.value.categoryId) { if (!form.value.title.trim() || !form.value.categoryId) {
error.value = 'نام و دسته را وارد کنید.'; error.value = 'نام و دسته را وارد کنید.';
return; return;
} }
const slug = optionalSlug(form.value.slug);
if (slug && !isValidSlug(slug)) {
error.value = 'اسلاگ فقط حروف کوچک انگلیسی و خط تیره باشد.';
return;
}
saving.value = true; saving.value = true;
error.value = ''; error.value = '';
try { try {
await submitBusinessRegistration({ await submitBusinessRegistration({
title: form.value.title.trim(), title: form.value.title.trim(),
categoryId: form.value.categoryId, categoryId: form.value.categoryId,
...(slug ? { slug } : {}),
description: form.value.description.trim() || undefined, description: form.value.description.trim() || undefined,
contactPhone: form.value.contactPhone.trim() || undefined, contactPhone: form.value.contactPhone.trim() || undefined,
address: form.value.address.trim() || undefined, address: form.value.address.trim() || undefined,