Packages & memberships

A React block (a whole screen) in Beamline's Salon & fitness app.

Prepaid packages and series, built: the packages down the side (version and how many sold, or not on sale yet), the open one beside them. Its price is a grip on a bar as long as booking its services one by one, so what the client saves is drawn as the rest of the bar and said in place, honestly ("saves up to" when a group's choices differ in price, the separate value said as a range), and what it costs more is hatched past the top for the owner only, with the exact field as its twin; the package is made on the card the client reads: each group (one of these services, or a number of credits, with add-ons included up to an amount) is its promise, opened in place to change it, an empty group refused in place, and the expiry its own line; beside it the owner's sum, each group booked one by one, the total, the price and what it saves, with the tax; a save is a new version and the packages already sold keep theirs, said with their count. One more part travels with it: ClientPackage, one client's package as they hold it: the credits left in each group set with count-adjust against what it came with and saved with a reason, a visit redeemed meanwhile refusing the stale save (who, where, both counts, the count back on the new record), the expiry changed or removed as its own save, and its history. ClientPackage also transfers a package to another client (the recipient found, a sentence naming both with the credits and the expiry, the buyer kept, the same holder refused, a transfer back the same action). Two more parts: MembershipMigration, a membership moved in from another system (active from its start, the first charge never before it, the old system's next charge drawn on the same line so paying twice shows, the old subscription still to cancel until a person confirms it, credits adjusted after), and PlanOnline, a plan sold online (its own switch, listed or by direct link only said as not private, short and full descriptions, the listing as clients see it, and its real state with the business-wide switch counted).

Use it for

  • Building a prepaid package or a series of visits from a menu of services: salons, spas, clinics, studios, gyms.
  • Pricing a bundle against what its parts cost one by one, and editing one already selling without changing what buyers bought.
  • ClientPackage: correcting a client's credits from their profile (a visit used but not recorded, a goodwill credit) and moving or removing their package's expiry.
  • MembershipMigration: moving a client's membership from another system without charging twice.
  • PlanOnline: selling a membership plan on the booking page or by its link.

Not for

  • Comparing subscription plans for buyers (pricing-table).
  • Store products and stock (purchase-orders).

