Skip to content

Experimental: The AI extension and its component APIs may change in the future. Please give us feedback on your experience with them.

Demos#

Confirmation states#

The four design states: pending, required, confirmed and expired. The application owns their state.

Share history?

Do you want to give the customer advisor access to this conversation’s history?
Awaiting confirmation

Share history?

Required
Do you want to give the customer advisor access to this conversation’s history?
Required

Share history?

Do you want to give the customer advisor access to this conversation’s history?
Confirmed

Share history?

Expired
Do you want to give the customer advisor access to this conversation’s history?
Expired
<Provider locale="en-GB">
  <Flex.Vertical
    gap="medium"
    style={{
      maxWidth: '32.6875rem',
    }}
  >
    {(['pending', 'required', 'confirmed', 'expired'] as const).map(
      (status) => (
        <Confirmation
          key={status}
          title="Share history?"
          status={status}
          onConfirm={() => null}
          onDecline={() => null}
        >
          Do you want to give the customer advisor access to this
          conversation’s history?
        </Confirmation>
      )
    )}
  </Flex.Vertical>
</Provider>

Choose and reset#

Confirm or decline the request, then reset it to try again. A declined decision stays visible, with a text label rather than color alone.

Add these companies to your watchlist?

Påkrevd
Review the companies from the attached document before continuing.
Påkrevd
const Decision = () => {
  const [status, setStatus] = useState<
    'required' | 'confirmed' | 'declined'
  >('required')
  return (
    <>
      <Confirmation
        title="Add these companies to your watchlist?"
        status={status}
        onConfirm={() => setStatus('confirmed')}
        onDecline={() => setStatus('declined')}
        confirmLabel="Add to watchlist"
        declineLabel="Keep current list"
      >
        Review the companies from the attached document before continuing.
      </Confirmation>
      <Button top onClick={() => setStatus('required')}>
        Reset decision
      </Button>
    </>
  )
}
render(<Decision />)

Application-owned expiry#

Start a one-minute request, extend it or turn off the limit. The application warns before expiry and keeps completed decisions visible.

Continue with this request?

Utløpt
Review the request before continuing.
Utløpt
const TimedDecision = () => {
  const [status, setStatus] = useState<
    'expired' | 'required' | 'confirmed' | 'declined'
  >('expired')
  const startRef = useRef<HTMLButtonElement>(null)
  const [deadline, setDeadline] = useState<number>(null)
  const [now, setNow] = useState(Date.now())
  useEffect(() => {
    if (status !== 'required' || deadline === null) {
      return undefined
    }
    const update = () => {
      const time = Date.now()
      setNow(time)
      if (time >= deadline) {
        const focused = document.activeElement
        if (
          focused instanceof HTMLElement &&
          focused.closest('[data-visual-test="ai-confirmation-expiry"]') &&
          !focused.closest('.dnb-ai-confirmation')
        ) {
          startRef.current?.focus()
        }
        setStatus('expired')
      }
    }
    const interval = setInterval(update, 1000)
    update()
    return () => clearInterval(interval)
  }, [status, deadline])
  return (
    <>
      <Flex.Horizontal bottom>
        <Button
          ref={startRef}
          onClick={() => {
            setNow(Date.now())
            setDeadline(Date.now() + 60000)
            setStatus('required')
          }}
        >
          {status === 'required' ? 'Restart request' : 'Start a request'}
        </Button>
        {status === 'required' && deadline !== null && (
          <>
            <Button onClick={() => setDeadline(Date.now() + 60000)}>
              Extend by one minute
            </Button>
            <Button
              onClick={() => {
                setDeadline(null)
                startRef.current?.focus()
              }}
            >
              Turn off time limit
            </Button>
          </>
        )}
      </Flex.Horizontal>
      <Confirmation
        title="Continue with this request?"
        status={status}
        onConfirm={() => setStatus('confirmed')}
        onDecline={() => setStatus('declined')}
      >
        {status === 'required' && deadline !== null
          ? 'You have ' +
            Math.max(0, Math.ceil((deadline - now) / 1000)) +
            ' seconds. Extend or turn off the limit if you need more time.'
          : 'Review the request before continuing.'}
      </Confirmation>
      <AriaLive>
        {status === 'required' &&
        deadline !== null &&
        deadline - now <= 30000
          ? 'This request expires soon. Extend or turn off the time limit using the buttons above.'
          : ''}
      </AriaLive>
    </>
  )
}
render(<TimedDecision />)
Suggest an edit