diff --git a/native/components/BarcodeScanner/_ReanimatedCameraTracers.tsx b/native/components/BarcodeScanner/_ReanimatedCameraTracers.tsx index e7a098c6..bdd960e9 100644 --- a/native/components/BarcodeScanner/_ReanimatedCameraTracers.tsx +++ b/native/components/BarcodeScanner/_ReanimatedCameraTracers.tsx @@ -176,7 +176,7 @@ const useStyles = createStyles((theme) => container: { flex: 1, justifyContent: "center", - backgroundColor: theme.colors.lightBlue, + // backgroundColor: theme.colors.lightBlue, height: "100%", }, camera: { diff --git a/native/components/BarcodeScanner/index.tsx b/native/components/BarcodeScanner/index.tsx index 9f682dfb..088d1459 100644 --- a/native/components/BarcodeScanner/index.tsx +++ b/native/components/BarcodeScanner/index.tsx @@ -3,7 +3,6 @@ import { BarCodeScanningResult, Camera, CameraType, Point } from "expo-camera"; import { useNavigation } from "@react-navigation/native"; import React, { useRef, useState } from "react"; import { - ActivityIndicator, Alert, Animated, StyleSheet, @@ -16,6 +15,7 @@ import { useListBarcodes } from "../../db/hooks/useListBarcodes"; import { BarcodeModalScreenProps } from "../../screens/BarcodeModalScreen"; import { createStyles } from "../../theme/useStyles"; import { CameraSwitchIcon } from "../Icon"; +import { LoadingSpinner } from "../LoadingSpinner"; import { Typography } from "../Typography"; import { BarcodeOutline } from "./BarcodeOutline"; @@ -88,10 +88,10 @@ export const BarcodeScanner = ({ setTRCornerAnimation(corners[3]); }; - if (isLoading && !barcodeList) { + if (!isLoading && !barcodeList) { return ( - + ); } @@ -101,6 +101,7 @@ export const BarcodeScanner = ({ - + @@ -176,7 +180,7 @@ const useStyles = createStyles((theme) => container: { flex: 1, justifyContent: "center", - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, height: "100%", }, camera: { diff --git a/native/components/BottomSheet/BottomSheet.tsx b/native/components/BottomSheet/BottomSheet.tsx index 763bf562..5755df35 100644 --- a/native/components/BottomSheet/BottomSheet.tsx +++ b/native/components/BottomSheet/BottomSheet.tsx @@ -27,21 +27,6 @@ import { useInternalBottomSheet } from "./internal/useInternalBottomSheet"; export const BOTTOMSHEET_TIMING_CLOSE = 250; -const useStyles = createStyles(() => - StyleSheet.create({ - absoluteFill: StyleSheet.absoluteFillObject, - overlay: { - backgroundColor: "black", - }, - bottomSheet: { - position: "absolute", - left: 0, - bottom: 0, - right: 0, - }, - }) -); - const BottomSheet = () => { const theme = useTheme(); const styles = useStyles(); @@ -196,3 +181,18 @@ const BottomSheet = () => { }; export default BottomSheet; + +const useStyles = createStyles(() => + StyleSheet.create({ + absoluteFill: StyleSheet.absoluteFillObject, + overlay: { + backgroundColor: "black", + }, + bottomSheet: { + position: "absolute", + left: 0, + bottom: 0, + right: 0, + }, + }) +); diff --git a/native/components/BottomSheet/contents/DatePicker.tsx b/native/components/BottomSheet/contents/DatePicker.tsx index 387be4b9..4c8552f1 100644 --- a/native/components/BottomSheet/contents/DatePicker.tsx +++ b/native/components/BottomSheet/contents/DatePicker.tsx @@ -20,18 +20,21 @@ export const DatePickerBottomSheetContent = ({ return ( - Wybierz datę + + Wybierz datę + { if (e.type === "dismissed") { return; @@ -44,7 +47,7 @@ export const DatePickerBottomSheetContent = ({ value={dateValue} mode={"time"} display="spinner" - themeVariant="light" + themeVariant="dark" is24Hour={true} onChange={(e, d) => { if (e.type === "dismissed") { @@ -68,11 +71,15 @@ export const DatePickerBottomSheetContent = ({ const useStyles = createStyles((theme) => StyleSheet.create({ + container: { + paddingTop: 16, + backgroundColor: theme.colors.darkBlue, + }, dateTitle: { alignSelf: "center", }, input: { - backgroundColor: theme.colors.white, + backgroundColor: theme.colors.darkBlue, alignSelf: "center", }, button: { diff --git a/native/components/BottomSheet/contents/Input.tsx b/native/components/BottomSheet/contents/Input.tsx index 25d9b1b5..f3a471a5 100644 --- a/native/components/BottomSheet/contents/Input.tsx +++ b/native/components/BottomSheet/contents/Input.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +// import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { Keyboard, StyleSheet, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; @@ -30,47 +30,51 @@ export const InputBottomSheetContent = ({ end: { height: keyboardHeight }, }, } = useKeyboard(); - const { control, handleSubmit, setFocus, formState } = - useForm({ - defaultValues: { - quantity: quantity.toString(), - }, - mode: "onChange", - }); + const { + control, + handleSubmit, + setFocus: _setFocus, + formState, + } = useForm({ + defaultValues: { + quantity: quantity.toString(), + }, + mode: "onChange", + }); const isErrored = !!formState.errors.quantity?.message; - useEffect(() => { - // hack needed to make android focus the input - if (isAndroid) { - setTimeout(() => { - setFocus("quantity"); - }, 1); - return; - } - setFocus("quantity"); - }, []); + // useEffect(() => { + // // hack needed to make android focus the input + // if (isAndroid) { + // setTimeout(() => { + // setFocus("quantity"); + // }, 1); + // return; + // } + // setFocus("quantity"); + // }, []); - useEffect(() => { - const keyboardWillHide = Keyboard.addListener("keyboardWillHide", () => - setFocus("quantity") - ); - const keyboardDidHide = Keyboard.addListener("keyboardDidHide", () => - setFocus("quantity") - ); - const keyboardDidShow = Keyboard.addListener("keyboardDidShow", () => { - setFocus("quantity"); - }); - return () => { - keyboardWillHide.remove(); - keyboardDidHide.remove(); - keyboardDidShow.remove(); - }; - }, [isErrored, setFocus, handleSubmit]); + // useEffect(() => { + // const keyboardWillHide = Keyboard.addListener("keyboardWillHide", () => + // setFocus("quantity") + // ); + // const keyboardDidHide = Keyboard.addListener("keyboardDidHide", () => + // setFocus("quantity") + // ); + // const keyboardDidShow = Keyboard.addListener("keyboardDidShow", () => { + // setFocus("quantity"); + // }); + // return () => { + // keyboardWillHide.remove(); + // keyboardDidHide.remove(); + // keyboardDidShow.remove(); + // }; + // }, [isErrored, setFocus, handleSubmit]); const onSubmit = (data: InputBottomSheetForm) => { !isErrored && Keyboard.dismiss(); - setQuantity(+data.quantity); + setQuantity(parseFloat(data.quantity.replace(/,/g, "."))); !isErrored && closeBottomSheet(); }; @@ -85,14 +89,16 @@ export const InputBottomSheetContent = ({ ]} > - Wpisz ilość + + Wpisz ilość + @@ -129,7 +137,7 @@ export const InputBottomSheetContent = ({ const useStyles = createStyles((theme) => StyleSheet.create({ container: { - backgroundColor: "white", + backgroundColor: theme.colors.darkBlue, paddingTop: theme.spacing, paddingHorizontal: theme.spacing * 2, }, diff --git a/native/components/BottomSheet/internal/BottomSheetContent.tsx b/native/components/BottomSheet/internal/BottomSheetContent.tsx index ec5231e6..49a7bca2 100644 --- a/native/components/BottomSheet/internal/BottomSheetContent.tsx +++ b/native/components/BottomSheet/internal/BottomSheetContent.tsx @@ -1,10 +1,11 @@ import React, { forwardRef, RefObject, useEffect } from "react"; -import { BackHandler, Keyboard, View } from "react-native"; +import { BackHandler, Keyboard, StyleSheet, View } from "react-native"; import { NativeViewGestureHandler, PanGestureHandler, } from "react-native-gesture-handler"; import Animated, { useAnimatedScrollHandler } from "react-native-reanimated"; +import { createStyles } from "../../../theme/useStyles"; interface Props { panRef: RefObject; @@ -15,6 +16,8 @@ interface Props { const BottomSheetContent = forwardRef( ({ scrollOffset, Component, onClose }: Props, ref) => { + const styles = useStyles(); + const scrollHandler = useAnimatedScrollHandler((e) => { scrollOffset.value = e.contentOffset.y; }); @@ -45,24 +48,8 @@ const BottomSheetContent = forwardRef( keyboardShouldPersistTaps="handled" > {/* TODO THEMING!! */} - - + + @@ -74,3 +61,22 @@ const BottomSheetContent = forwardRef( } ); export default BottomSheetContent; + +const useStyles = createStyles((theme) => + StyleSheet.create({ + top: { + backgroundColor: theme.colors.darkBlue, + borderTopRightRadius: 25, + borderTopLeftRadius: 25, + }, + thingy: { + height: 6, + width: 72, + borderColor: "gray", + borderWidth: 3, + borderRadius: 99, + alignSelf: "center", + marginVertical: 8, + }, + }) +); diff --git a/native/components/Button.tsx b/native/components/Button.tsx index f83c1a73..98fc6959 100644 --- a/native/components/Button.tsx +++ b/native/components/Button.tsx @@ -34,7 +34,7 @@ type ButtonProps = { isLoading?: boolean; }; -const BORDER_WIDTH = 4; +const BORDER_WIDTH = 2; // weird, but needed to supress errors, related to keeping the event around in an async context const debounceOnPress = ( @@ -100,14 +100,16 @@ const useStyles = createStyles((theme) => margin: theme.spacing * 0.5, alignItems: "center", justifyContent: "center", - borderRadius: theme.borderRadiusFull, + borderRadius: theme.borderRadiusSmall, }, primary: { - backgroundColor: theme.colors.mediumBlue, - padding: theme.spacing, + backgroundColor: theme.colors.darkBlue, + borderColor: theme.colors.highlight, + borderWidth: BORDER_WIDTH, + padding: theme.spacing - BORDER_WIDTH, }, secondary: { - borderColor: theme.colors.mediumBlue, + borderColor: theme.colors.lightBlue, borderWidth: BORDER_WIDTH, padding: theme.spacing - BORDER_WIDTH, }, @@ -116,7 +118,7 @@ const useStyles = createStyles((theme) => width: "100%", }, string: { - color: theme.colors.darkBlue, + color: theme.colors.darkGrey, }, disabled: { opacity: 0.6 }, // SIZES diff --git a/native/components/Card.tsx b/native/components/Card.tsx index cf6c2473..cdd769fd 100644 --- a/native/components/Card.tsx +++ b/native/components/Card.tsx @@ -7,6 +7,7 @@ import { ViewStyle, } from "react-native"; +import { useTheme } from "@react-navigation/native"; import { ThemeColors } from "../theme"; import { createStyles } from "../theme/useStyles"; @@ -16,14 +17,12 @@ interface CardProps { padding?: CardPaddings; fullWidth?: boolean; children: React.ReactNode; - color?: Exclude< - ThemeColors, - "error" | "grey" | "transparent" | "red" | "green" - >; + color?: ThemeColors; style?: StyleProp; borderTop?: boolean; borderBottom?: boolean; onPress?: () => void; + badge?: "red" | "green"; } export const Card = forwardRef( @@ -37,9 +36,11 @@ export const Card = forwardRef( borderTop = false, borderBottom = false, onPress, + badge, }: CardProps, _ref ) => { + const theme = useTheme(); const styles = useStyles(); if (onPress) { return ( @@ -49,11 +50,16 @@ export const Card = forwardRef( borderBottom && styles.borderBottom, borderTop && styles.borderTop, styles[padding], - styles[color], + { backgroundColor: theme.colors[color] }, fullWidth && styles.fullWidth, style, ]} > + {badge && ( + + )} {children} ); @@ -65,11 +71,16 @@ export const Card = forwardRef( borderBottom && styles.borderBottom, borderTop && styles.borderTop, styles[padding], - styles[color], + { backgroundColor: theme.colors[color] }, fullWidth && styles.fullWidth, style, ]} > + {badge && ( + + )} {children} ); @@ -86,6 +97,24 @@ const useStyles = createStyles((theme) => borderBottomLeftRadius: theme.borderRadius, borderBottomRightRadius: theme.borderRadius, }, + // badge: { + // position: "absolute", + // overflow: "hidden", + // backgroundColor: theme.colors.red, + // top: -2, + // left: -2, + // width: 12, + // height: 12, + // borderRadius: theme.borderRadius, + // }, + badge: { + position: "absolute", + height: "100%", + width: 5, + left: 0, + borderTopStartRadius: theme.borderRadiusSmall, + borderBottomStartRadius: theme.borderRadiusSmall, + }, none: { padding: 0, }, @@ -98,10 +127,5 @@ const useStyles = createStyles((theme) => fullWidth: { width: "100%", }, - black: { backgroundColor: theme.colors.black }, - white: { backgroundColor: theme.colors.white }, - lightBlue: { backgroundColor: theme.colors.lightBlue }, - mediumBlue: { backgroundColor: theme.colors.mediumBlue }, - darkBlue: { backgroundColor: theme.colors.darkBlue }, }) ); diff --git a/native/components/DateInputController.tsx b/native/components/DateInputController.tsx index 67615c8f..87abea39 100644 --- a/native/components/DateInputController.tsx +++ b/native/components/DateInputController.tsx @@ -106,7 +106,7 @@ const useStyles = createStyles((theme) => marginBottom: theme.spacing * 3, }, input: { - color: theme.colors.darkBlue, + color: theme.colors.darkGrey, }, }) ); diff --git a/native/components/Header.tsx b/native/components/Header.tsx index 07bda642..c25c9223 100644 --- a/native/components/Header.tsx +++ b/native/components/Header.tsx @@ -1,6 +1,7 @@ -import { useNavigation } from "@react-navigation/native"; +import { useNavigation, useTheme } from "@react-navigation/native"; import { NativeStackHeaderProps } from "@react-navigation/native-stack"; + import { View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { HeaderRight } from "./HeaderRight"; @@ -8,18 +9,17 @@ import { ArrowRightIcon } from "./Icon"; const HeaderWrapper = ({ children }: { children: React.ReactNode }) => { const insets = useSafeAreaInsets(); + const theme = useTheme(); return ( {children} @@ -31,7 +31,11 @@ export const Header = ({ route }: NativeStackHeaderProps) => { return ( {navigation.canGoBack() ? ( - + ) : ( )} diff --git a/native/components/HeaderRight.tsx b/native/components/HeaderRight.tsx index f0fb2045..06a160ab 100644 --- a/native/components/HeaderRight.tsx +++ b/native/components/HeaderRight.tsx @@ -5,6 +5,10 @@ import { CogIcon } from "./Icon"; export const HeaderRight = () => { const navigation = useNavigation(); return ( - navigation.navigate("SettingsScreen")} /> + navigation.navigate("SettingsScreen")} + color="darkGrey" + /> ); }; diff --git a/native/components/IDListCard.tsx b/native/components/IDListCard.tsx index f92f69d2..c8b984bf 100644 --- a/native/components/IDListCard.tsx +++ b/native/components/IDListCard.tsx @@ -38,14 +38,14 @@ export const IDListCard = ({ } > 15 ? "sBold" : "lBold"} numberOfLines={2} > {name} 15 ? "sBold" : "lBold"} > {quantity + " " + unit} diff --git a/native/components/ListCard/ListCardAdd.tsx b/native/components/ListCard/ListCardAdd.tsx index e0c601d6..2f2e34ed 100644 --- a/native/components/ListCard/ListCardAdd.tsx +++ b/native/components/ListCard/ListCardAdd.tsx @@ -3,23 +3,25 @@ import { useNavigation } from "@react-navigation/native"; import React from "react"; import { StyleSheet } from "react-native"; import { createStyles } from "../../theme/useStyles"; -import { Card } from "../Card"; +import { Button } from "../Button"; import { PlusIcon } from "../Icon"; export const InventoryCardAdd = () => { const styles = useStyles(); const navigation = useNavigation(); return ( - { navigation.navigate("NewStockScreen"); }} > - - + + ); }; @@ -30,6 +32,7 @@ const useStyles = createStyles((theme) => borderRadius: theme.borderRadiusSmall, alignItems: "center", justifyContent: "center", + alignSelf: "center", marginBottom: theme.spacing * 2, }, }) diff --git a/native/components/ListCard/ListCardLink.tsx b/native/components/ListCard/ListCardLink.tsx index 430b5ac8..8ae025cb 100644 --- a/native/components/ListCard/ListCardLink.tsx +++ b/native/components/ListCard/ListCardLink.tsx @@ -1,6 +1,6 @@ import { useNavigation } from "@react-navigation/native"; import React from "react"; -import { StyleSheet, View } from "react-native"; +import { StyleSheet } from "react-native"; import { DeliveryTabNavigationProp, InventoryTabNavigationProp, @@ -11,12 +11,11 @@ import { SmallerArrowRightIcon } from "../Icon"; import { Typography } from "../Typography"; type InventoryCardAddProps = { - title: string; + title: string | undefined; id: number; isDelivery: boolean; }; -// fuck this type assetion bullshit man const navigateToTabScreen = (navigation: any, id: number, isDelivery: boolean) => () => { if (isDelivery) { @@ -43,33 +42,17 @@ export const ListCardLink = ({ color="mediumBlue" style={styles.card} padding="none" + badge={isDelivery ? "green" : "red"} onPress={navigateToTabScreen(navigation, id, isDelivery)} > 15 ? "sBold" : "lBold"} + color="darkGrey" + variant={(title?.length ?? 0) > 15 ? "sBold" : "lBold"} numberOfLines={2} > {title} - - + ); }; diff --git a/native/components/LoadingSpinner.tsx b/native/components/LoadingSpinner.tsx index 6139dfcd..3bbd2372 100644 --- a/native/components/LoadingSpinner.tsx +++ b/native/components/LoadingSpinner.tsx @@ -1,6 +1,10 @@ import { useTheme } from "@react-navigation/native"; import { ActivityIndicator } from "react-native"; -export const LoadingSpinner = () => { +export const LoadingSpinner = ({ + size = 17, +}: { + size?: number | "small" | "large"; +}) => { const theme = useTheme(); - return ; + return ; }; diff --git a/native/components/NewBarcodeListItem.tsx b/native/components/NewBarcodeListItem.tsx index ccd9945b..44f81ced 100644 --- a/native/components/NewBarcodeListItem.tsx +++ b/native/components/NewBarcodeListItem.tsx @@ -23,7 +23,7 @@ export const NewBarcodeListItem = ({ padding="none" > 15 ? "sBold" : "lBold"} numberOfLines={2} > @@ -45,7 +45,7 @@ const useStyles = createStyles((theme) => borderRadius: theme.borderRadiusSmall, }, highlighted: { - borderColor: theme.colors.darkBlue, + borderColor: theme.colors.highlight, borderStyle: "solid", borderWidth: 2, marginLeft: -2, diff --git a/native/components/Skeleton.tsx b/native/components/Skeleton.tsx index 0ac20e4c..5d36b275 100644 --- a/native/components/Skeleton.tsx +++ b/native/components/Skeleton.tsx @@ -51,7 +51,7 @@ const useStyles = createStyles((theme) => defaultSkeletonStyle: { height: "100%", width: "100%", - backgroundColor: theme.colors.darkBlue, + backgroundColor: theme.colors.darkGrey, }, }) ); diff --git a/native/components/Snackbar/index.tsx b/native/components/Snackbar/index.tsx index f8ac236c..3bef4d95 100644 --- a/native/components/Snackbar/index.tsx +++ b/native/components/Snackbar/index.tsx @@ -100,7 +100,7 @@ const Snackbar = ({ item }: SnackbarProps) => { export const SnackbarRenderer = () => { const { state: items } = useSnackbar(); - console.log(items.slice(0, 1)); + //TODO: add a logger entry here return items .slice(0, 1) .map((item) => ); @@ -133,10 +133,10 @@ const useStyles = createStyles((theme) => backgroundColor: theme.colors.red, }, info: { - backgroundColor: theme.colors.grey, + backgroundColor: theme.colors.highlight, }, text: { - color: theme.colors.white, + color: theme.colors.mediumBlue, }, }) ); diff --git a/native/components/TabBar/TabBar.tsx b/native/components/TabBar/TabBar.tsx new file mode 100644 index 00000000..4d1b25ce --- /dev/null +++ b/native/components/TabBar/TabBar.tsx @@ -0,0 +1,210 @@ +import { BottomTabBarProps } from "@react-navigation/bottom-tabs"; +import { useTheme } from "@react-navigation/native"; +import React, { useEffect, useRef } from "react"; +import { + Animated, + Easing, + SafeAreaView, + Text, + TouchableOpacity, + View, +} from "react-native"; +import { BottomTabNavigatorScreen } from "../../navigation/types"; +import { TabBarDot } from "./TabBarDot"; +import { TabBarTriangleCover } from "./TabBarTriangleCover"; +import { CleanTabBarStyle } from "./TabStyle"; + +export const CleanTabBar = (props: BottomTabBarProps) => { + const theme = useTheme(); + const BACKGROUND_COLOR = theme.colors.mediumBlue; + + return ( + + + + + + ); +}; + +export const CleanTabBarContent = ({ + state, + descriptors, + navigation, +}: BottomTabBarProps) => { + const theme = useTheme(); + const BACKGROUND_COLOR = theme.colors.mediumBlue; + const FOREGROUND_COLOR = theme.colors.mediumBlue; + + return state.routes.map((route, index) => { + const focusAnimation = useRef(new Animated.Value(0)).current; + + const { options } = descriptors[route.key as BottomTabNavigatorScreen]; + + const label = options.title; + const labelStyle = + options.tabBarLabelStyle !== undefined ? options.tabBarLabelStyle : {}; + + let color = + options.tabBarActiveTintColor !== undefined + ? options.tabBarActiveTintColor + : theme.colors.darkBlue; + + const renderIcon = (focused: boolean) => { + if (!options.tabBarIcon) { + return No icon; + } + + return options.tabBarIcon({ + focused, + color: focused ? FOREGROUND_COLOR : FOREGROUND_COLOR, + size: 23, + }); + }; + + const isFocused = state.index === index; + + const onPress = () => { + const event = navigation.emit({ + type: "tabPress", + target: route.key, + canPreventDefault: true, + }); + + if (!isFocused && !event.defaultPrevented) { + navigation.navigate(route); + } + }; + + const onLongPress = () => { + navigation.emit({ + type: "tabLongPress", + target: route.key, + }); + }; + + useEffect(() => { + if (isFocused) { + onFocusedAnimation(); + } else { + notFocusedAnimation(); + } + }, [isFocused]); + + const onFocusedAnimation = () => { + Animated.timing(focusAnimation, { + toValue: 1, + duration: 700, + useNativeDriver: true, + easing: Easing.bezier(0.33, 1, 0.68, 1), + }).start(); + }; + + const notFocusedAnimation = () => { + Animated.timing(focusAnimation, { + toValue: 0, + duration: 700, + useNativeDriver: true, + easing: Easing.bezier(0.33, 1, 0.68, 1), + }).start(); + }; + + const translateYIcon = focusAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, -18], + }); + const scaleIcon = focusAnimation.interpolate({ + inputRange: [0, 0.9, 1], + outputRange: [1, 1, 0], + }); + const translateYFilterIcon = focusAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [20, -35], + }); + const translateYText = focusAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [40, 0], + }); + const scaleText = focusAnimation.interpolate({ + inputRange: [0, 0.1, 1], + outputRange: [0, 1, 1], + }); + const scaleDot = focusAnimation.interpolate({ + inputRange: [0, 1], + outputRange: [0, 1], + }); + + return ( + + + + {renderIcon(isFocused)} + + + + + + {label} + + + + + + + + ); + }); +}; diff --git a/native/components/TabBar/TabBarDot.tsx b/native/components/TabBar/TabBarDot.tsx new file mode 100644 index 00000000..e5bbdaa3 --- /dev/null +++ b/native/components/TabBar/TabBarDot.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Animated } from "react-native"; +import { CleanTabBarStyle } from "./TabStyle"; +import type { TabBarDotProps } from "./types"; + +export const TabBarDot = ({ color, scale = 1 }: TabBarDotProps) => { + return ( + + ); +}; diff --git a/native/components/TabBar/TabBarTriangleCover.tsx b/native/components/TabBar/TabBarTriangleCover.tsx new file mode 100644 index 00000000..573ad632 --- /dev/null +++ b/native/components/TabBar/TabBarTriangleCover.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { Animated, View } from "react-native"; +import { CleanTabBarStyle } from "./TabStyle"; +import type { TabBarTriangleProps } from "./types"; + +export const TabBarTriangleCover = ({ + color, + style, + translateY, +}: TabBarTriangleProps) => { + return ( + + + + + ); +}; diff --git a/native/components/TabBar/TabStyle.ts b/native/components/TabBar/TabStyle.ts new file mode 100644 index 00000000..4d0e7fc8 --- /dev/null +++ b/native/components/TabBar/TabStyle.ts @@ -0,0 +1,80 @@ +import { StyleSheet } from "react-native"; + +export const CleanTabBarStyle = StyleSheet.create({ + container: { + flexDirection: "column", + alignItems: "center", + overflow: "hidden", + }, + content: { + minHeight: 55, + flexDirection: "row", + marginBottom: 2, + }, + item: { + flex: 1, + flexDirection: "row", + overflow: "hidden", + }, + touchableItem: { + flex: 1, + padding: 5, + justifyContent: "center", + alignItems: "center", + }, + itemIconLayer: { + position: "absolute", + zIndex: 1, + }, + itemIconNotFound: { + borderWidth: 2, + width: 23, + height: 23, + }, + filterIcon: { + zIndex: 2, + position: "absolute", + width: "100%", + }, + itemTextLayer: { + zIndex: 3, + position: "absolute", + }, + itemText: { + fontWeight: "bold", + marginBottom: 5, + }, + filterText: { + zIndex: 4, + position: "absolute", + bottom: -5, + width: "100%", + }, + triangleTop: { + width: "100%", + height: 0, + backgroundColor: "transparent", + borderStyle: "solid", + borderTopWidth: 0, + borderRightWidth: 180, + borderBottomWidth: 20, + borderLeftWidth: 0, + borderTopColor: "transparent", + borderRightColor: "transparent", + borderLeftColor: "transparent", + marginBottom: -1, + }, + triangleBottom: { + width: "100%", + height: 50, + marginBottom: -50, + }, + itemDot: { + zIndex: 5, + width: 5, + height: 5, + borderRadius: 50, + position: "absolute", + bottom: 5, + }, +}); diff --git a/native/components/TabBar/index.ts b/native/components/TabBar/index.ts new file mode 100644 index 00000000..47ddee20 --- /dev/null +++ b/native/components/TabBar/index.ts @@ -0,0 +1 @@ +export * from "./TabBar"; diff --git a/native/components/TabBar/types.ts b/native/components/TabBar/types.ts new file mode 100644 index 00000000..a1804f6d --- /dev/null +++ b/native/components/TabBar/types.ts @@ -0,0 +1,16 @@ +import type { + AnimatableNumericValue, + StyleProp, + ViewStyle, +} from "react-native"; + +export type TabBarTriangleProps = { + color?: string; + style?: StyleProp; + translateY: AnimatableNumericValue; +}; + +export type TabBarDotProps = { + color?: string; + scale?: AnimatableNumericValue; +}; diff --git a/native/components/TextInput.tsx b/native/components/TextInput.tsx index 84ec79d4..4e910153 100644 --- a/native/components/TextInput.tsx +++ b/native/components/TextInput.tsx @@ -15,7 +15,7 @@ import { import { isAndroid } from "../constants"; import { createStyles } from "../theme/useStyles"; -const BORDER_WIDTH = 4; +const BORDER_WIDTH = 2; export type TextInputProps = Omit & { invalid?: boolean; disabled?: boolean; @@ -81,9 +81,9 @@ export const TextInput = React.forwardRef( accessible accessibilityLabel={props.accessibilityLabel} editable={!disabled || editable} - placeholderTextColor={theme.colors.darkBlue} - selectionColor={theme.colors.darkBlue} - cursorColor={theme.colors.darkBlue} + placeholderTextColor={theme.colors.darkGrey} + selectionColor={theme.colors.highlight} + cursorColor={theme.colors.highlight} onFocus={(e: NativeSyntheticEvent) => handleFocus(onFocus ? () => onFocus(e) : () => undefined) } @@ -109,19 +109,19 @@ const useStyles = createStyles((theme) => StyleSheet.create({ container: { ...theme.text.s, - borderRadius: theme.borderRadiusFull, - height: 44, + borderRadius: theme.borderRadiusSmall, + height: 48, justifyContent: isAndroid ? undefined : "center", - borderColor: theme.colors.mediumBlue, + borderColor: theme.colors.lightBlue, borderWidth: BORDER_WIDTH, padding: theme.spacing + (isAndroid ? 0 : -BORDER_WIDTH), }, containerMultiline: { height: undefined, - minHeight: 44, + minHeight: 48, }, content: { - height: 44, + height: 48, overflow: "hidden", flexDirection: "row", justifyContent: "flex-start", @@ -129,18 +129,19 @@ const useStyles = createStyles((theme) => }, contentMultiline: { height: undefined, - minHeight: 44, + minHeight: 48, paddingVertical: 6, }, focused: { ...theme.baseShadow, }, input: { - height: 44, + height: 54, flexGrow: 1, flexShrink: 1, width: "100%", paddingHorizontal: theme.spacing * 2, + color: theme.colors.highlight, }, inputMultiline: { height: undefined, diff --git a/native/components/TextInputController.tsx b/native/components/TextInputController.tsx index be0d9508..4445fecd 100644 --- a/native/components/TextInputController.tsx +++ b/native/components/TextInputController.tsx @@ -40,7 +40,7 @@ export const TextInputController = ({ ref={ref} /> {error && ( - + {error.message} )} diff --git a/native/components/Typography.tsx b/native/components/Typography.tsx index 21fbfbc9..454e4499 100644 --- a/native/components/Typography.tsx +++ b/native/components/Typography.tsx @@ -19,7 +19,6 @@ export type TypographyProps = { variant?: keyof MainTheme["text"]; numberOfLines?: number; align?: "left" | "center" | "right" | "auto" | "justify"; - underline?: boolean; opacity?: boolean; }; @@ -31,7 +30,6 @@ export const Typography = ({ variant = "l", numberOfLines, align = "left", - underline = false, opacity = false, }: TypographyProps) => { const theme = useTheme(); @@ -43,7 +41,6 @@ export const Typography = ({ color && { color: theme.colors[color] }, styles[variant], align && styles[`align${align}`], - underline && styles.underline, opacity && styles.opacity, style, ]} @@ -82,9 +79,6 @@ const useStyles = createStyles((theme) => lBold: { ...theme.text.lBold }, xl: { ...theme.text.xl }, xlBold: { ...theme.text.xlBold }, - underline: { - textDecorationLine: "underline", - }, opacity: { opacity: theme.opacity, }, diff --git a/native/db/hooks/useCreateInventory.ts b/native/db/hooks/useCreateInventory.ts index c67de29b..e7045701 100644 --- a/native/db/hooks/useCreateInventory.ts +++ b/native/db/hooks/useCreateInventory.ts @@ -7,8 +7,8 @@ import { useSession } from "./sessionContext"; export const useCreateInventory = () => { const { companyId, session } = useSession(); const queryClient = useQueryClient(); - return useMutation({ - mutationFn: async (inventory: InventoryInsert) => { + return useMutation( + async (inventory: InventoryInsert) => { const { data, error } = await supabase .from("inventory") .insert({ ...inventory, company_id: companyId }) @@ -17,18 +17,22 @@ export const useCreateInventory = () => { if (error) throw new Error(error.message); return data; }, - onMutate: async (inventory: InventoryInsert) => { - await queryClient.cancelQueries(["inventories", session?.user.id]); - queryClient.setQueryData( - ["inventories", session?.user.id], - (old: any) => [...old, inventory] - ); - }, - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: ["inventories", session?.user.id], - exact: true, - refetchType: "all", - }), - }); + { + onMutate: async (inventory: InventoryInsert) => { + await queryClient.cancelQueries(["inventories", session?.user.id]); + queryClient.setQueryData( + ["inventories", session?.user.id], + (old: any) => { + return { ...old, data: [{ ...old.data, inventory }] }; + } + ); + }, + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: ["inventories", session?.user.id], + exact: true, + refetchType: "all", + }), + } + ); }; diff --git a/native/navigation/BottomTabNavigation.tsx b/native/navigation/BottomTabNavigation.tsx index 97bb4e6e..ac43d70a 100644 --- a/native/navigation/BottomTabNavigation.tsx +++ b/native/navigation/BottomTabNavigation.tsx @@ -6,6 +6,8 @@ import { View } from "react-native"; import { DeliveryFormContextProvider } from "../components/DeliveryFormContext/DeliveryFormContextProvider"; import { DeliveryIcon, InventoryIcon, ListIcon } from "../components/Icon"; import { InventoryFormContextProvider } from "../components/InventoryFormContext/InventoryFormContextProvider"; + +import { CleanTabBar } from "../components/TabBar"; import { Typography } from "../components/Typography"; import { useListInventories } from "../db"; import { useGetInventoryName } from "../db/hooks/useGetInventoryName"; @@ -55,14 +57,19 @@ const DeliveryStackNavigator = ({ route }: DeliveryTabProps) => { headerBackground: () => ( ), - headerBackVisible: false, headerTitle: deliveryName, + headerTitleStyle: { + color: theme.colors.highlight, + }, + headerBackVisible: false, }} /> { headerBackground: () => ( ), - headerBackVisible: false, headerTitle: deliveryName, + headerTitleStyle: { + color: theme.colors.highlight, + }, + headerBackVisible: false, // headerShown: false, }} /> @@ -119,6 +131,8 @@ const InventoryStackNavigator = ({ route }: InventoryTabProps) => { headerBackground: () => ( { /> ), headerTitle: inventoryName, + headerTitleStyle: { + color: theme.colors.highlight, + }, headerBackVisible: false, }} /> @@ -133,7 +150,22 @@ const InventoryStackNavigator = ({ route }: InventoryTabProps) => { name="RecordScreen" component={RecordScreen} options={{ - headerShown: false, + headerBackground: () => ( + + ), + headerTitle: inventoryName, + headerTitleStyle: { + color: theme.colors.highlight, + }, + headerBackVisible: false, }} /> @@ -142,16 +174,20 @@ const InventoryStackNavigator = ({ route }: InventoryTabProps) => { }; export const BottomTabNavigation = ({}: BottomTabProps) => { + const theme = useTheme(); return ( - + } + > ( - - ), + tabBarActiveTintColor: theme.colors.highlight, + tabBarIcon: () => , headerShown: false, lazy: false, }} @@ -160,28 +196,24 @@ export const BottomTabNavigation = ({}: BottomTabProps) => { name="InventoryTab" component={InventoryStackNavigator} options={{ + title: "Inwentaryzacja", tabBarShowLabel: false, - tabBarIcon: ({ focused }) => ( - - ), + tabBarActiveTintColor: theme.colors.highlight, + tabBarIcon: () => , headerShown: false, + lazy: false, }} /> ( - - ), + tabBarActiveTintColor: theme.colors.highlight, + tabBarIcon: () => , headerShown: false, + lazy: false, }} /> diff --git a/native/navigation/LoginStackNavigation.tsx b/native/navigation/LoginStackNavigation.tsx index 211076bd..da783697 100644 --- a/native/navigation/LoginStackNavigation.tsx +++ b/native/navigation/LoginStackNavigation.tsx @@ -1,4 +1,5 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack"; +import { Header } from "../components/Header"; import LoginScreen from "../screens/LoginScreen"; import StartScreen from "../screens/StartScreen"; import { LoginStackParamList } from "./types"; @@ -7,12 +8,11 @@ const Stack = createNativeStackNavigator(); export const LoginStackNavigation = () => { return ( - - + + , NativeStackScreenProps >; +export type BottomTabNavigatorScreen = keyof BottomTabParamList; /** * List Tab/Stack diff --git a/native/screens/BarcodeModalScreen.tsx b/native/screens/BarcodeModalScreen.tsx index 182ee17a..6181d80a 100644 --- a/native/screens/BarcodeModalScreen.tsx +++ b/native/screens/BarcodeModalScreen.tsx @@ -37,14 +37,14 @@ export function BarcodeModalScreen({ route }: BarcodeModalScreenProps) { Aby skorzystać ze skanera kodów, pozwól aplikacji na dostęp do kamery. Aby skorzystać ze skanera kodów, pozwól aplikacji na dostęp do kamery. @@ -102,7 +102,7 @@ const useStyles = createStyles((theme) => container: { flex: 1, justifyContent: "center", - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, height: "100%", }, }) diff --git a/native/screens/DeliveryTabScreen.tsx b/native/screens/DeliveryTabScreen.tsx index 3d802e20..000a9305 100644 --- a/native/screens/DeliveryTabScreen.tsx +++ b/native/screens/DeliveryTabScreen.tsx @@ -66,9 +66,6 @@ export default function DeliveryTabScreen({ return ( - - - @@ -143,21 +140,13 @@ export default function DeliveryTabScreen({ const useStyles = createStyles((theme) => StyleSheet.create({ container: { - backgroundColor: theme.colors.lightBlue, - }, - topBar: { - ...theme.baseShadow, - width: "100%", - backgroundColor: theme.colors.mediumBlue, - height: 50, - justifyContent: "center", - alignItems: "center", + backgroundColor: theme.colors.darkBlue, }, listContainer: { paddingHorizontal: theme.spacing * 4 }, scroll: { width: "100%", height: "100%", - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, }, date: { paddingTop: theme.spacing, diff --git a/native/screens/InventoryTabScreen.tsx b/native/screens/InventoryTabScreen.tsx index 0a626455..3324e7fb 100644 --- a/native/screens/InventoryTabScreen.tsx +++ b/native/screens/InventoryTabScreen.tsx @@ -66,9 +66,6 @@ export default function InventoryTabScreen({ return ( - - - @@ -132,21 +129,14 @@ export default function InventoryTabScreen({ const useStyles = createStyles((theme) => StyleSheet.create({ container: { - backgroundColor: theme.colors.lightBlue, - }, - topBar: { - ...theme.baseShadow, - width: "100%", - backgroundColor: theme.colors.mediumBlue, - height: 50, - justifyContent: "center", - alignItems: "center", + backgroundColor: theme.colors.darkBlue, }, + listContainer: { paddingHorizontal: theme.spacing * 4 }, scroll: { width: "100%", height: "100%", - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, }, date: { paddingTop: theme.spacing, @@ -165,7 +155,7 @@ const useStyles = createStyles((theme) => marginTop: theme.spacing * 2, gap: theme.spacing, }, - skeletonTopBarText: { height: 20, width: "50%" }, + skeletonFullWidthButton: { width: "100%", height: 58 }, skeletonButton: { width: 58, height: 58 }, skeletonListItem: { diff --git a/native/screens/ListTabScreen.tsx b/native/screens/ListTabScreen.tsx index 2b307c8b..6042773d 100644 --- a/native/screens/ListTabScreen.tsx +++ b/native/screens/ListTabScreen.tsx @@ -14,12 +14,7 @@ import { createStyles } from "../theme/useStyles"; const MonthTitle = ({ title }: { title: string }) => { const styles = useStyles(); return ( - + {title} ); @@ -27,7 +22,7 @@ const MonthTitle = ({ title }: { title: string }) => { const DayTitle = ({ title }: { title: string }) => { const styles = useStyles(); return ( - + {title} ); @@ -114,7 +109,7 @@ export const ListTab = ({}: ListTabScreenProps) => { {inventories.map((inventory) => ( { const useStyles = createStyles((theme) => StyleSheet.create({ screen: { - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, height: "100%", }, scroll: { diff --git a/native/screens/LoginScreen.tsx b/native/screens/LoginScreen.tsx index 089376b4..369fc6b0 100644 --- a/native/screens/LoginScreen.tsx +++ b/native/screens/LoginScreen.tsx @@ -52,12 +52,7 @@ export default function LoginScreen({}: LoginScreenProps) { return ( - + Logowanie ); }; @@ -169,17 +172,18 @@ export function RecordScreen({ route, navigation }: RecordScreenProps) { return ( - + {/* nazwa produktu */} {recordName} - + Ile było: 999 ? "lBold" : "xlBold"} style={styles.wasAmount} + color="darkGrey" > {unit ? previousQuantity + " " + unit : null} @@ -187,6 +191,7 @@ export function RecordScreen({ route, navigation }: RecordScreenProps) { {steppers.negative.map(({ click, step }, i) => ( - + - Ile jest: + Ile jest: 999 ? "lBold" : "xlBold"} style={styles.title} + color="darkGrey" > {/* liczba + jednostka current */} {unit ? quantity + " " + unit : null} @@ -227,12 +233,13 @@ export function RecordScreen({ route, navigation }: RecordScreenProps) { containerStyle={styles.editButton} onPress={() => openManualInput(quantity!, setQuantity)} > - + {steppers.positive.map(({ click, step }, i) => ( - + @@ -267,19 +274,13 @@ export function RecordScreen({ route, navigation }: RecordScreenProps) { const useStyles = createStyles((theme) => StyleSheet.create({ - topBar: { - ...theme.baseShadow, - width: "100%", - backgroundColor: theme.colors.mediumBlue, - height: 50, - justifyContent: "center", - alignItems: "center", - }, - container: { backgroundColor: theme.colors.lightBlue, height: "100%" }, + container: { backgroundColor: theme.colors.darkBlue, height: "100%" }, contentContainer: { paddingHorizontal: theme.spacing * 3 }, title: { paddingTop: theme.spacing * 3 }, wasTitle: { marginTop: theme.spacing * 5.5 }, - wasAmount: { paddingTop: theme.spacing * 2 }, + wasAmount: { + paddingTop: theme.spacing * 2, + }, content: { alignItems: "center" }, gridRow: { flexDirection: "row" }, leftColumn: { flexDirection: "column", alignItems: "flex-start" }, diff --git a/native/screens/SettingsScreen.tsx b/native/screens/SettingsScreen.tsx index 75fda825..7d76bc14 100644 --- a/native/screens/SettingsScreen.tsx +++ b/native/screens/SettingsScreen.tsx @@ -30,10 +30,10 @@ export default function SettingsScreen({ navigation }: SettingsScreenProps) { return ( - + Ustawienia - + Twój email: @@ -90,10 +90,10 @@ export default function SettingsScreen({ navigation }: SettingsScreenProps) { // @ts-ignore navigation.navigate("StartScreen"); }} - type="secondary" - size="s" + type="primary" + size="xl" fullWidth - containerStyle={styles.mt2} + containerStyle={[styles.mt2, styles.selfCenter]} > Wyloguj się @@ -104,7 +104,7 @@ export default function SettingsScreen({ navigation }: SettingsScreenProps) { const useStyles = createStyles((theme) => StyleSheet.create({ container: { - backgroundColor: theme.colors.lightBlue, + backgroundColor: theme.colors.darkBlue, paddingHorizontal: theme.spacing * 2, paddingTop: theme.spacing * 2, alignItems: "center", @@ -113,6 +113,9 @@ const useStyles = createStyles((theme) => mt2: { marginTop: theme.spacing * 9, }, + selfCenter: { + alignSelf: "center", + }, mb: { marginBottom: 16 }, }) ); diff --git a/native/screens/StartScreen.tsx b/native/screens/StartScreen.tsx index 332da247..a143edf0 100644 --- a/native/screens/StartScreen.tsx +++ b/native/screens/StartScreen.tsx @@ -25,6 +25,7 @@ export default function StartScreen({ navigation }: StartScreenProps) { return ( - + InvTrack