ebanutsya

This commit is contained in:
2023-10-27 06:03:46 +03:00
parent 4f25112b5e
commit 37d3fb5a78
34 changed files with 831 additions and 17841 deletions

View File

@@ -0,0 +1,9 @@
import {FC} from "react";
import {responsiveHeight} from "react-native-responsive-dimensions";
import {View} from "react-native";
const FlashListSeparator: FC = () => {
return (<View
style={{flex: 1, height: responsiveHeight(2)}}></View>);
}
export default FlashListSeparator;

View File

@@ -0,0 +1,97 @@
import React, {FC} from "react";
import {SupplierProduct} from "../../../types/supplierProduct";
import {Image, StyleSheet, TouchableOpacity, View} from "react-native";
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";
type Props = {
product: SupplierProduct;
onPress: (product: SupplierProduct) => void;
}
const SelectProductElement: FC<Props> = React.memo(({product, onPress}) => {
return (
<TouchableOpacity onPress={() => {
onPress(product)
}}>
<View style={styles.container}>
<View style={styles.imageWrapper}>
<Image style={styles.image} source={{uri: product.thumbUrl}}/>
</View>
<View style={styles.description}>
<View style={styles.descriptionContent}>
<DText>{product.productName}</DText>
<DText style={{textAlign: "justify"}}>{}</DText>
{product.supplierName &&
<DText>Поставщик: {product.supplierName}</DText>
}
{product.supplierArticle &&
<DText>Артикул: {product.supplierArticle}</DText>
}
{product.inBlock &&
<DText>В блоке: {product.inBlock}</DText>
}
{product.shelfNumber &&
<DText>Номер полки: {product.shelfNumber}</DText>
}
</View>
</View>
</View>
</TouchableOpacity>
)
})
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
display: "flex",
borderRadius: RFPercentage(3),
flexDirection: "row",
padding: RFPercentage(2),
flex: 1,
},
imageWrapper: {
width: responsiveWidth(20),
},
image: {
width: "100%",
height: "100%",
},
description: {
// backgroundColor: "red",
flex: 1,
display: "flex",
flexDirection: "column",
paddingLeft: responsiveWidth(3),
gap: 0,
},
title: {
marginBottom: responsiveHeight(0.5),
flexDirection: "row",
alignItems: "center"
},
titleImage: {
width: responsiveWidth(4),
height: responsiveHeight(4),
resizeMode: "center",
marginLeft: responsiveHeight(1)
},
descriptionContent: {
// backgroundColor: "green",
flex: 1,
},
descriptionStatus: {
alignSelf: "flex-end",
// backgroundColor: "blue",
marginRight: responsiveWidth(2),
}
});
export default SelectProductElement;

View File

@@ -0,0 +1,59 @@
import {FC} from "react";
import {FlatList, StyleSheet, View} from "react-native";
import Modal from "react-native-modal";
import {FlashList} from "@shopify/flash-list";
import SelectProductElement from "./SelectProductElement";
import {SupplierProduct} from "../../../types/supplierProduct";
import FlashListSeparator from "../../FlashListSeparator/FlashListSeparator";
import DTitle from "../../DTitle/DTitle";
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
import {background} from "../../../css/colors";
type Props = {
visible: boolean;
products: SupplierProduct[];
onSelected: (product: SupplierProduct) => void
}
const SelectProductModal: FC<Props> = ({visible, products, onSelected}) => {
return (
<Modal isVisible={visible}>
<View style={styles.container}>
<DTitle style={styles.title}>К штрихкоду привязано несколько
товаров, выберите конкретный</DTitle>
<FlatList
keyboardShouldPersistTaps={"never"}
data={products}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
keyExtractor={(product) => product.supplierProductId.toString()}
renderItem={(product) => <SelectProductElement product={product.item} onPress={onSelected}/>}
ItemSeparatorComponent={FlashListSeparator}
>
</FlatList>
</View>
</Modal>
)
}
const styles = StyleSheet.create({
container: {
backgroundColor: background,
borderRadius: responsiveWidth(1),
paddingHorizontal: responsiveWidth(5),
paddingVertical: responsiveHeight(5),
rowGap: responsiveHeight(3),
marginVertical:responsiveHeight(10)
},
title: {
textAlign: "center"
},
listContainer: {
flex: 1
}
})
export default SelectProductModal;

