diff --git a/package.json b/package.json index c5eb363..9b9ffb8 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "dependencies": { "@expo/webpack-config": "^19.0.0", "@gorhom/bottom-sheet": "^4", + "@react-native-community/datetimepicker": "7.2.0", + "@react-native-picker/picker": "^2.5.1", "@react-navigation/bottom-tabs": "^6.5.8", "@react-navigation/native": "^6.1.7", "@reduxjs/toolkit": "^1.9.5", diff --git a/src/App.tsx b/src/App.tsx index e5989a4..759d0ba 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,7 +16,6 @@ export default function App() { }) if (!fontsLoading) return Loading... - return ( diff --git a/src/api/ordersApi.ts b/src/api/ordersApi.ts index b09ba4b..12e47c9 100644 --- a/src/api/ordersApi.ts +++ b/src/api/ordersApi.ts @@ -4,8 +4,16 @@ import {Order} from "../types/order"; const router = '/orders'; const ordersApi = { - getOrders: async (lastId: number) => { - + getOrders: async (page: number, orderBy: string, desc: boolean, shipmentDate: string, status: number): Promise => { + const params = { + page: page, + orderBy: orderBy, + desc: Number(desc), // Преобразование boolean в Number (0 или 1) + status: status, + shipmentDate: shipmentDate + }; + let response = await apiClient.get(`${router}/getOrders`, {params}) + return response.data; }, getOrdersBySupplierProduct: async (supplierProductId: number): Promise => { let response = await apiClient.get(`${router}/getBySupplierProductId?supplierProductId=${supplierProductId}`); diff --git a/src/components/Modals/ReprintModal/ReprintModal.tsx b/src/components/Modals/ReprintModal/ReprintModal.tsx index de58c6e..00a0210 100644 --- a/src/components/Modals/ReprintModal/ReprintModal.tsx +++ b/src/components/Modals/ReprintModal/ReprintModal.tsx @@ -21,6 +21,7 @@ const ReprintModal: FC = () => { dispatch(closeReprintModal()); dispatch(openLoadingModal()); PrintingApi.getLabel(order.databaseId).then(pdfBytes => { + PrintingService.getInstance().printPdf(printerName, pdfBytes).then(r => { dispatch(closeLoadingModal()); if (r) dispatch(closeReprintModal()); diff --git a/src/components/Modals/SortingModal/SortingModal.tsx b/src/components/Modals/SortingModal/SortingModal.tsx index 07b337c..6226be6 100644 --- a/src/components/Modals/SortingModal/SortingModal.tsx +++ b/src/components/Modals/SortingModal/SortingModal.tsx @@ -3,11 +3,22 @@ import {BottomSheetModal} from "@gorhom/bottom-sheet"; import {disableDim, enableDim} from "../../../features/interface/interfaceSlice"; import {StyleSheet, View} from "react-native"; import BasicButton from "../../BasicButton/BasicButton"; -import {useDispatch} from "react-redux"; +import {useDispatch, useSelector} from "react-redux"; import {RFPercentage} from "react-native-responsive-fontsize"; import RadioGroup from 'react-native-radio-buttons-group'; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; import {blue} from "../../../css/colors"; +import {Picker} from "@react-native-picker/picker"; +import DateTimePicker from '@react-native-community/datetimepicker'; +import {RootState} from "../../../redux/store"; +import { + closeOrdersFilterModal, + OrderStatus, + orderStatuses, + setDesc, + setOrderBy, setShipmentDate, setStatus +} from "../../../features/ordersFilter/ordersFilterSlice"; +import {retry} from "@reduxjs/toolkit/query"; export type SortingModalHandles = { present: () => void; @@ -19,12 +30,7 @@ export type SortingModalElement = { label: string; value: string; } -type Props = { - onChange: (sortingValue: string) => void; - onClose: () => void; - elements: SortingModalElement[]; - defaultElementId?: string; -}; + const createRadioButton = (element: SortingModalElement) => { return { @@ -41,55 +47,101 @@ const createRadioButton = (element: SortingModalElement) => { }; } -const SortingModal = forwardRef((props: Props, ref) => { - const {elements, onChange, onClose, defaultElementId = ""} = props; - const snapPoints = useMemo(() => ['40%', '40%'], []); +const SortingModal = () => { + const state = useSelector((state: RootState) => state.ordersFilter); + const elements = [ + {id: 'createdOnAsc', value: 'createdOnAsc', label: 'Дата создания по возрастанию'}, + {id: 'createdOnDesc', value: 'createdOnDesc', label: 'Дата создания по убыванию'}, + {id: 'shipmentDateAsc', value: 'shipmentDateAsc', label: 'Дата отгрузки по возрастанию'}, + {id: 'shipmentDateDesc', value: 'shipmentDateDesc', label: 'Дата отгрузки по убыванию'}, + ]; + const [showShipmentPicker, setShowShipmentPicker] = useState(false); + const snapPoints = useMemo(() => ['60%', '60%'], []); const dispatch = useDispatch(); const modalRef = useRef(null); const dismiss = () => { if (!modalRef.current) return; dispatch(disableDim()); modalRef.current.dismiss(); - onClose(); } const present = () => { if (!modalRef.current) return; modalRef.current.present(); dispatch(enableDim()); } - useImperativeHandle(ref, () => ({ - present: present, - dismiss: dismiss - })); - const [selectedId, setSelectedId] = useState(defaultElementId); useEffect(() => { - onChange(selectedId); - }, [selectedId]); + if (state.isVisible) present(); + else dismiss(); + }, [state.isVisible]); return ( { dispatch(disableDim()); + dispatch(closeOrdersFilterModal()) }}> - { + const orderRegex = /(Asc|Desc)$/; + const orderMatch = event.match(orderRegex); + if (!orderMatch) return; + const isDesc = orderMatch[0] === 'Desc'; + const orderByField = event.replace(orderRegex, ''); + if (!["createdOn", "shipmentDate"].includes(orderByField)) return + dispatch(setDesc(isDesc)); + dispatch(setOrderBy(orderByField as "createdOn" | "shipmentDate")); + + }} containerStyle={styles.radioButtons} radioButtons={elements.map(createRadioButton)}/> + + + + + dispatch(setStatus(value))}> + {orderStatuses.map((status) => { + + return ( + + ) + })} + + + setShowShipmentPicker(oldValue => !oldValue)} + label={"Выбрать дату отгрузки"}/> + {showShipmentPicker && + { + if (!event.nativeEvent.timestamp) return; + setShowShipmentPicker(false); + if (event.type === 'set') { + const selectedDate = new Date(event.nativeEvent.timestamp); + dispatch(setShipmentDate(selectedDate.toISOString())); + } + }}/>} { - dismiss(); + dispatch(closeOrdersFilterModal()); }}/> - ); -}); - + ) +}; const styles = StyleSheet.create({ container: { width: "100%", @@ -97,13 +149,17 @@ const styles = StyleSheet.create({ flex: 1, padding: RFPercentage(3), flexDirection: "column", - justifyContent: "space-between" + justifyContent: "space-between", + rowGap: responsiveHeight(1) }, radioButtons: { alignItems: "flex-start" }, - content: {}, + content: { + rowGap: responsiveHeight(1) + }, button: { + marginTop: "auto" }, diff --git a/src/components/OrderCard/OrderCard.tsx b/src/components/OrderCard/OrderCard.tsx index f009ff7..f1d57d9 100644 --- a/src/components/OrderCard/OrderCard.tsx +++ b/src/components/OrderCard/OrderCard.tsx @@ -4,10 +4,11 @@ import {RFPercentage} from "react-native-responsive-fontsize"; import DText from "../DText/DText"; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; import DTitle from "../DTitle/DTitle"; -import {Order} from "../../types/order"; +import {BaseMarketplace, Order} from "../../types/order"; import OrderProductsList from "./OrderProductsList"; import {useDispatch} from "react-redux"; import {setOrder} from "../../features/assembly/assemblySlice"; +import {OrderStatus, OrderStatusDictionary} from "../../features/ordersFilter/ordersFilterSlice"; type Props = { onPress?: (event: GestureResponderEvent) => void @@ -15,9 +16,17 @@ type Props = { onSelect: (order: Order) => void } + + +const BaseMarketplaceIconDict = { + [BaseMarketplace.Wildberries]: require('assets/icons/marketplaces/wildberries.png'), + [BaseMarketplace.Ozon]: require('assets/icons/marketplaces/ozon.png'), + [BaseMarketplace.YandexMarket]: require('assets/icons/marketplaces/yandex_market.png'), +}; const OrderCard: FC = ({onPress, onSelect, order}) => { + return ( - { + { if (onSelect) onSelect(order); }}> @@ -26,7 +35,7 @@ const OrderCard: FC = ({onPress, onSelect, order}) => { {order.orderNumber} - + Селлер: {order.sellerName} Маркетплейс: {order.marketplaceName} @@ -34,7 +43,7 @@ const OrderCard: FC = ({onPress, onSelect, order}) => { - Ожидает сборки + {OrderStatusDictionary[order.status as OrderStatus]} diff --git a/src/components/OrderCard/OrderProductsList.tsx b/src/components/OrderCard/OrderProductsList.tsx index 8b5be46..6d49abd 100644 --- a/src/components/OrderCard/OrderProductsList.tsx +++ b/src/components/OrderCard/OrderProductsList.tsx @@ -9,16 +9,16 @@ import {background} from "../../css/colors"; type ListProps = { products: OrderProduct[]; - onSelected: (product: OrderProduct) => void; + onSelected: (product: number) => void; } type CardProps = { product: OrderProduct; - onPress: (product: OrderProduct) => void; + onPress: (product: number) => void; id: number; } const OrderProductCard: FC = ({product, onPress, id}) => { return ( - onPress(product)}> + onPress(id)}> {id + 1}) {product.productName} diff --git a/src/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx index 73fd591..28fb0a8 100644 --- a/src/components/SearchBar/SearchBar.tsx +++ b/src/components/SearchBar/SearchBar.tsx @@ -7,16 +7,15 @@ import SelectProductModal from "../Modals/SelectProductModal/SelectProductModal" import {SupplierProduct} from "../../types/supplierProduct"; import barcodeApi from "../../api/barcodeApi"; import {useDispatch, useSelector} from "react-redux"; -import {openScanModal} from "../../features/scanModal/scanModalSlice"; +import {openScanModal, setScannedData} from "../../features/scanModal/scanModalSlice"; import {RootState} from "../../redux/store"; type Props = { - onSearch: (text: string) => void; + onSearch?: (text: string) => void; onSupplierProductSelected?: (supplierProduct: SupplierProduct) => void } const SearchBar: FC = ({onSearch, onSupplierProductSelected}) => { - // const [isScanModalVisible, setIsScanModalVisible] = useState(false); - // const [, setSelectProductModalVisible] = useState(false); + const dispatch = useDispatch(); const [searchInput, setSearchInput] = useState(""); const textInputRef = useRef(null); @@ -26,19 +25,19 @@ const SearchBar: FC = ({onSearch, onSupplierProductSelected}) => { useEffect(() => { if (!scannedData) return; barcodeApi.searchProducts(scannedData).then((response) => { - console.log("Response: " + response); setProducts(response) }); }, [scannedData]); const selectProductModalVisible = products.length > 0; return ( - { if (onSupplierProductSelected) onSupplierProductSelected(product); setProducts([]); + dispatch(setScannedData(undefined)); }}/> { + if (!onSearch) return; onSearch(searchInput); if (textInputRef.current) { textInputRef.current.clear(); @@ -77,7 +76,7 @@ const styles = StyleSheet.create({ borderTopRightRadius: responsiveWidth(1), borderBottomRightRadius: responsiveWidth(1), paddingHorizontal: responsiveWidth(5), - height:'100%' + height: '100%' }, scanImageWrapper: { paddingHorizontal: responsiveWidth(1), diff --git a/src/features/assembly/assemblySlice.ts b/src/features/assembly/assemblySlice.ts index d9b2778..14aa064 100644 --- a/src/features/assembly/assemblySlice.ts +++ b/src/features/assembly/assemblySlice.ts @@ -1,12 +1,16 @@ import {createSlice, PayloadAction} from "@reduxjs/toolkit"; -import {Order} from "../../types/order"; +import {Order, OrderProduct} from "../../types/order"; import {Assembly, ASSEMBLY_STATE} from "../../types/assembly"; +import selectProductElement from "../../components/Modals/SelectProductModal/SelectProductElement"; export interface AssemblyState { order?: Order; + initialOrder?: Order; assembly?: Assembly; - localState?: ASSEMBLY_STATE + selectedProductId?: number; + localState?: ASSEMBLY_STATE; + selectedProduct?: OrderProduct } const initialState: AssemblyState = { @@ -18,7 +22,9 @@ export const assembly = createSlice({ initialState, reducers: { setOrder: (state, action) => { + state.initialOrder = action.payload; state.order = action.payload; + state.selectedProductId = 0; }, setAssembly: (state, action: PayloadAction) => { state.assembly = action.payload; @@ -56,6 +62,7 @@ export const assembly = createSlice({ product.assembled = true; } }); + state.selectedProduct = state.order.products.find(product => product.databaseId == action.payload.orderProductId); // If all products is assembled if (!state.order.products.find(product => !product.assembled)) { state.assembly.state = ASSEMBLY_STATE.ALL_PRODUCTS_ASSEMBLED; @@ -72,9 +79,23 @@ export const assembly = createSlice({ product.shipped = true; } }); + state.selectedProduct = state.order.products.find(product => product.databaseId == action.payload.orderProductId); + + }, + selectProduct: (state, action: PayloadAction) => { + if (!state.order) return; + state.selectedProduct = state.order.products[action.payload]; } } }) -export const {setOrder, setAssembled, setAssembly, startAssembly, endAssembly, confirmAssembly} = assembly.actions; +export const { + setOrder, + setAssembled, + selectProduct, + setAssembly, + startAssembly, + endAssembly, + confirmAssembly +} = assembly.actions; export default assembly.reducer; \ No newline at end of file diff --git a/src/features/ordersFilter/ordersFilterSlice.ts b/src/features/ordersFilter/ordersFilterSlice.ts new file mode 100644 index 0000000..9a76d8d --- /dev/null +++ b/src/features/ordersFilter/ordersFilterSlice.ts @@ -0,0 +1,100 @@ +import {createSlice, PayloadAction} from "@reduxjs/toolkit"; + +export enum OrderStatus { + ALL = -1, + AWAITING_PACKAGING, + AWAITING_DELIVER, + DELIVERING, + DELIVERED, + CANCELLED, + PARTIALLY_RETURNED, + FULLY_RETURNED, + DISPUTED +} + +export const orderStatuses = [ + {key: OrderStatus.ALL, label: 'Все'}, + {key: OrderStatus.AWAITING_PACKAGING, label: 'Ожидает сборки'}, + {key: OrderStatus.AWAITING_DELIVER, label: 'Ожидает отгрузки'}, + {key: OrderStatus.DELIVERING, label: 'Доставляется'}, + {key: OrderStatus.DELIVERED, label: 'Доставлен'}, + {key: OrderStatus.CANCELLED, label: 'Отменен'}, + {key: OrderStatus.PARTIALLY_RETURNED, label: 'Частичный возврат'}, + {key: OrderStatus.FULLY_RETURNED, label: 'Полный возврат'}, + {key: OrderStatus.DISPUTED, label: 'Спорный'}, +]; +export const OrderStatusDictionary: { [key in OrderStatus]: string } = { + [OrderStatus.ALL]: 'Все', + [OrderStatus.AWAITING_PACKAGING]: 'Ожидает сборки', + [OrderStatus.AWAITING_DELIVER]: 'Ожидает отгрузки', + [OrderStatus.DELIVERING]: 'Доставляется', + [OrderStatus.DELIVERED]: 'Доставлен', + [OrderStatus.CANCELLED]: 'Отменен', + [OrderStatus.PARTIALLY_RETURNED]: 'Частичный возврат', + [OrderStatus.FULLY_RETURNED]: 'Полный возврат', + [OrderStatus.DISPUTED]: 'Спорный', +}; + +export interface OrdersFilterState { + isVisible: boolean; + orderBy: "createdOn" | "shipmentDate"; + desc: boolean; + status: OrderStatus; + shipmentDate: string; + page: number; +} + +const initialState: OrdersFilterState = { + isVisible: false, + orderBy: "createdOn", + desc: true, + shipmentDate: (new Date()).toISOString(), + status: OrderStatus.AWAITING_PACKAGING, + page: 0 +} + +export const ordersFilterSlice = createSlice({ + name: 'ordersFilter', + initialState, + reducers: { + openOrdersFilterModal: (state) => { + state.isVisible = true + }, + closeOrdersFilterModal: (state) => { + state.isVisible = false + }, + setOrderBy: (state, action: PayloadAction<"createdOn" | "shipmentDate">) => { + state.orderBy = action.payload; + }, + setDesc: (state, action: PayloadAction) => { + state.desc = action.payload; + }, + setStatus: (state, action: PayloadAction) => { + state.status = action.payload; + }, + setShipmentDate: (state, action: PayloadAction) => { + state.shipmentDate = action.payload; + }, + setPage: (state, action: PayloadAction) => { + state.page = action.payload; + }, + nextPage: (state) => { + state.page = state.page + 1 + }, + refreshPagination: (state) => { + state.page = 0 + } + } +}) + +export const { + openOrdersFilterModal, + closeOrdersFilterModal, + refreshPagination, + nextPage, + setOrderBy, + setDesc, + setStatus, + setShipmentDate +} = ordersFilterSlice.actions; +export default ordersFilterSlice.reducer; \ No newline at end of file diff --git a/src/redux/store.ts b/src/redux/store.ts index 3e2fb30..f184bbd 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -8,6 +8,7 @@ import imageZoomModalReducer from 'features/imageZoomModal/loadingModalSlice'; import assemblyReducer from 'features/assembly/assemblySlice'; import printingReducer from 'features/printing/printingSlice'; import reprintModalReducer from 'features/reprintModal/reprintModalSlice'; +import ordersFilterReducer from 'features/ordersFilter/ordersFilterSlice'; import {useDispatch} from "react-redux"; export const store = configureStore({ @@ -19,7 +20,8 @@ export const store = configureStore({ assembly: assemblyReducer, printing: printingReducer, reprintModal: reprintModalReducer, - imageZoomModal: imageZoomModalReducer + imageZoomModal: imageZoomModalReducer, + ordersFilter: ordersFilterReducer }, }); diff --git a/src/screens/BarcodeScreen/BarcodeScreen.tsx b/src/screens/BarcodeScreen/BarcodeScreen.tsx index 61e5cf3..326419a 100644 --- a/src/screens/BarcodeScreen/BarcodeScreen.tsx +++ b/src/screens/BarcodeScreen/BarcodeScreen.tsx @@ -1,15 +1,68 @@ -import {Button, Text, View} from "react-native"; +import {Button, StyleSheet, Text, View} from "react-native"; import {useAppDispatch} from "../../redux/store"; import * as process from "process"; +import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; +import SearchBar from "../../components/SearchBar/SearchBar"; +import {useDispatch} from "react-redux"; +import {NavigationProp, useNavigation} from "@react-navigation/native"; +import {TabNavigatorParamList} from "../MainScreen/MainScreen"; +import {FlashList} from "@shopify/flash-list"; +import {Order} from "../../types/order"; +import OrderCard from "../../components/OrderCard/OrderCard"; +import {setOrder} from "../../features/assembly/assemblySlice"; +import flashListSeparator from "../../components/FlashListSeparator/FlashListSeparator"; +import {useEffect, useState} from "react"; +import {openScanModal} from "../../features/scanModal/scanModalSlice"; +import ordersApi from "../../api/ordersApi"; function BarcodeScreen() { + const dispatch = useDispatch(); + const navigator = useNavigation>(); + const [orders, setOrders] = useState([]); + + useEffect(() => { + dispatch(openScanModal()); + }, []); return ( - - Barcode + + { + ordersApi.getOrdersBySupplierProduct(product.supplierProductId).then(setOrders) + }}/> + + item.orderNumber.toString()} + renderItem={({item}) => + { + dispatch(setOrder(order)); + navigator.navigate("Home"); + }} order={item}/>} + showsHorizontalScrollIndicator={false} + showsVerticalScrollIndicator={true} + onEndReachedThreshold={0.1} + estimatedItemSize={720} + ItemSeparatorComponent={flashListSeparator} + + /> + ) } +const styles = StyleSheet.create({ + container: { + width: "100%", + height: "100%", + display: "flex", + paddingHorizontal: responsiveWidth(5), + rowGap: responsiveHeight(2), + fontWeight: '500' + }, + content: { + flex: 1, + }, +}); export default BarcodeScreen; \ No newline at end of file diff --git a/src/screens/CommonPage/CommonPage.tsx b/src/screens/CommonPage/CommonPage.tsx index 235e783..f3ba8eb 100644 --- a/src/screens/CommonPage/CommonPage.tsx +++ b/src/screens/CommonPage/CommonPage.tsx @@ -18,6 +18,7 @@ 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"; +import SortingModal from "../../components/Modals/SortingModal/SortingModal"; function CommonPage() { const dim = useSelector((state: RootState) => state.interface.dim); @@ -62,6 +63,7 @@ function CommonPage() { + diff --git a/src/screens/OrderScreen/OrderScreen.tsx b/src/screens/OrderScreen/OrderScreen.tsx index 5877992..2f33433 100644 --- a/src/screens/OrderScreen/OrderScreen.tsx +++ b/src/screens/OrderScreen/OrderScreen.tsx @@ -17,7 +17,7 @@ import printingApi from "../../api/printingApi"; import PrintingService from "../../utils/PrintingService"; import OrderProductsList from "../../components/OrderCard/OrderProductsList"; import { - confirmAssembly, endAssembly, + confirmAssembly, endAssembly, selectProduct, setAssembled, setAssembly, setOrder, @@ -82,9 +82,9 @@ const OrderScreen: FC = ({order}) => { 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, setSelectedProduct] = useState(order.products[0]); - + const selectedProduct = useSelector((state: RootState) => state.assembly.selectedProduct); const [acceptModalVisible, setAcceptModalVisible] = useState(false); const [skipConfirmButtonVisible, setSkipConfirmButtonVisible] = useState(false); const _confirmAssembly = async () => { @@ -113,11 +113,13 @@ const OrderScreen: FC = ({order}) => { onPress={() => setAcceptModalVisible(true)} label={"Начать сборку"}/>) case ASSEMBLY_STATE.ASSEMBLING_PRODUCTS: + return ( { + if (!selectedProduct) return; dispatch(setAssembled({orderProductId: selectedProduct.databaseId})) }} />) @@ -183,10 +185,10 @@ const OrderScreen: FC = ({order}) => { dispatch(setLoadingText('Идет печать этикетки...')) dispatch(openLoadingModal()) printingApi.getLabel(order.databaseId).then(pdfData => { - printingService.getInstance().printPdf('ozon', pdfData).then((response) => { + printingService.getInstance().printPdf('wildberries', pdfData).then((response) => { dispatch(closeLoadingModal()); if (response) return; - dispatch(setPrinterName({printerName: 'ozon'})); + dispatch(setPrinterName({printerName: 'wildberries'})); dispatch(openReprintModal()); }); }) @@ -204,23 +206,27 @@ const OrderScreen: FC = ({order}) => { }); }, [assemblyState]); - + useEffect(() => { + if (!order) return; + dispatch(selectProduct(0)); + }, [initialOrder]); return ( - { + { if (!order) return; - setSelectedProduct(product) + dispatch(selectProduct(productId)) }}/> - { + { + if (!selectedProduct) return; dispatch(setImages([selectedProduct.imageUrl])); dispatch(openImageZoomModal()); }}> - + @@ -233,11 +239,11 @@ const OrderScreen: FC = ({order}) => { Селлер: {order.sellerName} {} Товар - Артикул DENCO: {selectedProduct.dencoArticle} - Поставщик: {selectedProduct.supplierName} + Артикул DENCO: {selectedProduct?.dencoArticle} + Поставщик: {selectedProduct?.supplierName} Номер товара: {0} - {} - Сборка + {/*{}*/} + {/*Сборка*/} @@ -249,7 +255,6 @@ const OrderScreen: FC = ({order}) => { onAccepted={() => { setAcceptModalVisible(false); assemblyApi.create(order.databaseId).then(creationResult => { - console.log(creationResult.message) Toast.show({ type: creationResult.ok ? 'success' : 'error', text1: 'Создание сборки', @@ -273,7 +278,6 @@ const OrderScreen: FC = ({order}) => { export const OrderScreenController: FC = () => { const order: Order | undefined = useSelector((state: RootState) => state.assembly.order); if (!order) return - console.log(order) return } diff --git a/src/screens/OrderScreen/useOrders.tsx b/src/screens/OrderScreen/useOrders.tsx new file mode 100644 index 0000000..adbfe9f --- /dev/null +++ b/src/screens/OrderScreen/useOrders.tsx @@ -0,0 +1,41 @@ +import {useEffect, useState} from "react"; +import {Order} from "../../types/order"; +import ordersApi from "../../api/ordersApi"; +import {setOrder} from "../../features/assembly/assemblySlice"; +import {RootState} from "../../redux/store"; +import {useDispatch, useSelector} from "react-redux"; +import {refreshPagination} from "../../features/ordersFilter/ordersFilterSlice"; + + +const useOrders = () => { + const dispatch = useDispatch(); + const [orders, setOrders] = useState([]); + const [isRefreshing, setIsRefreshing] = useState(false); + const filterState = useSelector((state: RootState) => state.ordersFilter); + const refresh = () => { + if (filterState.page == 0) return; + setIsRefreshing(true); + setOrders([]); + dispatch(refreshPagination()); + } + useEffect(() => { + if (filterState.isVisible) return; + + ordersApi.getOrders(filterState.page, filterState.orderBy, filterState.desc, filterState.shipmentDate, filterState.status).then(response => { + setOrders(oldOrders => [...oldOrders, ...response]); + setIsRefreshing(false); + }); + }, [filterState.page]); + + + useEffect(() => { + if (filterState.isVisible) return; + setOrders([]); + setIsRefreshing(true); + dispatch(refreshPagination()); + }, [filterState.orderBy, filterState.desc, filterState.status, filterState.shipmentDate, filterState.isVisible]); + + return {refresh, isRefreshing, orders}; +} + +export default useOrders; \ No newline at end of file diff --git a/src/screens/OrdersScreen/OrdersScreen.tsx b/src/screens/OrdersScreen/OrdersScreen.tsx index b03fd31..23a8ea8 100644 --- a/src/screens/OrdersScreen/OrdersScreen.tsx +++ b/src/screens/OrdersScreen/OrdersScreen.tsx @@ -1,5 +1,4 @@ import {StyleSheet, View} from "react-native"; -import SearchBar from "../../components/SearchBar/SearchBar"; import OrderCard from "../../components/OrderCard/OrderCard"; import {RFPercentage} from "react-native-responsive-fontsize"; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; @@ -9,66 +8,50 @@ import {useEffect, useRef, useState} from "react"; import {Order} from "../../types/order"; import {FlashList} from "@shopify/flash-list"; import SortingModal, { - SortingModalElement, SortingModalHandles } from "../../components/Modals/SortingModal/SortingModal"; import flashListSeparator from "../../components/FlashListSeparator/FlashListSeparator"; -import ordersApi from "../../api/ordersApi"; import {setOrder} from "../../features/assembly/assemblySlice"; import {NavigationProp, useNavigation} from "@react-navigation/native"; import {TabNavigatorParamList} from "../MainScreen/MainScreen"; +import useOrders from "../OrderScreen/useOrders"; +import {nextPage, openOrdersFilterModal} from "../../features/ordersFilter/ordersFilterSlice"; function OrdersScreen() { - const dispatch = useDispatch(); const navigator = useNavigation>(); + const {refresh, isRefreshing, orders} = useOrders(); - const [orders, setOrders] = useState([]); - const sortingModalRef = useRef(null); - const defaultSortingValue = 'createdOnAsc'; - const sortingModalElements: SortingModalElement[] = [ - {id: 'createdOnAsc', value: 'createdOnAsc', label: 'Дата создания по убыванию'}, - {id: 'createdOnDesc', value: 'createdOnDesc', label: 'Дата создания по возрастанию'}, - {id: 'shipmentDateAsc', value: 'shipmentDateAsc', label: 'Дата отгрузки по убыванию'}, - {id: 'shipmentDateDesc', value: 'shipmentDateDesc', label: 'Дата отгрузки по возрастанию'}, - ]; - - const [sortingValue, setSortingValue] = useState(defaultSortingValue); return ( - { - }} onSupplierProductSelected={product => { - ordersApi.getOrdersBySupplierProduct(product.supplierProductId).then(setOrders) - }}/> + { - if (!sortingModalRef.current) return; - sortingModalRef.current.present(); + dispatch(openOrdersFilterModal()); }}/> - item.orderNumber.toString()} - renderItem={({item}) => - dispatch(setOrder(order))} order={item}/>} - showsHorizontalScrollIndicator={false} - showsVerticalScrollIndicator={true} - onEndReachedThreshold={0.1} - estimatedItemSize={720} - onEndReached={() => { - }} - ItemSeparatorComponent={flashListSeparator} + item.databaseId.toString()} + renderItem={({item}) => + { + dispatch(setOrder(order)); + navigator.navigate("Home"); + }} order={item}/>} + showsHorizontalScrollIndicator={false} + showsVerticalScrollIndicator={true} + onEndReachedThreshold={0.5} + estimatedItemSize={720} + onEndReached={() => { + if (!orders.length) return; + dispatch(nextPage()); + }} + ItemSeparatorComponent={flashListSeparator} /> - { - }} - ref={sortingModalRef} - elements={sortingModalElements} - defaultElementId={defaultSortingValue} - /> diff --git a/src/screens/OrdersScreen/useOrdersFilter.tsx b/src/screens/OrdersScreen/useOrdersFilter.tsx new file mode 100644 index 0000000..b71fa5d --- /dev/null +++ b/src/screens/OrdersScreen/useOrdersFilter.tsx @@ -0,0 +1,3 @@ +const useOrdersFilter = () => { + +} \ No newline at end of file diff --git a/src/types/order.ts b/src/types/order.ts index c21d14a..a019c71 100644 --- a/src/types/order.ts +++ b/src/types/order.ts @@ -10,10 +10,19 @@ export type OrderProduct = { }; +export enum BaseMarketplace { + Wildberries, + Ozon, + YandexMarket +} + export type Order = { databaseId: number; orderNumber: string; marketplaceName: string; + baseMarketplace: BaseMarketplace; sellerName: string; products: OrderProduct[]; + status: number; }; +