Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions components/AttendedDecisionPreview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useState } from 'react'

import styles from './AttendedDecisionPreview.module.css'

const CLOUD_ATTENTION_DEMO = 'https://app.openadapt.ai/demo/attention'

const states = {
request: {
image: '/attended-decision/identity-request.png',
alt: 'OpenAdapt mobile portal requesting an identity check before Save',
},
result: {
image: '/attended-decision/identity-verified.png',
alt: 'OpenAdapt mobile portal showing the runner-verified identity result',
},
}

// The two images are exact headless captures of the public Cloud identity
// case. Their source, hashes, and capture sequence are in public/attended-decision.
export default function AttendedDecisionPreview() {
const [state, setState] = useState('request')
const current = states[state]

return (
<section className={styles.section} aria-labelledby="attended-decision-title">
<figure className={styles.device}>
<div
className={styles.toggle}
role="group"
aria-label="Mobile decision state"
data-testid="attended-decision-toggle"
>
<button
type="button"
aria-pressed={state === 'request'}
onClick={() => setState('request')}
>
Request
</button>
<button
type="button"
aria-pressed={state === 'result'}
onClick={() => setState('result')}
>
Runner result
</button>
</div>
<img
key={state}
src={current.image}
alt={current.alt}
data-testid="attended-decision-capture"
/>
<figcaption>
Exact public Cloud capture · synthetic OpenEMR data
</figcaption>
</figure>
<div className={styles.copy}>
<p className={styles.eyebrow}>Attended decisions · Cloud demo</p>
<h2 id="attended-decision-title">
Keep a person in the loop. Keep the runner in control.
</h2>
<p>
When identity conflicts, OpenAdapt pauses before Save. The
phone shows only permitted answers. The customer runner
reads the live record again and returns the result.
</p>
<a
className={styles.demoLink}
href={CLOUD_ATTENTION_DEMO}
target="_blank"
rel="noopener noreferrer"
data-testid="attended-decision-demo-link"
>
Try all six mobile decision cases in Cloud
<span aria-hidden="true"> →</span>
</a>
</div>
</section>
)
}
111 changes: 111 additions & 0 deletions components/AttendedDecisionPreview.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
.section {
display: grid;
grid-template-columns: minmax(220px, 0.58fr) minmax(0, 1fr);
align-items: center;
gap: 34px;
width: 100%;
max-width: 900px;
margin: -18px auto 44px;
padding: 22px;
border: 1px solid var(--hairline);
border-radius: 14px;
background: var(--panel);
text-align: left;
}

.device {
display: grid;
justify-items: center;
gap: 9px;
margin: 0;
}

.toggle {
display: inline-flex;
padding: 3px;
border: 1px solid var(--hairline);
border-radius: 999px;
background: var(--ground);
}

.toggle button {
padding: 6px 10px;
border: 0;
border-radius: 999px;
background: transparent;
color: var(--ink-3);
font-size: 0.72rem;
font-weight: 600;
cursor: pointer;
}

.toggle button[aria-pressed='true'] {
background: var(--ink);
color: var(--panel);
}

.device img {
display: block;
width: auto;
max-width: 100%;
height: 400px;
}

.device figcaption {
color: var(--ink-3);
font-size: 0.68rem;
line-height: 1.4;
text-align: center;
}

.copy h2 {
max-width: 29rem;
margin: 0 0 12px;
color: var(--ink);
font-size: clamp(1.45rem, 2.5vw, 2rem);
line-height: 1.12;
}

.copy > p:not(.eyebrow) {
max-width: 34rem;
margin: 0;
color: var(--ink-2);
font-size: 0.98rem;
line-height: 1.6;
}

.eyebrow {
margin: 0 0 8px;
color: var(--accent);
font-family: var(--font-mono);
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
}

.demoLink {
display: inline-flex;
align-items: center;
gap: 0.2rem;
margin-top: 20px;
font-size: 0.9rem;
font-weight: 600;
}

