Wire Home approval and work navigation links
This commit is contained in:
1 parent
86bb8f36cb
commit
d2695202b5
4 files changed
+31
-7
No files matched your search
@@ -30,7 +30,7 @@ export function App() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageProps = { snapshot, actions };
|
const pageProps = { snapshot, actions, navigate: setRoute };
|
||||||
const page = {
|
const page = {
|
||||||
home: <HomePage {...pageProps} />,
|
home: <HomePage {...pageProps} />,
|
||||||
team: <TeamPage {...pageProps} />,
|
team: <TeamPage {...pageProps} />,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { NewTaskDialog } from "./NewTaskDialog";
|
|||||||
import type { PageProps } from "./types";
|
import type { PageProps } from "./types";
|
||||||
import { activeOrgId, formatTime, money, requireActiveEmployee, requireActiveOrganization } from "./types";
|
import { activeOrgId, formatTime, money, requireActiveEmployee, requireActiveOrganization } from "./types";
|
||||||
|
|
||||||
export function HomePage({ snapshot, actions }: PageProps) {
|
export function HomePage({ snapshot, actions, navigate }: PageProps) {
|
||||||
const orgId = activeOrgId(snapshot);
|
const orgId = activeOrgId(snapshot);
|
||||||
const organization = requireActiveOrganization(snapshot);
|
const organization = requireActiveOrganization(snapshot);
|
||||||
const employee = requireActiveEmployee(snapshot);
|
const employee = requireActiveEmployee(snapshot);
|
||||||
@@ -66,12 +66,13 @@ export function HomePage({ snapshot, actions }: PageProps) {
|
|||||||
state: "approved",
|
state: "approved",
|
||||||
decidedByEmployeeId: employee.id,
|
decidedByEmployeeId: employee.id,
|
||||||
}))}
|
}))}
|
||||||
|
onOpen={() => navigate("approvals")}
|
||||||
/>
|
/>
|
||||||
<SpendCard providers={providers} totalBudgetCents={totalBudgetCents} capCents={budgetCapCents} agents={agents} />
|
<SpendCard providers={providers} totalBudgetCents={totalBudgetCents} capCents={budgetCapCents} agents={agents} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr)", gap: 12 }}>
|
<div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr)", gap: 12 }}>
|
||||||
<InProgressCard tasks={inProgressTasks} agents={agents} />
|
<InProgressCard tasks={inProgressTasks} agents={agents} onViewAll={() => navigate("work")} />
|
||||||
<TeamCard agents={agents} employee={employee} />
|
<TeamCard agents={agents} employee={employee} />
|
||||||
<GoalCard goal={primaryGoal} progress={goalProgress} organizationName={organization.name} />
|
<GoalCard goal={primaryGoal} progress={goalProgress} organizationName={organization.name} />
|
||||||
</div>
|
</div>
|
||||||
@@ -107,7 +108,9 @@ function TodayCard({
|
|||||||
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
||||||
const ownerName = owner?.name ?? employee.displayName;
|
const ownerName = owner?.name ?? employee.displayName;
|
||||||
const time = agendaTime(task, date);
|
const time = agendaTime(task, date);
|
||||||
const requiresApproval = approvals.some((approval) => approval.title === task.title);
|
const requiresApproval = approvals.some(
|
||||||
|
(approval) => approval.sourceEntityType === "task" && approval.sourceEntityId === task.id,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div key={task.id} className="row" style={{ gap: 12 }}>
|
<div key={task.id} className="row" style={{ gap: 12 }}>
|
||||||
<span className="num mono" style={{ width: 36, fontSize: 12, color: "var(--text-3)" }}>{time}</span>
|
<span className="num mono" style={{ width: 36, fontSize: 12, color: "var(--text-3)" }}>{time}</span>
|
||||||
@@ -129,11 +132,13 @@ function WaitingCard({
|
|||||||
agents,
|
agents,
|
||||||
employees,
|
employees,
|
||||||
onApprove,
|
onApprove,
|
||||||
|
onOpen,
|
||||||
}: {
|
}: {
|
||||||
approvals: ApprovalRecord[];
|
approvals: ApprovalRecord[];
|
||||||
agents: AgentRecord[];
|
agents: AgentRecord[];
|
||||||
employees: EmployeeRecord[];
|
employees: EmployeeRecord[];
|
||||||
onApprove: (approvalId: string) => void;
|
onApprove: (approvalId: string) => void;
|
||||||
|
onOpen: () => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<section className="card" style={{ padding: 18 }}>
|
<section className="card" style={{ padding: 18 }}>
|
||||||
@@ -152,7 +157,7 @@ function WaitingCard({
|
|||||||
</div>
|
</div>
|
||||||
<div className="row" style={{ gap: 6 }}>
|
<div className="row" style={{ gap: 6 }}>
|
||||||
<Button tone="primary" size="small" onClick={() => onApprove(approval.id)}>Approve</Button>
|
<Button tone="primary" size="small" onClick={() => onApprove(approval.id)}>Approve</Button>
|
||||||
<Button size="small">Open</Button>
|
<Button size="small" onClick={onOpen}>Open</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -204,13 +209,20 @@ function SpendCard({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function InProgressCard({ tasks, agents }: { tasks: TaskRecord[]; agents: AgentRecord[] }) {
|
function InProgressCard({ tasks, agents, onViewAll }: { tasks: TaskRecord[]; agents: AgentRecord[]; onViewAll: () => void }) {
|
||||||
const rows = tasks.slice(0, 4);
|
const rows = tasks.slice(0, 4);
|
||||||
return (
|
return (
|
||||||
<section className="card" style={{ padding: 18 }}>
|
<section className="card" style={{ padding: 18 }}>
|
||||||
<div className="row" style={{ marginBottom: 14 }}>
|
<div className="row" style={{ marginBottom: 14 }}>
|
||||||
<span className="card-label">In progress</span>
|
<span className="card-label">In progress</span>
|
||||||
<span style={{ marginLeft: "auto", fontSize: 11, color: "var(--text-3)" }}>{tasks.length} active</span>
|
<button
|
||||||
|
type="button"
|
||||||
|
className="link-button"
|
||||||
|
style={{ marginLeft: "auto", fontSize: 11 }}
|
||||||
|
onClick={onViewAll}
|
||||||
|
>
|
||||||
|
All work →
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{rows.map((task, index) => {
|
{rows.map((task, index) => {
|
||||||
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import type {
|
|||||||
OrganizationRecord,
|
OrganizationRecord,
|
||||||
} from "../../../shared/domain";
|
} from "../../../shared/domain";
|
||||||
import type { SnapshotActions } from "../app/useSnapshot";
|
import type { SnapshotActions } from "../app/useSnapshot";
|
||||||
|
import type { RouteId } from "../shared/Shell";
|
||||||
|
|
||||||
export interface PageProps {
|
export interface PageProps {
|
||||||
snapshot: AppSnapshot;
|
snapshot: AppSnapshot;
|
||||||
actions: SnapshotActions;
|
actions: SnapshotActions;
|
||||||
|
navigate: (route: RouteId) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activeOrgId(snapshot: AppSnapshot): string {
|
export function activeOrgId(snapshot: AppSnapshot): string {
|
||||||
|
|||||||
@@ -520,6 +520,16 @@ textarea.input { min-height: 84px; resize: vertical; line-height: 1.5; }
|
|||||||
.table-row.clickable { cursor: pointer; }
|
.table-row.clickable { cursor: pointer; }
|
||||||
.table-row.clickable:hover { background: var(--hover); }
|
.table-row.clickable:hover { background: var(--hover); }
|
||||||
|
|
||||||
|
.link-button {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
color: var(--text-3);
|
||||||
|
}
|
||||||
|
.link-button:hover { color: var(--text-1); }
|
||||||
|
|
||||||
.split-main { display: flex; flex-direction: row; min-height: 0; flex: 1; }
|
.split-main { display: flex; flex-direction: row; min-height: 0; flex: 1; }
|
||||||
.secondary-pane {
|
.secondary-pane {
|
||||||
width: 240px;
|
width: 240px;
|
||||||
|
|||||||
Reference in new issue
Block a user