forked from Goutam/lynkeduppro-crm
Role-aware registration: Customer/Employee/Owner/Contractor/Sub-Con/Vendor
- New "Your role" options matching the portal roles - Customer/Owner = self; Employee shows an Employee ID field; Contractor/Sub-Con/Vendor show their ID + property owner name - Validation adapts per role Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,11 +75,12 @@ export const countryCodes: CountryCode[] = [
|
||||
];
|
||||
|
||||
export const relationshipOptions = [
|
||||
"Homeowner",
|
||||
"Customer",
|
||||
"Employee",
|
||||
"Owner",
|
||||
"Contractor",
|
||||
"Property Manager",
|
||||
"Tenant",
|
||||
"Authorized Representative",
|
||||
"Sub-Con",
|
||||
"Vendor",
|
||||
];
|
||||
|
||||
export const sectors = [
|
||||
|
||||
@@ -27,7 +27,7 @@ export function RegisterFlow() {
|
||||
const [cc, setCc] = useState("+1");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [pw, setPw] = useState("");
|
||||
const [relationship, setRelationship] = useState("Homeowner");
|
||||
const [relationship, setRelationship] = useState("Customer");
|
||||
const [alloeNo, setAlloeNo] = useState("");
|
||||
const [alloeFirst, setAlloeFirst] = useState("");
|
||||
const [alloeLast, setAlloeLast] = useState("");
|
||||
@@ -42,15 +42,16 @@ export function RegisterFlow() {
|
||||
const [emailVerified, setEmailVerified] = useState(false);
|
||||
const [phoneVerified, setPhoneVerified] = useState(false);
|
||||
|
||||
const isSelf = relationship === "Homeowner";
|
||||
const isSelf = relationship === "Customer" || relationship === "Owner";
|
||||
const isEmployee = relationship === "Employee";
|
||||
const country = countryCodes.find((c) => c.code === cc)!;
|
||||
const phoneOk = phone.replace(/\D/g, "").length === country.digits;
|
||||
const pwOk = sso ? true : passwordStrength(pw).score >= 3;
|
||||
const alloeIdOk = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/.test(alloeNo);
|
||||
const alloeIdOk = /^(?=.*[a-zA-Z])(?=.*\d).{4,}$/.test(alloeNo);
|
||||
|
||||
const step0Valid =
|
||||
first.trim() && last.trim() && EMAIL_RE.test(sso?.email || email) && phoneOk && pwOk &&
|
||||
termsOk && privacyOk && (isSelf || (alloeIdOk && alloeFirst.trim() && alloeLast.trim()));
|
||||
termsOk && privacyOk && (isSelf || (alloeIdOk && (isEmployee || (alloeFirst.trim() && alloeLast.trim()))));
|
||||
|
||||
const step1Valid = /^LUP-\d{6}$/.test(allotment) || plotVerified;
|
||||
const step2Valid = emailVerified && phoneVerified;
|
||||
@@ -221,26 +222,38 @@ function StepAccount(p: {
|
||||
</div>
|
||||
|
||||
{p.isSelf ? (
|
||||
<div style={{ marginTop: 12 }}><FlashNote tone="success">Homeowner account — you own this property.</FlashNote></div>
|
||||
) : (
|
||||
<div style={{ marginTop: 12 }}><FlashNote tone="success">{p.relationship === "Owner" ? "Owner" : "Customer"} account — you own this property.</FlashNote></div>
|
||||
) : (() => {
|
||||
const isEmployee = p.relationship === "Employee";
|
||||
const cfg = ({
|
||||
Employee: { banner: "Registering as a LynkedUp Pro team member.", title: "Employee details", idLabel: "Employee ID", idPh: "EMP-12345" },
|
||||
Contractor:{ banner: "Registering on behalf of the property owner.", title: "Contractor details", idLabel: "Contractor ID", idPh: "Alphanumeric ID" },
|
||||
"Sub-Con": { banner: "Registering on behalf of the property owner.", title: "Sub-contractor details", idLabel: "Sub-contractor ID", idPh: "Alphanumeric ID" },
|
||||
Vendor: { banner: "Registering on behalf of the property owner.", title: "Vendor details", idLabel: "Vendor ID", idPh: "Alphanumeric ID" },
|
||||
} as Record<string, { banner: string; title: string; idLabel: string; idPh: string }>)[p.relationship]
|
||||
?? { banner: "Registering on behalf of the property owner.", title: "Property Owner Details", idLabel: "Owner / Property ID", idPh: "Alphanumeric ID" };
|
||||
return (
|
||||
<div style={{ marginTop: 12 }}>
|
||||
<FlashNote tone="info">Registering on behalf of the property owner.</FlashNote>
|
||||
<FlashNote tone="info">{cfg.banner}</FlashNote>
|
||||
<div className="dashed-block" style={{ marginTop: 12 }}>
|
||||
<div className="row between" style={{ marginBottom: 12 }}>
|
||||
<strong style={{ fontSize: 13.5 }}>Property Owner Details</strong>
|
||||
<strong style={{ fontSize: 13.5 }}>{cfg.title}</strong>
|
||||
{p.alloeNo && (p.alloeIdOk ? <Badge tone="green"><Icon name="check" size={12} /> Valid</Badge> : <Badge tone="gray">Checking…</Badge>)}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label">Owner / Property ID</label>
|
||||
<input className="input" value={p.alloeNo} onChange={(e) => p.setAlloeNo(e.target.value.toUpperCase())} placeholder="Alphanumeric ID" />
|
||||
<label className="label">{cfg.idLabel}</label>
|
||||
<input className="input" value={p.alloeNo} onChange={(e) => p.setAlloeNo(e.target.value.toUpperCase())} placeholder={cfg.idPh} />
|
||||
</div>
|
||||
{!isEmployee && (
|
||||
<div className="row gap-3" style={{ marginTop: 12 }}>
|
||||
<div className="field grow"><label className="label">Owner first name</label><input className="input" value={p.alloeFirst} onChange={(e) => p.setAlloeFirst(e.target.value)} /></div>
|
||||
<div className="field grow"><label className="label">Owner last name</label><input className="input" value={p.alloeLast} onChange={(e) => p.setAlloeLast(e.target.value)} /></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="col gap-2" style={{ marginTop: 16 }}>
|
||||
<label className="check-row">
|
||||
|
||||
Reference in New Issue
Block a user