ebanutsya
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-native": "0.72.6",
|
"react-native": "0.72.6",
|
||||||
"react-native-gesture-handler": "~2.12.0",
|
"react-native-gesture-handler": "~2.12.0",
|
||||||
|
"react-native-image-zoom-viewer": "^3.0.1",
|
||||||
"react-native-keyevent": "^0.3.1",
|
"react-native-keyevent": "^0.3.1",
|
||||||
"react-native-keyevent-expo-config-plugin": "^1.0.49",
|
"react-native-keyevent-expo-config-plugin": "^1.0.49",
|
||||||
"react-native-modal": "^13.0.1",
|
"react-native-modal": "^13.0.1",
|
||||||
|
|||||||
38
src/api/assemblyApi.ts
Normal file
38
src/api/assemblyApi.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import apiClient from "./apiClient";
|
||||||
|
import {Assembly} from "../types/assembly";
|
||||||
|
|
||||||
|
const router = '/assembly';
|
||||||
|
|
||||||
|
const assemblyApi = {
|
||||||
|
create: async (orderId: number): Promise<{
|
||||||
|
ok: boolean,
|
||||||
|
message: string,
|
||||||
|
assemblyId: number,
|
||||||
|
statusCode: string
|
||||||
|
}> => {
|
||||||
|
let response = await apiClient.post(`${router}/create`, {orderId});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
close: async (assemblyId: number): Promise<{ ok: boolean, message: string }> => {
|
||||||
|
let response = await apiClient.post(`${router}/close`, {assemblyId});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
getActive: async (): Promise<Assembly> => {
|
||||||
|
let response = await apiClient.get(`${router}/getActive`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
hasActive: async (): Promise<{ has: boolean }> => {
|
||||||
|
let response = await apiClient.get(`${router}/hasActive`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
updateState: async (assemblyId: number, state: number): Promise<{ ok: boolean }> => {
|
||||||
|
let response = await apiClient.post(`${router}/updateState`, {assemblyId, state});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
confirm: async (assemblyId: number): Promise<{ ok: boolean, message: string }> => {
|
||||||
|
let response = await apiClient.post(`${router}/confirm`, {assemblyId});
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default assemblyApi;
|
||||||
@@ -10,6 +10,10 @@ const ordersApi = {
|
|||||||
getOrdersBySupplierProduct: async (supplierProductId: number): Promise<Order[]> => {
|
getOrdersBySupplierProduct: async (supplierProductId: number): Promise<Order[]> => {
|
||||||
let response = await apiClient.get(`${router}/getBySupplierProductId?supplierProductId=${supplierProductId}`);
|
let response = await apiClient.get(`${router}/getBySupplierProductId?supplierProductId=${supplierProductId}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
},
|
||||||
|
getOrderById: async (orderId: number): Promise<Order> => {
|
||||||
|
let response = await apiClient.get(`${router}/getOrderById?orderId=${orderId}`);
|
||||||
|
return response.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
src/assets/icons/cancel.png
Normal file
BIN
src/assets/icons/cancel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
69
src/components/Modals/ImageZoomModal/ImageZoomModal.tsx
Normal file
69
src/components/Modals/ImageZoomModal/ImageZoomModal.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import {FC} from "react";
|
||||||
|
import {Props} from "react-native-paper";
|
||||||
|
import {StyleSheet, View, Image, TouchableOpacity} from "react-native";
|
||||||
|
import {BottomSheetModalProvider} from "@gorhom/bottom-sheet";
|
||||||
|
import {useDispatch, useSelector} from "react-redux";
|
||||||
|
import {RootState} from "../../../redux/store";
|
||||||
|
import Modal from "react-native-modal";
|
||||||
|
import {background, blue} from "../../../css/colors";
|
||||||
|
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||||||
|
import * as Progress from 'react-native-progress';
|
||||||
|
import ImageViewer from "react-native-image-zoom-viewer";
|
||||||
|
import {RFPercentage} from "react-native-responsive-fontsize";
|
||||||
|
import {closeImageZoomModal} from "../../../features/imageZoomModal/loadingModalSlice";
|
||||||
|
|
||||||
|
const ImageZoomModal: FC = () => {
|
||||||
|
const isVisible = useSelector((state: RootState) => state.imageZoomModal.isVisible);
|
||||||
|
const imageUrls = useSelector((state: RootState) => state.imageZoomModal.imageUrls);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return (
|
||||||
|
<Modal isVisible={isVisible}>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.header}>
|
||||||
|
<TouchableOpacity onPress={() => {
|
||||||
|
dispatch(closeImageZoomModal())
|
||||||
|
}}>
|
||||||
|
<View style={styles.imageWrapper}>
|
||||||
|
<Image source={require('assets/icons/cancel.png')} style={styles.image}/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
</View>
|
||||||
|
<ImageViewer
|
||||||
|
imageUrls={imageUrls.map(imageUrl => {
|
||||||
|
console.log(imageUrl)
|
||||||
|
return {
|
||||||
|
url: imageUrl
|
||||||
|
}
|
||||||
|
})}/>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignSelf: "center",
|
||||||
|
backgroundColor: background,
|
||||||
|
borderRadius: responsiveWidth(2),
|
||||||
|
paddingBottom: responsiveHeight(5),
|
||||||
|
paddingHorizontal: responsiveWidth(5),
|
||||||
|
height: "95%",
|
||||||
|
width: "95%"
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
padding: RFPercentage(2)
|
||||||
|
},
|
||||||
|
imageWrapper: {
|
||||||
|
height: responsiveHeight(4),
|
||||||
|
width: responsiveHeight(4),
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
|
resizeMode: "center"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default ImageZoomModal;
|
||||||
@@ -56,7 +56,7 @@ const OrderProductsList: FC<ListProps> = ({products, onSelected}) => {
|
|||||||
|
|
||||||
const listStyles = StyleSheet.create({
|
const listStyles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: "white",
|
backgroundColor: 'white',
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ const styles = StyleSheet.create({
|
|||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
borderTopRightRadius: responsiveWidth(1),
|
borderTopRightRadius: responsiveWidth(1),
|
||||||
borderBottomRightRadius: responsiveWidth(1),
|
borderBottomRightRadius: responsiveWidth(1),
|
||||||
paddingHorizontal: responsiveWidth(5)
|
paddingHorizontal: responsiveWidth(5),
|
||||||
|
height:'100%'
|
||||||
},
|
},
|
||||||
scanImageWrapper: {
|
scanImageWrapper: {
|
||||||
paddingHorizontal: responsiveWidth(1),
|
paddingHorizontal: responsiveWidth(1),
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
|
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
|
||||||
import {Order} from "../../types/order";
|
import {Order} from "../../types/order";
|
||||||
|
import {Assembly, ASSEMBLY_STATE} from "../../types/assembly";
|
||||||
|
|
||||||
|
|
||||||
export interface AssemblyState {
|
export interface AssemblyState {
|
||||||
order?: Order;
|
order?: Order;
|
||||||
|
assembly?: Assembly;
|
||||||
|
localState?: ASSEMBLY_STATE
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: AssemblyState = {
|
const initialState: AssemblyState = {
|
||||||
order: undefined,
|
localState: ASSEMBLY_STATE.NOT_STARTED
|
||||||
}
|
}
|
||||||
|
|
||||||
export const assembly = createSlice({
|
export const assembly = createSlice({
|
||||||
@@ -16,16 +20,47 @@ export const assembly = createSlice({
|
|||||||
setOrder: (state, action) => {
|
setOrder: (state, action) => {
|
||||||
state.order = action.payload;
|
state.order = action.payload;
|
||||||
},
|
},
|
||||||
|
setAssembly: (state, action: PayloadAction<Assembly>) => {
|
||||||
|
state.assembly = action.payload;
|
||||||
|
state.localState = action.payload.state;
|
||||||
|
},
|
||||||
|
startAssembly: (state) => {
|
||||||
|
if (!state.assembly) return;
|
||||||
|
state.assembly.createdAt = (new Date()).toDateString();
|
||||||
|
|
||||||
|
state.assembly.state = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS;
|
||||||
|
state.localState = ASSEMBLY_STATE.ASSEMBLING_PRODUCTS;
|
||||||
|
},
|
||||||
|
endAssembly: (state) => {
|
||||||
|
if (!state.assembly) return;
|
||||||
|
state.assembly.endedAt = (new Date()).toDateString();
|
||||||
|
|
||||||
|
state.assembly.state = ASSEMBLY_STATE.ENDED;
|
||||||
|
state.localState = ASSEMBLY_STATE.ENDED;
|
||||||
|
|
||||||
|
state.assembly = undefined;
|
||||||
|
state.localState = ASSEMBLY_STATE.NOT_STARTED;
|
||||||
|
state.order = undefined;
|
||||||
|
},
|
||||||
|
confirmAssembly: (state) => {
|
||||||
|
if (!state.assembly) return;
|
||||||
|
|
||||||
|
state.assembly.state = ASSEMBLY_STATE.CONFIRMED;
|
||||||
|
state.localState = ASSEMBLY_STATE.CONFIRMED;
|
||||||
|
},
|
||||||
setAssembled: (state, action: PayloadAction<{ orderProductId: number }>) => {
|
setAssembled: (state, action: PayloadAction<{ orderProductId: number }>) => {
|
||||||
if (!state.order || !state.order.products) return;
|
if (!state.order || !state.order.products || !state.assembly) return;
|
||||||
|
|
||||||
const orderProductId = action.payload.orderProductId;
|
const orderProductId = action.payload.orderProductId;
|
||||||
|
|
||||||
state.order.products.forEach(product => {
|
state.order.products.forEach(product => {
|
||||||
if (product.databaseId === orderProductId) {
|
if (product.databaseId === orderProductId) {
|
||||||
product.assembled = true;
|
product.assembled = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// If all products is assembled
|
||||||
|
if (!state.order.products.find(product => !product.assembled)) {
|
||||||
|
state.assembly.state = ASSEMBLY_STATE.ALL_PRODUCTS_ASSEMBLED;
|
||||||
|
state.localState = ASSEMBLY_STATE.ALL_PRODUCTS_ASSEMBLED;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setShipped: (state, action: PayloadAction<{ orderProductId: number }>) => {
|
setShipped: (state, action: PayloadAction<{ orderProductId: number }>) => {
|
||||||
if (!state.order || !state.order.products) return;
|
if (!state.order || !state.order.products) return;
|
||||||
@@ -41,5 +76,5 @@ export const assembly = createSlice({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const {setOrder, setAssembled, setShipped} = assembly.actions;
|
export const {setOrder, setAssembled, setAssembly, startAssembly, endAssembly, confirmAssembly} = assembly.actions;
|
||||||
export default assembly.reducer;
|
export default assembly.reducer;
|
||||||
30
src/features/imageZoomModal/loadingModalSlice.ts
Normal file
30
src/features/imageZoomModal/loadingModalSlice.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
export interface ImageZoomModalState {
|
||||||
|
isVisible: boolean;
|
||||||
|
imageUrls: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ImageZoomModalState = {
|
||||||
|
isVisible: false,
|
||||||
|
imageUrls: []
|
||||||
|
}
|
||||||
|
|
||||||
|
export const imageZoomModalSlice = createSlice({
|
||||||
|
name: 'loadingModal',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
openImageZoomModal: (state) => {
|
||||||
|
state.isVisible = true
|
||||||
|
},
|
||||||
|
closeImageZoomModal: (state) => {
|
||||||
|
state.isVisible = false
|
||||||
|
},
|
||||||
|
setImages: (state, action: PayloadAction<string[]>) => {
|
||||||
|
state.imageUrls = action.payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const {closeImageZoomModal, openImageZoomModal, setImages} = imageZoomModalSlice.actions;
|
||||||
|
export default imageZoomModalSlice.reducer;
|
||||||
@@ -4,6 +4,7 @@ import authReducer from 'features/auth/authSlice';
|
|||||||
import interfaceReducer from 'features/interface/interfaceSlice';
|
import interfaceReducer from 'features/interface/interfaceSlice';
|
||||||
import scanModalReducer from 'features/scanModal/scanModalSlice';
|
import scanModalReducer from 'features/scanModal/scanModalSlice';
|
||||||
import loadingModalReducer from 'features/loadingModal/loadingModalSlice';
|
import loadingModalReducer from 'features/loadingModal/loadingModalSlice';
|
||||||
|
import imageZoomModalReducer from 'features/imageZoomModal/loadingModalSlice';
|
||||||
import assemblyReducer from 'features/assembly/assemblySlice';
|
import assemblyReducer from 'features/assembly/assemblySlice';
|
||||||
import printingReducer from 'features/printing/printingSlice';
|
import printingReducer from 'features/printing/printingSlice';
|
||||||
import reprintModalReducer from 'features/reprintModal/reprintModalSlice';
|
import reprintModalReducer from 'features/reprintModal/reprintModalSlice';
|
||||||
@@ -17,7 +18,8 @@ export const store = configureStore({
|
|||||||
loadingModal: loadingModalReducer,
|
loadingModal: loadingModalReducer,
|
||||||
assembly: assemblyReducer,
|
assembly: assemblyReducer,
|
||||||
printing: printingReducer,
|
printing: printingReducer,
|
||||||
reprintModal: reprintModalReducer
|
reprintModal: reprintModalReducer,
|
||||||
|
imageZoomModal: imageZoomModalReducer
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,21 +14,43 @@ import ScanModal from "../../components/SearchBar/ScanModal";
|
|||||||
import {closeScanModal, setScannedData} from "../../features/scanModal/scanModalSlice";
|
import {closeScanModal, setScannedData} from "../../features/scanModal/scanModalSlice";
|
||||||
import LoadingModal from "../../components/Modals/LoadingModal/LoadingModal";
|
import LoadingModal from "../../components/Modals/LoadingModal/LoadingModal";
|
||||||
import ReprintModal from "../../components/Modals/ReprintModal/ReprintModal";
|
import ReprintModal from "../../components/Modals/ReprintModal/ReprintModal";
|
||||||
|
import assemblyApi from "../../api/assemblyApi";
|
||||||
|
import {assembly, setAssembly, setOrder} from "../../features/assembly/assemblySlice";
|
||||||
|
import ordersApi from "../../api/ordersApi";
|
||||||
|
import ImageZoomModal from "../../components/Modals/ImageZoomModal/ImageZoomModal";
|
||||||
|
|
||||||
function CommonPage() {
|
function CommonPage() {
|
||||||
const dim = useSelector((state: RootState) => state.interface.dim);
|
const dim = useSelector((state: RootState) => state.interface.dim);
|
||||||
const isAuthorized = useSelector((state: RootState) => state.auth.isAuthorized);
|
const isAuthorized = useSelector((state: RootState) => state.auth.isAuthorized);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const loadSettings = async (): Promise<boolean> => {
|
||||||
const loadSettings = async () => {
|
|
||||||
const token = await SecureStore.getItemAsync('accessToken');
|
const token = await SecureStore.getItemAsync('accessToken');
|
||||||
if (!token) return;
|
if (!token) return false;
|
||||||
dispatch(login({accessToken: token}));
|
dispatch(login({accessToken: token}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const loadAssembly = async () => {
|
||||||
|
assemblyApi.hasActive().then(({has}) => {
|
||||||
|
if (!has) return;
|
||||||
|
assemblyApi.getActive().then(assembly => {
|
||||||
|
ordersApi.getOrderById(assembly.orderId).then(order => {
|
||||||
|
dispatch(setAssembly(assembly));
|
||||||
|
dispatch(setOrder(order));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const initialize = () => {
|
||||||
|
loadSettings().then(isSettingsLoaded => {
|
||||||
|
if (!isSettingsLoaded) return;
|
||||||
|
loadAssembly();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadSettings();
|
initialize();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -39,6 +61,7 @@ function CommonPage() {
|
|||||||
<LoadingModal/>
|
<LoadingModal/>
|
||||||
<ScanModal/>
|
<ScanModal/>
|
||||||
<ReprintModal/>
|
<ReprintModal/>
|
||||||
|
<ImageZoomModal/>
|
||||||
<Toast config={toastConfig}/>
|
<Toast config={toastConfig}/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {View, Text, Image, StyleSheet, Button} from "react-native";
|
import {View, Text, Image, StyleSheet, Button, TouchableOpacity} from "react-native";
|
||||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||||||
import DText from "../../components/DText/DText";
|
import DText from "../../components/DText/DText";
|
||||||
import {RFPercentage} from "react-native-responsive-fontsize";
|
import {RFPercentage} from "react-native-responsive-fontsize";
|
||||||
@@ -16,14 +16,29 @@ import {useNavigation} from "@react-navigation/native";
|
|||||||
import printingApi from "../../api/printingApi";
|
import printingApi from "../../api/printingApi";
|
||||||
import PrintingService from "../../utils/PrintingService";
|
import PrintingService from "../../utils/PrintingService";
|
||||||
import OrderProductsList from "../../components/OrderCard/OrderProductsList";
|
import OrderProductsList from "../../components/OrderCard/OrderProductsList";
|
||||||
import {setAssembled, setOrder} from "../../features/assembly/assemblySlice";
|
import {
|
||||||
|
confirmAssembly, endAssembly,
|
||||||
|
setAssembled,
|
||||||
|
setAssembly,
|
||||||
|
setOrder,
|
||||||
|
startAssembly
|
||||||
|
} from "../../features/assembly/assemblySlice";
|
||||||
import AcceptModal from "../../components/Modals/AcceptModal/AcceptModal";
|
import AcceptModal from "../../components/Modals/AcceptModal/AcceptModal";
|
||||||
import {Order} from "../../types/order";
|
import {Order} from "../../types/order";
|
||||||
import acceptModal from "../../components/Modals/AcceptModal/AcceptModal";
|
import acceptModal from "../../components/Modals/AcceptModal/AcceptModal";
|
||||||
import printingService from "../../utils/PrintingService";
|
import printingService from "../../utils/PrintingService";
|
||||||
import ReprintModal from "../../components/Modals/ReprintModal/ReprintModal";
|
import ReprintModal from "../../components/Modals/ReprintModal/ReprintModal";
|
||||||
import {setData, setPrinterName} from "../../features/printing/printingSlice";
|
import {setPrinterName} from "../../features/printing/printingSlice";
|
||||||
import {openReprintModal} from "../../features/reprintModal/reprintModalSlice";
|
import {openReprintModal} from "../../features/reprintModal/reprintModalSlice";
|
||||||
|
import {ASSEMBLY_STATE} from "../../types/assembly";
|
||||||
|
import {RenderTargetOptions} from "@shopify/flash-list";
|
||||||
|
import {createOnShouldStartLoadWithRequest} from "react-native-webview/lib/WebViewShared";
|
||||||
|
import assemblyApi from "../../api/assemblyApi";
|
||||||
|
import Toast from "react-native-toast-message";
|
||||||
|
import mainScreen from "../MainScreen/MainScreen";
|
||||||
|
import toast from "../../components/Toast/Toast";
|
||||||
|
import {openImageZoomModal, setImages} from "../../features/imageZoomModal/loadingModalSlice";
|
||||||
|
|
||||||
|
|
||||||
type AssemblyPeriod = {
|
type AssemblyPeriod = {
|
||||||
started: Date;
|
started: Date;
|
||||||
@@ -65,39 +80,131 @@ type OrderScreenProps = {
|
|||||||
const OrderScreen: FC<OrderScreenProps> = ({order}) => {
|
const OrderScreen: FC<OrderScreenProps> = ({order}) => {
|
||||||
const navigator = useNavigation();
|
const navigator = useNavigation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const assembly = useSelector((state: RootState) => state.assembly.assembly);
|
||||||
|
const assemblyState = useSelector((state: RootState) => state.assembly.localState);
|
||||||
|
|
||||||
const [selectedProduct, setSelectedProduct] = useState(order.products[0]);
|
const [selectedProduct, setSelectedProduct] = useState(order.products[0]);
|
||||||
const [assemblyPeriod, setAssemblyPeriod] = useState<AssemblyPeriod>({started: new Date(), ended: new Date()})
|
|
||||||
const [acceptModalVisible, setAcceptModalVisible] = useState(false);
|
const [acceptModalVisible, setAcceptModalVisible] = useState(false);
|
||||||
const [reprintModalVisible, setReprintModalVisible] = useState(false);
|
const [skipConfirmButtonVisible, setSkipConfirmButtonVisible] = useState(false);
|
||||||
|
const _confirmAssembly = async () => {
|
||||||
|
if (!assembly) return;
|
||||||
|
dispatch(setLoadingText('Подтверждение сборки...'))
|
||||||
|
dispatch(openLoadingModal());
|
||||||
|
assemblyApi.confirm(assembly.databaseId).then(({ok, message}) => {
|
||||||
|
dispatch(closeLoadingModal());
|
||||||
|
Toast.show({
|
||||||
|
type: ok ? 'success' : 'error',
|
||||||
|
text1: 'Подтверждение сборки',
|
||||||
|
text2: message
|
||||||
|
})
|
||||||
|
if (ok) {
|
||||||
|
dispatch(confirmAssembly());
|
||||||
|
|
||||||
const [assemblyStarted, setAssemblyStarted] = useState(false);
|
} else {
|
||||||
const [assemblyIntervalId, setAssemblyIntervalId] = useState(0);
|
setSkipConfirmButtonVisible(true);
|
||||||
const prettyPrintMilliseconds = (milliseconds: number) => {
|
}
|
||||||
const totalSeconds = Math.floor(milliseconds / 1000);
|
})
|
||||||
const minutes = Math.floor(totalSeconds / 60);
|
|
||||||
const seconds = totalSeconds % 60;
|
|
||||||
|
|
||||||
// Форматируем минуты и секунды, чтобы они всегда были двузначными
|
|
||||||
const formattedMinutes = String(minutes).padStart(2, '0');
|
|
||||||
const formattedSeconds = String(seconds).padStart(2, '0');
|
|
||||||
|
|
||||||
return `${formattedMinutes}:${formattedSeconds}`;
|
|
||||||
}
|
}
|
||||||
const startAssembly = async () => {
|
const getButtons = () => {
|
||||||
setAssemblyStarted(true);
|
switch (assemblyState) {
|
||||||
let intervalId = setInterval(() => {
|
case ASSEMBLY_STATE.NOT_STARTED:
|
||||||
setAssemblyPeriod(oldValue => ({...oldValue, ended: new Date()}))
|
return (<BasicButton containerStyle={styles.buttonContainer}
|
||||||
}, 1000);
|
onPress={() => setAcceptModalVisible(true)}
|
||||||
setAssemblyIntervalId(Number(intervalId))
|
label={"Начать сборку"}/>)
|
||||||
};
|
case ASSEMBLY_STATE.ASSEMBLING_PRODUCTS:
|
||||||
|
return (<BasicButton
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
label={"Отметить как собранный"}
|
||||||
|
disabled={selectedProduct.assembled}
|
||||||
|
onPress={() => {
|
||||||
|
dispatch(setAssembled({orderProductId: selectedProduct.databaseId}))
|
||||||
|
}}
|
||||||
|
/>)
|
||||||
|
case ASSEMBLY_STATE.ALL_PRODUCTS_ASSEMBLED:
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<BasicButton
|
||||||
|
onPress={() => {
|
||||||
|
_confirmAssembly();
|
||||||
|
}}
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
label={"Подтвердить сборку"}
|
||||||
|
/>
|
||||||
|
{skipConfirmButtonVisible && <BasicButton
|
||||||
|
onPress={() => {
|
||||||
|
dispatch(confirmAssembly());
|
||||||
|
}}
|
||||||
|
style={{backgroundColor: 'orange'}}
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
label={"Пропустить подтверждение сборки"}
|
||||||
|
/>}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
case ASSEMBLY_STATE.CONFIRMED:
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<BasicButton
|
||||||
|
onPress={() => printLabel()}
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
label={"Печать этикетки"}
|
||||||
|
/>
|
||||||
|
<BasicButton
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
style={{backgroundColor: 'green'}}
|
||||||
|
label={"Завершить сборку"}
|
||||||
|
onPress={() => {
|
||||||
|
if (!assembly) return;
|
||||||
|
assemblyApi.close(assembly.databaseId).then(({ok, message}) => {
|
||||||
|
Toast.show({
|
||||||
|
type: ok ? 'success' : 'error',
|
||||||
|
text1: 'Завершение сборки',
|
||||||
|
text2: message
|
||||||
|
});
|
||||||
|
dispatch(endAssembly());
|
||||||
|
})
|
||||||
|
}}/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
case ASSEMBLY_STATE.ENDED:
|
||||||
|
return (
|
||||||
|
<BasicButton
|
||||||
|
containerStyle={styles.buttonContainer}
|
||||||
|
label={"Этот заказ уже собран"}
|
||||||
|
disabled
|
||||||
|
onPress={() => {
|
||||||
|
}}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const printLabel = () => {
|
||||||
|
if (!order) return;
|
||||||
|
dispatch(setLoadingText('Идет печать этикетки...'))
|
||||||
|
dispatch(openLoadingModal())
|
||||||
|
printingApi.getLabel(order.databaseId).then(pdfData => {
|
||||||
|
printingService.getInstance().printPdf('ozon', pdfData).then((response) => {
|
||||||
|
dispatch(closeLoadingModal());
|
||||||
|
if (response) return;
|
||||||
|
dispatch(setPrinterName({printerName: 'ozon'}));
|
||||||
|
dispatch(openReprintModal());
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let newSelectedProduct = order.products.find(o => o.databaseId == selectedProduct.databaseId);
|
if (!assembly) return;
|
||||||
if (!newSelectedProduct) return;
|
assemblyApi.updateState(assembly.databaseId, Number(assemblyState)).then(ok => {
|
||||||
setSelectedProduct(newSelectedProduct);
|
if (ok) return;
|
||||||
}, [order]);
|
Toast.show({
|
||||||
useEffect(() => {
|
type: 'error',
|
||||||
dispatch(closeLoadingModal())
|
text1: 'Обновление состояния',
|
||||||
}, []);
|
text2: 'Неудалось обновить состояние текущей сборки на сервере'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
}, [assemblyState]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.productsContainer}>
|
<View style={styles.productsContainer}>
|
||||||
@@ -107,9 +214,16 @@ const OrderScreen: FC<OrderScreenProps> = ({order}) => {
|
|||||||
setSelectedProduct(product)
|
setSelectedProduct(product)
|
||||||
}}/>
|
}}/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.imageWrapper}>
|
|
||||||
<Image style={styles.image} source={{uri: selectedProduct.imageUrl}}/>
|
<TouchableOpacity style={styles.imageWrapper} onPress={()=>{
|
||||||
</View>
|
dispatch(setImages([selectedProduct.imageUrl]));
|
||||||
|
dispatch(openImageZoomModal());
|
||||||
|
}}>
|
||||||
|
<View style={{flex: 1}}>
|
||||||
|
<Image style={styles.image} source={{uri: selectedProduct.imageUrl}}/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<View style={styles.dataContainer}>
|
<View style={styles.dataContainer}>
|
||||||
@@ -124,49 +238,29 @@ const OrderScreen: FC<OrderScreenProps> = ({order}) => {
|
|||||||
<DText>Номер товара: {0}</DText>
|
<DText>Номер товара: {0}</DText>
|
||||||
<DText>{}</DText>
|
<DText>{}</DText>
|
||||||
<DTitle style={styles.contentTitle}>Сборка</DTitle>
|
<DTitle style={styles.contentTitle}>Сборка</DTitle>
|
||||||
<DText>Затрачено
|
|
||||||
времени: {prettyPrintMilliseconds(assemblyPeriod.ended.getTime() - assemblyPeriod.started.getTime())}</DText>
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.buttonsContainer}>
|
<View style={styles.buttonsContainer}>
|
||||||
{assemblyStarted ? <>
|
{getButtons()}
|
||||||
<BasicButton
|
|
||||||
containerStyle={styles.buttonContainer}
|
|
||||||
label={"Отметить как собранный"}
|
|
||||||
disabled={selectedProduct.assembled}
|
|
||||||
onPress={() => {
|
|
||||||
dispatch(setAssembled({orderProductId: selectedProduct.databaseId}))
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<BasicButton
|
|
||||||
onPress={() => {
|
|
||||||
if (!order) return;
|
|
||||||
dispatch(setLoadingText('Идет печать этикетки...'))
|
|
||||||
dispatch(openLoadingModal())
|
|
||||||
printingApi.getLabel(order.databaseId).then(pdfData => {
|
|
||||||
printingService.getInstance().printPdf('ozon', pdfData).then((response) => {
|
|
||||||
dispatch(closeLoadingModal());
|
|
||||||
if (response) return;
|
|
||||||
dispatch(setPrinterName({printerName: 'ozon'}));
|
|
||||||
dispatch(openReprintModal());
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
containerStyle={styles.buttonContainer}
|
|
||||||
label={"Печать этикетки"}
|
|
||||||
disabled={Boolean(order.products.find(product => !product.assembled))}/>
|
|
||||||
</>
|
|
||||||
: <BasicButton containerStyle={styles.buttonContainer}
|
|
||||||
onPress={() => setAcceptModalVisible(true)}
|
|
||||||
label={"Начать сборку"}/>}
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<AcceptModal visible={acceptModalVisible}
|
<AcceptModal visible={acceptModalVisible}
|
||||||
text={`Вы уверены что хотите начать сборку заказа ${order.orderNumber}`}
|
text={`Вы уверены что хотите начать сборку заказа ${order.orderNumber}`}
|
||||||
onAccepted={() => {
|
onAccepted={() => {
|
||||||
setAcceptModalVisible(false);
|
setAcceptModalVisible(false);
|
||||||
startAssembly();
|
assemblyApi.create(order.databaseId).then(creationResult => {
|
||||||
|
console.log(creationResult.message)
|
||||||
|
Toast.show({
|
||||||
|
type: creationResult.ok ? 'success' : 'error',
|
||||||
|
text1: 'Создание сборки',
|
||||||
|
text2: creationResult.message
|
||||||
|
});
|
||||||
|
if (!creationResult.ok) return;
|
||||||
|
assemblyApi.getActive().then(activeAssembly => {
|
||||||
|
dispatch(setAssembly(activeAssembly));
|
||||||
|
dispatch(startAssembly())
|
||||||
|
})
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
onRefused={() => {
|
onRefused={() => {
|
||||||
setAcceptModalVisible(false);
|
setAcceptModalVisible(false);
|
||||||
|
|||||||
16
src/types/assembly.ts
Normal file
16
src/types/assembly.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export enum ASSEMBLY_STATE {
|
||||||
|
NOT_STARTED,
|
||||||
|
ASSEMBLING_PRODUCTS,
|
||||||
|
ALL_PRODUCTS_ASSEMBLED,
|
||||||
|
CONFIRMED,
|
||||||
|
ENDED
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Assembly = {
|
||||||
|
databaseId: number;
|
||||||
|
createdAt: string | null;
|
||||||
|
endedAt: string | null;
|
||||||
|
orderId: number;
|
||||||
|
isActive: boolean;
|
||||||
|
state: ASSEMBLY_STATE
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user