kit

Refusal

Built revision v17.10.0

React
Topics

Human support

Bring a missing role, layout, or state, or a rendering against the standard, to the session working on kit. Name the package and the entry.

On List, Record, Form, Stepped flow, Settings, Field result, Find, Help

Refusal

Choose an address

oakmere
Return to booking page

The remedy first shows the field it moves to.

Choose an address

Return to booking page

Booking page

Address
oakmere

A Refusal inside a Dialog, its causes on the page behind it.

Upcoming bookings in Main Hall

Oakmere Yoga

Riverside Scouts

Remove Main Hall

Remove Main Hall

Main Hall

Removing Main Hall takes it off your booking page and out of the diary.

Takes effect as soon as you confirm.

You can restore Main Hall from Trash.

A Refusal on its line alone, with no cause to go to.

A submit refused by two fields, each cause going to its field.

accounts@Enter a complete billing email, such as aisha@oakmereprimary.org.
960 123Enter the phone number with its area code, such as 01632 960 123.
Source
module Refusal = KitReact.Roles.Refusal

@set external disclose: (Dom.element, bool) => unit = "open"
type toggleEvent
@send external listen: (Dom.element, string, toggleEvent => unit) => unit = "addEventListener"
@send external unlisten: (Dom.element, string, toggleEvent => unit) => unit = "removeEventListener"

let cause = (key, label): Refusal.cause => {
  key,
  href: "#" ++ key,
  label,
  props: {},
  linkProps: {},
}

let rowProps = (id, subject, facts): KitReact.Roles.Row.props => {subjectElement: Span, props: {id: id}, subject, facts: [{key: "reason", content: facts, props: {}}]}

let row = (id, subject, facts) => React.jsxKeyed(KitReact.Roles.Row.make, rowProps(id, subject, facts), ~key=id, ())

let emailError = value => String.includes(value, "@") && String.includes(value, ".") ? None : Some("Enter a complete billing email, such as aisha@oakmereprimary.org.")
let phoneError = value => value->String.replaceRegExp(%re("/\D/g"), "")->String.length >= 10 ? None : Some("Enter the phone number with its area code, such as 01632 960 123.")

