Skip to content

Commit

Permalink
feat(barcode): polish :clean:
Browse files Browse the repository at this point in the history
  • Loading branch information
r0xsh committed Sep 5, 2024
1 parent 668dbe5 commit 01940c0
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 113 deletions.
21 changes: 17 additions & 4 deletions src/components/BarcodeCameraView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, forwardRef } from 'react';
import { Dimensions, Text } from 'react-native';
import { View, Vibration } from 'react-native';
import { CameraView, useCameraPermissions } from 'expo-camera/next';
Expand Down Expand Up @@ -30,7 +30,7 @@ function horizontalLineIntersectsBox(lineY, lineStartX, lineEndX, points) {
return lineEndX >= minX && lineStartX <= maxX;
}

export default function BarcodeCameraView(props) {
function BarcodeCameraView({ disabled, ...props }, ref) {
const [hasPermission, requestPermission] = useCameraPermissions();

const { width: CameraWidth } = Dimensions.get('window');
Expand All @@ -43,7 +43,7 @@ export default function BarcodeCameraView(props) {
//The hide behavior is a hack to force the camera to re-render
//if another camera is opened on modal. If we don't do this, the
//camera will not render.
const [hide, setHide] = useState(false);
const [hide, setHide] = useState(disabled ?? false);

if (!hasPermission) {
return (
Expand Down Expand Up @@ -82,14 +82,17 @@ export default function BarcodeCameraView(props) {
<>
<FocusHandler
onFocus={() => {
setHide(false);
if (!disabled) {
setHide(false);
}
}}
onBlur={() => {
setHide(true);
}}
/>
{!hide && (
<CameraView
ref={ref}
enableTorch={flash}
style={{
height: CameraHeight,
Expand Down Expand Up @@ -126,6 +129,16 @@ export default function BarcodeCameraView(props) {
</View>
</CameraView>
)}
{hide && (
<View
style={{
height: CameraHeight,
width: CameraWidth,
backgroundColor: 'black',
}}></View>
)}
</>
);
}

export default forwardRef(BarcodeCameraView);
5 changes: 5 additions & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -508,5 +508,10 @@
"RESTAURANT_MORE_INFOS": "More information",
"UPDATE_PARCEL_DETAILS": "Update parcel details",
"REPORT_AN_INCIDENT": "Report an incident",
"PICTURES": "Pictures",
"COURIER_BARCODE": "Scan barcode",
"TASK_MULTIPLE_PACKAGES": "Multiple packages",
"X_PACKAGES": "{{count}} packages",
"NO_NEED_TO_SCAN_OTHERS": "No need to scan the others",
}
}
2 changes: 2 additions & 0 deletions src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -483,5 +483,7 @@
"RESTAURANT_MORE_INFOS": "En savoir plus",
"UPDATE_PARCEL_DETAILS": "Mettre à jour les données de la livraison",
"REPORT_AN_INCIDENT": "Signaler un incident",
"PICTURES": "Photos",
"COURIER_BARCODE": "Scannez un code-barres",
}
}
199 changes: 126 additions & 73 deletions src/navigation/courier/barcode/Barcode.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import {
Expand All @@ -9,15 +9,16 @@ import {
Vibration,
Alert,
} from 'react-native';
import { Button, IconButton, TextArea } from 'native-base';
import { Button, IconButton, TextArea, FormControl, Icon } from 'native-base';
import Ionicons from 'react-native-vector-icons/Ionicons';
import BarcodeCameraView from '../../../components/BarcodeCameraView';

import { CommonActions } from '@react-navigation/native';
import NavigationHolder from '../../../NavigationHolder';
import { assignTask } from '../../../redux/Dispatch/actions';
import { unassignTask } from '../../../redux/Dispatch/actions';
import Modal from "react-native-modal"
import { phonecall } from 'react-native-communications';
import BottomModal from '../../../components/BottomModal';

async function _fetchBarcode(httpClient, barcode) {
if (barcode) {
Expand All @@ -29,6 +30,14 @@ async function _fetchBarcode(httpClient, barcode) {
};
}

async function _putNote(httpClient, task_id, note) {
if (note && task_id) {
return await httpClient.put(`/api/tasks/${task_id}/note`, {
note,
});
}
}

function TextSection({ title, value, variant = 'data' }) {
return (
<View style={styles.section}>
Expand All @@ -38,11 +47,15 @@ function TextSection({ title, value, variant = 'data' }) {
);
}

function BarcodePage({ httpClient, user, assignTask, unassignTask }) {
function BarcodePage({ t, httpClient, user, assignTask, unassignTask }) {
const [barcode, setBarcode] = useState(null);
const [entity, setEntity] = useState(null);
const [clientAction, setClientAction] = useState(null);
const [showNoteModal, setShowNoteModal] = useState(false);
const [noteLoading, setNoteLoading] = useState(false);
const [disableScan, setDisableScan] = useState(false);

const note = useRef(null);

const askUnassign = () => {
Alert.alert(
Expand Down Expand Up @@ -88,6 +101,22 @@ function BarcodePage({ httpClient, user, assignTask, unassignTask }) {
);
};

const checkMultiplePackages = packages => {
if (!packages) return;
const count = packages.reduce((acc, p) => acc + p.barcodes.length, 0);
if (count > 1) {
const details = packages
.map(p => `${p.barcodes.length}x ${p.name}`)
.join('\n');
setDisableScan(true);
Alert.alert(
t('TASK_MULTIPLE_PACKAGES'),
`${t('X_PACKAGES', { count })}:\n\n${details}\n\n${t('NO_NEED_TO_SCAN_OTHERS')}`,
[{ text: t('OK'), onPress: () => setDisableScan(false) }],
);
}
};

useEffect(() => {
return;
if (!clientAction) return;

Check failure on line 122 in src/navigation/courier/barcode/Barcode.js

View workflow job for this annotation

GitHub Actions / Basic tests

Unreachable code
Expand All @@ -105,81 +134,105 @@ function BarcodePage({ httpClient, user, assignTask, unassignTask }) {

useEffect(() => {
if (!entity) return;
if (!entity?.barcodes?.packages) return;
const packages = entity?.barcodes?.packages.reduce(
(acc, p) => acc + p.barcodes.length,
0,
);
if (packages > 1) {
const details = entity?.barcodes?.packages
.map(p => `${p.barcodes.length}x ${p.name}`)
.join('\n');
Alert.alert(
'Multiple packages',
`${packages} packages:\n\n${details}\n\nNo need to scan the other packages`,
[{ text: 'Ok' }],
);
}
checkMultiplePackages(entity?.barcodes?.packages);
}, [entity]);

Check failure on line 138 in src/navigation/courier/barcode/Barcode.js

View workflow job for this annotation

GitHub Actions / Basic tests

React Hook useEffect has a missing dependency: 'checkMultiplePackages'. Either include it or remove the dependency array

return <>
<Modal isVisible={showNoteModal} onDismiss={() => setShowNoteModal(false)}>
<View style={{ flex: 1, backgroundColor: 'white', padding: 20, borderRadius: 5 }}>
<TextArea />
<Button onPress={() => setShowNoteModal(false)}>Save</Button>
</View>
</Modal>
<View style={{ flex: 1 }}>
<BarcodeCameraView
onScanned={async code => {
if (clientAction) return;
const { entity, client_action } = await _fetchBarcode(
httpClient,
code,
);
setBarcode(code);
setEntity(entity);
setClientAction(client_action);
}}
/>
<ScrollView style={{ paddingHorizontal: 20, marginVertical: 20 }}>
<TextSection title="Address" value={entity?.address?.streetAddress} />
<TextSection title="Recipient" value={entity?.address?.contactName} />
<TextSection title="Weight / Volume" value={entity?.weight} />
<TextSection title="Phone" value={entity?.address?.telephone} />
<TextSection title="Code" value={barcode} />
<TextSection title="Comment" value={entity?.comments} variant="note" />
<Button onPress={() => setShowNoteModal(true)}>Add note</Button>
</ScrollView>
<View
style={{
padding: 15,
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<IconButton
_icon={{ as: Ionicons, name: 'call', color: 'green.500' }}
disabled={entity === null}
/>
<Button width="70%" colorScheme={'dark'}>
Finished
return (
<>
<BottomModal
isVisible={showNoteModal}
onDismiss={() => setShowNoteModal(false)}
onBackdropPress={() => setShowNoteModal(false)}>
<FormControl>
<FormControl.Label>{t('NOTES')}</FormControl.Label>
<TextArea
autoFocus
onChange={e => (note.current = e.nativeEvent.text)}
/>
</FormControl>
<Button
isLoading={noteLoading}
onPress={async () => {
setNoteLoading(true);
await _putNote(httpClient, entity?.id, note.current);
setShowNoteModal(false);
note.current = null;
setNoteLoading(false);
}}>
{t('OK')}
</Button>
<IconButton
onPress={() =>
NavigationHolder.dispatch(
CommonActions.navigate('CourierBarcodeReport', { entity }),
)
}
disabled={entity === null}
_icon={{
as: Ionicons,
name: 'warning',
color: 'red.500',
</BottomModal>
<View style={{ flex: 1 }}>
<BarcodeCameraView
disabled={disableScan || showNoteModal}
onScanned={async code => {
if (clientAction) return;
const { entity, client_action } = await _fetchBarcode(
httpClient,
code,
);
setBarcode(code);
setEntity(entity);
setClientAction(client_action);
}}
/>
<ScrollView style={{ paddingHorizontal: 20, marginVertical: 20 }}>
<TextSection
title={t('ADDRESS')}
value={entity?.address?.streetAddress}
/>
<TextSection
title={t('DELIVERY_DETAILS_RECIPIENT')}
value={entity?.address?.contactName}
/>
<TextSection title="Weight / Volume" value={entity?.weight} />
<TextSection
title={t('PHONE_NUMBER')}
value={entity?.address?.telephone}
/>
<TextSection title="Code" value={barcode} />
<TextSection
title={t('TASK_FORM_COMMENTS_LABEL')}
value={entity?.comments}
variant="note"
/>
</ScrollView>
<View
style={{
padding: 15,
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<IconButton
_icon={{ as: Ionicons, name: 'call', color: 'green.500' }}
disabled={entity?.address?.telephone == null}
onPress={() => phonecall(entity?.address?.telephone, true)}
/>
<Button
width="70%"
colorScheme={'dark'}
disabled={entity == null}
leftIcon={<Icon as={Ionicons} name="document" color="white" />}
onPress={() => setShowNoteModal(true)}>
Add Note
</Button>
<IconButton
onPress={() =>
NavigationHolder.dispatch(
CommonActions.navigate('CourierBarcodeReport', { entity }),
)
}
disabled={entity == null}
_icon={{
as: Ionicons,
name: 'warning',
color: 'red.500',
}}
/>
</View>
</View>
</View>
</>;
</>
);
}

const styles = StyleSheet.create({
Expand Down
Loading

0 comments on commit 01940c0

Please sign in to comment.