Fix business tenant binding and update password on cross-site signup.

Resolve the active business from the host domain so multi-business staff no longer load another tenant’s CMS data, and replace the Meshkee password when linking an existing account to a new site.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-21 12:07:17 +03:30
co-authored by Cursor
parent 193c63bfd2
commit 89269dff04
6 changed files with 52 additions and 50 deletions
+20 -30
View File
@@ -16,7 +16,7 @@ import {
resetPassword,
sendOtp,
} from '../services/authService'
import { LanguageSelect, PasswordStrengthMeter, isPasswordStrong, useLocale } from '@meshkee/dashboard-ui'
import { LanguageSelect, PasswordStrengthMeter, isPasswordStrong, useLocale, useToast } from '@meshkee/dashboard-ui'
import { useT } from '../i18n/useT'
import { safeRedirectPath } from '../lib/redirect'
import { BackgroundOrbs } from '../components/BackgroundOrbs'
@@ -66,6 +66,7 @@ export function LoginPage() {
const { businessName, businessNameEn, logoUrl } = useTenantBranding()
const tenantDomain = getTenantDomain()
const t = useT()
const { showToast } = useToast()
const { locale, dir } = useLocale()
const [view, setView] = useState<AuthView>('login')
@@ -207,7 +208,7 @@ export function LoginPage() {
}
}
async function runSignup() {
async function runSignup(acknowledgeExistingAccount = false) {
const cellNumber = resolveCellNumber()
if (!cellNumber) return
@@ -220,10 +221,15 @@ export function LoginPage() {
firstName: firstName.trim(),
lastName: lastName.trim(),
domain: tenantDomain,
...(acknowledgeExistingAccount ? { acknowledgeExistingAccount: true } : {}),
})
setCellExistsSites(null)
if (data.passwordUpdated) {
showToast(t('signup.toast.passwordUpdated'), 'info')
}
if (data.user.customerBusinesses.length === 0) {
logoutRequest()
setError(CUSTOMER_ACCESS_MESSAGE)
@@ -232,14 +238,19 @@ export function LoginPage() {
if (!data.user.cellVerifiedAt) {
logoutRequest()
await continueToSmsVerify(cellNumber)
await continueToSmsVerify(
cellNumber,
data.passwordUpdated
? t('signup.info.verifyExistingPasswordUpdated')
: t('signup.info.verify'),
)
return
}
await login(cellNumber, password)
navigate(redirectTo)
} catch (err) {
if (err instanceof ApiError) {
if (!acknowledgeExistingAccount && err instanceof ApiError) {
const sites = parseCellExistsSites(err.message)
if (sites !== null) {
setCellExistsSites(sites)
@@ -253,13 +264,13 @@ export function LoginPage() {
}
}
async function continueToSmsVerify(cellNumber: string) {
async function continueToSmsVerify(cellNumber: string, infoMessage?: string) {
setView('otp')
setSmsStep('phone')
setPassword('')
setConfirmPassword('')
setSmsCode('')
setInfo(t('signup.info.verify'))
setInfo(infoMessage ?? t('signup.info.verify'))
try {
const otpResult = await sendOtp(cellNumber, tenantDomain)
if (!otpResult.enabled) {
@@ -292,9 +303,8 @@ export function LoginPage() {
}
/**
* Existing Meshkee account on another site: user admits the notice, then proves
* phone ownership via SMS. login-otp links them to this website (password/data unchanged),
* so they appear in the business Customers list after verification.
* Existing Meshkee account on another site: user admits the notice, then we link
* them with the new password and prove phone ownership via SMS.
*/
async function handleAdmitCellExists() {
clearMessages()
@@ -304,27 +314,7 @@ export function LoginPage() {
return
}
setIsSubmitting(true)
setCellExistsSites(null)
try {
setInfo(t('signup.info.verifyExisting'))
setView('otp')
setSmsStep('phone')
setPassword('')
setConfirmPassword('')
setSmsCode('')
const otpResult = await sendOtp(cellNumber, tenantDomain)
if (!otpResult.enabled) {
setInfo(otpResult.message)
}
setCodeSent(true)
setSmsStep('code')
startCountdown()
} catch (otpErr) {
handleApiError(otpErr, t('login.error.sendCode'))
} finally {
setIsSubmitting(false)
}
await runSignup(true)
}
async function handleResetPassword(e: React.FormEvent) {