Skip to content

Commit fdf1b89

Browse files
committed
feat(registration-wizard): implement automatic tenant slug locking based on subdomain
- Added logic to automatically set the tenant slug from the current subdomain in the RegistrationWizard component. - Introduced a state to lock the tenant slug, preventing manual changes when it matches the subdomain. - Updated WorkspaceStep to reflect the locked state and provide appropriate messaging to users. Signed-off-by: Innei <tukon479@gmail.com>
1 parent 0eb4ac9 commit fdf1b89

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

be/apps/dashboard/src/modules/auth/components/registration-wizard/RegistrationWizard.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { useAuthUserValue } from '~/atoms/auth'
1010
import { useRegisterTenant } from '~/modules/auth/hooks/useRegisterTenant'
1111
import type { TenantRegistrationFormState, TenantSiteFieldKey } from '~/modules/auth/hooks/useRegistrationForm'
1212
import { useRegistrationForm } from '~/modules/auth/hooks/useRegistrationForm'
13+
import { getTenantSlugFromHost } from '~/modules/auth/utils/domain'
1314
import type { SchemaFormValue, UiSchema } from '~/modules/schema-form/types'
1415
import { getWelcomeSiteSchema } from '~/modules/welcome/api'
1516
import { LinearBorderContainer } from '~/modules/welcome/components/LinearBorderContainer'
@@ -41,6 +42,7 @@ export const RegistrationWizard: FC = () => {
4142
const [maxVisitedIndex, setMaxVisitedIndex] = useState(0)
4243
const contentRef = useRef<HTMLElement | null>(null)
4344
const slugManuallyEditedRef = useRef(false)
45+
const [lockedTenantSlug, setLockedTenantSlug] = useState<string | null>(null)
4446
const siteDefaultsAppliedRef = useRef(false)
4547

4648
const siteSchemaQuery = useQuery({
@@ -58,6 +60,25 @@ export const RegistrationWizard: FC = () => {
5860
})
5961
}, [])
6062

63+
useEffect(() => {
64+
try {
65+
const { hostname } = window.location
66+
const slug = getTenantSlugFromHost(hostname)
67+
if (!slug) {
68+
return
69+
}
70+
setLockedTenantSlug((prev) => (prev === slug ? prev : slug))
71+
slugManuallyEditedRef.current = true
72+
const currentValue = form.getFieldValue('tenantSlug')
73+
if (currentValue !== slug) {
74+
form.setFieldValue('tenantSlug', () => slug)
75+
void form.validateField('tenantSlug', 'change')
76+
}
77+
} catch {
78+
// Ignore hostname parsing failures; user can still enter slug manually.
79+
}
80+
}, [form])
81+
6182
useEffect(() => {
6283
const data = siteSchemaQuery.data as
6384
| {
@@ -365,6 +386,7 @@ export const RegistrationWizard: FC = () => {
365386
<WorkspaceStep
366387
form={form}
367388
slugManuallyEditedRef={slugManuallyEditedRef}
389+
lockedTenantSlug={lockedTenantSlug}
368390
isSubmitting={isLoading}
369391
onFieldInteraction={onFieldInteraction}
370392
/>

be/apps/dashboard/src/modules/auth/components/registration-wizard/steps/WorkspaceStep.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import { firstErrorMessage } from '../utils'
99
type WorkspaceStepProps = {
1010
form: ReturnType<typeof useRegistrationForm>
1111
slugManuallyEditedRef: MutableRefObject<boolean>
12+
lockedTenantSlug?: string | null
1213
isSubmitting: boolean
1314
onFieldInteraction: () => void
1415
}
1516

1617
export const WorkspaceStep: FC<WorkspaceStepProps> = ({
1718
form,
1819
slugManuallyEditedRef,
20+
lockedTenantSlug,
1921
isSubmitting,
2022
onFieldInteraction,
2123
}) => (
@@ -63,26 +65,33 @@ export const WorkspaceStep: FC<WorkspaceStepProps> = ({
6365
<form.Field name="tenantSlug">
6466
{(field) => {
6567
const error = firstErrorMessage(field.state.meta.errors)
68+
const isSlugLocked = Boolean(lockedTenantSlug)
69+
const helperText = isSlugLocked
70+
? 'Workspace slug follows the current subdomain and cannot be changed in this flow.'
71+
: 'Lowercase letters, numbers, and hyphen are allowed. We&apos;ll ensure the slug is unique.'
72+
6673
return (
6774
<div className="space-y-2">
6875
<Label htmlFor={field.name}>Workspace slug</Label>
6976
<Input
7077
id={field.name}
7178
value={field.state.value}
7279
onChange={(event) => {
80+
if (isSlugLocked) {
81+
return
82+
}
7383
onFieldInteraction()
7484
slugManuallyEditedRef.current = true
7585
field.handleChange(event.currentTarget.value)
7686
}}
7787
onBlur={field.handleBlur}
7888
placeholder="acme"
79-
disabled={isSubmitting}
89+
disabled={isSubmitting || isSlugLocked}
90+
readOnly={isSlugLocked}
8091
error={Boolean(error)}
8192
autoComplete="off"
8293
/>
83-
<p className="text-text-tertiary text-xs">
84-
Lowercase letters, numbers, and hyphen are allowed. We&apos;ll ensure the slug is unique.
85-
</p>
94+
<p className="text-text-tertiary text-xs">{helperText}</p>
8695
<FormError>{error}</FormError>
8796
</div>
8897
)

0 commit comments

Comments
 (0)