Anatomy

  • header: the product's mark and the title
  • package list (nav): each package's name, version and how many sold (or not on sale yet), its price
  • sheet head: the package's name and where it stands
  • price: a grip (value-grip) on a bar as long as the services booked one by one; what the client pays solid ink, what they save a dashed stretch to the separate value's top, the low end of a range (a group whose choices differ in price) a dotted mark, what it costs more hatched past the top; the exact field as the twin; the separate value (a range when it is one) over its mark and the saving under its stretch ("saves up to" for a range)
  • the client's card, where the package is made: name, price, a real saving only (no line when there is none: an overrun is the owner's to see, by the bar), each group as the promise the client reads with its ticket marks; a promise's pencil opens it in place to its type (one of these / credits), its services (multi-select, with their prices), visits for credits and add-ons (at none one quiet Add-on allowance button, the field once used), Done; an empty group stays open, refused in place; Add a group; the expiry as its line with a pencil (never, or after a number of months)
  • the owner's sum beside it (Booked one by one): each group's worth (a range when its choices differ), Together, The package, the saving or what it costs more; the tax as its line with a pencil
  • bar (sticky, while there is something to save or say): how many already sold keep the old version, Discard changes and Save as vN
  • ClientPackage: the client and the package with its version and purchase day; Credits left, a count-adjust per group drawing what is left (the change struck and said as −n credits), with what the group came with and how many were used said beside its name, never drawn as empty units; a group all used is one quiet line (Used, All 8 used); under them Why (a reason, required), Undo and Save credits, and what was said (saved, not saved because the package moved on, couldn't save); Expiry: Last day as a date picker, Remove expiry, and its own save (Save last day …, Save: never expires) with its own words; History newest first (bought, used at a location, an adjustment with its reason and who, the expiry moved or removed)
  • ClientPackage, Holder: Held by … (bought by … after a transfer), Transfer to another client, Transfer to (find a client), the sentence, Transfer to <name>, its words
  • MembershipMigration: client, plan, Active from, First charge here; the line (Active <date>, First charge <price>, <date>, <system> charges … dashed while it runs); the summary; paying twice warned; Start the membership, active, Adjust this month's credits; On <system>: plan, price, next charge, Still to cancel, I've cancelled it on <system>, confirmed at
  • PlanOnline: the plan and price, its state (on sale listed / by link only / not on sale / off for the business), Sell this plan online, Where clients find it (Listed; Direct link only: not private), the link and Copy link, Short and Full description, Save; As clients see it

States

  • on sale: v and sold said; editing opens the bar with what the buyers keep
  • not on sale yet: Save puts it on sale as v1; an empty group keeps Save disabled and says so
  • price under the separate value: saves an amount and a share; equal: the same; over: costs more, struck
  • held: the price scale holds still under the hand
  • saved: a new version, said with the count that keeps the old
  • save refused: the edit kept, said in the bar
  • look only (canManage false): every control disabled, the permission said, no bar
  • loading: shaped skeletons; no packages: an empty state
  • phone: the list, then the package full width with Back; the client's view under the editor
  • right to left: the bar, the grip and the arrows mirror
  • reduced motion: through the tokens
  • ClientPackage: a change waiting (the reason asked for only when saving without one)
  • ClientPackage: stale (a visit redeemed meanwhile: not saved, said with who, where, when and both counts; the counts back on the new record; Save waits until they are set again)
  • ClientPackage: saved (the change joins the record and the history)
  • ClientPackage: never expires (the picker says it), expired (said in place; the credits hold until the expiry moves), look only (the permission said, no controls), loading, no package
  • ClientPackage: transfer to the same holder refused
  • MembershipMigration: first charge before the start refused; paying twice; started; old cancelled
  • PlanOnline: listed, link only, off, off for the business

Keyboard

  • On the price grip: Left/Right $1, Shift $10, Home/End to the scale's ends; Escape mid-drag puts back the price
  • Tab through each group's type, services, visits and add-ons, expiry, tax and the bar
  • ClientPackage: each group's row is a slider (←/→ one credit, Home/End the ends) with the field as its twin; Why is a select; the date picker opens its month grid

Motion

The price grip glides between key steps and follows the hand while held; the bar's parts follow it. The bar fades in when there is something to save. Nothing runs at rest. ClientPackage: the change on a row draws as the hand moves; history entries arriving slide the rest down (FLIP); the save row and its words fade in.

Props

PropTypeDefaultDescription
packagesServicePackage[]—The packages, controlled with onPackagesChange; or defaultPackages.
defaultPackagesServicePackage[]—The starting packages when uncontrolled.
onPackagesChange(packages: ServicePackage[]) => void—After a save.
openstring—The open package's id.
defaultOpenstring—Initial open state when uncontrolled; defaults to false.
onOpenChange(id: string) => void—Reports an open-state change; no callback by default.
services (required)PricedService[]—The services a group can hold, with their price booked on their own.
currency (required)string—ISO 4217 code for the prices ("USD").
onSave(pkg: ServicePackage) => Promise<unknown>—Save a package; resolve once saved (the block raises the version). Reject to keep the edit.
canManageboolean—false: the person may look but not change packages.
loadingboolean—Shaped skeletons while the packages load.
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.
ClientPackage: holding / defaultHolding / onHoldingChange / onAdjust / onExpiryChange / reasons / today / timeZone / canManageHolding | null / (a: CreditAdjustment) => Promise<AdjustResult> / (id, expiresOn: string | null) => Promise<Holding> / string[] / string / string / boolean—The client's package (groups with bought and left, the last day or null, the history, a revision). onAdjust gets the changes, the reason and the revision they were set against; resolve saved with the holding as it is now, or stale when it moved on meanwhile (nothing saved; the person sets the credits again); reject to keep the change. The expiry saves on its own; this person's own expiry save never makes a waiting credits change stale. holding.ts has the same rule (changesOf, isStale, since) for your server; your app decides redemptions, balances and the stale answer.
ClientPackage: clients / onTransfer{ id, name }[] / (holdingId, toClientId) => Promise<Holding>—Who a package can go to; resolve with the holding as it is now (credits and expiry unchanged, a transferred event on its history, the bought event keeping the buyer).
MembershipMigration: clients / plans / oldSubscriptions / today / onStart / onConfirmCancelled / onAdjustCredits… / MembershipPlan[] / Record<clientId, OldSubscription> / string / (MigrationStart) => Promise / (clientId) => Promise<{ at }> / (clientId) => void—The old system's subscription per client is shown until a person confirms it cancelled there; the block never cancels it itself.
PlanOnline: plan / businessOnline / business / onSaveOnlinePlan / boolean / string / (plan) => Promise—The plan's own switch, visibility and descriptions; businessOnline off makes it not on sale whatever its own switch says.

Built from

Dependencies

lucide-react

Import

import { PackagesMemberships, ClientPackage, MembershipMigration, PlanOnline } from "@beamline/packages-memberships";

Get it

Packages & memberships 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 Salon & fitness

  • Workout planner: A training plan a person lives in: the program's next session with its estimate and Start, an exercise replaced for this session only or for every later…
  • Workout logger: A live training session: every exercise's sets as target-table rows with a done column; marking a set done fills its shape and starts the rest by itself…
  • Training progress: A person's training history: the headline counts (weeks in a row, days since the last workout, workouts this month), a month calendar that names each…
  • Program setup: A training program's setup and living settings: the intake (one question per step, the week drawn as you answer, a failed generation keeping every…
  • Protocol builder: A practitioner's reusable protocol and the client copies made from it. Foods and habits each carry a written intent (Include, Reduce, Exclude) in its…
  • Nutrition library: A nutrition practice's library. Recipes: ingredients with grams and servings, nutrients per serving summed (energy, protein, carbohydrate, fat, fibre), a…
  • Client forms: A salon's or spa's client forms and who they ask: the forms down the side with where each stands (on, set up and off, not set up yet), the open one…
  • Instructor finder: Finding a flight instructor. Search by name or airfield, filter by what you want to learn (each subject with how many teach it nearby), by distance, and…
  • Flight logbook: A pilot's logbook. Total time (with hours brought forward from earlier logbooks), PIC, night, the last 90 days and how many entries are still incomplete…

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.