Skip to content

Commit

Permalink
feat: app fully functionnal
Browse files Browse the repository at this point in the history
Need some style fix
  • Loading branch information
r0xsh committed Sep 4, 2024
1 parent 1af156c commit 668dbe5
Show file tree
Hide file tree
Showing 7 changed files with 426 additions and 55 deletions.
84 changes: 51 additions & 33 deletions src/components/BarcodeCameraView.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import _ from 'lodash';
import { Icon } from 'native-base';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { TouchableOpacity } from 'react-native-gesture-handler';
import FocusHandler from './FocusHandler';

function getBoxBoundaries(points) {
const xs = points.map(point => point.x);
Expand Down Expand Up @@ -39,6 +40,11 @@ export default function BarcodeCameraView(props) {
const [barcode, setBarcode] = useState(null);
const [flash, setFlash] = useState(false);

//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);

if (!hasPermission) {
return (
<View>
Expand Down Expand Up @@ -73,41 +79,53 @@ export default function BarcodeCameraView(props) {
}, 200);

return (
<CameraView
enableTorch={flash}
style={{
height: CameraHeight,
width: CameraWidth,
position: 'relative',
}}
onBarcodeScanned={onScanned}
barcodeScannerSettings={{
barcodeTypes: ['code128'],
}}>
<View
style={{
position: 'absolute',
borderColor: 'rgba(255, 0, 0, 0.6)',
borderBottomWidth: 1,
top: CameraHeight / 2,
left: PaddingHorizontal,
right: PaddingHorizontal,
<>
<FocusHandler
onFocus={() => {
setHide(false);
}}
onBlur={() => {
setHide(true);
}}
/>
<View
style={{
position: 'absolute',
top: 10,
right: 10,
}}>
<TouchableOpacity onPress={() => setFlash(!flash)}>
<Icon
as={Ionicons}
name={flash ? 'flash-sharp' : 'flash-off-sharp'}
style={{ color: 'rgba(255, 255, 255, 0.6)' }}
{!hide && (
<CameraView
enableTorch={flash}
style={{
height: CameraHeight,
width: CameraWidth,
position: 'relative',
}}
onBarcodeScanned={onScanned}
barcodeScannerSettings={{
barcodeTypes: ['code128'],
}}>
<View
style={{
position: 'absolute',
borderColor: 'rgba(255, 0, 0, 0.6)',
borderBottomWidth: 1,
top: CameraHeight / 2,
left: PaddingHorizontal,
right: PaddingHorizontal,
}}
/>
</TouchableOpacity>
</View>
</CameraView>
<View
style={{
position: 'absolute',
top: 10,
right: 10,
}}>
<TouchableOpacity onPress={() => setFlash(!flash)}>
<Icon
as={Ionicons}
name={flash ? 'flash-sharp' : 'flash-off-sharp'}
style={{ color: 'rgba(255, 255, 255, 0.6)' }}
/>
</TouchableOpacity>
</View>
</CameraView>
)}
</>
);
}
33 changes: 25 additions & 8 deletions src/navigation/courier/SelectRange.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { useState } from 'react';
import { FormControl, Input, KeyboardAvoidingView, Button } from 'native-base';
import { FormControl, Input, Button, ScrollView, View } from 'native-base';
import { withTranslation } from 'react-i18next';
import moment from 'moment';
import DateTimePicker from 'react-native-modal-datetime-picker';

import KeyboardAdjustView from '../../components/KeyboardAdjustView';

function SelectRange({ t, route, navigation }) {
const { after, before, navigateTo } = route.params;
const [afterDate, setAfterDate] = useState(moment(after));
Expand All @@ -12,23 +14,36 @@ function SelectRange({ t, route, navigation }) {
const [showAfterDatePicker, setShowAfterDatePicker] = useState(false);
const [showBeforeDatePicker, setShowBeforeDatePicker] = useState(false);

const isAfterInvalid = afterDate?.isBefore(moment());
const isBeforeInvalid = beforeDate?.isBefore(afterDate);

return (
<KeyboardAvoidingView p="4">
<FormControl>
<KeyboardAdjustView style={{flex: 1}} androidBehavior=''>
<ScrollView p="4" >
<FormControl isInvalid={isAfterInvalid}>
<FormControl.Label>{t('TASK_FORM_DONE_AFTER_LABEL')}</FormControl.Label>
<Input
onPressIn={() => setShowAfterDatePicker(true)}
onTouchStart={() => setShowAfterDatePicker(true)}
value={afterDate.format('ll LT')}
/>
</FormControl>
<FormControl isInvalid={isBeforeInvalid}>
<FormControl.Label>
{t('TASK_FORM_DONE_BEFORE_LABEL')}
</FormControl.Label>
<Input
onPressIn={() => setShowBeforeDatePicker(true)}
onTouchStart={() => setShowBeforeDatePicker(true)}
value={beforeDate.format('ll LT')}
/>
<Button
</FormControl>
</ScrollView>
<View p="4">
<Button mt="4"
onPress={() => {
if (isAfterInvalid || isBeforeInvalid) {
return;
}

navigation.navigate({
name: navigateTo,
params: {
Expand All @@ -39,23 +54,25 @@ function SelectRange({ t, route, navigation }) {
}}>
Reschedule
</Button>
</FormControl>
</View>

<DateTimePicker
mode="datetime"
isVisible={showAfterDatePicker}
minimumDate={new Date()}
minuteInterval={15}
onConfirm={date => setAfterDate(moment(date))}
onCancel={() => setShowAfterDatePicker(false)}
/>
<DateTimePicker
mode="datetime"
isVisible={showBeforeDatePicker}
minimumDate={afterDate.toDate()}
minuteInterval={15}
onConfirm={date => setBeforeDate(moment(date))}
onCancel={() => setShowBeforeDatePicker(false)}
/>
</KeyboardAvoidingView>
</KeyboardAdjustView>
);
}

Expand Down
133 changes: 121 additions & 12 deletions src/navigation/courier/barcode/Barcode.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { ScrollView, StyleSheet, Text, View, Vibration } from 'react-native';
import { Button, IconButton } from 'native-base';
import {
ScrollView,
StyleSheet,
Text,
View,
Vibration,
Alert,
} from 'react-native';
import { Button, IconButton, TextArea } 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"

async function _fetchBarcode(httpClient, barcode) {
if (barcode) {
Expand All @@ -28,17 +38,108 @@ function TextSection({ title, value, variant = 'data' }) {
);
}

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

return (
const askUnassign = () => {
Alert.alert(
'Task already assigned',
'This task is already assigned to you',
[
{
text: 'Unassign',
onPress: () => {
unassignTask(entity.id, user.username);
setClientAction(null);
},
},
{
text: 'Ok',
onPress: () => {
setClientAction(null);
},
},
],
);
};

const askAssign = () => {
Alert.alert(
'Task already assigned',
'This task is already assigned to another courier',
[
{
text: 'Assign to me',
onPress: () => {
assignTask(entity.id, user.username);
setClientAction(null);
},
},
{
text: 'Ok',
onPress: () => {
setClientAction(null);
},
},
],
);
};

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

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

View workflow job for this annotation

GitHub Actions / Basic tests

Unreachable code
switch (clientAction) {
case 'ask_unassign':
askUnassign();
break;
case 'ask_assign':
askAssign();
break;
default:
setClientAction(null);
}
}, [clientAction]);

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

View workflow job for this annotation

GitHub Actions / Basic tests

React Hook useEffect has missing dependencies: 'askAssign' and 'askUnassign'. Either include them or remove the dependency array

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' }],
);
}
}, [entity]);

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 => {
const { entity } = await _fetchBarcode(httpClient, 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 }}>
Expand All @@ -48,7 +149,7 @@ function BarcodePage({ httpClient }) {
<TextSection title="Phone" value={entity?.address?.telephone} />
<TextSection title="Code" value={barcode} />
<TextSection title="Comment" value={entity?.comments} variant="note" />
<Button variant="link">Add note</Button>
<Button onPress={() => setShowNoteModal(true)}>Add note</Button>
</ScrollView>
<View
style={{
Expand All @@ -64,9 +165,11 @@ function BarcodePage({ httpClient }) {
Finished
</Button>
<IconButton
onPress={() => NavigationHolder.dispatch(
CommonActions.navigate("CourierBarcodeReport", { entity } ),
)}
onPress={() =>
NavigationHolder.dispatch(
CommonActions.navigate('CourierBarcodeReport', { entity }),
)
}
disabled={entity === null}
_icon={{
as: Ionicons,
Expand All @@ -76,7 +179,7 @@ function BarcodePage({ httpClient }) {
/>
</View>
</View>
);
</>;
}

const styles = StyleSheet.create({
Expand All @@ -96,11 +199,17 @@ const styles = StyleSheet.create({
function mapStateToProps(state) {
return {
httpClient: state.app.httpClient,
user: state.app.user,
};
}

function mapDispatchToProps(dispatch) {
return {};
return {
assignTask: (task_id, username) =>
dispatch(assignTask({ '@id': task_id }, username)),
unassignTask: (task_id, username) =>
dispatch(unassignTask({ '@id': task_id }, username)),
};
}

export default connect(
Expand Down
Loading

0 comments on commit 668dbe5

Please sign in to comment.