View File

@@ -0,0 +1,113 @@
import {FC, forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
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 {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";
export type SortingModalHandles = {
present: () => void;
dismiss: () => void;
}
export type SortingModalElement = {
id: string;
label: string;
value: string;
}
type Props = {
onChange: (sortingValue: string) => void;
onClose: () => void;
elements: SortingModalElement[];
defaultElementId?: string;
};
const createRadioButton = (element: SortingModalElement) => {
return {
id: element.id,
label: element.label,
value: element.value,
size: RFPercentage(5),
color: blue,
labelStyle: {
fontSize: responsiveWidth(3),
fontWeight: "500" as const
},
borderSize: RFPercentage(0.5)
};
}
const SortingModal = forwardRef<SortingModalHandles, Props>((props: Props, ref) => {
const {elements, onChange, onClose, defaultElementId = ""} = props;
const snapPoints = useMemo(() => ['40%', '40%'], []);
const dispatch = useDispatch();
const modalRef = useRef<BottomSheetModal>(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<string>(defaultElementId);
useEffect(() => {
onChange(selectedId);
}, [selectedId]);
return (
<BottomSheetModal
ref={modalRef}
snapPoints={snapPoints}
onDismiss={() => {
dispatch(disableDim());
}}>
<View style={styles.container}>
<View style={styles.content}>
<RadioGroup selectedId={selectedId}
onPress={setSelectedId}
containerStyle={styles.radioButtons}
radioButtons={elements.map(createRadioButton)}/>
</View>
<BasicButton label={"Закрыть"} style={styles.button} onPress={() => {
dismiss();
}}/>
</View>
</BottomSheetModal>
);
});
const styles = StyleSheet.create({
container: {
width: "100%",
height: "100%",
flex: 1,
padding: RFPercentage(3),
flexDirection: "column",
justifyContent: "space-between"
},
radioButtons: {
alignItems: "flex-start"
},
content: {},
button: {
marginTop: "auto"
},
});
export default SortingModal;

View File

@@ -1,26 +1,18 @@
import {FC, useState} from "react";
import React, {FC, useState} from "react";
import {GestureResponderEvent, Image, StyleSheet, TouchableOpacity, View} from "react-native";
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";
type Props = {
onPress?: (event: GestureResponderEvent) => void
order: Order
}
const OrderCard: FC<Props> = ({onPress}) => {
const OrderCard: FC<Props> = React.memo(({onPress, order}) => {
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
});
return (
<TouchableOpacity onPress={() => {
@@ -54,7 +46,7 @@ const OrderCard: FC<Props> = ({onPress}) => {
</TouchableOpacity>
)
}
})
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
@@ -63,6 +55,7 @@ const styles = StyleSheet.create({
height: responsiveHeight(20),
flexDirection: "row",
padding: RFPercentage(2),
flex: 1
},
imageWrapper: {
width: responsiveWidth(30),

View File

@@ -5,6 +5,7 @@ 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";
type Props = {
visible: boolean
@@ -16,14 +17,21 @@ const ScanModal: FC<Props> = ({visible, onCancelButtonPress, onChanged}) => {
useEffect(() => {
if (visible) inputRef.current?.focus();
}, [visible]);
return (
<Modal isVisible={visible}>
<View style={styles.container}>
<DText style={styles.text}>Наведите сканер на штрихкод товара или заказа</DText>
<BasicButton onPress={onCancelButtonPress} style={styles.cancelButton} label={"Отмена"}/>
<TextInput onEndEditing={(e) => {
onChanged(e.nativeEvent.text);
}} style={styles.pseudoInput} ref={inputRef}/>
<TextInput
onEndEditing={(e) => {
onChanged(e.nativeEvent.text);
}}
style={styles.pseudoInput}
ref={inputRef}
autoFocus={true}
showSoftInputOnFocus={false}
/>
</View>
</Modal>
)

View File

@@ -1,27 +1,41 @@
import React, {FC, useRef, useState} from "react";
import React, {FC, useEffect, useRef, useState} from "react";
import {Image, StyleSheet, TextInput, TouchableOpacity, View} from "react-native";
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
import {RFPercentage} from "react-native-responsive-fontsize";
import BasicButton from "../BasicButton/BasicButton";
import ScanModal from "./ScanModal";
import telegramAuthButton from "../TelegramAuthButton/TelegramAuthButton";
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 {RootState} from "../../redux/store";
type Props = {
onSearch: (text: string) => void;
onSupplierProductSelected?: (supplierProduct: SupplierProduct) => void
}
const SearchBar: FC<Props> = ({onSearch}) => {
const [isScanModalVisible, setIsScanModalVisible] = useState<boolean>(false);
const SearchBar: FC<Props> = ({onSearch, onSupplierProductSelected}) => {
// const [isScanModalVisible, setIsScanModalVisible] = useState<boolean>(false);
// const [, setSelectProductModalVisible] = useState(false);
const dispatch = useDispatch();
const [searchInput, setSearchInput] = useState<string>("");
const textInputRef = useRef<TextInput>(null);
const [products, setProducts] = useState<SupplierProduct[]>([]);
const scannedData = useSelector((state: RootState) => state.scanModal.scannedData);
useEffect(() => {
if (!scannedData) return;
barcodeApi.searchProducts(scannedData).then(setProducts);
}, [scannedData]);
const selectProductModalVisible = products.length > 0;
return (
<View style={styles.container}>
<ScanModal
onChanged={(text) => {
setIsScanModalVisible(false);
onSearch(text);
}}
onCancelButtonPress={() => setIsScanModalVisible(false)}
visible={isScanModalVisible}/>
<SelectProductModal visible={selectProductModalVisible} products={products} onSelected={(product) => {
if (onSupplierProductSelected) onSupplierProductSelected(product);
setProducts([]);
}}/>
<BasicButton onPress={() => {
onSearch(searchInput);
if (textInputRef.current) {
@@ -29,7 +43,9 @@ const SearchBar: FC<Props> = ({onSearch}) => {
}
}} style={styles.scanButton} label={"Поиск"}/>
<View style={styles.scanImageWrapper}>
<TouchableOpacity onPress={() => setIsScanModalVisible(true)}>
<TouchableOpacity onPress={() => {
dispatch(openScanModal());
}}>
<Image style={styles.scanImage} source={require('assets/icons/scan.png')}/>
</TouchableOpacity>
</View>

View File

@@ -0,0 +1,30 @@
import Toast, {BaseToast, ErrorToast, ToastConfig} from 'react-native-toast-message';
import {responsiveHeight, responsiveWidth} from "react-native-responsive-dimensions";
const toastConfig: ToastConfig = {
success: (props) => (
<BaseToast
{...props}
text1Style={{fontSize: responsiveWidth(3)}}
text2Style={{fontSize: responsiveWidth(3)}}
style={{
width: responsiveWidth(90),
height: responsiveHeight(10),
borderLeftColor: "green"
}}
/>),
error: (props) => (
<BaseToast
{...props}
text1Style={{fontSize: responsiveWidth(3)}}
text2Style={{fontSize: responsiveWidth(3)}}
style={{
width: responsiveWidth(90),
height: responsiveHeight(10),
borderLeftColor: "red"
}}
/>),
}
export default toastConfig;