Change orders

A React block (a whole screen) in Beamline's Construction app.

Change orders against a contract, with the money drawn where it stands: one bar of the original contract, each approved change, a line at the current contract and each pending change, all for the companies you choose and counted over the same scope as the log; the open change's cost stack by section and markup, whose markups you drag (the change's piece in the contract bar grows while you hold); one step per state (send; approve, held, which sweeps the current contract line across the change's piece as you hold and commits only when the hold completes; create a revision with separate copy choices, void and unvoid with the restoration said); an unpriced line keeps every total partial.

Use it for

  • A builder's or owner's change order log: extra work priced line by line, marked up, approved into the contract or sent back for a revision.
  • Any contract or budget whose value is a base sum plus approved changes, with changes priced by section and marked up (agency change requests, scope changes in services contracts).

Not for

Anatomy

  • head: title, project, the companies in scope as chips (the scope of every total and every row)
  • contract: Original contract, Approved changes (N), Current contract, Pending (N, M not priced) in words; the bar: the original drawn short behind a cut (said under the bar), approved changes as solid ink pieces, the current contract line with its sum, pending changes outlined, changes not sent faint, an unpriced change hatched with no length claimed; each piece opens its change and is ringed while its log row is pointed at or focused; a change with no price is hatched, a narrow slot with its number
  • log: number pinned (a draft says Not numbered), change with its company, status, amount (or so far, while a line is not priced), decision due, who has it
  • change (beside the log, a sheet in a narrow room): number, revision, status, More (Reject, Reopen, Void), title, company, due, who has it, its reason; the total (or Partial: known amount and lines not priced); the cost stack: each section's subtotal in an ink step, each markup a quiet filled step (its row carries the same swatch and rings its piece when pointed at or focused), a hatched piece for unpriced lines, labels where they fit and a key with every piece and amount
  • next step: Send for approval (draft; not while a line is unpriced), Hold to approve with the amount (pending; while held the figure shows where the current contract goes), Create revision (rejected), Unvoid (void), the approved day (approved)
  • costs by section: description, quantity, unit allowed for the section, unit price, cost, remove; Add per section (drafts); read only once sent
  • markups: label, its base in words and amount, the rate (the exact twin of the grip), the amount
  • backup documents; past revisions folded, each with its decision and its cost stack, read only
  • dialogs: Reject and Void with a reason; Create revision with Copy the costs and Copy the backup documents as separate choices, each saying what it copies; Unvoid saying the status and the person it returns to
  • cost presets (toolbar): a section at a time with its units; each preset one line (name, rate per unit) that opens its rate in place, with one sentence on the lines already priced from it, which keep their copy; Import workbook: the rows ready (new, rate changes) and each refused row named, added only on Add
  • a draft's section: Add and From preset (its presets, name and rate per unit); a line priced from a preset whose rate has changed since says both rates: an approved or pending line keeps its own, a draft line offers Use (the new rate)
  • related: typed cards (question, task, form: icon, number, title, status); a card opens its record; a question offers New change from it
  • notes, then replies by email (sender and address, time, subject, three lines, dashed until added): Add to notes, then In the notes; a note from a reply is quoted and says whose email it came from

States

  • all companies and a subset (the figures, the bar and the rows share the scope)
  • original contract not known for a company in scope: the original and current contract say Not known, with the companies named
  • pending with a line not priced: hatched in the bar, so far in the log, counted in Pending as not priced, never added as complete
  • draft with a line not priced: Send is held back and the step says how many lines need a price
  • markup held: the stack's scale stays still (its ceiling is every markup at 25 %), the piece, the total, the log amount and the change's piece in the bar follow while held; letting go saves once; Escape puts back the rate from the press
  • approving (held): the bar is drawn as the approval leaves it, at the hold's pace: the current contract line sweeps across the change's piece, which fills with the approved ink, and the pending pieces after it glide over by its width; the Current contract figure says where it goes (→ amount) without rolling, and Becomes amount waits, still, under the place the line lands; let go early or press Escape and everything glides back, nothing approved; the completed hold shows one label, Approving amount, while it saves, the figures roll once and nothing drawn moves again; refused, the piece goes back and the reason shows, and the hold starts over
  • rejected with its reason; create revision (copy choices, previewed); the new revision a draft; the old one read only in Past revisions
  • void and its restoration preview (the status and assignee the app recorded, and who it does not go back to)
  • saving refused (the last saved sheet put back, the reason under the stack)
  • no rows for the scope or the search; loading and failed to load (the grid's own)
  • narrow room: the change opens in a sheet; the figures take two columns
  • preset rate typed: the sentence of what it leaves alone; saved: the library line says the new rate, every change's amount and the contract are unchanged; refused: the reason, the rate as it was
  • workbook checked: ready rows (new, rate changes) and refused rows (no such section, a unit the section does not use, no name, no rate, the same name twice); nothing usable; added
  • a line from a preset whose rate moved: draft (Use the new rate) and approved or pending (keeps its own)
  • a reply adding, added (In the notes), refused (the reason), already added by someone else (who and when; the note shown once)
  • back from a related record: the same change open, the same search and filters, the row located; a new change from a question, open

Keyboard

  • the companies and statuses are toggle chips
  • the pieces of the contract bar are buttons (Tab, Enter opens the change)
  • the log is the data grid: arrows between cells, Enter opens
  • a markup's grip is a slider: arrows half a percent, Shift or Page 5 %, Home and End 0 and 25 %; the rate field is its exact twin
  • More is a menu; dialogs trap focus
  • Hold to approve is a hold: Space or Enter held on it (a finger or the mouse held too), Escape before it completes cancels
  • Cost presets is a button; the sections are a radio group; a preset's line is a button that opens its rate and focuses it; Enter saves
  • a related card is a button (its name says kind, number and title); New change from it and Add to notes are buttons

Motion

Approve is a hold: while it is held, the change's piece, the current contract line and every pending piece after it travel linearly, over exactly the hold's length, to where the approval puts them, and the piece fills with the approved ink behind the line; letting go early glides them back with the considered duration; the save then changes nothing drawn and the figures roll once. A send or a scope change glides the pieces with the considered duration (transforms only). While a markup is held nothing glides and the pieces follow the hand in the same frame. Nothing moves at rest; reduced motion places everything at once (the hold's fill, the preview in words and the commit stay). A note added from a reply grows out of the reply (the shared FLIP engine's origin); the cost sentence, the library and the cards place at once.

Props

PropTypeDefaultDescription
ordersChangeOrder[]—
defaultOrdersChangeOrder[]—
onOrdersChange((orders: ChangeOrder[]) => void)—
contracts (required)Contract[]—
people (required)ChangePerson[]—
me (required)string—The signed-in person's id.
projectstring—
currencystring—ISO 4217 code. Default USD.
openstring | null—Controlled open state; omit to use defaultOpen.
defaultOpenstring | null—Initial open state when uncontrolled; defaults to false.
onOpenChange((id: string | null) => void)—Reports an open-state change; no callback by default.
filtersRecord<string, string[]>—`company`: the companies in scope (none: all); `status`: statuses shown in the log.
defaultFiltersRecord<string, string[]>—
onFiltersChange((filters: Record<string, string[]>) => void)—
querystring—
defaultQuerystring—
onQueryChange((query: string) => void)—
loadingboolean—
errorstring | Error | null—
onRetry(() => void)—
classNamestring—Classes on the documented visual root; no override by default.
styleCSSProperties—Inline styles on the documented visual root; no overrides by default.
refRef<HTMLDivElement>—Receives the documented native target or imperative handle; omitted by default.
onSheetChange((id: string, sheet: CostSheet) => void | Promise<unknown>)—The cost sheet changed (lines or markups), sent once the person stops changing it. A rejection puts back the last saved sheet and says why. Only drafts are edited.
onSend((id: string) => void | Promise<void | { number?: string | undefined; assignee?: string…—Draft → pending. Not offered while a line is not priced. Resolve with the number it was given and who has it now (the approver), when the app assigns them.
onApprove((id: string) => void | Promise<unknown>)—Pending → approved: its amount moves into the contract.
onReject((id: string, reason: string) => void | Promise<unknown>)—Pending → rejected, with the reason.
onReopen((id: string) => void | Promise<unknown>)—Approved → pending again.
onCreateRevision((id: string, copy: { costs: boolean; documents: boolean; }) => void | Promise<unknown>)—Rejected → a new draft revision; costs and backup documents are copied only when chosen.
onVoid((id: string, reason: string) => void | Promise<void | { restore: { status: ChangeStatu…—Any → void. Resolve `{ restore }` with what Unvoid will put back (the status and the assignee it had).
onUnvoid((id: string) => void | Promise<unknown>)—Void → the change's `restore`.
canApproveboolean—Whether the signed-in person may approve and reject. Default true.
presetsCostPreset[]—The cost preset library.
defaultPresetsCostPreset[]—
onPresetsChange((presets: CostPreset[]) => void)—
onPresetsSave((presets: CostPreset[]) => void | Promise<unknown>)—Presets changed or added (a rate saved, a workbook's rows added). A rejection keeps the library as it was and says why. Lines already priced from a preset keep their copy. Without it the library is read only.
onPresetsImport((file: File) => PresetRow[] | Promise<PresetRow[]>)—Read a workbook into rows; the block checks each row against the sections and their units before anything is added. Without it there is no import.
onAdoptEmail((id: string, emailId: string) => Promise<{ note: ChangeNote; already?: boolean | undef…—Add an emailed reply to the change's notes. Resolve with the note. When the app finds it already added, resolve `{ note, already: true }` with the note that holds it: the block says so and adds nothing.
onOpenRecord((record: RelatedRecord, back: ChangeOrdersPlace) => void)—Open a related record, usually in its own page; `back` is where the person was, to bring them back to.
onCreateFromQuestion((id: string, questionId: string) => ChangeOrder | Promise<ChangeOrder>)—Create a draft change order from a related question. Resolve with the new change (its `related` should name the question); it opens.

Built from

Dependencies

lucide-react

Import

import { ChangeOrders, UNITS } from "@beamline/change-orders";

Get it

Change orders 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 Construction

  • Submittal register: The documents a trade owes a project before its material is bought, on the clocks that matter: a log whose rows each draw their way to site on one shared…
  • Inspection review: A unit's inspection, reviewed in three views. Findings: rooms and features with their condition, answers, notes and photos, and each feature's…
  • Work orders: A maintenance work order that coordinates subtasks: the children's progress drawn by status with cancelled ones counted apart, the parent completed on…
  • Action center: Everything waiting on a person across projects: a strip of every open item on the days ahead, one lane per kind of owing (You submit, You answer, Tasks…
  • Company access: A project's companies as one board: No company first (office access waits for a company, and says so), then each company with its code and its people…
  • Condition checklist: An inspection by area. Each item marked good (success), soon (warning) or needs work now (danger), or not checked yet and kept apart below; what was…
  • Corrective actions: A corrective action raised from a failed inspection answer, for food safety, facilities or quality teams. The answer, its photo and note are pinned above…
  • Quality checks: Quality checks by picture and the control points that make them. A check asks for one photo: an upload that fails keeps its file with Try again, and…
  • Maintenance plan: Maintenance of shared equipment. The instruments, most urgent first, each with its most pressing kind and how due it is (overdue, due soon, fine, never…
  • Maintenance plans: An operations team's maintenance plans. The queue lists every asset-plan pair (one machine can appear under two plans) with its last service, next due…
  • Equipment register: A business's machines and vehicles: a register filtered by status (in use, in repair, sold, each counted) with each machine's photo or type icon…
  • Asset workspace: One physical asset: a machine, vehicle or piece of plant. Its header keeps the system id apart from the name and serial, with type, site, status and the…
  • Asset packs: Packs of assets (sounds, presets, fonts), the providers they come from and the storage they take. Download and install are two phases with their own…
  • Instrument use: Shared instruments. The slot search reads as one sentence (how long, which instrument type, the dates and the working hours with the lab's time zone)…
  • Job booking: A customer books a home or field-service job on the company's own site, phone first. Services with how many units, each unit adding its time and price…
  • Job booking setup: Online booking for a field-service company, set up from three sides that feed one booking form. Services: each priced and timed per unit with whether it…
  • Rental availability: A rental shop's availability: a product's month for the quantity a customer wants (each day available, some left with the count, booked out or not known…
  • Rooms & equipment: A salon's or clinic's rooms and equipment and what its services need of them: resources by group at each location, how many appointments each holds at…
  • System pages: The four pages a product shows when the normal one cannot: page not found (search and the likely places), something broke (try again, an error id to…

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.