Skip to content

Commit

Permalink
feat: add BarcodeScanner module (#6)
Browse files Browse the repository at this point in the history
This PR adds support for the
[BarcodeScanner](https://learn.microsoft.com/en-us/uwp/api/windows.devices.pointofservice.barcodescanner?view=winrt-22621)
class from the
[Windows.Devices.PointOfService](https://learn.microsoft.com/en-us/uwp/api/windows.devices.pointofservice?view=winrt-22621)
namespace.

It also adds a hook and an example.
  • Loading branch information
joshuayoes authored Mar 12, 2024
2 parents b1fe139 + c9d6958 commit b39100f
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 24 deletions.
12 changes: 9 additions & 3 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as React from 'react';
import { StyleSheet, View, Text, SectionList } from 'react-native';
import { useDeviceInformation, usePosPrinter } from 'react-native-pos-tools';
import {
useBarcodeScanner,
useDeviceInformation,
usePosPrinter,
} from 'react-native-pos-tools';

interface SectionProps {
data: any;
Expand All @@ -21,13 +25,15 @@ const Section = ({ data, error, loading }: SectionProps) => {
export default function App() {
const posPrinter = usePosPrinter();
const deviceInformation = useDeviceInformation();
const barcodeScanner = useBarcodeScanner();

return (
<View style={styles.container}>
<SectionList<SectionProps>
sections={[
{ title: 'POS Printer', data: [posPrinter], key: '1' },
{ title: 'Device Information', data: [deviceInformation], key: '2' },
{ title: 'POS Printer', data: [posPrinter] },
{ title: 'Barcode Scanner', data: [barcodeScanner] },
{ title: 'Device Information', data: [deviceInformation] },
]}
renderItem={({ item }) => <Section {...item} />}
renderSectionHeader={({ section: { title } }) => (
Expand Down
21 changes: 21 additions & 0 deletions src/NativeBarcodeScanner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import { TurboModuleRegistry } from 'react-native';

export interface BarcodeScannerSpec extends TurboModule {
/**
* Returns the first available barcode scanner.
* @throws {Error} A device is not found.
* @see https://learn.microsoft.com/en-us/uwp/api/windows.devices.pointofservice.barcodescanner.getdefaultasync?view=winrt-22621#windows-devices-pointofservice-barcodescanner-getdefaultasync
*/
getDefaultAsync(): Promise<ReactBarcodeScanner>;
}

export default TurboModuleRegistry.get<BarcodeScannerSpec>(
'BarcodeScanner'
) as BarcodeScannerSpec | null;

/** @link windows/ReactNativePosTools/NativeBarcodeScanner.cs */
export interface ReactBarcodeScanner {
/** @see https://learn.microsoft.com/en-us/uwp/api/windows.devices.pointofservice.barcodescanner.deviceid?view=winrt-22621 */
DeviceId: string;
}
90 changes: 69 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import NativePosPrinter, { type ReactPosPrinter } from './NativePosPrinter';
import ReactNativePosTools from './NativeReactNativePosTools';
import type { ReactDeviceInformation } from './NativeDeviceInformation';
import NativeDeviceInformation from './NativeDeviceInformation';
import NativeBarcodeScanner, {
type ReactBarcodeScanner,
} from './NativeBarcodeScanner';

class MethodUndefinedError extends Error {
constructor({
Expand Down Expand Up @@ -31,26 +34,17 @@ export const multiply = (a: number, b: number): number => {
return result;
};

export const getDefaultAsync = async (): Promise<ReactPosPrinter> => {
if (NativePosPrinter?.getDefaultAsync === undefined) {
throw new MethodUndefinedError({
moduleName: 'PosPrinter',
methodName: 'getDefaultAsync',
});
}

return NativePosPrinter.getDefaultAsync();
};

export const findAllAsync = async (): Promise<ReactDeviceInformation[]> => {
if (NativeDeviceInformation?.findAllAsync === undefined) {
throw new MethodUndefinedError({
moduleName: 'DeviceInformation',
methodName: 'findAllAsync',
});
}
export const posPrinter = {
getDefaultAsync: async (): Promise<ReactPosPrinter> => {
if (NativePosPrinter?.getDefaultAsync === undefined) {
throw new MethodUndefinedError({
moduleName: 'PosPrinter',
methodName: 'getDefaultAsync',
});
}

return NativeDeviceInformation.findAllAsync();
return NativePosPrinter.getDefaultAsync();
},
};

export const usePosPrinter = () => {
Expand All @@ -59,7 +53,8 @@ export const usePosPrinter = () => {
const [loading, setLoading] = React.useState<boolean>(true);

React.useEffect(() => {
getDefaultAsync()
posPrinter
.getDefaultAsync()
.then((printer) => {
setData(printer);
})
Expand All @@ -78,6 +73,19 @@ export const usePosPrinter = () => {
};
};

export const deviceInformation = {
findAllAsync: async (): Promise<ReactDeviceInformation[]> => {
if (NativeDeviceInformation?.findAllAsync === undefined) {
throw new MethodUndefinedError({
moduleName: 'DeviceInformation',
methodName: 'findAllAsync',
});
}

return NativeDeviceInformation.findAllAsync();
},
};

export const useDeviceInformation = () => {
const [data, setData] = React.useState<
ReactDeviceInformation[] | undefined
Expand All @@ -86,7 +94,8 @@ export const useDeviceInformation = () => {
const [loading, setLoading] = React.useState<boolean>(true);

React.useEffect(() => {
findAllAsync()
deviceInformation
.findAllAsync()
.then((devices) => {
setData(devices);
console.log(devices);
Expand All @@ -105,3 +114,42 @@ export const useDeviceInformation = () => {
loading,
};
};

export const barcodeScanner = {
getDefaultAsync: async () => {
if (NativeBarcodeScanner?.getDefaultAsync === undefined) {
throw new MethodUndefinedError({
moduleName: 'BarcodeScanner',
methodName: 'getDefaultAsync',
});
}

return NativeBarcodeScanner.getDefaultAsync();
},
};

export const useBarcodeScanner = () => {
const [data, setData] = React.useState<ReactBarcodeScanner | undefined>();
const [error, setError] = React.useState<Error | undefined>();
const [loading, setLoading] = React.useState<boolean>(true);

React.useEffect(() => {
barcodeScanner
.getDefaultAsync()
.then((scanner) => {
setData(scanner);
})
.catch((err) => {
setError(err);
})
.finally(() => {
setLoading(false);
});
}, []);

return {
data,
error,
loading,
};
};
51 changes: 51 additions & 0 deletions windows/ReactNativePosTools/NativeBarcodeScanner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.ReactNative.Managed;

using Windows.Devices.PointOfService;

namespace ReactNativePosTools
{
// This is the structure that will be returned to the JavaScript side
// src/NativeBarcodeScanner.ts
struct ReactBarcodeScanner
{
public string DeviceId { get; set; }

public ReactBarcodeScanner(string deviceId)
{
DeviceId = deviceId;
}
};

[ReactModule("BarcodeScanner")]
internal class NativeBarcodeScanner
{
private BarcodeScanner scanner = null;

[ReactMethod("getDefaultAsync")]
public async void GetDefaultAsync(ReactPromise<ReactBarcodeScanner> result)
{
try
{
scanner = await BarcodeScanner.GetDefaultAsync();
if (scanner == null)
{
result.Reject(new ReactError { Message = "Scanner was not found" });
}
else
{
result.Resolve(new ReactBarcodeScanner { DeviceId = scanner.DeviceId });
}
}
catch (Exception ex)
{
result.Reject(new ReactError { Message = ex.Message });
}
}
}
}
1 change: 1 addition & 0 deletions windows/ReactNativePosTools/ReactNativePosTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="NativeBarcodeScanner.cs" />
<Compile Include="NativeDeviceInformation.cs" />
<Compile Include="NativePosPrinter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down

0 comments on commit b39100f

Please sign in to comment.