@adminide-stack/yantra-mobile 12.0.141 → 12.0.142

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import {useMemo,useState,useRef,useCallback,useEffect}from'react';import {Alert,BackHandler,Share,View,StyleSheet,ScrollView,Text,Linking}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {useSafeInsets}from'../canvas/withRemoteSafeArea.js';import {createRemoteUploadMedia,createRemoteConnectorExec}from'../canvas/videoEditor/remoteMediaClient.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {Tap,DIM}from'../inbox/components/Tap.js';import {DictationList}from'./components/DictationList.js';import {NoteView}from'./components/NoteView.js';import {RecordingPanel,StartPanel}from'./components/RecordPanel.js';import {writeNoteFromRecording,dictateErrorText}from'./dictateClient.js';import {dictateTheme}from'./dictateTheme.js';import {createDictationStore}from'./dictationStore.js';import {noteToText}from'./noteText.js';import {useDictationRecorder,MicrophoneDeniedError}from'./useDictationRecorder.js';var __defProp = Object.defineProperty;
1
+ import {jsx,jsxs}from'react/jsx-runtime';import {useMemo,useState,useEffect,useCallback,useRef}from'react';import {Alert,BackHandler,Share,View,StyleSheet,ScrollView,Text,Linking}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {useSafeInsets}from'../canvas/withRemoteSafeArea.js';import {createRemoteUploadMedia,createRemoteConnectorExec}from'../canvas/videoEditor/remoteMediaClient.js';import {useAppTheme}from'../../theme/AppThemeProvider.js';import {Tap,DIM}from'../inbox/components/Tap.js';import {DictationList}from'./components/DictationList.js';import {NoteView}from'./components/NoteView.js';import {RecordingPanel,StartPanel}from'./components/RecordPanel.js';import {writeNoteFromRecording,dictateErrorText,suggestFromNote,suggestErrorText}from'./dictateClient.js';import {readShowIdentifiers,writeShowIdentifiers}from'./dictatePreference.js';import {dictateTheme}from'./dictateTheme.js';import {createDictationStore}from'./dictationStore.js';import {noteToText}from'./noteText.js';import {labelText}from'./privacy.js';import {shownNote}from'./shownNote.js';import {useDictationRecorder,MicrophoneDeniedError}from'./useDictationRecorder.js';var __defProp = Object.defineProperty;
2
2
  var __defProps = Object.defineProperties;
