-
Notifications
You must be signed in to change notification settings - Fork 2
Scheduler Tasks Backend Integration #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
483252f
372f9ff
4e0faf6
3d94c8a
7e1a110
11fb1ab
c458f09
3514352
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| import { Request, Response, Router } from "express"; | ||
| import { | ||
| addAssignment, | ||
| addEvent, | ||
| addFeedback, | ||
| addTask, | ||
|
|
@@ -10,10 +9,10 @@ import { | |
| queryItems, | ||
| } from "../cosmos"; | ||
| import { | ||
| Assignment, | ||
| Event, | ||
| Feedback, | ||
| Task, | ||
| TaskCategory, | ||
| } from "../../../rise-dc-app/src/shared/types"; | ||
|
|
||
| const SCHEDULING_DB = process.env.COSMOS_SCHEDULING_DB || "Scheduling"; | ||
|
|
@@ -88,17 +87,20 @@ schedulerRouter.delete("/tasks/:id", async (req: Request, res: Response) => { | |
| } | ||
| }); | ||
|
|
||
| // TODO: Fix this! | ||
| schedulerRouter.post("/events", async (req: Request, res: Response) => { | ||
| try { | ||
| const { name, icon, tasks, image, complete } = req.body; | ||
| const { userId, name, icon, steps, image, startTime, endTime, category, complete } = req.body; | ||
| const event: Event = { | ||
| id: `event_${Date.now()}`, | ||
| userId: userId || "", | ||
| name, | ||
| icon: icon || "", | ||
| complete: complete || false, | ||
| tasks: tasks || [], | ||
| steps: steps || [], | ||
| image: image || { id: "", caption: "" }, | ||
| startTime: startTime || { hour: 0, minute: 0, period: "AM" }, | ||
| endTime: endTime || { hour: 0, minute: 0, period: "AM" }, | ||
| category: (category as TaskCategory) || TaskCategory.Misc, | ||
| }; | ||
| const createdEvent = await addEvent(event); | ||
| return res.status(201).json(createdEvent); | ||
|
|
@@ -118,54 +120,14 @@ schedulerRouter.get("/events", async (_, res: Response) => { | |
| } | ||
| }); | ||
|
|
||
| // ===== ASSIGNMENTS ===== | ||
| schedulerRouter.post("/assignments", async (req: Request, res: Response) => { | ||
| try { | ||
| const { complete, date, startTime, endTime, event } = req.body; | ||
| const assignment: Assignment = { | ||
| id: `assignment_${Date.now()}`, | ||
| complete: complete || false, | ||
| date, | ||
| startTime, | ||
| endTime, | ||
| event, | ||
| }; | ||
| const createdAssignment = await addAssignment(assignment); | ||
| return res.status(201).json(createdAssignment); | ||
| } catch (error) { | ||
| console.error(error); | ||
| return res.status(500).json({ error: "Failed to create assignment" }); | ||
| } | ||
| }); | ||
|
|
||
| schedulerRouter.get("/assignments", async (req: Request, res: Response) => { | ||
| try { | ||
| const { date } = req.query; | ||
| let assignments: Assignment[]; | ||
| if (date) { | ||
| assignments = await queryItems<Assignment>( | ||
| SCHEDULING_DB, | ||
| "Assignments", | ||
| "SELECT * FROM c WHERE c.date = @date", | ||
| [{ name: "@date", value: date as string }], | ||
| ); | ||
| } else { | ||
| assignments = await getAllItems<Assignment>(SCHEDULING_DB, "Assignments"); | ||
| } | ||
| return res.json(assignments); | ||
| } catch (error) { | ||
| console.error(error); | ||
| return res.status(500).json({ error: "Failed to fetch assignments" }); | ||
| } | ||
| }); | ||
|
|
||
| // ===== FEEDBACK ===== | ||
| schedulerRouter.post("/feedback", async (req: Request, res: Response) => { | ||
| try { | ||
| const { taskAssignmentId, taskId, reaction } = req.body; | ||
| const { taskId, reaction } = req.body; | ||
| const feedback: Feedback = { | ||
| id: `feedback_${Date.now()}`, | ||
| taskAssignmentId, | ||
| taskAssignmentId: "", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's look at the scheduler.ts file around line 130
cat -n backend/src/routes/scheduler.ts | sed -n '115,145p'Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1057 🏁 Script executed: # Search for Feedback interface definition
fd -t f . | xargs rg -l 'interface Feedback'Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 228 🏁 Script executed: # Search for taskAssignmentId usage patterns throughout the codebase
rg -n 'taskAssignmentId' --type=ts -C 2Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1080
The Either extract 🤖 Prompt for AI Agents |
||
| taskId, | ||
| reaction, | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,17 @@ | ||
| import { StrictMode } from "react"; | ||
| import { createRoot } from "react-dom/client"; | ||
| import { QueryClientProvider } from "@tanstack/react-query"; | ||
| import { queryClient } from "./shared/constants/query"; | ||
| import "./index.css"; | ||
| import App from "./App"; | ||
| import { FavoritesProvider } from "./shared/state/FavoritesContext"; | ||
|
|
||
| createRoot(document.getElementById("root")).render( | ||
| <StrictMode> | ||
| <FavoritesProvider> | ||
| <App /> | ||
| </FavoritesProvider> | ||
| </StrictMode>, | ||
| <QueryClientProvider client={queryClient}> | ||
| <FavoritesProvider> | ||
| <App /> | ||
| </FavoritesProvider> | ||
| </QueryClientProvider> | ||
| </StrictMode> | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,10 @@ | ||
| import React, { useState } from "react"; | ||
| import "./EventSelectionModal.css"; | ||
| import back from "./icon_components/back.png"; | ||
|
|
||
| interface TimeSlot { | ||
| hour: number; | ||
| minute: number; | ||
| period: "AM" | "PM"; | ||
| } | ||
| import { useCreateTask } from "../hooks/useTask"; | ||
| import { useQueryClient } from "@tanstack/react-query"; | ||
| import { TaskPayload } from "../services/taskService"; | ||
| import { TaskCategory, TimeSlot } from "../shared/types"; | ||
|
|
||
| interface TimeSelectionModalProps { | ||
| isOpen: boolean; | ||
|
|
@@ -23,6 +21,8 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| selectedEvent = "Sweep floor", | ||
| onTimeConfirmed, | ||
| }) => { | ||
| const queryClient = useQueryClient(); | ||
| const createTaskMutation = useCreateTask(); | ||
| const [currentStep, setCurrentStep] = | ||
| useState<TimeSelectionStep>("START_TIME"); | ||
| const [startTime, setStartTime] = useState<TimeSlot>({ | ||
|
|
@@ -41,7 +41,7 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| const updateTime = ( | ||
| timeType: "start" | "end", | ||
| field: "hour" | "minute", | ||
| increment: boolean, | ||
| increment: boolean | ||
| ) => { | ||
| const currentTime = timeType === "start" ? startTime : endTime; | ||
| const setTime = timeType === "start" ? setStartTime : setEndTime; | ||
|
|
@@ -64,7 +64,7 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| const updateTimeDirect = ( | ||
| timeType: "start" | "end", | ||
| field: "hour" | "minute", | ||
| value: number, | ||
| value: number | ||
| ) => { | ||
| const setTime = timeType === "start" ? setStartTime : setEndTime; | ||
| const currentTime = timeType === "start" ? startTime : endTime; | ||
|
|
@@ -100,9 +100,34 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| }; | ||
|
|
||
| const handleFinish = () => { | ||
| onTimeConfirmed?.(startTime, endTime); | ||
| setCurrentStep("START_TIME"); | ||
| onClose(); | ||
| // TODO: Get specific userId, icon, and category | ||
| const taskPayload: TaskPayload = { | ||
| userId: "", | ||
| name: selectedEvent, | ||
| icon: "", | ||
| startTime: startTime, | ||
| endTime: endTime, | ||
| category: TaskCategory.Misc, | ||
| }; | ||
|
Comment on lines
102
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's understand the repository structure
git ls-files | head -20Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 228 🏁 Script executed: # Look for backend directory structure
fd -type d -name backend | head -10Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 256 🏁 Script executed: # Search for Task/Event model definitions and validation
rg -n "userId.*required|userId.*validation|interface Task|type Task" --type ts --type js -A 3Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1927 🏁 Script executed: # Check for scheduler route handlers
fd -type f -name "*scheduler*" | grep -E "\.(ts|js)$"Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 256 🏁 Script executed: # Get full TaskPayload definition and surrounding context
cat -n rise-dc-app/src/services/taskService.ts | head -50Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1209 🏁 Script executed: # Search for createTask mutation and how it's used
rg -n "createTask|useCreateTask" rise-dc-app/src --type ts --type tsx -B 2 -A 5Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 113 🏁 Script executed: # Look for any validation logic in task-related files
rg -n "userId.*empty|validate|required" rise-dc-app/src -B 2 -A 2Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1997 🏁 Script executed: # Check if there's a backend directory anywhere
find . -maxdepth 3 -type d -name "*backend*" -o -name "*server*" -o -name "*api*" 2>/dev/null | grep -v node_modulesRepository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 119 🏁 Script executed: # Explore backend structure
ls -la backend/Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 578 🏁 Script executed: # Look for Task model/schema and validation
fd . backend -type f \( -name "*task*" -o -name "*model*" -o -name "*schema*" \) | head -20Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 256 🏁 Script executed: # Search for the /api/scheduler/tasks endpoint handler
rg -n "scheduler/tasks|TaskPayload|userId" backend/ -B 2 -A 5Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 2905 🏁 Script executed: # Check for validation middleware or rules
rg -n "validate|required|empty" backend/ -i | head -30Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 68 🏁 Script executed: # Check how tasks are retrieved/filtered
rg -n "listTasks|GET.*tasks|userId" backend/src/routes/scheduler.ts -B 2 -A 5Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 916 Empty The backend's POST Either retrieve the actual |
||
|
|
||
| createTaskMutation.mutate(taskPayload, { | ||
| onSuccess: (data) => { | ||
| console.log("Task created successfully:", data); | ||
|
|
||
| // Reset and close the modal | ||
| onTimeConfirmed?.(startTime, endTime); | ||
| setCurrentStep("START_TIME"); | ||
| onClose(); | ||
| }, | ||
| onError: (error) => { | ||
| console.error("Failed to create task:", error); | ||
| alert("Failed to create task. Please try again."); | ||
| }, | ||
| onSettled: () => { | ||
| // Refresh the tasks list | ||
| queryClient.invalidateQueries({ queryKey: ["tasks"] }); | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| const handleClose = () => { | ||
|
|
@@ -115,7 +140,7 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| time: TimeSlot, | ||
| isActive: boolean, | ||
| label: string, | ||
| icon: string = "🕐", | ||
| icon: string = "🕐" | ||
| ) => ( | ||
| <div | ||
| className={`time-selector ${isActive ? "active" : "disabled"} ${timeType}-time-selector`} | ||
|
|
@@ -237,13 +262,13 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| "start", | ||
| startTime, | ||
| currentStep === "START_TIME", | ||
| "Start time", | ||
| "Start time" | ||
| )} | ||
| {renderTimeSelector( | ||
| "end", | ||
| endTime, | ||
| currentStep === "END_TIME", | ||
| "End time", | ||
| "End time" | ||
| )} | ||
| </div> | ||
|
|
||
|
|
@@ -253,8 +278,11 @@ const TimeSelectionModal: React.FC<TimeSelectionModalProps> = ({ | |
| <button | ||
| className="finish-adding-task-button" | ||
| onClick={handleFinish} | ||
| disabled={createTaskMutation.isPending} | ||
| > | ||
| Finish Adding Task | ||
| {createTaskMutation.isPending | ||
| ? "Creating Task..." | ||
| : "Finish Adding Task"} | ||
| </button> | ||
| ) : ( | ||
| <> | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,31 +1,31 @@ | ||||||
| import { TaskCategory } from "../scheduling_components/quiet_hobbies/types"; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify TaskCategory definitions and usages across the codebase
echo "=== TaskCategory in quiet_hobbies/types.ts ==="
find rise-dc-app -name "quiet_hobbies" -type d 2>/dev/null | head -1
rg -n "TaskCategory" rise-dc-app/src/scheduling_components/quiet_hobbies/types.ts 2>/dev/null || echo "File not found or no matches"
echo -e "\n=== TaskCategory in shared/types ==="
find rise-dc-app/src/shared/types -type f -name "*.ts" 2>/dev/null | head -5
rg -n "TaskCategory" rise-dc-app/src/shared/types/ 2>/dev/null || echo "No matches in shared/types"
echo -e "\n=== All TaskCategory imports ==="
rg -n "import.*TaskCategory" rise-dc-app/src/ 2>/dev/null || echo "No imports found"
echo -e "\n=== Repository structure check ==="
ls -la rise-dc-app/src/ 2>/dev/null | head -20Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1666 🏁 Script executed: #!/bin/bash
echo "=== quiet_hobbies/types.ts - TaskCategory definition ==="
sed -n '30,40p' rise-dc-app/src/scheduling_components/quiet_hobbies/types.ts
echo -e "\n=== shared/types/index.ts - TaskCategory definition ==="
sed -n '105,120p' rise-dc-app/src/shared/types/index.ts
echo -e "\n=== Full context in quiet_hobbies/types.ts (lines 25-45) ==="
sed -n '25,45p' rise-dc-app/src/scheduling_components/quiet_hobbies/types.ts
echo -e "\n=== Full context in shared/types/index.ts (lines 100-125) ==="
sed -n '100,125p' rise-dc-app/src/shared/types/index.tsRepository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1671 🏁 Script executed: #!/bin/bash
echo "=== taskService.ts full content ==="
cat -n rise-dc-app/src/services/taskService.ts
echo -e "\n=== Check where taskService functions are called ==="
rg -n "taskService\|from.*taskService" rise-dc-app/src/ -A 2 | head -40Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 1299 🏁 Script executed: #!/bin/bash
echo "=== Task interface in shared/types ==="
rg -n "export interface Task" rise-dc-app/src/shared/types/index.ts -A 10Repository: Hack4Impact-UMD/microsoft-hackathon-fall25 Length of output: 355 Fix TaskCategory import to use shared/types enum consistently.
Update the import to use the -import { TaskCategory } from "../scheduling_components/quiet_hobbies/types";
+import { TaskCategory } from "../shared/types";📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| import { Image, Task } from "../shared/types"; | ||||||
| import { Image, Task, TimeSlot } from "../shared/types"; | ||||||
| import { delJSON, getJSON, postJSON } from "./service"; | ||||||
|
|
||||||
| export interface TaskPayload { | ||||||
| userId: string; | ||||||
| icon: string; | ||||||
| name: string; | ||||||
| image?: Image; | ||||||
| startTime: string; | ||||||
| endTime: string; | ||||||
| startTime: TimeSlot; | ||||||
| endTime: TimeSlot; | ||||||
| category: TaskCategory; | ||||||
| } | ||||||
|
|
||||||
| export async function createTask(payload: TaskPayload): Promise<Task> { | ||||||
| return postJSON<Task, TaskPayload>("/api/tasks", payload); | ||||||
| return postJSON<Task, TaskPayload>("/api/scheduler/tasks", payload); | ||||||
| } | ||||||
|
|
||||||
| export async function getTask(id: string): Promise<Task> { | ||||||
| return getJSON<Task>(`/api/tasks/${id}`); | ||||||
| return getJSON<Task>(`/api/scheduler/tasks/${id}`); | ||||||
| } | ||||||
|
|
||||||
| export async function listTasks(): Promise<Task[]> { | ||||||
| return getJSON<Task[]>("/api/tasks"); | ||||||
| return getJSON<Task[]>("/api/scheduler/tasks"); | ||||||
| } | ||||||
|
|
||||||
| export async function deleteTask( | ||||||
| id: string, | ||||||
| ): Promise<{ message: string; id: string }> { | ||||||
| return delJSON<{ message: string; id: string }>(`/api/tasks/${id}`); | ||||||
| return delJSON<{ message: string; id: string }>(`/api/scheduler/tasks/${id}`); | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider requiring
userIdinstead of defaulting to empty string.Defaulting
userIdto an empty string could complicate user-based filtering, ownership tracking, and access control. If events must be associated with a user, validate thatuserIdis provided and return a 400 error if missing.Apply this diff to require userId:
Then add validation before creating the event:
🤖 Prompt for AI Agents