diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9889a4f..8a1e9c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,13 +25,14 @@ stages: lint_job: stage: lint - image: node + image: "reactnativecommunity/react-native-android:latest" rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: manual - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH script: - - npm install + - yarn install + - npx expo install - npx tsc cache: policy: pull-push diff --git a/app/(tabs)/budget/_layout.tsx b/app/(tabs)/budget/_layout.tsx index ce907f3..c0835eb 100644 --- a/app/(tabs)/budget/_layout.tsx +++ b/app/(tabs)/budget/_layout.tsx @@ -5,6 +5,7 @@ export default function _Layout() { + ); diff --git a/app/(tabs)/budget/addCategory.tsx b/app/(tabs)/budget/addCategory.tsx index 904f37c..984d98e 100644 --- a/app/(tabs)/budget/addCategory.tsx +++ b/app/(tabs)/budget/addCategory.tsx @@ -1,21 +1,23 @@ 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 { AutoDecimalInput, CustomColorPicker, NavigationButton, TypeSelectorSwitch } from "../../../components"; +import { addCategory } from "../../../services/database"; import { useTheme } from "../../contexts/ThemeContext"; -const addCategory = () => { +export default function Page() { const {colors} = useTheme(); const parameters = useLocalSearchParams(); const [categoryName, setCategoryName] = useState("Enter Category Name..."); - const [categoryColor, setCategoryColor] = useState(null); + const [categoryColor, setCategoryColor] = useState('#' + Math.floor(Math.random()*16777215).toString(16)); const [selectedType, setSelectedType] = useState("expense"); + const [amount, setAmount] = useState(0); return ( - Category Editor + Add Category @@ -24,6 +26,12 @@ const addCategory = () => { }}/> + + { + setAmount(!Number.isNaN(Number.parseFloat(value)) ? Number.parseFloat(value) : 0); + }}/> + + { @@ -32,7 +40,7 @@ const addCategory = () => { /> - { + { setCategoryColor(color); }}/> @@ -42,7 +50,7 @@ const addCategory = () => { router.back(); }}/> { - console.log("Implement Saving here!"); + addCategory(categoryName, categoryColor, selectedType, amount); router.back(); }}/> @@ -51,8 +59,6 @@ const addCategory = () => { ); } -export default addCategory; - const styles = StyleSheet.create({ containerStyle: { flex: 1, @@ -82,5 +88,9 @@ const styles = StyleSheet.create({ textInputStyle: { paddingHorizontal: 10, fontSize: 25, + }, + budgetInput: { + marginBottom: 10, + marginHorizontal: 10, } }); \ No newline at end of file diff --git a/app/(tabs)/budget/category.tsx b/app/(tabs)/budget/category.tsx index dc283bf..a58d02b 100644 --- a/app/(tabs)/budget/category.tsx +++ b/app/(tabs)/budget/category.tsx @@ -7,12 +7,14 @@ import { useTheme } from "../../contexts/ThemeContext"; export default function Page() { const {colors} = useTheme(); - const {category_guid, category_name} = useLocalSearchParams(); + const {category_guid} = useLocalSearchParams(); + + const {category_amount, category_color, category_name, category_type} = fetchCategoryInformation(category_guid.toString()); const {data, isLoading, reFetch} = useFetch({sql: "SELECT e.guid AS expense_guid, e.name AS expense_name, c.name AS category_name, e.datetime AS expense_datetime, e.amount AS expense_amount, c.color AS category_color FROM expense e JOIN category c ON e.category_guid = c.guid WHERE c.guid = ? ORDER BY expense_datetime desc;", args: [category_guid]}); const handleEditCategory = () => { - console.log("edit category"); + router.push({pathname: "./(tabs)/budget/editCategory", params: {category_guid: category_guid, category_color: category_color, category_amount: category_amount, category_name: category_name, category_type: category_type}}); } const handleBackButton = () => { @@ -54,6 +56,25 @@ export default function Page() { ); } +const fetchCategoryInformation = (guid: string) => { + + const {data} = useFetch({sql: "SELECT * FROM category WHERE guid = ?", args: [guid]}); + + let category_name = ""; + let category_color = ""; + let category_amount = 0; + let category_type = ""; + + if (data && data[0]) { + if ("name" in data[0]) category_name = data[0].name as string; + if ("color" in data[0]) category_color = data[0].color as string; + if ("allocated_amount" in data[0]) category_amount = data[0].allocated_amount as number; + if ("type" in data[0]) category_type = data[0].type as string; + } + + return {category_name, category_color, category_amount, category_type}; +} + const styles = StyleSheet.create({ safeAreaView: { flex: 1, diff --git a/app/(tabs)/budget/editCategory.tsx b/app/(tabs)/budget/editCategory.tsx new file mode 100644 index 0000000..b3b8ec7 --- /dev/null +++ b/app/(tabs)/budget/editCategory.tsx @@ -0,0 +1,96 @@ +import { router, useLocalSearchParams } from "expo-router"; +import { useState } from "react"; +import { SafeAreaView, StyleSheet, Text, TextInput, View } from "react-native"; +import { AutoDecimalInput, CustomColorPicker, NavigationButton, TypeSelectorSwitch } from "../../../components"; +import { useTheme } from "../../contexts/ThemeContext"; + +const addCategory = () => { + const {colors} = useTheme(); + const {category_guid, category_amount, category_color, category_name, category_type} = useLocalSearchParams(); + + const [categoryName, setCategoryName] = useState(category_name.toString()); + const [categoryColor, setCategoryColor] = useState(category_color.toString()); + const [selectedType, setSelectedType] = useState(category_type.toString()); + const [amount, setAmount] = useState(Number.parseFloat(category_amount.toString())); + + return ( + + Edit Category + + + + { + setCategoryName(newName); + }}/> + + + + { + setAmount(!Number.isNaN(Number.parseFloat(value)) ? Number.parseFloat(value) : 0); + }}/> + + + { + setSelectedType(type); + }} + /> + + + { + setCategoryColor(color); + }}/> + + + + { + router.back(); + }}/> + { + console.log("Implement Saving here!"); + router.back(); + }}/> + + + + ); +} + +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, + }, + budgetInput: { + marginBottom: 10, + marginHorizontal: 10, + } +}); \ No newline at end of file diff --git a/app/(tabs)/budget/index.tsx b/app/(tabs)/budget/index.tsx index 9131dc7..3f2aa97 100644 --- a/app/(tabs)/budget/index.tsx +++ b/app/(tabs)/budget/index.tsx @@ -38,7 +38,7 @@ export default function Page() { }; const handleCategoryPress = (item: {[column: string]: any;}) => { - router.push({pathname: "/(tabs)/budget/category", params: {category_guid: item.category_guid, category_name: item.category_name}}) + router.push({pathname: "./(tabs)/budget/category", params: {category_guid: item.category_guid, category_name: item.category_name}}) } return ( diff --git a/components/budget/categoryItem.tsx b/components/budget/categoryItem.tsx index 6c29e14..d64a29b 100644 --- a/components/budget/categoryItem.tsx +++ b/components/budget/categoryItem.tsx @@ -16,12 +16,12 @@ const CategoryItem = (properties: CategoryItemProps) => { const { colors } = useTheme(); - const subText = `${properties.total_expenses} / ${properties.allocated_amount} €`; + const subText = `${properties.total_expenses.toFixed(2)} / ${properties.allocated_amount} €`; return ( - + {properties.category} diff --git a/components/budget/customColorPicker.tsx b/components/budget/customColorPicker.tsx index b78e1b4..f601f12 100644 --- a/components/budget/customColorPicker.tsx +++ b/components/budget/customColorPicker.tsx @@ -2,14 +2,14 @@ import { StyleSheet } from "react-native"; import ColorPicker, { BrightnessSlider, HueSlider, Preview, SaturationSlider, } from "reanimated-color-picker"; export type CustomColorPickerProperties = { - currentColor?: string | null, + color: string, handleColorChange: (color: string) => void | undefined, } const CustomColorPicker = (properties: CustomColorPickerProperties) => { return ( { properties.handleColorChange(color["hex"]) }} @@ -30,10 +30,6 @@ const CustomColorPicker = (properties: CustomColorPickerProperties) => { ); } -const generateRandomColor = (): string => { - return '#' + Math.floor(Math.random()*16777215).toString(16); -} - export default CustomColorPicker; const styles = StyleSheet.create({