diff --git a/app/(tabs)/budget/_layout.tsx b/app/(tabs)/budget/_layout.tsx index 5c62492..238abc6 100644 --- a/app/(tabs)/budget/_layout.tsx +++ b/app/(tabs)/budget/_layout.tsx @@ -1,16 +1,10 @@ import { Stack } from "expo-router"; -import { useTheme } from "../../contexts/ThemeContext"; export default function _Layout() { - const { colors } = useTheme(); return ( - + - + ); } \ No newline at end of file diff --git a/app/(tabs)/budget/addCategory.tsx b/app/(tabs)/budget/addCategory.tsx index e8edbbc..c211406 100644 --- a/app/(tabs)/budget/addCategory.tsx +++ b/app/(tabs)/budget/addCategory.tsx @@ -1,8 +1,86 @@ +import { router, useLocalSearchParams } from "expo-router"; +import { useState } from "react"; +import { SafeAreaView, StyleSheet, Text, TextInput, View } from "react-native"; +import { CustomColorPicker, NavigationButton, TypeSelectorSwitch } from "../../../components"; +import { useTheme } from "../../contexts/ThemeContext"; const addCategory = () => { + const {colors} = useTheme(); + + const parameters = useLocalSearchParams(); + + const [categoryName, setCartegoryName] = useState("Enter Category Name..."); + const [categoryColor, setCartegoryColor] = useState(null); + const [selectedType, setSelectedType] = useState("expense"); + return ( - <> + + Category Editor + + + + { + setCartegoryName(newName); + }}/> + + + { + setSelectedType(type); + }} + /> + + + { + setCartegoryColor(color); + }}/> + + + + { + router.back(); + }}/> + { + console.log("Implement Saving here!"); + router.back(); + }}/> + + + ); } -export default addCategory; \ No newline at end of file +export default addCategory; + +const styles = StyleSheet.create({ + containerStyle: { + flex: 1, + margin: 10, + borderRadius: 10, + }, + safeAreaViewStyle: { + flex: 1, + flexDirection: "column" + }, + headingTextStyle: { + fontSize: 40, + fontWeight: "bold", + alignSelf: "center", + marginVertical: 10, + }, + navigationButtonViewStyle: { + flexDirection: "row", + justifyContent: "center", + marginBottom: 10, + }, + textInputViewStyle: { + borderRadius: 10, + paddingVertical: 10, + margin: 10, + }, + textInputStyle: { + paddingHorizontal: 10, + fontSize: 25, + } +}); \ No newline at end of file diff --git a/app/(tabs)/budget/index.tsx b/app/(tabs)/budget/index.tsx index 4ca010e..3e2052c 100644 --- a/app/(tabs)/budget/index.tsx +++ b/app/(tabs)/budget/index.tsx @@ -4,8 +4,7 @@ import { useEffect, useState } from 'react'; import { StyleSheet, View } from 'react-native'; import { FlatList } from 'react-native-gesture-handler'; import { SafeAreaView } from 'react-native-safe-area-context'; -import { BudgetHeader, LoadingSymbol, Plus } from '../../../components'; -import CategoryItem from '../../../components/budget/categoryItem'; +import { BudgetHeader, CategoryItem, LoadingSymbol, Plus } from '../../../components'; import useFetch from '../../../hooks/useFetch'; import { useTheme } from '../../contexts/ThemeContext'; @@ -43,7 +42,7 @@ export default function Page() { { - router.push("/(tabs)/budget/addCategory") + router.push({pathname: '/(tabs)/budget/addCategory', params: { guid: '123'}}); //This needs to be changed to a regular push, without parameters }}/> {isLoading ? () : ( diff --git a/babel.config.js b/babel.config.js index 79900d3..f76b519 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,6 +4,7 @@ module.exports = function (api) { presets: ['babel-preset-expo'], plugins: [ 'expo-router/babel', + 'react-native-reanimated/plugin', ], }; }; diff --git a/components/budget/customColorPicker.tsx b/components/budget/customColorPicker.tsx new file mode 100644 index 0000000..b78e1b4 --- /dev/null +++ b/components/budget/customColorPicker.tsx @@ -0,0 +1,51 @@ +import { StyleSheet } from "react-native"; +import ColorPicker, { BrightnessSlider, HueSlider, Preview, SaturationSlider, } from "reanimated-color-picker"; + +export type CustomColorPickerProperties = { + currentColor?: string | null, + handleColorChange: (color: string) => void | undefined, +} + +const CustomColorPicker = (properties: CustomColorPickerProperties) => { + return ( + { + properties.handleColorChange(color["hex"]) + }} + style={styles.colorPickerStyle} + sliderThickness={30} + thumbSize={40} + thumbShape= "circle"> + + + + + + + ); +} + +const generateRandomColor = (): string => { + return '#' + Math.floor(Math.random()*16777215).toString(16); +} + +export default CustomColorPicker; + +const styles = StyleSheet.create({ + colorPickerStyle: { + justifyContent: 'center', + }, + sliderStyle: { + margin: 10, + }, + previewStyle: { + margin: 10, + height: 50, + borderRadius: 10, + } + }); \ No newline at end of file diff --git a/components/budget/typeSelectorSwitch.tsx b/components/budget/typeSelectorSwitch.tsx new file mode 100644 index 0000000..dc6231b --- /dev/null +++ b/components/budget/typeSelectorSwitch.tsx @@ -0,0 +1,53 @@ + +import { StyleSheet, Text, TouchableOpacity, View } from "react-native"; +import { useTheme } from "../../app/contexts/ThemeContext"; + +export type TypeSelectorSwitchProperties = { + handleButtonPress: (type: string) => void, + currentSelected: string, +} + +const TypeSelectorSwitch = (properties: TypeSelectorSwitchProperties) => { + const {colors} = useTheme(); + + return ( + + { + properties.handleButtonPress("expense"); + }} + style={[styles.touchableOpacityStyle, properties.currentSelected == "expense" ? {backgroundColor: colors.accentColor} : {backgroundColor: colors.elementDefaultColor}] + }> + Expenses + + { + properties.handleButtonPress("saving"); + }} + style={[styles.touchableOpacityStyle, properties.currentSelected == "saving" ? {backgroundColor: colors.accentColor} : {backgroundColor: colors.elementDefaultColor}] + }> + Savings + + + ); +} + +export default TypeSelectorSwitch; + +const styles = StyleSheet.create({ + containerStyle: { + flexDirection: "row", + justifyContent: "center", + }, + touchableOpacityStyle: { + flex: 1, + marginHorizontal: 10, + borderRadius: 10, + }, + textStyle: { + paddingHorizontal: 10, + fontSize: 25, + textAlign: "center", + paddingVertical: 5, + } +}); \ No newline at end of file diff --git a/components/common/button.tsx b/components/common/button.tsx new file mode 100644 index 0000000..a846cfd --- /dev/null +++ b/components/common/button.tsx @@ -0,0 +1,39 @@ + +import { StyleSheet, Text, TouchableHighlight } from "react-native"; +import { useTheme } from "../../app/contexts/ThemeContext"; + +export type NavigationButtonProperties = { + onPress?: () => void | undefined, + text: string, +} + +const NavigationButton = (properties: NavigationButtonProperties) => { + + const {colors} = useTheme(); + + return ( + + + {properties.text} + + ); +} + +export default NavigationButton; + +const styles = StyleSheet.create({ + touchableHighlightStyle: { + borderRadius: 10, + marginVertical: 10, + marginHorizontal: 15, + paddingHorizontal: 20, + paddingVertical: 5, + }, + buttonTextStyle: { + textAlign: "center", + fontSize: 30, + } +}); diff --git a/components/index.tsx b/components/index.tsx index 4d74a43..f3dd44f 100644 --- a/components/index.tsx +++ b/components/index.tsx @@ -4,19 +4,24 @@ import Welcome from "./home/Welcome" import ExpenseItem from "./home/expenseItem" //common +import CustomCard from "./common/CustomCard" +import SearchBar from "./common/SearchBar" +import NavigationButton from "./common/button" import LoadingSymbol from "./common/loadingSymbol" import Plus from "./common/plus" -import SearchBar from "./common/SearchBar" -import CustomCard from "./common/CustomCard" +//budget +import BudgetHeader from "./budget/budgetHeader" +import CategoryItem from "./budget/categoryItem" +import CustomColorPicker from "./budget/customColorPicker" +import TypeSelectorSwitch from "./budget/typeSelectorSwitch" //login -import BudgetHeader from "./budget/budgetHeader" import Input from "./login/input" export { - BudgetHeader, ButtonSetting, CustomCard, ExpenseItem, Input, - LoadingSymbol, Plus, - SearchBar, ToggleSetting, Welcome + BudgetHeader, ButtonSetting, CategoryItem, CustomCard, CustomColorPicker, ExpenseItem, Input, + LoadingSymbol, NavigationButton, Plus, + SearchBar, ToggleSetting, TypeSelectorSwitch, Welcome } diff --git a/package-lock.json b/package-lock.json index d597893..16b6032 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,10 +26,12 @@ "react-native": "0.72.6", "react-native-calendars": "^1.1303.0", "react-native-gesture-handler": "~2.12.0", + "react-native-reanimated": "^3.3.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", "react-native-uuid": "^2.0.1", - "react-native-web": "~0.19.6" + "react-native-web": "~0.19.6", + "reanimated-color-picker": "^2.4.2" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -1415,6 +1417,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-object-assign": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.23.3.tgz", + "integrity": "sha512-TPJ6O7gVC2rlQH2hvQGRH273G1xdoloCj9Pc07Q7JbIZYDi+Sv5gaE2fu+r5E7qK4zyt6vj0FbZaZTRU5C3OMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", @@ -15761,6 +15777,27 @@ "react-native": "*" } }, + "node_modules/react-native-reanimated": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.3.0.tgz", + "integrity": "sha512-LzfpPZ1qXBGy5BcUHqw3pBC0qSd22qXS3t8hWSbozXNrBkzMhhOrcILE/nEg/PHpNNp1xvGOW8NwpAMF006roQ==", + "dependencies": { + "@babel/plugin-transform-object-assign": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-proposal-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-safe-area-context": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.6.3.tgz", @@ -15909,6 +15946,23 @@ "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, + "node_modules/reanimated-color-picker": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/reanimated-color-picker/-/reanimated-color-picker-2.4.2.tgz", + "integrity": "sha512-UNw1jEEOjY2m6F/sI7/nZQwT+yl7kSxao9wJtdkHUsrmm66QRqWKku76/hZGXyl+wzdKk4yLmXMPaEaLq69GBg==", + "peerDependencies": { + "expo": ">=44.0.0", + "react": "*", + "react-native": "*", + "react-native-gesture-handler": ">=2.0.0", + "react-native-reanimated": "^2.0.0 || ^3.0.0" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, "node_modules/recast": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", diff --git a/package.json b/package.json index 7f833d1..abb4142 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,12 @@ "react-native": "0.72.6", "react-native-calendars": "^1.1303.0", "react-native-gesture-handler": "~2.12.0", + "react-native-reanimated": "^3.3.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", "react-native-uuid": "^2.0.1", - "react-native-web": "~0.19.6" + "react-native-web": "~0.19.6", + "reanimated-color-picker": "^2.4.2" }, "devDependencies": { "@babel/core": "^7.20.0",