Skip to content
Open
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
5 changes: 4 additions & 1 deletion packages/jsActions/nanoflow-actions-native/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Fixed

- We've fixed a synchronization issue with Base64 images generated by the Signature widget.

## [5.2.0] Nanoflow Commons - 2026-1-23

- We've migrated from using @react-native-community/geolocation to react-native-permissions for handling location permissions.
-

## [5.1.6] Nanoflow Commons - 2025-12-05

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Base64 } from "js-base64";
import RNBlobUtil from "react-native-blob-util";

// BEGIN EXTRA CODE
// END EXTRA CODE
Expand All @@ -16,7 +17,7 @@ import { Base64 } from "js-base64";
* @param {MxObject} image
* @returns {Promise.<boolean>}
*/
export function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject): Promise<boolean> {
export async function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject): Promise<boolean> {
// BEGIN USER CODE

if (!base64) {
Expand All @@ -26,11 +27,52 @@ export function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject):
throw new Error("image should not be null");
}

const blob = new Blob([Base64.toUint8Array(base64)], { type: "image/png" });
// Native platform
if (navigator && navigator.product === "ReactNative") {
try {
// Remove data URI prefix if present (e.g., "data:image/png;base64,")
let cleanBase64 = base64;
if (base64.includes(",")) {
cleanBase64 = base64.split(",")[1];
}

// Remove any whitespace/newlines
cleanBase64 = cleanBase64.replace(/\s/g, "");

// Validate base64 format
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) {
throw new Error("Invalid base64 format");
}

// Create a temporary file path
const tempPath = `${RNBlobUtil.fs.dirs.CacheDir}/temp_image_${Date.now()}.png`;

// Write Base64 data to a temporary file
await RNBlobUtil.fs.writeFile(tempPath, cleanBase64, "base64");

// Fetch the file as a blob
const res = await fetch(`file://${tempPath}`);
const blob = await res.blob();

return new Promise((resolve, reject) => {
mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => {
RNBlobUtil.fs.unlink(tempPath).catch(() => { });
resolve(true);
}, (error) => {
RNBlobUtil.fs.unlink(tempPath).catch(() => { });
reject(error);
});
});
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to decode base64 to image: ${errorMessage}`);
}
}

// Other platforms
const blob = new Blob([Base64.toUint8Array(base64)], { type: "image/png" });
return new Promise((resolve, reject) => {
mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => resolve(true), reject);
});

// END USER CODE
}
Loading