diff --git a/app/_layout.tsx b/app/_layout.tsx index 8a4b149..d6672d1 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -3,6 +3,7 @@ import {StyleSheet, View} from "react-native" import { FontAwesome } from "@expo/vector-icons"; import {useThemeColor} from "../hooks/hooks"; +import React from "react"; export default function Layout() { // const selectedColor: string = useThemeColor( "tabIconSelected"); diff --git a/app/index.tsx b/app/index.tsx index 27ced03..c9d4450 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,8 +1,15 @@ -import { StyleSheet, View, Text } from 'react-native'; -import {useThemeColor} from "../hooks/hooks"; +import { StyleSheet, View, Text, NativeSyntheticEvent, NativeScrollEvent } from 'react-native'; +import { useThemeColor } from "../hooks/hooks"; +import { SafeAreaView } from 'react-native-safe-area-context' +import { ExpenseItem, Plus, Welcome, SearchBar } from '../components'; +import { FlatList, TextInput } from 'react-native-gesture-handler'; +import { useRef, useState } from 'react'; +import React from 'react'; export default function Page() { + const [plusShow, setPlusShow] = useState(true); + const prevOffset = useRef(0); const styles = StyleSheet.create({ container: { flex: 1, @@ -16,10 +23,53 @@ export default function Page() { } }); + const profile = require("../assets/images/profile.jpg") + + const handleScroll = (event: NativeSyntheticEvent)=>{ + const currentOffset = event.nativeEvent.contentOffset.y >= 0 ? event.nativeEvent.contentOffset.y : 0 + const isScrollingUp : boolean = currentOffset <= prevOffset.current; + const isTop : boolean = currentOffset === 0 + prevOffset.current = currentOffset + setPlusShow(isScrollingUp || isTop) + } + + const data = [ + {id:"1",category: "Category 1", color: "blue", date:"01.01.2023 18:00", title:"1 Super fancy spending with long name that will not display", value: "€ 30,00"}, + {id:"2",category: "Category 2", color: "red", date:"01.01.2023 18:00", title:"2 Super fancy spending", value: "€ 30,00"}, + {id:"3",category: "Category 3", color: "green", date:"01.01.2023 18:00", title:"3 Super fancy spending", value: "€ 30,00"}, + {id:"4",category: "Category 4", color: "orange", date:"01.01.2023 18:00", title:"4 Super fancy spending", value: "€ 30,00"}, + {id:"5",category: "Category 1", color: "blue", date:"01.01.2023 18:00", title:"5 Super fancy spending", value: "€ 30,00"}, + {id:"6",category: "Category 2", color: "red", date:"01.01.2023 18:00", title:"6 Super fancy spending with long name that will not display", value: "€ 30,00"}, + {id:"7",category: "Category 3", color: "green", date:"01.01.2023 18:00", title:"7 Super fancy spending", value: "€ 30,00"}, + {id:"8",category: "Category 4", color: "orange", date:"01.01.2023 18:00", title:"8 Super fancy spending", value: "€ 30,00"}, + {id:"9",category: "Category 1", color: "blue", date:"01.01.2023 18:00", title:"9 Super fancy spending", value: "€ 30,00"}, + {id:"10" ,category: "Category 2", color: "red", date:"01.01.2023 18:00", title:"10 Super fancy spending", value: "€ 30,00"}, + {id:"11" ,category: "Category 3", color: "green", date:"01.01.2023 18:00", title:"11 Super fancy spending", value: "€ 30,00"}, + {id:"12" ,category: "Category 4", color: "orange", date:"01.01.2023 18:00", title:"12 Super fancy spending", value: "€ 30,00"}, + ] + return ( - - Home - - ); + + {plusShow && } + {/* console.log("hello")}> */} + + + console.log("hello")}> + + + } + renderItem = {({item}) => } + keyExtractor={item => item.id} + ItemSeparatorComponent={()=>} + onScroll={handleScroll} + scrollEventThrottle={20} + > + + + + ); } \ No newline at end of file diff --git a/assets/images/profile.jpg b/assets/images/profile.jpg new file mode 100644 index 0000000..f263453 Binary files /dev/null and b/assets/images/profile.jpg differ diff --git a/components/common/customCard/CustomCard.tsx b/components/common/customCard/CustomCard.tsx new file mode 100644 index 0000000..289df26 --- /dev/null +++ b/components/common/customCard/CustomCard.tsx @@ -0,0 +1,50 @@ +import { View, Text, StyleSheet, Platform } from 'react-native' +import React from 'react' +import { ViewProps } from 'react-native/Libraries/Components/View/ViewPropTypes' +import { useThemeColor } from '../../../hooks/hooks' +import { SHADOWS } from '../../../constants/theme' + +function generateBoxShadowStyle( + xOffset: number, + yOffset: number, + shadowColorIos: string, + shadowOpacity: number, + shadowRadius: number, + elevation: number, + shadowColorAndroid: string +):void { + if(Platform.OS === 'ios'){ + styles.boxShadow = { + shadowColor: shadowColorIos, + shadowOffset : {width: xOffset, height: yOffset}, + shadowOpacity, + shadowRadius, + backgroundColor: useThemeColor("backgroundColor") + } + }else if (Platform.OS === 'android'){ + styles.boxShadow = { + elevation: elevation, + shadowColor: shadowColorAndroid, + }; + } +} + +export default function CustomCard(props : ViewProps) { + generateBoxShadowStyle(1, 1, '#171717', 0.2, 20, 10, '#171717') + return ( + + {props.children} + + ) +} + +const styles = StyleSheet.create({ + container:{ + flexDirection: "row", + alignItems: "stretch", + alignContent: "space-between", + borderRadius: 20, + marginHorizontal: 10, + }, + boxShadow: {}, +}) \ No newline at end of file diff --git a/components/common/plus/plus.tsx b/components/common/plus/plus.tsx new file mode 100644 index 0000000..5121ffa --- /dev/null +++ b/components/common/plus/plus.tsx @@ -0,0 +1,28 @@ +import { View, Text, ViewProps, StyleSheet } from 'react-native' +import { AntDesign } from '@expo/vector-icons' +import React from 'react' + +const Plus = (props : ViewProps) => { + return ( + + {props.children} + + + ) +} +const style = StyleSheet.create({ + plus:{ + position: "absolute", + right: 20, + bottom: 20, + zIndex: 1, + backgroundColor: "orange", + padding: 20, + borderRadius: 500, + height: 60, + width: 60, + alignItems: 'center', + justifyContent: "center" + } +}) +export default Plus \ No newline at end of file diff --git a/components/common/searchBar/SearchBar.tsx b/components/common/searchBar/SearchBar.tsx new file mode 100644 index 0000000..23c61cf --- /dev/null +++ b/components/common/searchBar/SearchBar.tsx @@ -0,0 +1,68 @@ +import { View, Text, ViewProps, StyleSheet, Button } from 'react-native' +import React from 'react' +import { TextInput, TouchableOpacity } from 'react-native-gesture-handler' +import { AntDesign } from '@expo/vector-icons'; +import { useThemeColor } from '../../../hooks/hooks'; +import { SIZES } from '../../../constants/theme'; + +type SearchBarProps = {placeholder: string} & ViewProps + + + +export default function SearchBar(props: SearchBarProps) { + const [isActive, setIsactive] = React.useState(false); + + const backgroundColor = useThemeColor("backgroundColor"); + const handleChange = (text:string) : void => { + if(text !== ""){ + if(!isActive){ + setIsactive(true) + } + }else { + if(isActive){ + setIsactive(false) + } + } + } + +//TODO: Handle textCancel + return ( + + + + {isActive && + + + + } + + ) +} + +const styles = StyleSheet.create({ + container: { + marginHorizontal: 10, + marginBottom: 20, + flexDirection: 'row', + justifyContent: "center", + alignItems: "center", + height: 40, + backgroundColor: "red", //tochange + borderRadius: 10, + paddingHorizontal: 10 + }, + TextInput: { + flex: 1, + height: "100%", + justifyContent: "space-between", + alignItems: "center", + flexDirection: "row", + width: "100%", + }, + cancel:{ + height: "100%", + width: 30, + justifyContent: "center", + alignItems:"center", + } +}) diff --git a/components/home/Welcome/Welcome.tsx b/components/home/Welcome/Welcome.tsx new file mode 100644 index 0000000..757be58 --- /dev/null +++ b/components/home/Welcome/Welcome.tsx @@ -0,0 +1,71 @@ +import { View, Text, ViewProps, Image, GestureResponderEvent } from 'react-native' +import React from 'react' +import { MARGINS, SIZES, SHADOWS } from '../../../constants/theme' +import { TouchableOpacity } from 'react-native-gesture-handler' +import { useThemeColor } from '../../../hooks/hooks' + +type WelcomeProps = ViewProps & {name: string, image : any, onPress: () => void | undefined} + +function formatDate(date: Date) : string { + const day = String(date.getDate()).padStart(2, '0') + const month = String(date.getMonth() + 1).padStart(2, '0') + const year = String(date.getFullYear()) + return `${day}.${month}.${year}` +} + +function getTimeOfDay(date: Date) : string { + const hour = date.getHours() + if(hour < 12){ + return "morning" + } else if(hour >= 12 && hour < 18){ + return "afternoon" + } else if(hour >= 18){ + return "evening" + } + return "day" +} + + + +export default function Welcome(props: WelcomeProps) { + const date = new Date() + const dateString = formatDate(date) + const timeOfDay = getTimeOfDay(date) + const onpress = props.onPress + + const textcolor = useThemeColor("primaryText") + + return ( + + + + + + {dateString} + + + Good {timeOfDay}, {props.name} + + + ) +} \ No newline at end of file diff --git a/components/home/expenseItem/expenseItem.tsx b/components/home/expenseItem/expenseItem.tsx new file mode 100644 index 0000000..acd7821 --- /dev/null +++ b/components/home/expenseItem/expenseItem.tsx @@ -0,0 +1,61 @@ +import { View, Text, StyleSheet, ColorValue } from 'react-native' +import React from 'react' +import { useThemeColor } from '../../../hooks/hooks'; +import CustomCard from "../../common/customCard/CustomCard"; +import { SIZES } from '../../../constants/theme'; + +export type ExpenseItemProps = {color: ColorValue, category: string, title: string, date: string, value : string} +export default function ExpenseItem(itemProps : ExpenseItemProps) { + const textColor = useThemeColor("primaryText"); + const backgroundColor = useThemeColor("backgroundColor") + return ( + + + + {itemProps.category} + {itemProps.title} + {itemProps.date} + + + {itemProps.value} + + + + + ) +} + +const styles = StyleSheet.create({ + colorTip: { + width: 20, + borderTopLeftRadius: 20, + borderBottomLeftRadius: 20, + }, + + textSection: { + flexDirection: "column", + alignContent: "space-between", + alignItems:"flex-start", + paddingLeft: 10, + flex:1, + alignSelf: "stretch", + paddingVertical: 5 + }, + valueSection: { + justifyContent:"center", + borderTopRightRadius: 20, + borderBottomRightRadius: 20, + } +}) \ No newline at end of file diff --git a/components/index.jsx b/components/index.jsx new file mode 100644 index 0000000..403df5a --- /dev/null +++ b/components/index.jsx @@ -0,0 +1,15 @@ +//home +import ExpenseItem from "./home/expenseItem/expenseItem" +import Welcome from "./home/Welcome/Welcome" + +//common +import Plus from "./common/plus/plus" +import SearchBar from "./common/searchBar/SearchBar" + +export { + ExpenseItem, + Welcome, + Plus, + SearchBar +} + diff --git a/constants/theme.ts b/constants/theme.ts new file mode 100644 index 0000000..9bb46e0 --- /dev/null +++ b/constants/theme.ts @@ -0,0 +1,23 @@ +const SIZES = { + small: 12, + normal: 17, + large: 20, + xlarge: 25, + xxLarge: 30 +} + +const MARGINS = { + normal: 10 +} + +const SHADOWS = { + light: { + shadowColor: "#ADB7C3", + shadowRadius: 20, + elevation: 10, + shadowOpacity: 0.6, + shadowOffset: { width: 1, height: 1 } + } +} + +export {SIZES, SHADOWS, MARGINS} \ No newline at end of file