diff --git a/app/_layout.tsx b/app/_layout.tsx index a814643..ea5b827 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -13,8 +13,11 @@ import AddCalendarEvents from './addCalendarEvents'; import AddHealthEvents from './addHealthEvents'; import AddMeals from './addMeals'; import AddFinanceEvents from './addFinanceEvents'; -import ViewEvents from './viewEvents'; +import ViewFinanceEvents from './viewFinanceEvents'; import { NavigationContainer } from '@react-navigation/native'; +import ViewHealthEvents from './viewHealthEvents'; +import ViewCalendarEvents from './viewCalendarEvents'; +import ViewMealEvents from './viewMealEvents'; const Stack = createStackNavigator(); @@ -63,7 +66,10 @@ export default function Layout() { - + + + + ); diff --git a/app/addHealthEvents.tsx b/app/addHealthEvents.tsx index 284f124..9548b60 100644 --- a/app/addHealthEvents.tsx +++ b/app/addHealthEvents.tsx @@ -19,7 +19,6 @@ export default function AddHealthEvents() { { name: 'event_date', label: 'Date', type: 'date' }, { name: 'event_time', label: 'Time', type: 'time' }, { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, - { name: 'description', label: 'Description', type: 'textarea' }, ]; const handleSave = async (saveData: any) => { diff --git a/app/addMeals.tsx b/app/addMeals.tsx index b674f27..cb7ce1a 100644 --- a/app/addMeals.tsx +++ b/app/addMeals.tsx @@ -67,7 +67,7 @@ export default function AddMeals() { useEffect(() => { fetchIngredients(); }, []); - + cLog("AddMeals: Ingredients:", ingredients); return ( { export const getPageName = (page) => { switch(page){ case 'finance': - return 'Finance'; + return 'viewFinanceEvents'; case 'healthTracker': - return 'Health'; + return 'viewHealthEvents'; case 'mealTracker': - return 'Meal'; + return 'viewMealEvents'; case 'calendarEvents': - return 'Calendar'; + return 'viewCalendarEvents'; default: return 'Home'; } +}; + +export const getPageFromEventType = (eventType) => { + switch(eventType){ + case 'health': + return 'healthTracker'; + case 'meal': + return 'mealTracker'; + case 'calendar': + return 'calendarEvents'; + default: + return eventType; + } } \ No newline at end of file diff --git a/app/mainPageTemplate.tsx b/app/mainPageTemplate.tsx index 2fbc24e..0853ed3 100644 --- a/app/mainPageTemplate.tsx +++ b/app/mainPageTemplate.tsx @@ -8,6 +8,7 @@ import { RootStackParamList, Task } from '../components/Types'; import { useNavigation } from '@react-navigation/native'; import { StackNavigationProp } from '@react-navigation/stack'; import { cLog } from './log'; +import { getPageFromEventType, getPageName } from './constants'; // import { cLog } from './log'; interface FormProps { @@ -32,9 +33,11 @@ const GenericMainPageForm: React.FC = ({ title, header, nextPage, thi const handleViewPress = (item: Task) => { // cLog(item); const route = { ...item, thisPage }; - if(thisPage === 'index') + if(route.thisPage === 'index'){ + route.thisPage = getPageFromEventType(route.event.event_type) as keyof RootStackParamList; + } cLog("Route:",route); - navigation.navigate('viewEvents', { event: route }); + navigation.navigate(getPageName(route.thisPage) as any, { event: route }); } const renderTask = ({ item }: { item: Task }) => ( diff --git a/app/viewCalendarEvents.tsx b/app/viewCalendarEvents.tsx new file mode 100644 index 0000000..13a1b2b --- /dev/null +++ b/app/viewCalendarEvents.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import axios from 'axios'; +import { IPAddr, repeatingData } from './constants'; +import { cLog } from './log' +import GenericViewPageForm from './viewEventPage'; +import { RouteProp, useRoute } from '@react-navigation/native'; +import { RootStackParamList } from '@/components/Types'; + +type ViewEventsRouteProp = RouteProp; + +export default function ViewCalendarEvents() { + const route = useRoute(); + const { event } = route.params; + cLog("Passed event:", event); + const fields = [ + { name: 'title', label: 'Title', type: 'text' }, + { name: 'event_date', label: 'Date', type: 'date' }, + { name: 'event_time', label: 'Time', type: 'time' }, + { name: 'description', label: 'Description', type: 'textarea' }, + { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, + ]; + const handleSave = async (saveData: any) => { + try { + cLog("Save Data:", saveData); + const hit = IPAddr + '/update_calendar_event'; + cLog('Updating event with:' + hit); + const response = await axios.put(hit, saveData); + cLog('Event updated successfully:' + response.data); + } catch (error) { + console.error('Error updating event:', error); + } + }; + + let eventDate = event.event.event_date; + if (event.event.event_date != event.event.event_time) { + const dateTimeString = `${event.event.event_date}T${event.event.event_time}`; + eventDate = new Date(dateTimeString); + } + + if (eventDate) event.event['event_date'] = eventDate; + if (eventDate) event.event['event_time'] = eventDate; + if (event.event['repeat_timeline']) event.event['repeat_timeline'] = parseInt(event.event['repeat_timeline'], 10); + if (event.event['repeat_timeline'] !== undefined) event.event['repeating'] = event.event['repeat_timeline'] !== 0; + + return ( + + ); +} \ No newline at end of file diff --git a/app/viewEventPage.tsx b/app/viewEventPage.tsx new file mode 100644 index 0000000..a1c597f --- /dev/null +++ b/app/viewEventPage.tsx @@ -0,0 +1,175 @@ +import React, { useState } from 'react'; +import { View, TextInput, Text, TouchableOpacity, ScrollView } from 'react-native'; +import DateTimePicker from '@react-native-community/datetimepicker'; +import { Dropdown } from 'react-native-element-dropdown'; +import { styles } from './styles'; +import { RootStackParamList } from '@/components/Types'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { useNavigation } from '@react-navigation/native'; +import MultiSelect from 'react-native-multiple-select'; + +interface FormProps { + title: string; + initialData: any; + fields: Array<{ name: string; label: string; type: string; options?: any }>; + mainPage: keyof RootStackParamList; + onSave: (data: any) => void; +} + +const GenericViewPageForm: React.FC = ({ title, initialData, fields, mainPage, onSave }) => { + const [formData, setFormData] = useState(initialData); + const [showDatePicker, setShowDatePicker] = useState(false); + const [showTimePicker, setShowTimePicker] = useState(false); + const [currentField, setCurrentField] = useState(null); // Tracks which field is being edited + + type TrackerNavigationProp = StackNavigationProp; + const navigation = useNavigation(); + + const handleChange = (name: string, value: any) => { + setFormData({ ...formData, [name]: value }); + }; + + const handleDateChange = (name: string, selectedDate: any) => { + if (selectedDate) { + handleChange(name, selectedDate); + setShowDatePicker(false); + } + }; + + const handleTimeChange = (name: string, event: any, selectedTime: any) => { + if (event.type === 'dismissed') { + setShowTimePicker(false); + } else if (selectedTime) { + handleChange(name, selectedTime); + } + }; + + const handleSave = () => { + const formattedData = { + ...formData, + event_date: formData.event_date?.toISOString().split('T')[0], + event_time: formData.event_time?.toTimeString().split(' ')[0], + }; + onSave(formattedData); + navigation.navigate(mainPage as any); + }; + + const showPicker = (type: 'date' | 'time', fieldName: string) => { + setCurrentField(fieldName); + if (type === 'date') { + setShowDatePicker(true); + } else { + setShowTimePicker(true); + } + }; + + const handleIngredientChange = (selectedItems: string[]) => { + handleChange('ingredients', selectedItems); + }; + return ( + + {title} + + {fields.map((field, index) => ( + + + {field.label} + {field.type === 'text' && ( + handleChange(field.name, text)} + placeholder={field.label} + /> + )} + {field.type === 'date' && ( + + showPicker('date', field.name)}> + {formData[field.name] ? formData[field.name].toDateString() : 'Select Date'} + + {showDatePicker && ( + handleDateChange(currentField!, selectedDate)} + /> + )} + + )} + {field.type === 'multi-select' && ( + handleIngredientChange(selectedItems)} + selectText="Select Ingredients" + searchInputPlaceholderText="Search Ingredients..." + displayKey="label" + styleDropdownMenuSubsection={styles.dropdown} + /> + )} + {field.type === 'time' && ( + + showPicker('time', field.name)}> + {formData[field.name] ? formData[field.name].toLocaleTimeString() : 'Select Time'} + + {showTimePicker && ( + handleTimeChange(currentField!, event, selectedTime)} + /> + )} + + )} + {field.type === 'dropdown' && ( + handleChange(field.name, item.value)} + placeholder="Select" + /> + )} + + {field.type === 'textarea' && ( + handleChange(field.name, text)} + multiline + placeholder={field.label} + /> + )} + {field.type === 'number' && ( + handleChange(field.name, text)} + placeholder={field.label} + keyboardType="numeric" + /> + )} + + + ))} + + + + Save + + navigation.navigate(mainPage as any)}> + Cancel + + + + ); +}; + +export default GenericViewPageForm; \ No newline at end of file diff --git a/app/viewEvents.tsx b/app/viewEvents.tsx deleted file mode 100644 index 1ff1392..0000000 --- a/app/viewEvents.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import { getPageName, IPAddr, repeatingData } from './constants'; -import GenericAddPageForm from './addEventPage'; -import { cLog } from './log' -import { RouteProp, useFocusEffect, useRoute } from '@react-navigation/native'; -import { RootStackParamList } from '@/components/Types'; -import axios from 'axios'; - -type ViewEventsRouteProp = RouteProp; - -export default function ViewCalendarEvents() { - const [ingredients, setIngredients] = useState([]); - const route = useRoute(); - const { event } = route.params; - cLog(event); - const fields = [ - { name: 'title', label: 'Title', type: 'text' }, - { name: 'event_date', label: 'Date', type: 'date' }, - { name: 'event_time', label: 'Time', type: 'time' }, - { name: 'description', label: 'Description', type: 'textarea' }, - { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, - { name: 'money', label: 'Money', type: 'number' }, - { name: 'ingredients', label: 'Ingredients', type: 'multi-select' }, - ]; - - - cLog(fields); - const filteredFields = fields - .filter(field => field.name in event.event) // Keep only fields where name exists in data - .map(field => ({ ...field, value: event.event[field.name] })); // Attach value from data - - const orderedValues = Object.keys(event.event) - .filter(key => fields.some(field => field.name === key)) - .reduce((obj: { [key: string]: any }, key) => { - obj[key] = event.event[key]; - return obj; - }, {}); - - const dateTimeString = `${orderedValues.event_date}T${orderedValues.event_time}`; - const eventDate = new Date(dateTimeString); - - const fetchIngredients = async () => { - const hit = IPAddr + '/get_ingredients/13'; - cLog('Fetching ingredients from:' + hit); - axios.get(hit) - .then(response => { - const fetchedIngredients = response.data.map((item: any) => ({ - label: item.ingredientName, - value: item.id, - })); - setIngredients(fetchedIngredients); - }) - .catch(error => console.error('Error fetching ingredients:', error)); - }; - - useFocusEffect( - useCallback(() => { - fetchIngredients(); - }, []) - ); - - // Assign values only if they exist - if (eventDate) orderedValues['event_date'] = eventDate; - if (eventDate) orderedValues['event_time'] = eventDate; - if (orderedValues['repeat_timeline']) orderedValues['repeat_timeline'] = parseInt(orderedValues['repeat_timeline'], 10); - if (orderedValues['repeat_timeline'] !== undefined) orderedValues['repeating'] = orderedValues['repeat_timeline'] !== 0; - if (event?.event?.userId !== undefined) orderedValues['user_id'] = event.event.userId; - - if (event?.event?.ingredients) { - orderedValues['usedIngredients'] = event.event.ingredients.split(",").map(Number); // Convert string to array of numbers - } - - cLog("Ordered Values", orderedValues); - cLog("Filtered Fields", filteredFields); - const handleSave = async (saveData: any) => { - // try { - // // Format date and time before sending - // const payload = { - // ...saveData, - // repeating: Boolean(saveData.repeating), - // repeat_timeline: saveData.repeating - // }; - // cLog(payload); - // const hit = IPAddr + '/add_calendar_event'; - // cLog('Saving event to:' + hit); - // const response = await axios.post(hit, payload); - // cLog('Event saved successfully:' + response.data); - // } catch (error) { - // console.error('Error saving event:', error); - // } - cLog(saveData) - }; - - return ( - - ); -} diff --git a/app/viewFinanceEvents.tsx b/app/viewFinanceEvents.tsx new file mode 100644 index 0000000..d96207e --- /dev/null +++ b/app/viewFinanceEvents.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import axios from 'axios'; +import { IPAddr, repeatingData } from './constants'; +import { cLog } from './log' +import GenericViewPageForm from './viewEventPage'; +import { RouteProp, useRoute } from '@react-navigation/native'; +import { RootStackParamList } from '@/components/Types'; + +type ViewEventsRouteProp = RouteProp; + +export default function ViewFinanceEvents() { + const route = useRoute(); + const { event } = route.params; + cLog("Passed event:", event); + const fields = [ + { name: 'title', label: 'Title', type: 'text' }, + { name: 'event_date', label: 'Date', type: 'date' }, + { name: 'event_time', label: 'Time', type: 'time' }, + { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, + { name: 'money', label: 'Money', type: 'number' } + ]; + const handleSave = async (saveData: any) => { + try { + cLog("Save Data:", saveData); + const hit = IPAddr + '/update_finance_event'; + cLog('Updating event with:' + hit); + const response = await axios.put(hit, saveData); + cLog('Event updated successfully:' + response.data); + } catch (error) { + console.error('Error updating event:', error); + } + }; + + let eventDate = event.event.event_date; + if (event.event.event_date != event.event.event_time) { + const dateTimeString = `${event.event.event_date}T${event.event.event_time}`; + eventDate = new Date(dateTimeString); + } + + if (eventDate) event.event['event_date'] = eventDate; + if (eventDate) event.event['event_time'] = eventDate; + if (event.event['repeat_timeline']) event.event['repeat_timeline'] = parseInt(event.event['repeat_timeline'], 10); + if (event.event['repeat_timeline'] !== undefined) event.event['repeating'] = event.event['repeat_timeline'] !== 0; + + return ( + + ); +} \ No newline at end of file diff --git a/app/viewHealthEvents.tsx b/app/viewHealthEvents.tsx new file mode 100644 index 0000000..6da44e2 --- /dev/null +++ b/app/viewHealthEvents.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import axios from 'axios'; +import { IPAddr, repeatingData } from './constants'; +import { cLog } from './log' +import GenericViewPageForm from './viewEventPage'; +import { RouteProp, useRoute } from '@react-navigation/native'; +import { RootStackParamList } from '@/components/Types'; + +type ViewEventsRouteProp = RouteProp; + +export default function ViewHealthEvents() { + const route = useRoute(); + const { event } = route.params; + cLog("Passed event:", event); + const fields = [ + { name: 'title', label: 'Title', type: 'text' }, + { name: 'event_date', label: 'Date', type: 'date' }, + { name: 'event_time', label: 'Time', type: 'time' }, + { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, + ]; + const handleSave = async (saveData: any) => { + try { + cLog("Save Data:", saveData); + const hit = IPAddr + '/update_health_event'; + cLog('Updating event with:' + hit); + const response = await axios.put(hit, saveData); + cLog('Event updated successfully:' + response.data); + } catch (error) { + console.error('Error updating event:', error); + } + }; + + let eventDate = event.event.event_date; + if (event.event.event_date != event.event.event_time) { + const dateTimeString = `${event.event.event_date}T${event.event.event_time}`; + eventDate = new Date(dateTimeString); + } + + if (eventDate) event.event['event_date'] = eventDate; + if (eventDate) event.event['event_time'] = eventDate; + if (event.event['repeat_timeline']) event.event['repeat_timeline'] = parseInt(event.event['repeat_timeline'], 10); + if (event.event['repeat_timeline'] !== undefined) event.event['repeating'] = event.event['repeat_timeline'] !== 0; + + return ( + + ); +} \ No newline at end of file diff --git a/app/viewMealEvents.tsx b/app/viewMealEvents.tsx new file mode 100644 index 0000000..cb301a7 --- /dev/null +++ b/app/viewMealEvents.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; +import { IPAddr, repeatingData } from './constants'; +import { cLog } from './log' +import GenericViewPageForm from './viewEventPage'; +import { RouteProp, useRoute } from '@react-navigation/native'; +import { RootStackParamList } from '@/components/Types'; + +type ViewEventsRouteProp = RouteProp; + +export default function ViewMealEvents() { + const [allIngredients, setIngredients] = useState([]); + const route = useRoute(); + const { event } = route.params; + cLog("Passed event:", event); + const fields = [ + { name: 'title', label: 'Title', type: 'text' }, + { name: 'event_date', label: 'Date', type: 'date' }, + { name: 'event_time', label: 'Time', type: 'time' }, + { name: 'repeat_timeline', label: 'Repeating', type: 'dropdown', options: repeatingData }, + { name: 'ingredients', label: 'Ingredients', type: 'multi-select' }, + ]; + const handleSave = async (saveData: any) => { + try { + const payload = { + ...saveData, + ingredients: saveData.ingredients.join(','), + }; + cLog("Save Data:", payload); + const hit = IPAddr + '/update_meal_event'; + cLog('Updating event with:' + hit); + const response = await axios.put(hit, payload); + cLog('Event updated successfully:' + response.data); + } catch (error) { + console.error('Error updating event:', error); + } + }; + + const fetchIngredients = async () => { + try { + const response = await axios.get(IPAddr + '/get_ingredients/13'); + const fetchedIngredients = response.data.map((item: any) => ({ + label: item.ingredientName, + value: item.id, + })); + setIngredients(fetchedIngredients); // Update state with fetched ingredients + } catch (error) { + console.error('Error fetching ingredients:', error); + } + }; + + + useEffect(() => { + fetchIngredients(); + }, []); + + let eventDate = event.event.event_date; + if (event.event.event_date != event.event.event_time) { + const dateTimeString = `${event.event.event_date}T${event.event.event_time}`; + eventDate = new Date(dateTimeString); + } + cLog("Ingredients:", allIngredients); + if (event.event['ingredients'] && !Array.isArray(event.event['ingredients'])) event.event['ingredients'] = event.event['ingredients'].split(',').map((id: string) => parseInt(id, 10)); + if (eventDate) event.event['event_date'] = eventDate; + if (eventDate) event.event['event_time'] = eventDate; + if (event.event['repeat_timeline']) event.event['repeat_timeline'] = parseInt(event.event['repeat_timeline'], 10); + if (event.event['repeat_timeline'] !== undefined) event.event['repeating'] = event.event['repeat_timeline'] !== 0; + + return ( + + ); +} \ No newline at end of file diff --git a/backend/omniplanner.db b/backend/omniplanner.db index 2369c08..abb2ae8 100644 Binary files a/backend/omniplanner.db and b/backend/omniplanner.db differ diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEvents.java b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEvents.java index 871d732..7d86694 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEvents.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEvents.java @@ -43,8 +43,8 @@ public int getUserId() { return userId; } - public void setUserId(int user_id) { - this.userId = user_id; + public void setUserId(int userId) { + this.userId = userId; } public String getTitle() { diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsController.java b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsController.java index 1d106c2..2dae2a7 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsController.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsController.java @@ -3,6 +3,7 @@ import com.main.omniplanner.responses.CalendarEventResponse; import com.main.omniplanner.user.User; import com.main.omniplanner.user.UserRepository; +import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -59,4 +60,11 @@ public ResponseEntity getEventsByUserId(@PathVariable int return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } + + @Transactional + @PutMapping("/update_calendar_event") + public ResponseEntity updateEvent(@RequestBody CalendarEvents event) { + calendarEventsService.updateEvent(event); + return new ResponseEntity<>(event, HttpStatus.OK); + } } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsRepository.java b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsRepository.java index e6f61fc..05e91c9 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsRepository.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsRepository.java @@ -2,10 +2,13 @@ import com.main.omniplanner.finance.FinanceEvents; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.sql.Date; +import java.sql.Time; import java.util.List; @Repository @@ -13,4 +16,8 @@ public interface CalendarEventsRepository extends JpaRepository findByUserId(int userId); @Query("SELECT f FROM CalendarEvents f WHERE f.userId = :userId AND (f.repeating = true OR f.event_date >= :currentTimeMillis) ORDER BY f.event_date ASC") List findUpcomingByUserId(@Param("userId") int userId, @Param("currentTimeMillis") Long currentTimeMillis); + + @Modifying + @Query("UPDATE CalendarEvents f SET f.title = :title, f.event_date = :event_date, f.event_time = :event_time, f.repeating = :repeating, f.repeat_timeline = :repeat_timeline, f.description = :description WHERE f.id = :id" ) + void updateEvent(@Param("id") int id, @Param("title") String title, @Param("event_date") Date event_date, @Param("event_time") Time event_time, @Param("repeating") boolean repeating, @Param("repeat_timeline") String repeat_timeline, @Param("description") String description); } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsService.java b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsService.java index 1ff3b14..f7a1226 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsService.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/calendar/CalendarEventsService.java @@ -40,4 +40,8 @@ public List getEventsByUserId(int userId) { return calendarEventsRepository.findUpcomingByUserId(userId, currentTimeMillis); } + public void updateEvent(CalendarEvents event) { + calendarEventsRepository.updateEvent(event.getId(), event.getTitle(), event.getEvent_date(), event.getEvent_time(), event.isRepeating(), event.getRepeat_timeline(), event.getDescription()); + } + } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsController.java b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsController.java index 09a4af8..73c4f63 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsController.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsController.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -28,4 +29,11 @@ public ResponseEntity> getEventsByUserId(@PathVariable int u List events = financeEventsService.getEventsByUserId(userId); return ResponseEntity.ok(events); } + + @Transactional + @PutMapping("/update_finance_event") + public ResponseEntity updateEvent(@RequestBody FinanceEvents event) { + financeEventsService.updateEvent(event); + return new ResponseEntity<>(event, HttpStatus.OK); + } } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsRepository.java b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsRepository.java index 957dbc6..1abb7de 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsRepository.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsRepository.java @@ -1,10 +1,13 @@ package com.main.omniplanner.finance; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.sql.Date; +import java.sql.Time; import java.util.List; @Repository @@ -13,4 +16,7 @@ public interface FinanceEventsRepository extends JpaRepository= :currentTimeMillis) ORDER BY f.event_date ASC") List findUpcomingByUserId(@Param("userId") int userId, @Param("currentTimeMillis") Long currentTimeMillis); + @Modifying + @Query("UPDATE FinanceEvents f SET f.title = :title, f.event_date = :event_date, f.event_time = :event_time, f.repeating = :repeating, f.repeat_timeline = :repeat_timeline, f.money = :money WHERE f.id = :id" ) + void updateEvent(@Param("id") int id, @Param("title") String title, @Param("event_date") Date event_date, @Param("event_time") Time event_time, @Param("repeating") boolean repeating, @Param("repeat_timeline") String repeat_timeline, @Param("money") Double money); } \ No newline at end of file diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsService.java b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsService.java index 6871fcd..bc64e47 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsService.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/finance/FinanceEventsService.java @@ -40,4 +40,8 @@ public List getEventsByUserId(int userId) { return financeEventsRepository.findUpcomingByUserId(userId, currentTimeMillis); } + public void updateEvent(FinanceEvents event) { + financeEventsRepository.updateEvent(event.getId(), event.getTitle(), event.getEvent_date(), event.getEvent_time(), event.isRepeating(), event.getRepeat_timeline(), event.getMoney()); + } + } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEvents.java b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEvents.java index 0b5a031..ff65838 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEvents.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEvents.java @@ -41,8 +41,8 @@ public int getUserId() { return userId; } - public void setUserId(int user_id) { - this.userId = user_id; + public void setUserId(int userId) { + this.userId = userId; } public String getTitle() { diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsController.java b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsController.java index 6d1b479..ff30720 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsController.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsController.java @@ -1,8 +1,10 @@ package com.main.omniplanner.health; +import com.main.omniplanner.finance.FinanceEvents; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -28,4 +30,11 @@ public ResponseEntity> getEventsByUserId(@PathVariable int us List events = healthEventsService.getEventsByUserId(userId); return ResponseEntity.ok(events); } + + @Transactional + @PutMapping("/update_health_event") + public ResponseEntity updateEvent(@RequestBody HealthEvents event) { + healthEventsService.updateEvent(event); + return new ResponseEntity<>(event, HttpStatus.OK); + } } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsRepository.java b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsRepository.java index a0065de..f401860 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsRepository.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsRepository.java @@ -3,10 +3,13 @@ import com.main.omniplanner.calendar.CalendarEventsRepository; import com.main.omniplanner.finance.FinanceEvents; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.sql.Date; +import java.sql.Time; import java.util.List; @Repository @@ -14,4 +17,8 @@ public interface HealthEventsRepository extends JpaRepository findByUserId(int userId); @Query("SELECT f FROM HealthEvents f WHERE f.userId = :userId AND (f.repeating = true OR f.event_date >= :currentTimeMillis) ORDER BY f.event_date ASC") List findUpcomingByUserId(@Param("userId") int userId, @Param("currentTimeMillis") Long currentTimeMillis); + + @Modifying + @Query("UPDATE HealthEvents f SET f.title = :title, f.event_date = :event_date, f.event_time = :event_time, f.repeating = :repeating, f.repeat_timeline = :repeat_timeline WHERE f.id = :id" ) + void updateEvent(@Param("id") int id, @Param("title") String title, @Param("event_date") Date event_date, @Param("event_time") Time event_time, @Param("repeating") boolean repeating, @Param("repeat_timeline") String repeat_timeline); } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsService.java b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsService.java index 77ccc1f..6818832 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsService.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/health/HealthEventsService.java @@ -40,4 +40,8 @@ public List getEventsByUserId(int userId) { return healthEventsRepository.findUpcomingByUserId(userId, currentTimeMillis); } + public void updateEvent(HealthEvents event) { + healthEventsRepository.updateEvent(event.getId(), event.getTitle(), event.getEvent_date(), event.getEvent_time(), event.isRepeating(), event.getRepeat_timeline()); + } + } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsController.java b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsController.java index eadd8b1..c530b72 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsController.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsController.java @@ -1,6 +1,9 @@ package com.main.omniplanner.meals; import com.main.omniplanner.Ingredients.Ingredients; +import com.main.omniplanner.user.Event; +import com.main.omniplanner.user.EventService; +import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -30,4 +33,10 @@ public ResponseEntity> getEventsByUserId(@PathVariable int user return ResponseEntity.ok(events); } + @Transactional + @PutMapping("/update_meal_event") + public ResponseEntity updateEvent(@RequestBody MealEvents event) { + mealEventsService.updateEvent(event); + return new ResponseEntity<>(event, HttpStatus.OK); + } } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsRepository.java b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsRepository.java index 0ada79d..33be749 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsRepository.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsRepository.java @@ -2,10 +2,13 @@ import com.main.omniplanner.finance.FinanceEvents; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.sql.Date; +import java.sql.Time; import java.util.List; @Repository @@ -13,5 +16,9 @@ public interface MealEventsRepository extends JpaRepository List findByUserId(int userId); @Query("SELECT f FROM MealEvents f WHERE f.userId = :userId AND (f.repeating = true OR f.event_date >= :currentTimeMillis) ORDER BY f.event_date ASC") List findUpcomingByUserId(@Param("userId") int userId, @Param("currentTimeMillis") Long currentTimeMillis); + + @Modifying + @Query("UPDATE MealEvents f SET f.title = :title, f.event_date = :event_date, f.event_time = :event_time, f.repeating = :repeating, f.repeat_timeline = :repeat_timeline, f.ingredients = :ingredients WHERE f.id = :id" ) + void updateEvent(@Param("id") int id, @Param("title") String title, @Param("event_date") Date event_date, @Param("event_time") Time event_time, @Param("repeating") boolean repeating, @Param("repeat_timeline") String repeat_timeline, @Param("ingredients") String ingredients); } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsService.java b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsService.java index 6940d56..c3bb878 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsService.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/meals/MealEventsService.java @@ -43,4 +43,8 @@ public List getEventsByUserId(int userId) { return mealEventsRepository.findUpcomingByUserId(userId, currentTimeMillis); } + public void updateEvent(MealEvents event) { + mealEventsRepository.updateEvent(event.getId(), event.getTitle(), event.getEvent_date(), event.getEvent_time(), event.isRepeating(), event.getRepeat_timeline(), event.getIngredients()); + } + } diff --git a/backend/omniplanner/src/main/java/com/main/omniplanner/user/Event.java b/backend/omniplanner/src/main/java/com/main/omniplanner/user/Event.java index 543e310..ffcc55f 100644 --- a/backend/omniplanner/src/main/java/com/main/omniplanner/user/Event.java +++ b/backend/omniplanner/src/main/java/com/main/omniplanner/user/Event.java @@ -43,7 +43,7 @@ public void setDescription(String description) { @Column(name = "title", length = 255) private String title; - @Column(name = "user_id") + @Column(name = "userId") private int userId; @Column(name = "ingredients") diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsControllerTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsControllerTest.java index b1df314..38917c5 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsControllerTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsControllerTest.java @@ -147,4 +147,23 @@ void testAddEvent_Success() { assertEquals("New Event", response.getBody().getTitle()); } + @Test + void updateEvent_Success() { + // Given + CalendarEvents event = new CalendarEvents(); + event.setId(1); + event.setUserId(1); + event.setTitle("New Event"); + event.setEvent_date(Date.valueOf("2023-10-10")); + event.setEvent_time(Time.valueOf("14:00:00")); + + ResponseEntity response = calendarEventsController.updateEvent(event); + + // Then + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); + assertEquals("New Event", response.getBody().getTitle()); + } + + } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsServiceTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsServiceTest.java index 9b50626..5ffe509 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsServiceTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/CalendarTests/CalendarEventsServiceTest.java @@ -68,4 +68,10 @@ public void testGetSaveEvent() { verify(calendarEventsRepository).save(calendarEvents); verify(calendarEventsRepository).findUpcomingByUserId(eq(0), anyLong()); } + + @Test + public void testUpdateEvent() { + calendarEventsService.updateEvent(calendarEvents); + verify(calendarEventsRepository).updateEvent(0, "Team Meeting", date, time, true, "weekly", "Meeting"); + } } \ No newline at end of file diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsControllerTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsControllerTest.java index d7d6a21..01855ee 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsControllerTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsControllerTest.java @@ -119,4 +119,13 @@ void testAddEvent_Success() { assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); assertEquals("Event 1", response.getBody().getTitle()); } + + @Test + void testUpdateEvent_Success() { + ResponseEntity response = financeEventsController.updateEvent(event1); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); + assertEquals("Event 1", response.getBody().getTitle()); + } } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsServiceTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsServiceTest.java index 6bcc57d..8631f8f 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsServiceTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/FinanceTests/FinanceEventsServiceTest.java @@ -69,4 +69,10 @@ public void testGetSaveEvent() { verify(financeEventsRepository).save(financeEvents); verify(financeEventsRepository).findUpcomingByUserId(eq(0), anyLong()); } + + @Test + public void testUpdateEvent() { + financeEventsService.updateEvent(financeEvents); + verify(financeEventsRepository).updateEvent(eq(0), eq("Team Meeting"), eq(date), eq(time), eq(true), eq("weekly"), eq(9.99)); + } } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsControllerTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsControllerTest.java index 7226452..cb69186 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsControllerTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsControllerTest.java @@ -106,4 +106,13 @@ void testAddEvent_Success() { assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); assertEquals("Event 1", response.getBody().getTitle()); } + + @Test + void testUpdateEvent_Success() { + ResponseEntity response = healthEventsController.updateEvent(event1); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); + assertEquals("Event 1", response.getBody().getTitle()); + } } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsServiceTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsServiceTest.java index 92366f1..6db862c 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsServiceTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/HealthTests/HealthEventsServiceTest.java @@ -67,4 +67,10 @@ public void testGetSaveEvent() { verify(healthEventsRepository).save(healthEvents); verify(healthEventsRepository).findUpcomingByUserId(eq(0), anyLong()); } + + @Test + public void testUpdateEvent() { + healthEventsService.updateEvent(healthEvents); + verify(healthEventsRepository).updateEvent(eq(0), eq("Team Meeting"), eq(date), eq(time), eq(true), eq("weekly")); + } } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsControllerTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsControllerTest.java index 0410c6f..acd7cc0 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsControllerTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsControllerTest.java @@ -99,4 +99,13 @@ void testAddEvent_Success() { assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); assertEquals("Event 1", response.getBody().getTitle()); } + + @Test + void testUpdateEvent_Success() { + ResponseEntity response = mealEventsController.updateEvent(event1); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(1, Objects.requireNonNull(response.getBody()).getId()); + assertEquals("Event 1", response.getBody().getTitle()); + } } diff --git a/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsServiceTest.java b/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsServiceTest.java index 4a93a2e..7b4a883 100644 --- a/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsServiceTest.java +++ b/backend/omniplanner/src/test/java/com/main/omniplanner/MealTests/MealEventsServiceTest.java @@ -64,4 +64,10 @@ public void testGetSaveEvent() { verify(mealEventsRepository).save(mealEvents); verify(mealEventsRepository).findUpcomingByUserId(eq(0), anyLong()); } + + @Test + public void testUpdateEvent() { + mealEventsService.updateEvent(mealEvents); + verify(mealEventsRepository).updateEvent(eq(0), eq("Team Meeting"), eq(date), eq(time), eq(false), isNull(), isNull()); + } } diff --git a/components/Types.tsx b/components/Types.tsx index 74ce477..6e9b91a 100644 --- a/components/Types.tsx +++ b/components/Types.tsx @@ -19,7 +19,10 @@ export type RootStackParamList = { 'addCalendarEvents': undefined; 'addHealthEvents': undefined; 'addMeals': undefined; - 'viewEvents': { event: any }; + 'viewFinanceEvents': { event: Task }; + 'viewHealthEvents': { event: Task }; + 'viewMealEvents': { event: Task }; + 'viewCalendarEvents': { event: Task }; };