Redesign Support as bento hub, restore full sidebar, Western names

- Support Center overview rebuilt as a bento grid: large live-chat hero
  tile, support team tile, mini channel tiles and a recent-tickets strip.
- Restore full workspace sidebar (Workspace/Team/Profile groups) with a
  premium golden active state; unbuilt modules show a Coming Soon view.
- Use Western names across the UI (James Carter; Emma Wilson, Liam Foster,
  Sophie Turner, Noah Mitchell) incl. tickets, threads, portal demo user.
- Remove the Allottee card from Profile; add a clean Account & identity
  card and live-editable contacts.
- Relabel "Plot" -> "House number" everywhere; drop the allotment chip in
  favour of the property category.
- Premium visual pass: brand gradients, depth, glow accents, pill tabs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 22:19:07 +05:30
parent 3ab6768c1c
commit d7eb82f182
9 changed files with 297 additions and 137 deletions
+31 -52
View File
@@ -79,14 +79,14 @@ function ProfileHeaderCard() {
<div className="profile-hero-role">{user.role} · Member since {user.memberSince}</div>
<div className="profile-hero-chips">
<span className="hero-chip"><Icon name="pin" size={13} /> {user.sector} · {user.pocket}</span>
<span className="hero-chip"><Icon name="key" size={13} /> Allotment {user.allotmentNo}</span>
<span className="hero-chip accent"><Icon name="check" size={13} /> Plot {user.plot}</span>
<span className="hero-chip"><Icon name="owners" size={13} /> {user.category}</span>
<span className="hero-chip accent"><Icon name="check" size={13} /> House {user.plot}</span>
</div>
</div>
</div>
<div className="profile-hero-stats">
<HeroStat value={user.category} label="Category" />
<HeroStat value={user.size} label="Plot size" />
<HeroStat value={user.size} label="House size" />
<HeroStat value="33%" label="KYC complete" accent="var(--orange)" />
</div>
</div>
@@ -116,33 +116,27 @@ function PersonalInfoTab() {
// editable contact values (live-updating after OTP confirmation)
const [contacts, setContacts] = useState({ email: user.email.full, mobile: user.mobile.full, whatsapp: user.whatsapp.full });
// editable account-holder fields
const [editId, setEditId] = useState(false);
const [holder, setHolder] = useState({ name: user.name, relationship: user.relationship });
const [holderDraft, setHolderDraft] = useState(holder);
function verify() {
if (plot.trim() === user.plot) { setVerified(true); setErr(""); push({ tone: "success", title: "Verified", desc: "Your full details are now visible and editable." }); }
else setErr(`That doesn't match the plot number on file (hint: it's ${user.plot}).`);
else setErr(`That doesn't match the house number on file (hint: it's ${user.plot}).`);
}
function mask(kind: ContactKind, full: string) {
return kind === "email" ? maskEmail(full) : maskPhone(full);
}
const rows: { key: ContactKind | "pan" | "aadhaar"; label: string; full: string; masked: string; editable: boolean }[] = [
{ key: "email", label: "Email", full: contacts.email, masked: mask("email", contacts.email), editable: true },
{ key: "mobile", label: "Mobile", full: contacts.mobile, masked: mask("mobile", contacts.mobile), editable: true },
{ key: "whatsapp", label: "WhatsApp", full: contacts.whatsapp, masked: mask("whatsapp", contacts.whatsapp), editable: true },
{ key: "pan", label: "PAN", full: user.pan.full, masked: user.pan.masked, editable: false },
{ key: "aadhaar", label: "Aadhaar", full: user.aadhaar.full, masked: user.aadhaar.masked, editable: false },
const contactRows: { key: ContactKind; label: string; full: string; masked: string }[] = [
{ key: "email", label: "Email", full: contacts.email, masked: mask("email", contacts.email) },
{ key: "mobile", label: "Mobile", full: contacts.mobile, masked: mask("mobile", contacts.mobile) },
{ key: "whatsapp", label: "WhatsApp", full: contacts.whatsapp, masked: mask("whatsapp", contacts.whatsapp) },
];
return (
<div className="grid-2">
<div className="card">
<div className="card-head">
<h3>Personal details</h3>
<h3>Contact details</h3>
{verified
? <Pill tone="green"><Icon name="eye" size={13} /> Revealed</Pill>
: <Pill tone="orange"><Icon name="eye-off" size={13} /> Masked</Pill>}
@@ -153,10 +147,10 @@ function PersonalInfoTab() {
<div className="reveal-gate-ic"><Icon name="lock" size={20} /></div>
<div className="reveal-gate-txt">
<strong>Verify to reveal &amp; edit</strong>
<span>Sensitive details are masked. Enter your plot number to unmask and edit them.</span>
<span>Sensitive details are masked. Enter your house number to unmask and edit them.</span>
</div>
<div className="reveal-gate-form">
<input className="ds-input" placeholder="Plot number" value={plot} maxLength={6}
<input className="ds-input" placeholder="House number" value={plot} maxLength={6}
onChange={(e) => { setPlot(e.target.value.replace(/\D/g, "")); setErr(""); }}
onKeyDown={(e) => e.key === "Enter" && verify()} />
<Btn icon="check" onClick={verify}>Reveal</Btn>
@@ -166,15 +160,14 @@ function PersonalInfoTab() {
)}
<dl className="kv-list">
{rows.map((f) => (
{contactRows.map((f) => (
<div className="kv" key={f.key}>
<dt>{f.label}</dt>
<dd className={verified ? "kv-edit" : "masked"}>
{verified ? f.full : f.masked}
{verified && f.editable && (
<button className="kv-edit-btn" aria-label={`Edit ${f.label}`} onClick={() => setChange(f.key as ContactKind)}><Icon name="edit" size={13} /></button>
{verified && (
<button className="kv-edit-btn" aria-label={`Edit ${f.label}`} onClick={() => setChange(f.key)}><Icon name="edit" size={13} /></button>
)}
{verified && !f.editable && <span className="kv-lock"><Icon name="lock" size={12} /> via KYC</span>}
</dd>
</div>
))}
@@ -189,40 +182,26 @@ function PersonalInfoTab() {
<div className="card">
<div className="card-head">
<h3>Allottee &amp; account holder</h3>
{!editId
? <Btn variant="outline" size="sm" icon="edit" onClick={() => { setHolderDraft(holder); setEditId(true); }}>Edit</Btn>
: <div className="row gap-2"><Btn variant="ghost" size="sm" onClick={() => setEditId(false)}>Cancel</Btn><Btn size="sm" icon="check" onClick={() => { setHolder(holderDraft); setEditId(false); push({ tone: "success", title: "Details saved" }); }}>Save</Btn></div>}
<h3>Account &amp; identity</h3>
{verified
? <Pill tone="green"><Icon name="eye" size={13} /> Revealed</Pill>
: <Pill tone="muted"><Icon name="lock" size={12} /> Protected</Pill>}
</div>
{user.isAllottee ? (
<div className="callout tone-green">
<Icon name="check-circle" size={18} />
<div><strong>You are the allottee.</strong><span>The account holder and the allottee are the same person ({holder.relationship}).</span></div>
<dl className="kv-list">
<div className="kv"><dt>Full name</dt><dd>{user.name}</dd></div>
<div className="kv"><dt>Role</dt><dd>{user.role}</dd></div>
<div className="kv"><dt>Member since</dt><dd>{user.memberSince}</dd></div>
<div className="kv"><dt>Account status</dt><dd><Pill tone="green"><StatusDot status="online" /> Active</Pill></dd></div>
<div className="kv">
<dt>PAN</dt>
<dd className={verified ? "kv-edit" : "masked"}>{verified ? user.pan.full : user.pan.masked}{verified && <span className="kv-lock"><Icon name="lock" size={12} /> via KYC</span>}</dd>
</div>
) : (
<div className="callout tone-orange">
<Icon name="info" size={18} />
<div><strong>Acting on behalf of the allottee.</strong><span>Account holder differs from the allottee actions are logged against you.</span></div>
<div className="kv">
<dt>Aadhaar</dt>
<dd className={verified ? "kv-edit" : "masked"}>{verified ? user.aadhaar.full : user.aadhaar.masked}{verified && <span className="kv-lock"><Icon name="lock" size={12} /> via KYC</span>}</dd>
</div>
)}
{editId ? (
<div className="edit-grid">
<Field label="Account holder name"><input className="ds-input" value={holderDraft.name} onChange={(e) => setHolderDraft((d) => ({ ...d, name: e.target.value }))} /></Field>
<Field label="Relationship to allottee">
<select className="ds-select" value={holderDraft.relationship} onChange={(e) => setHolderDraft((d) => ({ ...d, relationship: e.target.value }))}>
{["Self", "Spouse", "Son / Daughter", "Authorized Representative", "Power of Attorney"].map((r) => <option key={r} value={r}>{r}</option>)}
</select>
</Field>
</div>
) : (
<dl className="kv-list">
<div className="kv"><dt>Allottee name</dt><dd>{user.allotteeName}</dd></div>
<div className="kv"><dt>Account holder</dt><dd>{holder.name}</dd></div>
<div className="kv"><dt>Relationship</dt><dd><Pill tone="blue">{holder.relationship}</Pill></dd></div>
<div className="kv"><dt>Allotment no.</dt><dd>{user.allotmentNo}</dd></div>
<div className="kv"><dt>Property</dt><dd>{user.sector} · {user.pocket} · Plot {user.plot}</dd></div>
</dl>
)}
</dl>
<p className="muted-note"><Icon name="info" size={13} /> PAN &amp; Aadhaar are managed under the KYC tab and can&apos;t be edited here.</p>
</div>
<ChangeContactModal