// GET /api/tasks/upcoming — Today's tasks per user, grouped by period #include "cJSON.h" #include "esp_http_server.h" #include "todo.hpp" #include "types.hpp" internal esp_err_t api_tasks_upcoming_handler(httpd_req_t *req) { httpd_resp_set_type(req, "application/json"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); cJSON *root = cJSON_CreateObject(); cJSON *users_arr = cJSON_AddArrayToObject(root, "users"); for (int u = 0; u < MAX_USERS; u++) { if (!g_Users[u].active) continue; // Collect incomplete tasks for this user // Include: recurring tasks (any day) and one-off tasks cJSON *user_obj = cJSON_CreateObject(); cJSON_AddNumberToObject(user_obj, "id", g_Users[u].id); cJSON_AddStringToObject(user_obj, "name", g_Users[u].name); cJSON *tasks_arr = cJSON_AddArrayToObject(user_obj, "tasks"); for (int t = 0; t < MAX_TASKS; t++) { if (!g_Tasks[t].active || g_Tasks[t].completed || g_Tasks[t].user_id != g_Users[u].id) continue; cJSON *t_obj = cJSON_CreateObject(); cJSON_AddNumberToObject(t_obj, "id", g_Tasks[t].id); cJSON_AddStringToObject(t_obj, "title", g_Tasks[t].title); cJSON_AddNumberToObject(t_obj, "due_date", (double)g_Tasks[t].due_date); cJSON_AddNumberToObject(t_obj, "period", g_Tasks[t].period); cJSON_AddNumberToObject(t_obj, "recurrence", g_Tasks[t].recurrence); cJSON_AddBoolToObject(t_obj, "completed", g_Tasks[t].completed); cJSON_AddItemToArray(tasks_arr, t_obj); } cJSON_AddItemToArray(users_arr, user_obj); } const char *json = cJSON_PrintUnformatted(root); httpd_resp_sendstr(req, json); free((void *)json); cJSON_Delete(root); return ESP_OK; } internal const httpd_uri_t api_tasks_upcoming_uri = { .uri = "/api/tasks/upcoming", .method = HTTP_GET, .handler = api_tasks_upcoming_handler, .user_ctx = NULL};