Using Experimental Chrome API in React? - reactjs

I am trying to use Chrome nfc api (WEB NFC) inside of react, so when you open the react page on mobile with nfc enabled and press a button it check to see if nfc scan.
I was reading through the doc and the sample code to do this is,
scanButton.addEventListener("click", async () => {
log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
log("> Scan started");
ndef.addEventListener("readingerror", () => {
log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
log(`> Serial Number: ${serialNumber}`);
log(`> Records: (${message.records.length})`);
});
} catch (error) {
log("Argh! " + error);
}
});
My react page is currently,
import { Button } from "#material-ui/core";
import React from "react";
const nfcpage = () => {
return (
<>
<Button
id = "scanButton"
>
Press to test NFC
</Button>
</>
);
};
export default nfcpage;
I want the scanButton code to run when the button is pressed. In other words to make scanButton into a function that can be called by my button via onClick{}.
Thank you

I was able to fix this by creating an async function from the sample code and passing that to onClick in the button component

Related

React - How to get unit test coverage for toggling open a popover that uses state or determine if it should be open

I'm trying to get unit test coverage for the code in red (see screenshot) using react-testing-library. Would anyone know what unit test would cover this? I'm still learning the react-testing-library. TIA
screenshot of code here showing red, uncovered code
If you don't open the screenshot above, the code inside this function is what needs to be covered.
const togglePopover = () => {
setToolTipOpen((prev) => !prev);
};
actual full component code block:
import React, { FunctionComponent, useState, KeyboardEvent, useRef, useEffect } from 'react';
import styles from './InfoPopover.module.scss';
import { Popover, PopoverBody } from 'x'
import { PopperPlacementType } from '#material-ui/core';
import { ReactComponent as InfoIcon } from '../../../assets/icons/tooltipIcon.svg';
export interface PopperProps {
placement?: PopperPlacementType;
tipMessage: React.ReactNode | string;
stringedTipMessage: string;
}
const InfoPopover: FunctionComponent<PopperProps> = ({
placement,
tipMessage,
stringedTipMessage
}: PopperProps) => {
const [toolTipOpen, setToolTipOpen] = useState(false);
const togglePopover = () => {
setToolTipOpen((prev) => !prev);
};
const handleBlur = () => {
setToolTipOpen(false);
};
return (
<>
<button
id="popoverTarget"
className={styles.tooltipButton}
onBlur={handleBlur}
aria-label={`Tooltip Content - ${stringedTipMessage}`}
>
<InfoIcon aria-label="status tooltip" />
</button>
<Popover
target="popoverTarget"
trigger="legacy"
toggle={togglePopover}
placement={placement}
isOpen={toolTipOpen}
arrowClassName={styles.toolTipArrow}
popperClassName={styles.toolTipPopout}
>
<PopoverBody>{tipMessage}</PopoverBody>
</Popover>
</>
);
};
export default InfoPopover;
With React Testing Library, the approach is to test what the user can see/do rather than test the internals of your application.
With your example, assuming you are trying to test a simple open/close popup user flow then the user would be seeing a button, and when they activate that button they would see a popover. A simple RTL approach would be as follows:
const popoverTipMessage = "My popover message";
render(<InfoPopover tipMessage={popoverTipMessage} />);
// Popover isn't activated, so it shouldn't be in the DOM
expect(screen.getByText(popoverTipMessage)).not.toBeInDocument();
// Find button and click it to show the Popover
fireEvent.click(screen.getByRole('button', {
name: /tooltip content/i
}));
// Popover should now be activated, so check if it's visible (in the DOM)
await waitFor(() => {
// This relies on RTL's text matching to find the component.
expect(screen.getByText(popoverTipMessage)).toBeInDocument();
});
// Find button and click it again to hide the Popover
fireEvent.click(screen.getByRole('button', {
name: /tooltip content/i
}));
// Popover should now be hidden, so check if the DOM element has gone
// Note: There are other ways of checking appearance/disappearance. Check the RTL docs.
await waitFor(() => {
// This relies on RTL's text matching to find the component but there are other better ways to find an element
expect(screen.getByText(popoverTipMessage)).not.toBeInDocument();
});
The query methods I've used above are some of the basic ones, however RTL has many different queries to find the element you need to target. It has accessibility at the forefront of its design so leans heavily on these. Take a look in the docs: https://testing-library.com/docs/react-testing-library/example-intro