@react.component
let make = () => {
  let (email, setEmail) = React.useState(() => "accounts@")
  let (phone, setPhone) = React.useState(() => "960 123")
  let fieldErrors = [("refusal-fields-email", emailError(email)), ("refusal-fields-phone", phoneError(phone))]->Array.filterMap(((key, error)) => error->Option.map(words => (key, words)))
  let caseRef = React.useRef(Nullable.null)
  let dialogRef = React.useRef(Nullable.null)
  let (dialogOpen, setDialogOpen) = React.useState(() => false)
  React.useEffect0(() => switch (Nullable.toOption(caseRef.current), Nullable.toOption(dialogRef.current)) {
  | (Some(details), Some(dialog)) =>
    let discloseCase = _ => details->disclose(true)
    listen(dialog, "beforetoggle", discloseCase)
    Some(() => unlisten(dialog, "beforetoggle", discloseCase))
  | _ => None
  })
  <>
    {ReactDOM.jsxs("form", KitReact.Dom.bind(~layout=#form, {id: "refusal-handle-form", children: React.array([
      ReactDOM.jsx("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#notices), {ariaLive: #polite})),
      ReactDOM.jsx("section", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"task-context"), {children: <h2>{React.string("Choose an address")}</h2>})),
      ReactDOM.jsxs("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"form-groups"), {children: React.array([
        ReactDOM.jsx("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#notices), {ariaLive: #polite})),
        <KitReact.Roles.FormGroup id="refusal-handle-form-group" kind=Text(Medium)
          label={React.string("Address")} labelProps={{htmlFor: "refusal-handle"}}
          controlProps={{id: "refusal-handle", name: "handle"}} controlValue="oakmere" printedValue={React.string("oakmere")} />,
      ])})),
      <KitReact.Roles.ActionGroup props={KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"submit-return"), {})}
        refusal={{id: "refusal-handle-taken", line: React.string("That address is taken. Choose another."), causes: [cause("refusal-handle", React.string("Use oakmere-hall"))]}}
        lead=PrimaryAction({children: React.string("Continue"), props: {type_: "button"}})
        return={<KitReact.Roles.WayBack href="#refusal-booking-page">{React.string("Return to booking page")}</KitReact.Roles.WayBack>} statusLines=[{children: React.null}] />,
    ])}))}
    <p className="specimen-case-line">{React.string("The remedy first shows the field it moves to.")}</p>
    {ReactDOM.jsxs("form", KitReact.Dom.bind(~layout=#form, {id: "refusal-mounted-form", children: React.array([
      ReactDOM.jsx("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#notices), {ariaLive: #polite})),
      ReactDOM.jsx("section", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"task-context"), {children: <h2>{React.string("Choose an address")}</h2>})),
      ReactDOM.jsx("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"form-groups"), {id: "refusal-mounted-fields", children: ReactDOM.jsx("div", KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#notices), {ariaLive: #polite}))})),
      <KitReact.Roles.ActionGroup props={KitReact.Dom.bind(~region=KitReact.Bindings.Layouts.Form.region(#"submit-return"), {})}
        refusal={{id: "refusal-mounted-taken", line: React.string("That address is taken. Choose another."), causes: [cause("refusal-mounted-fields", React.string("Use oakmere-hall"))]}}
        lead=PrimaryAction({children: React.string("Continue"), props: {type_: "button"}})
        return={<KitReact.Roles.WayBack href="#refusal-booking-page">{React.string("Return to booking page")}</KitReact.Roles.WayBack>} statusLines=[{children: React.null}] />,
    ])}))}
    <KitReact.Roles.HeadedRegion props={{id: "refusal-booking-page"}} heading=[KitReact.Words.Text("Booking page")]
      content={<KitReact.Roles.FactGroup><KitReact.Roles.LabelledFact name={React.string("Address")} value=Words([KitReact.Words.Text("oakmere")]) /></KitReact.Roles.FactGroup>} />
    <p className="specimen-case-line">{React.string("A Refusal inside a Dialog, its causes on the page behind it.")}</p>
    <section ariaLabelledby="refusal-bookings-title">
      <h3 id="refusal-bookings-title">{React.string("Upcoming bookings in Main Hall")}</h3>
      {row("refusal-booking-yoga", React.string("Oakmere Yoga"), Words([KitReact.Words.Time(KitReact.Time.intervalWithDay(Specimen_Reader.reader, ~start=Date.fromString("2026-05-12T17:00:00Z"), ~end=Date.fromString("2026-05-12T18:30:00Z")))]))}
      {row("refusal-booking-scouts", React.string("Riverside Scouts"), Words([KitReact.Words.Time(KitReact.Time.intervalWithDay(Specimen_Reader.reader, ~start=Date.fromString("2026-05-15T18:00:00Z"), ~end=Date.fromString("2026-05-15T20:00:00Z")))]))}
    </section>
    <details ref={ReactDOM.Ref.domRef(caseRef)}>
      <summary>{React.string("Remove Main Hall")}</summary>
      <KitReact.Roles.SecondaryAction props={{id: "refusal-remove-hall-opener", type_: "button", onClick: _ => setDialogOpen(_ => true)}}>{React.string("Remove Main Hall")}</KitReact.Roles.SecondaryAction>
      <KitReact.Roles.Dialog
        open_=dialogOpen
        returnFocus="refusal-remove-hall-opener"
        onOpen={() => setDialogOpen(_ => true)}
        onClose={() => setDialogOpen(_ => false)}
        id="refusal-remove-hall-dialog"
        props={{ref: ReactDOM.Ref.domRef(dialogRef), ariaLabelledby: "refusal-remove-hall-title"}}
        heading={React.string("Remove Main Hall")}
        headingProps={{id: "refusal-remove-hall-title"}}
        lead={PrimaryAction({children: React.string("Remove hall"), props: {type_: "button"}})}
        secondaryAction={{children: React.string("Keep hall"), props: {type_: "button"}}}
        refusal={{
          id: "refusal-remove-hall",
          line: React.string("Remove Main Hall is refused while it has upcoming bookings:"),
          causes: [
            cause("refusal-booking-yoga", <>{React.string("Oakmere Yoga, ")}<time dateTime="2026-05-12T18:00">{KitReact.TimeParts.elements(["12 May 2026", ", 18:00"])} </time></>),
            cause("refusal-booking-scouts", <>{React.string("Riverside Scouts, ")}<time dateTime="2026-05-15T19:00">{KitReact.TimeParts.elements(["15 May 2026", ", 19:00"])} </time></>),
          ],
        }}
      >
          <KitReact.Roles.InlineConsequence
            region=KitReact.Roles.InlineConsequence.Consequence
            props={{ariaLabel: "Remove Main Hall"}}
            subject={React.string("Main Hall")}
            consequence={React.string("Removing Main Hall takes it off your booking page and out of the diary.")}
            effectiveTime={React.string("Takes effect as soon as you confirm.")}
            correctionPath={React.string("You can restore Main Hall from Trash.")}
          />
      </KitReact.Roles.Dialog>
    </details>
    <p className="specimen-case-line">{React.string("A Refusal on its line alone, with no cause to go to.")}</p>
    <div>
      <Refusal
        id="refusal-refund-line"
        line={React.string("Issue refund is refused until both transfers on this invoice have arrived.")}
      />
      <KitReact.Roles.ActionGroup
        lead=PrimaryAction({children: React.string("Issue refund"), props: {type_: "button"}})
      />
    </div>
    <p className="specimen-case-line">{React.string("A submit refused by two fields, each cause going to its field.")}</p>
    <form id="refusal-fields-form">
      <KitReact.Roles.FormGroup id="refusal-fields-email-form-group"
        kind=Email
        label={React.string("Billing email")}
        labelProps={{htmlFor: "refusal-fields-email"}}
        controlProps={{id: "refusal-fields-email", name: "email", onChange: event => {
          let value = ReactEvent.Form.currentTarget(event)["value"]
          setEmail(_ => value)
        }}}
        controlValue="accounts@"
        printedValue={React.string(email)}
        error=?{emailError(email)->Option.map(React.string)}
      />
      <KitReact.Roles.FormGroup id="refusal-fields-phone-form-group"
        kind=Telephone
        label={React.string("Phone")}
        labelProps={{htmlFor: "refusal-fields-phone"}}
        controlProps={{id: "refusal-fields-phone", name: "phone", onChange: event => {
          let value = ReactEvent.Form.currentTarget(event)["value"]
          setPhone(_ => value)
        }}}
        controlValue="960 123"
        printedValue={React.string(phone)}
        error=?{phoneError(phone)->Option.map(React.string)}
      />
      {switch fieldErrors {
      | [] => React.null
      | errors =>
        <Refusal
          id="refusal-fields"
          line={React.string(switch errors->Array.length {
          | 1 => "1 field needs a change."
          | count => `${Int.toString(count)} fields need a change.`
          })}
          causes={errors->Array.map(((key, words)) => cause(key, React.string(words)))}
        />
      }}
      <KitReact.Roles.ActionGroup
        lead=PrimaryAction({children: React.string("Save hirer"), props: {type_: "button"}})
      />
    </form>
  </>
}