I'm encountering an error while working on my React Native application.
When I attempt to transform the HTML content of a page into a PDF for export and client email, I receive the following error:
Error: Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported.
The backend API is built in ASP.NET Core 8. The page I am trying to convert to PDF contains a client's signature, and the application will be used on both Android and iOS devices.
This is the page that I want to export:
import React, { useState, useEffect, useRef } from "react";
import {
View,
Text,
Image,
StyleSheet,
ScrollView,
TextInput,
Button,
Alert,
TouchableOpacity,
Modal,
Switch,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
import { useAppContext } from "../../AppContext";
import { getCurrentDate } from "../helpers/DateHelper";
import SignatureSpace from "../components/SignatureSpace";
import { error } from "pdf-lib";
const DataScreen = () => {
const {
cardHolderName,
userID,
email,
phoneNumber,
address,
locality,
postalCode,
county,
barcodeData,
registrationType,
fiscalCode,
globalRegistrationType,
companyNameData,
} = useAppContext();
const navigation = useNavigation();
const pageRefAll = useRef(null);
const signatureRef = useRef(null);
const [signatureData, setSignatureData] = useState(null);
const [isButtonEnabled, setIsButtonEnabled] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const [form, setForm] = useState({
date: "",
communicationChannel: [],
});
// .............
useEffect(() => {
const allFieldsCompleted = signatureData !== null;
setIsButtonEnabled(allFieldsCompleted);
}, [signatureData]);
const sendCardToEmail = async () => {
try {
let emailBody =
`Hello, ${cardHolderName}\nHere are your registration details:\n` +
`Email: ${email}\n` +
`Phone Number: ${phoneNumber}\n` +
`Address: ${address}, ${postalCode}, ${locality}, ${county}`;
if (registrationType === "business") {
emailBody += `\nFiscal Code: ${fiscalCode}`;
}
const emailDetails = {
name: cardHolderName,
fiscalCode: fiscalCode,
email: email,
phoneNumber: phoneNumber,
barcode: barcodeData,
registrationType: registrationType,
address: `${address}, ${postalCode}, ${locality}, ${county}`,
body: emailBody,
};
const response = await fetch(
"https://flowermarketapi.azurewebsites.net/Clients/send-email",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(emailDetails),
}
);
if (response.ok) {
console.log("Email sent successfully!");
} else {
console.error("Failed to send email. " + (await response.text()));
}
} catch (error) {
console.error("Error sending email", error);
}
};
const handleSubmit = async () => {
if (!isButtonEnabled) return;
// sendCardToEmail();
// navigation.navigate("Card");
const gdprHtmlString = `
<div class="dataScreen">
>! here is the text that will be sent to API in order to convert and send via email
</div>`;
console.log("GDPR " + { companyNameData } + ".pdf");
const blob = dataURItoBlob(signatureData);
console.log("signatureData", signatureData);
const formData = new FormData();
console.log("FormData", FormData);
try {
formData.append("model", gdprHtmlString);
console.log("model", gdprHtmlString); // here is stop the application and not move forward
formData.append("signature", blob);
console.log("signature", blob);
formData.append("userID", userID);
console.log("userID", userID);
formData.append("fileNameftp", companyNameData);
console.log("fileNameftp", companyNameData);
} catch (error) {
console.log("Error during creating PDF: ", error);
}
try {
// Send the request with both form data and JSON data
const response1 = await fetch(
"https://flowermarketapi.azurewebsites.net/api/fileupload/export",
{
method: "POST",
body: formData,
}
);
if (response1.ok) {
console.log("response ok");
}
} catch (error) {
console.log("Error during loading: ", error);
}
try {
sendCardToEmail();
navigation.navigate("Card");
} catch (error) {
console.error("Error during submission: ", error);
Alert.alert(
"Error",
"There was an error during submission: " + error.message
);
}
};
function dataURItoBlob(dataURI) {
const byteString = atob(dataURI.split(",")[1]);
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
return (
<ScrollView contentContainerStyle={styles.dataScreen}>
<View style={styles.dataContainer} ref={pageRefAll}>
<View style={styles.dataHeader}>
<Image
source={require("../../assets/logo-dark 600.png")}
style={styles.dataLogo}
resizeMode="contain"
onError={(error) => console.log("Image load error: ", error)}
onLoad={() => console.log("Image loaded successfully")}
/>
<Text style={styles.companyName}>FLOWERS MARKET HOLLAND S.R.L.</Text>
>! ............. the text that will be sent to the client .................
>! ..........................
>! ..........................
<View style={styles.signatureContainer}>
<View style={styles.signatureSection}>
<Text style={styles.labelTop}>{getCurrentDate(".")}</Text>
<Text style={styles.labelTop}>{companyNameData}</Text>
<Text style={styles.labelTop}>{cardHolderName}</Text>
<TouchableOpacity
style={styles.clientSignature}
onPress={handleSignatureOpen}
>
{signatureData ? (
<Image
source={{ uri: signatureData }}
style={{ width: "100%", height: "100%" }}
/>
) : (
<Text>Sign Here</Text>
)}
</TouchableOpacity>
</View>
{signatureData && (
<View style={styles.signatureContainer}>
{/* <Text>Signature Captured:</Text> */}
<Image
source={{ uri: signatureData }}
style={styles.signatureImage}
/>
</View>
)}
<Modal
visible={isModalVisible}
animationType="slide"
onRequestClose={handleSignatureClose}
>
<SignatureSpace
ref={signatureRef}
onSave={handleSignatureSave}
onClose={handleSignatureClose}
/>
</Modal>
</View>
</View>
</View>
<TouchableOpacity
style={[
styles.acceptButton,
!isButtonEnabled && styles.disabledButton,
]}
onPress={handleSubmit}
disabled={!isButtonEnabled}
>
<Text style={styles.buttonText}>Accept and Continue</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
};
The package-json look like this:
{
"name": "my-project",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@kichiyaki/react-native-barcode-generator": "^0.6.7",
"@react-native-masked-view/masked-view": "^0.3.1",
"@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.17",
"@react-navigation/stack": "^6.3.29",
"expo": "~51.0.9",
"expo-dev-client": "~4.0.15",
"expo-status-bar": "~1.12.1",
"pdf-lib": "^1.17.1",
"react": "18.2.0",
"react-native": "0.74.1",
"react-native-barcode-builder": "^2.0.0",
"react-native-barcode-creator": "^0.1.7",
"react-native-gesture-handler": "^2.16.2",
"react-native-image-picker": "^7.1.2",
"react-native-safe-area-context": "^4.10.3",
"react-native-screens": "^3.31.1",
"react-native-signature-canvas": "^4.7.2",
"react-native-svg": "^15.3.0",
"react-native-view-shot": "^3.8.0",
"react-native-webview": "^13.8.6"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}
I tried to adding more logging to the console in order to see where it stops, and discovered that it stops in the handleSubmit function:
console.log("model", gdprHtmlString);
The app runs on a tablet emulator from Android Studio because the client requires this technology. I need help finding a solution to send the client the page's content in a PDF with his signature.