3
3
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -41,7 +41,7 @@ function DictateExperience({
41
41
  deps,
42
42
  store: injectedStore
43
43
  }) {
44
- var _a, _b;
44
+ var _a, _b, _c;
45
45
  const appTheme = useAppTheme();
46
46
  const theme = useMemo(() => dictateTheme(hostDark != null ? hostDark : appTheme.isDark), [hostDark, appTheme.isDark]);
47
47
  const insets = useSafeInsets();
@@ -55,6 +55,17 @@ function DictateExperience({
55
55
  const [starting, setStarting] = useState(false);
56
56
  const [error, setError] = useState(null);
57
57
  const [micDenied, setMicDenied] = useState(false);
58
+ const [showIdentifiers, setShowIdentifiers] = useState(false);
59
+ const [suggestStates, setSuggestStates] = useState({});
60
+ useEffect(() => {
61
+ void readShowIdentifiers().then(setShowIdentifiers);
62
+ }, []);
63
+ const toggleIdentifiers = useCallback(() => {
64
+ setShowIdentifiers((show) => {
65
+ writeShowIdentifiers(!show);
66
+ return !show;
67
+ });
68
+ }, []);
58
69
  const tokenRef = useRef(token);
59
70
  tokenRef.current = token;
60
71
  const agent = useMemo(() => deps != null ? deps : {
@@ -103,6 +114,7 @@ function DictateExperience({
103
114
  status: "ready",
104
115
  note: written.note,
105
116
  transcript: written.transcript,
117
+ redaction: written.redaction,
106
118
  model: written.model,
107
119
  error: void 0
108
120
  });
@@ -114,9 +126,9 @@ function DictateExperience({
114
126
  });
115
127
  } finally {
116
128
  setStages((_a2) => {
117
- var _c = _a2, {
129
+ var _c2 = _a2, {
118
130
  [_b2 = record.id]: _done
119
- } = _c, rest = __objRest(_c, [
131
+ } = _c2, rest = __objRest(_c2, [
120
132
  __restKey(_b2)
121
133
  ]);
122
134
  return rest;
@@ -124,6 +136,40 @@ function DictateExperience({
124
136
  await refresh();
125
137
  }
126
138
  }, [agent, store, refresh]);
139
+ const suggest = useCallback(async (record) => {
140
+ if (!record.redaction) return;
141
+ setSuggestStates((s) => __spreadProps(__spreadValues({}, s), {
142
+ [record.id]: {
143
+ status: "loading"
144
+ }
145
+ }));
146
+ try {
147
+ const {
148
+ items,
149
+ identifiers
150
+ } = await suggestFromNote(record.redaction, agent);
151
+ await store.update(record.id, {
152
+ suggestions: {
153
+ items,
154
+ identifiers,
155
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
156
+ }
157
+ });
158
+ await refresh();
159
+ setSuggestStates((s) => __spreadProps(__spreadValues({}, s), {
160
+ [record.id]: {
161
+ status: "idle"
162
+ }
163
+ }));
164
+ } catch (err) {
165
+ setSuggestStates((s) => __spreadProps(__spreadValues({}, s), {
166
+ [record.id]: {
167
+ status: "error",
168
+ message: suggestErrorText(err)
169
+ }
170
+ }));
171
+ }
172
+ }, [agent, store, refresh]);
127
173
  const start = useCallback(async () => {
128
174
  setError(null);
129
175
  setStarting(true);
@@ -217,11 +263,13 @@ function DictateExperience({
217
263
  const open = screen.kind === "note" ? (_a = records.find((r) => r.id === screen.id)) != null ? _a : null : null;
218
264
  const share = useCallback(() => {
219
265
  if (!(open == null ? void 0 : open.note)) return;
266
+ const shown = shownNote(open, open.note, showIdentifiers);
267
+ const text = noteToText(shown.note, shown.transcript, shown.suggestions);
220
268
  void Share.share({
221
- title: open.note.title,
222
- message: noteToText(open.note)
269
+ title: labelText(shown.note.title),
270
+ message: labelText(text)
223
271
  });
224
- }, [open]);
272
+ }, [open, showIdentifiers]);
225
273
  const remove = useCallback(() => {
226
274
  if (!open) return;
227
275
  const removed = open.note ? "The note and transcript are removed from this phone." : "The recording is removed from this phone.";
@@ -247,6 +295,10 @@ function DictateExperience({
247
295
  if (screen.kind === "note" && open) {
248
296
  body = /* @__PURE__ */ jsx(NoteView, { record: open, stage: (_b = stages[open.id]) != null ? _b : null, theme, bottomInset: insets.bottom, onRetry: () => {
249
297
  void write(open);
298
+ }, showIdentifiers, onToggleIdentifiers: toggleIdentifiers, suggestState: (_c = suggestStates[open.id]) != null ? _c : {
299
+ status: "idle"
300
+ }, onSuggest: () => {
301
+ void suggest(open);
250
302
  } });
251
303
  } else if (screen.kind === "record" && recorder.phase !== "idle") {
252
304
  body = /* @__PURE__ */ jsx(View, { style: styles.recordBody, children: /* @__PURE__ */ jsx(RecordingPanel, { theme, phase: recorder.phase, pauseReason: recorder.pauseReason, elapsedMs: recorder.elapsedMs, level: recorder.level, noInput: recorder.noInput, onPause: recorder.pause, onResume: recorder.resume, onDone: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"DictateExperience.js","sources":["../../../src/features/dictate/DictateExperience.tsx"],"sourcesContent":["/**\n * Dictate: a clinician speaks a visit note; Yantra writes it up as a SOAP note\n * with the points to check before it is used.\n *\n * Record (screen kept awake, paused honestly if the app leaves the screen) ->\n * the recording is kept on the phone at once -> uploaded and handed to\n * YANTRA_MEETINGS_CLINICAL_NOTE (medical speech-to-text, then the note) ->\n * the note is saved on the phone and the recording deleted. A note that could\n * not be written keeps its recording for Retry, across restarts.\n *\n * The host screen passes the session (token + surface index URL); everything\n * else - the recorder, the store, the agent calls - lives here.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { Alert, BackHandler, Linking, ScrollView, Share, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { useSafeInsets } from '../canvas/withRemoteSafeArea';\nimport { createRemoteConnectorExec, createRemoteUploadMedia } from '../canvas/videoEditor/remoteMediaClient';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { DIM, Tap } from '../inbox/components/Tap';\nimport { DictationList } from './components/DictationList';\nimport { NoteView } from './components/NoteView';\nimport { RecordingPanel, StartPanel } from './components/RecordPanel';\nimport { dictateErrorText, writeNoteFromRecording, type DictateDeps, type DictateStage } from './dictateClient';\nimport { dictateTheme } from './dictateTheme';\nimport { createDictationStore, type DictationStore } from './dictationStore';\nimport { noteToText } from './noteText';\nimport type { DictationRecord } from './types';\nimport { MicrophoneDeniedError, useDictationRecorder } from './useDictationRecorder';\n\nexport interface DictateExperienceProps {\n isDark?: boolean;\n token?: string | null;\n /** The surface index URL; the agent (uploads, the note) is derived from it. */\n indexUrl: string;\n sessionError?: string | null;\n onRetrySession?: () => void;\n onExit: () => void;\n /** Tests and previews inject these; the app builds them from the session. */\n deps?: DictateDeps;\n store?: DictationStore;\n}\n\ntype Screen = { kind: 'home' } | { kind: 'record' } | { kind: 'note'; id: string };\n\nexport const PREVIEW_NOTICE =\n 'Preview: dictate made-up visits only. Real patient information needs your practice’s HIPAA agreement with Yantra first.';\n\nexport function DictateExperience({\n isDark: hostDark,\n token,\n indexUrl,\n sessionError,\n onRetrySession,\n onExit,\n deps,\n store: injectedStore,\n}: DictateExperienceProps) {\n const appTheme = useAppTheme();\n const theme = useMemo(() => dictateTheme(hostDark ?? appTheme.isDark), [hostDark, appTheme.isDark]);\n const insets = useSafeInsets();\n const store = useMemo(() => injectedStore ?? createDictationStore(), [injectedStore]);\n const recorder = useDictationRecorder();\n const [screen, setScreen] = useState<Screen>({ kind: 'home' });\n const [records, setRecords] = useState<DictationRecord[]>([]);\n const [stages, setStages] = useState<Record<string, DictateStage>>({});\n const [starting, setStarting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [micDenied, setMicDenied] = useState(false);\n\n const tokenRef = useRef(token);\n tokenRef.current = token;\n const agent = useMemo<DictateDeps>(\n () =>\n deps ?? {\n exec: (connector, action, params, options) => {\n const { current } = tokenRef;\n if (!current) return Promise.reject(new Error('Network request failed: not signed in yet'));\n return createRemoteConnectorExec(current, indexUrl)(connector, action, params, options);\n },\n upload: (uri) => {\n const { current } = tokenRef;\n if (!current) return Promise.reject(new Error('Network request failed: not signed in yet'));\n return createRemoteUploadMedia(current, indexUrl)(uri);\n },\n },\n [deps, indexUrl],\n );\n\n const refresh = useCallback(async () => setRecords(await store.list()), [store]);\n\n // A note being written when the app last closed never finished: offer it again.\n useEffect(() => {\n void (async () => {\n for (const r of await store.list()) {\n if (r.status === 'writing') await store.update(r.id, { status: r.audioUri ? 'saved' : 'failed' });\n }\n await refresh();\n })();\n }, [store, refresh]);\n\n const write = useCallback(\n async (record: DictationRecord) => {\n if (!record.audioUri) return;\n setStages((s) => ({ ...s, [record.id]: 'uploading' }));\n await store.update(record.id, { status: 'writing', error: undefined });\n await refresh();\n try {\n const written = await writeNoteFromRecording(record.audioUri, agent, {}, (stage) =>\n setStages((s) => ({ ...s, [record.id]: stage })),\n );\n await store.update(record.id, {\n status: 'ready',\n note: written.note,\n transcript: written.transcript,\n model: written.model,\n error: undefined,\n });\n await store.dropAudio(record.id);\n } catch (err) {\n await store.update(record.id, { status: 'failed', error: dictateErrorText(err) });\n } finally {\n setStages(({ [record.id]: _done, ...rest }) => rest);\n await refresh();\n }\n },\n [agent, store, refresh],\n );\n\n const start = useCallback(async () => {\n setError(null);\n setStarting(true);\n try {\n await recorder.start();\n setMicDenied(false);\n setScreen({ kind: 'record' });\n } catch (err) {\n // A declined microphone is not an error to retry: it is a setting, so offer the way there.\n if (err instanceof MicrophoneDeniedError) setMicDenied(true);\n else setError('The microphone could not start. Try again.');\n } finally {\n setStarting(false);\n }\n }, [recorder]);\n\n const done = useCallback(async () => {\n const out = await recorder.finish();\n if (!out) {\n setScreen({ kind: 'home' });\n setError('The recording could not be saved. Try again.');\n return;\n }\n const record = await store.keepRecording(out.uri, out.durationMs);\n await refresh();\n setScreen({ kind: 'note', id: record.id });\n void write(record);\n }, [recorder, store, refresh, write]);\n\n const discard = useCallback(() => {\n Alert.alert('Discard this dictation?', 'The recording is deleted and no note is written.', [\n { text: 'Keep dictating', style: 'cancel' },\n {\n text: 'Discard',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n const out = await recorder.finish();\n if (out) await store.discardRecording(out.uri);\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n }, [recorder, store]);\n\n const back = useCallback(() => {\n if (screen.kind === 'record') {\n if (recorder.phase === 'recording') recorder.pause();\n Alert.alert('Stop dictating?', 'Write the note from what you have recorded, or discard it.', [\n { text: 'Keep dictating', style: 'cancel' },\n {\n text: 'Write the note',\n onPress: () => {\n void done();\n },\n },\n {\n text: 'Discard',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n const out = await recorder.finish();\n if (out) await store.discardRecording(out.uri);\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n return true;\n }\n if (screen.kind === 'note') {\n setScreen({ kind: 'home' });\n return true;\n }\n onExit();\n return true;\n }, [screen.kind, recorder, done, store, onExit]);\n\n useEffect(() => {\n const sub = BackHandler.addEventListener('hardwareBackPress', back);\n return () => sub.remove();\n }, [back]);\n\n const open = screen.kind === 'note' ? (records.find((r) => r.id === screen.id) ?? null) : null;\n\n const share = useCallback(() => {\n if (!open?.note) return;\n void Share.share({ title: open.note.title, message: noteToText(open.note) });\n }, [open]);\n\n const remove = useCallback(() => {\n if (!open) return;\n const removed = open.note\n ? 'The note and transcript are removed from this phone.'\n : 'The recording is removed from this phone.';\n Alert.alert('Delete this dictation?', removed, [\n { text: 'Cancel', style: 'cancel' },\n {\n text: 'Delete',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n await store.remove(open.id);\n await refresh();\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n }, [open, store, refresh]);\n\n const title = screen.kind === 'note' ? 'Note' : 'Dictate';\n\n // The note, the live recording, or the home list - whichever screen is open.\n let body: React.ReactNode;\n if (screen.kind === 'note' && open) {\n body = (\n <NoteView\n record={open}\n stage={stages[open.id] ?? null}\n theme={theme}\n bottomInset={insets.bottom}\n onRetry={() => {\n void write(open);\n }}\n />\n );\n } else if (screen.kind === 'record' && recorder.phase !== 'idle') {\n body = (\n <View style={styles.recordBody}>\n <RecordingPanel\n theme={theme}\n phase={recorder.phase}\n pauseReason={recorder.pauseReason}\n elapsedMs={recorder.elapsedMs}\n level={recorder.level}\n noInput={recorder.noInput}\n onPause={recorder.pause}\n onResume={recorder.resume}\n onDone={() => {\n void done();\n }}\n onDiscard={discard}\n />\n </View>\n );\n } else {\n body = (\n <ScrollView contentContainerStyle={[styles.home, { paddingBottom: 24 + insets.bottom }]}>\n <Text style={[styles.lead, { color: theme.ink }]}>Dictate a visit</Text>\n <Text style={[styles.leadDetail, { color: theme.muted }]}>\n Speak your note. Yantra writes it up as a SOAP note and lists what to check before you use it.\n </Text>\n <StartPanel\n theme={theme}\n starting={starting}\n recordsInBackground={recorder.recordsInBackground}\n onStart={() => {\n void start();\n }}\n />\n {error ? <Text style={[styles.error, { color: theme.crit }]}>{error}</Text> : null}\n {micDenied ? (\n <View style={[styles.banner, { backgroundColor: theme.recSoft }]}>\n <MaterialCommunityIcons name=\"microphone-off\" size={18} color={theme.crit} />\n <Text style={[styles.bannerText, { color: theme.crit }]}>\n Microphone access is off for Yantra.\n </Text>\n <Tap\n onPress={() => {\n void Linking.openSettings();\n }}\n accessibilityRole=\"button\"\n style={[styles.bannerAction, { backgroundColor: theme.card, borderColor: theme.border }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.bannerActionText, { color: theme.ink }]}>Open Settings</Text>\n </Tap>\n </View>\n ) : null}\n {sessionError ? (\n <Tap\n onPress={onRetrySession}\n accessibilityRole=\"button\"\n style={[styles.banner, { backgroundColor: theme.recSoft }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.bannerText, { color: theme.crit }]}>\n Not connected, so notes cannot be written yet. Tap to retry.\n </Text>\n </Tap>\n ) : null}\n <View\n style={[\n styles.banner,\n {\n backgroundColor: theme.warnSoft,\n borderColor: theme.warnBorder,\n borderWidth: StyleSheet.hairlineWidth,\n },\n ]}\n >\n <MaterialCommunityIcons name=\"shield-alert-outline\" size={18} color={theme.warnInk} />\n <Text style={[styles.bannerText, { color: theme.warnInk }]}>{PREVIEW_NOTICE}</Text>\n </View>\n <Text style={[styles.sectionLabel, { color: theme.muted }]}>RECENT</Text>\n <DictationList records={records} theme={theme} onOpen={(r) => setScreen({ kind: 'note', id: r.id })} />\n </ScrollView>\n );\n }\n\n return (\n <View style={[styles.screen, { backgroundColor: theme.screen, paddingTop: insets.top }]}>\n <View style={[styles.header, { borderBottomColor: theme.border }]}>\n <Tap\n onPress={back}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Back\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"chevron-left\" size={28} color={theme.ink} />\n </Tap>\n <Text style={[styles.headerTitle, { color: theme.ink }]}>{title}</Text>\n <View style={styles.headerActions}>\n {open?.note ? (\n <Tap\n onPress={share}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Share the note\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"export-variant\" size={22} color={theme.ink} />\n </Tap>\n ) : null}\n {/* Any dictation can go, note or not; just not while its note is being written. */}\n {open && !stages[open.id] ? (\n <Tap\n onPress={remove}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Delete\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"trash-can-outline\" size={22} color={theme.ink} />\n </Tap>\n ) : null}\n </View>\n </View>\n\n {body}\n </View>\n );\n}\n\nexport default DictateExperience;\n\nconst styles = StyleSheet.create({\n screen: { flex: 1 },\n header: {\n height: 52,\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: 4,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n headerButton: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center' },\n headerTitle: { flex: 1, fontSize: 17, fontWeight: '600' },\n headerActions: { flexDirection: 'row', alignItems: 'center' },\n home: { paddingHorizontal: 16, paddingTop: 20 },\n lead: { fontSize: 24, fontWeight: '700' },\n leadDetail: { marginTop: 6, fontSize: 15, lineHeight: 21 },\n error: { textAlign: 'center', fontSize: 13, marginBottom: 8 },\n banner: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 10,\n borderRadius: 12,\n paddingHorizontal: 12,\n paddingVertical: 10,\n marginBottom: 12,\n },\n bannerText: { flex: 1, fontSize: 13, lineHeight: 18 },\n bannerAction: {\n paddingHorizontal: 12,\n paddingVertical: 7,\n borderRadius: 999,\n borderWidth: StyleSheet.hairlineWidth,\n },\n bannerActionText: { fontSize: 13, fontWeight: '600' },\n sectionLabel: { marginTop: 12, marginBottom: 8, fontSize: 12, fontWeight: '700', letterSpacing: 0.8 },\n recordBody: { flex: 1, justifyContent: 'center', paddingHorizontal: 16 },\n});\n"],"names":["_b","_a"],"mappings":"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"}
1
+ {"version":3,"file":"DictateExperience.js","sources":["../../../src/features/dictate/DictateExperience.tsx"],"sourcesContent":["/**\n * Dictate: a clinician speaks a visit note; Yantra writes it up as a SOAP note\n * with the points to check before it is used.\n *\n * Record (screen kept awake, paused honestly if the app leaves the screen) ->\n * the recording is kept on the phone at once -> uploaded and handed to\n * YANTRA_MEETINGS_CLINICAL_NOTE (medical speech-to-text, then the note) ->\n * the note is saved on the phone and the recording deleted. A note that could\n * not be written keeps its recording for Retry, across restarts.\n *\n * The host screen passes the session (token + surface index URL); everything\n * else - the recorder, the store, the agent calls - lives here.\n */\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { Alert, BackHandler, Linking, ScrollView, Share, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { useSafeInsets } from '../canvas/withRemoteSafeArea';\nimport { createRemoteConnectorExec, createRemoteUploadMedia } from '../canvas/videoEditor/remoteMediaClient';\nimport { useAppTheme } from '../../theme/AppThemeProvider';\nimport { DIM, Tap } from '../inbox/components/Tap';\nimport { DictationList } from './components/DictationList';\nimport { NoteView } from './components/NoteView';\nimport { RecordingPanel, StartPanel } from './components/RecordPanel';\nimport {\n dictateErrorText,\n suggestErrorText,\n suggestFromNote,\n writeNoteFromRecording,\n type DictateDeps,\n type DictateStage,\n} from './dictateClient';\nimport { readShowIdentifiers, writeShowIdentifiers } from './dictatePreference';\nimport { dictateTheme } from './dictateTheme';\nimport { createDictationStore, type DictationStore } from './dictationStore';\nimport { noteToText } from './noteText';\nimport { labelText } from './privacy';\nimport { shownNote, type SuggestState } from './shownNote';\nimport type { DictationRecord } from './types';\nimport { MicrophoneDeniedError, useDictationRecorder } from './useDictationRecorder';\n\nexport interface DictateExperienceProps {\n isDark?: boolean;\n token?: string | null;\n /** The surface index URL; the agent (uploads, the note) is derived from it. */\n indexUrl: string;\n sessionError?: string | null;\n onRetrySession?: () => void;\n onExit: () => void;\n /** Tests and previews inject these; the app builds them from the session. */\n deps?: DictateDeps;\n store?: DictationStore;\n}\n\ntype Screen = { kind: 'home' } | { kind: 'record' } | { kind: 'note'; id: string };\n\nexport const PREVIEW_NOTICE =\n 'Preview: dictate made-up visits only. Real patient information needs your practice’s HIPAA agreement with Yantra first.';\n\nexport function DictateExperience({\n isDark: hostDark,\n token,\n indexUrl,\n sessionError,\n onRetrySession,\n onExit,\n deps,\n store: injectedStore,\n}: DictateExperienceProps) {\n const appTheme = useAppTheme();\n const theme = useMemo(() => dictateTheme(hostDark ?? appTheme.isDark), [hostDark, appTheme.isDark]);\n const insets = useSafeInsets();\n const store = useMemo(() => injectedStore ?? createDictationStore(), [injectedStore]);\n const recorder = useDictationRecorder();\n const [screen, setScreen] = useState<Screen>({ kind: 'home' });\n const [records, setRecords] = useState<DictationRecord[]>([]);\n const [stages, setStages] = useState<Record<string, DictateStage>>({});\n const [starting, setStarting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [micDenied, setMicDenied] = useState(false);\n const [showIdentifiers, setShowIdentifiers] = useState(false);\n const [suggestStates, setSuggestStates] = useState<Record<string, SuggestState>>({});\n\n useEffect(() => {\n void readShowIdentifiers().then(setShowIdentifiers);\n }, []);\n const toggleIdentifiers = useCallback(() => {\n setShowIdentifiers((show) => {\n writeShowIdentifiers(!show);\n return !show;\n });\n }, []);\n\n const tokenRef = useRef(token);\n tokenRef.current = token;\n const agent = useMemo<DictateDeps>(\n () =>\n deps ?? {\n exec: (connector, action, params, options) => {\n const { current } = tokenRef;\n if (!current) return Promise.reject(new Error('Network request failed: not signed in yet'));\n return createRemoteConnectorExec(current, indexUrl)(connector, action, params, options);\n },\n upload: (uri) => {\n const { current } = tokenRef;\n if (!current) return Promise.reject(new Error('Network request failed: not signed in yet'));\n return createRemoteUploadMedia(current, indexUrl)(uri);\n },\n },\n [deps, indexUrl],\n );\n\n const refresh = useCallback(async () => setRecords(await store.list()), [store]);\n\n // A note being written when the app last closed never finished: offer it again.\n useEffect(() => {\n void (async () => {\n for (const r of await store.list()) {\n if (r.status === 'writing') await store.update(r.id, { status: r.audioUri ? 'saved' : 'failed' });\n }\n await refresh();\n })();\n }, [store, refresh]);\n\n const write = useCallback(\n async (record: DictationRecord) => {\n if (!record.audioUri) return;\n setStages((s) => ({ ...s, [record.id]: 'uploading' }));\n await store.update(record.id, { status: 'writing', error: undefined });\n await refresh();\n try {\n const written = await writeNoteFromRecording(record.audioUri, agent, {}, (stage) =>\n setStages((s) => ({ ...s, [record.id]: stage })),\n );\n await store.update(record.id, {\n status: 'ready',\n note: written.note,\n transcript: written.transcript,\n redaction: written.redaction,\n model: written.model,\n error: undefined,\n });\n await store.dropAudio(record.id);\n } catch (err) {\n await store.update(record.id, { status: 'failed', error: dictateErrorText(err) });\n } finally {\n setStages(({ [record.id]: _done, ...rest }) => rest);\n await refresh();\n }\n },\n [agent, store, refresh],\n );\n\n const suggest = useCallback(\n async (record: DictationRecord) => {\n if (!record.redaction) return;\n setSuggestStates((s) => ({ ...s, [record.id]: { status: 'loading' } }));\n try {\n const { items, identifiers } = await suggestFromNote(record.redaction, agent);\n await store.update(record.id, {\n suggestions: { items, identifiers, createdAt: new Date().toISOString() },\n });\n await refresh();\n setSuggestStates((s) => ({ ...s, [record.id]: { status: 'idle' } }));\n } catch (err) {\n setSuggestStates((s) => ({ ...s, [record.id]: { status: 'error', message: suggestErrorText(err) } }));\n }\n },\n [agent, store, refresh],\n );\n\n const start = useCallback(async () => {\n setError(null);\n setStarting(true);\n try {\n await recorder.start();\n setMicDenied(false);\n setScreen({ kind: 'record' });\n } catch (err) {\n // A declined microphone is not an error to retry: it is a setting, so offer the way there.\n if (err instanceof MicrophoneDeniedError) setMicDenied(true);\n else setError('The microphone could not start. Try again.');\n } finally {\n setStarting(false);\n }\n }, [recorder]);\n\n const done = useCallback(async () => {\n const out = await recorder.finish();\n if (!out) {\n setScreen({ kind: 'home' });\n setError('The recording could not be saved. Try again.');\n return;\n }\n const record = await store.keepRecording(out.uri, out.durationMs);\n await refresh();\n setScreen({ kind: 'note', id: record.id });\n void write(record);\n }, [recorder, store, refresh, write]);\n\n const discard = useCallback(() => {\n Alert.alert('Discard this dictation?', 'The recording is deleted and no note is written.', [\n { text: 'Keep dictating', style: 'cancel' },\n {\n text: 'Discard',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n const out = await recorder.finish();\n if (out) await store.discardRecording(out.uri);\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n }, [recorder, store]);\n\n const back = useCallback(() => {\n if (screen.kind === 'record') {\n if (recorder.phase === 'recording') recorder.pause();\n Alert.alert('Stop dictating?', 'Write the note from what you have recorded, or discard it.', [\n { text: 'Keep dictating', style: 'cancel' },\n {\n text: 'Write the note',\n onPress: () => {\n void done();\n },\n },\n {\n text: 'Discard',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n const out = await recorder.finish();\n if (out) await store.discardRecording(out.uri);\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n return true;\n }\n if (screen.kind === 'note') {\n setScreen({ kind: 'home' });\n return true;\n }\n onExit();\n return true;\n }, [screen.kind, recorder, done, store, onExit]);\n\n useEffect(() => {\n const sub = BackHandler.addEventListener('hardwareBackPress', back);\n return () => sub.remove();\n }, [back]);\n\n const open = screen.kind === 'note' ? (records.find((r) => r.id === screen.id) ?? null) : null;\n\n // What is on screen goes: hidden identifiers stay hidden (\"[Name 1]\"), shown ones go as dictated.\n const share = useCallback(() => {\n if (!open?.note) return;\n const shown = shownNote(open, open.note, showIdentifiers);\n const text = noteToText(shown.note, shown.transcript, shown.suggestions);\n void Share.share({ title: labelText(shown.note.title), message: labelText(text) });\n }, [open, showIdentifiers]);\n\n const remove = useCallback(() => {\n if (!open) return;\n const removed = open.note\n ? 'The note and transcript are removed from this phone.'\n : 'The recording is removed from this phone.';\n Alert.alert('Delete this dictation?', removed, [\n { text: 'Cancel', style: 'cancel' },\n {\n text: 'Delete',\n style: 'destructive',\n onPress: () => {\n void (async () => {\n await store.remove(open.id);\n await refresh();\n setScreen({ kind: 'home' });\n })();\n },\n },\n ]);\n }, [open, store, refresh]);\n\n const title = screen.kind === 'note' ? 'Note' : 'Dictate';\n\n // The note, the live recording, or the home list - whichever screen is open.\n let body: React.ReactNode;\n if (screen.kind === 'note' && open) {\n body = (\n <NoteView\n record={open}\n stage={stages[open.id] ?? null}\n theme={theme}\n bottomInset={insets.bottom}\n onRetry={() => {\n void write(open);\n }}\n showIdentifiers={showIdentifiers}\n onToggleIdentifiers={toggleIdentifiers}\n suggestState={suggestStates[open.id] ?? { status: 'idle' }}\n onSuggest={() => {\n void suggest(open);\n }}\n />\n );\n } else if (screen.kind === 'record' && recorder.phase !== 'idle') {\n body = (\n <View style={styles.recordBody}>\n <RecordingPanel\n theme={theme}\n phase={recorder.phase}\n pauseReason={recorder.pauseReason}\n elapsedMs={recorder.elapsedMs}\n level={recorder.level}\n noInput={recorder.noInput}\n onPause={recorder.pause}\n onResume={recorder.resume}\n onDone={() => {\n void done();\n }}\n onDiscard={discard}\n />\n </View>\n );\n } else {\n body = (\n <ScrollView contentContainerStyle={[styles.home, { paddingBottom: 24 + insets.bottom }]}>\n <Text style={[styles.lead, { color: theme.ink }]}>Dictate a visit</Text>\n <Text style={[styles.leadDetail, { color: theme.muted }]}>\n Speak your note. Yantra writes it up as a SOAP note and lists what to check before you use it.\n </Text>\n <StartPanel\n theme={theme}\n starting={starting}\n recordsInBackground={recorder.recordsInBackground}\n onStart={() => {\n void start();\n }}\n />\n {error ? <Text style={[styles.error, { color: theme.crit }]}>{error}</Text> : null}\n {micDenied ? (\n <View style={[styles.banner, { backgroundColor: theme.recSoft }]}>\n <MaterialCommunityIcons name=\"microphone-off\" size={18} color={theme.crit} />\n <Text style={[styles.bannerText, { color: theme.crit }]}>\n Microphone access is off for Yantra.\n </Text>\n <Tap\n onPress={() => {\n void Linking.openSettings();\n }}\n accessibilityRole=\"button\"\n style={[styles.bannerAction, { backgroundColor: theme.card, borderColor: theme.border }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.bannerActionText, { color: theme.ink }]}>Open Settings</Text>\n </Tap>\n </View>\n ) : null}\n {sessionError ? (\n <Tap\n onPress={onRetrySession}\n accessibilityRole=\"button\"\n style={[styles.banner, { backgroundColor: theme.recSoft }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.bannerText, { color: theme.crit }]}>\n Not connected, so notes cannot be written yet. Tap to retry.\n </Text>\n </Tap>\n ) : null}\n <View\n style={[\n styles.banner,\n {\n backgroundColor: theme.warnSoft,\n borderColor: theme.warnBorder,\n borderWidth: StyleSheet.hairlineWidth,\n },\n ]}\n >\n <MaterialCommunityIcons name=\"shield-alert-outline\" size={18} color={theme.warnInk} />\n <Text style={[styles.bannerText, { color: theme.warnInk }]}>{PREVIEW_NOTICE}</Text>\n </View>\n <Text style={[styles.sectionLabel, { color: theme.muted }]}>RECENT</Text>\n <DictationList records={records} theme={theme} onOpen={(r) => setScreen({ kind: 'note', id: r.id })} />\n </ScrollView>\n );\n }\n\n return (\n <View style={[styles.screen, { backgroundColor: theme.screen, paddingTop: insets.top }]}>\n <View style={[styles.header, { borderBottomColor: theme.border }]}>\n <Tap\n onPress={back}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Back\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"chevron-left\" size={28} color={theme.ink} />\n </Tap>\n <Text style={[styles.headerTitle, { color: theme.ink }]}>{title}</Text>\n <View style={styles.headerActions}>\n {open?.note ? (\n <Tap\n onPress={share}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Share the note\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"export-variant\" size={22} color={theme.ink} />\n </Tap>\n ) : null}\n {/* Any dictation can go, note or not; just not while its note is being written. */}\n {open && !stages[open.id] ? (\n <Tap\n onPress={remove}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Delete\"\n style={styles.headerButton}\n pressedStyle={DIM}\n >\n <MaterialCommunityIcons name=\"trash-can-outline\" size={22} color={theme.ink} />\n </Tap>\n ) : null}\n </View>\n </View>\n\n {body}\n </View>\n );\n}\n\nexport default DictateExperience;\n\nconst styles = StyleSheet.create({\n screen: { flex: 1 },\n header: {\n height: 52,\n flexDirection: 'row',\n alignItems: 'center',\n paddingHorizontal: 4,\n borderBottomWidth: StyleSheet.hairlineWidth,\n },\n headerButton: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center' },\n headerTitle: { flex: 1, fontSize: 17, fontWeight: '600' },\n headerActions: { flexDirection: 'row', alignItems: 'center' },\n home: { paddingHorizontal: 16, paddingTop: 20 },\n lead: { fontSize: 24, fontWeight: '700' },\n leadDetail: { marginTop: 6, fontSize: 15, lineHeight: 21 },\n error: { textAlign: 'center', fontSize: 13, marginBottom: 8 },\n banner: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 10,\n borderRadius: 12,\n paddingHorizontal: 12,\n paddingVertical: 10,\n marginBottom: 12,\n },\n bannerText: { flex: 1, fontSize: 13, lineHeight: 18 },\n bannerAction: {\n paddingHorizontal: 12,\n paddingVertical: 7,\n borderRadius: 999,\n borderWidth: StyleSheet.hairlineWidth,\n },\n bannerActionText: { fontSize: 13, fontWeight: '600' },\n sectionLabel: { marginTop: 12, marginBottom: 8, fontSize: 12, fontWeight: '700', letterSpacing: 0.8 },\n recordBody: { flex: 1, justifyContent: 'center', paddingHorizontal: 16 },\n});\n"],"names":["_b","_a","_c"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import {jsx,jsxs}from'react/jsx-runtime';import {useState,useEffect}from'react';import {View,StyleSheet,Text,ScrollView,ActivityIndicator}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {Tap,DIM}from'../../inbox/components/Tap.js';import {formatDuration,NOTE_DISCLAIMER}from'../noteText.js';const STAGE_TEXT = {
1
+ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useState,useEffect}from'react';import {View,StyleSheet,Text,ScrollView,ActivityIndicator}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {Tap,DIM}from'../../inbox/components/Tap.js';import {formatDuration,NOTE_DISCLAIMER,SUGGESTION_HEADINGS,SUGGESTION_DISCLAIMER}from'../noteText.js';import {splitPlaceholders,placeholderLabel}from'../privacy.js';import {shownNote}from'../shownNote.js';const STAGE_TEXT = {
2
2
  uploading: "Uploading the recording\u2026",
3
3
  writing: "Transcribing and writing the note\u2026"
4
4
  };
@@ -11,6 +11,17 @@ function dictationDate(iso) {
11
11
  minute: "2-digit"
12
12
  });
13
13
  }
14
+ function Redacted({
15
+ text,
16
+ theme
17
+ }) {
18
+ const runs = splitPlaceholders(text);
19
+ if (runs.length === 1 && !runs[0].placeholder) return /* @__PURE__ */ jsx(Fragment, { children: text });
20
+ return /* @__PURE__ */ jsx(Fragment, { children: runs.map((run, i) => run.placeholder ? /* @__PURE__ */ jsx(Text, { style: [styles.placeholder, {
21
+ backgroundColor: theme.chip,
22
+ color: theme.muted
23
+ }], accessibilityLabel: `${placeholderLabel(run.text)}, hidden`, children: `\xA0${placeholderLabel(run.text).replace(/ /g, "\xA0")}\xA0` }, i) : run.text) });
24
+ }
14
25
  function Section({
15
26
  title,
16
27
  items,
@@ -30,10 +41,115 @@ function Section({
30
41
  }] }),
31
42
  /* @__PURE__ */ jsx(Text, { style: [styles.itemText, {
32
43
  color: theme.ink
33
- }], children: item })
44
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: item, theme }) })
34
45
  ] }, i))
35
46
  ] });
36
47
  }
48
+ function PrivacyRow({
49
+ record,
50
+ showIdentifiers,
51
+ onToggle,
52
+ theme
53
+ }) {
54
+ const {
55
+ redaction
56
+ } = record;
57
+ if (!redaction) return null;
58
+ const count = redaction.identifiers.length;
59
+ const what = count === 1 ? "1 name or number" : `${count} names and numbers`;
60
+ const line = count ? `${what} ${showIdentifiers ? "shown here" : "hidden"}. The AI never saw them.` : "No names or numbers were heard. The AI saw the dictation as spoken.";
61
+ return /* @__PURE__ */ jsxs(View, { style: [styles.privacy, {
62
+ backgroundColor: theme.goodSoft
63
+ }], children: [
64
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "shield-lock-outline", size: 18, color: theme.good }),
65
+ /* @__PURE__ */ jsxs(View, { style: styles.privacyText, children: [
66
+ /* @__PURE__ */ jsx(Text, { style: [styles.privacyLine, {
67
+ color: theme.ink
68
+ }], children: line }),
69
+ redaction.method === "patterns" && count ? /* @__PURE__ */ jsx(Text, { style: [styles.privacyNote, {
70
+ color: theme.warnInk
71
+ }], children: "Found without the medical transcriber; check that no name was missed." }) : null
72
+ ] }),
73
+ count ? /* @__PURE__ */ jsx(Tap, { onPress: onToggle, accessibilityRole: "button", accessibilityLabel: showIdentifiers ? "Hide names and numbers" : "Show names and numbers", style: [styles.privacyToggle, {
74
+ borderColor: theme.border,
75
+ backgroundColor: theme.card
76
+ }], pressedStyle: DIM, children: /* @__PURE__ */ jsx(Text, { style: [styles.privacyToggleText, {
77
+ color: theme.ink
78
+ }], children: showIdentifiers ? "Hide" : "Show" }) }) : null
79
+ ] });
80
+ }
81
+ const SUGGESTION_ICON = {
82
+ missing: "text-box-plus-outline",
83
+ safety: "alert-octagon-outline",
84
+ coding: "tag-outline",
85
+ follow_up: "calendar-check-outline"
86
+ };
87
+ function Suggestions({
88
+ items,
89
+ state,
90
+ onSuggest,
91
+ theme
92
+ }) {
93
+ const loading = state.status === "loading";
94
+ let content;
95
+ if (!items) {
96
+ content = /* @__PURE__ */ jsx(Text, { style: [styles.suggestWhy, {
97
+ color: theme.muted
98
+ }], children: "Ask the AI to read the note and point out what to add or check before you sign. It reads the note with names and numbers hidden." });
99
+ } else if (!items.length) {
100
+ content = /* @__PURE__ */ jsx(Text, { style: [styles.suggestWhy, {
101
+ color: theme.muted
102
+ }], children: "Nothing to add: the note covers what the AI would check." });
103
+ } else {
104
+ content = Object.keys(SUGGESTION_HEADINGS).map((kind) => {
105
+ const group = items.filter((s) => s.kind === kind);
106
+ if (!group.length) return null;
107
+ return /* @__PURE__ */ jsxs(View, { style: styles.suggestGroup, children: [
108
+ /* @__PURE__ */ jsxs(View, { style: styles.suggestHead, children: [
109
+ /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: SUGGESTION_ICON[kind], size: 16, color: kind === "safety" ? theme.crit : theme.accent }),
110
+ /* @__PURE__ */ jsx(Text, { style: [styles.suggestKind, {
111
+ color: theme.ink
112
+ }], children: SUGGESTION_HEADINGS[kind] })
113
+ ] }),
114
+ group.map((s, i) => /* @__PURE__ */ jsxs(View, { style: styles.suggestItem, children: [
115
+ /* @__PURE__ */ jsx(Text, { style: [styles.suggestText, {
116
+ color: theme.ink
117
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: s.text, theme }) }),
118
+ s.why ? /* @__PURE__ */ jsx(Text, { style: [styles.suggestWhy, {
119
+ color: theme.muted
120
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: s.why, theme }) }) : null
121
+ ] }, i))
122
+ ] }, kind);
123
+ });
124
+ }
125
+ let buttonLabel = "Get suggestions";
126
+ if (loading) buttonLabel = "Reading the note\u2026";
127
+ else if (items) buttonLabel = "Ask again";
128
+ return /* @__PURE__ */ jsxs(View, { style: [styles.card, {
129
+ backgroundColor: theme.card,
130
+ borderColor: theme.border
131
+ }], children: [
132
+ /* @__PURE__ */ jsx(Text, { style: [styles.heading, {
133
+ color: theme.muted
134
+ }], children: "SUGGESTIONS" }),
135
+ content,
136
+ state.status === "error" ? /* @__PURE__ */ jsx(Text, { style: [styles.suggestError, {
137
+ color: theme.crit
138
+ }], children: state.message }) : null,
139
+ /* @__PURE__ */ jsxs(Tap, { onPress: onSuggest, disabled: loading, accessibilityRole: "button", accessibilityLabel: items ? "Ask for suggestions again" : "Get suggestions", style: [styles.suggestButton, {
140
+ borderColor: theme.accent,
141
+ opacity: loading ? 0.6 : 1
142
+ }], pressedStyle: DIM, children: [
143
+ loading ? /* @__PURE__ */ jsx(ActivityIndicator, { color: theme.accent, size: "small" }) : /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "lightbulb-on-outline", size: 18, color: theme.accent }),
144
+ /* @__PURE__ */ jsx(Text, { style: [styles.suggestButtonText, {
145
+ color: theme.accent
146
+ }], children: buttonLabel })
147
+ ] }),
148
+ (items == null ? void 0 : items.length) ? /* @__PURE__ */ jsx(Text, { style: [styles.suggestFoot, {
149
+ color: theme.faint
150
+ }], children: SUGGESTION_DISCLAIMER }) : null
151
+ ] });
152
+ }
37
153
  function actionTone(action, theme) {
38
154
  if (action === "start") return {
39
155
  bg: theme.goodSoft,
@@ -74,10 +190,10 @@ function Medications({
74
190
  /* @__PURE__ */ jsxs(View, { style: styles.medText, children: [
75
191
  /* @__PURE__ */ jsx(Text, { style: [styles.medName, {
76
192
  color: theme.ink
77
- }], children: med.name }),
193
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: med.name, theme }) }),
78
194
  /* @__PURE__ */ jsx(Text, { style: [styles.medDetail, {
79
195
  color: detail ? theme.muted : theme.warnInk
80
- }], children: detail || "No dose or frequency dictated" })
196
+ }], children: detail ? /* @__PURE__ */ jsx(Redacted, { text: detail, theme }) : "No dose or frequency dictated" })
81
197
  ] }),