@media (max-width: 700px) {
.section {
grid-template-columns: 1fr;
gap: 22px;
margin: -12px auto 34px;
padding: 18px;
}

.device {
grid-row: 2;
}

.device img {
height: 390px;
}
}
2 changes: 2 additions & 0 deletions components/MastHead.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import Link from 'next/link'

import ReplayHero from '@components/ReplayHero'
import AttendedDecisionPreview from '@components/AttendedDecisionPreview'
import { track, EVENTS } from 'utils/analytics'

import styles from './MastHead.module.css'
Expand Down Expand Up @@ -114,6 +115,7 @@ export default function Home({ githubStats }) {
</div>
<div className="flex flex-col align-center justify-center px-4 min-w-0 max-w-full overflow-hidden">
<ReplayHero />
<AttendedDecisionPreview />
</div>
</div>
</div>
Expand Down
21 changes: 21 additions & 0 deletions cypress/e2e/attended-decision-preview.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
describe('attended decision preview', () => {
it('switches between the real request and runner result, and links to the full demo', () => {
cy.visit('/')

cy.get('[data-testid="attended-decision-toggle"]').within(() => {
cy.get('button').eq(1).click().should('have.attr', 'aria-pressed', 'true')
})
cy.get('[data-testid="attended-decision-capture"]')
.should('have.attr', 'src', '/attended-decision/identity-verified.png')

cy.get('[data-testid="attended-decision-toggle"]').within(() => {
cy.get('button').eq(0).click().should('have.attr', 'aria-pressed', 'true')
})
cy.get('[data-testid="attended-decision-capture"]')
.should('have.attr', 'src', '/attended-decision/identity-request.png')

cy.get('[data-testid="attended-decision-demo-link"]')
.should('have.attr', 'href', 'https://app.openadapt.ai/demo/attention')
.and('have.attr', 'target', '_blank')
})
})
9 changes: 9 additions & 0 deletions lib/publicJsonArtifacts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ export const PUBLIC_JSON_ARTIFACTS = Object.freeze({
'Capture provenance and content hashes for the public Desktop screenshots.',
sha256: '8c0c67b7af7d4cedbf93175e4a74d1a7ac7f19b799e309dbeb044cf8dced30ee',
}),
'/attended-decision/provenance.json': Object.freeze({
source: '/attended-decision/provenance.json',
fileName: 'provenance.json',
format: 'json',
title: 'Attended decision capture provenance',
description:
'Source, action sequence, and content hashes for the public mobile decision captures.',
sha256: '1592c08273916431af74b2af509c1aa67afde21df69c0d689194da29ec03cb77',
}),
'/lending-demo/provenance.json': Object.freeze({
source: '/lending-demo/provenance.json',
fileName: 'provenance.json',
Expand Down
Binary file added public/attended-decision/identity-request.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions public/attended-decision/provenance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"source": {
"url": "https://app.openadapt.ai/demo/attention",
"captured_at": "2026-07-29",
"method": "Headless Playwright Chromium capture of the live public .attention-device element",
"viewport": {
"width": 768,
"height": 1100,
"device_scale_factor": 2
},
"data_boundary": "The public demo uses synthetic OpenEMR data. These captures do not show customer data."
},
"captures": [
{
"file": "identity-request.png",
"state": "Initial public identity request before an operator action; the retained OpenEMR evidence image completed with nonzero natural dimensions before capture",
"sha256": "9c9c8673b3497d61fd0aa636fb175ace4fd0f37bcf2b738149a80eefaf8f6cec",
"dimensions": {
"width": 860,
"height": 1936
}
},
{
"file": "identity-verified.png",
"state": "Public runner result after the permitted Check identity action",
"sha256": "5a83d5fd4b02f8c16f6ebb25f3ebb6eace839c3fede27077cde0c18945c5d728",
"dimensions": {
"width": 860,
"height": 1686
}
}
],
"sequence": [
"Open the public attention demo.",
"Wait until the retained OpenEMR evidence image is visible, complete, and has nonzero natural width and height.",
"Capture the .attention-device element in its initial identity-request state.",
"Select the permitted Check identity action.",
"Wait for the Identity verified runner receipt.",
"Capture the same .attention-device element."
]
}
Loading