profile name change

This commit is contained in:
2026-09-08 19:20:42 +05:30
parent 035ceb44a7
commit a94c23c20e
4 changed files with 67 additions and 6 deletions

View File

@@ -9,6 +9,21 @@ export interface CreateTenantRequest {
companyname: string;
primarycontact: string;
primaryemail: string;
/**
* Who runs the shop — `tenants.firstname`.
*
* Asked here because here is the only moment it can be asked. The primary
* branch and the merchant's own admin login are both created inside
* `CreateTenantUser`'s transaction, and the login is copied from the tenant
* row — so a name given now names the business AND the account that will
* sign in. Left out, both are blank, which is what every merchant on the
* platform currently has: the store profile prints "—" for Store admin and
* the account carries no person's name at all.
*
* One field, not two: `tenants` has a `firstname` column and no
* `lastname`, so this is the whole name.
*/
firstname?: string;
locationname: string;
categoryid: number;
subcategoryid?: number;
@@ -200,6 +215,9 @@ function toTenantBody(form: CreateTenantRequest): Record<string, unknown> {
companyname: form.companyname,
primaryemail: form.primaryemail,
primarycontact: form.primarycontact,
// Written to `tenants.firstname` and copied onto the admin login the same
// transaction creates — see the note on the field.
firstname: (form.firstname ?? '').trim(),
categoryid: form.categoryid,
subcategoryid: form.subcategoryid ?? 0,
address: form.address,

View File

@@ -109,6 +109,10 @@ export interface TenantInfo {
approved?: number;
moduleid?: number;
subcategoryname?: string;
/** The app category by name — "Daily Needs", not "Category 2". */
categoryname?: string;
/** When the merchant was created. Not returned before Sept 2026. */
created?: string;
firstname?: string;
lastname?: string;
/** Capitalised on the wire. */

View File

@@ -20,6 +20,8 @@ import { useAppCategories } from '@/queries/hooks';
interface FormState {
tenantname: string;
companyname: string;
/** Who runs the shop. Written to `tenants.firstname` — see `CreateTenantRequest`. */
adminname: string;
primarycontact: string;
primaryemail: string;
locationname: string;
@@ -34,6 +36,7 @@ interface FormState {
const EMPTY: FormState = {
tenantname: '',
companyname: '',
adminname: '',
primarycontact: '',
primaryemail: '',
locationname: '',
@@ -94,6 +97,7 @@ export function OnboardTenantPage() {
const isComplete =
form.tenantname.trim() !== '' &&
form.companyname.trim() !== '' &&
form.adminname.trim() !== '' &&
form.primarycontact.trim() !== '' &&
form.primaryemail.trim() !== '' &&
form.locationname.trim() !== '' &&
@@ -109,6 +113,7 @@ export function OnboardTenantPage() {
mutation.mutate({
tenantname: form.tenantname.trim(),
companyname: form.companyname.trim(),
firstname: form.adminname.trim(),
primarycontact: form.primarycontact.trim(),
primaryemail: form.primaryemail.trim(),
locationname: form.locationname.trim(),
@@ -193,6 +198,19 @@ export function OnboardTenantPage() {
onChange={set('companyname')}
placeholder="e.g. Kaveri Retail Pvt. Ltd."
/>
{/* Asked here because here is the only place it can be asked.
The primary outlet and the merchant's own admin login are
both created inside this one call, and the login is copied
from the tenant row — so the name given here names the
business AND the account that signs in. Left out, both are
blank, which is the state every merchant is in today. */}
<TextInput
label={<span>Store admin <span style={{ color: 'var(--color-error)' }}>*</span></span> as any}
value={form.adminname}
onChange={set('adminname')}
placeholder="e.g. Ravi Kumar"
description="The person who administers this shop. Their name goes on the store profile and on the admin login created with it — the account is provisioned as Admin, which is what this field is named after."
/>
<TextInput
label={<span>Primary phone <span style={{ color: 'var(--color-error)' }}>*</span></span> as any}
value={form.primarycontact}

View File

@@ -33,8 +33,9 @@
* Two things the design asks for do not exist behind it, and are shown as
* absent rather than invented: a separate TRADE LICENCE (the `tenants` table
* has one licence column, `licenseno`, which is where FSSAI goes), and a store
* manager (`firstname`, `lastname` and `Accountname` come back empty for every
* merchant read so far). `created` does exist and is now returned — the column
* admin (`tenants.firstname` — there is no lastname column — which was
* collected by no form and permitted by no allowlist until now, so it is empty
* on every merchant created before this). `created` does exist and is now returned — the column
* was always there and the endpoint simply never selected it.
*/
@@ -77,6 +78,7 @@ type CardId = 'basic' | 'contact' | 'licence' | 'more';
/** Every field this page may write, so a save cannot send anything else. */
const EDITABLE = [
'tenantname',
'firstname',
'tenanttype',
'primarycontact',
'primaryemail',
@@ -95,7 +97,7 @@ const EDITABLE = [
type Editable = (typeof EDITABLE)[number];
const CARD_FIELDS: Record<CardId, readonly Editable[]> = {
basic: ['tenantname', 'tenanttype'],
basic: ['tenantname', 'firstname', 'tenanttype'],
contact: ['primarycontact', 'primaryemail', 'address', 'suburb', 'city', 'state', 'postcode'],
licence: ['licenseno'],
more: ['tenantinfo', 'minorder', 'registrationno'],
@@ -262,7 +264,7 @@ export function ShopProfilePage() {
<Fact label="Branch" value={branchLabel(text('locationname')) || '—'} />
<Fact label="City" value={text('city') || '—'} />
<Fact
label="Store manager"
label="Store admin"
value={
[text('firstname'), text('lastname')].filter(Boolean).join(' ') ||
String(record['Accountname'] ?? '').trim() ||
@@ -337,6 +339,20 @@ export function ShopProfilePage() {
onChange={set('tenantname')}
/>
</Field>
{/* `tenants.firstname`, and there is no lastname column — so
this is the whole name. Collected at onboarding from now
on; editable here because every merchant created before
that has it empty. */}
<Field label="Store admin">
<TextInput
label="Store admin"
isLabelHidden
size="sm"
value={form['firstname'] ?? ''}
onChange={set('firstname')}
placeholder="The person who administers this shop"
/>
</Field>
<Field label="Store type">
<TextInput
label="Store type"
@@ -354,7 +370,7 @@ export function ShopProfilePage() {
<Row label="Branch" value={branchLabel(text('locationname'))} />
<Row label="Registered as" value={text('companyname')} />
<Row
label="Store manager"
label="Store admin"
value={[text('firstname'), text('lastname')].filter(Boolean).join(' ')}
/>
<Row label="Store type" value={text('tenanttype')} />
@@ -591,7 +607,12 @@ export function ShopProfilePage() {
<Row label="App location" value={text('applocation')} />
<Row
label="Category"
value={String(record['subcategoryname'] ?? '') || `Category ${record['categoryid'] ?? '—'}`}
/* The NAME, never "Category 2". The join has always produced it;
`categoryname` is newly carried on the response. */
value={
String(record['categoryname'] ?? '').trim() ||
String(record['subcategoryname'] ?? '').trim()
}
/>
<Row
label="Approved"