// Woodbury Operator — Tenant Profile (view + edit + unit assignment).
// Registers window.TenantProfileScreen.
(function () {
const NS = window.WoodburyPropertiesDesignSystem_7290ca;
const { Card, CardHeader, Button, Badge, Avatar, ProgressBar, IconTile, Eyebrow, Input, Select, Modal, Textarea } = NS;
const HISTORY = [
{ unit: "AC Leak", meta: "Reported 2 hours ago · HVAC notified", icon: "wind", tone: "danger", badge: "Urgent", badgeTone: "danger" },
{ unit: "Repaint request", meta: "Completed 12 Mar", icon: "paintbrush", tone: "sunken", badge: "Resolved", badgeTone: "success" },
{ unit: "Wi-Fi router swap", meta: "Completed 02 Feb", icon: "wifi", tone: "sunken", badge: "Resolved", badgeTone: "success" },
];
const DOCS = [
{ name: "Signed Tenancy Agreement.pdf", meta: "248 KB · Signed 12 Apr" },
{ name: "ID Verification.pdf", meta: "512 KB · Verified 10 Apr" },
];
const TIMELINE = [
{ icon: "wrench", tone: "danger", title: "Maintenance reported", body: "AC Leak in House 1 — marked urgent, HVAC notified.", time: "Today · 09:12" },
{ icon: "message-square", tone: "brand", title: "Message received", body: "“The unit is making a loud grinding noise.”", time: "Today · 09:10" },
{ icon: "clipboard-check", tone: "accent", title: "Routine inspection passed", body: "Quarterly inspection completed — no issues found.", time: "14 Mar · 11:30" },
{ icon: "paintbrush", tone: "success", title: "Maintenance resolved", body: "Repaint request completed and signed off.", time: "12 Mar · 16:40" },
{ icon: "file-signature", tone: "success", title: "Lease signed", body: "12-month tenancy agreement executed for House 1.", time: "01 Jun 2024 · 10:00" },
{ icon: "shield-check", tone: "success", title: "Identity verified", body: "National ID verification cleared during screening.", time: "28 May 2024 · 14:05" },
{ icon: "user-plus", tone: "sunken", title: "Applicant onboarded", body: "Profile created and invited to the resident portal.", time: "20 May 2024 · 09:00" },
];
function Field({ label, value, editing, onChange, type }) {
if (editing) return onChange && onChange(e.target.value)} />;
return (
);
}
function TenantProfileScreen({ onBack }) {
const [tenant, setTenant] = React.useState({
name: "Kofi Mensah", email: "kofi.mensah@yahoo.com", phone: "+233 20 887 3341", avatar: "../../assets/images/av-kofi.jpg",
emergency: "Akosua Mensah · +233 24 118 0092", nationalId: "GHA-724901183-6",
property: "Lashibi Townhouses", unit: "House 1", moveIn: "01 Jun 2024", ends: "28 May 2026", left: 28, term: "12 months", status: "Active",
});
const [editing, setEditing] = React.useState(false);
const [draft, setDraft] = React.useState(tenant);
const [assign, setAssign] = React.useState(false);
const [note, setNote] = React.useState(false);
const [noteText, setNoteText] = React.useState("");
const [notes, setNotes] = React.useState([]);
const [docModal, setDocModal] = React.useState(false);
const [docName, setDocName] = React.useState("");
const [docFolder, setDocFolder] = React.useState("Tenancy Agreements");
const [, forceDocs] = React.useReducer((x) => x + 1, 0);
React.useEffect(() => { if (window.WBFocus && window.WBFocus.kind === "edit-tenant") { setDraft(tenant); setEditing(true); window.WBFocus = null; } }, []);
const [aProp, setAProp] = React.useState(tenant.property);
const [aUnit, setAUnit] = React.useState(tenant.unit);
const startEdit = () => { setDraft(tenant); setEditing(true); };
const save = () => { setTenant(draft); setEditing(false); window.WBToast("Tenant profile updated"); };
const set = (k, v) => setDraft((d) => ({ ...d, [k]: v }));
const confirmAssign = () => {
setTenant((t) => ({ ...t, property: aProp, unit: aUnit }));
setAssign(false);
window.WBToast("Unit reassigned to " + aProp + " · " + aUnit);
};
const unlink = async () => {
const yes = await window.WBConfirm({ title: "Unlink unit?", message: "This removes " + tenant.name + " from " + tenant.unit + ". Their lease will need reassignment.", confirmLabel: "Unlink", danger: true });
if (!yes) return;
setTenant((t) => ({ ...t, property: "—", unit: "Unassigned", status: "Unassigned" }));
window.WBToast("Unit unlinked", "danger");
};
return (
Back
{editing
? setEditing(false)}>Cancel Save
: Edit Profile }
} />
{/* Identity */}
{tenant.name}
{tenant.status === "Active" ? Active Tenant : {tenant.status} }
{tenant.property} · {tenant.unit}
window.WBToast("Messaging " + tenant.name)}>Message
set("name", v)} />
set("email", v)} />
set("phone", v)} />
set("nationalId", v)} />
set("emergency", v)} />
set("moveIn", v)} />
{/* Unit assignment */}
setAssign(true)}>Assign Unit
: { setAProp(tenant.property); setAUnit(tenant.unit); setAssign(true); }}>Change Unit } />
{tenant.unit === "Unassigned" ? (
No unit linked. Assign one to activate the tenancy.
) : (
{tenant.unit}
{tenant.property} · linked since {tenant.moveIn}
Unlink
)}
Maintenance history · {tenant.unit}
{HISTORY.map((h, i) => (
))}
Lease
{tenant.unit === "Unassigned" ? (
No active lease — link a unit first.
) : (
{tenant.left} days left Ends {tenant.ends}
window.WBToast("Renewal initiated for " + tenant.name)}>Initiate Renewal
)}
Documents
{ setDocName(""); setDocFolder("Tenancy Agreements"); setDocModal(true); }}>Upload
{(window.WB_TENANT_DOCS[tenant.name] || []).map((d) => (
{d.name}
{d.meta} · {d.folder}
window.WBToast("Downloading " + d.name)} />
))}
{(window.WB_TENANT_DOCS[tenant.name] || []).length === 0 &&
No documents yet.
}
{/* Activity timeline */}
setNote(true)}>Log Note} />
{notes.concat(TIMELINE).map((e, i, arr) => {
const tones = { danger: ["var(--danger-bg)", "var(--danger)"], brand: ["var(--walnut-100)", "var(--walnut-700)"], accent: ["rgba(194,125,72,0.14)", "var(--terracotta-600)"], success: ["var(--success-bg)", "var(--success)"], sunken: ["var(--cream-100)", "var(--gray-500)"] }[e.tone] || ["var(--cream-100)", "var(--gray-500)"];
return (
{e.title}
{e.time}
{e.body}
);
})}
{/* Log note modal */}
setNote(false)} icon="pencil" title="Log Note" subtitle={"Add an activity note for " + tenant.name} width={460}
footer={ setNote(false)}>Cancel { setNotes((n) => [{ icon: "sticky-note", tone: "accent", title: "Note added", body: noteText.trim(), time: "Just now" }, ...n]); setNoteText(""); setNote(false); window.WBToast("Note logged"); }}>Save Note }>
{/* Upload document modal */}
setDocModal(false)} icon="upload" title="Upload Document" subtitle={"Link a file to " + tenant.name}
footer={ setDocModal(false)}>Cancel {
const nm = docName.trim().endsWith(".pdf") ? docName.trim() : docName.trim() + ".pdf";
window.WBAddTenantDoc(tenant.name, { name: nm, meta: "Uploaded just now", folder: docFolder });
setNotes((n) => [{ icon: "file-text", tone: "brand", title: "Document uploaded", body: nm + " filed under " + docFolder + ".", time: "Just now" }, ...n]);
setDocModal(false); forceDocs(); window.WBToast(nm + " saved to " + docFolder);
}}>Upload }>
{/* Assign / change unit modal */}
setAssign(false)} icon="link" title={tenant.unit === "Unassigned" ? "Assign Unit" : "Change Unit"} subtitle={"Link " + tenant.name + " to an apartment."}
footer={ setAssign(false)}>Cancel Confirm Assignment }>
);
}
window.TenantProfileScreen = TenantProfileScreen;
})();