ebanutsya
This commit is contained in:
BIN
Assemblr.7z
BIN
Assemblr.7z
Binary file not shown.
@@ -34,6 +34,7 @@
|
||||
"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",
|
||||
|
||||
12
src/api/printingApi.ts
Normal file
12
src/api/printingApi.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import apiClient from "./apiClient";
|
||||
|
||||
const router = '/printing';
|
||||
|
||||
const printingApi = {
|
||||
getLabel: async (orderId: number): Promise<Uint8Array> => {
|
||||
let response = await apiClient.get(`${router}/getLabel?orderId=${orderId}`, {responseType: 'arraybuffer'});
|
||||
return new Uint8Array(response.data);
|
||||
|
||||
},
|
||||
}
|
||||
export default printingApi;
|
||||
@@ -10,15 +10,16 @@ type Props = {
|
||||
containerStyle?: StyleProp<ViewStyle>;
|
||||
isUnset?: boolean;
|
||||
onPress?: (event: GestureResponderEvent) => void
|
||||
disabled?: boolean
|
||||
};
|
||||
|
||||
const BasicButton: FC<Props> = ({label, onPress, containerStyle, style, isUnset = false}) => {
|
||||
const BasicButton: FC<Props> = ({label, onPress, containerStyle, style, isUnset = false, disabled = false}) => {
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress}>
|
||||
<TouchableOpacity style={{flex: 1}} disabled={disabled} onPress={onPress}>
|
||||
|
||||
<View style={[styles.container, style]}>
|
||||
<DText style={styles.text}>{label}</DText>
|
||||
</View>
|
||||
<View style={[styles.container, style, disabled ? {backgroundColor: "#A0A0A0"} : {}]}>
|
||||
<DText style={styles.text}>{label}</DText>
|
||||
</View>
|
||||
|
||||
</TouchableOpacity>
|
||||
);
|
||||
@@ -33,11 +34,13 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: '#2478F8',
|
||||
borderRadius: responsiveWidth(1),
|
||||
padding: responsiveWidth(2),
|
||||
flex: 1
|
||||
},
|
||||
text: {
|
||||
color: "white",
|
||||
fontSize: RFPercentage(2),
|
||||
textAlignVertical: "center",
|
||||
textAlign: "center"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
55
src/components/Modals/LoadingModal/LoadingModal.tsx
Normal file
55
src/components/Modals/LoadingModal/LoadingModal.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import {FC} from "react";
|
||||
import {Props} from "react-native-paper";
|
||||
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 {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);
|
||||
|
||||
return (
|
||||
<Modal isVisible={isVisible}>
|
||||
<View style={styles.container}>
|
||||
<DTitle style={{textAlign: "center"}}>{loadingText}</DTitle>
|
||||
<View style={styles.progressBarWrapper}>
|
||||
<Progress.Circle size={RFPercentage(20)}
|
||||
color={blue}
|
||||
indeterminate={true}
|
||||
style={styles.progressBar}
|
||||
borderWidth={responsiveWidth(1)}
|
||||
/>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignSelf: "center",
|
||||
backgroundColor: background,
|
||||
width: responsiveWidth(80),
|
||||
height: responsiveHeight(50),
|
||||
borderRadius: responsiveWidth(2),
|
||||
paddingHorizontal: responsiveWidth(20),
|
||||
paddingVertical: responsiveHeight(10),
|
||||
justifyContent: "center",
|
||||
rowGap: responsiveHeight(5)
|
||||
},
|
||||
progressBarWrapper: {
|
||||
alignItems: "center"
|
||||
},
|
||||
progressBar: {
|
||||
justifyContent: "center"
|
||||
}
|
||||
})
|
||||
export default LoadingModal;
|
||||
@@ -42,7 +42,7 @@ const SelectProductModal: FC<Props> = ({visible, products, onSelected}) => {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: background,
|
||||
borderRadius: responsiveWidth(1),
|
||||
borderRadius: responsiveWidth(2),
|
||||
paddingHorizontal: responsiveWidth(5),
|
||||
paddingVertical: responsiveHeight(5),
|
||||
rowGap: responsiveHeight(3),
|
||||
|
||||
@@ -5,42 +5,36 @@ import DText from "../DText/DText";
|
||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||||
import DTitle from "../DTitle/DTitle";
|
||||
import {Order} from "../../types/order";
|
||||
import OrderProductsList from "./OrderProductsList";
|
||||
|
||||
type Props = {
|
||||
onPress?: (event: GestureResponderEvent) => void
|
||||
onSelect: (order: Order) => void
|
||||
order: Order
|
||||
|
||||
}
|
||||
const OrderCard: FC<Props> = React.memo(({onPress, order}) => {
|
||||
|
||||
const OrderCard: FC<Props> = React.memo(({onPress, onSelect, order}) => {
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => {
|
||||
console.log("pressed11")
|
||||
onSelect(order);
|
||||
}}>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.imageWrapper}>
|
||||
<Image style={styles.image} source={{uri: order.imageUrl}}/>
|
||||
</View>
|
||||
<View style={styles.description}>
|
||||
<View style={styles.descriptionContent}>
|
||||
<View style={styles.title}>
|
||||
<View style={styles.container}><View style={styles.description}>
|
||||
<View style={styles.descriptionContent}>
|
||||
<View style={styles.title}>
|
||||
|
||||
<DTitle>{order.orderNumber}</DTitle>
|
||||
<Image source={require('assets/icons/marketplaces/ozon.png')} style={styles.titleImage}/>
|
||||
</View>
|
||||
<DText>Количество: 5</DText>
|
||||
<DText>Поставщик: {order.supplierName}</DText>
|
||||
<DText>Селлер: {order.sellerName}</DText>
|
||||
<DText>Цвет: ГОЛУБОЙ</DText>
|
||||
</View>
|
||||
|
||||
<View style={styles.descriptionStatus}>
|
||||
<DText>
|
||||
Ожидает сборки
|
||||
</DText>
|
||||
<DTitle>{order.orderNumber}</DTitle>
|
||||
<Image source={require('assets/icons/marketplaces/ozon.png')} style={styles.titleImage}/>
|
||||
</View>
|
||||
<DText>Селлер: {order.sellerName}</DText>
|
||||
<DText>Маркетплейс: {order.marketplaceName}</DText>
|
||||
</View>
|
||||
<View style={styles.descriptionStatus}>
|
||||
<DText>
|
||||
Ожидает сборки
|
||||
</DText>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
@@ -52,7 +46,7 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: "white",
|
||||
display: "flex",
|
||||
borderRadius: RFPercentage(3),
|
||||
height: responsiveHeight(20),
|
||||
height: responsiveHeight(15),
|
||||
flexDirection: "row",
|
||||
padding: RFPercentage(2),
|
||||
flex: 1
|
||||
|
||||
68
src/components/OrderCard/OrderProductsList.tsx
Normal file
68
src/components/OrderCard/OrderProductsList.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import {FC} from "react";
|
||||
import {FlatList, StyleSheet, View, Image, TouchableOpacity} from "react-native";
|
||||
import {OrderProduct} from "../../types/order";
|
||||
import DTitle from "../DTitle/DTitle";
|
||||
import DText from "../DText/DText";
|
||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||||
import {RFPercentage} from "react-native-responsive-fontsize";
|
||||
import {background} from "../../css/colors";
|
||||
|
||||
type ListProps = {
|
||||
products: OrderProduct[];
|
||||
onSelected: (product: OrderProduct) => void;
|
||||
}
|
||||
type CardProps = {
|
||||
product: OrderProduct;
|
||||
onPress: (product: OrderProduct) => void;
|
||||
id: number;
|
||||
}
|
||||
const OrderProductCard: FC<CardProps> = ({product, onPress, id}) => {
|
||||
return (
|
||||
<TouchableOpacity onPress={() => onPress(product)}>
|
||||
<View style={cardStyles.container}>
|
||||
<View style={cardStyles.content}>
|
||||
<DText>{id + 1}) {product.productName}</DText>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
)
|
||||
}
|
||||
const cardStyles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: "row",
|
||||
backgroundColor: background,
|
||||
borderRadius: RFPercentage(1),
|
||||
padding: RFPercentage(1)
|
||||
},
|
||||
content:{
|
||||
|
||||
}
|
||||
})
|
||||
const OrderProductsList: FC<ListProps> = ({products, onSelected}) => {
|
||||
return (
|
||||
|
||||
<View style={listStyles.container}>
|
||||
<DTitle style={listStyles.title}>Товары</DTitle>
|
||||
<FlatList data={products}
|
||||
contentContainerStyle={{rowGap: responsiveHeight(1)}}
|
||||
renderItem={(item) => <OrderProductCard id={item.index} product={item.item}
|
||||
onPress={onSelected}/>}/>
|
||||
</View>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const listStyles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "white",
|
||||
flex: 1
|
||||
},
|
||||
title: {
|
||||
marginBottom: responsiveHeight(2),
|
||||
textAlign: "center"
|
||||
}
|
||||
})
|
||||
|
||||
export default OrderProductsList;
|
||||
@@ -5,15 +5,14 @@ import {RFPercentage} from "react-native-responsive-fontsize";
|
||||
import Modal from "react-native-modal";
|
||||
import BasicButton from "../BasicButton/BasicButton";
|
||||
import DText from "../DText/DText";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {RootState} from "../../redux/store";
|
||||
import {closeScanModal, setScannedData} from "../../features/scanModal/scanModalSlice";
|
||||
|
||||
type Props = {
|
||||
visible: boolean
|
||||
onCancelButtonPress?: (event: GestureResponderEvent) => void,
|
||||
onChanged: (text: string) => void
|
||||
}
|
||||
const ScanModal: FC<Props> = ({visible, onCancelButtonPress, onChanged}) => {
|
||||
const ScanModal: FC = () => {
|
||||
const inputRef = useRef<TextInput | null>(null);
|
||||
const visible = useSelector((state: RootState) => state.scanModal.isVisible);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
if (visible) inputRef.current?.focus();
|
||||
}, [visible]);
|
||||
@@ -22,10 +21,13 @@ const ScanModal: FC<Props> = ({visible, onCancelButtonPress, onChanged}) => {
|
||||
<Modal isVisible={visible}>
|
||||
<View style={styles.container}>
|
||||
<DText style={styles.text}>Наведите сканер на штрихкод товара или заказа</DText>
|
||||
<BasicButton onPress={onCancelButtonPress} style={styles.cancelButton} label={"Отмена"}/>
|
||||
<BasicButton onPress={() => {
|
||||
dispatch(closeScanModal());
|
||||
}} style={styles.cancelButton} label={"Отмена"}/>
|
||||
<TextInput
|
||||
onEndEditing={(e) => {
|
||||
onChanged(e.nativeEvent.text);
|
||||
dispatch(setScannedData(e.nativeEvent.text));
|
||||
dispatch(closeScanModal())
|
||||
}}
|
||||
style={styles.pseudoInput}
|
||||
ref={inputRef}
|
||||
@@ -39,7 +41,7 @@ const ScanModal: FC<Props> = ({visible, onCancelButtonPress, onChanged}) => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: responsiveWidth(1),
|
||||
borderRadius: responsiveWidth(2),
|
||||
backgroundColor: "white",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
|
||||
@@ -28,7 +28,7 @@ const SearchBar: FC<Props> = ({onSearch, onSupplierProductSelected}) => {
|
||||
barcodeApi.searchProducts(scannedData).then(setProducts);
|
||||
}, [scannedData]);
|
||||
|
||||
const selectProductModalVisible = products.length > 0;
|
||||
const selectProductModalVisible = products.length > 0 && false;
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
||||
@@ -74,8 +74,6 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 0,
|
||||
borderTopRightRadius: responsiveWidth(1),
|
||||
borderBottomRightRadius: responsiveWidth(1),
|
||||
width: responsiveWidth(25),
|
||||
flex: 1
|
||||
},
|
||||
scanImageWrapper: {
|
||||
paddingHorizontal: responsiveWidth(1),
|
||||
@@ -87,7 +85,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
textInput: {
|
||||
height: responsiveHeight(height),
|
||||
flex: 1,
|
||||
flex: 2,
|
||||
borderWidth: 1,
|
||||
borderColor: "#A5A5A5",
|
||||
borderTopLeftRadius: responsiveWidth(1),
|
||||
|
||||
28
src/features/assembly/assemblySlice.ts
Normal file
28
src/features/assembly/assemblySlice.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {createSlice} from "@reduxjs/toolkit";
|
||||
import {Order} from "../../types/order";
|
||||
|
||||
export interface AssemblyState {
|
||||
order?: Order;
|
||||
}
|
||||
|
||||
const initialState: AssemblyState = {
|
||||
order: undefined,
|
||||
}
|
||||
|
||||
export const assembly = createSlice({
|
||||
name: 'assembly',
|
||||
initialState,
|
||||
reducers: {
|
||||
setOrder: (state, action) => {
|
||||
state.order = action.payload;
|
||||
},
|
||||
setAssembled: (state, payload) => {
|
||||
state.order = ({...state.order, orderNumber:"2282"})
|
||||
},
|
||||
setShipped: (state) => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const {setOrder} = assembly.actions;
|
||||
export default assembly.reducer;
|
||||
30
src/features/loadingModal/loadingModalSlice.ts
Normal file
30
src/features/loadingModal/loadingModalSlice.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import {createSlice} from "@reduxjs/toolkit";
|
||||
|
||||
export interface LoadingModalState {
|
||||
isVisible: boolean;
|
||||
loadingText: string
|
||||
}
|
||||
|
||||
const initialState: LoadingModalState = {
|
||||
isVisible: false,
|
||||
loadingText: "Подождите..."
|
||||
}
|
||||
|
||||
export const loadingModalSlice = createSlice({
|
||||
name: 'loadingModal',
|
||||
initialState,
|
||||
reducers: {
|
||||
openLoadingModal: (state) => {
|
||||
state.isVisible = true
|
||||
},
|
||||
closeLoadingModal: (state) => {
|
||||
state.isVisible = false
|
||||
},
|
||||
setLoadingText: (state, action) => {
|
||||
state.loadingText = action.payload;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const {openLoadingModal, closeLoadingModal, setLoadingText} = loadingModalSlice.actions;
|
||||
export default loadingModalSlice.reducer;
|
||||
@@ -3,13 +3,17 @@ import {configureStore} from '@reduxjs/toolkit';
|
||||
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 assemblyReducer from 'features/assembly/assemblySlice';
|
||||
import {useDispatch} from "react-redux";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
auth: authReducer,
|
||||
interface: interfaceReducer,
|
||||
scanModal: scanModalReducer
|
||||
scanModal: scanModalReducer,
|
||||
loadingModal: loadingModalReducer,
|
||||
assembly: assemblyReducer
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ import Toast from "react-native-toast-message";
|
||||
import toastConfig from "../../components/Toast/Toast";
|
||||
import ScanModal from "../../components/SearchBar/ScanModal";
|
||||
import {closeScanModal, setScannedData} from "../../features/scanModal/scanModalSlice";
|
||||
import LoadingModal from "../../components/Modals/LoadingModal/LoadingModal";
|
||||
|
||||
function CommonPage() {
|
||||
const dim = useSelector((state: RootState) => state.interface.dim);
|
||||
const isAuthorized = useSelector((state: RootState) => state.auth.isAuthorized);
|
||||
const isScanModalVisible = useSelector((state: RootState) => state.scanModal.isVisible);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -35,15 +35,9 @@ function CommonPage() {
|
||||
<View style={styles.main}>
|
||||
{isAuthorized ? <MainScreen/> : <LoginScreen/>}
|
||||
<View style={[styles.overlay, {display: dim ? 'flex' : 'none'}]}/>
|
||||
<LoadingModal/>
|
||||
<ScanModal/>
|
||||
<Toast config={toastConfig}/>
|
||||
<ScanModal visible={isScanModalVisible}
|
||||
onCancelButtonPress={() => {
|
||||
dispatch(closeScanModal());
|
||||
}}
|
||||
onChanged={text => {
|
||||
dispatch(setScannedData(text));
|
||||
dispatch(closeScanModal());
|
||||
}}/>
|
||||
</View>
|
||||
|
||||
)
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
import {StyleSheet, Text, View, ImageBackground, Linking, Image} from 'react-native';
|
||||
import {StyleSheet, Text, View, ImageBackground, Image} from 'react-native';
|
||||
import {createBottomTabNavigator} from "@react-navigation/bottom-tabs";
|
||||
import HomeScreen from "../HomeScreen/HomeScreen";
|
||||
import BoxScreen from "../BoxScreen/BoxScreen";
|
||||
import BarcodeScreen from "../BarcodeScreen/BarcodeScreen";
|
||||
import MoneyScreen from "../MoneyScreen/MoneyScreen";
|
||||
import ProfileScreen from "../ProfileScreen/ProfileScreen";
|
||||
import {DefaultTheme, NavigationContainer} from "@react-navigation/native";
|
||||
import moneyScreen from "../MoneyScreen/MoneyScreen";
|
||||
import profileScreen from "../ProfileScreen/ProfileScreen";
|
||||
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
|
||||
import {RFPercentage} from "react-native-responsive-fontsize";
|
||||
import LoginScreen from "../LoginScreen/LoginScreen";
|
||||
import OrderScreen from "../OrderScreen/OrderScreen";
|
||||
import OrdersScreen from "../OrdersScreen/OrdersScreen";
|
||||
import {background} from "../../css/colors";
|
||||
import * as fs from "fs";
|
||||
|
||||
export type TabNavigatorParamList = {
|
||||
Home: undefined;
|
||||
Box: undefined;
|
||||
Barcode: undefined;
|
||||
Money: undefined;
|
||||
Profile: undefined;
|
||||
};
|
||||
|
||||
interface CustomTabProps {
|
||||
name: string;
|
||||
component: React.ComponentType<any>;
|
||||
icon: any;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
const CustomTab = ({name, component, icon}: CustomTabProps) => ({
|
||||
const CustomTab = ({name, component, icon, hidden}: CustomTabProps) => ({
|
||||
name,
|
||||
component,
|
||||
options: {
|
||||
@@ -43,31 +47,36 @@ const CustomTab = ({name, component, icon}: CustomTabProps) => ({
|
||||
function MainScreen() {
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
const tabScreens = [
|
||||
const tabScreens: CustomTabProps[] = [
|
||||
{
|
||||
name: "Home",
|
||||
component: OrderScreen,
|
||||
icon: require('assets/icons/home.png')
|
||||
icon: require('assets/icons/home.png'),
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
name: "Box",
|
||||
component: OrdersScreen,
|
||||
icon: require('assets/icons/box.png')
|
||||
icon: require('assets/icons/box.png'),
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
name: "Barcode",
|
||||
component: BarcodeScreen,
|
||||
icon: require('assets/icons/barcode.png')
|
||||
icon: require('assets/icons/barcode.png'),
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
name: "Money",
|
||||
component: moneyScreen,
|
||||
icon: require('assets/icons/money.png')
|
||||
icon: require('assets/icons/money.png'),
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
name: "Profile",
|
||||
component: profileScreen,
|
||||
icon: require('assets/icons/profile.png')
|
||||
icon: require('assets/icons/profile.png'),
|
||||
hidden: false
|
||||
}
|
||||
];
|
||||
|
||||
@@ -90,6 +99,7 @@ function MainScreen() {
|
||||
name: tabScreen.name,
|
||||
component: tabScreen.component,
|
||||
icon: tabScreen.icon,
|
||||
hidden: tabScreen.hidden
|
||||
})}/>
|
||||
)}
|
||||
</Tab.Navigator>
|
||||
|
||||
@@ -5,108 +5,151 @@ 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, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import userApi from "../../api/userApi";
|
||||
|
||||
type ArticleTextProps = {
|
||||
article: number
|
||||
}
|
||||
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";
|
||||
import {useNavigation} from "@react-navigation/native";
|
||||
import printingApi from "../../api/printingApi";
|
||||
import PrintingService from "../../utils/PrintingService";
|
||||
import OrderProductsList from "../../components/OrderCard/OrderProductsList";
|
||||
import {setOrder} from "../../features/assembly/assemblySlice";
|
||||
|
||||
|
||||
function OrderScreen() {
|
||||
|
||||
const [order, setOrder] = useState({
|
||||
article: 183658,
|
||||
imageUrl: "https://421421.selcdn.ru/denco/996956/thumbzoom/h0b41036e5dc84a88b3dd344a46ab33edt.jpg-640x640.jpg",
|
||||
orderNumber: "93757290-0104-7",
|
||||
productName: "Фигурки животных «Собачки» 258, 5-7 см., статичные / 12 шт.",
|
||||
supplierName: "simaland",
|
||||
marketplaceName: "Wildberries РЕНТА",
|
||||
sellerName: "DENCO",
|
||||
assembled: false
|
||||
});
|
||||
const order = useSelector((state: RootState) => state.assembly.order);
|
||||
if (!order) return (
|
||||
<View style={noOrderStyles.container}>
|
||||
<DText style={noOrderStyles.title}>Заказ не выбран!</DText>
|
||||
<View style={noOrderStyles.buttonWrapper}>
|
||||
|
||||
<BasicButton onPress={() => {
|
||||
// @ts-ignore
|
||||
navigator.navigate("Box");
|
||||
}} label={"На главную"}/>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
)
|
||||
const dispatch = useDispatch();
|
||||
const assembled = useSelector((state: RootState) => state.assembly.assembled);
|
||||
const shipped = useSelector((state: RootState) => state.assembly.shipped);
|
||||
const navigator = useNavigation();
|
||||
const [selectedProduct, setSelectedProduct] = useState(order.products[0]);
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.dataContainer}>
|
||||
<View style={styles.productsContainer}>
|
||||
<View style={styles.orderProductsListWrapper}>
|
||||
<OrderProductsList products={order.products} onSelected={() => {
|
||||
}}/>
|
||||
</View>
|
||||
<View style={styles.imageWrapper}>
|
||||
<Image source={{uri: order.imageUrl}} style={styles.image}/>
|
||||
</View>
|
||||
<View style={styles.contentContainer}>
|
||||
<View style={styles.contentWrapper}>
|
||||
<DTitle style={styles.contentTitle}>{order.orderNumber}</DTitle>
|
||||
<Hyperlink url={`https://denco.store/manager/?a=resource/update&id=${order.article}`}>
|
||||
<DText style={styles.articleText}>Артикул: {order.article}</DText>
|
||||
</Hyperlink>
|
||||
<DText>Товар: {order.productName}</DText>
|
||||
<DText>Поставщик: {order.supplierName}</DText>
|
||||
<DText>Селлер: {order.sellerName}</DText>
|
||||
<DText>Маркетплейс: {order.marketplaceName}</DText>
|
||||
</View>
|
||||
<Image style={styles.image} source={{uri: selectedProduct.imageUrl}}/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.contentContainer}>
|
||||
<View style={styles.dataContainer}>
|
||||
<DTitle style={styles.contentTitle}>Заказ</DTitle>
|
||||
<DText>Номер заказа: {order.orderNumber}</DText>
|
||||
<DText>Маркетплейс: {order.marketplaceName}</DText>
|
||||
<DText>Селлер: {order.sellerName}</DText>
|
||||
<DText>{}</DText>
|
||||
<DTitle style={styles.contentTitle}>Товар</DTitle>
|
||||
<DText>Артикул DENCO: {selectedProduct.dencoArticle}</DText>
|
||||
<DText>Поставщик: {selectedProduct.supplierName}</DText>
|
||||
<DText>Номер товара: {0}</DText>
|
||||
</View>
|
||||
<View style={styles.buttonsContainer}>
|
||||
<BasicButton label={"Отметить как собранный"}
|
||||
disabled={!selectedProduct.assembled}
|
||||
onPress={()=>{
|
||||
setOrder(oldValue => ({ ...oldValue }));
|
||||
}}
|
||||
/>
|
||||
<BasicButton label={"Печать этикетки"}
|
||||
disabled={Boolean(order.products.find(product => product.assembled))}/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.buttonsContainer}>
|
||||
<View style={styles.buttonsWrapper}>
|
||||
{!order.assembled &&
|
||||
<BasicButton label={"Отметить как собранный"} onPress={() => {
|
||||
userApi.test()
|
||||
// setOrder({...order, assembled: true})
|
||||
// console.log(order);
|
||||
}}/>
|
||||
}
|
||||
|
||||
{order.assembled &&
|
||||
<BasicButton label={"Печать этикетки"}/>
|
||||
}
|
||||
{/*<BasicButton label={"Следующий товар"}/>*/}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const noOrderStyles = StyleSheet.create({
|
||||
container: {
|
||||
justifyContent: "center",
|
||||
flex: 1,
|
||||
rowGap: responsiveHeight(5)
|
||||
},
|
||||
title: {
|
||||
textAlign: "center",
|
||||
fontSize: responsiveWidth(5)
|
||||
},
|
||||
buttonWrapper: {
|
||||
paddingHorizontal: responsiveWidth(20)
|
||||
}
|
||||
})
|
||||
const styles = StyleSheet.create({
|
||||
orderProductsListWrapper: {
|
||||
flex: 0.5,
|
||||
backgroundColor: "white",
|
||||
borderRadius: RFPercentage(3),
|
||||
padding: RFPercentage(2),
|
||||
},
|
||||
buttonWrapper: {
|
||||
flex: 1,
|
||||
backgroundColor: "red"
|
||||
},
|
||||
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",
|
||||
flex: 1,
|
||||
paddingHorizontal: responsiveWidth(5)
|
||||
|
||||
paddingHorizontal: responsiveWidth(5),
|
||||
paddingBottom: responsiveHeight(10),
|
||||
rowGap: responsiveHeight(2)
|
||||
},
|
||||
dataContainer: {
|
||||
// backgroundColor: "black",
|
||||
productsContainer: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
columnGap: responsiveWidth(3)
|
||||
},
|
||||
buttonsContainer: {
|
||||
// backgroundColor: "blue",
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
paddingHorizontal: responsiveWidth(10)
|
||||
columnGap: responsiveWidth(3),
|
||||
height: responsiveHeight(30)
|
||||
},
|
||||
|
||||
buttonsWrapper: {
|
||||
// backgroundColor: "red",
|
||||
rowGap: responsiveHeight(3)
|
||||
},
|
||||
imageWrapper: {
|
||||
width: responsiveWidth(40),
|
||||
height: responsiveHeight(40),
|
||||
// height: responsiveHeight(40),
|
||||
// backgroundColor: "red",
|
||||
flex: 0.5,
|
||||
backgroundColor: "white",
|
||||
padding: RFPercentage(2),
|
||||
borderRadius: RFPercentage(3)
|
||||
},
|
||||
image: {
|
||||
flex: 1,
|
||||
borderRadius: RFPercentage(3)
|
||||
},
|
||||
contentContainer: {
|
||||
padding: RFPercentage(2),
|
||||
backgroundColor: "white",
|
||||
borderRadius: RFPercentage(3),
|
||||
flex: 1
|
||||
|
||||
resizeMode: "contain"
|
||||
},
|
||||
contentWrapper: {
|
||||
display: "flex",
|
||||
|
||||
@@ -23,10 +23,15 @@ import sortingModal from "../../components/Modals/SortingModal/SortingModal";
|
||||
import flashListSeparator from "../../components/FlashListSeparator/FlashListSeparator";
|
||||
import {RootState} from "../../redux/store";
|
||||
import ordersApi from "../../api/ordersApi";
|
||||
import {setOrder} from "../../features/assembly/assemblySlice";
|
||||
import {NavigationProp, useNavigation} from "@react-navigation/native";
|
||||
import {TabNavigatorParamList} from "../MainScreen/MainScreen";
|
||||
|
||||
function OrdersScreen() {
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const navigator = useNavigation<NavigationProp<TabNavigatorParamList, 'Home'>>();
|
||||
|
||||
const [orders, setOrders] = useState<Order[]>([]);
|
||||
const sortingModalRef = useRef<SortingModalHandles | null>(null);
|
||||
const defaultSortingValue = 'createdOnAsc';
|
||||
@@ -56,8 +61,9 @@ function OrdersScreen() {
|
||||
data={orders}
|
||||
keyExtractor={(item: Order) => item.orderNumber.toString()}
|
||||
renderItem={({item}) =>
|
||||
<OrderCard order={item} onPress={() => {
|
||||
|
||||
<OrderCard order={item} onSelect={(order) => {
|
||||
dispatch(setOrder(order));
|
||||
navigator.navigate("Home");
|
||||
}}/>}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
showsVerticalScrollIndicator={true}
|
||||
@@ -70,7 +76,6 @@ function OrdersScreen() {
|
||||
/>
|
||||
<SortingModal onChange={setSortingValue}
|
||||
onClose={() => {
|
||||
console.log("Closed")
|
||||
}}
|
||||
ref={sortingModalRef}
|
||||
elements={sortingModalElements}
|
||||
|
||||
@@ -1,45 +1,19 @@
|
||||
export type Order = {
|
||||
export type OrderProduct = {
|
||||
databaseId: number;
|
||||
article: number;
|
||||
imageUrl: string;
|
||||
orderNumber: string;
|
||||
productName: string;
|
||||
dencoArticle: number;
|
||||
supplierName: string;
|
||||
marketplaceName: string;
|
||||
sellerName: string;
|
||||
productName: string;
|
||||
assembled: boolean;
|
||||
shipped: boolean
|
||||
imageUrl: string;
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Генератор случайных строк заданной длины
|
||||
function generateRandomString(length: number): string {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Генератор случайных данных для заказа
|
||||
function generateRandomOrder(): Order {
|
||||
return {
|
||||
databaseId: Math.floor(Math.random() * 1000), // Произвольное число для databaseId
|
||||
article: Math.floor(Math.random() * 100000), // Произвольное число для article
|
||||
imageUrl: 'https://example.com/image.png', // Произвольная ссылка на изображение
|
||||
orderNumber: generateRandomString(12), // Случайная строка длиной 12 символов
|
||||
productName: 'Random Product', // Произвольное название продукта
|
||||
supplierName: 'Random Supplier', // Произвольное имя поставщика
|
||||
marketplaceName: 'Random Marketplace', // Произвольное имя маркетплейса
|
||||
sellerName: 'Random Seller', // Произвольное имя продавца
|
||||
assembled: Math.random() < 0.5, // Произвольное булевое значение (true/false)
|
||||
};
|
||||
}
|
||||
|
||||
// Генератор массива случайных заказов
|
||||
export function generateRandomOrders(count: number): Order[] {
|
||||
const orders: Order[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
orders.push(generateRandomOrder());
|
||||
}
|
||||
return orders;
|
||||
}
|
||||
export type Order = {
|
||||
databaseId: number;
|
||||
orderNumber: string;
|
||||
marketplaceName: string;
|
||||
sellerName: string;
|
||||
products: OrderProduct[];
|
||||
};
|
||||
|
||||
34
src/utils/PrintingService.ts
Normal file
34
src/utils/PrintingService.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import axios from "axios";
|
||||
|
||||
class PrintingService {
|
||||
private static instance: PrintingService | null = null;
|
||||
private readonly apiUrl: string;
|
||||
private readonly port: number;
|
||||
|
||||
public static getInstance(port?: number): PrintingService {
|
||||
if (!this.instance) {
|
||||
this.instance = new PrintingService(port);
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
private constructor(port = 2282) {
|
||||
this.apiUrl = "127.0.0.1";
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private async print(printer: string, type: string, bytes: Uint8Array): Promise<string> {
|
||||
let response = await axios.post(`http://${this.apiUrl}:${this.port}/print/${printer}/${type}`, bytes.buffer);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async printPdf(printer: string, pdfBytes: Uint8Array): Promise<string> {
|
||||
return this.print(printer, "pdf", pdfBytes);
|
||||
}
|
||||
|
||||
public async printImage(printer: string, imageBytes: Uint8Array): Promise<string> {
|
||||
return this.print(printer, "image", imageBytes);
|
||||
}
|
||||
}
|
||||
|
||||
export default PrintingService;
|
||||
Reference in New Issue
Block a user