Improve business edit: names/about, and git URL on domain edit.

Replace color/locale in Edit business with EN/FA name and about; show git repo on Edit domain to provision storefront.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-08 14:18:31 +03:30
co-authored by Cursor
parent 7d6c1cd4e3
commit f4a087089e
3 changed files with 84 additions and 88 deletions
+76 -88
View File
@@ -43,17 +43,13 @@ import {
import { listBusinessCategories } from '../services/categoryService'
import { Modal } from '../components/Modal'
import { MultiSelectDropdown } from '../components/MultiSelectDropdown'
import { PrimaryColorPicker } from '../components/PrimaryColorPicker'
import { PrimaryColorSwatchControl } from '../components/PrimaryColorSwatchControl'
import { useToast } from '../context/ToastContext'
import {
DEFAULT_BUSINESS_PRIMARY_COLOR_ID,
normalizeBusinessPrimaryColorId,
type BusinessPrimaryColorId,
} from '../utils/businessPrimaryColors'
import {
getBusinessSettings,
updateBusinessBranding,
updateBusinessDefaultLocale,
updateBusinessModules,
updateBusinessPrimaryColor,
@@ -215,11 +211,8 @@ export function BusinessesPage() {
const [editOpen, setEditOpen] = useState(false)
const [editBusiness, setEditBusiness] = useState<BusinessListItem | null>(null)
const [editName, setEditName] = useState('')
const [editPrimaryColor, setEditPrimaryColor] = useState<BusinessPrimaryColorId>(
DEFAULT_BUSINESS_PRIMARY_COLOR_ID,
)
const [editDefaultLocale, setEditDefaultLocale] = useState<DashboardLocale>(DEFAULT_LOCALE)
const [editLoadingSettings, setEditLoadingSettings] = useState(false)
const [editNameFa, setEditNameFa] = useState('')
const [editAbout, setEditAbout] = useState('')
const [editSubmitting, setEditSubmitting] = useState(false)
const [editError, setEditError] = useState('')
@@ -370,25 +363,10 @@ export function BusinessesPage() {
function openEdit(b: BusinessListItem) {
setEditBusiness(b)
setEditName(b.name)
setEditPrimaryColor(normalizeBusinessPrimaryColorId(b.primaryColor))
setEditDefaultLocale(normalizeDefaultLocale(b.defaultLocale))
setEditNameFa(b.nameFa ?? '')
setEditAbout(b.about ?? '')
setEditError('')
setEditOpen(true)
setEditLoadingSettings(true)
const controller = new AbortController()
void getBusinessSettings(b.id, controller.signal)
.then((data) => {
setEditPrimaryColor(data.settings.branding.primaryColor)
setEditDefaultLocale(normalizeDefaultLocale(data.settings.branding.defaultLocale))
})
.catch((err) => {
if (isAbortError(err)) return
setEditError(err instanceof ApiError ? err.message : 'Unable to load business theme.')
})
.finally(() => {
if (!controller.signal.aborted) setEditLoadingSettings(false)
})
}
function goToBusinessUsers(b: BusinessListItem, membership: 'staff' | 'all') {
@@ -557,13 +535,17 @@ export function BusinessesPage() {
async function submitEdit() {
if (!editBusiness) return
const name = editName.trim()
const nameFa = editNameFa.trim()
if (!name || !nameFa) return
setEditSubmitting(true)
setEditError('')
try {
await updateBusiness(editBusiness.id, { name: editName })
await updateBusinessBranding(editBusiness.id, {
primaryColor: editPrimaryColor,
defaultLocale: editDefaultLocale,
await updateBusiness(editBusiness.id, {
name,
nameFa,
about: editAbout.trim(),
})
setData((prev) => {
if (!prev) return prev
@@ -573,9 +555,9 @@ export function BusinessesPage() {
item.id === editBusiness.id
? {
...item,
name: editName.trim(),
primaryColor: editPrimaryColor,
defaultLocale: editDefaultLocale,
name,
nameFa,
about: editAbout.trim() || null,
}
: item,
),
@@ -596,7 +578,7 @@ export function BusinessesPage() {
setDomainBusiness(b)
setDomainId(b.domainId)
setDomainHost(b.domain ?? '')
setDomainGitRepoUrl('')
setDomainGitRepoUrl(b.gitRepoUrl ?? '')
setDomainError('')
setDomainOpen(true)
}
@@ -736,7 +718,15 @@ export function BusinessesPage() {
setDomainError('')
try {
if (domainId) {
await updateBusinessDomain(domainBusiness.id, domainId, { host })
const updated = (await updateBusinessDomain(domainBusiness.id, domainId, {
host,
...(gitRepoUrl ? { gitRepoUrl } : {}),
})) as {
id: number
host: string
deploySlug?: string | null
provisionError?: string | null
}
setData((prev) => {
if (!prev) return prev
return {
@@ -746,7 +736,17 @@ export function BusinessesPage() {
),
}
})
showToast(`Domain updated to "${host}".`, 'success')
if (updated.provisionError) {
showToast(`Domain updated to "${host}", but storefront setup failed.`, 'error')
showToast(updated.provisionError, 'error')
} else if (gitRepoUrl && updated.deploySlug) {
showToast(
`Domain updated. Storefront deploy is ready on Websites.`,
'success',
)
} else {
showToast(`Domain updated to "${host}".`, 'success')
}
} else {
const created = (await addBusinessDomain(domainBusiness.id, {
host,
@@ -1231,45 +1231,37 @@ export function BusinessesPage() {
</p>
) : null}
<div className={styles.field}>
<label htmlFor="edit-name">Business name</label>
<label htmlFor="edit-name-en">Name (EN)</label>
<input
id="edit-name"
id="edit-name-en"
value={editName}
onChange={(e) => setEditName(e.target.value)}
placeholder="Business name"
disabled={editSubmitting}
/>
</div>
<div className={styles.field}>
<label>Dashboard primary color</label>
{editLoadingSettings ? (
<p className={styles.helperText}>Loading theme...</p>
) : (
<PrimaryColorPicker
value={editPrimaryColor}
onChange={setEditPrimaryColor}
disabled={editSubmitting}
/>
)}
<label htmlFor="edit-name-fa">Name (FA)</label>
<input
id="edit-name-fa"
className="faText"
value={editNameFa}
onChange={(e) => setEditNameFa(e.target.value)}
placeholder="نام فارسی"
dir="rtl"
lang="fa"
disabled={editSubmitting}
/>
</div>
<div className={styles.field}>
<label htmlFor="edit-default-locale">Default dashboard language</label>
{editLoadingSettings ? (
<p className={styles.helperText}>Loading language...</p>
) : (
<select
id="edit-default-locale"
className={styles.localeSelect}
value={editDefaultLocale}
disabled={editSubmitting}
onChange={(e) => setEditDefaultLocale(normalizeDefaultLocale(e.target.value))}
>
<option value="fa">Farsi (FA)</option>
<option value="en">English (EN)</option>
</select>
)}
<p className={styles.helperText}>
Business and customer dashboards open in this language.
</p>
<label htmlFor="edit-about">About business</label>
<textarea
id="edit-about"
value={editAbout}
onChange={(e) => setEditAbout(e.target.value)}
placeholder="Short description about the business"
disabled={editSubmitting}
/>
</div>
<div style={{ height: 12 }} />
<div className={styles.actionsRow}>
@@ -1285,7 +1277,7 @@ export function BusinessesPage() {
type="button"
className={`${styles.btn} ${styles.btnPrimary}`}
onClick={() => void submitEdit()}
disabled={editSubmitting || !editName.trim() || editLoadingSettings}
disabled={editSubmitting || !editName.trim() || !editNameFa.trim()}
>
Save
</button>
@@ -1318,27 +1310,23 @@ export function BusinessesPage() {
disabled={domainSubmitting}
/>
</div>
{!domainId ? (
<>
<div style={{ height: 12 }} />
<div className={styles.field}>
<label htmlFor="domain-git-repo">Git repo URL (optional)</label>
<input
id="domain-git-repo"
value={domainGitRepoUrl}
onChange={(e) => setDomainGitRepoUrl(e.target.value)}
placeholder="git@git.meshkee.com:Meshkee-Websites/oaktasty.git"
disabled={domainSubmitting}
autoComplete="off"
spellCheck={false}
/>
<p className={styles.subText} style={{ marginTop: 6 }}>
Fill to enable storefront Deploy on Websites. Leave empty for domain-only
(dashboards).
</p>
</div>
</>
) : null}
<div style={{ height: 12 }} />
<div className={styles.field}>
<label htmlFor="domain-git-repo">Git repo URL (optional)</label>
<input
id="domain-git-repo"
value={domainGitRepoUrl}
onChange={(e) => setDomainGitRepoUrl(e.target.value)}
placeholder="git@git.meshkee.com:Meshkee-Websites/oaktasty.git"
disabled={domainSubmitting}
autoComplete="off"
spellCheck={false}
/>
<p className={styles.subText} style={{ marginTop: 6 }}>
Fill to enable storefront Deploy on Websites. Leave empty for domain-only
(dashboards).
</p>
</div>
<div style={{ height: 12 }} />
<div className={styles.actionsRow}>
<button
@@ -19,6 +19,8 @@ export interface ListBusinessesParams {
export interface UpdateBusinessPayload {
name?: string
nameFa?: string
about?: string
slug?: string
oldBusinessId?: number | null
}
@@ -36,6 +38,8 @@ export interface DisableBusinessPayload {
export interface UpdateDomainPayload {
host: string
/** When set, provisions storefront deploy on the websites VM. */
gitRepoUrl?: string
}
export async function listBusinesses(params: ListBusinessesParams, signal?: AbortSignal) {
+4
View File
@@ -15,10 +15,14 @@ export interface BusinessDomainInfo {
export interface BusinessListItem {
id: string
name: string
nameFa: string | null
about: string | null
createdAt: string
domainId: number | null
domain: string | null
sslEnabled: boolean | null
gitRepoUrl: string | null
deploySlug: string | null
ownerName: string | null
ownerNameEn: string | null
ownerCellNumber: string | null