On List
Reordering
Rows in an order you set, one selected, and Main hall waiting for the order to be saved.
Seats 120
Save the room order before moving Main hall.
Seats 30
Seats 12
A table of records grouped by standing, the last group closed, whose Move dialog offers the groups, and one row whose move was refused.
| Request | Hirer responsible for the request | ||
|---|---|---|---|
Confirmed 2 | |||
| Choir rehearsal | Oakmere Singers | ||
| Yoga class | Priya Shah | ||
Waiting 2 | |||
| Toddler group | Tom Reid | ||
| Chess club Chess club was not moved to Confirmed: Saturday mornings are fully booked. | Ana Lima | ||
Declined 0 | |||
Records with identifier subjects.
| Record | Name |
|---|---|
PD/RCT/0001 | Saturday hire |
PD/RCT/0001/REVISION/00000000000000000000000000000000000000000000000000000001 | Revised Saturday hire |
Identifier subjects in the rows print form.
| Record | Name |
|---|---|
Saturday hire | |
Revised Saturday hire |
A total without a supporting price.
| Item | Price |
|---|---|
| Room hire | £680.00 |
| Total due | £680.00 |
A total with a credit card price underneath.
| Item | Price |
|---|---|
| Room hire | £680.00 |
| Total due | £680.00 Price when paying by credit card, including the processing fee: £701.94 |
The same total, printed as labelled rows.
| Item | Price |
|---|---|
Room hire | £680.00 |
Total due | £680.00 Price when paying by credit card, including the processing fee: £701.94 |
A total with a credit card price beneath its name.
| Item | Price |
|---|---|
| Room hire | £680.00 |
| Total duePrice when paying by credit card, including the processing fee: £701.94 | £680.00 |
The Move dialog, opened on its own.
Source
type element
type event
type detail = {dispatcher: element}
type request = {detail: detail}
@val @scope("document") external findById: string => Nullable.t<element> = "getElementById"
@new external requestFrom: (string, request) => event = "CustomEvent"
@send external dispatch: (element, event) => bool = "dispatchEvent"
@get external currentTarget: ReactEvent.Mouse.t => element = "currentTarget"
let room = (~root, ~slug, ~name, ~seats, ~checked=?, ~href, ()) => {
let row = `${root}-${slug}`
let subject = row ++ "-subject"
let row: KitReact.Roles.Row.props = {
props: {id: row},
handle: true,
selection: ?checked->Option.map(checked => <>
<KitReact.Roles.SelectionControl checked props={{name: "room", value: slug}} />
<span>{React.string("Select " ++ name)}</span>
</>),
subject: React.string(name),
subjectHref: href,
subjectProps: {id: subject},
facts: [{key: "seats", content: Words([KitReact.Words.Text("Seats "), KitReact.Words.Amount(KitReact.Amount.count(Specimen_Reader.reader, seats))]), props: {}}],
actions: [KitReact.Roles.Row.Move(KitReact.Roles.Reordering.Move.role({row, subject, state: ?(slug == "main-hall" ? Some(KitReact.ActionState.Inert({id: row ++ "-move", words: [KitReact.Words.Text("Save the room order before moving Main hall.")]})) : None)}))],
}
row
}
let positions = (root, names) => names->Array.map(((slug, name)): KitReact.Roles.Reordering.position => {id: `${root}-${slug}`, name})
let reorder = (order, root, {rows, place}: KitReact.Reordering.move) => {
let slugOf = row => row->String.slice(~start=String.length(root) + 1)
let moving = rows->Array.map(slugOf)
let rest = order->Array.filter(((slug, _)) => !(moving->Array.includes(slug)))
let carried = order->Array.filter(((slug, _)) => moving->Array.includes(slug))
let split = (target, after) => {
let at = rest->Array.findIndex(((slug, _)) => slug == slugOf(target)) + (after ? 1 : 0)
rest->Array.slice(~start=0, ~end=at)->Array.concat(carried)->Array.concat(rest->Array.slice(~start=at))
}
switch place {
| Before(target) => split(target, false)
| After(target) => split(target, true)
| Into(_) => order
}
}
let standing = [("confirmed", "Confirmed"), ("waiting", "Waiting"), ("declined", "Declined")]
let requests = [("choir", "Choir rehearsal", "confirmed", "Oakmere Singers"), ("yoga", "Yoga class", "confirmed", "Priya Shah"), ("toddlers", "Toddler group", "waiting", "Tom Reid"), ("chess", "Chess club", "waiting", "Ana Lima")]
let request = (~root, ~href, ~standing=?, (slug, name, group, hirer)): KitReact.Table.RowsTable.row => {
let row = `${root}-${slug}`
let subject = row ++ "-subject"
{
subject: <a href> {React.string(name)} </a>,
facts: [{content: Content(React.string(hirer)), props: {}}],
expansion: None,
props: {id: row},
subjectProps: {id: subject},
group: `${root}-${group}`,
?standing,
actions: [KitReact.Table.Move(KitReact.Roles.Reordering.Move.role({row, subject}))],
}
}
let refused = ((slug, _, _, _)) =>
slug == "chess" ? Some(KitReact.Table.Failed({words: [KitReact.Words.Text("Chess club was not moved to Confirmed: Saturday mornings are fully booked.")]})) : None
let standingGroup = (~root, ~expanded=true, (slug, name), count): KitReact.Table.group => {
let state: KitReact.Roles.Stamp.state = switch slug {
| "confirmed" => Settled
| "waiting" => Attention
| _ => Neutral
}
{
id: `${root}-${slug}`,
value: <KitReact.Roles.Stamp state> {React.string(name)} </KitReact.Roles.Stamp>,
count,
expanded,
}
}
let standingTable = (~caption, ~rows, ~groups): KitReact.Table.RowsTable.props => {
caption: React.string(caption),
subjectHeading: "Request",
columnHeadings: [{label: "Hirer responsible for the request"}],
rows,
groups,
handle: true,
}
let moveGroup = (root, (slug, name)): KitReact.Roles.Reordering.group => {id: `${root}-${slug}`, name}
let standingGroups = (root): KitReact.Roles.Reordering.groups => {
first: moveGroup(root, standing[0]->Option.getUnsafe),
rest: standing->Array.slice(~start=1)->Array.map(group => moveGroup(root, group)),
}
let standingPositions = (root, requests) => requests->Array.map(((slug, name, group, _)): KitReact.Roles.Reordering.position => {id: `${root}-${slug}`, name, group: `${root}-${group}`})
let regroup = (order, root, {rows, place}: KitReact.Reordering.move) => {
let slugOf = row => row->String.slice(~start=String.length(root) + 1)
let moving = rows->Array.map(slugOf)
let rest = order->Array.filter(((slug, _, _, _)) => !(moving->Array.includes(slug)))
let carriedTo = group => order->Array.filter(((slug, _, _, _)) => moving->Array.includes(slug))->Array.map(((slug, name, _, hirer)) => (slug, name, group, hirer))
let beside = (target, after) => {
let at = rest->Array.findIndex(((slug, _, _, _)) => slug == slugOf(target))
let (_, _, group, _) = rest[at]->Option.getUnsafe
let at = at + (after ? 1 : 0)
rest->Array.slice(~start=0, ~end=at)->Array.concat(carriedTo(group))->Array.concat(rest->Array.slice(~start=at))
}
switch place {
| Before(target) => beside(target, false)
| After(target) => beside(target, true)
| Into(group) => rest->Array.concat(carriedTo(slugOf(group)))
}
}
let count = (order, group) => order->Array.filter(((_, _, held, _)) => held == group)->Array.length->Int.toString
let rooms = [("main-hall", ("Main hall", 120, false)), ("garden-room", ("Garden room", 30, true)), ("committee-room", ("Committee room", 12, false))]
let names = order => order->Array.map(((slug, (name, _, _))) => (slug, name))
@react.component
let make = () => {
let (roomOrder, setRoomOrder) = React.useState(() => rooms)
let (requestOrder, setRequestOrder) = React.useState(() => requests)
let totalPrice: KitReact.Words.t = [KitReact.Words.Amount(KitReact.Amount.money(Specimen_Reader.reader, ~amount="680.00", ~currency="GBP"))]
let cardPrice: KitReact.Supporting.t = [{pieces: [KitReact.Words.Text("Price when paying by credit card, including the processing fee: "), KitReact.Words.Amount(KitReact.Amount.money(Specimen_Reader.reader, ~amount="701.94", ~currency="GBP"))]}]
<>
<p className="specimen-case-line">{React.string("Rows in an order you set, one selected, and Main hall waiting for the order to be saved.")}</p>
<KitReact.Roles.Reordering
id="reordering-rooms"
ordering=Ordered({placeLabel: "Place it", rowLabel: "Room"})
onMove={move => setRoomOrder(order => reorder(order, "reordering-rooms", move))}
closeLabel="Keep the order"
positions={positions("reordering-rooms", names(roomOrder))}
rows={roomOrder->Array.map(((slug, (name, seats, checked))) =>
room(~root="reordering-rooms", ~slug, ~name, ~seats, ~checked, ~href="#role-reordering", ())
)}
/>
<p className="specimen-case-line">{React.string("A table of records grouped by standing, the last group closed, whose Move dialog offers the groups, and one row whose move was refused.")}</p>
<KitReact.Roles.Reordering.Table
id="reordering-standing"
ordering=Ordered({placeLabel: "Place it", rowLabel: "Request", grouping: {groups: standingGroups("reordering-standing"), label: "Standing"}})
onMove={move => setRequestOrder(order => regroup(order, "reordering-standing", move))}
closeLabel="Keep the order"
positions={standingPositions("reordering-standing", requestOrder)}
table={standingTable(
~caption="Requests for Saturday mornings by standing",
~rows=requestOrder->Array.map(row => request(~root="reordering-standing", ~href="#role-reordering", ~standing=?refused(row), row)),
~groups=[
standingGroup(~root="reordering-standing", standing[0]->Option.getUnsafe, count(requestOrder, "confirmed")),
standingGroup(~root="reordering-standing", standing[1]->Option.getUnsafe, count(requestOrder, "waiting")),
standingGroup(~root="reordering-standing", ~expanded=false, standing[2]->Option.getUnsafe, count(requestOrder, "declined")),
],
)}
/>
<p className="specimen-case-line">{React.string("Records with identifier subjects.")}</p>
<KitReact.Table.RowsTable
props={{id: "records-identifier-subjects"}}
caption={React.string("Records by number")}
subjectHeading="Record"
columnHeadings={[{label: "Name"}]}
rows={[
{subject: <a href="#role-reordering"><code>{React.string("PD/RCT/0001")}</code></a>, facts: [{content: Content(React.string("Saturday hire"))}], expansion: None},
{subject: <a href="#role-reordering"><code>{React.string("PD/RCT/0001/REVISION/00000000000000000000000000000000000000000000000000000001")}</code></a>, facts: [{content: Content(React.string("Revised Saturday hire"))}], expansion: None},
]}
/>
<p className="specimen-case-line">{React.string("Identifier subjects in the rows print form.")}</p>
<KitReact.Table.RowsTable
props={{id: "records-identifier-subjects-rows"}}
printForm=Rows
caption={React.string("Records by number")}
subjectHeading="Record"
columnHeadings={[{label: "Name"}]}
rows={[
{subject: <a href="#role-reordering"><code>{React.string("PD/RCT/0001")}</code></a>, facts: [{content: Content(React.string("Saturday hire"))}], expansion: None},
{subject: <a href="#role-reordering"><code>{React.string("PD/RCT/0001/REVISION/00000000000000000000000000000000000000000000000000000001")}</code></a>, facts: [{content: Content(React.string("Revised Saturday hire"))}], expansion: None},
]}
/>
<p className="specimen-case-line">{React.string("A total without a supporting price.")}</p>
<KitReact.Table.RowsTable
props={{id: "records-total"}}
caption={React.string("Hire price")}
subjectHeading="Item"
columnHeadings={[{label: "Price", kind: KitReact.Table.RowsHeadingKind.Amount}]}
rows={[{subject: React.string("Room hire"), facts: [{content: Words(totalPrice)}], expansion: None}]}
total={{subject: React.string("Total due"), facts: [Some({content: Words(totalPrice)})]}}
/>
<p className="specimen-case-line">{React.string("A total with a credit card price underneath.")}</p>
<KitReact.Table.RowsTable
props={{id: "records-total-supporting"}}
caption={React.string("Hire price")}
subjectHeading="Item"
columnHeadings={[{label: "Price", kind: KitReact.Table.RowsHeadingKind.Amount}]}
rows={[{subject: React.string("Room hire"), facts: [{content: Words(totalPrice)}], expansion: None}]}
total={{subject: React.string("Total due"), facts: [Some({content: Words(totalPrice), supporting: cardPrice})]}}
/>
<p className="specimen-case-line">{React.string("The same total, printed as labelled rows.")}</p>
<KitReact.Table.RowsTable
props={{id: "records-total-supporting-rows"}}
printForm=Rows
caption={React.string("Hire price")}
subjectHeading="Item"
columnHeadings={[{label: "Price", kind: KitReact.Table.RowsHeadingKind.Amount}]}
rows={[{subject: React.string("Room hire"), facts: [{content: Words(totalPrice)}], expansion: None}]}
total={{subject: React.string("Total due"), facts: [Some({content: Words(totalPrice), supporting: cardPrice})]}}
/>
<p className="specimen-case-line">{React.string("A total with a credit card price beneath its name.")}</p>
<KitReact.Table.ComparisonTable
props={{id: "comparison-total-supporting"}}
caption={React.string("Hire price")}
subjectHeading={{label: "Item"}}
columnHeadings={[{label: "Price", kind: KitReact.Table.HeadingKind.Amount}]}
rows={[{subject: React.string("Room hire"), facts: [{content: Words(totalPrice)}], expansion: None}]}
total={{subject: React.string("Total due"), facts: [{content: Words(totalPrice)}], subjectSupporting: cardPrice}}
/>
<p className="specimen-case-line">{React.string("The Move dialog, opened on its own.")}</p>
<KitReact.Roles.SecondaryAction props={{type_: "button", onClick: event => {
let dispatcher = currentTarget(event)
findById("reordering-rooms-move")->Nullable.toOption->Option.forEach(dialog =>
ignore(dialog->dispatch(requestFrom("kit:modal-open", {detail: {dispatcher: dispatcher}})))
)
}}}>{React.string("Show the Move dialog")}</KitReact.Roles.SecondaryAction>
</>
}
Reordering, moving
Source
@react.component
let make = () =>
<>
<KitReact.Roles.Reordering.Table
id="reordering-moving-standing"
ordering=Ordered({placeLabel: "Place it", rowLabel: "Request", grouping: {groups: Role_Reordering.standingGroups("reordering-moving-standing"), label: "Standing"}})
onMove={_ => ()}
closeLabel="Keep the order"
positions={Role_Reordering.standingPositions("reordering-moving-standing", Role_Reordering.requests)}
table={Role_Reordering.standingTable(
~caption="Requests for Saturday mornings by standing",
~rows=Role_Reordering.requests->Array.map(request =>
Role_Reordering.request(~root="reordering-moving-standing", ~href="../#role-reordering-moving", request)
),
~groups=[
Role_Reordering.standingGroup(~root="reordering-moving-standing", Role_Reordering.standing[0]->Option.getUnsafe, "2"),
Role_Reordering.standingGroup(~root="reordering-moving-standing", Role_Reordering.standing[1]->Option.getUnsafe, "2"),
Role_Reordering.standingGroup(~root="reordering-moving-standing", Role_Reordering.standing[2]->Option.getUnsafe, "0"),
],
)}
/>
<p className="specimen-case-line">{React.string("Rooms waiting for their order to be checked.")}</p>
<details>
<summary>{React.string("Move a room")}</summary>
<KitReact.Roles.Reordering
id="reordering-inert-rooms"
ordering=Ordered({placeLabel: "Place it", rowLabel: "Room"})
onMove={_ => ()}
closeLabel="Keep the order"
moveState=Inert({id: "reordering-inert-rooms-commit", words: [KitReact.Words.Text("Move waits until the room order has been checked.")]})
positions={Role_Reordering.positions("reordering-inert-rooms", [("garden-room", "Garden room"), ("committee-room", "Committee room")])}
rows={[("garden-room", "Garden room", 30), ("committee-room", "Committee room", 12)]->Array.map(((slug, name, seats)) =>
Role_Reordering.room(~root="reordering-inert-rooms", ~slug, ~name, ~seats, ~href="../#role-reordering-moving", ())
)}
/>
</details>
</>