Ask for organization business field at signup, including jewelry.

Store Didar-style industry on the org so registration, settings, and Ask Mento share the same catalog.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-03 16:45:59 +03:30
co-authored by Cursor
parent ce94658fcd
commit d2f66d11fc
14 changed files with 286 additions and 8 deletions
+79 -3
View File
@@ -5,16 +5,24 @@ import { api } from '@/lib/api';
import { useAuthStore } from '@/stores/auth';
import type {
InviteUserRequest,
OrganizationDto,
OrgUserDto,
UpdateOrganizationRequest,
UserRole,
} from '@mento/shared';
import { USER_ROLE_LABELS, canManageUsers } from '@/lib/roles';
import { USER_ROLE_LABELS, canManageSettings, canManageUsers } from '@/lib/roles';
import { BUSINESS_FIELDS, BUSINESS_FIELD_LABELS } from '@/lib/business-fields';
const auth = useAuthStore();
const loading = ref(false);
const saving = ref(false);
const error = ref('');
const users = ref<OrgUserDto[]>([]);
const org = ref<OrganizationDto | null>(null);
const orgName = ref('');
const businessField = ref('');
const orgSaving = ref(false);
const orgOk = ref('');
const email = ref('');
const fullName = ref('');
@@ -29,6 +37,7 @@ const inviteRoles: Array<{ value: Exclude<UserRole, 'owner'>; label: string }> =
const isOwner = computed(() => auth.user?.role === 'owner');
const canInvite = computed(() => canManageUsers(auth.user?.role));
const canEditOrg = computed(() => canManageSettings(auth.user?.role));
function roleOptionsFor(user: OrgUserDto): UserRole[] {
if (isOwner.value) return ['owner', 'admin', 'sales', 'support'];
@@ -40,7 +49,14 @@ async function load() {
loading.value = true;
error.value = '';
try {
users.value = (await api.get<OrgUserDto[]>('/users')).data;
const [usersRes, orgRes] = await Promise.all([
api.get<OrgUserDto[]>('/users'),
api.get<OrganizationDto>('/organizations/current'),
]);
users.value = usersRes.data;
org.value = orgRes.data;
orgName.value = orgRes.data.name;
businessField.value = orgRes.data.businessField ?? '';
} catch (e) {
if (axios.isAxiosError(e) && !e.response) {
error.value = 'اتصال به API برقرار نشد.';
@@ -52,6 +68,37 @@ async function load() {
}
}
async function saveOrg() {
if (!canEditOrg.value) return;
if (!businessField.value) {
error.value = 'زمینه فعالیت را انتخاب کنید.';
return;
}
orgSaving.value = true;
error.value = '';
orgOk.value = '';
try {
const payload: UpdateOrganizationRequest = {
name: orgName.value.trim(),
businessField: businessField.value as UpdateOrganizationRequest['businessField'],
};
const { data } = await api.patch<OrganizationDto>('/organizations/current', payload);
org.value = data;
orgName.value = data.name;
businessField.value = data.businessField ?? '';
orgOk.value = 'مشخصات سازمان ذخیره شد.';
} catch (e) {
if (axios.isAxiosError(e)) {
const msg = (e.response?.data as { message?: string | string[] })?.message;
error.value = Array.isArray(msg) ? msg.join('، ') : (msg ?? 'ذخیره سازمان ناموفق بود');
} else {
error.value = 'ذخیره سازمان ناموفق بود';
}
} finally {
orgSaving.value = false;
}
}
async function invite() {
if (!email.value.trim() || !fullName.value.trim() || password.value.length < 8) {
error.value = 'نام، ایمیل و رمز حداقل ۸ کاراکتر لازم است.';
@@ -110,10 +157,33 @@ onMounted(load);
<p class="eyebrow">تنظیمات</p>
<h1>تیم و نقش‌ها</h1>
<p class="lead">
کاربران سازمان را اضافه کنید و نقش بدهید. تنظیمات سازمانی فقط برای مالک و مدیر است.
زمینه فعالیت سازمان و کاربران را اینجا مدیریت کنید. تنظیمات سازمانی فقط برای مالک و مدیر است.
</p>
</header>
<form v-if="org" class="invite" @submit.prevent="saveOrg">
<h2>سازمان</h2>
<div class="grid">
<label>
نام سازمان
<input v-model="orgName" :disabled="!canEditOrg" required minlength="2" />
</label>
<label>
زمینه فعالیت
<select v-model="businessField" :disabled="!canEditOrg" required>
<option value="" disabled>انتخاب کنید</option>
<option v-for="id in BUSINESS_FIELDS" :key="id" :value="id">
{{ BUSINESS_FIELD_LABELS[id] }}
</option>
</select>
</label>
</div>
<p v-if="orgOk" class="ok">{{ orgOk }}</p>
<button v-if="canEditOrg" class="btn" type="submit" :disabled="orgSaving">
{{ orgSaving ? 'در حال ذخیره…' : 'ذخیره مشخصات سازمان' }}
</button>
</form>
<p v-if="error" class="error">{{ error }}</p>
<p v-else-if="loading" class="muted">در حال بارگذاری…</p>
@@ -202,6 +272,12 @@ h1 {
color: #b42318;
}
.ok {
margin: 0;
color: #0f766e;
font-size: 0.9rem;
}
.invite,
.row {
background: var(--surface);