diff --git a/app.json b/app.json index bb52bf5..fa64b4a 100644 --- a/app.json +++ b/app.json @@ -1,7 +1,14 @@ { "expo": { "plugins": [ - "react-native-keyevent-expo-config-plugin" + [ + "expo-build-properties", + { + "android": { + "usesCleartextTraffic": true + } + } + ] ], "name": "Assemblr", "slug": "Assemblr", @@ -25,7 +32,10 @@ "foregroundImage": "./src/assets/adaptive-icon.png", "backgroundColor": "#ffffff" }, - "package": "com.anonymous.Assemblr" + "package": "com.anonymous.Assemblr", + "permissions": [ + "INTERNET" + ] }, "web": { "favicon": "./src/assets/favicon.png" diff --git a/package.json b/package.json index 9b9ffb8..881f48c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "axios": "^1.5.0", "babel-plugin-module-resolver": "^5.0.0", "expo": "~49.0.8", + "expo-build-properties": "~0.8.3", "expo-secure-store": "~12.3.1", "expo-splash-screen": "~0.20.5", "expo-status-bar": "~1.6.0", @@ -37,13 +38,13 @@ "react-native-keyevent-expo-config-plugin": "^1.0.49", "react-native-modal": "^13.0.1", "react-native-paper": "^5.10.6", - "react-native-progress": "^5.0.1", "react-native-radio-buttons-group": "^3.0.5", "react-native-reanimated": "3.3.0", "react-native-responsive-dimensions": "^3.1.1", "react-native-responsive-fontsize": "^0.5.1", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", + "react-native-svg": "13.9.0", "react-native-toast-message": "^2.1.7", "react-native-vector-icons": "^10.0.0", "react-native-web": "~0.19.6", diff --git a/src/api/apiClient.ts b/src/api/apiClient.ts index f3508cd..e72b58b 100644 --- a/src/api/apiClient.ts +++ b/src/api/apiClient.ts @@ -5,6 +5,7 @@ import {logout} from "../features/auth/authSlice"; import {store} from "../redux/store"; const apiClient = axios.create({ + // baseURL: 'https://assemblr.denco.store', baseURL: 'http://192.168.1.101:5000', }); @@ -26,12 +27,12 @@ apiClient.interceptors.request.use(async (config) => { return config; }, function (error) { + console.log("очко") + if (error.response && error.response.status === 401) { console.log("очко") - } - // return Promise.reject(error); }); diff --git a/src/api/assemblyApi.ts b/src/api/assemblyApi.ts index 1f6c28a..da1eae4 100644 --- a/src/api/assemblyApi.ts +++ b/src/api/assemblyApi.ts @@ -17,6 +17,10 @@ const assemblyApi = { let response = await apiClient.post(`${router}/close`, {assemblyId}); return response.data; }, + cancel: async (): Promise<{ ok: boolean, message: string }> => { + let response = await apiClient.post(`${router}/cancel`); + return response.data; + }, getActive: async (): Promise => { let response = await apiClient.get(`${router}/getActive`); return response.data; diff --git a/src/api/barcodeApi.ts b/src/api/barcodeApi.ts index ad50563..5f0af9f 100644 --- a/src/api/barcodeApi.ts +++ b/src/api/barcodeApi.ts @@ -1,10 +1,10 @@ -import {SupplierProduct} from "../types/supplierProduct"; import apiClient from "./apiClient"; +import {Product} from "../types/product"; const router = '/barcode'; const barcodeApi = { - searchProducts: async (barcode: string): Promise => { + searchProducts: async (barcode: string): Promise => { let response = await apiClient.get(`${router}/searchProducts?barcode=${barcode}`); return response.data; } diff --git a/src/api/generalApi.ts b/src/api/generalApi.ts new file mode 100644 index 0000000..9cabadb --- /dev/null +++ b/src/api/generalApi.ts @@ -0,0 +1,12 @@ +import apiClient from "./apiClient"; +import {ShippingWarehouse} from "../types/shippingWarehouse"; + +const router = '/general'; + +const generalApi = { + getShippingWarehouses: async (): Promise => { + let response = await apiClient.get(`${router}/getShippingWarehouses`); + return response.data; + }, +} +export default generalApi; \ No newline at end of file diff --git a/src/api/ordersApi.ts b/src/api/ordersApi.ts index 12e47c9..e68df74 100644 --- a/src/api/ordersApi.ts +++ b/src/api/ordersApi.ts @@ -1,22 +1,24 @@ import apiClient from "./apiClient"; import {Order} from "../types/order"; +import * as inspector from "inspector"; const router = '/orders'; const ordersApi = { - getOrders: async (page: number, orderBy: string, desc: boolean, shipmentDate: string, status: number): Promise => { + getOrders: async (page: number, orderBy: string, desc: boolean, shipmentDate: string, status: number, shipmentWarehouseId: number): Promise => { const params = { page: page, orderBy: orderBy, desc: Number(desc), // Преобразование boolean в Number (0 или 1) status: status, - shipmentDate: shipmentDate + shipmentDate: shipmentDate, + shipmentWarehouseId: shipmentWarehouseId }; 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}`); + getOrdersByProduct: async (productId: number): Promise => { + let response = await apiClient.get(`${router}/getByProductId?productId=${productId}`); return response.data; }, getOrderById: async (orderId: number): Promise => { diff --git a/src/api/userApi.ts b/src/api/userApi.ts index ec0fd19..80b55fa 100644 --- a/src/api/userApi.ts +++ b/src/api/userApi.ts @@ -5,8 +5,5 @@ const userApi = { let response = await apiClient.post('/auth/login', {login, password}); return response.data; }, - test: async () => { - await apiClient.post('/auth/protected'); - } } export default userApi; \ No newline at end of file diff --git a/src/assets/adaptive-icon.png b/src/assets/adaptive-icon.png index 03d6f6b..a6967d5 100644 Binary files a/src/assets/adaptive-icon.png and b/src/assets/adaptive-icon.png differ diff --git a/src/assets/icon.png b/src/assets/icon.png index a0b1526..f9af95a 100644 Binary files a/src/assets/icon.png and b/src/assets/icon.png differ diff --git a/src/assets/icons/settings/close.png b/src/assets/icons/settings/close.png new file mode 100644 index 0000000..71098f7 Binary files /dev/null and b/src/assets/icons/settings/close.png differ diff --git a/src/components/Modals/LoadingModal/LoadingModal.tsx b/src/components/Modals/LoadingModal/LoadingModal.tsx index 4d84387..a151b54 100644 --- a/src/components/Modals/LoadingModal/LoadingModal.tsx +++ b/src/components/Modals/LoadingModal/LoadingModal.tsx @@ -1,31 +1,21 @@ -import {FC} from "react"; -import {Props} from "react-native-paper"; +import React, {FC, useState} from "react"; import {StyleSheet, View} from "react-native"; -import {BottomSheetModalProvider} from "@gorhom/bottom-sheet"; import {useSelector} from "react-redux"; import {RootState} from "../../../redux/store"; import Modal from "react-native-modal"; -import {background, blue} from "../../../css/colors"; +import {background} from "../../../css/colors"; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; -import * as Progress from 'react-native-progress'; import DTitle from "../../DTitle/DTitle"; -import {RFPercentage} from "react-native-responsive-fontsize"; const LoadingModal: FC = () => { const isVisible = useSelector((state: RootState) => state.loadingModal.isVisible); const loadingText = useSelector((state: RootState) => state.loadingModal.loadingText); - + const [ch, sCh] = useState(false); return ( {loadingText} - diff --git a/src/components/Modals/SelectProductModal/SelectProductElement.tsx b/src/components/Modals/SelectProductModal/SelectProductElement.tsx index 14f36b9..0bd0378 100644 --- a/src/components/Modals/SelectProductModal/SelectProductElement.tsx +++ b/src/components/Modals/SelectProductModal/SelectProductElement.tsx @@ -5,10 +5,11 @@ import DTitle from "../../DTitle/DTitle"; import DText from "../../DText/DText"; import {RFPercentage} from "react-native-responsive-fontsize"; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; +import {Product} from "../../../types/product"; type Props = { - product: SupplierProduct; - onPress: (product: SupplierProduct) => void; + product: Product; + onPress: (product: Product) => void; } const SelectProductElement: FC = React.memo(({product, onPress}) => { return ( @@ -24,18 +25,7 @@ const SelectProductElement: FC = React.memo(({product, onPress}) => { {product.productName} {} - {product.supplierName && - Поставщик: {product.supplierName} - } - {product.supplierArticle && - Артикул: {product.supplierArticle} - } - {product.inBlock && - В блоке: {product.inBlock} - } - {product.shelfNumber && - Номер полки: {product.shelfNumber} - } + Артикул DENCO: {product.dencoArticle} diff --git a/src/components/Modals/SelectProductModal/SelectProductModal.tsx b/src/components/Modals/SelectProductModal/SelectProductModal.tsx index c57ba16..f54e4b2 100644 --- a/src/components/Modals/SelectProductModal/SelectProductModal.tsx +++ b/src/components/Modals/SelectProductModal/SelectProductModal.tsx @@ -8,11 +8,12 @@ import FlashListSeparator from "../../FlashListSeparator/FlashListSeparator"; import DTitle from "../../DTitle/DTitle"; import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; import {background} from "../../../css/colors"; +import {Product} from "../../../types/product"; type Props = { visible: boolean; - products: SupplierProduct[]; - onSelected: (product: SupplierProduct) => void + products: Product[]; + onSelected: (product: Product) => void } @@ -27,7 +28,7 @@ const SelectProductModal: FC = ({visible, products, onSelected}) => { data={products} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} - keyExtractor={(product) => product.supplierProductId.toString()} + keyExtractor={(product) => product.productId.toString()} renderItem={(product) => } ItemSeparatorComponent={FlashListSeparator} > diff --git a/src/components/Modals/SortingModal/SortingModal.tsx b/src/components/Modals/SortingModal/SortingModal.tsx index 6226be6..2eaf895 100644 --- a/src/components/Modals/SortingModal/SortingModal.tsx +++ b/src/components/Modals/SortingModal/SortingModal.tsx @@ -13,12 +13,11 @@ import DateTimePicker from '@react-native-community/datetimepicker'; import {RootState} from "../../../redux/store"; import { closeOrdersFilterModal, - OrderStatus, orderStatuses, setDesc, - setOrderBy, setShipmentDate, setStatus + setOrderBy, setShipmentDate, setShippingWarehouse, setStatus } from "../../../features/ordersFilter/ordersFilterSlice"; -import {retry} from "@reduxjs/toolkit/query"; +import ShippingWarehouseSelect from "../../ShippingWarehouseSelect/ShippingWarehouseSelect"; export type SortingModalHandles = { present: () => void; @@ -49,6 +48,8 @@ const createRadioButton = (element: SortingModalElement) => { const SortingModal = () => { const state = useSelector((state: RootState) => state.ordersFilter); + const shipmentWarehouseSelectorState = useSelector((state: RootState) => state.shippingWarehouseSelect); + const elements = [ {id: 'createdOnAsc', value: 'createdOnAsc', label: 'Дата создания по возрастанию'}, {id: 'createdOnDesc', value: 'createdOnDesc', label: 'Дата создания по убыванию'}, @@ -73,6 +74,9 @@ const SortingModal = () => { if (state.isVisible) present(); else dismiss(); }, [state.isVisible]); + useEffect(() => { + dispatch(setShippingWarehouse(shipmentWarehouseSelectorState.selectedShippingWarehouse)); + }, [shipmentWarehouseSelectorState.selectedShippingWarehouse]); return ( { radioButtons={elements.map(createRadioButton)}/> - + + + dispatch(setStatus(value))}> + {orderStatuses.map((status) => { + return ( + + ) + })} + + - dispatch(setStatus(value))}> - {orderStatuses.map((status) => { - - return ( - - ) - })} - + + setShowShipmentPicker(oldValue => !oldValue)} label={"Выбрать дату отгрузки"}/> {showShipmentPicker && @@ -162,7 +166,13 @@ const styles = StyleSheet.create({ marginTop: "auto" }, - + selectors: { + rowGap: responsiveHeight(1) + }, + selector: { + borderWidth: responsiveWidth(0.1), + borderRadius: responsiveWidth(1) + } }); diff --git a/src/components/SearchBar/ScanModal.tsx b/src/components/SearchBar/ScanModal.tsx index 63f8fba..db61d15 100644 --- a/src/components/SearchBar/ScanModal.tsx +++ b/src/components/SearchBar/ScanModal.tsx @@ -14,11 +14,7 @@ const ScanModal: FC = () => { const visible = useSelector((state: RootState) => state.scanModal.isVisible); const dispatch = useDispatch(); useEffect(() => { - // if (visible) inputRef.current?.focus(); - if (visible){ - dispatch(setScannedData('4750735280715')); - dispatch(closeScanModal()) - } + if (visible) inputRef.current?.focus(); }, [visible]); return ( diff --git a/src/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx index 28fb0a8..2d2b416 100644 --- a/src/components/SearchBar/SearchBar.tsx +++ b/src/components/SearchBar/SearchBar.tsx @@ -9,17 +9,18 @@ import barcodeApi from "../../api/barcodeApi"; import {useDispatch, useSelector} from "react-redux"; import {openScanModal, setScannedData} from "../../features/scanModal/scanModalSlice"; import {RootState} from "../../redux/store"; +import {Product} from "../../types/product"; type Props = { onSearch?: (text: string) => void; - onSupplierProductSelected?: (supplierProduct: SupplierProduct) => void + onProductSelected?: (product: Product) => void } -const SearchBar: FC = ({onSearch, onSupplierProductSelected}) => { +const SearchBar: FC = ({onSearch, onProductSelected}) => { const dispatch = useDispatch(); const [searchInput, setSearchInput] = useState(""); const textInputRef = useRef(null); - const [products, setProducts] = useState([]); + const [products, setProducts] = useState([]); const scannedData = useSelector((state: RootState) => state.scanModal.scannedData); useEffect(() => { @@ -28,14 +29,22 @@ const SearchBar: FC = ({onSearch, onSupplierProductSelected}) => { setProducts(response) }); }, [scannedData]); - const selectProductModalVisible = products.length > 0; + useEffect(() => { + if (products.length == 0 || products.length > 1 || !onProductSelected) return; + onProductSelected(products[0]); + setProducts([]); + dispatch(setScannedData(undefined)); + }, [products]); + const selectProductModalVisible = products.length > 1; return ( - { - if (onSupplierProductSelected) onSupplierProductSelected(product); - setProducts([]); - dispatch(setScannedData(undefined)); - }}/> + { + if (onProductSelected) onProductSelected(product); + setProducts([]); + dispatch(setScannedData(undefined)); + }}/> { if (!onSearch) return; onSearch(searchInput); diff --git a/src/components/ShippingWarehouseSelect/ShippingWarehouseSelect.tsx b/src/components/ShippingWarehouseSelect/ShippingWarehouseSelect.tsx new file mode 100644 index 0000000..3e33532 --- /dev/null +++ b/src/components/ShippingWarehouseSelect/ShippingWarehouseSelect.tsx @@ -0,0 +1,44 @@ +import {FC, useEffect} from "react"; +import {useDispatch, useSelector} from "react-redux"; +import {RootState} from "../../redux/store"; +import {Picker} from "@react-native-picker/picker"; +import generalApi from "../../api/generalApi"; +import { + initializeShippingWarehouseSelect, + selectShippingWarehouse +} from "../../features/shippingWarehouseSelect/shippingWarehouseSelectSlice"; +import {responsiveWidth} from "react-native-responsive-dimensions"; +import {View} from "react-native"; + +const ShippingWarehouseSelect: FC = () => { + const state = useSelector((state: RootState) => state.shippingWarehouseSelect); + const dispatch = useDispatch(); + useEffect(() => { + if (state.initialized) return; + generalApi.getShippingWarehouses().then(shippingWarehouses => + dispatch(initializeShippingWarehouseSelect(shippingWarehouses))) + }, []); + return ( + + dispatch(selectShippingWarehouse({shippingWarehouseId: value}))} + > + {state.shippingWarehouses.map(shippingWarehouse => ( + + ))} + + + + ) +} + +export default ShippingWarehouseSelect \ No newline at end of file diff --git a/src/features/assembly/assemblySlice.ts b/src/features/assembly/assemblySlice.ts index 14aa064..2e385a1 100644 --- a/src/features/assembly/assemblySlice.ts +++ b/src/features/assembly/assemblySlice.ts @@ -25,6 +25,7 @@ export const assembly = createSlice({ state.initialOrder = action.payload; state.order = action.payload; state.selectedProductId = 0; + state.localState = ASSEMBLY_STATE.NOT_STARTED; }, setAssembly: (state, action: PayloadAction) => { state.assembly = action.payload; @@ -80,11 +81,20 @@ export const assembly = createSlice({ } }); state.selectedProduct = state.order.products.find(product => product.databaseId == action.payload.orderProductId); - + }, + setLocalState: (state, action: PayloadAction) => { + state.localState = action.payload; }, selectProduct: (state, action: PayloadAction) => { if (!state.order) return; state.selectedProduct = state.order.products[action.payload]; + }, + reset: (state) => { + state.assembly = undefined; + state.order = undefined; + state.localState = ASSEMBLY_STATE.NOT_STARTED + state.selectedProductId = undefined; + state.selectedProduct = undefined; } } }) @@ -96,6 +106,8 @@ export const { setAssembly, startAssembly, endAssembly, - confirmAssembly + confirmAssembly, + setLocalState, + reset } = 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 index 9a76d8d..a88562b 100644 --- a/src/features/ordersFilter/ordersFilterSlice.ts +++ b/src/features/ordersFilter/ordersFilterSlice.ts @@ -1,4 +1,6 @@ import {createSlice, PayloadAction} from "@reduxjs/toolkit"; +import {ShippingWarehouse} from "../../types/shippingWarehouse"; +import ShippingWarehouseSelect from "../../components/ShippingWarehouseSelect/ShippingWarehouseSelect"; export enum OrderStatus { ALL = -1, @@ -42,15 +44,20 @@ export interface OrdersFilterState { status: OrderStatus; shipmentDate: string; page: number; + shippingWarehouse: ShippingWarehouse } const initialState: OrdersFilterState = { isVisible: false, - orderBy: "createdOn", + orderBy: "shipmentDate", desc: true, shipmentDate: (new Date()).toISOString(), status: OrderStatus.AWAITING_PACKAGING, - page: 0 + page: 0, + shippingWarehouse: { + id: -1, + name: 'Все склады отгрузки' + } } export const ordersFilterSlice = createSlice({ @@ -75,14 +82,18 @@ export const ordersFilterSlice = createSlice({ setShipmentDate: (state, action: PayloadAction) => { state.shipmentDate = action.payload; }, + setShippingWarehouse: (state, action: PayloadAction) => { + state.shippingWarehouse = action.payload; + }, setPage: (state, action: PayloadAction) => { + console.log(action) state.page = action.payload; }, nextPage: (state) => { state.page = state.page + 1 }, refreshPagination: (state) => { - state.page = 0 + state.page = -1 } } }) @@ -95,6 +106,8 @@ export const { setOrderBy, setDesc, setStatus, - setShipmentDate + setShipmentDate, + setPage, + setShippingWarehouse } = ordersFilterSlice.actions; export default ordersFilterSlice.reducer; \ No newline at end of file diff --git a/src/features/shippingWarehouseSelect/shippingWarehouseSelectSlice.ts b/src/features/shippingWarehouseSelect/shippingWarehouseSelectSlice.ts new file mode 100644 index 0000000..bda0b6e --- /dev/null +++ b/src/features/shippingWarehouseSelect/shippingWarehouseSelectSlice.ts @@ -0,0 +1,38 @@ +import {createSlice, PayloadAction} from "@reduxjs/toolkit"; +import {ShippingWarehouse} from "../../types/shippingWarehouse"; + +export interface ShippingWarehouseSelectState { + shippingWarehouses: ShippingWarehouse[] + selectedShippingWarehouse: ShippingWarehouse + initialized: boolean +} + +const initialState: ShippingWarehouseSelectState = { + shippingWarehouses: [], + selectedShippingWarehouse: { + id: -1, + name: "Все склады отгрузки" + }, + initialized: false +} + +export const shippingWarehouseSelect = createSlice({ + name: 'shippingWarehouse', + initialState, + reducers: { + initializeShippingWarehouseSelect: (state, action: PayloadAction) => { + state.shippingWarehouses = action.payload; + state.initialized = true; + if (state.shippingWarehouses.length > 0) state.selectedShippingWarehouse = state.shippingWarehouses[0]; + }, + selectShippingWarehouse: (state, action: PayloadAction<{ shippingWarehouseId: number }>) => { + let selectedWarehouse = state.shippingWarehouses.find(wh => wh.id == action.payload.shippingWarehouseId); + if (!selectedWarehouse) return; + state.selectedShippingWarehouse = selectedWarehouse; + } + + } +}) + +export const {initializeShippingWarehouseSelect, selectShippingWarehouse} = shippingWarehouseSelect.actions; +export default shippingWarehouseSelect.reducer; \ No newline at end of file diff --git a/src/redux/store.ts b/src/redux/store.ts index f184bbd..c6fcce3 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -9,6 +9,7 @@ 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 shippingWarehouseSelectReducer from 'features/shippingWarehouseSelect/shippingWarehouseSelectSlice'; import {useDispatch} from "react-redux"; export const store = configureStore({ @@ -21,7 +22,8 @@ export const store = configureStore({ printing: printingReducer, reprintModal: reprintModalReducer, imageZoomModal: imageZoomModalReducer, - ordersFilter: ordersFilterReducer + ordersFilter: ordersFilterReducer, + shippingWarehouseSelect: shippingWarehouseSelectReducer }, }); diff --git a/src/screens/BarcodeScreen/BarcodeScreen.tsx b/src/screens/BarcodeScreen/BarcodeScreen.tsx index 326419a..8cee1c4 100644 --- a/src/screens/BarcodeScreen/BarcodeScreen.tsx +++ b/src/screens/BarcodeScreen/BarcodeScreen.tsx @@ -14,6 +14,7 @@ import flashListSeparator from "../../components/FlashListSeparator/FlashListSep import {useEffect, useState} from "react"; import {openScanModal} from "../../features/scanModal/scanModalSlice"; import ordersApi from "../../api/ordersApi"; +import DTitle from "../../components/DTitle/DTitle"; function BarcodeScreen() { const dispatch = useDispatch(); @@ -26,27 +27,32 @@ function BarcodeScreen() { }, []); return ( - { - ordersApi.getOrdersBySupplierProduct(product.supplierProductId).then(setOrders) + { + ordersApi.getOrdersByProduct(product.productId).then(setOrders) }}/> - 0 ? item.orderNumber.toString()} + renderItem={({item}) => + { + dispatch(setOrder(order)); + navigator.navigate("Home"); + }} order={item}/>} + showsHorizontalScrollIndicator={false} + showsVerticalScrollIndicator={true} + onEndReachedThreshold={0.1} + estimatedItemSize={720} + ItemSeparatorComponent={flashListSeparator} + /> : + + Нет заказов по данному + товару + } - keyboardShouldPersistTaps={"never"} - data={orders} - keyExtractor={(item: Order) => item.orderNumber.toString()} - renderItem={({item}) => - { - dispatch(setOrder(order)); - navigator.navigate("Home"); - }} order={item}/>} - showsHorizontalScrollIndicator={false} - showsVerticalScrollIndicator={true} - onEndReachedThreshold={0.1} - estimatedItemSize={720} - ItemSeparatorComponent={flashListSeparator} - - /> ) diff --git a/src/screens/CommonPage/CommonPage.tsx b/src/screens/CommonPage/CommonPage.tsx index f3ba8eb..c156add 100644 --- a/src/screens/CommonPage/CommonPage.tsx +++ b/src/screens/CommonPage/CommonPage.tsx @@ -15,10 +15,12 @@ import {closeScanModal, setScannedData} from "../../features/scanModal/scanModal 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 {assembly, setAssembly, setLocalState, setOrder} from "../../features/assembly/assemblySlice"; import ordersApi from "../../api/ordersApi"; import ImageZoomModal from "../../components/Modals/ImageZoomModal/ImageZoomModal"; import SortingModal from "../../components/Modals/SortingModal/SortingModal"; +import {setLoadingText} from "../../features/loadingModal/loadingModalSlice"; +import {ASSEMBLY_STATE} from "../../types/assembly"; function CommonPage() { const dim = useSelector((state: RootState) => state.interface.dim); @@ -31,6 +33,7 @@ function CommonPage() { dispatch(login({accessToken: token})); return true; } + const loadAssembly = async () => { assemblyApi.hasActive().then(({has}) => { if (!has) return; @@ -38,6 +41,7 @@ function CommonPage() { ordersApi.getOrderById(assembly.orderId).then(order => { dispatch(setAssembly(assembly)); dispatch(setOrder(order)); + dispatch(setLocalState(assembly.state as ASSEMBLY_STATE)); }) }) }) diff --git a/src/screens/LoginScreen/LoginScreen.tsx b/src/screens/LoginScreen/LoginScreen.tsx index ed6727d..878f0e2 100644 --- a/src/screens/LoginScreen/LoginScreen.tsx +++ b/src/screens/LoginScreen/LoginScreen.tsx @@ -14,8 +14,8 @@ import * as SecureStore from 'expo-secure-store'; function LoginScreen() { const dispatch = useAppDispatch(); - const [loginValue, setLoginValue] = useState('dsnon'); - const [passwordValue, setPasswordValue] = useState('ochko'); + const [loginValue, setLoginValue] = useState(''); + const [passwordValue, setPasswordValue] = useState(''); const handleLogin = async () => { const response = await userApi.login(loginValue, passwordValue); if (!response.ok) { diff --git a/src/screens/OrderScreen/OrderScreen.tsx b/src/screens/OrderScreen/OrderScreen.tsx index 2f33433..5df09b2 100644 --- a/src/screens/OrderScreen/OrderScreen.tsx +++ b/src/screens/OrderScreen/OrderScreen.tsx @@ -1,14 +1,10 @@ -import {View, Text, Image, StyleSheet, Button, TouchableOpacity} from "react-native"; +import {View, Image, StyleSheet, 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"; import DTitle from "../../components/DTitle/DTitle"; import BasicButton from "../../components/BasicButton/BasicButton"; -import Hyperlink from "../../components/Hyperlink/Hyperlink"; import React, {FC, useEffect, useState} from "react"; -import userApi from "../../api/userApi"; -import {StatusBar} from "expo-status-bar"; -import * as Progress from 'react-native-progress'; import {useDispatch, useSelector} from "react-redux"; import {RootState} from "../../redux/store"; import {closeLoadingModal, openLoadingModal, setLoadingText} from "../../features/loadingModal/loadingModalSlice"; @@ -182,13 +178,14 @@ const OrderScreen: FC = ({order}) => { } 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('wildberries', pdfData).then((response) => { + printingService.getInstance().printPdf(printer, pdfData).then((response) => { dispatch(closeLoadingModal()); if (response) return; - dispatch(setPrinterName({printerName: 'wildberries'})); + dispatch(setPrinterName({printerName: printer})); dispatch(openReprintModal()); }); }) diff --git a/src/screens/OrderScreen/useOrders.tsx b/src/screens/OrderScreen/useOrders.tsx index adbfe9f..d9bea9d 100644 --- a/src/screens/OrderScreen/useOrders.tsx +++ b/src/screens/OrderScreen/useOrders.tsx @@ -4,37 +4,63 @@ 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"; +import { + refreshPagination, + setOrderBy, + setPage, + setShippingWarehouse +} from "../../features/ordersFilter/ordersFilterSlice"; const useOrders = () => { const dispatch = useDispatch(); const [orders, setOrders] = useState([]); + const [isInitialized, setIsInitialized] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const filterState = useSelector((state: RootState) => state.ordersFilter); + const fetchOrders = async (): Promise => { + return ordersApi.getOrders( + filterState.page, + filterState.orderBy, + filterState.desc, + filterState.shipmentDate, + filterState.status, + filterState.shippingWarehouse.id + ); + } + + const appendOrders = (newOrders: Order[]) => { + setOrders([...newOrders, ...orders]); + } const refresh = () => { - if (filterState.page == 0) return; - setIsRefreshing(true); setOrders([]); - dispatch(refreshPagination()); + dispatch(setPage(0)); + fetchOrders().then(setOrders); } 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); - }); + if (!isInitialized || filterState.isVisible) return; + fetchOrders().then(appendOrders); }, [filterState.page]); useEffect(() => { - if (filterState.isVisible) return; - setOrders([]); - setIsRefreshing(true); - dispatch(refreshPagination()); - }, [filterState.orderBy, filterState.desc, filterState.status, filterState.shipmentDate, filterState.isVisible]); + if (!isInitialized || filterState.isVisible) return; + fetchOrders().then(setOrders) + }, [filterState.orderBy, + filterState.desc, + filterState.status, + filterState.shipmentDate, + filterState.isVisible, + filterState.shippingWarehouse + ]); + useEffect(() => { + fetchOrders().then(newOrders=>{ + setOrders(newOrders); + setIsInitialized(true); + + }) + }, []); return {refresh, isRefreshing, orders}; } diff --git a/src/screens/OrdersScreen/OrdersScreen.tsx b/src/screens/OrdersScreen/OrdersScreen.tsx index 23a8ea8..0fded19 100644 --- a/src/screens/OrdersScreen/OrdersScreen.tsx +++ b/src/screens/OrdersScreen/OrdersScreen.tsx @@ -16,6 +16,7 @@ import {NavigationProp, useNavigation} from "@react-navigation/native"; import {TabNavigatorParamList} from "../MainScreen/MainScreen"; import useOrders from "../OrderScreen/useOrders"; import {nextPage, openOrdersFilterModal} from "../../features/ordersFilter/ordersFilterSlice"; +import DTitle from "../../components/DTitle/DTitle"; function OrdersScreen() { const dispatch = useDispatch(); @@ -52,6 +53,10 @@ function OrdersScreen() { ItemSeparatorComponent={flashListSeparator} /> + {orders.length <= 0 && + Нет заказов по заданному фильтру + } + diff --git a/src/screens/ProfileScreen/ProfileScreen.tsx b/src/screens/ProfileScreen/ProfileScreen.tsx index 929905e..490ce6e 100644 --- a/src/screens/ProfileScreen/ProfileScreen.tsx +++ b/src/screens/ProfileScreen/ProfileScreen.tsx @@ -1,18 +1,17 @@ -import {Button, Text, View, StyleSheet, TouchableOpacity, Image, ScrollView, GestureResponderEvent} from "react-native"; -import {useAppDispatch} from "../../redux/store"; -import * as process from "process"; +import {View, StyleSheet, TouchableOpacity, Image, ScrollView, GestureResponderEvent} from "react-native"; import {responsiveFontSize, responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions"; -import {background, blue, gray} from "../../css/colors"; +import {blue, gray} from "../../css/colors"; import {RFPercentage} from "react-native-responsive-fontsize"; import DText from "../../components/DText/DText"; import DTitle from "../../components/DTitle/DTitle"; -import {ScreenStackHeaderLeftView} from "react-native-screens"; import Separator from "../../components/Separator/Separator"; import {BottomSheetModal} from "@gorhom/bottom-sheet"; import {useMemo, useRef, useState} from "react"; -import {openApp} from "rn-openapp"; -import SelectProductModal from "../../components/Modals/SelectProductModal/SelectProductModal"; -import selectProductModal from "../../components/Modals/SelectProductModal/SelectProductModal"; +import assemblyApi from "../../api/assemblyApi"; +import Toast from "react-native-toast-message"; +import {useDispatch} from "react-redux"; +import {reset} from "../../features/assembly/assemblySlice"; + type SettingsElementProps = { icon: any; @@ -58,6 +57,7 @@ function ProfileScreen() { const bottomSheetModalRef = useRef(null); const snapPoints = useMemo(() => ['25%', '40%'], []); const [modalVisible, setModalVisible] = useState(false); + const dispatch = useDispatch(); return ( @@ -76,9 +76,18 @@ function ProfileScreen() { > + { - openApp('assemblrprintingservice'); - }} icon={require('assets/icons/settings/printer.png')} title={'Принтеры'}/> + assemblyApi.cancel().then(response => { + + Toast.show({ + type: response.ok ? "success" : "error", + text1: "Отмена сборки", + text2: response.message, + }); + dispatch(reset()); + }) + }} icon={require('assets/icons/settings/close.png')} title={'Отменить сборку'}/> @@ -187,7 +196,7 @@ const styles = StyleSheet.create({ backgroundColor: "white", borderRadius: 100, borderWidth: RFPercentage(0.3), - padding: RFPercentage(1), + padding: RFPercentage(1.5), justifyContent: "center", alignItems: "center" diff --git a/src/types/product.ts b/src/types/product.ts new file mode 100644 index 0000000..cc51637 --- /dev/null +++ b/src/types/product.ts @@ -0,0 +1,6 @@ +export type Product = { + productId: number; + dencoArticle: number; + productName: string; + thumbUrl: string; +} \ No newline at end of file diff --git a/src/types/shippingWarehouse.ts b/src/types/shippingWarehouse.ts new file mode 100644 index 0000000..c20723c --- /dev/null +++ b/src/types/shippingWarehouse.ts @@ -0,0 +1,4 @@ +export type ShippingWarehouse = { + id: number; + name: string; +} \ No newline at end of file diff --git a/src/utils/PrintingService.ts b/src/utils/PrintingService.ts index 27254f4..25f4fe9 100644 --- a/src/utils/PrintingService.ts +++ b/src/utils/PrintingService.ts @@ -1,4 +1,5 @@ import axios from "axios"; +import {blue100} from "react-native-paper/lib/typescript/styles/themes/v2/colors"; class PrintingService { private static instance: PrintingService | null = null; @@ -17,9 +18,24 @@ class PrintingService { this.port = port; } + private newAbortSignal(timeoutMs: number) { + const abortController = new AbortController(); + setTimeout(() => abortController.abort(), timeoutMs || 0); + + return abortController.signal; + } + private async print(printer: string, type: string, bytes: Uint8Array): Promise { - let response = await axios.post(`http://${this.apiUrl}:${this.port}/print/${printer}/${type}`, bytes.buffer); - return response.data.ok; + try { + let response = await axios.post(`http://${this.apiUrl}:${this.port}/print/${printer}/${type}`, bytes.buffer, { + timeout: 20 * 1000, + signal: this.newAbortSignal(20 * 1000) + }); + return response.data.ok; + } catch (error) { + console.log(error); + return false; + } } public async printPdf(printer: string, pdfBytes: Uint8Array): Promise { @@ -29,6 +45,11 @@ class PrintingService { public async printImage(printer: string, imageBytes: Uint8Array): Promise { return this.print(printer, "image", imageBytes); } + + public getPrinter(baseMarketplace: number): string { + if (baseMarketplace == 0) return "wildberries"; + return "ozon"; + } } export default PrintingService; \ No newline at end of file