359 lines
14 KiB
TypeScript
359 lines
14 KiB
TypeScript
import {View, Image, StyleSheet, TouchableOpacity, ScrollView} from "react-native";
|
||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||
import DText from "../../components/DText/DText";
|
||
import {RFPercentage} from "react-native-responsive-fontsize";
|
||
import DTitle from "../../components/DTitle/DTitle";
|
||
import BasicButton from "../../components/BasicButton/BasicButton";
|
||
import React, {FC, useEffect, useState} from "react";
|
||
import {useDispatch, useSelector} from "react-redux";
|
||
import {RootState} from "../../redux/store";
|
||
import {closeLoadingModal, openLoadingModal, setLoadingText} from "../../features/loadingModal/loadingModalSlice";
|
||
import {NavigationProp, useNavigation} from "@react-navigation/native";
|
||
import printingApi from "../../api/printingApi";
|
||
import PrintingService from "../../utils/PrintingService";
|
||
import OrderProductsList from "../../components/OrderCard/OrderProductsList";
|
||
import {
|
||
confirmAssembly, endAssembly, selectProduct,
|
||
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 {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, {TabNavigatorParamList} from "../MainScreen/MainScreen";
|
||
import toast from "../../components/Toast/Toast";
|
||
import {openImageZoomModal, setImages} from "../../features/imageZoomModal/loadingModalSlice";
|
||
|
||
|
||
type AssemblyPeriod = {
|
||
started: Date;
|
||
ended: Date;
|
||
}
|
||
|
||
const NoOrderScreen: FC = () => {
|
||
|
||
|
||
return (
|
||
<View style={noOrderStyles.container}>
|
||
<DText style={noOrderStyles.title}>Заказ не выбран!</DText>
|
||
</View>
|
||
)
|
||
}
|
||
const noOrderStyles = StyleSheet.create({
|
||
container: {
|
||
justifyContent: "center",
|
||
flex: 1,
|
||
rowGap: responsiveHeight(5)
|
||
},
|
||
title: {
|
||
textAlign: "center",
|
||
fontSize: responsiveWidth(5)
|
||
},
|
||
buttonWrapper: {
|
||
paddingHorizontal: responsiveWidth(20),
|
||
}
|
||
})
|
||
|
||
type OrderScreenProps = {
|
||
order: Order;
|
||
}
|
||
const OrderScreen: FC<OrderScreenProps> = ({order}) => {
|
||
const navigator = useNavigation<NavigationProp<TabNavigatorParamList, 'Barcode'>>();
|
||
|
||
const dispatch = useDispatch();
|
||
const assembly = useSelector((state: RootState) => state.assembly.assembly);
|
||
const assemblyState = useSelector((state: RootState) => state.assembly.localState);
|
||
const initialOrder = useSelector((state: RootState) => state.assembly.initialOrder);
|
||
|
||
const selectedProduct = useSelector((state: RootState) => state.assembly.selectedProduct);
|
||
const [acceptModalVisible, setAcceptModalVisible] = 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());
|
||
} else {
|
||
setSkipConfirmButtonVisible(true);
|
||
}
|
||
})
|
||
}
|
||
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={() => {
|
||
if (!selectedProduct) return;
|
||
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());
|
||
navigator.navigate('Barcode');
|
||
})
|
||
}}/>
|
||
</>
|
||
)
|
||
case ASSEMBLY_STATE.ENDED:
|
||
return (
|
||
<BasicButton
|
||
containerStyle={styles.buttonContainer}
|
||
label={"Этот заказ уже собран"}
|
||
disabled
|
||
onPress={() => {
|
||
}}/>
|
||
)
|
||
}
|
||
}
|
||
const printLabel = () => {
|
||
if (!order) return;
|
||
let printer = printingService.getInstance().getPrinter(order.baseMarketplace);
|
||
dispatch(setLoadingText('Идет печать этикетки...'))
|
||
dispatch(openLoadingModal())
|
||
printingApi.getLabel(order.databaseId).then(pdfData => {
|
||
printingService.getInstance().printPdf(printer, pdfData).then((response) => {
|
||
dispatch(closeLoadingModal());
|
||
if (response) return;
|
||
dispatch(setPrinterName({printerName: printer}));
|
||
dispatch(openReprintModal());
|
||
});
|
||
})
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (!assembly) return;
|
||
assemblyApi.updateState(assembly.databaseId, Number(assemblyState)).then(ok => {
|
||
if (ok) return;
|
||
Toast.show({
|
||
type: 'error',
|
||
text1: 'Обновление состояния',
|
||
text2: 'Неудалось обновить состояние текущей сборки на сервере'
|
||
})
|
||
});
|
||
switch (assemblyState) {
|
||
case ASSEMBLY_STATE.CONFIRMED:
|
||
printLabel();
|
||
break;
|
||
case ASSEMBLY_STATE.ASSEMBLING_PRODUCTS:
|
||
if (!selectedProduct) return;
|
||
if (order.products.length == 1) {
|
||
dispatch(setAssembled({orderProductId: selectedProduct.databaseId}));
|
||
}
|
||
break;
|
||
}
|
||
}, [assemblyState]);
|
||
useEffect(() => {
|
||
if (!order) return;
|
||
dispatch(selectProduct(0));
|
||
}, [initialOrder]);
|
||
return (
|
||
<View style={styles.container}>
|
||
<View style={styles.productsContainer}>
|
||
<View style={styles.orderProductsListWrapper}>
|
||
<OrderProductsList products={order.products} onSelected={(productId) => {
|
||
if (!order) return;
|
||
dispatch(selectProduct(productId))
|
||
}}/>
|
||
</View>
|
||
|
||
<TouchableOpacity style={styles.imageWrapper} onPress={() => {
|
||
if (!selectedProduct) return;
|
||
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}>
|
||
<ScrollView>
|
||
<DTitle style={styles.contentTitle}>Заказ</DTitle>
|
||
<DText>Номер заказа: {order.orderNumber}</DText>
|
||
<DText>Маркетплейс: {order.marketplaceName}</DText>
|
||
<DText>Селлер: {order.sellerName}</DText>
|
||
<DText>Создан: {order.createdOn}</DText>
|
||
<DText>Отгрузка: {order.shipmentDate}</DText>
|
||
<DText>{}</DText>
|
||
<DTitle style={styles.contentTitle}>Товар</DTitle>
|
||
<DText>Арт. DENCO: {selectedProduct?.dencoArticle}</DText>
|
||
<DText>Арт. поставщика: {selectedProduct?.supplierArticle}</DText>
|
||
<DText>Фасовка: {selectedProduct?.inBlock} шт.</DText>
|
||
<DText>Поставщик: {selectedProduct?.supplierName}</DText>
|
||
</ScrollView>
|
||
|
||
</View>
|
||
<View style={styles.buttonsContainer}>
|
||
{getButtons()}
|
||
</View>
|
||
</View>
|
||
<AcceptModal visible={acceptModalVisible}
|
||
text={`Вы уверены что хотите начать сборку заказа ${order.orderNumber}`}
|
||
onAccepted={() => {
|
||
setAcceptModalVisible(false);
|
||
assemblyApi.create(order.databaseId).then(creationResult => {
|
||
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);
|
||
}}/>
|
||
</View>
|
||
|
||
)
|
||
}
|
||
|
||
export const OrderScreenController: FC = () => {
|
||
const order: Order | undefined = useSelector((state: RootState) => state.assembly.order);
|
||
if (!order) return <NoOrderScreen/>
|
||
return <OrderScreen order={order}/>
|
||
}
|
||
|
||
|
||
const styles = StyleSheet.create({
|
||
orderProductsListWrapper: {
|
||
flex: 0.5,
|
||
backgroundColor: "white",
|
||
borderRadius: RFPercentage(3),
|
||
padding: RFPercentage(2),
|
||
},
|
||
buttonContainer: {
|
||
flex: 1,
|
||
},
|
||
dataContainer: {
|
||
backgroundColor: "white",
|
||
padding: RFPercentage(2),
|
||
flex: 0.5,
|
||
borderRadius: RFPercentage(3),
|
||
},
|
||
buttonsContainer: {
|
||
backgroundColor: "white",
|
||
padding: RFPercentage(2),
|
||
flex: 0.5,
|
||
borderRadius: RFPercentage(3),
|
||
rowGap: responsiveHeight(2)
|
||
},
|
||
contentContainer: {
|
||
flex: 1,
|
||
borderRadius: RFPercentage(3),
|
||
flexDirection: "row",
|
||
columnGap: responsiveWidth(3),
|
||
},
|
||
container: {
|
||
width: "100%",
|
||
height: "100%",
|
||
display: "flex",
|
||
paddingHorizontal: responsiveWidth(5),
|
||
paddingBottom: responsiveHeight(10),
|
||
rowGap: responsiveHeight(2)
|
||
},
|
||
productsContainer: {
|
||
display: "flex",
|
||
flexDirection: "row",
|
||
columnGap: responsiveWidth(3),
|
||
height: responsiveHeight(30)
|
||
},
|
||
|
||
buttonsWrapper: {
|
||
rowGap: responsiveHeight(3)
|
||
},
|
||
imageWrapper: {
|
||
flex: 0.5,
|
||
backgroundColor: "white",
|
||
padding: RFPercentage(2),
|
||
borderRadius: RFPercentage(3)
|
||
},
|
||
image: {
|
||
flex: 1,
|
||
resizeMode: "contain"
|
||
},
|
||
contentWrapper: {
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
gap: 0,
|
||
},
|
||
contentTitle: {
|
||
alignSelf: "center"
|
||
},
|
||
articleText: {
|
||
color: 'blue',
|
||
textDecorationLine: 'underline'
|
||
}
|
||
})
|
||
export default OrderScreen; |