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:
@@ -2,12 +2,14 @@
|
||||
import { ref } from 'vue';
|
||||
import { useRouter, RouterLink } from 'vue-router';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { BUSINESS_FIELDS, BUSINESS_FIELD_LABELS } from '@/lib/business-fields';
|
||||
import axios from 'axios';
|
||||
|
||||
const auth = useAuthStore();
|
||||
const router = useRouter();
|
||||
|
||||
const organizationName = ref('');
|
||||
const businessField = ref('');
|
||||
const fullName = ref('');
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
@@ -20,6 +22,7 @@ async function submit() {
|
||||
try {
|
||||
await auth.register({
|
||||
organizationName: organizationName.value,
|
||||
businessField: businessField.value,
|
||||
fullName: fullName.value,
|
||||
email: email.value,
|
||||
password: password.value,
|
||||
@@ -47,13 +50,22 @@ async function submit() {
|
||||
<section class="panel">
|
||||
<p class="eyebrow">شروع با منتو</p>
|
||||
<h1>ساخت سازمان</h1>
|
||||
<p class="lead">اولین کاربر بهعنوان مالک سازمان ثبت میشود.</p>
|
||||
<p class="lead">اولین کاربر بهعنوان مالک سازمان ثبت میشود. زمینه فعالیت کمک میکند منتو فضای کاری را با صنعت شما همتراز کند.</p>
|
||||
|
||||
<form class="form" @submit.prevent="submit">
|
||||
<div class="field">
|
||||
<label for="org">نام سازمان</label>
|
||||
<input id="org" v-model="organizationName" required />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="field">زمینه فعالیت</label>
|
||||
<select id="field" v-model="businessField" required>
|
||||
<option value="" disabled>انتخاب کنید</option>
|
||||
<option v-for="id in BUSINESS_FIELDS" :key="id" :value="id">
|
||||
{{ BUSINESS_FIELD_LABELS[id] }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="name">نام شما</label>
|
||||
<input id="name" v-model="fullName" required />
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user