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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions formulus-formplayer/src/mocks/webview-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,12 @@ class WebViewMock {
this.showAudioSimulationPopup(fieldId);
});
},
getAttachmentUri: (_fileName: string): Promise<string | null> => {
console.log(
'[WebView Mock] getAttachmentUri (browser dev: no local files)',
);
return Promise.resolve(null);
},
launchIntent: (
fieldId: string,
intentData: Record<string, any>,
Expand Down
46 changes: 35 additions & 11 deletions formulus-formplayer/src/renderers/PhotoQuestionRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,42 @@ const PhotoQuestionRenderer: React.FC<PhotoQuestionProps> = ({
// Get the current photo data from the form data (now JSON format)
const currentPhotoData = data || null;

// Set photo URL from stored data if available
// Prefer uri; else resolve basename via bridge (draft → committed → pending upload)
useEffect(() => {
console.log('Photo data changed:', currentPhotoData);
if (currentPhotoData?.uri) {
// For WebView, we need to handle file:// URLs differently
// In development/mock mode, file URLs might work, but in production we need a different approach
console.log('Setting photo URL from stored data:', currentPhotoData.uri);
setPhotoUrl(currentPhotoData.uri);
} else {
console.log('No photo URI found, clearing photoUrl state');
setPhotoUrl(null);
}
let cancelled = false;
const run = async () => {
console.log('Photo data changed:', currentPhotoData);
if (currentPhotoData?.uri) {
const u = currentPhotoData.uri;
const display =
u.startsWith('file://') || u.startsWith('http') ? u : `file://${u}`;
console.log('Setting photo URL from stored data:', display);
if (!cancelled) setPhotoUrl(display);
return;
}
if (currentPhotoData?.filename) {
const resolved = await formulusClient.current.getAttachmentUri(
currentPhotoData.filename,
);
if (!cancelled) {
setPhotoUrl(resolved);
console.log(
'Resolved photo from filename:',
currentPhotoData.filename,
resolved,
);
}
return;
}
if (!cancelled) {
console.log('No photo URI or filename, clearing photoUrl state');
setPhotoUrl(null);
}
};
void run();
return () => {
cancelled = true;
};
}, [currentPhotoData]);

// Handle camera request with new Promise-based approach
Expand Down
12 changes: 12 additions & 0 deletions formulus-formplayer/src/services/FormulusInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ class FormulusClient {
} as CameraResult);
}

/**
* Resolve an attachment basename to a WebView-loadable URL (draft, committed, or pending upload).
*/
public async getAttachmentUri(fileName: string): Promise<string | null> {
await this.tryEnsureFormulus();
if (this.formulus) {
return this.formulus.getAttachmentUri(fileName);
}
console.warn('Formulus interface not available for getAttachmentUri');
return null;
}

/**
* Request location from the Formulus RN app.
* The shared interface no longer returns a typed LocationResult; this
Expand Down
7 changes: 4 additions & 3 deletions formulus-formplayer/src/types/FormulusInterfaceDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,9 @@ export interface FormulusInterface {

/**
* Resolve a synced or camera-saved attachment to a WebView-loadable `file://` URL.
* Checks `{DocumentDirectory}/attachments/` and `pending_upload/`. Pass the basename only
* (e.g. `photo.filename` from observation data); path segments and ".." are rejected.
* Checks `{DocumentDirectory}/attachments/draft/` (unsaved capture), then `attachments/`,
* then `pending_upload/`. Pass the basename only (e.g. `photo.filename` from observation
* data); path segments and ".." are rejected.
* @param fileName - Attachment file basename
* @returns `file://` URL if the file exists, otherwise `null`
*/
Expand Down Expand Up @@ -494,7 +495,7 @@ export interface FormulusCallbacks {
/**
* Current version of the interface
*/
export const FORMULUS_INTERFACE_VERSION = '1.2.0';
export const FORMULUS_INTERFACE_VERSION = '1.2.1';

/** Parses major.minor.patch from the start of a version string (ignores prerelease after `-`). */
function semverSegments(version: string): [number, number, number] {
Expand Down
Loading
Loading