82
198
  /* @__PURE__ */ jsx(View, { style: [styles.pill, {
83
199
  backgroundColor: tone.bg
@@ -115,7 +231,11 @@ function NoteView({
115
231
  stage,
116
232
  theme,
117
233
  bottomInset,
118
- onRetry
234
+ onRetry,
235
+ showIdentifiers,
236
+ onToggleIdentifiers,
237
+ suggestState,
238
+ onSuggest
119
239
  }) {
120
240
  var _a;
121
241
  const [showTranscript, setShowTranscript] = useState(false);
@@ -140,17 +260,20 @@ function NoteView({
140
260
  ] });
141
261
  }
142
262
  const {
143
- note
144
- } = record;
263
+ note,
264
+ transcript,
265
+ suggestions
266
+ } = shownNote(record, record.note, showIdentifiers);
145
267
  return /* @__PURE__ */ jsxs(ScrollView, { contentContainerStyle: [styles.scroll, {
146
268
  paddingBottom: 24 + bottomInset
147
269
  }], children: [
148
270
  /* @__PURE__ */ jsx(Text, { style: [styles.title, {
149
271
  color: theme.ink
150
- }], children: note.title }),
272
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: note.title, theme }) }),
151
273
  /* @__PURE__ */ jsx(Text, { style: [styles.meta, {
152
274
  color: theme.faint
153
275
  }], children: meta }),
276
+ /* @__PURE__ */ jsx(PrivacyRow, { record, showIdentifiers, onToggle: onToggleIdentifiers, theme }),
154
277
  note.to_verify.length ? /* @__PURE__ */ jsxs(View, { style: [styles.verify, {
155
278
  backgroundColor: theme.warnSoft,
156
279
  borderColor: theme.warnBorder
@@ -161,9 +284,12 @@ function NoteView({
161
284
  color: theme.warnInk
162
285
  }], children: "Check before you use" })
163
286
  ] }),
164
- note.to_verify.map((item, i) => /* @__PURE__ */ jsx(Text, { style: [styles.verifyItem, {
287
+ note.to_verify.map((item, i) => /* @__PURE__ */ jsxs(Text, { style: [styles.verifyItem, {
165
288
  color: theme.warnInk
166
- }], children: `\u2022 ${item}` }, i))
289
+ }], children: [
290
+ "\u2022 ",
291
+ /* @__PURE__ */ jsx(Redacted, { text: item, theme })
292
+ ] }, i))
167
293
  ] }) : null,
168
294
  /* @__PURE__ */ jsx(Section, { title: "SUBJECTIVE", items: note.subjective, theme }),
169
295
  /* @__PURE__ */ jsx(Section, { title: "OBJECTIVE", items: note.objective, theme }),