Laser Barcode Scanner Issue in React (Expo)

Is it possible using laser barcode scanner in expo?
i did something like this , but i cant make it to work.
Basicly im trying to get the scanned data from PDA(android) device , that when i click to scan on PDA i get info to a console log per example to test it ,later on i will need that data to spread to a specific number of inputboxes.
Right now when i clicked on the scan button nothing happens but if i try to use a phone with a camera it works without the click function.
import { Text, View, StyleSheet, Button } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
export default function App() {
const [scanned, setScanned] = useState(false);
const handleBarCodeScanned = ({ data }) => {
setScanned(true);
alert(`${data}`);
};
const handleKeyPress = (event) => {
if(event.key === 'Enter'){
handleBarCodeScanned
}
};
return (
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleKeyPress}
></BarCodeScanner>
);
}```

Stripe payment button for ReactJs with a simple Snippet Code

I have found a lot of repositories and examples about installing an Stripe complete checkout, but I cannot just use the simple Snippet code that Stripe offers for a product. How can I use that code on a page in my React Project? Here is the code. I just want to redirect the user to the Stripe checkout page for that product, I don't want to use my own formulary and I don't want either to collect data in my app. Thanks a lot.
<!-- Load Stripe.js on your website. -->
<script src="https://js.stripe.com/v3"></script>
<!-- Create a button that your customers click to complete their purchase. Customize the styling to suit your branding. -->
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em"
id="checkout-button-price_1Heree568gerg54rtretrt"
role="link"
type="button"
>
Checkout
</button>
<div id="error-message"></div>
<script>
(function() {
var stripe = Stripe('pk_live_t5tyutrytutruytyutyufake....');
var checkoutButton = document.getElementById('checkout-button-price_1Heree568gerg54rtretrt');
checkoutButton.addEventListener('click', function () {
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
lineItems: [{price: 'price_1Heree568gerg54rtretrt', quantity: 1}],
mode: 'subscription',
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/payments/checkout/fulfill-orders
successUrl: 'https://myweb.com/success',
cancelUrl: 'https://myweb.com/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();
</script>
You can create a dedicated component for that. As stated in the documentation, I am using StripeJS to import it as a module.
// npm install #stripe/stripe-js
import React from 'react';
import {loadStripe} from '#stripe/stripe-js';
const StripeButton = (props) => {
const [stripeError, setStripeError] = React.useState(null);
const [stripe, setStripe] = React.useState(null);
useEffect( async () => {
if (!stripe) {
// Here, you can use some `props` instead of hardcoding the API key
const stripeTmp = await loadStripe('pk_live_t5tyutrytutruytyutyufake....');
setStripe(stripeTmp);
}
});
const handleClick = () => {
// Reset error holder
setStripeError(null);
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
// Here you can use another `prop` instead of hard coding it
lineItems: [{price: 'price_1Heree568gerg54rtretrt', quantity: 1}],
mode: 'subscription',
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/payments/checkout/fulfill-orders
successUrl: 'https://myweb.com/success',
cancelUrl: 'https://myweb.com/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
setStripeError(result.error.message);
}
});
}
return (
<>
{ stripe ? (
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px ;border:0;border-radius:4px;font-size:1em"
id="checkout-button-price_1Heree568gerg54rtretrt"
role="link"
type="button"
onClick={ handleClick }
>
Checkout
</button>
) : "Loading..."
}
{ stripeError ? <div id="error-message">{ stripeError }</div> : null }
</>
)
}
export default StripeButton;

expo SMS.sendSMSAsync inside a loop pops sms modal and immediately closing

I'm trying to send a text message using expo-sms, the problem is when the sms modal is open to send the message - it immediately closing and the result of SMS.sendSMSAsync is cancelled.
my code is this:
<TouchableOpacity onPress={() => handleSend(contacts, text)}>{...}</TouchableOpacity>
async function handleSend(contacts, text) {
try {
const numbersArr = contacts.map(c => c.number)
while (numbersArr.length > 0) {
const number = numbersArr.pop()
const { result } = await SMS.sendSMSAsync(number, text)
// 'result' here is 'canceled' for each number
}
showMessagesSuccessfullySentMessage()
} catch (e) {
console.error(e)
showSmsSendingProblemError()
}
}
SMS sending is available, of course, I do the check in advanced using useEffect when the component is mounted:
useEffect(() => {
;(async function() {
const isAvailable = await SMS.isAvailableAsync()
setIsSmsAllowed(isAvailable)
})()
}, [])
what am I doing wrong? what did I miss?
Moreover, when I write a brand new app from scratch with the following code, everything works just perfect:
const numbersArr = ['1234', '12345', '123456', '1234567'] // dummy numbers here
export default function App() {
async function handleSend () {
const isAvailable = await SMS.isAvailableAsync()
if (isAvailable) {
while (numbersArr.length > 0) {
const n = numbersArr.pop()
const result = await SMS.sendSMSAsync(n, 'My sample HelloWorld message')
console.log('results', result)
}
} else {
// misfortune... there's no SMS available on this device
}
}
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
<Button title="Send" onPress={handleSend}/>
</View>
)
}
some technical data and versions:
tested on iPhone 11 Pro
"expo": "~36.0.0"
"expo-sms": "~8.0.0"
We don't have any known issues with Expo SMS at the moment. I wrote a small example Snack, you can see it here. I've tested the dialog on both Android and iOS.
If you think this is an issue with Expo, please open an issue at expo/expo.
the problem was that my selected dummy contacts was accidentally created with the wrong phone number field, eventually resulted with number=undefined being called on SMS.sendSMSAsync(undefined, 'My sample HelloWorld message')
Obviously I created those dummy contacts to avoid testing the app on my real contacts...
(sorry for bothering the network)
Opened an issue to expo to discuss the option to throw error or at least a warning in dev stage to warn for undefined/null value being passed to SMS.sendSMSAsync

How to implement barcode scanner in reactjs application?

I am developing an Order Scan web application, and the challenge I'm facing is that, if barcode matches, where I'm going to receive data in my react.js application. I'll be using a barcode scanner device, so can I use this npm package https://www.npmjs.com/package/react-barcode-reader. If so, how to implement it in my react app?
I have searched the web for answers. I couldn't find anything to my specific problem in react.js.
A barcode scanner is simply an input device. Just think of it as a keyboard.
You may receive its inputs via any TextInputs component.
If your barcode scanner is programmed to terminate with "\n", then the TextInput will also trigger onSubmit event.
I would recommend using the React Barcode Scanner NPM package. A simple demonstration is on that site. You can use their Barcode Scanner component:
<BarcodeReader
onError={handleError}
onScan={handleScan}
/>
You can apply that component in where you want the user to perform the scan. You will just need to make a handleScan and handleError function.
Examples:
const [scanData, setScanData] = useState()
const handleScan = (data) => {
setScanData(data)
}
const handleError = (err) => console.error(err)
The data will be stored in the scanData variable. Hope you find this helpful.
This is a very simple example for barcode reading in React, using simple vanilla javascript:
This works using timeframe to detect barcode readings. You can easily change it for endline codes (you won't need the timeout)
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [barcodeRead, setBarcodeRead] = useState("");
const barcode = {
timing: 1000,
data: "",
};
const barcodeReaded = () => {
if (barcode.data.length > 1) {
setBarcodeRead(barcode.data);
} else {
barcode.data = "";
}
};
let timeout = setTimeout(barcodeReaded, 500);
useEffect(() => {
window.addEventListener("keypress", (e) => {
console.log(e.key);
console.log(e.timeStamp);
if (barcode.data.length === 0 || e.timeStamp - barcode.timing < 200) {
barcode.data += e.key;
barcode.timing = e.timeStamp;
clearTimeout(timeout);
timeout = setTimeout(barcodeReaded, 500);
} else {
barcode.data = "";
}
console.log(barcode);
});
}, []);
return (
<div className="App">
<div>Readed: {barcodeRead}</div>
</div>
);
}
export default App;

Resources