ebanutsya
This commit is contained in:
		
							
								
								
									
										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[]> => {
 | 
			
		||||
        let response = await apiClient.get(`${router}/getBySupplierProductId?supplierProductId=${supplierProductId}`);
 | 
			
		||||
        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({
 | 
			
		||||
    container: {
 | 
			
		||||
        backgroundColor: "white",
 | 
			
		||||
        backgroundColor: 'white',
 | 
			
		||||
        flex: 1
 | 
			
		||||
    },
 | 
			
		||||
    title: {
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,8 @@ const styles = StyleSheet.create({
 | 
			
		||||
        borderRadius: 0,
 | 
			
		||||
        borderTopRightRadius: responsiveWidth(1),
 | 
			
		||||
        borderBottomRightRadius: responsiveWidth(1),
 | 
			
		||||
        paddingHorizontal: responsiveWidth(5)
 | 
			
		||||
        paddingHorizontal: responsiveWidth(5),
 | 
			
		||||
        height:'100%'
 | 
			
		||||
    },
 | 
			
		||||
    scanImageWrapper: {
 | 
			
		||||
        paddingHorizontal: responsiveWidth(1),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,16 @@
 | 
			
		||||
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
 | 
			
		||||
import {Order} from "../../types/order";
 | 
			
		||||
import {Assembly, ASSEMBLY_STATE} from "../../types/assembly";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export interface AssemblyState {
 | 
			
		||||
    order?: Order;
 | 
			
		||||
    assembly?: Assembly;
 | 
			
		||||
    localState?: ASSEMBLY_STATE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialState: AssemblyState = {
 | 
			
		||||
    order: undefined,
 | 
			
		||||
    localState: ASSEMBLY_STATE.NOT_STARTED
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const assembly = createSlice({
 | 
			
		||||
@@ -16,16 +20,47 @@ export const assembly = createSlice({
 | 
			
		||||
        setOrder: (state, action) => {
 | 
			
		||||
            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 }>) => {
 | 
			
		||||
            if (!state.order || !state.order.products) return;
 | 
			
		||||
 | 
			
		||||
            if (!state.order || !state.order.products || !state.assembly) return;
 | 
			
		||||
            const orderProductId = action.payload.orderProductId;
 | 
			
		||||
 | 
			
		||||
            state.order.products.forEach(product => {
 | 
			
		||||
                if (product.databaseId === orderProductId) {
 | 
			
		||||
                    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 }>) => {
 | 
			
		||||
            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;
 | 
			
		||||
							
								
								
									
										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 scanModalReducer from 'features/scanModal/scanModalSlice';
 | 
			
		||||
import loadingModalReducer from 'features/loadingModal/loadingModalSlice';
 | 
			
		||||
import imageZoomModalReducer from 'features/imageZoomModal/loadingModalSlice';
 | 
			
		||||
import assemblyReducer from 'features/assembly/assemblySlice';
 | 
			
		||||
import printingReducer from 'features/printing/printingSlice';
 | 
			
		||||
import reprintModalReducer from 'features/reprintModal/reprintModalSlice';
 | 
			
		||||
@@ -17,7 +18,8 @@ export const store = configureStore({
 | 
			
		||||
        loadingModal: loadingModalReducer,
 | 
			
		||||
        assembly: assemblyReducer,
 | 
			
		||||
        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 LoadingModal from "../../components/Modals/LoadingModal/LoadingModal";
 | 
			
		||||
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() {
 | 
			
		||||
    const dim = useSelector((state: RootState) => state.interface.dim);
 | 
			
		||||
    const isAuthorized = useSelector((state: RootState) => state.auth.isAuthorized);
 | 
			
		||||
 | 
			
		||||
    const dispatch = useDispatch();
 | 
			
		||||
 | 
			
		||||
    const loadSettings = async () => {
 | 
			
		||||
    const loadSettings = async (): Promise<boolean> => {
 | 
			
		||||
        const token = await SecureStore.getItemAsync('accessToken');
 | 
			
		||||
        if (!token) return;
 | 
			
		||||
        if (!token) return false;
 | 
			
		||||
        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(() => {
 | 
			
		||||
        loadSettings();
 | 
			
		||||
        initialize();
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@@ -39,6 +61,7 @@ function CommonPage() {
 | 
			
		||||
            <LoadingModal/>
 | 
			
		||||
            <ScanModal/>
 | 
			
		||||
            <ReprintModal/>
 | 
			
		||||
            <ImageZoomModal/>
 | 
			
		||||
            <Toast config={toastConfig}/>
 | 
			
		||||
        </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 DText from "../../components/DText/DText";
 | 
			
		||||
import {RFPercentage} from "react-native-responsive-fontsize";
 | 
			
		||||
@@ -16,14 +16,29 @@ import {useNavigation} from "@react-navigation/native";
 | 
			
		||||
import printingApi from "../../api/printingApi";
 | 
			
		||||
import PrintingService from "../../utils/PrintingService";
 | 
			
		||||
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 {Order} from "../../types/order";
 | 
			
		||||
import acceptModal from "../../components/Modals/AcceptModal/AcceptModal";
 | 
			
		||||
import printingService from "../../utils/PrintingService";
 | 
			
		||||
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 {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 = {
 | 
			
		||||
    started: Date;
 | 
			
		||||
@@ -65,39 +80,131 @@ type OrderScreenProps = {
 | 
			
		||||
const OrderScreen: FC<OrderScreenProps> = ({order}) => {
 | 
			
		||||
    const navigator = useNavigation();
 | 
			
		||||
    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 [assemblyPeriod, setAssemblyPeriod] = useState<AssemblyPeriod>({started: new Date(), ended: new Date()})
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    const [assemblyIntervalId, setAssemblyIntervalId] = useState(0);
 | 
			
		||||
    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}`;
 | 
			
		||||
            } else {
 | 
			
		||||
                setSkipConfirmButtonVisible(true);
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    const startAssembly = async () => {
 | 
			
		||||
        setAssemblyStarted(true);
 | 
			
		||||
        let intervalId = setInterval(() => {
 | 
			
		||||
            setAssemblyPeriod(oldValue => ({...oldValue, ended: new Date()}))
 | 
			
		||||
        }, 1000);
 | 
			
		||||
        setAssemblyIntervalId(Number(intervalId))
 | 
			
		||||
    };
 | 
			
		||||
    const getButtons = () => {
 | 
			
		||||
        switch (assemblyState) {
 | 
			
		||||
            case ASSEMBLY_STATE.NOT_STARTED:
 | 
			
		||||
                return (<BasicButton containerStyle={styles.buttonContainer}
 | 
			
		||||
                                     onPress={() => setAcceptModalVisible(true)}
 | 
			
		||||
                                     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(() => {
 | 
			
		||||
        let newSelectedProduct = order.products.find(o => o.databaseId == selectedProduct.databaseId);
 | 
			
		||||
        if (!newSelectedProduct) return;
 | 
			
		||||
        setSelectedProduct(newSelectedProduct);
 | 
			
		||||
    }, [order]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        dispatch(closeLoadingModal())
 | 
			
		||||
    }, []);
 | 
			
		||||
        if (!assembly) return;
 | 
			
		||||
        assemblyApi.updateState(assembly.databaseId, Number(assemblyState)).then(ok => {
 | 
			
		||||
            if (ok) return;
 | 
			
		||||
            Toast.show({
 | 
			
		||||
                type: 'error',
 | 
			
		||||
                text1: 'Обновление состояния',
 | 
			
		||||
                text2: 'Неудалось обновить состояние текущей сборки на сервере'
 | 
			
		||||
            })
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    }, [assemblyState]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <View style={styles.container}>
 | 
			
		||||
            <View style={styles.productsContainer}>
 | 
			
		||||
@@ -107,9 +214,16 @@ const OrderScreen: FC<OrderScreenProps> = ({order}) => {
 | 
			
		||||
                        setSelectedProduct(product)
 | 
			
		||||
                    }}/>
 | 
			
		||||
                </View>
 | 
			
		||||
                <View style={styles.imageWrapper}>
 | 
			
		||||
                    <Image style={styles.image} source={{uri: selectedProduct.imageUrl}}/>
 | 
			
		||||
                </View>
 | 
			
		||||
 | 
			
		||||
                <TouchableOpacity style={styles.imageWrapper} onPress={()=>{
 | 
			
		||||
                    dispatch(setImages([selectedProduct.imageUrl]));
 | 
			
		||||
                    dispatch(openImageZoomModal());
 | 
			
		||||
                }}>
 | 
			
		||||
                    <View style={{flex: 1}}>
 | 
			
		||||
                        <Image style={styles.image} source={{uri: selectedProduct.imageUrl}}/>
 | 
			
		||||
                    </View>
 | 
			
		||||
                </TouchableOpacity>
 | 
			
		||||
 | 
			
		||||
            </View>
 | 
			
		||||
            <View style={styles.contentContainer}>
 | 
			
		||||
                <View style={styles.dataContainer}>
 | 
			
		||||
@@ -124,49 +238,29 @@ const OrderScreen: FC<OrderScreenProps> = ({order}) => {
 | 
			
		||||
                    <DText>Номер товара: {0}</DText>
 | 
			
		||||
                    <DText>{}</DText>
 | 
			
		||||
                    <DTitle style={styles.contentTitle}>Сборка</DTitle>
 | 
			
		||||
                    <DText>Затрачено
 | 
			
		||||
                        времени: {prettyPrintMilliseconds(assemblyPeriod.ended.getTime() - assemblyPeriod.started.getTime())}</DText>
 | 
			
		||||
 | 
			
		||||
                </View>
 | 
			
		||||
                <View style={styles.buttonsContainer}>
 | 
			
		||||
                    {assemblyStarted ? <>
 | 
			
		||||
                            <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={"Начать сборку"}/>}
 | 
			
		||||
 | 
			
		||||
                    {getButtons()}
 | 
			
		||||
                </View>
 | 
			
		||||
            </View>
 | 
			
		||||
            <AcceptModal visible={acceptModalVisible}
 | 
			
		||||
                         text={`Вы уверены что хотите начать сборку заказа ${order.orderNumber}`}
 | 
			
		||||
                         onAccepted={() => {
 | 
			
		||||
                             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={() => {
 | 
			
		||||
                             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