ebanutsya
This commit is contained in:
9
src/components/FlashListSeparator/FlashListSeparator.tsx
Normal file
9
src/components/FlashListSeparator/FlashListSeparator.tsx
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
113
src/components/Modals/SortingModal/SortingModal.tsx
Normal file
113
src/components/Modals/SortingModal/SortingModal.tsx
Normal 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;
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
|
||||
30
src/components/Toast/Toast.tsx
Normal file
30
src/components/Toast/Toast.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user