Payroll approvals

A React block (a whole screen) in Beamline's HR & payroll app.

Payroll approvals for a company paying through a payroll provider. Expenses are split by whose move it is (you, another approver, the employee answering a question) against the payroll's cutoff with the time left (a day away in the warning tint, passed in the danger tint, approvals then landing in the next payroll and saying so); decisions are taken one at a time or for the ticked ones, a rejection needs a reason, and a decision counts only once the provider acknowledges it: refused or closed keeps the expense as it was and says how to correct it. Contractors' submissions are grouped by contractor with their approval progress in one hue, a rate over the contract said, and Approve scoped to what is ticked ("Approve 2 of 3 for Ana Ruiz"). The history keeps requester, subject and the policy that routed each request in their own columns, with each request's levels in order. Each entity's approval levels are set in order (a person or a role, the amount over which each applies, self-approval), a level nobody can approve said as blocking, saved as a new version that approves nothing. The expenses on screen export with their filters said back, receipts in or out, prepared with progress and downloaded apart.

Use it for

  • Deciding expenses and contractor submissions that feed a payroll, before its cutoff.
  • Reading who decided what and under which policy, and setting each entity's approval levels.

Not for

Anatomy

  • header: the product's mark and title; tabs Expenses (waiting on you), Contractors (waiting), History, Approval levels
  • expenses: the cutoff line with the time left; Waiting on you / Another approver / The employee with counts; the entity; Export; the selection bar (Approve n, Reject n); the table: person and entity, submitted, category, receipt, amount, Approve and Reject (or who it waits on, or the question asked), each row's answer
  • contractors: a card per contractor: select all, progress in steps, Approve n of m for the contractor; each submission's title, hours at a rate, over the contract's rate, amount, state
  • history: outcome and type filters; decided, asked by, for, type, amount, routed by, outcome; a row opens to its levels in order
  • approval levels: the entity and version; each level's number, who approves, the amount over which it applies, move up, down, remove; Add a level; self-approval; Save as version n
  • export: format, Include receipts with the count without one, Prepare, the progress, the file, Download

States

  • expenses: loading, nothing waiting on you, a queue empty
  • cutoff: days left, hours left (warning), passed (danger, approvals land in the next payroll)
  • a decision: sending, approved in this payroll, approved into the next, rejected (with a reason), refused (kept, with the reason), closed (kept, with the fix), no answer
  • contractors: progress, ticked, approving, approved, refused with the reason, over the contract's rate
  • history: an outcome or type filter on, nothing matches, levels open
  • levels: a level nobody can approve (blocks saving), changed, saving, saved as a new version, refused (draft kept), discarded
  • export: preparing with progress, failed, ready, downloading, downloaded, download failed (retry without preparing)
  • phone: tables scroll sideways, level fields stack
  • right to left: mirrors

Keyboard

  • Tab through the tabs, the queue, the entity, Export, the selection boxes, each row's Approve and Reject; the reject dialog starts in its reason

Motion

None of its own.

Props

PropTypeDefaultDescription
entities (required)ApprovalEntity[]—
expenses (required)PayrollExpense[] | null—Expenses waiting on someone; null while loading.
cutoff{ period: string; at: string; next: string; } | null—The payroll the decisions feed, its cutoff (ISO instant), and the one after it.
onDecide((ids: string[], decision: "approve" | "reject", reason?: string | undefined) => Promis…—Record decisions. Only acknowledged ones change an expense; refused and closed keep it as it was, said.
submissionsContractorSubmission[]—
onApproveSubmissions((ids: string[]) => Promise<{ approved: string[]; refused?: { id: string; reason: strin…—
historyApprovalRecord[]—
policiesApprovalPolicy[]—
approversPolicyApprover[]—
onSavePolicy((policy: ApprovalPolicy) => Promise<{ version: number; }>)—Save an entity's levels as a new version. Approves nothing; open requests keep their route.
onExport((options: ExportOptions, progress: (fraction: number) => void) => Promise<{ name: stri…—Prepare the export file, reporting progress 0–1; resolve with its name and size.
onDownloadExport((name: string) => Promise<void>)—Download a prepared export, apart from preparing it.
nowstring—The moment the queue is read at (ISO instant); defaults to now.
defaultViewView—
defaultQueue"approver" | "employee" | "you"—
defaultSelectedstring[]—
defaultExportOpenboolean—
productstring—Your product's name, shown as its mark.
classNamestring—Classes on the documented visual root; no override by default.
refRef<HTMLDivElement>—Receives the documented native target or imperative handle; omitted by default.

Built from

Dependencies

lucide-react

Import

import { PayrollApprovals } from "@beamline/payroll-approvals";

Get it

Payroll approvals is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Get Beamline · Connect your agent

More in HR & payroll

  • Shift planner: A workplace's week of staff shifts against what it needs: a row per person with their week's hours against their contract, each day a 24-hour track with…
  • Shift rotations: Rotating shift patterns from pattern to people: a pattern of one to four weeks painted day by day with a shift template, a rest day or nothing (pick the…
  • Roster publishing: The week's roster before it goes out: areas down the side and days across, each shift a chip with who works it and its hours, its state its tone (not…
  • My shift: The worker's own shift on their phone: today drawn to scale (the plan's areas as blocks on an hour axis, under them what was worked: on-plan time in…
  • Timesheet review: Timesheets for a manager: the day's counts at the head (scheduled, on shift, late, on break, to approve), the ones that filter being buttons, an…
  • Hours ledger: One worker's pay cycle of shifts, for the worker or their payroll admin: the wall-clock span and the paid hours as separate columns, a night shift…
  • Payroll run: A pay period from report to submission, one payroll account at a time (a worker on two accounts is on both runs, never combined): the workers on one…
  • Payroll cycles: The client's side of an outsourced payroll across countries: every entity's current cycle on one board, its stage drawn as steps, the one thing that…
  • Benefit changes: An employee's benefit changes after a life event. The centre puts their turn first: each task (a proof to upload, with its deadline in the warning tint…
  • Hiring pipeline: A recruiting team's pipeline across every open job. Stage groups (reviewing, interviewing, closing) are counted across jobs above job sections that fold…
  • Recruiter home: A recruiter's own work, in one place. Upcoming interviews with who sits in, today's first; feedback owed, overdue first and on the danger tone, written…
  • Stage reports: Reports on how applications move through stages, built from each application's stage intervals. By week: applications present in each stage (or from each…
  • Link booking: A candidate's booking link for one stage of one job: a column with the job, the stage's length, who they meet (each with their role), where and what the…
  • Team & members: The people page of a workspace: seats used against the plan, members and pending invitations in one list with search and a role filter, role changes that…

Part of Beamline UI: polished, editable React components and complete screens for custom applications. Build your own style from any look; tokens, fonts, radii, motion; not only colours.