232 lines
7.8 KiB
TypeScript
232 lines
7.8 KiB
TypeScript
import { useEffect } from "preact/hooks";
|
||
import FloatingTileButtons from "./tiles/FloatingTileButtons.tsx";
|
||
import type { OnboardingStatus } from "../services/onboardingService.ts";
|
||
|
||
interface MemberHomeProps {
|
||
onboardingStatus?: OnboardingStatus | null;
|
||
/** Server-provided calendar year for hydration-safe initial link (avoids server/client date mismatch). */
|
||
serverCalendarYear?: number;
|
||
/** Server-provided calendar month (1–12) for hydration-safe initial link. */
|
||
serverCalendarMonth?: number;
|
||
}
|
||
|
||
export default function MemberHome(
|
||
{ onboardingStatus, serverCalendarYear, serverCalendarMonth }:
|
||
MemberHomeProps,
|
||
) {
|
||
useEffect(() => {
|
||
const lockRoute = localStorage.getItem("lock-route");
|
||
if (lockRoute) {
|
||
localStorage.removeItem("lock-route");
|
||
globalThis.location.href = lockRoute;
|
||
return;
|
||
}
|
||
|
||
const loginPurpose = localStorage.getItem("login-purpose");
|
||
if (loginPurpose) {
|
||
localStorage.removeItem("login-purpose");
|
||
const tenantDone = Boolean(onboardingStatus?.onboarded_tenant);
|
||
const destination = loginPurpose === "landlord"
|
||
? "/landlord/dashboard"
|
||
: loginPurpose === "tenant"
|
||
? (tenantDone ? "/tenant/dashboard" : "/tenant/onboarding")
|
||
: "";
|
||
if (destination) {
|
||
globalThis.location.href = destination;
|
||
}
|
||
}
|
||
}, [onboardingStatus]);
|
||
|
||
const tileIds = [
|
||
{ id: "landlord-hub", label: "Landlord" },
|
||
{ id: "tenant-hub", label: "Tenant" },
|
||
{ id: "admin-center", label: "Admin" },
|
||
{ id: "user-profile", label: "Profile" },
|
||
{ id: "dashboard", label: "Dashboard" },
|
||
{ id: "financial-calendar", label: "Calendar" },
|
||
];
|
||
|
||
const tenantOnboarded = Boolean(onboardingStatus?.onboarded_tenant);
|
||
const landlordStep = onboardingStatus?.onboarding_step ?? 0;
|
||
const landlordStarted = Boolean(onboardingStatus?.onboarded_landlord) ||
|
||
landlordStep > 0;
|
||
const landlordReady = landlordStarted && landlordStep === 0;
|
||
const landlordInProgress = landlordStep > 0;
|
||
|
||
const landlordPrimary = landlordReady
|
||
? { label: "Open Landlord Dashboard", href: "/landlord/dashboard" }
|
||
: landlordInProgress
|
||
? { label: "Continue Landlord Setup", href: "/landlord/onboarding/profile" }
|
||
: { label: "Start Landlord Setup", href: "/landlord/onboarding/profile" };
|
||
|
||
const tenantPrimary = tenantOnboarded
|
||
? { label: "Open Tenant Dashboard", href: "/tenant/dashboard" }
|
||
: { label: "Continue Tenant Setup", href: "/tenant/onboarding" };
|
||
|
||
const year = serverCalendarYear ?? new Date().getFullYear();
|
||
const month = serverCalendarMonth ?? new Date().getMonth() + 1;
|
||
const calendarHref = `/calendar/financial-calendar/${year}/${
|
||
month.toString().padStart(2, "0")
|
||
}?`;
|
||
|
||
return (
|
||
<>
|
||
<div class="landing-home landing-home--member">
|
||
<div class="landing-grid-overlay" aria-hidden="true"></div>
|
||
<div class="landing-orb landing-orb--north" aria-hidden="true"></div>
|
||
<div class="landing-orb landing-orb--east" aria-hidden="true"></div>
|
||
<div class="landing-orb landing-orb--south" aria-hidden="true"></div>
|
||
|
||
<section class="member-hero-panel">
|
||
<div class="member-hero-main">
|
||
<img
|
||
src="/logo.svg"
|
||
alt="Cyber Hybrid Hub Logo"
|
||
width="72"
|
||
height="72"
|
||
class="member-logo"
|
||
/>
|
||
<div>
|
||
<p class="landing-eyebrow">Member Workspace</p>
|
||
<h1 class="member-heading">Go straight to what matters</h1>
|
||
<p class="member-copy">
|
||
Open landlord or tenant dashboards quickly, or jump into the
|
||
financial calendar to plan your monthly budget.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="member-status-row">
|
||
<div class="status-chip">
|
||
<span>Landlord</span>
|
||
<strong>
|
||
{landlordReady
|
||
? "Ready"
|
||
: landlordInProgress
|
||
? "Setup in Progress"
|
||
: "Not Started"}
|
||
</strong>
|
||
</div>
|
||
<div class="status-chip">
|
||
<span>Tenant</span>
|
||
<strong>{tenantOnboarded ? "Ready" : "Setup Needed"}</strong>
|
||
</div>
|
||
<div class="status-chip">
|
||
<span>Finance</span>
|
||
<strong>Calendar Ready</strong>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="member-hub-grid">
|
||
<article id="landlord-hub" class="hub-card">
|
||
<div class="hub-card-header">
|
||
<h2>Landlord Operations</h2>
|
||
<span
|
||
class={`hub-badge ${
|
||
landlordReady
|
||
? "hub-badge--ready"
|
||
: landlordInProgress
|
||
? "hub-badge--progress"
|
||
: "hub-badge--pending"
|
||
}`}
|
||
>
|
||
{landlordReady
|
||
? "Onboarded"
|
||
: landlordInProgress
|
||
? "In Progress"
|
||
: "Not Set Up"}
|
||
</span>
|
||
</div>
|
||
<p>
|
||
Manage listings, tenants, lease activity, and incoming payments
|
||
from a single workflow.
|
||
</p>
|
||
<div class="hub-actions">
|
||
<a href={landlordPrimary.href} class="primary-action">
|
||
{landlordPrimary.label}
|
||
</a>
|
||
<a
|
||
href={landlordReady
|
||
? "/landlord/properties/add"
|
||
: "/landlord/onboarding/profile"}
|
||
class="secondary-action"
|
||
>
|
||
{landlordReady ? "Add Property" : "Complete Profile"}
|
||
</a>
|
||
</div>
|
||
</article>
|
||
|
||
<article id="tenant-hub" class="hub-card">
|
||
<div class="hub-card-header">
|
||
<h2>Tenant Workspace</h2>
|
||
<span
|
||
class={`hub-badge ${
|
||
tenantOnboarded ? "hub-badge--ready" : "hub-badge--pending"
|
||
}`}
|
||
>
|
||
{tenantOnboarded ? "Active" : "Needs Setup"}
|
||
</span>
|
||
</div>
|
||
<p>
|
||
Stay on top of rent, maintenance requests, and documents with
|
||
clear tenant-first workflows.
|
||
</p>
|
||
<div class="hub-actions">
|
||
<a href={tenantPrimary.href} class="primary-action">
|
||
{tenantPrimary.label}
|
||
</a>
|
||
<a href="/tenant/property" class="secondary-action">
|
||
View Property Details
|
||
</a>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
|
||
<section class="member-quick-grid">
|
||
<article id="admin-center" class="quick-card">
|
||
<h3>Admin Center</h3>
|
||
<p>
|
||
Administrative controls are available based on your account
|
||
permissions.
|
||
</p>
|
||
</article>
|
||
|
||
<a
|
||
id="user-profile"
|
||
href="/user-profile"
|
||
class="quick-card quick-card-link"
|
||
>
|
||
<h3>Profile</h3>
|
||
<p>Review account and security preferences.</p>
|
||
</a>
|
||
|
||
<button
|
||
onClick={() => {
|
||
localStorage.setItem("lock-route", "/language/dashboard");
|
||
globalThis.location.href = "/language/dashboard";
|
||
}}
|
||
type="button"
|
||
id="dashboard"
|
||
class="quick-card quick-card-link text-left"
|
||
>
|
||
<h3>Dashboard</h3>
|
||
<p>Open your language and learning dashboard.</p>
|
||
</button>
|
||
|
||
<a
|
||
href={calendarHref}
|
||
id="financial-calendar"
|
||
class="quick-card quick-card-link"
|
||
>
|
||
<h3>Financial Calendar</h3>
|
||
<p>Track income and obligations by day.</p>
|
||
</a>
|
||
</section>
|
||
</div>
|
||
|
||
<FloatingTileButtons ids={[...tileIds]} />
|
||
</>
|
||
);
|
||
}
|