@@ -171,7 +297,8 @@ function NoteView({
171
297
  /* @__PURE__ */ jsx(Section, { title: "PLAN", items: note.plan, theme }),
172
298
  /* @__PURE__ */ jsx(Medications, { meds: note.medications, theme }),
173
299
  note.follow_up ? /* @__PURE__ */ jsx(Section, { title: "FOLLOW-UP", items: [note.follow_up], theme }) : null,
174
- record.transcript ? /* @__PURE__ */ jsxs(View, { style: [styles.card, {
300
+ record.redaction ? /* @__PURE__ */ jsx(Suggestions, { items: suggestions, state: suggestState, onSuggest, theme }) : null,
301
+ transcript ? /* @__PURE__ */ jsxs(View, { style: [styles.card, {
175
302
  backgroundColor: theme.card,
176
303
  borderColor: theme.border
177
304
  }], children: [
@@ -183,7 +310,7 @@ function NoteView({
183
310
  ] }),
184
311
  showTranscript ? /* @__PURE__ */ jsx(Text, { style: [styles.transcript, {
185
312
  color: theme.ink
186
- }], children: record.transcript }) : null
313
+ }], children: /* @__PURE__ */ jsx(Redacted, { text: transcript, theme }) }) : null
187
314
  ] }) : null,
188
315
  /* @__PURE__ */ jsx(Text, { style: [styles.disclaimer, {
189
316
  color: theme.faint
@@ -301,6 +428,94 @@ const styles = StyleSheet.create({
301
428
  fontSize: 12,
302
429
  textAlign: "center"
303
430
  },
431
+ placeholder: {
432
+ fontSize: 13,
433
+ fontWeight: "600",
434
+ borderRadius: 4,
435
+ overflow: "hidden"
436
+ },
437
+ privacy: {
438
+ marginTop: 12,
439
+ borderRadius: 12,
440
+ paddingHorizontal: 12,
441
+ paddingVertical: 10,
442
+ flexDirection: "row",
443
+ alignItems: "center",
444
+ gap: 10
445
+ },
446
+ privacyText: {
447
+ flex: 1
448
+ },
449
+ privacyLine: {
450
+ fontSize: 13,
451
+ lineHeight: 18
452
+ },
453
+ privacyNote: {
454
+ marginTop: 2,
455
+ fontSize: 12,
456
+ lineHeight: 17
457
+ },
458
+ privacyToggle: {
459
+ paddingHorizontal: 14,
460
+ paddingVertical: 6,
461
+ borderRadius: 999,
462
+ borderWidth: StyleSheet.hairlineWidth
463
+ },
464
+ privacyToggleText: {
465
+ fontSize: 13,
466
+ fontWeight: "600"
467
+ },
468
+ suggestGroup: {
469
+ marginTop: 8
470
+ },
471
+ suggestHead: {
472
+ flexDirection: "row",
473
+ alignItems: "center",
474
+ gap: 6,
475
+ marginBottom: 2
476
+ },
477
+ suggestKind: {
478
+ fontSize: 14,
479
+ fontWeight: "700"
480
+ },
481
+ suggestItem: {
482
+ marginTop: 6,
483
+ paddingLeft: 22
484
+ },
485
+ suggestText: {
486
+ fontSize: 15,
487
+ lineHeight: 21
488
+ },
489
+ suggestWhy: {
490
+ marginTop: 2,
491
+ fontSize: 13,
492
+ lineHeight: 18
493
+ },
494
+ suggestError: {
495
+ marginTop: 10,
496
+ fontSize: 13,
497
+ lineHeight: 18
498
+ },
499
+ suggestButton: {
500
+ marginTop: 12,
501
+ flexDirection: "row",
502
+ alignItems: "center",
503
+ justifyContent: "center",
504
+ gap: 8,
505
+ paddingVertical: 10,
506
+ borderRadius: 999,
507
+ borderWidth: 1
508
+ },
509
+ suggestButtonText: {
510
+ fontSize: 15,
511
+ fontWeight: "600"
512
+ },
513
+ suggestFoot: {
514
+ marginTop: 10,
515
+ fontSize: 12,
516
+ lineHeight: 17,
517
+ textAlign: "center"
518
+ },
304
519
  center: {
305
520
  flex: 1,
306
521
  alignItems: "center",
@@ -1 +1 @@
1
- {"version":3,"file":"NoteView.js","sources":["../../../../src/features/dictate/components/NoteView.tsx"],"sourcesContent":["/**\n * A dictation's note: what to check first (amber, above everything), the four\n * SOAP sections, the medications with what was dictated for each, follow-up,\n * and the transcript behind a toggle. While the note is being written this\n * shows the stage; when writing failed, why and a Retry that reuses the saved\n * recording.\n */\nimport React, { useEffect, useState } from 'react';\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { DIM, Tap } from '../../inbox/components/Tap';\nimport { formatDuration, NOTE_DISCLAIMER } from '../noteText';\nimport type { DictateStage } from '../dictateClient';\nimport type { DictateTheme } from '../dictateTheme';\nimport type { DictationRecord, NoteMedication } from '../types';\n\nconst STAGE_TEXT: Record<DictateStage, string> = {\n uploading: 'Uploading the recording…',\n writing: 'Transcribing and writing the note…',\n};\n\nexport function dictationDate(iso: string): string {\n const d = new Date(iso);\n return Number.isNaN(d.getTime())\n ? ''\n : d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n}\n\nfunction Section({ title, items, theme }: { title: string; items: string[]; theme: DictateTheme }) {\n if (!items.length) return null;\n return (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Text style={[styles.heading, { color: theme.muted }]}>{title}</Text>\n {items.map((item, i) => (\n <View key={i} style={styles.item}>\n <View style={[styles.bullet, { backgroundColor: theme.faint }]} />\n <Text style={[styles.itemText, { color: theme.ink }]}>{item}</Text>\n </View>\n ))}\n </View>\n );\n}\n\nfunction actionTone(action: NoteMedication['action'], theme: DictateTheme): { bg: string; ink: string } {\n if (action === 'start') return { bg: theme.goodSoft, ink: theme.good };\n if (action === 'change') return { bg: theme.accentSoft, ink: theme.accent };\n if (action === 'stop') return { bg: theme.recSoft, ink: theme.crit };\n return { bg: theme.chip, ink: theme.muted };\n}\n\nfunction Medications({ meds, theme }: { meds: NoteMedication[]; theme: DictateTheme }) {\n if (!meds.length) return null;\n return (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Text style={[styles.heading, { color: theme.muted }]}>MEDICATIONS</Text>\n {meds.map((med, i) => {\n const tone = actionTone(med.action, theme);\n const detail = [med.dose, med.route, med.frequency].filter(Boolean).join(' · ');\n return (\n <View\n key={`${med.name}-${i}`}\n style={[\n styles.med,\n i > 0 && { borderTopColor: theme.border, borderTopWidth: StyleSheet.hairlineWidth },\n ]}\n >\n <View style={styles.medText}>\n <Text style={[styles.medName, { color: theme.ink }]}>{med.name}</Text>\n <Text style={[styles.medDetail, { color: detail ? theme.muted : theme.warnInk }]}>\n {detail || 'No dose or frequency dictated'}\n </Text>\n </View>\n <View style={[styles.pill, { backgroundColor: tone.bg }]}>\n <Text style={[styles.pillText, { color: tone.ink }]}>{med.action}</Text>\n </View>\n </View>\n );\n })}\n </View>\n );\n}\n\nfunction Writing({ stage, theme }: { stage: DictateStage; theme: DictateTheme }) {\n const [seconds, setSeconds] = useState(0);\n useEffect(() => {\n const id = setInterval(() => setSeconds((s) => s + 1), 1000);\n return () => clearInterval(id);\n }, []);\n return (\n <View style={styles.center}>\n <ActivityIndicator color={theme.accent} />\n <Text style={[styles.centerTitle, { color: theme.ink }]}>{STAGE_TEXT[stage]}</Text>\n <Text style={[styles.centerDetail, { color: theme.faint }]}>{seconds}s · usually under a minute</Text>\n </View>\n );\n}\n\nexport function NoteView({\n record,\n stage,\n theme,\n bottomInset,\n onRetry,\n}: {\n record: DictationRecord;\n stage: DictateStage | null;\n theme: DictateTheme;\n bottomInset: number;\n onRetry: () => void;\n}) {\n const [showTranscript, setShowTranscript] = useState(false);\n const meta = [dictationDate(record.createdAt), formatDuration(record.durationMs)].filter(Boolean).join(' · ');\n\n if (record.status === 'writing' || (record.status === 'saved' && stage)) {\n return <Writing stage={stage ?? 'writing'} theme={theme} />;\n }\n if (!record.note) {\n return (\n <View style={styles.center}>\n <MaterialCommunityIcons name=\"alert-circle-outline\" size={28} color={theme.crit} />\n <Text style={[styles.centerTitle, { color: theme.ink }]}>No note yet</Text>\n <Text style={[styles.centerDetail, { color: theme.muted }]}>\n {record.error ?? 'The recording is saved on this phone.'}\n </Text>\n {record.audioUri ? (\n <Tap\n onPress={onRetry}\n accessibilityRole=\"button\"\n style={[styles.retry, { backgroundColor: theme.accent }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.retryText, { color: theme.accentInk }]}>Write the note</Text>\n </Tap>\n ) : null}\n </View>\n );\n }\n\n const { note } = record;\n return (\n <ScrollView contentContainerStyle={[styles.scroll, { paddingBottom: 24 + bottomInset }]}>\n <Text style={[styles.title, { color: theme.ink }]}>{note.title}</Text>\n <Text style={[styles.meta, { color: theme.faint }]}>{meta}</Text>\n\n {note.to_verify.length ? (\n <View style={[styles.verify, { backgroundColor: theme.warnSoft, borderColor: theme.warnBorder }]}>\n <View style={styles.verifyHead}>\n <MaterialCommunityIcons name=\"alert-outline\" size={18} color={theme.warnInk} />\n <Text style={[styles.verifyTitle, { color: theme.warnInk }]}>Check before you use</Text>\n </View>\n {note.to_verify.map((item, i) => (\n <Text key={i} style={[styles.verifyItem, { color: theme.warnInk }]}>\n {`• ${item}`}\n </Text>\n ))}\n </View>\n ) : null}\n\n <Section title=\"SUBJECTIVE\" items={note.subjective} theme={theme} />\n <Section title=\"OBJECTIVE\" items={note.objective} theme={theme} />\n <Section title=\"ASSESSMENT\" items={note.assessment} theme={theme} />\n <Section title=\"PLAN\" items={note.plan} theme={theme} />\n <Medications meds={note.medications} theme={theme} />\n {note.follow_up ? <Section title=\"FOLLOW-UP\" items={[note.follow_up]} theme={theme} /> : null}\n\n {record.transcript ? (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Tap\n onPress={() => setShowTranscript((v) => !v)}\n accessibilityRole=\"button\"\n style={styles.transcriptToggle}\n pressedStyle={DIM}\n >\n <Text style={[styles.heading, styles.headingFlat, { color: theme.muted }]}>TRANSCRIPT</Text>\n <MaterialCommunityIcons\n name={showTranscript ? 'chevron-up' : 'chevron-down'}\n size={20}\n color={theme.muted}\n />\n </Tap>\n {showTranscript ? (\n <Text style={[styles.transcript, { color: theme.ink }]}>{record.transcript}</Text>\n ) : null}\n </View>\n ) : null}\n\n <Text style={[styles.disclaimer, { color: theme.faint }]}>{NOTE_DISCLAIMER}</Text>\n </ScrollView>\n );\n}\n\nconst styles = StyleSheet.create({\n scroll: { paddingHorizontal: 16, paddingTop: 8 },\n title: { fontSize: 21, fontWeight: '700', lineHeight: 27 },\n meta: { marginTop: 4, fontSize: 13 },\n verify: { marginTop: 16, borderRadius: 14, borderWidth: StyleSheet.hairlineWidth, padding: 14 },\n verifyHead: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 6 },\n verifyTitle: { fontSize: 14, fontWeight: '700' },\n verifyItem: { fontSize: 14, lineHeight: 20, marginTop: 4 },\n card: {\n marginTop: 12,\n borderRadius: 14,\n borderWidth: StyleSheet.hairlineWidth,\n paddingHorizontal: 14,\n paddingVertical: 12,\n },\n heading: { fontSize: 12, fontWeight: '700', letterSpacing: 0.8, marginBottom: 6 },\n headingFlat: { marginBottom: 0 },\n item: { flexDirection: 'row', alignItems: 'flex-start', marginTop: 6 },\n bullet: { width: 5, height: 5, borderRadius: 2.5, marginTop: 8, marginRight: 10 },\n itemText: { flex: 1, fontSize: 15, lineHeight: 21 },\n med: { flexDirection: 'row', alignItems: 'center', paddingVertical: 10 },\n medText: { flex: 1, paddingRight: 10 },\n medName: { fontSize: 15, fontWeight: '600', textTransform: 'capitalize' },\n medDetail: { marginTop: 2, fontSize: 13 },\n pill: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 999 },\n pillText: { fontSize: 12, fontWeight: '600', textTransform: 'capitalize' },\n transcriptToggle: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' },\n transcript: { marginTop: 10, fontSize: 14, lineHeight: 21 },\n disclaimer: { marginTop: 18, fontSize: 12, textAlign: 'center' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32 },\n centerTitle: { marginTop: 14, fontSize: 16, fontWeight: '600', textAlign: 'center' },\n centerDetail: { marginTop: 6, fontSize: 13, lineHeight: 19, textAlign: 'center' },\n retry: { marginTop: 18, paddingHorizontal: 20, paddingVertical: 12, borderRadius: 999 },\n retryText: { fontSize: 15, fontWeight: '600' },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NoteView.js","sources":["../../../../src/features/dictate/components/NoteView.tsx"],"sourcesContent":["/**\n * A dictation's note: what to check first (amber, above everything), the four\n * SOAP sections, the medications with what was dictated for each, follow-up,\n * the AI's suggestions on demand, and the transcript behind a toggle. While\n * the note is being written this shows the stage; when writing failed, why and\n * a Retry that reuses the saved recording.\n *\n * A note written with its identifiers hidden from the AI shows them hidden\n * (\"Name 1\") or put back, as the clinician chooses; the suggestions are asked\n * for with the hidden version only.\n */\nimport React, { useEffect, useState } from 'react';\nimport { ActivityIndicator, ScrollView, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { DIM, Tap } from '../../inbox/components/Tap';\nimport { formatDuration, NOTE_DISCLAIMER, SUGGESTION_DISCLAIMER, SUGGESTION_HEADINGS } from '../noteText';\nimport { placeholderLabel, splitPlaceholders } from '../privacy';\nimport type { DictateStage } from '../dictateClient';\nimport type { DictateTheme } from '../dictateTheme';\nimport type { DictationRecord, NoteMedication, NoteSuggestion, SuggestionKind } from '../types';\nimport { shownNote, type SuggestState } from '../shownNote';\n\nconst STAGE_TEXT: Record<DictateStage, string> = {\n uploading: 'Uploading the recording…',\n writing: 'Transcribing and writing the note…',\n};\n\nexport function dictationDate(iso: string): string {\n const d = new Date(iso);\n return Number.isNaN(d.getTime())\n ? ''\n : d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n}\n\n/** Text with each hidden identifier drawn as a small label (\"Name 1\"), so it reads as a gap, not a code. */\nfunction Redacted({ text, theme }: { text: string; theme: DictateTheme }) {\n const runs = splitPlaceholders(text);\n if (runs.length === 1 && !runs[0].placeholder) return <>{text}</>;\n return (\n <>\n {runs.map((run, i) =>\n run.placeholder ? (\n <Text\n key={i}\n style={[styles.placeholder, { backgroundColor: theme.chip, color: theme.muted }]}\n accessibilityLabel={`${placeholderLabel(run.text)}, hidden`}\n >\n {/* Non-breaking: a label wraps whole, never leaving a shaded gap at a line end. */}\n {`\\u00A0${placeholderLabel(run.text).replace(/ /g, '\\u00A0')}\\u00A0`}\n </Text>\n ) : (\n run.text\n ),\n )}\n </>\n );\n}\n\nfunction Section({ title, items, theme }: { title: string; items: string[]; theme: DictateTheme }) {\n if (!items.length) return null;\n return (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Text style={[styles.heading, { color: theme.muted }]}>{title}</Text>\n {items.map((item, i) => (\n <View key={i} style={styles.item}>\n <View style={[styles.bullet, { backgroundColor: theme.faint }]} />\n <Text style={[styles.itemText, { color: theme.ink }]}>\n <Redacted text={item} theme={theme} />\n </Text>\n </View>\n ))}\n </View>\n );\n}\n\n/** What the AI saw, and the switch between hidden and put back. */\nfunction PrivacyRow({\n record,\n showIdentifiers,\n onToggle,\n theme,\n}: {\n record: DictationRecord;\n showIdentifiers: boolean;\n onToggle: () => void;\n theme: DictateTheme;\n}) {\n const { redaction } = record;\n if (!redaction) return null;\n const count = redaction.identifiers.length;\n const what = count === 1 ? '1 name or number' : `${count} names and numbers`;\n const line = count\n ? `${what} ${showIdentifiers ? 'shown here' : 'hidden'}. The AI never saw them.`\n : 'No names or numbers were heard. The AI saw the dictation as spoken.';\n return (\n <View style={[styles.privacy, { backgroundColor: theme.goodSoft }]}>\n <MaterialCommunityIcons name=\"shield-lock-outline\" size={18} color={theme.good} />\n <View style={styles.privacyText}>\n <Text style={[styles.privacyLine, { color: theme.ink }]}>{line}</Text>\n {redaction.method === 'patterns' && count ? (\n <Text style={[styles.privacyNote, { color: theme.warnInk }]}>\n Found without the medical transcriber; check that no name was missed.\n </Text>\n ) : null}\n </View>\n {count ? (\n <Tap\n onPress={onToggle}\n accessibilityRole=\"button\"\n accessibilityLabel={showIdentifiers ? 'Hide names and numbers' : 'Show names and numbers'}\n style={[styles.privacyToggle, { borderColor: theme.border, backgroundColor: theme.card }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.privacyToggleText, { color: theme.ink }]}>\n {showIdentifiers ? 'Hide' : 'Show'}\n </Text>\n </Tap>\n ) : null}\n </View>\n );\n}\n\nconst SUGGESTION_ICON: Record<SuggestionKind, React.ComponentProps<typeof MaterialCommunityIcons>['name']> = {\n missing: 'text-box-plus-outline',\n safety: 'alert-octagon-outline',\n coding: 'tag-outline',\n follow_up: 'calendar-check-outline',\n};\n\n/** The AI's read of the note, on demand: grouped by kind, each with why. */\nfunction Suggestions({\n items,\n state,\n onSuggest,\n theme,\n}: {\n items: NoteSuggestion[] | null;\n state: SuggestState;\n onSuggest: () => void;\n theme: DictateTheme;\n}) {\n const loading = state.status === 'loading';\n let content: React.ReactNode;\n if (!items) {\n content = (\n <Text style={[styles.suggestWhy, { color: theme.muted }]}>\n Ask the AI to read the note and point out what to add or check before you sign. It reads the note with\n names and numbers hidden.\n </Text>\n );\n } else if (!items.length) {\n content = (\n <Text style={[styles.suggestWhy, { color: theme.muted }]}>\n Nothing to add: the note covers what the AI would check.\n </Text>\n );\n } else {\n content = (Object.keys(SUGGESTION_HEADINGS) as SuggestionKind[]).map((kind) => {\n const group = items.filter((s) => s.kind === kind);\n if (!group.length) return null;\n return (\n <View key={kind} style={styles.suggestGroup}>\n <View style={styles.suggestHead}>\n <MaterialCommunityIcons\n name={SUGGESTION_ICON[kind]}\n size={16}\n color={kind === 'safety' ? theme.crit : theme.accent}\n />\n <Text style={[styles.suggestKind, { color: theme.ink }]}>{SUGGESTION_HEADINGS[kind]}</Text>\n </View>\n {group.map((s, i) => (\n <View key={i} style={styles.suggestItem}>\n <Text style={[styles.suggestText, { color: theme.ink }]}>\n <Redacted text={s.text} theme={theme} />\n </Text>\n {s.why ? (\n <Text style={[styles.suggestWhy, { color: theme.muted }]}>\n <Redacted text={s.why} theme={theme} />\n </Text>\n ) : null}\n </View>\n ))}\n </View>\n );\n });\n }\n let buttonLabel = 'Get suggestions';\n if (loading) buttonLabel = 'Reading the note…';\n else if (items) buttonLabel = 'Ask again';\n return (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Text style={[styles.heading, { color: theme.muted }]}>SUGGESTIONS</Text>\n {content}\n {state.status === 'error' ? (\n <Text style={[styles.suggestError, { color: theme.crit }]}>{state.message}</Text>\n ) : null}\n <Tap\n onPress={onSuggest}\n disabled={loading}\n accessibilityRole=\"button\"\n accessibilityLabel={items ? 'Ask for suggestions again' : 'Get suggestions'}\n style={[styles.suggestButton, { borderColor: theme.accent, opacity: loading ? 0.6 : 1 }]}\n pressedStyle={DIM}\n >\n {loading ? (\n <ActivityIndicator color={theme.accent} size=\"small\" />\n ) : (\n <MaterialCommunityIcons name=\"lightbulb-on-outline\" size={18} color={theme.accent} />\n )}\n <Text style={[styles.suggestButtonText, { color: theme.accent }]}>{buttonLabel}</Text>\n </Tap>\n {items?.length ? (\n <Text style={[styles.suggestFoot, { color: theme.faint }]}>{SUGGESTION_DISCLAIMER}</Text>\n ) : null}\n </View>\n );\n}\n\nfunction actionTone(action: NoteMedication['action'], theme: DictateTheme): { bg: string; ink: string } {\n if (action === 'start') return { bg: theme.goodSoft, ink: theme.good };\n if (action === 'change') return { bg: theme.accentSoft, ink: theme.accent };\n if (action === 'stop') return { bg: theme.recSoft, ink: theme.crit };\n return { bg: theme.chip, ink: theme.muted };\n}\n\nfunction Medications({ meds, theme }: { meds: NoteMedication[]; theme: DictateTheme }) {\n if (!meds.length) return null;\n return (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Text style={[styles.heading, { color: theme.muted }]}>MEDICATIONS</Text>\n {meds.map((med, i) => {\n const tone = actionTone(med.action, theme);\n const detail = [med.dose, med.route, med.frequency].filter(Boolean).join(' · ');\n return (\n <View\n key={`${med.name}-${i}`}\n style={[\n styles.med,\n i > 0 && { borderTopColor: theme.border, borderTopWidth: StyleSheet.hairlineWidth },\n ]}\n >\n <View style={styles.medText}>\n <Text style={[styles.medName, { color: theme.ink }]}>\n <Redacted text={med.name} theme={theme} />\n </Text>\n <Text style={[styles.medDetail, { color: detail ? theme.muted : theme.warnInk }]}>\n {detail ? <Redacted text={detail} theme={theme} /> : 'No dose or frequency dictated'}\n </Text>\n </View>\n <View style={[styles.pill, { backgroundColor: tone.bg }]}>\n <Text style={[styles.pillText, { color: tone.ink }]}>{med.action}</Text>\n </View>\n </View>\n );\n })}\n </View>\n );\n}\n\nfunction Writing({ stage, theme }: { stage: DictateStage; theme: DictateTheme }) {\n const [seconds, setSeconds] = useState(0);\n useEffect(() => {\n const id = setInterval(() => setSeconds((s) => s + 1), 1000);\n return () => clearInterval(id);\n }, []);\n return (\n <View style={styles.center}>\n <ActivityIndicator color={theme.accent} />\n <Text style={[styles.centerTitle, { color: theme.ink }]}>{STAGE_TEXT[stage]}</Text>\n <Text style={[styles.centerDetail, { color: theme.faint }]}>{seconds}s · usually under a minute</Text>\n </View>\n );\n}\n\nexport function NoteView({\n record,\n stage,\n theme,\n bottomInset,\n onRetry,\n showIdentifiers,\n onToggleIdentifiers,\n suggestState,\n onSuggest,\n}: {\n record: DictationRecord;\n stage: DictateStage | null;\n theme: DictateTheme;\n bottomInset: number;\n onRetry: () => void;\n showIdentifiers: boolean;\n onToggleIdentifiers: () => void;\n suggestState: SuggestState;\n onSuggest: () => void;\n}) {\n const [showTranscript, setShowTranscript] = useState(false);\n const meta = [dictationDate(record.createdAt), formatDuration(record.durationMs)].filter(Boolean).join(' · ');\n\n if (record.status === 'writing' || (record.status === 'saved' && stage)) {\n return <Writing stage={stage ?? 'writing'} theme={theme} />;\n }\n if (!record.note) {\n return (\n <View style={styles.center}>\n <MaterialCommunityIcons name=\"alert-circle-outline\" size={28} color={theme.crit} />\n <Text style={[styles.centerTitle, { color: theme.ink }]}>No note yet</Text>\n <Text style={[styles.centerDetail, { color: theme.muted }]}>\n {record.error ?? 'The recording is saved on this phone.'}\n </Text>\n {record.audioUri ? (\n <Tap\n onPress={onRetry}\n accessibilityRole=\"button\"\n style={[styles.retry, { backgroundColor: theme.accent }]}\n pressedStyle={DIM}\n >\n <Text style={[styles.retryText, { color: theme.accentInk }]}>Write the note</Text>\n </Tap>\n ) : null}\n </View>\n );\n }\n\n const { note, transcript, suggestions } = shownNote(record, record.note, showIdentifiers);\n return (\n <ScrollView contentContainerStyle={[styles.scroll, { paddingBottom: 24 + bottomInset }]}>\n <Text style={[styles.title, { color: theme.ink }]}>\n <Redacted text={note.title} theme={theme} />\n </Text>\n <Text style={[styles.meta, { color: theme.faint }]}>{meta}</Text>\n <PrivacyRow\n record={record}\n showIdentifiers={showIdentifiers}\n onToggle={onToggleIdentifiers}\n theme={theme}\n />\n\n {note.to_verify.length ? (\n <View style={[styles.verify, { backgroundColor: theme.warnSoft, borderColor: theme.warnBorder }]}>\n <View style={styles.verifyHead}>\n <MaterialCommunityIcons name=\"alert-outline\" size={18} color={theme.warnInk} />\n <Text style={[styles.verifyTitle, { color: theme.warnInk }]}>Check before you use</Text>\n </View>\n {note.to_verify.map((item, i) => (\n <Text key={i} style={[styles.verifyItem, { color: theme.warnInk }]}>\n {'• '}\n <Redacted text={item} theme={theme} />\n </Text>\n ))}\n </View>\n ) : null}\n\n <Section title=\"SUBJECTIVE\" items={note.subjective} theme={theme} />\n <Section title=\"OBJECTIVE\" items={note.objective} theme={theme} />\n <Section title=\"ASSESSMENT\" items={note.assessment} theme={theme} />\n <Section title=\"PLAN\" items={note.plan} theme={theme} />\n <Medications meds={note.medications} theme={theme} />\n {note.follow_up ? <Section title=\"FOLLOW-UP\" items={[note.follow_up]} theme={theme} /> : null}\n\n {/* Only a note whose identifiers were hidden from the AI goes back to it. */}\n {record.redaction ? (\n <Suggestions items={suggestions} state={suggestState} onSuggest={onSuggest} theme={theme} />\n ) : null}\n\n {transcript ? (\n <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>\n <Tap\n onPress={() => setShowTranscript((v) => !v)}\n accessibilityRole=\"button\"\n style={styles.transcriptToggle}\n pressedStyle={DIM}\n >\n <Text style={[styles.heading, styles.headingFlat, { color: theme.muted }]}>TRANSCRIPT</Text>\n <MaterialCommunityIcons\n name={showTranscript ? 'chevron-up' : 'chevron-down'}\n size={20}\n color={theme.muted}\n />\n </Tap>\n {showTranscript ? (\n <Text style={[styles.transcript, { color: theme.ink }]}>\n <Redacted text={transcript} theme={theme} />\n </Text>\n ) : null}\n </View>\n ) : null}\n\n <Text style={[styles.disclaimer, { color: theme.faint }]}>{NOTE_DISCLAIMER}</Text>\n </ScrollView>\n );\n}\n\nconst styles = StyleSheet.create({\n scroll: { paddingHorizontal: 16, paddingTop: 8 },\n title: { fontSize: 21, fontWeight: '700', lineHeight: 27 },\n meta: { marginTop: 4, fontSize: 13 },\n verify: { marginTop: 16, borderRadius: 14, borderWidth: StyleSheet.hairlineWidth, padding: 14 },\n verifyHead: { flexDirection: 'row', alignItems: 'center', gap: 8, marginBottom: 6 },\n verifyTitle: { fontSize: 14, fontWeight: '700' },\n verifyItem: { fontSize: 14, lineHeight: 20, marginTop: 4 },\n card: {\n marginTop: 12,\n borderRadius: 14,\n borderWidth: StyleSheet.hairlineWidth,\n paddingHorizontal: 14,\n paddingVertical: 12,\n },\n heading: { fontSize: 12, fontWeight: '700', letterSpacing: 0.8, marginBottom: 6 },\n headingFlat: { marginBottom: 0 },\n item: { flexDirection: 'row', alignItems: 'flex-start', marginTop: 6 },\n bullet: { width: 5, height: 5, borderRadius: 2.5, marginTop: 8, marginRight: 10 },\n itemText: { flex: 1, fontSize: 15, lineHeight: 21 },\n med: { flexDirection: 'row', alignItems: 'center', paddingVertical: 10 },\n medText: { flex: 1, paddingRight: 10 },\n medName: { fontSize: 15, fontWeight: '600', textTransform: 'capitalize' },\n medDetail: { marginTop: 2, fontSize: 13 },\n pill: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 999 },\n pillText: { fontSize: 12, fontWeight: '600', textTransform: 'capitalize' },\n transcriptToggle: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' },\n transcript: { marginTop: 10, fontSize: 14, lineHeight: 21 },\n disclaimer: { marginTop: 18, fontSize: 12, textAlign: 'center' },\n placeholder: { fontSize: 13, fontWeight: '600', borderRadius: 4, overflow: 'hidden' },\n privacy: {\n marginTop: 12,\n borderRadius: 12,\n paddingHorizontal: 12,\n paddingVertical: 10,\n flexDirection: 'row',\n alignItems: 'center',\n gap: 10,\n },\n privacyText: { flex: 1 },\n privacyLine: { fontSize: 13, lineHeight: 18 },\n privacyNote: { marginTop: 2, fontSize: 12, lineHeight: 17 },\n privacyToggle: {\n paddingHorizontal: 14,\n paddingVertical: 6,\n borderRadius: 999,\n borderWidth: StyleSheet.hairlineWidth,\n },\n privacyToggleText: { fontSize: 13, fontWeight: '600' },\n suggestGroup: { marginTop: 8 },\n suggestHead: { flexDirection: 'row', alignItems: 'center', gap: 6, marginBottom: 2 },\n suggestKind: { fontSize: 14, fontWeight: '700' },\n suggestItem: { marginTop: 6, paddingLeft: 22 },\n suggestText: { fontSize: 15, lineHeight: 21 },\n suggestWhy: { marginTop: 2, fontSize: 13, lineHeight: 18 },\n suggestError: { marginTop: 10, fontSize: 13, lineHeight: 18 },\n suggestButton: {\n marginTop: 12,\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingVertical: 10,\n borderRadius: 999,\n borderWidth: 1,\n },\n suggestButtonText: { fontSize: 15, fontWeight: '600' },\n suggestFoot: { marginTop: 10, fontSize: 12, lineHeight: 17, textAlign: 'center' },\n center: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32 },\n centerTitle: { marginTop: 14, fontSize: 16, fontWeight: '600', textAlign: 'center' },\n centerDetail: { marginTop: 6, fontSize: 13, lineHeight: 19, textAlign: 'center' },\n retry: { marginTop: 18, paddingHorizontal: 20, paddingVertical: 12, borderRadius: 999 },\n retryText: { fontSize: 15, fontWeight: '600' },\n});\n"],"names":[],"mappings":"+dAqBA,MAAM,UAA2C,GAAA;AAAA,EAC/C,SAAW,EAAA,+BAAA;AAAA,EACX,OAAS,EAAA;AACX,CAAA;AACO,SAAS,cAAc,GAAqB,EAAA;AACjD,EAAM,MAAA,CAAA,GAAI,IAAI,IAAA,CAAK,GAAG,CAAA;AACtB,EAAO,OAAA,MAAA,CAAO,MAAM,CAAE,CAAA,OAAA,EAAS,CAAI,GAAA,EAAA,GAAK,CAAE,CAAA,cAAA,CAAe,MAAW,EAAA;AAAA,IAClE,KAAO,EAAA,OAAA;AAAA,IACP,GAAK,EAAA,SAAA;AAAA,IACL,IAAM,EAAA,SAAA;AAAA,IACN,MAAQ,EAAA;AAAA,GACT,CAAA;AACH;AAGA,SAAS,QAAS,CAAA;AAAA,EAChB,IAAA;AAAA,EACA;AACF,CAGG,EAAA;AACD,EAAM,MAAA,IAAA,GAAO,kBAAkB,IAAI,CAAA;AACnC,EAAI,IAAA,IAAA,CAAK,MAAW,KAAA,CAAA,IAAK,CAAC,IAAA,CAAK,CAAC,CAAE,CAAA,WAAA,EAAoB,uBAAA,GAAA,CAAA,QAAA,EAAA,EAAG,QAAK,EAAA,IAAA,EAAA,CAAA;AAC9D,EAAA,uBACW,GAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA,IAAA,CAAK,GAAI,CAAA,CAAC,GAAK,EAAA,CAAA,KAAM,GAAI,CAAA,WAAA,mBAAe,GAAA,CAAA,IAAA,EAAA,EAAa,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,IACxF,iBAAiB,KAAM,CAAA,IAAA;AAAA,IACvB,OAAO,KAAM,CAAA;AAAA,GACd,GAAG,kBAAoB,EAAA,CAAA,EAAG,iBAAiB,GAAI,CAAA,IAAI,CAAC,CAAA,QAAA,CAAA,EAEhC,QAAS,EAAA,CAAA,IAAA,EAAA,gBAAA,CAAiB,IAAI,IAAI,CAAA,CAAE,OAAQ,CAAA,IAAA,EAAM,MAAQ,CAAC,UALrB,CAM3C,CAAA,GAAU,GAAI,CAAA,IAAI,CAC9B,EAAA,CAAA;AACR;AACA,SAAS,OAAQ,CAAA;AAAA,EACf,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAIG,EAAA;AACD,EAAI,IAAA,CAAC,KAAM,CAAA,MAAA,EAAe,OAAA,IAAA;AAC1B,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,IAChC,iBAAiB,KAAM,CAAA,IAAA;AAAA,IACvB,aAAa,KAAM,CAAA;AAAA,GACpB,CACS,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,OAAS,EAAA;AAAA,MACpC,OAAO,KAAM,CAAA;AAAA,KACd,GAAI,QAAM,EAAA,KAAA,EAAA,CAAA;AAAA,IACF,KAAA,CAAM,IAAI,CAAC,IAAA,EAAM,sBAAO,IAAA,CAAA,IAAA,EAAA,EAAa,KAAO,EAAA,MAAA,CAAO,IAC5C,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,MAAQ,EAAA;AAAA,QACzC,iBAAiB,KAAM,CAAA;AAAA,OACxB,CAAG,EAAA,CAAA;AAAA,sBACW,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,QAAU,EAAA;AAAA,QAC3C,OAAO,KAAM,CAAA;AAAA,OACd,CACiB,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,IAAM,EAAA,IAAA,EAAM,OAAc,CACxC,EAAA;AAAA,KAAA,EAAA,EAR2B,CAS/B,CAAO;AAAA,GACf,EAAA,CAAA;AACR;AAGA,SAAS,UAAW,CAAA;AAAA,EAClB,MAAA;AAAA,EACA,eAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAKG,EAAA;AACD,EAAM,MAAA;AAAA,IACJ;AAAA,GACE,GAAA,MAAA;AACJ,EAAI,IAAA,CAAC,WAAkB,OAAA,IAAA;AACvB,EAAM,MAAA,KAAA,GAAQ,UAAU,WAAY,CAAA,MAAA;AACpC,EAAA,MAAM,IAAO,GAAA,KAAA,KAAU,CAAI,GAAA,kBAAA,GAAqB,GAAG,KAAK,CAAA,kBAAA,CAAA;AACxD,EAAM,MAAA,IAAA,GAAO,QAAQ,CAAG,EAAA,IAAI,IAAI,eAAkB,GAAA,YAAA,GAAe,QAAQ,CAA6B,wBAAA,CAAA,GAAA,qEAAA;AACtG,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,OAAS,EAAA;AAAA,IACnC,iBAAiB,KAAM,CAAA;AAAA,GACxB,CACS,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,0BAAuB,IAAK,EAAA,qBAAA,EAAsB,MAAM,EAAI,EAAA,KAAA,EAAO,MAAM,IAAM,EAAA,CAAA;AAAA,oBAC/E,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,WAChB,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,WAAa,EAAA;AAAA,QAC1C,OAAO,KAAM,CAAA;AAAA,OACd,GAAI,QAAK,EAAA,IAAA,EAAA,CAAA;AAAA,MACC,SAAA,CAAU,WAAW,UAAc,IAAA,KAAA,uBAAS,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,WAAa,EAAA;AAAA,QACtF,OAAO,KAAM,CAAA;AAAA,OACd,CAAG,EAAA,QAAA,EAAA,uEAAA,EAEU,CAAU,GAAA;AAAA,KAClB,EAAA,CAAA;AAAA,IACC,KAAQ,mBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,OAAA,EAAS,UAAU,iBAAkB,EAAA,QAAA,EAAS,kBAAoB,EAAA,eAAA,GAAkB,wBAA2B,GAAA,wBAAA,EAA0B,KAAO,EAAA,CAAC,OAAO,aAAe,EAAA;AAAA,MAC3L,aAAa,KAAM,CAAA,MAAA;AAAA,MACnB,iBAAiB,KAAM,CAAA;AAAA,KACxB,GAAG,YAAc,EAAA,GAAA,EACF,8BAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,iBAAmB,EAAA;AAAA,MACpD,OAAO,KAAM,CAAA;AAAA,KACd,CACkB,EAAA,QAAA,EAAA,eAAA,GAAkB,MAAS,GAAA,MAAA,EAChC,GACJ,CAAS,GAAA;AAAA,GACjB,EAAA,CAAA;AACR;AACA,MAAM,eAAuG,GAAA;AAAA,EAC3G,OAAS,EAAA,uBAAA;AAAA,EACT,MAAQ,EAAA,uBAAA;AAAA,EACR,MAAQ,EAAA,aAAA;AAAA,EACR,SAAW,EAAA;AACb,CAAA;AAGA,SAAS,WAAY,CAAA;AAAA,EACnB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAKG,EAAA;AACD,EAAM,MAAA,OAAA,GAAU,MAAM,MAAW,KAAA,SAAA;AACjC,EAAI,IAAA,OAAA;AACJ,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAA,OAAA,mBAAW,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,MACzC,OAAO,KAAM,CAAA;AAAA,KACd,GAAG,QAGI,EAAA,kIAAA,EAAA,CAAA;AAAA,GACV,MAAA,IAAW,CAAC,KAAA,CAAM,MAAQ,EAAA;AACxB,IAAA,OAAA,mBAAW,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,MACzC,OAAO,KAAM,CAAA;AAAA,KACd,GAAG,QAEI,EAAA,0DAAA,EAAA,CAAA;AAAA,GACH,MAAA;AACL,IAAA,OAAA,GAAW,MAAO,CAAA,IAAA,CAAK,mBAAmB,CAAA,CAAuB,IAAI,CAAQ,IAAA,KAAA;AAC3E,MAAA,MAAM,QAAQ,KAAM,CAAA,MAAA,CAAO,CAAK,CAAA,KAAA,CAAA,CAAE,SAAS,IAAI,CAAA;AAC/C,MAAI,IAAA,CAAC,KAAM,CAAA,MAAA,EAAe,OAAA,IAAA;AAC1B,MAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAgB,KAAO,EAAA,MAAA,CAAO,YACxB,EAAA,QAAA,EAAA;AAAA,wBAAC,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,WAChB,EAAA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,sBAAuB,EAAA,EAAA,IAAA,EAAM,eAAgB,CAAA,IAAI,CAAG,EAAA,IAAA,EAAM,EAAI,EAAA,KAAA,EAAO,IAAS,KAAA,QAAA,GAAW,KAAM,CAAA,IAAA,GAAO,MAAM,MAAQ,EAAA,CAAA;AAAA,0BACpH,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,YAC9C,OAAO,KAAM,CAAA;AAAA,WACd,CAAA,EAAI,QAAoB,EAAA,mBAAA,CAAA,IAAI,CAAE,EAAA;AAAA,SACrB,EAAA,CAAA;AAAA,QACC,KAAA,CAAM,IAAI,CAAC,CAAA,EAAG,sBAAO,IAAA,CAAA,IAAA,EAAA,EAAa,KAAO,EAAA,MAAA,CAAO,WACzC,EAAA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,WAAa,EAAA;AAAA,YAClD,OAAO,KAAM,CAAA;AAAA,WACd,GACqB,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,MAAM,CAAE,CAAA,IAAA,EAAM,OAAc,CAC1C,EAAA,CAAA;AAAA,UACC,EAAE,GAAM,mBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,YAC1D,OAAO,KAAM,CAAA;AAAA,WACd,GACyB,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,MAAM,CAAE,CAAA,GAAA,EAAK,KAAc,EAAA,CAAA,EACzC,CAAU,GAAA;AAAA,SAAA,EAAA,EAVU,CAW5B,CAAO;AAAA,OAAA,EAAA,EAlBP,IAmBR,CAAA;AAAA,KACX,CAAA;AAAA;AAEH,EAAA,IAAI,WAAc,GAAA,iBAAA;AAClB,EAAA,IAAI,SAAuB,WAAA,GAAA,wBAAA;AAAA,OAAA,IAA6B,OAAqB,WAAA,GAAA,WAAA;AAC7E,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,IAChC,iBAAiB,KAAM,CAAA,IAAA;AAAA,IACvB,aAAa,KAAM,CAAA;AAAA,GACpB,CACS,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,OAAS,EAAA;AAAA,MACpC,OAAO,KAAM,CAAA;AAAA,KACd,GAAG,QAAW,EAAA,aAAA,EAAA,CAAA;AAAA,IACN,OAAA;AAAA,IACA,KAAA,CAAM,WAAW,OAAU,mBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,YAAc,EAAA;AAAA,MACrE,OAAO,KAAM,CAAA;AAAA,KACd,CAAA,EAAI,QAAM,EAAA,KAAA,CAAA,OAAA,EAAQ,CAAU,GAAA,IAAA;AAAA,oBACpB,IAAA,CAAA,GAAA,EAAA,EAAI,OAAS,EAAA,SAAA,EAAW,UAAU,OAAS,EAAA,iBAAA,EAAkB,QAAS,EAAA,kBAAA,EAAoB,QAAQ,2BAA8B,GAAA,iBAAA,EAAmB,KAAO,EAAA,CAAC,OAAO,aAAe,EAAA;AAAA,MACxL,aAAa,KAAM,CAAA,MAAA;AAAA,MACnB,OAAA,EAAS,UAAU,GAAM,GAAA;AAAA,KAC1B,CAAG,EAAA,YAAA,EAAc,GACL,EAAA,QAAA,EAAA;AAAA,MAAA,OAAA,uBAAW,iBAAkB,EAAA,EAAA,KAAA,EAAO,KAAM,CAAA,MAAA,EAAQ,MAAK,OAAQ,EAAA,CAAA,mBAAM,GAAA,CAAA,sBAAA,EAAA,EAAuB,MAAK,sBAAuB,EAAA,IAAA,EAAM,EAAI,EAAA,KAAA,EAAO,MAAM,MAAQ,EAAA,CAAA;AAAA,sBACvJ,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,iBAAmB,EAAA;AAAA,QAChD,OAAO,KAAM,CAAA;AAAA,OACd,GAAI,QAAY,EAAA,WAAA,EAAA;AAAA,KACX,EAAA,CAAA;AAAA,IAAA,CACC,+BAAO,MAAS,oBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,MACzD,OAAO,KAAM,CAAA;AAAA,KACd,CAAI,EAAA,QAAA,EAAA,qBAAA,EAAsB,CAAU,GAAA;AAAA,GACjC,EAAA,CAAA;AACR;AACA,SAAS,UAAA,CAAW,QAAkC,KAGpD,EAAA;AACA,EAAI,IAAA,MAAA,KAAW,SAAgB,OAAA;AAAA,IAC7B,IAAI,KAAM,CAAA,QAAA;AAAA,IACV,KAAK,KAAM,CAAA;AAAA,GACb;AACA,EAAI,IAAA,MAAA,KAAW,UAAiB,OAAA;AAAA,IAC9B,IAAI,KAAM,CAAA,UAAA;AAAA,IACV,KAAK,KAAM,CAAA;AAAA,GACb;AACA,EAAI,IAAA,MAAA,KAAW,QAAe,OAAA;AAAA,IAC5B,IAAI,KAAM,CAAA,OAAA;AAAA,IACV,KAAK,KAAM,CAAA;AAAA,GACb;AACA,EAAO,OAAA;AAAA,IACL,IAAI,KAAM,CAAA,IAAA;AAAA,IACV,KAAK,KAAM,CAAA;AAAA,GACb;AACF;AACA,SAAS,WAAY,CAAA;AAAA,EACnB,IAAA;AAAA,EACA;AACF,CAGG,EAAA;AACD,EAAI,IAAA,CAAC,IAAK,CAAA,MAAA,EAAe,OAAA,IAAA;AACzB,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,IAChC,iBAAiB,KAAM,CAAA,IAAA;AAAA,IACvB,aAAa,KAAM,CAAA;AAAA,GACpB,CACS,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,OAAS,EAAA;AAAA,MACpC,OAAO,KAAM,CAAA;AAAA,KACd,GAAG,QAAW,EAAA,aAAA,EAAA,CAAA;AAAA,IACN,IAAK,CAAA,GAAA,CAAI,CAAC,GAAA,EAAK,CAAM,KAAA;AAC5B,MAAA,MAAM,IAAO,GAAA,UAAA,CAAW,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA;AACzC,MAAA,MAAM,MAAS,GAAA,CAAC,GAAI,CAAA,IAAA,EAAM,GAAI,CAAA,KAAA,EAAO,GAAI,CAAA,SAAS,CAAE,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,QAAK,CAAA;AAC9E,MAAA,4BAAQ,IAA8B,EAAA,EAAA,KAAA,EAAO,CAAC,MAAO,CAAA,GAAA,EAAK,IAAI,CAAK,IAAA;AAAA,QACjE,gBAAgB,KAAM,CAAA,MAAA;AAAA,QACtB,gBAAgB,UAAW,CAAA;AAAA,OAC5B,CACiB,EAAA,QAAA,EAAA;AAAA,wBAAC,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,OAChB,EAAA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,OAAS,EAAA;AAAA,YAC9C,OAAO,KAAM,CAAA;AAAA,WACd,GACqB,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,MAAM,GAAI,CAAA,IAAA,EAAM,OAAc,CAC5C,EAAA,CAAA;AAAA,0BACC,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,SAAW,EAAA;AAAA,YAChD,KAAO,EAAA,MAAA,GAAS,KAAM,CAAA,KAAA,GAAQ,KAAM,CAAA;AAAA,WACrC,GACsB,QAAS,EAAA,MAAA,mBAAA,GAAA,CAAC,YAAS,IAAM,EAAA,MAAA,EAAQ,KAAc,EAAA,CAAA,GAAK,+BACzD,EAAA;AAAA,SACJ,EAAA,CAAA;AAAA,wBACC,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,UACzC,iBAAiB,IAAK,CAAA;AAAA,SACvB,CACmB,EAAA,QAAA,kBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,QAAU,EAAA;AAAA,UAC/C,OAAO,IAAK,CAAA;AAAA,SACb,CAAA,EAAI,QAAI,EAAA,GAAA,CAAA,MAAA,EAAO,CACF,EAAA;AAAA,OAAA,EAAA,EAtBA,CAAG,EAAA,GAAA,CAAI,IAAI,CAAA,CAAA,EAAI,CAAC,CAuBpB,CAAA,CAAA;AAAA,KACf;AAAA,GACG,EAAA,CAAA;AACR;AACA,SAAS,OAAQ,CAAA;AAAA,EACf,KAAA;AAAA,EACA;AACF,CAGG,EAAA;AACD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,CAAC,CAAA;AACxC,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,EAAA,GAAK,YAAY,MAAM,UAAA,CAAW,OAAK,CAAI,GAAA,CAAC,GAAG,GAAI,CAAA;AACzD,IAAO,OAAA,MAAM,cAAc,EAAE,CAAA;AAAA,GAC/B,EAAG,EAAE,CAAA;AACL,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,MACjB,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,iBAAA,EAAA,EAAkB,KAAO,EAAA,KAAA,CAAM,MAAQ,EAAA,CAAA;AAAA,oBACvC,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,MACxC,OAAO,KAAM,CAAA;AAAA,KACd,CAAA,EAAI,QAAW,EAAA,UAAA,CAAA,KAAK,CAAE,EAAA,CAAA;AAAA,oBACd,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,YAAc,EAAA;AAAA,MACzC,OAAO,KAAM,CAAA;AAAA,KACd,CAAI,EAAA,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,MAAQ;AAAA,KAA0B,EAAA;AAAA,GACnC,EAAA,CAAA;AACR;AACO,SAAS,QAAS,CAAA;AAAA,EACvB,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,eAAA;AAAA,EACA,mBAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAUG,EAAA;AArUH,EAAA,IAAA,EAAA;AAsUE,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAS,KAAK,CAAA;AAC1D,EAAA,MAAM,IAAO,GAAA,CAAC,aAAc,CAAA,MAAA,CAAO,SAAS,CAAG,EAAA,cAAA,CAAe,MAAO,CAAA,UAAU,CAAC,CAAE,CAAA,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,QAAK,CAAA;AAC5G,EAAA,IAAI,OAAO,MAAW,KAAA,SAAA,IAAa,MAAO,CAAA,MAAA,KAAW,WAAW,KAAO,EAAA;AACrE,IAAA,uBAAQ,GAAA,CAAA,OAAA,EAAA,EAAQ,KAAO,EAAA,KAAA,IAAA,IAAA,GAAA,KAAA,GAAS,WAAW,KAAc,EAAA,CAAA;AAAA;AAE3D,EAAI,IAAA,CAAC,OAAO,IAAM,EAAA;AAChB,IAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,MACf,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,0BAAuB,IAAK,EAAA,sBAAA,EAAuB,MAAM,EAAI,EAAA,KAAA,EAAO,MAAM,IAAM,EAAA,CAAA;AAAA,sBAChF,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,QAC1C,OAAO,KAAM,CAAA;AAAA,OACd,GAAG,QAAW,EAAA,aAAA,EAAA,CAAA;AAAA,sBACJ,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,YAAc,EAAA;AAAA,QAC3C,OAAO,KAAM,CAAA;AAAA,OACd,CAAA,EACc,QAAO,EAAA,CAAA,EAAA,GAAA,MAAA,CAAA,KAAA,KAAP,YAAgB,uCACrB,EAAA,CAAA;AAAA,MACC,MAAA,CAAO,QAAW,mBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,OAAA,EAAS,OAAS,EAAA,iBAAA,EAAkB,QAAS,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,KAAO,EAAA;AAAA,QACnG,iBAAiB,KAAM,CAAA;AAAA,OACxB,GAAG,YAAc,EAAA,GAAA,EACA,8BAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,SAAW,EAAA;AAAA,QAC9C,OAAO,KAAM,CAAA;AAAA,OACd,CAAA,EAAG,QAAc,EAAA,gBAAA,EAAA,CAAA,EACN,CAAS,GAAA;AAAA,KACjB,EAAA,CAAA;AAAA;AAEV,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACE,GAAA,SAAA,CAAU,MAAQ,EAAA,MAAA,CAAO,MAAM,eAAe,CAAA;AAClD,EAAA,uBAAQ,IAAA,CAAA,UAAA,EAAA,EAAW,qBAAuB,EAAA,CAAC,OAAO,MAAQ,EAAA;AAAA,IACxD,eAAe,EAAK,GAAA;AAAA,GACrB,CACS,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,KAAO,EAAA;AAAA,MAClC,OAAO,KAAM,CAAA;AAAA,KACd,GACW,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,MAAM,IAAK,CAAA,KAAA,EAAO,OAAc,CAC9C,EAAA,CAAA;AAAA,oBACC,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,MACjC,OAAO,KAAM,CAAA;AAAA,KACd,GAAI,QAAK,EAAA,IAAA,EAAA,CAAA;AAAA,wBACD,UAAW,EAAA,EAAA,MAAA,EAAgB,eAAkC,EAAA,QAAA,EAAU,qBAAqB,KAAc,EAAA,CAAA;AAAA,IAE1G,IAAA,CAAK,UAAU,MAAS,mBAAA,IAAA,CAAC,QAAK,KAAO,EAAA,CAAC,OAAO,MAAQ,EAAA;AAAA,MAC5D,iBAAiB,KAAM,CAAA,QAAA;AAAA,MACvB,aAAa,KAAM,CAAA;AAAA,KACpB,CACe,EAAA,QAAA,EAAA;AAAA,sBAAC,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,UAChB,EAAA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,0BAAuB,IAAK,EAAA,eAAA,EAAgB,MAAM,EAAI,EAAA,KAAA,EAAO,MAAM,OAAS,EAAA,CAAA;AAAA,wBAC5E,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,WAAa,EAAA;AAAA,UAChD,OAAO,KAAM,CAAA;AAAA,SACd,GAAG,QAAoB,EAAA,sBAAA,EAAA;AAAA,OACZ,EAAA,CAAA;AAAA,MACC,IAAA,CAAK,SAAU,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,CAAM,qBAAA,IAAA,CAAC,IAAa,EAAA,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,UAAY,EAAA;AAAA,QACtF,OAAO,KAAM,CAAA;AAAA,OACd,CACsB,EAAA,QAAA,EAAA;AAAA,QAAA,SAAA;AAAA,wBACA,GAAA,CAAA,QAAA,EAAA,EAAS,IAAM,EAAA,IAAA,EAAM,KAAc,EAAA;AAAA,OAAA,EAAA,EAJA,CAKxC,CAAO;AAAA,KAAA,EACf,CAAU,GAAA,IAAA;AAAA,wBAEb,OAAQ,EAAA,EAAA,KAAA,EAAM,cAAa,KAAO,EAAA,IAAA,CAAK,YAAY,KAAc,EAAA,CAAA;AAAA,wBACjE,OAAQ,EAAA,EAAA,KAAA,EAAM,aAAY,KAAO,EAAA,IAAA,CAAK,WAAW,KAAc,EAAA,CAAA;AAAA,wBAC/D,OAAQ,EAAA,EAAA,KAAA,EAAM,cAAa,KAAO,EAAA,IAAA,CAAK,YAAY,KAAc,EAAA,CAAA;AAAA,wBACjE,OAAQ,EAAA,EAAA,KAAA,EAAM,QAAO,KAAO,EAAA,IAAA,CAAK,MAAM,KAAc,EAAA,CAAA;AAAA,oBACrD,GAAA,CAAA,WAAA,EAAA,EAAY,IAAM,EAAA,IAAA,CAAK,aAAa,KAAc,EAAA,CAAA;AAAA,IAClD,IAAK,CAAA,SAAA,mBAAa,GAAA,CAAA,OAAA,EAAA,EAAQ,KAAM,EAAA,WAAA,EAAY,KAAO,EAAA,CAAC,IAAK,CAAA,SAAS,CAAG,EAAA,KAAA,EAAc,CAAK,GAAA,IAAA;AAAA,IAGxF,MAAA,CAAO,SAAY,mBAAA,GAAA,CAAC,WAAY,EAAA,EAAA,KAAA,EAAO,aAAa,KAAO,EAAA,YAAA,EAAc,SAAsB,EAAA,KAAA,EAAc,CAAK,GAAA,IAAA;AAAA,IAElH,6BAAc,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,IAAM,EAAA;AAAA,MAC/C,iBAAiB,KAAM,CAAA,IAAA;AAAA,MACvB,aAAa,KAAM,CAAA;AAAA,KACpB,CACe,EAAA,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,GAAI,EAAA,EAAA,OAAA,EAAS,MAAM,iBAAA,CAAkB,OAAK,CAAC,CAAC,CAAG,EAAA,iBAAA,EAAkB,QAAS,EAAA,KAAA,EAAO,MAAO,CAAA,gBAAA,EAAkB,cAAc,GACrH,EAAA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,CAAC,MAAO,CAAA,OAAA,EAAS,OAAO,WAAa,EAAA;AAAA,UAChE,OAAO,KAAM,CAAA;AAAA,SACd,GAAG,QAAU,EAAA,YAAA,EAAA,CAAA;AAAA,wBACE,GAAA,CAAC,sBAAuB,EAAA,EAAA,IAAA,EAAM,cAAiB,GAAA,YAAA,GAAe,gBAAgB,IAAM,EAAA,EAAA,EAAI,KAAO,EAAA,KAAA,CAAM,KAAO,EAAA;AAAA,OAChH,EAAA,CAAA;AAAA,MACC,iCAAkB,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,QAC/D,OAAO,KAAM,CAAA;AAAA,OACd,GACqB,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,MAAM,UAAY,EAAA,KAAA,EAAc,GAC9C,CAAU,GAAA;AAAA,KAAA,EAClB,CAAU,GAAA,IAAA;AAAA,oBAEb,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,UAAY,EAAA;AAAA,MACvC,OAAO,KAAM,CAAA;AAAA,KACd,GAAI,QAAgB,EAAA,eAAA,EAAA;AAAA,GACjB,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,MAAQ,EAAA;AAAA,IACN,iBAAmB,EAAA,EAAA;AAAA,IACnB,UAAY,EAAA;AAAA,GACd;AAAA,EACA,KAAO,EAAA;AAAA,IACL,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,UAAY,EAAA;AAAA,GACd;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,SAAW,EAAA,CAAA;AAAA,IACX,QAAU,EAAA;AAAA,GACZ;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,SAAW,EAAA,EAAA;AAAA,IACX,YAAc,EAAA,EAAA;AAAA,IACd,aAAa,UAAW,CAAA,aAAA;AAAA,IACxB,OAAS,EAAA;AAAA,GACX;AAAA,EACA,UAAY,EAAA;AAAA,IACV,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,GAAK,EAAA,CAAA;AAAA,IACL,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,UAAY,EAAA;AAAA,IACV,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,EAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,SAAW,EAAA,EAAA;AAAA,IACX,YAAc,EAAA,EAAA;AAAA,IACd,aAAa,UAAW,CAAA,aAAA;AAAA,IACxB,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,aAAe,EAAA,GAAA;AAAA,IACf,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,WAAa,EAAA;AAAA,IACX,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,YAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,CAAA;AAAA,IACP,MAAQ,EAAA,CAAA;AAAA,IACR,YAAc,EAAA,GAAA;AAAA,IACd,SAAW,EAAA,CAAA;AAAA,IACX,WAAa,EAAA;AAAA,GACf;AAAA,EACA,QAAU,EAAA;AAAA,IACR,IAAM,EAAA,CAAA;AAAA,IACN,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,GAAK,EAAA;AAAA,IACH,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,IAAM,EAAA,CAAA;AAAA,IACN,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,aAAe,EAAA;AAAA,GACjB;AAAA,EACA,SAAW,EAAA;AAAA,IACT,SAAW,EAAA,CAAA;AAAA,IACX,QAAU,EAAA;AAAA,GACZ;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,CAAA;AAAA,IACjB,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,QAAU,EAAA;AAAA,IACR,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,aAAe,EAAA;AAAA,GACjB;AAAA,EACA,gBAAkB,EAAA;AAAA,IAChB,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA;AAAA,GAClB;AAAA,EACA,UAAY,EAAA;AAAA,IACV,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,UAAY,EAAA;AAAA,IACV,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,SAAW,EAAA;AAAA,GACb;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,YAAc,EAAA,CAAA;AAAA,IACd,QAAU,EAAA;AAAA,GACZ;AAAA,EACA,OAAS,EAAA;AAAA,IACP,SAAW,EAAA,EAAA;AAAA,IACX,YAAc,EAAA,EAAA;AAAA,IACd,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,EAAA;AAAA,IACjB,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,GAAK,EAAA;AAAA,GACP;AAAA,EACA,WAAa,EAAA;AAAA,IACX,IAAM,EAAA;AAAA,GACR;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,WAAa,EAAA;AAAA,IACX,SAAW,EAAA,CAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,aAAe,EAAA;AAAA,IACb,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,CAAA;AAAA,IACjB,YAAc,EAAA,GAAA;AAAA,IACd,aAAa,UAAW,CAAA;AAAA,GAC1B;AAAA,EACA,iBAAmB,EAAA;AAAA,IACjB,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,WAAa,EAAA;AAAA,IACX,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,GAAK,EAAA,CAAA;AAAA,IACL,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,WAAa,EAAA;AAAA,IACX,SAAW,EAAA,CAAA;AAAA,IACX,WAAa,EAAA;AAAA,GACf;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,UAAY,EAAA;AAAA,IACV,SAAW,EAAA,CAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,aAAe,EAAA;AAAA,IACb,SAAW,EAAA,EAAA;AAAA,IACX,aAAe,EAAA,KAAA;AAAA,IACf,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,QAAA;AAAA,IAChB,GAAK,EAAA,CAAA;AAAA,IACL,eAAiB,EAAA,EAAA;AAAA,IACjB,YAAc,EAAA,GAAA;AAAA,IACd,WAAa,EAAA;AAAA,GACf;AAAA,EACA,iBAAmB,EAAA;AAAA,IACjB,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA,GACd;AAAA,EACA,WAAa,EAAA;AAAA,IACX,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,EAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,CAAA;AAAA,IACN,UAAY,EAAA,QAAA;AAAA,IACZ,cAAgB,EAAA,QAAA;AAAA,IAChB,iBAAmB,EAAA;AAAA,GACrB;AAAA,EACA,WAAa,EAAA;AAAA,IACX,SAAW,EAAA,EAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,YAAc,EAAA;AAAA,IACZ,SAAW,EAAA,CAAA;AAAA,IACX,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,EAAA;AAAA,IACZ,SAAW,EAAA;AAAA,GACb;AAAA,EACA,KAAO,EAAA;AAAA,IACL,SAAW,EAAA,EAAA;AAAA,IACX,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,EAAA;AAAA,IACjB,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,SAAW,EAAA;AAAA,IACT,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA;AAAA;AAEhB,CAAC,CAAA"}
@@ -16,6 +16,8 @@ var __spreadValues = (a, b) => {
16
16
  };
17
17
  const DICTATE_CONNECTOR = "yantra-meetings";
18
18
  const CLINICAL_NOTE_ACTION = "YANTRA_MEETINGS_CLINICAL_NOTE";
19
+ const SUGGEST_ACTION = "YANTRA_MEETINGS_CLINICAL_SUGGEST";
20
+ const SUGGEST_TIMEOUT_MS = 4 * 6e4;
19
21
  const NOTE_TIMEOUT_MS = 10 * 6e4;
20
22
  class DictateError extends Error {
21
23
  constructor(kind, message) {
@@ -31,6 +33,47 @@ const strings = (v) => {
31
33
  return str(v) ? [str(v)] : [];
32
34
  };
33
35
  const ACTIONS = ["start", "continue", "change", "stop", "mentioned"];
36
+ const KINDS = ["missing", "safety", "coding", "follow_up"];
37
+ function shapeNote(note) {
38
+ const meds = Array.isArray(note.medications) ? note.medications : [];
39
+ return {
40
+ title: str(note.title) || "Clinical note",
41
+ subjective: strings(note.subjective),
42
+ objective: strings(note.objective),
43
+ assessment: strings(note.assessment),
44
+ plan: strings(note.plan),
45
+ medications: meds.map(asRecord).filter((m) => !!m && !!str(m.name)).map((m) => {
46
+ const action = str(m.action).toLowerCase();
47
+ return {
48
+ name: str(m.name),
49
+ dose: str(m.dose),
50
+ route: str(m.route),
51
+ frequency: str(m.frequency),
52
+ action: ACTIONS.includes(action) ? action : "mentioned"
53
+ };
54
+ }),
55
+ follow_up: str(note.follow_up),
56
+ to_verify: strings(note.to_verify)
57
+ };
58
+ }
59
+ function identifiersOf(v) {
60
+ return (Array.isArray(v) ? v : []).map(asRecord).filter((i) => !!i && /^\[[A-Z]+_\d+\]$/.test(str(i.token)) && !!str(i.value)).map((i) => ({
61
+ token: str(i.token),
62
+ value: str(i.value),
63
+ kind: str(i.kind)
64
+ }));
65
+ }
66
+ function redactionOf(v) {
67
+ const r = asRecord(v);
68
+ const note = asRecord(r == null ? void 0 : r.note);
69
+ if (!r || !note) return void 0;
70
+ return {
71
+ method: r.method === "patterns" ? "patterns" : "entities",
72
+ note: shapeNote(note),
73
+ transcript: str(r.transcript),
74
+ identifiers: identifiersOf(r.identifiers)
75
+ };
76
+ }
34
77
  function unwrapNote(raw) {
35
78
  var _a;
36
79
  let layer = asRecord(raw);
@@ -40,30 +83,14 @@ function unwrapNote(raw) {
40
83
  const note = asRecord(layer.note);
41
84
  if (note) {
42
85
  const transcript = asRecord(layer.transcript);
43
- const meds = Array.isArray(note.medications) ? note.medications : [];
44
- return {
45
- note: {
46
- title: str(note.title) || "Clinical note",
47
- subjective: strings(note.subjective),
48
- objective: strings(note.objective),
49
- assessment: strings(note.assessment),
50
- plan: strings(note.plan),
51
- medications: meds.map(asRecord).filter((m) => !!m && !!str(m.name)).map((m) => {
52
- const action = str(m.action).toLowerCase();
53
- return {
54
- name: str(m.name),
55
- dose: str(m.dose),
56
- route: str(m.route),
57
- frequency: str(m.frequency),
58
- action: ACTIONS.includes(action) ? action : "mentioned"
59
- };
60
- }),
61
- follow_up: str(note.follow_up),
62
- to_verify: strings(note.to_verify)
63
- },
86
+ const redaction = redactionOf(layer.redaction);
87
+ return __spreadValues({
88
+ note: shapeNote(note),
64
89
  transcript: str(transcript == null ? void 0 : transcript.text),
65
90
  model: str(layer.model) || void 0
66
- };
91
+ }, redaction ? {
92
+ redaction
93
+ } : {});
67
94
  }
68
95
  layer = (_a = asRecord(layer.data)) != null ? _a : asRecord(layer.result);
69
96
  }
@@ -100,4 +127,47 @@ async function writeNoteFromRecording(audioUri, deps, opts = {}, onStage = () =>
100
127
  const empty = !written.transcript && ![n.subjective, n.objective, n.assessment, n.plan].some((s) => s.length);
101
128
  if (empty) throw new DictateError("empty", "The dictation has no speech.");
102
129
  return written;
103
- }export{CLINICAL_NOTE_ACTION,DICTATE_CONNECTOR,DictateError,NOTE_TIMEOUT_MS,dictateErrorText,unwrapNote,writeNoteFromRecording};//# sourceMappingURL=dictateClient.js.map
130
+ }
131
+ async function suggestFromNote(redaction, deps) {
132
+ var _a;
133
+ const raw = await deps.exec(DICTATE_CONNECTOR, SUGGEST_ACTION, {
134
+ note: redaction.note,
135
+ transcript: redaction.transcript,
136
+ // Which placeholders exist, so a new one numbers on; never what they stand for.
137
+ identifiers: redaction.identifiers.map(({
138
+ token,
139
+ kind
140
+ }) => ({
141
+ token,
142
+ kind
143
+ }))
144
+ }, {
145
+ timeoutMs: SUGGEST_TIMEOUT_MS
146
+ });
147
+ let layer = asRecord(raw);
148
+ for (let depth = 0; layer && depth < 6; depth += 1) {
149
+ if (Array.isArray(layer.suggestions)) {
150
+ const items = layer.suggestions.map(asRecord).filter((s) => !!s && KINDS.includes(str(s.kind)) && !!str(s.text)).map((s) => ({
151
+ kind: str(s.kind),
152
+ text: str(s.text),
153
+ why: str(s.why)
154
+ }));
155
+ return {
156
+ items,
157
+ identifiers: identifiersOf(layer.identifiers)
158
+ };
159
+ }
160
+ const reason = [layer.error, layer.message].find((v) => typeof v === "string" && !!v.trim());
161
+ if (layer.successful === false && reason) throw new DictateError("failed", reason);
162
+ layer = (_a = asRecord(layer.data)) != null ? _a : asRecord(layer.result);
163
+ }
164
+ throw new DictateError("failed", "The suggestions came back empty.");
165
+ }
166
+ function suggestErrorText(err) {
167
+ const message = err instanceof Error ? err.message : String(err);
168
+ if (/network request failed|offline|not signed in/i.test(message)) return "You are offline or signed out. Try again when you are back online.";
169
+ if (/action '[^']*' not found in connector|not found in registry|is not installed/i.test(message)) return "Suggestions are not available on this workspace yet.";
170
+ if (/temporarily unavailable|problem on our side|all LLM providers failed|HTTP 5\d\d/i.test(message)) return "Yantra could not read the note right now. This is a problem on our side; try again in a few minutes.";
171
+ if (/timed? ?out|abort/i.test(message)) return "Reading the note took too long. Try again.";
172
+ return "The suggestions could not be written. Try again.";
173
+ }export{CLINICAL_NOTE_ACTION,DICTATE_CONNECTOR,DictateError,NOTE_TIMEOUT_MS,SUGGEST_ACTION,SUGGEST_TIMEOUT_MS,dictateErrorText,identifiersOf,suggestErrorText,suggestFromNote,unwrapNote,writeNoteFromRecording};//# sourceMappingURL=dictateClient.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dictateClient.js","sources":["../../../src/features/dictate/dictateClient.ts"],"sourcesContent":["/**\n * Recording -> SOAP note. The recording is uploaded first and handed to the\n * connector as a URL (connector params travel as one CLI argument, capped at\n * 128 KB - audio never rides inline), then YANTRA_MEETINGS_CLINICAL_NOTE\n * transcribes it with a medical speech model and writes the note.\n */\nimport type { RemoteConnectorExec } from '../canvas/videoEditor/remoteMediaClient';\nimport type { ClinicalNote, MedicationAction } from './types';\n\nexport const DICTATE_CONNECTOR = 'yantra-meetings';\nexport const CLINICAL_NOTE_ACTION = 'YANTRA_MEETINGS_CLINICAL_NOTE';\n/** Transcription plus the note runs ~10 s for two minutes of speech; an hour's dictation stays well inside this. */\nexport const NOTE_TIMEOUT_MS = 10 * 60_000;\n\nexport type DictateStage = 'uploading' | 'writing';\n\nexport interface DictateDeps {\n exec: RemoteConnectorExec;\n upload: (localUri: string) => Promise<string>;\n}\n\nexport interface WrittenNote {\n note: ClinicalNote;\n transcript: string;\n model?: string;\n}\n\nexport class DictateError extends Error {\n constructor(\n readonly kind: 'offline' | 'unavailable' | 'empty' | 'failed',\n message: string,\n ) {\n super(message);\n this.name = 'DictateError';\n }\n}\n\ntype Json = Record<string, unknown>;\nconst asRecord = (v: unknown): Json | null => (v && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : null);\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst strings = (v: unknown): string[] => {\n if (Array.isArray(v)) return v.map(str).filter(Boolean);\n return str(v) ? [str(v)] : [];\n};\nconst ACTIONS: MedicationAction[] = ['start', 'continue', 'change', 'stop', 'mentioned'];\n\n/** The note whatever wraps it ({ data: { note } }, { result: ... }), shaped defensively. */\nexport function unwrapNote(raw: unknown): WrittenNote {\n let layer = asRecord(raw);\n const seen: Json[] = [];\n for (let depth = 0; layer && depth < 6; depth += 1) {\n seen.push(layer);\n const note = asRecord(layer.note);\n if (note) {\n const transcript = asRecord(layer.transcript);\n const meds = Array.isArray(note.medications) ? note.medications : [];\n return {\n note: {\n title: str(note.title) || 'Clinical note',\n subjective: strings(note.subjective),\n objective: strings(note.objective),\n assessment: strings(note.assessment),\n plan: strings(note.plan),\n medications: meds\n .map(asRecord)\n .filter((m): m is Json => !!m && !!str(m.name))\n .map((m) => {\n const action = str(m.action).toLowerCase() as MedicationAction;\n return {\n name: str(m.name),\n dose: str(m.dose),\n route: str(m.route),\n frequency: str(m.frequency),\n action: ACTIONS.includes(action) ? action : 'mentioned',\n };\n }),\n follow_up: str(note.follow_up),\n to_verify: strings(note.to_verify),\n },\n transcript: str(transcript?.text),\n model: str(layer.model) || undefined,\n };\n }\n layer = asRecord(layer.data) ?? asRecord(layer.result);\n }\n const reason = seen\n .flatMap((l) => [l.error, l.message, l.stderr])\n .find((v): v is string => typeof v === 'string' && v.trim().length > 0);\n throw new DictateError('failed', reason ?? 'The note came back empty.');\n}\n\n/** A message a clinician can act on, never a stack trace. */\nexport function dictateErrorText(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (err instanceof DictateError && err.kind === 'empty')\n return 'No speech was heard in the recording. Try again closer to the phone.';\n if (/network request failed|offline|not signed in/i.test(message))\n return 'You are offline or signed out. The recording is saved; try again when you are back online.';\n if (/no speech|has no speech/i.test(message))\n return 'No speech was heard in the recording. Try again closer to the phone.';\n // Every exec failure starts with the action's name (\"YANTRA_MEETINGS_CLINICAL_NOTE failed: ...\"), so\n // only cdecli's own words for a missing connector or action mean Dictate is not set up here.\n if (\n /action '[^']*' not found in connector|not found in registry|is not installed|auto-install (failed|did not complete)/i.test(\n message,\n )\n )\n return 'Dictate is not available on this workspace yet. The recording is saved.';\n // Ours, not theirs: the service behind the note (the connector's neutral \"temporarily unavailable\",\n // or, from an older connector, its raw \"all LLM providers failed\"), or the agent itself failing.\n if (\n /temporarily unavailable|problem on our side|all LLM providers failed|transcription failed|HTTP 5\\d\\d/i.test(\n message,\n )\n )\n return 'Yantra could not write the note right now. This is a problem on our side; the recording is saved, so try again in a few minutes.';\n if (/declined by the content safety rules/i.test(message))\n return 'The note could not be written from this dictation. The recording is saved.';\n if (/timed? ?out|abort/i.test(message)) return 'Writing the note took too long. The recording is saved; try again.';\n return 'The note could not be written. The recording is saved; try again.';\n}\n\nexport async function writeNoteFromRecording(\n audioUri: string,\n deps: DictateDeps,\n opts: { keyterms?: string[]; context?: string } = {},\n onStage: (stage: DictateStage) => void = () => undefined,\n): Promise<WrittenNote> {\n onStage('uploading');\n const inputUrl = await deps.upload(audioUri);\n onStage('writing');\n const raw = await deps.exec(\n DICTATE_CONNECTOR,\n CLINICAL_NOTE_ACTION,\n {\n input_url: inputUrl,\n ...(opts.keyterms?.length ? { keyterms: opts.keyterms } : {}),\n ...(opts.context?.trim() ? { context: opts.context.trim() } : {}),\n },\n { timeoutMs: NOTE_TIMEOUT_MS },\n );\n const written = unwrapNote(raw);\n const n = written.note;\n const empty = !written.transcript && ![n.subjective, n.objective, n.assessment, n.plan].some((s) => s.length);\n if (empty) throw new DictateError('empty', 'The dictation has no speech.');\n return written;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dictateClient.js","sources":["../../../src/features/dictate/dictateClient.ts"],"sourcesContent":["/**\n * Recording -> SOAP note. The recording is uploaded first and handed to the\n * connector as a URL (connector params travel as one CLI argument, capped at\n * 128 KB - audio never rides inline), then YANTRA_MEETINGS_CLINICAL_NOTE\n * transcribes it with a medical speech model and writes the note from a\n * transcript whose identifiers are placeholders; it returns the note both ways.\n *\n * Suggestions: YANTRA_MEETINGS_CLINICAL_SUGGEST reads the hidden version only,\n * so nothing identifying goes back to the AI from this phone.\n */\nimport type { RemoteConnectorExec } from '../canvas/videoEditor/remoteMediaClient';\nimport type {\n ClinicalNote,\n MedicationAction,\n NoteIdentifier,\n NoteRedaction,\n NoteSuggestion,\n SuggestionKind,\n} from './types';\n\nexport const DICTATE_CONNECTOR = 'yantra-meetings';\nexport const CLINICAL_NOTE_ACTION = 'YANTRA_MEETINGS_CLINICAL_NOTE';\nexport const SUGGEST_ACTION = 'YANTRA_MEETINGS_CLINICAL_SUGGEST';\n/** A read of one note runs about ten seconds. */\nexport const SUGGEST_TIMEOUT_MS = 4 * 60_000;\n/** Transcription plus the note runs ~10 s for two minutes of speech; an hour's dictation stays well inside this. */\nexport const NOTE_TIMEOUT_MS = 10 * 60_000;\n\nexport type DictateStage = 'uploading' | 'writing';\n\nexport interface DictateDeps {\n exec: RemoteConnectorExec;\n upload: (localUri: string) => Promise<string>;\n}\n\nexport interface WrittenNote {\n note: ClinicalNote;\n transcript: string;\n model?: string;\n /** Absent from a connector that does not hide identifiers yet. */\n redaction?: NoteRedaction;\n}\n\nexport class DictateError extends Error {\n constructor(\n readonly kind: 'offline' | 'unavailable' | 'empty' | 'failed',\n message: string,\n ) {\n super(message);\n this.name = 'DictateError';\n }\n}\n\ntype Json = Record<string, unknown>;\nconst asRecord = (v: unknown): Json | null => (v && typeof v === 'object' && !Array.isArray(v) ? (v as Json) : null);\nconst str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\nconst strings = (v: unknown): string[] => {\n if (Array.isArray(v)) return v.map(str).filter(Boolean);\n return str(v) ? [str(v)] : [];\n};\nconst ACTIONS: MedicationAction[] = ['start', 'continue', 'change', 'stop', 'mentioned'];\nconst KINDS: SuggestionKind[] = ['missing', 'safety', 'coding', 'follow_up'];\n\nfunction shapeNote(note: Json): ClinicalNote {\n const meds = Array.isArray(note.medications) ? note.medications : [];\n return {\n title: str(note.title) || 'Clinical note',\n subjective: strings(note.subjective),\n objective: strings(note.objective),\n assessment: strings(note.assessment),\n plan: strings(note.plan),\n medications: meds\n .map(asRecord)\n .filter((m): m is Json => !!m && !!str(m.name))\n .map((m) => {\n const action = str(m.action).toLowerCase() as MedicationAction;\n return {\n name: str(m.name),\n dose: str(m.dose),\n route: str(m.route),\n frequency: str(m.frequency),\n action: ACTIONS.includes(action) ? action : 'mentioned',\n };\n }),\n follow_up: str(note.follow_up),\n to_verify: strings(note.to_verify),\n };\n}\n\n/** Only well-formed placeholders: a malformed one could not be put back. */\nexport function identifiersOf(v: unknown): NoteIdentifier[] {\n return (Array.isArray(v) ? v : [])\n .map(asRecord)\n .filter((i): i is Json => !!i && /^\\[[A-Z]+_\\d+\\]$/.test(str(i.token)) && !!str(i.value))\n .map((i) => ({ token: str(i.token), value: str(i.value), kind: str(i.kind) }));\n}\n\nfunction redactionOf(v: unknown): NoteRedaction | undefined {\n const r = asRecord(v);\n const note = asRecord(r?.note);\n if (!r || !note) return undefined;\n return {\n method: r.method === 'patterns' ? 'patterns' : 'entities',\n note: shapeNote(note),\n transcript: str(r.transcript),\n identifiers: identifiersOf(r.identifiers),\n };\n}\n\n/** The note whatever wraps it ({ data: { note } }, { result: ... }), shaped defensively. */\nexport function unwrapNote(raw: unknown): WrittenNote {\n let layer = asRecord(raw);\n const seen: Json[] = [];\n for (let depth = 0; layer && depth < 6; depth += 1) {\n seen.push(layer);\n const note = asRecord(layer.note);\n if (note) {\n const transcript = asRecord(layer.transcript);\n const redaction = redactionOf(layer.redaction);\n return {\n note: shapeNote(note),\n transcript: str(transcript?.text),\n model: str(layer.model) || undefined,\n ...(redaction ? { redaction } : {}),\n };\n }\n layer = asRecord(layer.data) ?? asRecord(layer.result);\n }\n const reason = seen\n .flatMap((l) => [l.error, l.message, l.stderr])\n .find((v): v is string => typeof v === 'string' && v.trim().length > 0);\n throw new DictateError('failed', reason ?? 'The note came back empty.');\n}\n\n/** A message a clinician can act on, never a stack trace. */\nexport function dictateErrorText(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (err instanceof DictateError && err.kind === 'empty')\n return 'No speech was heard in the recording. Try again closer to the phone.';\n if (/network request failed|offline|not signed in/i.test(message))\n return 'You are offline or signed out. The recording is saved; try again when you are back online.';\n if (/no speech|has no speech/i.test(message))\n return 'No speech was heard in the recording. Try again closer to the phone.';\n // Every exec failure starts with the action's name (\"YANTRA_MEETINGS_CLINICAL_NOTE failed: ...\"), so\n // only cdecli's own words for a missing connector or action mean Dictate is not set up here.\n if (\n /action '[^']*' not found in connector|not found in registry|is not installed|auto-install (failed|did not complete)/i.test(\n message,\n )\n )\n return 'Dictate is not available on this workspace yet. The recording is saved.';\n // Ours, not theirs: the service behind the note (the connector's neutral \"temporarily unavailable\",\n // or, from an older connector, its raw \"all LLM providers failed\"), or the agent itself failing.\n if (\n /temporarily unavailable|problem on our side|all LLM providers failed|transcription failed|HTTP 5\\d\\d/i.test(\n message,\n )\n )\n return 'Yantra could not write the note right now. This is a problem on our side; the recording is saved, so try again in a few minutes.';\n if (/declined by the content safety rules/i.test(message))\n return 'The note could not be written from this dictation. The recording is saved.';\n if (/timed? ?out|abort/i.test(message)) return 'Writing the note took too long. The recording is saved; try again.';\n return 'The note could not be written. The recording is saved; try again.';\n}\n\nexport async function writeNoteFromRecording(\n audioUri: string,\n deps: DictateDeps,\n opts: { keyterms?: string[]; context?: string } = {},\n onStage: (stage: DictateStage) => void = () => undefined,\n): Promise<WrittenNote> {\n onStage('uploading');\n const inputUrl = await deps.upload(audioUri);\n onStage('writing');\n const raw = await deps.exec(\n DICTATE_CONNECTOR,\n CLINICAL_NOTE_ACTION,\n {\n input_url: inputUrl,\n ...(opts.keyterms?.length ? { keyterms: opts.keyterms } : {}),\n ...(opts.context?.trim() ? { context: opts.context.trim() } : {}),\n },\n { timeoutMs: NOTE_TIMEOUT_MS },\n );\n const written = unwrapNote(raw);\n const n = written.note;\n const empty = !written.transcript && ![n.subjective, n.objective, n.assessment, n.plan].some((s) => s.length);\n if (empty) throw new DictateError('empty', 'The dictation has no speech.');\n return written;\n}\n\n/** The AI's suggestions on a note, asked for with its hidden version only. */\nexport async function suggestFromNote(\n redaction: NoteRedaction,\n deps: Pick<DictateDeps, 'exec'>,\n): Promise<{ items: NoteSuggestion[]; identifiers: NoteIdentifier[] }> {\n const raw = await deps.exec(\n DICTATE_CONNECTOR,\n SUGGEST_ACTION,\n {\n note: redaction.note,\n transcript: redaction.transcript,\n // Which placeholders exist, so a new one numbers on; never what they stand for.\n identifiers: redaction.identifiers.map(({ token, kind }) => ({ token, kind })),\n },\n { timeoutMs: SUGGEST_TIMEOUT_MS },\n );\n let layer = asRecord(raw);\n for (let depth = 0; layer && depth < 6; depth += 1) {\n if (Array.isArray(layer.suggestions)) {\n const items = layer.suggestions\n .map(asRecord)\n .filter((s): s is Json => !!s && KINDS.includes(str(s.kind) as SuggestionKind) && !!str(s.text))\n .map((s) => ({ kind: str(s.kind) as SuggestionKind, text: str(s.text), why: str(s.why) }));\n return { items, identifiers: identifiersOf(layer.identifiers) };\n }\n const reason = [layer.error, layer.message].find((v): v is string => typeof v === 'string' && !!v.trim());\n if (layer.successful === false && reason) throw new DictateError('failed', reason);\n layer = asRecord(layer.data) ?? asRecord(layer.result);\n }\n throw new DictateError('failed', 'The suggestions came back empty.');\n}\n\n/** Why there are no suggestions, in words a clinician can act on. */\nexport function suggestErrorText(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (/network request failed|offline|not signed in/i.test(message))\n return 'You are offline or signed out. Try again when you are back online.';\n if (/action '[^']*' not found in connector|not found in registry|is not installed/i.test(message))\n return 'Suggestions are not available on this workspace yet.';\n if (/temporarily unavailable|problem on our side|all LLM providers failed|HTTP 5\\d\\d/i.test(message))\n return 'Yantra could not read the note right now. This is a problem on our side; try again in a few minutes.';\n if (/timed? ?out|abort/i.test(message)) return 'Reading the note took too long. Try again.';\n return 'The suggestions could not be written. Try again.';\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ var _a;
2
+ let AsyncStorage = null;
3
+ try {
4
+ AsyncStorage = (_a = require("@react-native-async-storage/async-storage").default) != null ? _a : null;
5
+ } catch (e) {
6
+ AsyncStorage = null;
7
+ }
8
+ const KEY = "yantra.dictate.showIdentifiers.v1";
9
+ async function readShowIdentifiers() {
10
+ if (!AsyncStorage) return false;
11
+ try {
12
+ return await AsyncStorage.getItem(KEY) === "1";
13
+ } catch (e) {
14
+ return false;
15
+ }
16
+ }
17
+ function writeShowIdentifiers(show) {
18
+ AsyncStorage == null ? void 0 : AsyncStorage.setItem(KEY, show ? "1" : "0").catch(() => void 0);
19
+ }export{readShowIdentifiers,writeShowIdentifiers};//# sourceMappingURL=dictatePreference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictatePreference.js","sources":["../../../src/features/dictate/dictatePreference.ts"],"sourcesContent":["/**\n * Whether Dictate shows a note with its names and numbers put back or hidden.\n * Hidden unless the clinician chose otherwise on this phone; either way the AI\n * only ever saw placeholders.\n */\ntype StorageLike = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n};\n\nlet AsyncStorage: StorageLike | null = null;\ntry {\n // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n AsyncStorage = require('@react-native-async-storage/async-storage').default ?? null;\n} catch {\n AsyncStorage = null;\n}\n\nconst KEY = 'yantra.dictate.showIdentifiers.v1';\n\nexport async function readShowIdentifiers(): Promise<boolean> {\n if (!AsyncStorage) return false;\n try {\n return (await AsyncStorage.getItem(KEY)) === '1';\n } catch {\n return false;\n }\n}\n\nexport function writeShowIdentifiers(show: boolean): void {\n AsyncStorage?.setItem(KEY, show ? '1' : '0').catch(() => undefined);\n}\n"],"names":[],"mappings":"AAAA,IAAA,EAAA;AASA,IAAI,YAAmC,GAAA,IAAA;AACvC,IAAI;AAEF,EAAA,YAAA,GAAA,CAAe,EAAQ,GAAA,OAAA,CAAA,2CAA2C,CAAE,CAAA,OAAA,KAArD,IAAgE,GAAA,EAAA,GAAA,IAAA;AACjF,CAAQ,CAAA,OAAA,CAAA,EAAA;AACN,EAAe,YAAA,GAAA,IAAA;AACjB;AACA,MAAM,GAAM,GAAA,mCAAA;AACZ,eAAsB,mBAAwC,GAAA;AAC5D,EAAI,IAAA,CAAC,cAAqB,OAAA,KAAA;AAC1B,EAAI,IAAA;AACF,IAAA,OAAQ,MAAM,YAAA,CAAa,OAAQ,CAAA,GAAG,CAAO,KAAA,GAAA;AAAA,GACvC,CAAA,OAAA,CAAA,EAAA;AACN,IAAO,OAAA,KAAA;AAAA;AAEX;AACO,SAAS,qBAAqB,IAAqB,EAAA;AACxD,EAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAQ,GAAK,EAAA,IAAA,GAAO,GAAM,GAAA,GAAA,CAAA,CAAK,MAAM,MAAM,MAAA,CAAA;AAC3D"}
@@ -1,4 +1,11 @@
1
1
  const NOTE_DISCLAIMER = "AI draft from a dictation. Review before use.";
2
+ const SUGGESTION_DISCLAIMER = "AI suggestions for you to consider, not medical advice.";
3
+ const SUGGESTION_HEADINGS = {
4
+ safety: "Check for safety",
5
+ missing: "Missing from the note",
6
+ coding: "Coding",
7
+ follow_up: "Follow-up"
8
+ };
2
9
  const ACTION_LABEL = {
3
10
  start: "start",
4
11
  continue: "continue",
@@ -10,7 +17,7 @@ function medicationLine(med) {
10
17
  const parts = [med.name, med.dose, med.route, med.frequency].map((p) => p.trim()).filter(Boolean);
11
18
  return `${parts.join(" ")} (${ACTION_LABEL[med.action]})`;
12
19
  }
13
- function noteToText(note) {
20
+ function noteToText(note, transcript, suggestions) {
14
21
  const lines = [note.title, NOTE_DISCLAIMER];
15
22
  const section = (heading, items) => {
16
23
  if (!items.length) return;
@@ -23,6 +30,14 @@ function noteToText(note) {
23
30
  section("PLAN", note.plan);
24
31
  section("MEDICATIONS", note.medications.map(medicationLine));
25
32
  if (note.follow_up.trim()) lines.push("", "FOLLOW-UP", note.follow_up.trim());
33
+ if (suggestions == null ? void 0 : suggestions.length) {
34
+ lines.push("", "SUGGESTIONS", SUGGESTION_DISCLAIMER);
35
+ for (const kind of Object.keys(SUGGESTION_HEADINGS)) {
36
+ const group = suggestions.filter((s) => s.kind === kind);
37
+ if (group.length) lines.push(`${SUGGESTION_HEADINGS[kind]}:`, ...group.map((s) => `- ${s.text}${s.why ? ` (${s.why})` : ""}`));
38
+ }
39
+ }
40
+ if (transcript == null ? void 0 : transcript.trim()) lines.push("", "TRANSCRIPT", transcript.trim());
26
41
  return lines.join("\n");
27
42
  }
28
43
  function formatDuration(ms) {
@@ -32,4 +47,4 @@ function formatDuration(ms) {
32
47
  const s = total % 60;
33
48
  const ss = String(s).padStart(2, "0");
34
49
  return h ? `${h}:${String(m).padStart(2, "0")}:${ss}` : `${m}:${ss}`;
35
- }export{NOTE_DISCLAIMER,formatDuration,medicationLine,noteToText};//# sourceMappingURL=noteText.js.map
50
+ }export{NOTE_DISCLAIMER,SUGGESTION_DISCLAIMER,SUGGESTION_HEADINGS,formatDuration,medicationLine,noteToText};//# sourceMappingURL=noteText.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"noteText.js","sources":["../../../src/features/dictate/noteText.ts"],"sourcesContent":["/**\n * The note as plain text, for Copy and Share: section headings in capitals,\n * one item per line, the checks first so they cannot be missed once pasted.\n */\nimport type { ClinicalNote, NoteMedication } from './types';\n\nexport const NOTE_DISCLAIMER = 'AI draft from a dictation. Review before use.';\n\nconst ACTION_LABEL: Record<NoteMedication['action'], string> = {\n start: 'start',\n continue: 'continue',\n change: 'change',\n stop: 'stop',\n mentioned: 'mentioned',\n};\n\n/** \"lisinopril 20 mg PO once daily (change)\" - only the parts that were dictated. */\nexport function medicationLine(med: NoteMedication): string {\n const parts = [med.name, med.dose, med.route, med.frequency].map((p) => p.trim()).filter(Boolean);\n return `${parts.join(' ')} (${ACTION_LABEL[med.action]})`;\n}\n\nexport function noteToText(note: ClinicalNote): string {\n const lines: string[] = [note.title, NOTE_DISCLAIMER];\n const section = (heading: string, items: string[]) => {\n if (!items.length) return;\n lines.push('', heading, ...items.map((item) => `- ${item}`));\n };\n section('CHECK BEFORE USE', note.to_verify);\n section('SUBJECTIVE', note.subjective);\n section('OBJECTIVE', note.objective);\n section('ASSESSMENT', note.assessment);\n section('PLAN', note.plan);\n section('MEDICATIONS', note.medications.map(medicationLine));\n if (note.follow_up.trim()) lines.push('', 'FOLLOW-UP', note.follow_up.trim());\n return lines.join('\\n');\n}\n\n/** \"4:07\" or \"1:02:09\". */\nexport function formatDuration(ms: number): string {\n const total = Math.max(0, Math.floor(ms / 1000));\n const h = Math.floor(total / 3600);\n const m = Math.floor((total % 3600) / 60);\n const s = total % 60;\n const ss = String(s).padStart(2, '0');\n return h ? `${h}:${String(m).padStart(2, '0')}:${ss}` : `${m}:${ss}`;\n}\n"],"names":[],"mappings":"AAKO,MAAM,eAAkB,GAAA;AAC/B,MAAM,YAAyD,GAAA;AAAA,EAC7D,KAAO,EAAA,OAAA;AAAA,EACP,QAAU,EAAA,UAAA;AAAA,EACV,MAAQ,EAAA,QAAA;AAAA,EACR,IAAM,EAAA,MAAA;AAAA,EACN,SAAW,EAAA;AACb,CAAA;AAGO,SAAS,eAAe,GAA6B,EAAA;AAC1D,EAAA,MAAM,QAAQ,CAAC,GAAA,CAAI,MAAM,GAAI,CAAA,IAAA,EAAM,IAAI,KAAO,EAAA,GAAA,CAAI,SAAS,CAAA,CAAE,IAAI,CAAK,CAAA,KAAA,CAAA,CAAE,MAAM,CAAA,CAAE,OAAO,OAAO,CAAA;AAC9F,EAAO,OAAA,CAAA,EAAG,MAAM,IAAK,CAAA,GAAG,CAAC,CAAK,EAAA,EAAA,YAAA,CAAa,GAAI,CAAA,MAAM,CAAC,CAAA,CAAA,CAAA;AACxD;AACO,SAAS,WAAW,IAA4B,EAAA;AACrD,EAAA,MAAM,KAAkB,GAAA,CAAC,IAAK,CAAA,KAAA,EAAO,eAAe,CAAA;AACpD,EAAM,MAAA,OAAA,GAAU,CAAC,OAAA,EAAiB,KAAoB,KAAA;AACpD,IAAI,IAAA,CAAC,MAAM,MAAQ,EAAA;AACnB,IAAM,KAAA,CAAA,IAAA,CAAK,EAAI,EAAA,OAAA,EAAS,GAAG,KAAA,CAAM,IAAI,CAAQ,IAAA,KAAA,CAAA,EAAA,EAAK,IAAI,CAAA,CAAE,CAAC,CAAA;AAAA,GAC3D;AACA,EAAQ,OAAA,CAAA,kBAAA,EAAoB,KAAK,SAAS,CAAA;AAC1C,EAAQ,OAAA,CAAA,YAAA,EAAc,KAAK,UAAU,CAAA;AACrC,EAAQ,OAAA,CAAA,WAAA,EAAa,KAAK,SAAS,CAAA;AACnC,EAAQ,OAAA,CAAA,YAAA,EAAc,KAAK,UAAU,CAAA;AACrC,EAAQ,OAAA,CAAA,MAAA,EAAQ,KAAK,IAAI,CAAA;AACzB,EAAA,OAAA,CAAQ,aAAe,EAAA,IAAA,CAAK,WAAY,CAAA,GAAA,CAAI,cAAc,CAAC,CAAA;AAC3D,EAAI,IAAA,IAAA,CAAK,SAAU,CAAA,IAAA,EAAQ,EAAA,KAAA,CAAM,IAAK,CAAA,EAAA,EAAI,WAAa,EAAA,IAAA,CAAK,SAAU,CAAA,IAAA,EAAM,CAAA;AAC5E,EAAO,OAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAGO,SAAS,eAAe,EAAoB,EAAA;AACjD,EAAM,MAAA,KAAA,GAAQ,KAAK,GAAI,CAAA,CAAA,EAAG,KAAK,KAAM,CAAA,EAAA,GAAK,GAAI,CAAC,CAAA;AAC/C,EAAA,MAAM,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,GAAQ,IAAI,CAAA;AACjC,EAAA,MAAM,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,GAAQ,OAAO,EAAE,CAAA;AACtC,EAAA,MAAM,IAAI,KAAQ,GAAA,EAAA;AAClB,EAAA,MAAM,KAAK,MAAO,CAAA,CAAC,CAAE,CAAA,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,OAAO,IAAI,CAAG,EAAA,CAAC,CAAI,CAAA,EAAA,MAAA,CAAO,CAAC,CAAE,CAAA,QAAA,CAAS,CAAG,EAAA,GAAG,CAAC,CAAI,CAAA,EAAA,EAAE,KAAK,CAAG,EAAA,CAAC,IAAI,EAAE,CAAA,CAAA;AACpE"}
1
+ {"version":3,"file":"noteText.js","sources":["../../../src/features/dictate/noteText.ts"],"sourcesContent":["/**\n * The note as plain text, for Copy and Share: section headings in capitals,\n * one item per line, the checks first so they cannot be missed once pasted,\n * and the transcript last, as the screen shows it under the note.\n */\nimport type { ClinicalNote, NoteMedication, NoteSuggestion, SuggestionKind } from './types';\n\nexport const NOTE_DISCLAIMER = 'AI draft from a dictation. Review before use.';\nexport const SUGGESTION_DISCLAIMER = 'AI suggestions for you to consider, not medical advice.';\n/** In the order the screen and the shared text show them. */\nexport const SUGGESTION_HEADINGS: Record<SuggestionKind, string> = {\n safety: 'Check for safety',\n missing: 'Missing from the note',\n coding: 'Coding',\n follow_up: 'Follow-up',\n};\n\nconst ACTION_LABEL: Record<NoteMedication['action'], string> = {\n start: 'start',\n continue: 'continue',\n change: 'change',\n stop: 'stop',\n mentioned: 'mentioned',\n};\n\n/** \"lisinopril 20 mg PO once daily (change)\" - only the parts that were dictated. */\nexport function medicationLine(med: NoteMedication): string {\n const parts = [med.name, med.dose, med.route, med.frequency].map((p) => p.trim()).filter(Boolean);\n return `${parts.join(' ')} (${ACTION_LABEL[med.action]})`;\n}\n\nexport function noteToText(note: ClinicalNote, transcript?: string, suggestions?: NoteSuggestion[] | null): string {\n const lines: string[] = [note.title, NOTE_DISCLAIMER];\n const section = (heading: string, items: string[]) => {\n if (!items.length) return;\n lines.push('', heading, ...items.map((item) => `- ${item}`));\n };\n section('CHECK BEFORE USE', note.to_verify);\n section('SUBJECTIVE', note.subjective);\n section('OBJECTIVE', note.objective);\n section('ASSESSMENT', note.assessment);\n section('PLAN', note.plan);\n section('MEDICATIONS', note.medications.map(medicationLine));\n if (note.follow_up.trim()) lines.push('', 'FOLLOW-UP', note.follow_up.trim());\n if (suggestions?.length) {\n lines.push('', 'SUGGESTIONS', SUGGESTION_DISCLAIMER);\n for (const kind of Object.keys(SUGGESTION_HEADINGS) as SuggestionKind[]) {\n const group = suggestions.filter((s) => s.kind === kind);\n if (group.length)\n lines.push(\n `${SUGGESTION_HEADINGS[kind]}:`,\n ...group.map((s) => `- ${s.text}${s.why ? ` (${s.why})` : ''}`),\n );\n }\n }\n if (transcript?.trim()) lines.push('', 'TRANSCRIPT', transcript.trim());\n return lines.join('\\n');\n}\n\n/** \"4:07\" or \"1:02:09\". */\nexport function formatDuration(ms: number): string {\n const total = Math.max(0, Math.floor(ms / 1000));\n const h = Math.floor(total / 3600);\n const m = Math.floor((total % 3600) / 60);\n const s = total % 60;\n const ss = String(s).padStart(2, '0');\n return h ? `${h}:${String(m).padStart(2, '0')}:${ss}` : `${m}:${ss}`;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ const PLACEHOLDER = /\[[A-Z]+_\d+\]/g;
21
+ const LABEL = {
22
+ NAME: "Name",
23
+ CLINICIAN: "Clinician",
24
+ FACILITY: "Facility",
25
+ ORG: "Organization",
26
+ DOB: "Birth date",
27
+ DATE: "Date",
28
+ AGE: "Age",
29
+ ID: "ID",
30
+ PHONE: "Phone",
31
+ EMAIL: "Email",
32
+ URL: "Link",
33
+ IP: "IP address",
34
+ ADDRESS: "Address"
35
+ };
36
+ function placeholderLabel(token) {
37
+ var _a;
38
+ const m = /^\[([A-Z]+)_(\d+)\]$/.exec(token);
39
+ if (!m) return token;
40
+ return `${(_a = LABEL[m[1]]) != null ? _a : m[1].charAt(0) + m[1].slice(1).toLowerCase()} ${m[2]}`;
41
+ }
42
+ function splitPlaceholders(text) {
43
+ var _a;
44
+ const runs = [];
45
+ let last = 0;
46
+ for (const m of text.matchAll(PLACEHOLDER)) {
47
+ const at = (_a = m.index) != null ? _a : 0;
48
+ if (at > last) runs.push({
49
+ text: text.slice(last, at),
50
+ placeholder: false
51
+ });
52
+ runs.push({
53
+ text: m[0],
54
+ placeholder: true
55
+ });
56
+ last = at + m[0].length;
57
+ }
58
+ if (last < text.length) runs.push({
59
+ text: text.slice(last),
60
+ placeholder: false
61
+ });
62
+ return runs;
63
+ }
64
+ function restoreText(text, identifiers) {
65
+ const byToken = new Map(identifiers.map((id) => [id.token, id.value]));
66
+ return text.replace(PLACEHOLDER, (token) => {
67
+ var _a;
68
+ return (_a = byToken.get(token)) != null ? _a : token;
69
+ });
70
+ }
71
+ function labelText(text) {
72
+ return text.replace(PLACEHOLDER, (token) => `[${placeholderLabel(token)}]`);
73
+ }
74
+ function mapNote(note, fn) {
75
+ return {
76
+ title: fn(note.title),
77
+ subjective: note.subjective.map(fn),
78
+ objective: note.objective.map(fn),
79
+ assessment: note.assessment.map(fn),
80
+ plan: note.plan.map(fn),
81
+ medications: note.medications.map((m) => __spreadProps(__spreadValues({}, m), {
82
+ name: fn(m.name),
83
+ dose: fn(m.dose),
84
+ route: fn(m.route),
85
+ frequency: fn(m.frequency)
86
+ })),
87
+ follow_up: fn(note.follow_up),
88
+ to_verify: note.to_verify.map(fn)
89
+ };
90
+ }
91
+ function mapSuggestions(items, fn) {
92
+ return items.map((s) => __spreadProps(__spreadValues({}, s), {
93
+ text: fn(s.text),
94
+ why: fn(s.why)
95
+ }));
96
+ }export{labelText,mapNote,mapSuggestions,placeholderLabel,restoreText,splitPlaceholders};//# sourceMappingURL=privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.js","sources":["../../../src/features/dictate/privacy.ts"],"sourcesContent":["/**\n * Placeholders in a dictation note. Before any AI reads a dictation, the\n * connector replaces each identifier (a name, a birth date, a phone number...)\n * with a placeholder such as \"[NAME_1]\" and hands back what each one stands\n * for. This phone keeps both: it shows the note with the identifiers hidden or\n * put back, and anything it sends to the AI later (suggestions) carries the\n * placeholders only.\n */\nimport type { ClinicalNote, NoteIdentifier, NoteSuggestion } from './types';\n\nconst PLACEHOLDER = /\\[[A-Z]+_\\d+\\]/g;\n\nconst LABEL: Record<string, string> = {\n NAME: 'Name',\n CLINICIAN: 'Clinician',\n FACILITY: 'Facility',\n ORG: 'Organization',\n DOB: 'Birth date',\n DATE: 'Date',\n AGE: 'Age',\n ID: 'ID',\n PHONE: 'Phone',\n EMAIL: 'Email',\n URL: 'Link',\n IP: 'IP address',\n ADDRESS: 'Address',\n};\n\n/** \"[NAME_1]\" -> \"Name 1\", how a hidden identifier reads on screen. */\nexport function placeholderLabel(token: string): string {\n const m = /^\\[([A-Z]+)_(\\d+)\\]$/.exec(token);\n if (!m) return token;\n return `${LABEL[m[1]] ?? m[1].charAt(0) + m[1].slice(1).toLowerCase()} ${m[2]}`;\n}\n\n/** The text in runs, each placeholder its own run, for drawing them apart. */\nexport function splitPlaceholders(text: string): Array<{ text: string; placeholder: boolean }> {\n const runs: Array<{ text: string; placeholder: boolean }> = [];\n let last = 0;\n for (const m of text.matchAll(PLACEHOLDER)) {\n const at = m.index ?? 0;\n if (at > last) runs.push({ text: text.slice(last, at), placeholder: false });\n runs.push({ text: m[0], placeholder: true });\n last = at + m[0].length;\n }\n if (last < text.length) runs.push({ text: text.slice(last), placeholder: false });\n return runs;\n}\n\n/** Each placeholder put back to what it stands for; one this phone does not know stays. */\nexport function restoreText(text: string, identifiers: NoteIdentifier[]): string {\n const byToken = new Map(identifiers.map((id) => [id.token, id.value]));\n return text.replace(PLACEHOLDER, (token) => byToken.get(token) ?? token);\n}\n\n/** Each placeholder as its label in brackets, for text that leaves the phone hidden (\"[Name 1]\"). */\nexport function labelText(text: string): string {\n return text.replace(PLACEHOLDER, (token) => `[${placeholderLabel(token)}]`);\n}\n\nexport function mapNote(note: ClinicalNote, fn: (text: string) => string): ClinicalNote {\n return {\n title: fn(note.title),\n subjective: note.subjective.map(fn),\n objective: note.objective.map(fn),\n assessment: note.assessment.map(fn),\n plan: note.plan.map(fn),\n medications: note.medications.map((m) => ({\n ...m,\n name: fn(m.name),\n dose: fn(m.dose),\n route: fn(m.route),\n frequency: fn(m.frequency),\n })),\n follow_up: fn(note.follow_up),\n to_verify: note.to_verify.map(fn),\n };\n}\n\nexport function mapSuggestions(items: NoteSuggestion[], fn: (text: string) => string): NoteSuggestion[] {\n return items.map((s) => ({ ...s, text: fn(s.text), why: fn(s.why) }));\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AASA,MAAM,WAAc,GAAA,iBAAA;AACpB,MAAM,KAAgC,GAAA;AAAA,EACpC,IAAM,EAAA,MAAA;AAAA,EACN,SAAW,EAAA,WAAA;AAAA,EACX,QAAU,EAAA,UAAA;AAAA,EACV,GAAK,EAAA,cAAA;AAAA,EACL,GAAK,EAAA,YAAA;AAAA,EACL,IAAM,EAAA,MAAA;AAAA,EACN,GAAK,EAAA,KAAA;AAAA,EACL,EAAI,EAAA,IAAA;AAAA,EACJ,KAAO,EAAA,OAAA;AAAA,EACP,KAAO,EAAA,OAAA;AAAA,EACP,GAAK,EAAA,MAAA;AAAA,EACL,EAAI,EAAA,YAAA;AAAA,EACJ,OAAS,EAAA;AACX,CAAA;AAGO,SAAS,iBAAiB,KAAuB,EAAA;AA3BxD,EAAA,IAAA,EAAA;AA4BE,EAAM,MAAA,CAAA,GAAI,sBAAuB,CAAA,IAAA,CAAK,KAAK,CAAA;AAC3C,EAAI,IAAA,CAAC,GAAU,OAAA,KAAA;AACf,EAAO,OAAA,CAAA,EAAA,CAAG,EAAM,GAAA,KAAA,CAAA,CAAA,CAAE,CAAC,CAAC,MAAV,IAAe,GAAA,EAAA,GAAA,CAAA,CAAE,CAAC,CAAA,CAAE,MAAO,CAAA,CAAC,IAAI,CAAE,CAAA,CAAC,CAAE,CAAA,KAAA,CAAM,CAAC,CAAA,CAAE,aAAa,CAAA,CAAA,EAAI,CAAE,CAAA,CAAC,CAAC,CAAA,CAAA;AAC/E;AAGO,SAAS,kBAAkB,IAG/B,EAAA;AArCH,EAAA,IAAA,EAAA;AAsCE,EAAA,MAAM,OAGD,EAAC;AACN,EAAA,IAAI,IAAO,GAAA,CAAA;AACX,EAAA,KAAA,MAAW,CAAK,IAAA,IAAA,CAAK,QAAS,CAAA,WAAW,CAAG,EAAA;AAC1C,IAAM,MAAA,EAAA,GAAA,CAAK,EAAE,GAAA,CAAA,CAAA,KAAA,KAAF,IAAW,GAAA,EAAA,GAAA,CAAA;AACtB,IAAI,IAAA,EAAA,GAAK,IAAM,EAAA,IAAA,CAAK,IAAK,CAAA;AAAA,MACvB,IAAM,EAAA,IAAA,CAAK,KAAM,CAAA,IAAA,EAAM,EAAE,CAAA;AAAA,MACzB,WAAa,EAAA;AAAA,KACd,CAAA;AACD,IAAA,IAAA,CAAK,IAAK,CAAA;AAAA,MACR,IAAA,EAAM,EAAE,CAAC,CAAA;AAAA,MACT,WAAa,EAAA;AAAA,KACd,CAAA;AACD,IAAO,IAAA,GAAA,EAAA,GAAK,CAAE,CAAA,CAAC,CAAE,CAAA,MAAA;AAAA;AAEnB,EAAA,IAAI,IAAO,GAAA,IAAA,CAAK,MAAQ,EAAA,IAAA,CAAK,IAAK,CAAA;AAAA,IAChC,IAAA,EAAM,IAAK,CAAA,KAAA,CAAM,IAAI,CAAA;AAAA,IACrB,WAAa,EAAA;AAAA,GACd,CAAA;AACD,EAAO,OAAA,IAAA;AACT;AAGgB,SAAA,WAAA,CAAY,MAAc,WAAuC,EAAA;AAC/E,EAAA,MAAM,OAAU,GAAA,IAAI,GAAI,CAAA,WAAA,CAAY,GAAI,CAAA,CAAA,EAAA,KAAM,CAAC,EAAA,CAAG,KAAO,EAAA,EAAA,CAAG,KAAK,CAAC,CAAC,CAAA;AACnE,EAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,WAAA,EAAa,CAAM,KAAA,KAAA;AAjEzC,IAAA,IAAA,EAAA;AAiE4C,IAAQ,OAAA,CAAA,EAAA,GAAA,OAAA,CAAA,GAAA,CAAI,KAAK,CAAA,KAAjB,IAAsB,GAAA,EAAA,GAAA,KAAA;AAAA,GAAK,CAAA;AACvE;AAGO,SAAS,UAAU,IAAsB,EAAA;AAC9C,EAAO,OAAA,IAAA,CAAK,QAAQ,WAAa,EAAA,CAAA,KAAA,KAAS,IAAI,gBAAiB,CAAA,KAAK,CAAC,CAAG,CAAA,CAAA,CAAA;AAC1E;AACgB,SAAA,OAAA,CAAQ,MAAoB,EAA4C,EAAA;AACtF,EAAO,OAAA;AAAA,IACL,KAAA,EAAO,EAAG,CAAA,IAAA,CAAK,KAAK,CAAA;AAAA,IACpB,UAAY,EAAA,IAAA,CAAK,UAAW,CAAA,GAAA,CAAI,EAAE,CAAA;AAAA,IAClC,SAAW,EAAA,IAAA,CAAK,SAAU,CAAA,GAAA,CAAI,EAAE,CAAA;AAAA,IAChC,UAAY,EAAA,IAAA,CAAK,UAAW,CAAA,GAAA,CAAI,EAAE,CAAA;AAAA,IAClC,IAAM,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,EAAE,CAAA;AAAA,IACtB,aAAa,IAAK,CAAA,WAAA,CAAY,GAAI,CAAA,CAAA,CAAA,KAAM,iCACnC,CADmC,CAAA,EAAA;AAAA,MAEtC,IAAA,EAAM,EAAG,CAAA,CAAA,CAAE,IAAI,CAAA;AAAA,MACf,IAAA,EAAM,EAAG,CAAA,CAAA,CAAE,IAAI,CAAA;AAAA,MACf,KAAA,EAAO,EAAG,CAAA,CAAA,CAAE,KAAK,CAAA;AAAA,MACjB,SAAA,EAAW,EAAG,CAAA,CAAA,CAAE,SAAS;AAAA,KACzB,CAAA,CAAA;AAAA,IACF,SAAA,EAAW,EAAG,CAAA,IAAA,CAAK,SAAS,CAAA;AAAA,IAC5B,SAAW,EAAA,IAAA,CAAK,SAAU,CAAA,GAAA,CAAI,EAAE;AAAA,GAClC;AACF;AACgB,SAAA,cAAA,CAAe,OAAyB,EAAgD,EAAA;AACtG,EAAA,OAAO,KAAM,CAAA,GAAA,CAAI,CAAM,CAAA,KAAA,aAAA,CAAA,cAAA,CAAA,EAAA,EAClB,CADkB,CAAA,EAAA;AAAA,IAErB,IAAA,EAAM,EAAG,CAAA,CAAA,CAAE,IAAI,CAAA;AAAA,IACf,GAAA,EAAK,EAAG,CAAA,CAAA,CAAE,GAAG;AAAA,GACb,CAAA,CAAA;AACJ"}
@@ -0,0 +1,24 @@
1
+ import {mapSuggestions,restoreText,mapNote}from'./privacy.js';function shownNote(record, note, showIdentifiers) {
2
+ var _a, _b, _c, _d, _e, _f;
3
+ const {
4
+ redaction
5
+ } = record;
6
+ if (!redaction) return {
7
+ note,
8
+ transcript: (_a = record.transcript) != null ? _a : "",
9
+ suggestions: null
10
+ };
11
+ const items = (_c = (_b = record.suggestions) == null ? void 0 : _b.items) != null ? _c : null;
12
+ if (!showIdentifiers) return {
13
+ note: redaction.note,
14
+ transcript: redaction.transcript,
15
+ suggestions: items
16
+ };
17
+ const identifiers = [...redaction.identifiers, ...(_e = (_d = record.suggestions) == null ? void 0 : _d.identifiers) != null ? _e : []];
18
+ const restore = (text) => restoreText(text, identifiers);
19
+ return {
20
+ note: mapNote(redaction.note, restore),
21
+ transcript: (_f = record.transcript) != null ? _f : restore(redaction.transcript),
22
+ suggestions: items ? mapSuggestions(items, restore) : null
23
+ };
24
+ }export{shownNote};//# sourceMappingURL=shownNote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shownNote.js","sources":["../../../src/features/dictate/shownNote.ts"],"sourcesContent":["/**\n * The note as the clinician chose to see it: identifiers hidden (what the AI\n * saw) or put back. A note written before identifiers were hidden has only\n * the one version.\n */\nimport { mapNote, mapSuggestions, restoreText } from './privacy';\nimport type { ClinicalNote, DictationRecord, NoteSuggestion } from './types';\n\nexport type SuggestState = { status: 'idle' } | { status: 'loading' } | { status: 'error'; message: string };\n\nexport interface ShownNote {\n note: ClinicalNote;\n transcript: string;\n /** null until suggestions were asked for (and always for a note written before hiding). */\n suggestions: NoteSuggestion[] | null;\n}\n\nexport function shownNote(record: DictationRecord, note: ClinicalNote, showIdentifiers: boolean): ShownNote {\n const { redaction } = record;\n if (!redaction) return { note, transcript: record.transcript ?? '', suggestions: null };\n const items = record.suggestions?.items ?? null;\n if (!showIdentifiers) return { note: redaction.note, transcript: redaction.transcript, suggestions: items };\n const identifiers = [...redaction.identifiers, ...(record.suggestions?.identifiers ?? [])];\n const restore = (text: string) => restoreText(text, identifiers);\n return {\n note: mapNote(redaction.note, restore),\n transcript: record.transcript ?? restore(redaction.transcript),\n suggestions: items ? mapSuggestions(items, restore) : null,\n };\n}\n"],"names":[],"mappings":"8DAqBgB,SAAA,SAAA,CAAU,MAAyB,EAAA,IAAA,EAAoB,eAAqC,EAAA;AArB5G,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAsBE,EAAM,MAAA;AAAA,IACJ;AAAA,GACE,GAAA,MAAA;AACJ,EAAI,IAAA,CAAC,WAAkB,OAAA;AAAA,IACrB,IAAA;AAAA,IACA,UAAA,EAAA,CAAY,EAAO,GAAA,MAAA,CAAA,UAAA,KAAP,IAAqB,GAAA,EAAA,GAAA,EAAA;AAAA,IACjC,WAAa,EAAA;AAAA,GACf;AACA,EAAA,MAAM,KAAQ,GAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,MAAA,CAAO,WAAP,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAoB,UAApB,IAA6B,GAAA,EAAA,GAAA,IAAA;AAC3C,EAAI,IAAA,CAAC,iBAAwB,OAAA;AAAA,IAC3B,MAAM,SAAU,CAAA,IAAA;AAAA,IAChB,YAAY,SAAU,CAAA,UAAA;AAAA,IACtB,WAAa,EAAA;AAAA,GACf;AACA,EAAA,MAAM,WAAc,GAAA,CAAC,GAAG,SAAA,CAAU,WAAa,EAAA,GAAA,CAAI,EAAO,GAAA,CAAA,EAAA,GAAA,MAAA,CAAA,WAAA,KAAP,IAAoB,GAAA,MAAA,GAAA,EAAA,CAAA,WAAA,KAApB,IAAmC,GAAA,EAAA,GAAA,EAAG,CAAA;AACzF,EAAA,MAAM,OAAU,GAAA,CAAC,IAAiB,KAAA,WAAA,CAAY,MAAM,WAAW,CAAA;AAC/D,EAAO,OAAA;AAAA,IACL,IAAM,EAAA,OAAA,CAAQ,SAAU,CAAA,IAAA,EAAM,OAAO,CAAA;AAAA,IACrC,aAAY,EAAO,GAAA,MAAA,CAAA,UAAA,KAAP,IAAqB,GAAA,EAAA,GAAA,OAAA,CAAQ,UAAU,UAAU,CAAA;AAAA,IAC7D,WAAa,EAAA,KAAA,GAAQ,cAAe,CAAA,KAAA,EAAO,OAAO,CAAI,GAAA;AAAA,GACxD;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminide-stack/yantra-mobile",
3
- "version": "12.0.141",
3
+ "version": "12.0.142",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -27,7 +27,7 @@
27
27
  "uuid": "^9.0.0"
28
28
  },
29
29
  "devDependencies": {
30
- "common": "^12.0.141",
30
+ "common": "12.0.141",
31
31
  "libphonenumber-js": "^1.13.3"
32
32
  },
33
33
  "peerDependencies": {
@@ -45,7 +45,7 @@
45
45
  "@messenger-box/platform-mobile": "*",
46
46
  "@react-native-async-storage/async-storage": "*",
47
47
  "@react-navigation/native": "*",
48
- "common": "12.0.139",
48
+ "common": "12.0.141",
49
49
  "expo-background-task": "*",
50
50
  "expo-constants": "*",
51
51
  "expo-secure-store": "*",
@@ -67,5 +67,5 @@
67
67
  "typescript": {
68
68
  "definition": "lib/index.d.ts"
69
69
  },
70
- "gitHead": "83758e82e8d73fe2a09a01da52ba758f1cdf1ad1"
70
+ "gitHead": "80980b8e928ffa364accf4aa00afa3a0d18b1ce1"
71
71
  }