diff --git a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx index b629d246..fe08256b 100644 --- a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx @@ -1,76 +1,206 @@ -import { Icon, Pill } from "../shared/ui"; +import { Avatar, Button, Icon, Pill } from "../shared/ui"; +import type { ApprovalRecord, TaskRecord } from "../../../shared/domain"; import type { PageProps } from "./types"; import { activeOrgId, money } from "./types"; -export function HomePage({ snapshot }: PageProps) { +export function HomePage({ snapshot, actions }: PageProps) { const orgId = activeOrgId(snapshot); const organization = snapshot.organizations.find((item) => item.id === orgId); if (!organization) throw new Error("Active organization is missing."); + const employee = snapshot.employees.find((item) => item.orgId === orgId); + if (!employee) throw new Error("Active employee is missing."); const tasks = snapshot.tasks.filter((item) => item.orgId === orgId); const approvals = snapshot.approvals.filter((item) => item.orgId === orgId); const agents = snapshot.agents.filter((item) => item.orgId === orgId); const providers = snapshot.providers.filter((item) => item.orgId === orgId && item.enabled); - const budget = agents.reduce((sum, agent) => sum + agent.budgetCents, 0); + const goals = snapshot.goals.filter((item) => item.orgId === orgId); const pending = approvals.filter((item) => item.state === "pending"); + const inProgress = tasks.filter((item) => item.status === "in_progress"); + const totalBudgetCents = agents.reduce((sum, agent) => sum + agent.budgetCents, 0); + const primaryGoal = goals[0] ?? null; + const greeting = greetingByHour(new Date().getHours()); + const firstName = employee.displayName.split(" ")[0]; return (
-

{organization.name}

-

{organization.goal}

+
+
+

{greeting}, {firstName}

+

+ {pending.length} {pending.length === 1 ? "thing" : "things"} waiting on you · {agents.length} {agents.length === 1 ? "agent" : "agents"} on deck +

+
+
+ + +
+
+
- - item.status !== "done").length)} /> - + + { + const emp = employee; + void actions.run(() => window.agentCompany.decideApproval({ orgId, approvalId: id, state: "approved", decidedByEmployeeId: emp.id })); + }} /> +
+
-
-
Work
- {tasks.length === 0 ? : tasks.slice(0, 6).map((task) => ( -
- - {task.title} - {task.status.replaceAll("_", " ")} -
- ))} -
-
-
Decisions
- {pending.length === 0 ? : pending.slice(0, 4).map((approval) => ( -
-
{approval.title}
- {approval.risk} -
- ))} -
-
-
-
-
Providers
- {providers.length === 0 ? : providers.map((provider) => ( -
- - {provider.label} -
- ))} -
-
-
Mission
-
{organization.mission}
-
+ + + t.status === "done").length} />
); } -function MetricCard({ label, value }: { label: string; value: string }) { +function TodayCard({ tasks, agents }: { tasks: TaskRecord[]; agents: Array<{ id: string; name: string }> }) { + const today = new Date().toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }); return ( -
-
{label}
-
{value}
+
+
+
Today
+
{today}
+
+ {tasks.length === 0 ? ( +
No active work
+ ) : tasks.slice(0, 4).map((task) => { + const agent = agents.find((a) => a.id === task.assigneeAgentId); + return ( +
+ — +
+ {task.title} + {agent && · {agent.name}} +
+ {task.risk === "high" && High risk} +
+ ); + })}
); } -function EmptyLine({ label }: { label: string }) { - return
{label}
; +function WaitingCard({ approvals, onApprove }: { approvals: ApprovalRecord[]; onApprove: (id: string) => void }) { + return ( +
+
+
Waiting on you
+ {approvals.length > 0 && {approvals.length}} +
+ {approvals.length === 0 ? ( +
Nothing pending
+ ) : approvals.slice(0, 2).map((approval) => ( +
+
{approval.title}
+
+ {approval.risk} risk · {approval.kind} +
+
+ + +
+
+ ))} +
+ ); +} + +function SpendCard({ providers, totalBudgetCents }: { providers: Array<{ id: string; label: string; budgetCents?: number }>; totalBudgetCents: number }) { + const topProviders = providers.slice(0, 3); + const budgetLabel = money(totalBudgetCents); + return ( +
+
Monthly budget
+
+
{budgetLabel}
+
allocated
+
+
+
0 ? "100%" : "0%", height: "100%", background: "var(--text-1)" }} /> +
+ {topProviders.length === 0 ? ( +
No providers
+ ) : ( +
+ {topProviders.map((provider) => ( +
+ {provider.label} + — +
+ ))} +
+ )} +
+ ); +} + +function InProgressCard({ tasks, agents }: { tasks: TaskRecord[]; agents: Array<{ id: string; name: string; department: string }> }) { + return ( +
+
+
In progress
+
All work →
+
+ {tasks.length === 0 ? ( +
No active work
+ ) : tasks.slice(0, 4).map((task, index) => { + const agent = agents.find((a) => a.id === task.assigneeAgentId); + const isLast = index === tasks.slice(0, 4).length - 1; + return ( +
+ +
{task.title}
+ {agent && {agent.department || "Agent"}} + {agent && } +
+ ); + })} +
+ ); +} + +function TeamCard({ agents, employee }: { agents: Array<{ id: string; name: string; role: string }>; employee: { displayName: string; role: string } }) { + return ( +
+
Team
+ {agents.slice(0, 4).map((agent) => ( +
+ +
{agent.name}
+
{agent.role}
+
+ ))} +
+ +
{employee.displayName}
+
{employee.role} · human
+
+
+ ); +} + +function GoalCard({ goal, totalTasks, doneTasks }: { goal: { title: string; description: string } | null; totalTasks: number; doneTasks: number }) { + const pct = totalTasks > 0 ? Math.round((doneTasks / totalTasks) * 100) : 0; + return ( +
+
Quarter goal
+
+ {goal ? goal.title : "No active goal"} +
+
+
{pct}%
+
complete
+
+
+
+
+
+ ); +} + +function greetingByHour(hour: number): string { + if (hour < 12) return "Good morning"; + if (hour < 17) return "Good afternoon"; + return "Good evening"; }