Emmanuel Frimpong Asante commited on
Commit
ebe0f8b
·
1 Parent(s): 781898e

update space

Browse files
Files changed (36) hide show
  1. .env +1 -0
  2. .idea/workspace.xml +10 -13
  3. README.md +29 -7
  4. backend/app/middleware/auth_middleware.py +1 -0
  5. backend/app/models/inventory_item.py +1 -0
  6. backend/app/routes/auth.py +3 -0
  7. backend/app/routes/chat.py +1 -0
  8. backend/app/routes/dashboard.py +0 -1
  9. backend/app/routes/farm.py +5 -4
  10. backend/app/routes/health.py +8 -5
  11. backend/app/routes/inventory.py +3 -2
  12. backend/app/routes/pages.py +10 -6
  13. backend/app/routes/task.py +1 -0
  14. backend/app/schemas/chat_history_schema.py +4 -1
  15. backend/app/schemas/inventory_item_schema.py +4 -2
  16. backend/app/schemas/user_schema.py +3 -1
  17. backend/app/services/disease_detection.py +0 -2
  18. backend/app/services/llama_service.py +2 -1
  19. backend/app/static/js/group.js +5 -5
  20. backend/app/static/js/health.js +3 -3
  21. backend/app/static/js/inventory.js +5 -6
  22. backend/app/static/js/tasks.js +2 -3
  23. backend/app/templates/auth/register.html +32 -27
  24. backend/app/templates/chat/index.html +259 -259
  25. backend/app/templates/dashboard.html +76 -76
  26. backend/app/templates/group/manage_group.html +44 -41
  27. backend/app/templates/health/log_health.html +27 -25
  28. backend/app/templates/health/manage_health.html +49 -47
  29. backend/app/templates/inventory/add_inventory.html +46 -46
  30. backend/app/templates/inventory/view_inventory.html +65 -62
  31. backend/app/templates/landing.html +4 -2
  32. backend/app/templates/main/base.html +16 -7
  33. backend/app/templates/main/partials/sidebar.html +22 -15
  34. backend/app/templates/todo/add_task.html +47 -47
  35. backend/app/templates/todo/manage_tasks.html +71 -69
  36. test_main.http +4 -1
.env CHANGED
@@ -14,6 +14,7 @@ EMAIL_PASSWORD=your-email-password
14
  EMAIL_FROM_NAME="Poultry Management System"
15
  EMAIL_RECEIVER="default-receiver@example.com" # default receiver for general notifications
16
 
 
17
 
18
  # TensorFlow Settings
19
  TF_ENABLE_ONEDNN_OPTS=0
 
14
  EMAIL_FROM_NAME="Poultry Management System"
15
  EMAIL_RECEIVER="default-receiver@example.com" # default receiver for general notifications
16
 
17
+ JWT_SECRET_KEY="mypass"
18
 
19
  # TensorFlow Settings
20
  TF_ENABLE_ONEDNN_OPTS=0
.idea/workspace.xml CHANGED
@@ -4,10 +4,7 @@
4
  <option name="autoReloadType" value="SELECTIVE" />
5
  </component>
6
  <component name="ChangeListManager">
7
- <list default="true" id="27c9ae1a-a6fa-4472-8bcd-a7087620894b" name="Changes" comment="update space">
8
- <change beforePath="$PROJECT_DIR$/.env" beforeDir="false" afterPath="$PROJECT_DIR$/.env" afterDir="false" />
9
- <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
10
- </list>
11
  <option name="SHOW_DIALOG" value="false" />
12
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
13
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -128,14 +125,6 @@
128
  <workItem from="1730454506390" duration="12672000" />
129
  <workItem from="1730494385249" duration="17097000" />
130
  </task>
131
- <task id="LOCAL-00103" summary="update space">
132
- <option name="closed" value="true" />
133
- <created>1730470756352</created>
134
- <option name="number" value="00103" />
135
- <option name="presentableId" value="LOCAL-00103" />
136
- <option name="project" value="LOCAL" />
137
- <updated>1730470756352</updated>
138
- </task>
139
  <task id="LOCAL-00104" summary="update space">
140
  <option name="closed" value="true" />
141
  <created>1730471112648</created>
@@ -520,7 +509,15 @@
520
  <option name="project" value="LOCAL" />
521
  <updated>1731736727627</updated>
522
  </task>
523
- <option name="localTasksCounter" value="152" />
 
 
 
 
 
 
 
 
524
  <servers />
525
  </component>
526
  <component name="TypeScriptGeneratedFilesManager">
 
4
  <option name="autoReloadType" value="SELECTIVE" />
5
  </component>
6
  <component name="ChangeListManager">
7
+ <list default="true" id="27c9ae1a-a6fa-4472-8bcd-a7087620894b" name="Changes" comment="update space" />
 
 
 
8
  <option name="SHOW_DIALOG" value="false" />
9
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
10
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
 
125
  <workItem from="1730454506390" duration="12672000" />
126
  <workItem from="1730494385249" duration="17097000" />
127
  </task>
 
 
 
 
 
 
 
 
128
  <task id="LOCAL-00104" summary="update space">
129
  <option name="closed" value="true" />
130
  <created>1730471112648</created>
 
509
  <option name="project" value="LOCAL" />
510
  <updated>1731736727627</updated>
511
  </task>
512
+ <task id="LOCAL-00152" summary="update space">
513
+ <option name="closed" value="true" />
514
+ <created>1731737347454</created>
515
+ <option name="number" value="00152" />
516
+ <option name="presentableId" value="LOCAL-00152" />
517
+ <option name="project" value="LOCAL" />
518
+ <updated>1731737347454</updated>
519
+ </task>
520
+ <option name="localTasksCounter" value="153" />
521
  <servers />
522
  </component>
523
  <component name="TypeScriptGeneratedFilesManager">
README.md CHANGED
@@ -14,11 +14,16 @@ Here’s the updated `README.md` with an improved structure and updated to-do li
14
 
15
  # 🐔 Poultry Farming Assistance and Management System
16
 
17
- This project combines a **Poultry Farming Assistance System** and a **Poultry Management System**, streamlining health monitoring, task management, inventory tracking, and disease detection using AI. Designed for farmers and farm admins, this system enables effective poultry health management, provides real-time alerts, and generates actionable insights to enhance productivity.
 
 
 
18
 
19
  ## Key Features
 
20
  1. **User Authentication and Role-Based Access**: Secure registration and login for farmers and admins.
21
- 2. **Health Management with AI-Driven Disease Detection**: Fecal image analysis for common poultry diseases and personalized treatment recommendations.
 
22
  3. **To-Do List and Task Management**: Track daily farm tasks and share across groups.
23
  4. **Inventory Management**: Monitor feed, medication, and supply levels with automated alerts.
24
  5. **Data Logging and Reporting**: Real-time dashboards, export options, and health reports.
@@ -29,11 +34,14 @@ This project combines a **Poultry Farming Assistance System** and a **Poultry Ma
29
  ## System Overview
30
 
31
  ### Poultry Farming Assistance System
32
- - **AI-Powered Disease Detection**: Uses pre-trained models (e.g., `Final_Chicken_disease_model.h5`) to analyze fecal images and identify poultry diseases.
 
 
33
  - **Health Monitoring**: Tracks metrics such as weight loss, mortality rate, and feed intake for proactive care.
34
  - **Treatment Recommendations**: Offers tailored suggestions based on detected health issues.
35
 
36
  ### Poultry Management System
 
37
  - **Task and To-Do List Management**: Allows farm admins to assign tasks and track completion across groups.
38
  - **Inventory Tracking**: Manages inventory levels and provides alerts for low-stock items.
39
  - **Health Records**: Logs poultry health data and tracks disease outbreaks.
@@ -42,6 +50,7 @@ This project combines a **Poultry Farming Assistance System** and a **Poultry Ma
42
  ---
43
 
44
  ## Use Cases
 
45
  - **Farmers**: Access disease detection, complete tasks, view health records, and receive alerts.
46
  - **Admins**: Create tasks, monitor group activities, manage inventory, and ensure flock health.
47
 
@@ -50,16 +59,20 @@ This project combines a **Poultry Farming Assistance System** and a **Poultry Ma
50
  ## 📝 To-Do List
51
 
52
  ### 1. Setup and Configuration
53
- - [x] Set up a virtual environment and install required packages (`FastAPI`, `TensorFlow`, `MongoDB`, `transformers`, etc.).
 
 
54
  - [x] Configure MongoDB and test CRUD operations.
55
  - [x] Establish environment variables for MongoDB, email credentials, and Hugging Face API token.
56
 
57
  ### 2. Authentication System
 
58
  - [x] Develop user registration for farmers and admins.
59
  - [x] Implement login/logout with JWT.
60
  - [x] Set up password encryption (`bcrypt`) for secure storage.
61
 
62
  ### 3. Poultry Farming Assistance System
 
63
  - [x] Integrate the poultry disease detection model (`Final_Chicken_disease_model.h5`).
64
  - [x] Set up image preprocessing for disease detection.
65
  - [x] Build endpoints for image upload and disease analysis.
@@ -67,48 +80,56 @@ This project combines a **Poultry Farming Assistance System** and a **Poultry Ma
67
  - [x] Implement real-time health monitoring and alerts.
68
 
69
  ### 4. To-Do List Management
 
70
  - [x] Design MongoDB schema for to-do lists.
71
  - [x] Create routes for farmers to view and mark to-do items.
72
  - [x] Build functionality for admins to assign tasks.
73
  - [x] Develop an **AdminLTE 4**-based UI for managing tasks.
74
 
75
  ### 5. Data Logging and Reporting
 
76
  - [x] Implement data logging for activities and health records.
77
  - [x] Build reporting dashboards using **AdminLTE**.
78
  - [x] Enable export functionality (PDF, XLS).
79
  - [x] Integrate real-time visualization tools for health and productivity insights.
80
 
81
  ### 6. Health Management
 
82
  - [x] Define MongoDB schema for health records.
83
  - [x] Integrate disease detection data into health management.
84
  - [x] Develop an **AdminLTE** dashboard for disease and health tracking.
85
  - [x] Automate health alerts and treatment recommendations.
86
 
87
  ### 7. Inventory Management
 
88
  - [x] Design MongoDB schema for inventory tracking.
89
  - [x] Implement routes for adding, updating, and managing inventory items.
90
  - [x] Create an **AdminLTE** dashboard for inventory status.
91
  - [x] Set up email alerts for low-stock items.
92
 
93
  ### 8. Notification System
 
94
  - [x] Configure email service for notifications (`smtplib` or `nodemailer`).
95
  - [x] Implement notifications for:
96
- - [x] Task completion.
97
- - [x] Health alerts and recommendations.
98
- - [x] Inventory updates and low stock alerts.
99
  - [x] Test the notification system across scenarios.
100
 
101
  ### 9. Group Management
 
102
  - [x] Create MongoDB schema for managing user groups.
103
  - [x] Allow admins to create groups and share tasks.
104
  - [x] Enable farmers to join groups and track shared tasks.
105
 
106
  ### 10. Testing and Debugging
 
107
  - [ ] Write unit tests for modules (authentication, to-do lists, health management, inventory, etc.).
108
  - [ ] Conduct integration testing to validate end-to-end functionality.
109
  - [ ] Debug MongoDB transactions, pytorch predictions, and AdminLTE dashboards.
110
 
111
  ### 11. Deployment
 
112
  - [ ] Deploy the application on Hugging Face Spaces or other cloud platforms.
113
  - [ ] Configure production settings (environment variables, security).
114
  - [ ] Set up CI/CD pipeline for automatic testing and deployment.
@@ -116,6 +137,7 @@ This project combines a **Poultry Farming Assistance System** and a **Poultry Ma
116
  ---
117
 
118
  ## Future Enhancements
 
119
  - **Mobile Application**: Develop a mobile app using `Flutter` for remote management.
120
  - **AI-Based Inventory Forecasting**: Predict inventory needs based on usage trends.
121
  - **Multi-Language Support**: Localize the interface for global users.
 
14
 
15
  # 🐔 Poultry Farming Assistance and Management System
16
 
17
+ This project combines a **Poultry Farming Assistance System** and a **Poultry Management System**, streamlining health
18
+ monitoring, task management, inventory tracking, and disease detection using AI. Designed for farmers and farm admins,
19
+ this system enables effective poultry health management, provides real-time alerts, and generates actionable insights to
20
+ enhance productivity.
21
 
22
  ## Key Features
23
+
24
  1. **User Authentication and Role-Based Access**: Secure registration and login for farmers and admins.
25
+ 2. **Health Management with AI-Driven Disease Detection**: Fecal image analysis for common poultry diseases and
26
+ personalized treatment recommendations.
27
  3. **To-Do List and Task Management**: Track daily farm tasks and share across groups.
28
  4. **Inventory Management**: Monitor feed, medication, and supply levels with automated alerts.
29
  5. **Data Logging and Reporting**: Real-time dashboards, export options, and health reports.
 
34
  ## System Overview
35
 
36
  ### Poultry Farming Assistance System
37
+
38
+ - **AI-Powered Disease Detection**: Uses pre-trained models (e.g., `Final_Chicken_disease_model.h5`) to analyze fecal
39
+ images and identify poultry diseases.
40
  - **Health Monitoring**: Tracks metrics such as weight loss, mortality rate, and feed intake for proactive care.
41
  - **Treatment Recommendations**: Offers tailored suggestions based on detected health issues.
42
 
43
  ### Poultry Management System
44
+
45
  - **Task and To-Do List Management**: Allows farm admins to assign tasks and track completion across groups.
46
  - **Inventory Tracking**: Manages inventory levels and provides alerts for low-stock items.
47
  - **Health Records**: Logs poultry health data and tracks disease outbreaks.
 
50
  ---
51
 
52
  ## Use Cases
53
+
54
  - **Farmers**: Access disease detection, complete tasks, view health records, and receive alerts.
55
  - **Admins**: Create tasks, monitor group activities, manage inventory, and ensure flock health.
56
 
 
59
  ## 📝 To-Do List
60
 
61
  ### 1. Setup and Configuration
62
+
63
+ - [x] Set up a virtual environment and install required packages (`FastAPI`, `TensorFlow`, `MongoDB`, `transformers`,
64
+ etc.).
65
  - [x] Configure MongoDB and test CRUD operations.
66
  - [x] Establish environment variables for MongoDB, email credentials, and Hugging Face API token.
67
 
68
  ### 2. Authentication System
69
+
70
  - [x] Develop user registration for farmers and admins.
71
  - [x] Implement login/logout with JWT.
72
  - [x] Set up password encryption (`bcrypt`) for secure storage.
73
 
74
  ### 3. Poultry Farming Assistance System
75
+
76
  - [x] Integrate the poultry disease detection model (`Final_Chicken_disease_model.h5`).
77
  - [x] Set up image preprocessing for disease detection.
78
  - [x] Build endpoints for image upload and disease analysis.
 
80
  - [x] Implement real-time health monitoring and alerts.
81
 
82
  ### 4. To-Do List Management
83
+
84
  - [x] Design MongoDB schema for to-do lists.
85
  - [x] Create routes for farmers to view and mark to-do items.
86
  - [x] Build functionality for admins to assign tasks.
87
  - [x] Develop an **AdminLTE 4**-based UI for managing tasks.
88
 
89
  ### 5. Data Logging and Reporting
90
+
91
  - [x] Implement data logging for activities and health records.
92
  - [x] Build reporting dashboards using **AdminLTE**.
93
  - [x] Enable export functionality (PDF, XLS).
94
  - [x] Integrate real-time visualization tools for health and productivity insights.
95
 
96
  ### 6. Health Management
97
+
98
  - [x] Define MongoDB schema for health records.
99
  - [x] Integrate disease detection data into health management.
100
  - [x] Develop an **AdminLTE** dashboard for disease and health tracking.
101
  - [x] Automate health alerts and treatment recommendations.
102
 
103
  ### 7. Inventory Management
104
+
105
  - [x] Design MongoDB schema for inventory tracking.
106
  - [x] Implement routes for adding, updating, and managing inventory items.
107
  - [x] Create an **AdminLTE** dashboard for inventory status.
108
  - [x] Set up email alerts for low-stock items.
109
 
110
  ### 8. Notification System
111
+
112
  - [x] Configure email service for notifications (`smtplib` or `nodemailer`).
113
  - [x] Implement notifications for:
114
+ - [x] Task completion.
115
+ - [x] Health alerts and recommendations.
116
+ - [x] Inventory updates and low stock alerts.
117
  - [x] Test the notification system across scenarios.
118
 
119
  ### 9. Group Management
120
+
121
  - [x] Create MongoDB schema for managing user groups.
122
  - [x] Allow admins to create groups and share tasks.
123
  - [x] Enable farmers to join groups and track shared tasks.
124
 
125
  ### 10. Testing and Debugging
126
+
127
  - [ ] Write unit tests for modules (authentication, to-do lists, health management, inventory, etc.).
128
  - [ ] Conduct integration testing to validate end-to-end functionality.
129
  - [ ] Debug MongoDB transactions, pytorch predictions, and AdminLTE dashboards.
130
 
131
  ### 11. Deployment
132
+
133
  - [ ] Deploy the application on Hugging Face Spaces or other cloud platforms.
134
  - [ ] Configure production settings (environment variables, security).
135
  - [ ] Set up CI/CD pipeline for automatic testing and deployment.
 
137
  ---
138
 
139
  ## Future Enhancements
140
+
141
  - **Mobile Application**: Develop a mobile app using `Flutter` for remote management.
142
  - **AI-Based Inventory Forecasting**: Predict inventory needs based on usage trends.
143
  - **Multi-Language Support**: Localize the interface for global users.
backend/app/middleware/auth_middleware.py CHANGED
@@ -75,6 +75,7 @@ def role_required(role: str):
75
 
76
  Prompts and returns the user to the origin for access denied.
77
  """
 
78
  def role_verifier(user=Depends(get_current_user)):
79
  # Check if the user's role matches the required role
80
  if user.get("role") != role:
 
75
 
76
  Prompts and returns the user to the origin for access denied.
77
  """
78
+
79
  def role_verifier(user=Depends(get_current_user)):
80
  # Check if the user's role matches the required role
81
  if user.get("role") != role:
backend/app/models/inventory_item.py CHANGED
@@ -1,6 +1,7 @@
1
  from pydantic import BaseModel
2
  from typing import Optional
3
 
 
4
  class InventoryItem(BaseModel):
5
  item_name: str
6
  quantity: int
 
1
  from pydantic import BaseModel
2
  from typing import Optional
3
 
4
+
5
  class InventoryItem(BaseModel):
6
  item_name: str
7
  quantity: int
backend/app/routes/auth.py CHANGED
@@ -64,6 +64,7 @@ async def register_user(user: UserCreate):
64
  logger.error("Error registering user: %s", str(e))
65
  raise HTTPException(status_code=500, detail="Internal server error")
66
 
 
67
  @router.post("/login")
68
  async def login_user(login: LoginRequest, response: Response):
69
  """
@@ -111,6 +112,7 @@ async def login_user(login: LoginRequest, response: Response):
111
  logger.error("Unexpected error during login: %s", str(e))
112
  raise HTTPException(status_code=500, detail="Internal server error")
113
 
 
114
  @router.post("/logout")
115
  async def logout_user(response: Response):
116
  """
@@ -123,6 +125,7 @@ async def logout_user(response: Response):
123
  logger.info("User logged out successfully")
124
  return {"message": "User logged out successfully"}
125
 
 
126
  @router.get("/me")
127
  async def get_current_user_info(request: Request):
128
  """
 
64
  logger.error("Error registering user: %s", str(e))
65
  raise HTTPException(status_code=500, detail="Internal server error")
66
 
67
+
68
  @router.post("/login")
69
  async def login_user(login: LoginRequest, response: Response):
70
  """
 
112
  logger.error("Unexpected error during login: %s", str(e))
113
  raise HTTPException(status_code=500, detail="Internal server error")
114
 
115
+
116
  @router.post("/logout")
117
  async def logout_user(response: Response):
118
  """
 
125
  logger.info("User logged out successfully")
126
  return {"message": "User logged out successfully"}
127
 
128
+
129
  @router.get("/me")
130
  async def get_current_user_info(request: Request):
131
  """
backend/app/routes/chat.py CHANGED
@@ -11,6 +11,7 @@ from bson import ObjectId
11
  router = APIRouter()
12
  db = get_database()
13
 
 
14
  @router.post("/")
15
  async def chat_with_ai(message: str, current_user: dict = Depends(get_current_user)):
16
  """
 
11
  router = APIRouter()
12
  db = get_database()
13
 
14
+
15
  @router.post("/")
16
  async def chat_with_ai(message: str, current_user: dict = Depends(get_current_user)):
17
  """
backend/app/routes/dashboard.py CHANGED
@@ -12,7 +12,6 @@ db = get_database()
12
  logger = logging.getLogger(__name__)
13
 
14
 
15
-
16
  @router.get("/data")
17
  async def get_dashboard_data(current_user: dict = Depends(get_current_user)):
18
  """
 
12
  logger = logging.getLogger(__name__)
13
 
14
 
 
15
  @router.get("/data")
16
  async def get_dashboard_data(current_user: dict = Depends(get_current_user)):
17
  """
backend/app/routes/farm.py CHANGED
@@ -14,6 +14,7 @@ router = APIRouter()
14
  db = get_database()
15
  logger = logging.getLogger(__name__)
16
 
 
17
  @router.post("/")
18
  async def create_group(group_name: str, current_user: dict = Depends(get_current_user)):
19
  """
@@ -94,7 +95,8 @@ async def get_farmers_in_group(current_user: dict = Depends(get_current_user)):
94
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
95
 
96
  # Retrieve farmers in the group
97
- farmers = list(db.users.find({"farm_id": ObjectId(current_user["farm_id"]), "role": "farmer"}, {"password_hash": 0}))
 
98
 
99
  # Convert ObjectId fields to strings
100
  for farmer in farmers:
@@ -119,7 +121,7 @@ async def remove_farmer_from_group(farmer_id: str, current_user: dict = Depends(
119
  raise HTTPException(status_code=403, detail="Only admins can remove farmers from groups")
120
 
121
  try:
122
- group = db.groups.find_one({ "created_by": ObjectId(current_user["user_id"])})
123
  if not group:
124
  logger.warning("Group not found or unauthorized access by admin: %s", current_user["email"])
125
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
@@ -154,7 +156,7 @@ async def get_group_name(current_user: dict = Depends(get_current_user)):
154
  raise HTTPException(status_code=403, detail="Only admins can view group names")
155
 
156
  try:
157
- group = db.groups.find_one({ "created_by": ObjectId(current_user["user_id"])})
158
  if not group:
159
  logger.warning("Group not found or unauthorized access attempt by admin: %s", current_user["email"])
160
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
@@ -165,4 +167,3 @@ async def get_group_name(current_user: dict = Depends(get_current_user)):
165
  except Exception as e:
166
  logger.error("Error retrieving group name: %s", str(e))
167
  raise HTTPException(status_code=500, detail="Internal server error")
168
-
 
14
  db = get_database()
15
  logger = logging.getLogger(__name__)
16
 
17
+
18
  @router.post("/")
19
  async def create_group(group_name: str, current_user: dict = Depends(get_current_user)):
20
  """
 
95
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
96
 
97
  # Retrieve farmers in the group
98
+ farmers = list(
99
+ db.users.find({"farm_id": ObjectId(current_user["farm_id"]), "role": "farmer"}, {"password_hash": 0}))
100
 
101
  # Convert ObjectId fields to strings
102
  for farmer in farmers:
 
121
  raise HTTPException(status_code=403, detail="Only admins can remove farmers from groups")
122
 
123
  try:
124
+ group = db.groups.find_one({"created_by": ObjectId(current_user["user_id"])})
125
  if not group:
126
  logger.warning("Group not found or unauthorized access by admin: %s", current_user["email"])
127
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
 
156
  raise HTTPException(status_code=403, detail="Only admins can view group names")
157
 
158
  try:
159
+ group = db.groups.find_one({"created_by": ObjectId(current_user["user_id"])})
160
  if not group:
161
  logger.warning("Group not found or unauthorized access attempt by admin: %s", current_user["email"])
162
  raise HTTPException(status_code=404, detail="Group not found or unauthorized access")
 
167
  except Exception as e:
168
  logger.error("Error retrieving group name: %s", str(e))
169
  raise HTTPException(status_code=500, detail="Internal server error")
 
backend/app/routes/health.py CHANGED
@@ -10,6 +10,7 @@ from backend.app.schemas.health_record_schema import HealthRecordSchema
10
  from backend.app.services.disease_detection import detect_disease
11
  import cv2
12
  import numpy as np
 
13
  # Initialize router and logger
14
  router = APIRouter()
15
  db = get_database()
@@ -68,8 +69,8 @@ logger = logging.getLogger(__name__)
68
 
69
  @router.post("/detect_and_log")
70
  async def detect_and_log_health_record(
71
- file: UploadFile = File(...),
72
- current_user: dict = Depends(get_current_user)
73
  ):
74
  """
75
  Detect disease from an uploaded image and log a health record if a disease is detected.
@@ -119,6 +120,7 @@ async def detect_and_log_health_record(
119
  logger.error("Error during disease detection or logging: %s", str(e))
120
  raise HTTPException(status_code=500, detail="Internal server error")
121
 
 
122
  @router.get("/")
123
  async def get_health_records(current_user: dict = Depends(get_current_user)):
124
  """
@@ -145,11 +147,12 @@ async def get_health_records(current_user: dict = Depends(get_current_user)):
145
  logger.error("Error retrieving health records: %s", str(e))
146
  raise HTTPException(status_code=500, detail="Internal server error")
147
 
 
148
  @router.put("/{record_id}")
149
  async def update_health_record(
150
- record_id: str,
151
- updated_data: HealthRecordSchema,
152
- current_user: dict = Depends(get_current_user)
153
  ):
154
  """
155
  Update an existing health record for the user's associated farm.
 
10
  from backend.app.services.disease_detection import detect_disease
11
  import cv2
12
  import numpy as np
13
+
14
  # Initialize router and logger
15
  router = APIRouter()
16
  db = get_database()
 
69
 
70
  @router.post("/detect_and_log")
71
  async def detect_and_log_health_record(
72
+ file: UploadFile = File(...),
73
+ current_user: dict = Depends(get_current_user)
74
  ):
75
  """
76
  Detect disease from an uploaded image and log a health record if a disease is detected.
 
120
  logger.error("Error during disease detection or logging: %s", str(e))
121
  raise HTTPException(status_code=500, detail="Internal server error")
122
 
123
+
124
  @router.get("/")
125
  async def get_health_records(current_user: dict = Depends(get_current_user)):
126
  """
 
147
  logger.error("Error retrieving health records: %s", str(e))
148
  raise HTTPException(status_code=500, detail="Internal server error")
149
 
150
+
151
  @router.put("/{record_id}")
152
  async def update_health_record(
153
+ record_id: str,
154
+ updated_data: HealthRecordSchema,
155
+ current_user: dict = Depends(get_current_user)
156
  ):
157
  """
158
  Update an existing health record for the user's associated farm.
backend/app/routes/inventory.py CHANGED
@@ -16,7 +16,7 @@ logger = logging.getLogger(__name__)
16
 
17
  @router.post("/", response_model=dict)
18
  async def add_inventory_item(
19
- item: InventoryItemCreate, current_user: dict = Depends(get_current_user)
20
  ):
21
  """
22
  Add a new inventory item.
@@ -43,6 +43,7 @@ async def add_inventory_item(
43
  logger.error("Error adding inventory item: %s", str(e))
44
  raise HTTPException(status_code=500, detail="Internal server error")
45
 
 
46
  @router.get("/", response_model=list[InventoryItemSchema])
47
  async def get_inventory_items(current_user: dict = Depends(get_current_user)):
48
  """
@@ -106,7 +107,7 @@ async def get_inventory_item(item_id: str):
106
 
107
  @router.put("/{item_id}", response_model=dict)
108
  async def update_inventory_item(
109
- item_id: str, item: InventoryItemUpdate, current_user: dict = Depends(get_current_user)
110
  ):
111
  """
112
  Update an existing inventory item by its unique ID.
 
16
 
17
  @router.post("/", response_model=dict)
18
  async def add_inventory_item(
19
+ item: InventoryItemCreate, current_user: dict = Depends(get_current_user)
20
  ):
21
  """
22
  Add a new inventory item.
 
43
  logger.error("Error adding inventory item: %s", str(e))
44
  raise HTTPException(status_code=500, detail="Internal server error")
45
 
46
+
47
  @router.get("/", response_model=list[InventoryItemSchema])
48
  async def get_inventory_items(current_user: dict = Depends(get_current_user)):
49
  """
 
107
 
108
  @router.put("/{item_id}", response_model=dict)
109
  async def update_inventory_item(
110
+ item_id: str, item: InventoryItemUpdate, current_user: dict = Depends(get_current_user)
111
  ):
112
  """
113
  Update an existing inventory item by its unique ID.
backend/app/routes/pages.py CHANGED
@@ -122,7 +122,7 @@ async def manage_inventory_page(request: Request, current_user: dict = Depends(g
122
  logger.info("Rendering inventory management page for user ID: %s", current_user["user_id"])
123
  return templates.TemplateResponse(
124
  "inventory/view_inventory.html", {"request": request, "title": "Manage Inventory",
125
- "farm_id": current_user["farm_id"]}
126
  )
127
 
128
 
@@ -144,7 +144,7 @@ async def add_health_record_page(request: Request, current_user: dict = Depends(
144
  logger.info("Rendering add health record page for user ID: %s", current_user["user_id"])
145
  return templates.TemplateResponse(
146
  "health/log_health.html", {"request": request, "title": "Log New Health Record",
147
- "farm_id": current_user["farm_id"]}
148
  )
149
 
150
 
@@ -164,7 +164,9 @@ async def manage_health_records_page(request: Request, current_user: dict = Depe
164
  logger.warning("Unauthorized access attempt to manage health records page.")
165
  return RedirectResponse(url="/login")
166
  logger.info("Rendering health records management page for user ID: %s", current_user["user_id"])
167
- return templates.TemplateResponse( "health/manage_health.html", {"request": request, "title": "Manage Health Records","farm_id": current_user["farm_id"]})
 
 
168
 
169
 
170
  @router.get("/mangroup", response_class=HTMLResponse)
@@ -186,7 +188,7 @@ async def group_management_page(request: Request, current_user: dict = Depends(g
186
  logger.info("Rendering group management page for admin ID: %s", current_user["user_id"])
187
  return templates.TemplateResponse(
188
  "group/manage_group.html", {"request": request, "title": "Manage Group", "is_admin": True,
189
- "farm_id": current_user["farm_id"]}
190
  )
191
 
192
 
@@ -209,7 +211,7 @@ async def add_task_page(request: Request, current_user: dict = Depends(get_curre
209
  logger.info("Rendering add task page for admin ID: %s", current_user["user_id"])
210
  return templates.TemplateResponse(
211
  "todo/add_task.html", {"request": request, "title": "Add Task", "is_admin": True,
212
- "farm_id": current_user["farm_id"], "current_user.role": current_user["role"]}
213
  )
214
 
215
 
@@ -235,6 +237,8 @@ async def manage_tasks_page(request: Request, current_user: dict = Depends(get_c
235
  {"request": request, "title": "Manage Tasks", "is_admin": is_admin, "user_id": current_user["user_id"],
236
  "farm_id": current_user["farm_id"], "current_user.role": current_user["role"]}
237
  )
 
 
238
  @router.get("/chat", response_class=HTMLResponse)
239
  async def chat_page(request: Request, current_user: dict = Depends(get_current_user)):
240
  """
@@ -285,4 +289,4 @@ async def chat_history_page(request: Request, current_user: dict = Depends(get_c
285
  "title": "Chat History",
286
  "user_id": current_user["user_id"]
287
  }
288
- )
 
122
  logger.info("Rendering inventory management page for user ID: %s", current_user["user_id"])
123
  return templates.TemplateResponse(
124
  "inventory/view_inventory.html", {"request": request, "title": "Manage Inventory",
125
+ "farm_id": current_user["farm_id"]}
126
  )
127
 
128
 
 
144
  logger.info("Rendering add health record page for user ID: %s", current_user["user_id"])
145
  return templates.TemplateResponse(
146
  "health/log_health.html", {"request": request, "title": "Log New Health Record",
147
+ "farm_id": current_user["farm_id"]}
148
  )
149
 
150
 
 
164
  logger.warning("Unauthorized access attempt to manage health records page.")
165
  return RedirectResponse(url="/login")
166
  logger.info("Rendering health records management page for user ID: %s", current_user["user_id"])
167
+ return templates.TemplateResponse("health/manage_health.html",
168
+ {"request": request, "title": "Manage Health Records",
169
+ "farm_id": current_user["farm_id"]})
170
 
171
 
172
  @router.get("/mangroup", response_class=HTMLResponse)
 
188
  logger.info("Rendering group management page for admin ID: %s", current_user["user_id"])
189
  return templates.TemplateResponse(
190
  "group/manage_group.html", {"request": request, "title": "Manage Group", "is_admin": True,
191
+ "farm_id": current_user["farm_id"]}
192
  )
193
 
194
 
 
211
  logger.info("Rendering add task page for admin ID: %s", current_user["user_id"])
212
  return templates.TemplateResponse(
213
  "todo/add_task.html", {"request": request, "title": "Add Task", "is_admin": True,
214
+ "farm_id": current_user["farm_id"], "current_user.role": current_user["role"]}
215
  )
216
 
217
 
 
237
  {"request": request, "title": "Manage Tasks", "is_admin": is_admin, "user_id": current_user["user_id"],
238
  "farm_id": current_user["farm_id"], "current_user.role": current_user["role"]}
239
  )
240
+
241
+
242
  @router.get("/chat", response_class=HTMLResponse)
243
  async def chat_page(request: Request, current_user: dict = Depends(get_current_user)):
244
  """
 
289
  "title": "Chat History",
290
  "user_id": current_user["user_id"]
291
  }
292
+ )
backend/app/routes/task.py CHANGED
@@ -91,6 +91,7 @@ async def get_tasks(current_user: dict = Depends(get_current_user)):
91
  logger.error("Error retrieving tasks: %s", str(e))
92
  raise HTTPException(status_code=500, detail="Internal server error")
93
 
 
94
  @router.put("/{task_id}")
95
  async def update_task(task_id: str, task: Task):
96
  """
 
91
  logger.error("Error retrieving tasks: %s", str(e))
92
  raise HTTPException(status_code=500, detail="Internal server error")
93
 
94
+
95
  @router.put("/{task_id}")
96
  async def update_task(task_id: str, task: Task):
97
  """
backend/app/schemas/chat_history_schema.py CHANGED
@@ -3,6 +3,7 @@ from typing import List, Optional
3
  from datetime import datetime, timezone
4
  from bson import ObjectId
5
 
 
6
  class ChatMessage(BaseModel):
7
  """
8
  Represents an individual chat message in the history.
@@ -11,6 +12,7 @@ class ChatMessage(BaseModel):
11
  assistant_response: str
12
  timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
13
 
 
14
  class ChatHistory(BaseModel):
15
  """
16
  Represents a chat session with a list of chat messages.
@@ -20,7 +22,8 @@ class ChatHistory(BaseModel):
20
  session_id: ObjectId # Unique identifier for the chat session
21
  messages: List[ChatMessage] = [] # List of messages in the chat session
22
  created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) # When the session was created
23
- updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) # Last time the session was updated
 
24
 
25
  class Config:
26
  arbitrary_types_allowed = True
 
3
  from datetime import datetime, timezone
4
  from bson import ObjectId
5
 
6
+
7
  class ChatMessage(BaseModel):
8
  """
9
  Represents an individual chat message in the history.
 
12
  assistant_response: str
13
  timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
14
 
15
+
16
  class ChatHistory(BaseModel):
17
  """
18
  Represents a chat session with a list of chat messages.
 
22
  session_id: ObjectId # Unique identifier for the chat session
23
  messages: List[ChatMessage] = [] # List of messages in the chat session
24
  created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) # When the session was created
25
+ updated_at: datetime = Field(
26
+ default_factory=lambda: datetime.now(timezone.utc)) # Last time the session was updated
27
 
28
  class Config:
29
  arbitrary_types_allowed = True
backend/app/schemas/inventory_item_schema.py CHANGED
@@ -57,7 +57,8 @@ class InventoryItemCreate(BaseModel):
57
  category: str
58
  quantity: int
59
  status: Optional[str] = "active" # Default status is "active"
60
- last_updated: Optional[datetime] = Field(default_factory=lambda: datetime.now(timezone.utc)) # Automatically set the creation timestamp
 
61
  farm_id: str # ID of the farm
62
 
63
 
@@ -79,5 +80,6 @@ class InventoryItemUpdate(BaseModel):
79
  quantity: Optional[int] = None
80
  status: Optional[str] = None
81
  updated_by: Optional[str] = None
82
- last_updated: Optional[datetime] = Field(default_factory=lambda: datetime.now(timezone.utc)) # Automatically set the update timestamp
 
83
  farm_id: Optional[str] = None # Optional farm ID for reassignment
 
57
  category: str
58
  quantity: int
59
  status: Optional[str] = "active" # Default status is "active"
60
+ last_updated: Optional[datetime] = Field(
61
+ default_factory=lambda: datetime.now(timezone.utc)) # Automatically set the creation timestamp
62
  farm_id: str # ID of the farm
63
 
64
 
 
80
  quantity: Optional[int] = None
81
  status: Optional[str] = None
82
  updated_by: Optional[str] = None
83
+ last_updated: Optional[datetime] = Field(
84
+ default_factory=lambda: datetime.now(timezone.utc)) # Automatically set the update timestamp
85
  farm_id: Optional[str] = None # Optional farm ID for reassignment
backend/app/schemas/user_schema.py CHANGED
@@ -1,9 +1,9 @@
1
-
2
  # schemas/user_schema.py
3
  from bson import ObjectId
4
  from pydantic import BaseModel, EmailStr, Field
5
  from typing import Optional
6
 
 
7
  class UserSchema(BaseModel):
8
  id: Optional[str] = Field(None, alias="_id") # Use alias for MongoDB compatibility
9
  username: str
@@ -16,6 +16,7 @@ class UserSchema(BaseModel):
16
  arbitrary_types_allowed = True
17
  json_encoders = {ObjectId: str} # Automatically convert ObjectId to str
18
 
 
19
  class UserCreate(BaseModel):
20
  username: str
21
  email: EmailStr
@@ -23,6 +24,7 @@ class UserCreate(BaseModel):
23
  role: str # User role (e.g., "admin" or "farmer")
24
  group_name: Optional[str] # Group name for initial group creation in registration
25
 
 
26
  class LoginRequest(BaseModel):
27
  email: EmailStr
28
  password: str
 
 
1
  # schemas/user_schema.py
2
  from bson import ObjectId
3
  from pydantic import BaseModel, EmailStr, Field
4
  from typing import Optional
5
 
6
+
7
  class UserSchema(BaseModel):
8
  id: Optional[str] = Field(None, alias="_id") # Use alias for MongoDB compatibility
9
  username: str
 
16
  arbitrary_types_allowed = True
17
  json_encoders = {ObjectId: str} # Automatically convert ObjectId to str
18
 
19
+
20
  class UserCreate(BaseModel):
21
  username: str
22
  email: EmailStr
 
24
  role: str # User role (e.g., "admin" or "farmer")
25
  group_name: Optional[str] # Group name for initial group creation in registration
26
 
27
+
28
  class LoginRequest(BaseModel):
29
  email: EmailStr
30
  password: str
backend/app/services/disease_detection.py CHANGED
@@ -277,5 +277,3 @@ def detect_disease(image_file):
277
  # Log and return a generic error message for unexpected issues
278
  logger.error("Unhandled error in detect_disease: %s", detection_error)
279
  raise HTTPException(status_code=500, detail="Unexpected error during disease detection.")
280
-
281
-
 
277
  # Log and return a generic error message for unexpected issues
278
  logger.error("Unhandled error in detect_disease: %s", detection_error)
279
  raise HTTPException(status_code=500, detail="Unexpected error during disease detection.")
 
 
backend/app/services/llama_service.py CHANGED
@@ -85,7 +85,8 @@ def process_message(user_id: ObjectId, session_id: ObjectId, message: str) -> st
85
  history = chat_history.get("messages", []) if chat_history else []
86
 
87
  # Combine history into a single context string
88
- context = "\n".join([f"User: {chat['user_message']}\nAssistant: {chat['assistant_response']}" for chat in history])
 
89
  context += f"\nUser: {message}\nAssistant:"
90
 
91
  # Tokenize the input text
 
85
  history = chat_history.get("messages", []) if chat_history else []
86
 
87
  # Combine history into a single context string
88
+ context = "\n".join(
89
+ [f"User: {chat['user_message']}\nAssistant: {chat['assistant_response']}" for chat in history])
90
  context += f"\nUser: {message}\nAssistant:"
91
 
92
  # Tokenize the input text
backend/app/static/js/group.js CHANGED
@@ -19,7 +19,7 @@ async function loadGroupDetails() {
19
  // Fetch farmers in the group
20
  const response = await fetch(`/groups/farmers`, {
21
  method: 'GET',
22
- headers: { 'Content-Type': 'application/json' }
23
  });
24
 
25
  if (!response.ok) {
@@ -52,7 +52,7 @@ async function fetchGroupName() {
52
  try {
53
  const response = await fetch(`/groups/name`, {
54
  method: 'GET',
55
- headers: { 'Content-Type': 'application/json' }
56
  });
57
 
58
  if (!response.ok) {
@@ -83,8 +83,8 @@ async function addFarmer(event) {
83
  try {
84
  const response = await fetch(`/groups/add_farmer`, {
85
  method: 'POST',
86
- headers: { 'Content-Type': 'application/json' },
87
- body: JSON.stringify({ username, email, password, role }),
88
  });
89
 
90
  if (!response.ok) {
@@ -110,7 +110,7 @@ async function removeFarmer(farmerId) {
110
  try {
111
  const response = await fetch(`/groups/remove_farmer/${farmerId}`, {
112
  method: 'DELETE',
113
- headers: { 'Content-Type': 'application/json' }
114
  });
115
 
116
  if (!response.ok) {
 
19
  // Fetch farmers in the group
20
  const response = await fetch(`/groups/farmers`, {
21
  method: 'GET',
22
+ headers: {'Content-Type': 'application/json'}
23
  });
24
 
25
  if (!response.ok) {
 
52
  try {
53
  const response = await fetch(`/groups/name`, {
54
  method: 'GET',
55
+ headers: {'Content-Type': 'application/json'}
56
  });
57
 
58
  if (!response.ok) {
 
83
  try {
84
  const response = await fetch(`/groups/add_farmer`, {
85
  method: 'POST',
86
+ headers: {'Content-Type': 'application/json'},
87
+ body: JSON.stringify({username, email, password, role}),
88
  });
89
 
90
  if (!response.ok) {
 
110
  try {
111
  const response = await fetch(`/groups/remove_farmer/${farmerId}`, {
112
  method: 'DELETE',
113
+ headers: {'Content-Type': 'application/json'}
114
  });
115
 
116
  if (!response.ok) {
backend/app/static/js/health.js CHANGED
@@ -122,8 +122,8 @@ async function updateHealthRecord(event) {
122
  try {
123
  const response = await fetch(`/health/${id}`, {
124
  method: 'PUT',
125
- headers: { 'Content-Type': 'application/json' },
126
- body: JSON.stringify({ recommendation }),
127
  });
128
 
129
  if (response.ok) {
@@ -150,7 +150,7 @@ function confirmDeleteHealthRecord(id) {
150
 
151
  async function deleteHealthRecord() {
152
  try {
153
- const response = await fetch(`/health/${deleteRecordId}`, { method: 'DELETE' });
154
 
155
  if (response.ok) {
156
  alert("Health record deleted successfully!");
 
122
  try {
123
  const response = await fetch(`/health/${id}`, {
124
  method: 'PUT',
125
+ headers: {'Content-Type': 'application/json'},
126
+ body: JSON.stringify({recommendation}),
127
  });
128
 
129
  if (response.ok) {
 
150
 
151
  async function deleteHealthRecord() {
152
  try {
153
+ const response = await fetch(`/health/${deleteRecordId}`, {method: 'DELETE'});
154
 
155
  if (response.ok) {
156
  alert("Health record deleted successfully!");
backend/app/static/js/inventory.js CHANGED
@@ -34,7 +34,6 @@ function showUpdateForm(id, name, quantity, category, status) {
34
  }
35
 
36
 
37
-
38
  // Add Inventory Item
39
  async function addInventoryItem(event) {
40
  event.preventDefault();
@@ -49,7 +48,7 @@ async function addInventoryItem(event) {
49
  }
50
  if (!user_id || !farm_id) {
51
  alert("User or farm details are missing. Please log in again.");
52
- console.error("Missing user_id or farm_id:", { user_id, farm_id });
53
  return;
54
  }
55
 
@@ -63,7 +62,7 @@ async function addInventoryItem(event) {
63
  // Validate inputs
64
  if (!item_name || isNaN(quantity) || !category) {
65
  alert("Please provide valid inputs for all fields.");
66
- console.error("Invalid inputs:", { item_name, quantity, category });
67
  return;
68
  }
69
 
@@ -75,7 +74,7 @@ async function addInventoryItem(event) {
75
  'Content-Type': 'application/json',
76
  'Authorization': `Bearer ${token}`
77
  },
78
- body: JSON.stringify({ item_name, quantity, category, farm_id, status, updated_by })
79
  });
80
 
81
  if (response.ok) {
@@ -177,7 +176,7 @@ async function updateInventoryItem(event) {
177
  // Validate form values
178
  if (!id || !item_name || isNaN(quantity) || !category || !status) {
179
  alert("Please provide valid inputs for all fields.");
180
- console.error("Invalid update inputs:", { id, item_name, quantity, category, status });
181
  return;
182
  }
183
 
@@ -189,7 +188,7 @@ async function updateInventoryItem(event) {
189
  'Content-Type': 'application/json',
190
  'Authorization': `Bearer ${token}`
191
  },
192
- body: JSON.stringify({ item_name, quantity, category, status, updated_by })
193
  });
194
 
195
  if (response.ok) {
 
34
  }
35
 
36
 
 
37
  // Add Inventory Item
38
  async function addInventoryItem(event) {
39
  event.preventDefault();
 
48
  }
49
  if (!user_id || !farm_id) {
50
  alert("User or farm details are missing. Please log in again.");
51
+ console.error("Missing user_id or farm_id:", {user_id, farm_id});
52
  return;
53
  }
54
 
 
62
  // Validate inputs
63
  if (!item_name || isNaN(quantity) || !category) {
64
  alert("Please provide valid inputs for all fields.");
65
+ console.error("Invalid inputs:", {item_name, quantity, category});
66
  return;
67
  }
68
 
 
74
  'Content-Type': 'application/json',
75
  'Authorization': `Bearer ${token}`
76
  },
77
+ body: JSON.stringify({item_name, quantity, category, farm_id, status, updated_by})
78
  });
79
 
80
  if (response.ok) {
 
176
  // Validate form values
177
  if (!id || !item_name || isNaN(quantity) || !category || !status) {
178
  alert("Please provide valid inputs for all fields.");
179
+ console.error("Invalid update inputs:", {id, item_name, quantity, category, status});
180
  return;
181
  }
182
 
 
188
  'Content-Type': 'application/json',
189
  'Authorization': `Bearer ${token}`
190
  },
191
+ body: JSON.stringify({item_name, quantity, category, status, updated_by})
192
  });
193
 
194
  if (response.ok) {
backend/app/static/js/tasks.js CHANGED
@@ -53,7 +53,7 @@ async function addTask(event) {
53
  try {
54
  const response = await fetch('/tasks/', {
55
  method: 'POST',
56
- headers: { 'Content-Type': 'application/json' },
57
  body: JSON.stringify({
58
  task_description: taskDescription,
59
  assigned_to: assignedTo,
@@ -77,7 +77,6 @@ async function addTask(event) {
77
  let deleteTaskId = null;
78
 
79
 
80
-
81
  async function loadTasks() {
82
  /**
83
  * Load and display tasks for the group.
@@ -152,7 +151,7 @@ function confirmDeleteTask(id) {
152
 
153
  async function deleteTask() {
154
  try {
155
- const response = await fetch(`/tasks/${deleteTaskId}`, { method: 'DELETE' });
156
  if (response.ok) {
157
  alert("Task deleted successfully!");
158
  const modal = bootstrap.Modal.getInstance(document.getElementById('deleteTaskModal'));
 
53
  try {
54
  const response = await fetch('/tasks/', {
55
  method: 'POST',
56
+ headers: {'Content-Type': 'application/json'},
57
  body: JSON.stringify({
58
  task_description: taskDescription,
59
  assigned_to: assignedTo,
 
77
  let deleteTaskId = null;
78
 
79
 
 
80
  async function loadTasks() {
81
  /**
82
  * Load and display tasks for the group.
 
151
 
152
  async function deleteTask() {
153
  try {
154
+ const response = await fetch(`/tasks/${deleteTaskId}`, {method: 'DELETE'});
155
  if (response.ok) {
156
  alert("Task deleted successfully!");
157
  const modal = bootstrap.Modal.getInstance(document.getElementById('deleteTaskModal'));
backend/app/templates/auth/register.html CHANGED
@@ -5,9 +5,11 @@
5
  <title>Register</title>
6
  <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@fontsource/source-sans-3@5.0.12/index.css"
7
  integrity="sha256-tXJfXfp6Ewt1ilPzLDtQnJV4hclT9XuaZUKyUvmyr+Q=" rel="stylesheet">
8
- <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/styles/overlayscrollbars.min.css"
 
9
  integrity="sha256-dSokZseQNT08wYEWiz5iLI8QPlKxG+TswNRD8k35cpg=" rel="stylesheet">
10
- <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.min.css"
 
11
  integrity="sha256-Qsx5lrStHZyR9REqhUF8iQt73X06c8LGIUPzpOhwRrI=" rel="stylesheet">
12
  <link href="../static/css/adminlte.css" rel="stylesheet">
13
  </head>
@@ -20,7 +22,8 @@
20
  <p class="register-box-msg">Register a new admin account</p>
21
  <form id="registerForm" onsubmit="registerUser(event)">
22
  <div class="input-group mb-3">
23
- <input class="form-control" id="username" name="username" placeholder="Username" required type="text">
 
24
  <div class="input-group-text"><span class="bi bi-person"></span></div>
25
  </div>
26
  <div class="input-group mb-3">
@@ -28,11 +31,13 @@
28
  <div class="input-group-text"><span class="bi bi-envelope"></span></div>
29
  </div>
30
  <div class="input-group mb-3">
31
- <input class="form-control" id="password" name="password" placeholder="Password" required type="password">
 
32
  <div class="input-group-text"><span class="bi bi-lock-fill"></span></div>
33
  </div>
34
  <div class="input-group mb-3">
35
- <input class="form-control" id="group_name" name="group_name" placeholder="Group Name (Farm Name)" required type="text">
 
36
  <div class="input-group-text"><span class="bi bi-house-door"></span></div>
37
  </div>
38
  <div class="row">
@@ -59,31 +64,31 @@
59
 
60
  <script src="../static/js/auth.js"></script>
61
  <script>
62
- async function registerUser(event) {
63
- event.preventDefault();
64
- const username = document.getElementById('username').value;
65
- const email = document.getElementById('email').value;
66
- const password = document.getElementById('password').value;
67
- const group_name = document.getElementById('group_name').value;
68
 
69
- try {
70
- const response = await fetch('/auth/register', {
71
- method: 'POST',
72
- headers: { 'Content-Type': 'application/json' },
73
- body: JSON.stringify({ username, email, password, role: 'admin', group_name })
74
- });
75
- if (response.ok) {
76
- alert("Admin registered successfully!");
77
- window.location.href = "/login";
78
- } else {
79
- const error = await response.json();
80
- alert("Error: " + error.detail);
 
 
 
 
81
  }
82
- } catch (error) {
83
- console.error("Error registering admin:", error);
84
- alert("An error occurred while registering.");
85
  }
86
- }
87
  </script>
88
  </body>
89
  </html>
 
5
  <title>Register</title>
6
  <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@fontsource/source-sans-3@5.0.12/index.css"
7
  integrity="sha256-tXJfXfp6Ewt1ilPzLDtQnJV4hclT9XuaZUKyUvmyr+Q=" rel="stylesheet">
8
+ <link crossorigin="anonymous"
9
+ href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/styles/overlayscrollbars.min.css"
10
  integrity="sha256-dSokZseQNT08wYEWiz5iLI8QPlKxG+TswNRD8k35cpg=" rel="stylesheet">
11
+ <link crossorigin="anonymous"
12
+ href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.min.css"
13
  integrity="sha256-Qsx5lrStHZyR9REqhUF8iQt73X06c8LGIUPzpOhwRrI=" rel="stylesheet">
14
  <link href="../static/css/adminlte.css" rel="stylesheet">
15
  </head>
 
22
  <p class="register-box-msg">Register a new admin account</p>
23
  <form id="registerForm" onsubmit="registerUser(event)">
24
  <div class="input-group mb-3">
25
+ <input class="form-control" id="username" name="username" placeholder="Username" required
26
+ type="text">
27
  <div class="input-group-text"><span class="bi bi-person"></span></div>
28
  </div>
29
  <div class="input-group mb-3">
 
31
  <div class="input-group-text"><span class="bi bi-envelope"></span></div>
32
  </div>
33
  <div class="input-group mb-3">
34
+ <input class="form-control" id="password" name="password" placeholder="Password" required
35
+ type="password">
36
  <div class="input-group-text"><span class="bi bi-lock-fill"></span></div>
37
  </div>
38
  <div class="input-group mb-3">
39
+ <input class="form-control" id="group_name" name="group_name" placeholder="Group Name (Farm Name)"
40
+ required type="text">
41
  <div class="input-group-text"><span class="bi bi-house-door"></span></div>
42
  </div>
43
  <div class="row">
 
64
 
65
  <script src="../static/js/auth.js"></script>
66
  <script>
67
+ async function registerUser(event) {
68
+ event.preventDefault();
69
+ const username = document.getElementById('username').value;
70
+ const email = document.getElementById('email').value;
71
+ const password = document.getElementById('password').value;
72
+ const group_name = document.getElementById('group_name').value;
73
 
74
+ try {
75
+ const response = await fetch('/auth/register', {
76
+ method: 'POST',
77
+ headers: {'Content-Type': 'application/json'},
78
+ body: JSON.stringify({username, email, password, role: 'admin', group_name})
79
+ });
80
+ if (response.ok) {
81
+ alert("Admin registered successfully!");
82
+ window.location.href = "/login";
83
+ } else {
84
+ const error = await response.json();
85
+ alert("Error: " + error.detail);
86
+ }
87
+ } catch (error) {
88
+ console.error("Error registering admin:", error);
89
+ alert("An error occurred while registering.");
90
  }
 
 
 
91
  }
 
92
  </script>
93
  </body>
94
  </html>
backend/app/templates/chat/index.html CHANGED
@@ -6,276 +6,276 @@
6
  <title>AI Chat</title>
7
 
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
9
- <style>
10
- /* General Reset */
11
-
12
- body {
13
- margin: 0;
14
- font-family: Arial, sans-serif;
15
- background-color: #f7f8fc;
16
- display: flex;
17
- height: 100vh;
18
- overflow: hidden;
19
- }
20
-
21
- .chatgpt-clone {
22
- display: flex;
23
- width: 100%;
24
- height: 100%;
25
- }
26
-
27
- /* Sidebar Styling */
28
- .chat-sidebar {
29
- width: 25%;
30
- background-color: #2c2c54;
31
- color: white;
32
- display: flex;
33
- flex-direction: column;
34
- padding: 20px;
35
- overflow-y: auto;
36
- }
37
-
38
- .chat-sidebar h2 {
39
- margin-top: 0;
40
- font-size: 20px;
41
- border-bottom: 1px solid #4e4e8f;
42
- padding-bottom: 10px;
43
- }
44
-
45
- .chat-sidebar ul {
46
- list-style-type: none;
47
- padding: 0;
48
- margin: 0;
49
- flex: 1;
50
- overflow-y: auto;
51
- }
52
-
53
- .chat-sidebar ul li {
54
- padding: 10px;
55
- margin: 5px 0;
56
- background-color: #393975;
57
- border-radius: 5px;
58
- cursor: pointer;
59
- transition: background-color 0.3s;
60
- }
61
-
62
- .chat-sidebar ul li:hover {
63
- background-color: #5050a5;
64
- }
65
-
66
- .new-chat-button {
67
- padding: 10px;
68
- background-color: #5050a5;
69
- border: none;
70
- color: white;
71
- border-radius: 5px;
72
- cursor: pointer;
73
- font-size: 16px;
74
- margin-top: 10px;
75
- }
76
-
77
- .new-chat-button:hover {
78
- background-color: #7070c0;
79
- }
80
-
81
- /* Main Chat Interface */
82
- .chat-main {
83
- width: 75%;
84
- display: flex;
85
- flex-direction: column;
86
- background-color: #ffffff;
87
- }
88
-
89
- .chat-header {
90
- background-color: #f7f8fc;
91
- padding: 20px;
92
- border-bottom: 1px solid #e2e2e2;
93
- }
94
-
95
- .chat-header h1 {
96
- margin: 0;
97
- font-size: 22px;
98
- color: #2c2c54;
99
- }
100
-
101
- .chat-window {
102
- flex: 1;
103
- overflow-y: auto;
104
- padding: 20px;
105
- display: flex;
106
- flex-direction: column;
107
- gap: 15px;
108
- background-color: #f5f5f5;
109
- }
110
-
111
- .chat-bubble {
112
- max-width: 70%;
113
- padding: 15px;
114
- border-radius: 15px;
115
- word-wrap: break-word;
116
- box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
117
- }
118
-
119
- .user-message {
120
- align-self: flex-end;
121
- background-color: #3b82f6;
122
- color: white;
123
- border-bottom-right-radius: 0;
124
- }
125
-
126
- .bot-response {
127
- align-self: flex-start;
128
- background-color: #e2e8f0;
129
- color: #2c2c54;
130
- border-bottom-left-radius: 0;
131
- }
132
-
133
- .chat-footer {
134
- padding: 10px 20px;
135
- background-color: #f7f8fc;
136
- display: flex;
137
- align-items: center;
138
- border-top: 1px solid #e2e2e2;
139
- }
140
-
141
- textarea#messageInput {
142
- flex: 1;
143
- resize: none;
144
- border: 1px solid #d1d5db;
145
- border-radius: 5px;
146
- padding: 10px;
147
- font-size: 16px;
148
- }
149
-
150
- .send-button {
151
- background-color: #3b82f6;
152
- color: white;
153
- border: none;
154
- padding: 10px 15px;
155
- margin-left: 10px;
156
- border-radius: 5px;
157
- cursor: pointer;
158
- }
159
-
160
- .send-button i {
161
- font-size: 18px;
162
- }
163
-
164
- .send-button:hover {
165
- background-color: #2563eb;
166
- }
167
- </style>
168
  </head>
169
  <body>
170
- <div class="chatgpt-clone">
171
- <!-- Sidebar for Chat History -->
172
- <aside class="chat-sidebar">
173
- <h2>Chat History</h2>
174
- <ul id="chatHistoryList">
175
- <!-- Chat history dynamically loaded here -->
176
- </ul>
177
- <button class="new-chat-button" onclick="startNewChat()">+ New Chat</button>
178
- </aside>
179
-
180
- <!-- Main Chat Interface -->
181
- <main class="chat-main">
182
- <header class="chat-header">
183
- <h1>AI Assistant</h1>
184
- </header>
185
-
186
- <div class="chat-window" id="chatWindow">
187
- <!-- Chat messages dynamically loaded here -->
188
- </div>
189
-
190
- <footer class="chat-footer">
191
  <textarea
192
- id="messageInput"
193
- placeholder="Type your message..."
194
- onkeydown="if (event.key === 'Enter' && !event.shiftKey) sendMessage(event);"
195
  ></textarea>
196
- <button class="send-button" onclick="sendMessage(event)">
197
- <i class="fas fa-paper-plane"></i>
198
- </button>
199
- </footer>
200
- </main>
201
- </div>
202
- <script>
203
- // Fetch chat history and populate the sidebar
204
- async function fetchChatHistory() {
205
- try {
206
- const response = await fetch("/chat/history");
207
- if (!response.ok) {
208
- throw new Error("Failed to fetch chat history.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
210
-
211
- const history = await response.json();
212
- const historyList = document.getElementById("chatHistoryList");
213
- historyList.innerHTML = "";
214
-
215
- history.forEach(chat => {
216
- const listItem = document.createElement("li");
217
- listItem.textContent = chat.message;
218
- listItem.onclick = () => loadChat(chat);
219
- historyList.appendChild(listItem);
220
- });
221
- } catch (error) {
222
- console.error("Error fetching chat history:", error);
223
  }
224
- }
225
-
226
- // Send a new message
227
- async function sendMessage(event) {
228
- event.preventDefault();
229
- const messageInput = document.getElementById("messageInput");
230
- const message = messageInput.value.trim();
231
-
232
- if (!message) return;
233
-
234
- // Add user message to the chat window
235
- addMessageToChatWindow(message, "user-message");
236
-
237
- try {
238
- const response = await fetch("/chat", {
239
- method: "POST",
240
- headers: { "Content-Type": "application/json" },
241
- body: JSON.stringify({ message }),
242
- });
243
-
244
- const data = await response.json();
245
- addMessageToChatWindow(data.response, "bot-response");
246
- } catch (error) {
247
- console.error("Error sending message:", error);
 
 
248
  }
249
 
250
- messageInput.value = "";
251
- }
252
-
253
- // Add a message to the chat window
254
- function addMessageToChatWindow(message, className) {
255
- const chatWindow = document.getElementById("chatWindow");
256
- const bubble = document.createElement("div");
257
- bubble.className = `chat-bubble ${className}`;
258
- bubble.textContent = message;
259
- chatWindow.appendChild(bubble);
260
- chatWindow.scrollTop = chatWindow.scrollHeight;
261
- }
262
-
263
- // Start a new chat session
264
- async function startNewChat() {
265
- try {
266
- await fetch("/chat/new", { method: "POST" });
267
  const chatWindow = document.getElementById("chatWindow");
268
- chatWindow.innerHTML = "";
269
- } catch (error) {
270
- console.error("Error starting new chat:", error);
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
272
- }
273
 
274
- // Initialize
275
- document.addEventListener("DOMContentLoaded", () => {
276
- fetchChatHistory();
277
- });
278
 
279
- </script>
280
  </body>
281
  </html>
 
6
  <title>AI Chat</title>
7
 
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
9
+ <style>
10
+ /* General Reset */
11
+
12
+ body {
13
+ margin: 0;
14
+ font-family: Arial, sans-serif;
15
+ background-color: #f7f8fc;
16
+ display: flex;
17
+ height: 100vh;
18
+ overflow: hidden;
19
+ }
20
+
21
+ .chatgpt-clone {
22
+ display: flex;
23
+ width: 100%;
24
+ height: 100%;
25
+ }
26
+
27
+ /* Sidebar Styling */
28
+ .chat-sidebar {
29
+ width: 25%;
30
+ background-color: #2c2c54;
31
+ color: white;
32
+ display: flex;
33
+ flex-direction: column;
34
+ padding: 20px;
35
+ overflow-y: auto;
36
+ }
37
+
38
+ .chat-sidebar h2 {
39
+ margin-top: 0;
40
+ font-size: 20px;
41
+ border-bottom: 1px solid #4e4e8f;
42
+ padding-bottom: 10px;
43
+ }
44
+
45
+ .chat-sidebar ul {
46
+ list-style-type: none;
47
+ padding: 0;
48
+ margin: 0;
49
+ flex: 1;
50
+ overflow-y: auto;
51
+ }
52
+
53
+ .chat-sidebar ul li {
54
+ padding: 10px;
55
+ margin: 5px 0;
56
+ background-color: #393975;
57
+ border-radius: 5px;
58
+ cursor: pointer;
59
+ transition: background-color 0.3s;
60
+ }
61
+
62
+ .chat-sidebar ul li:hover {
63
+ background-color: #5050a5;
64
+ }
65
+
66
+ .new-chat-button {
67
+ padding: 10px;
68
+ background-color: #5050a5;
69
+ border: none;
70
+ color: white;
71
+ border-radius: 5px;
72
+ cursor: pointer;
73
+ font-size: 16px;
74
+ margin-top: 10px;
75
+ }
76
+
77
+ .new-chat-button:hover {
78
+ background-color: #7070c0;
79
+ }
80
+
81
+ /* Main Chat Interface */
82
+ .chat-main {
83
+ width: 75%;
84
+ display: flex;
85
+ flex-direction: column;
86
+ background-color: #ffffff;
87
+ }
88
+
89
+ .chat-header {
90
+ background-color: #f7f8fc;
91
+ padding: 20px;
92
+ border-bottom: 1px solid #e2e2e2;
93
+ }
94
+
95
+ .chat-header h1 {
96
+ margin: 0;
97
+ font-size: 22px;
98
+ color: #2c2c54;
99
+ }
100
+
101
+ .chat-window {
102
+ flex: 1;
103
+ overflow-y: auto;
104
+ padding: 20px;
105
+ display: flex;
106
+ flex-direction: column;
107
+ gap: 15px;
108
+ background-color: #f5f5f5;
109
+ }
110
+
111
+ .chat-bubble {
112
+ max-width: 70%;
113
+ padding: 15px;
114
+ border-radius: 15px;
115
+ word-wrap: break-word;
116
+ box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
117
+ }
118
+
119
+ .user-message {
120
+ align-self: flex-end;
121
+ background-color: #3b82f6;
122
+ color: white;
123
+ border-bottom-right-radius: 0;
124
+ }
125
+
126
+ .bot-response {
127
+ align-self: flex-start;
128
+ background-color: #e2e8f0;
129
+ color: #2c2c54;
130
+ border-bottom-left-radius: 0;
131
+ }
132
+
133
+ .chat-footer {
134
+ padding: 10px 20px;
135
+ background-color: #f7f8fc;
136
+ display: flex;
137
+ align-items: center;
138
+ border-top: 1px solid #e2e2e2;
139
+ }
140
+
141
+ textarea#messageInput {
142
+ flex: 1;
143
+ resize: none;
144
+ border: 1px solid #d1d5db;
145
+ border-radius: 5px;
146
+ padding: 10px;
147
+ font-size: 16px;
148
+ }
149
+
150
+ .send-button {
151
+ background-color: #3b82f6;
152
+ color: white;
153
+ border: none;
154
+ padding: 10px 15px;
155
+ margin-left: 10px;
156
+ border-radius: 5px;
157
+ cursor: pointer;
158
+ }
159
+
160
+ .send-button i {
161
+ font-size: 18px;
162
+ }
163
+
164
+ .send-button:hover {
165
+ background-color: #2563eb;
166
+ }
167
+ </style>
168
  </head>
169
  <body>
170
+ <div class="chatgpt-clone">
171
+ <!-- Sidebar for Chat History -->
172
+ <aside class="chat-sidebar">
173
+ <h2>Chat History</h2>
174
+ <ul id="chatHistoryList">
175
+ <!-- Chat history dynamically loaded here -->
176
+ </ul>
177
+ <button class="new-chat-button" onclick="startNewChat()">+ New Chat</button>
178
+ </aside>
179
+
180
+ <!-- Main Chat Interface -->
181
+ <main class="chat-main">
182
+ <header class="chat-header">
183
+ <h1>AI Assistant</h1>
184
+ </header>
185
+
186
+ <div class="chat-window" id="chatWindow">
187
+ <!-- Chat messages dynamically loaded here -->
188
+ </div>
189
+
190
+ <footer class="chat-footer">
191
  <textarea
192
+ id="messageInput"
193
+ placeholder="Type your message..."
194
+ onkeydown="if (event.key === 'Enter' && !event.shiftKey) sendMessage(event);"
195
  ></textarea>
196
+ <button class="send-button" onclick="sendMessage(event)">
197
+ <i class="fas fa-paper-plane"></i>
198
+ </button>
199
+ </footer>
200
+ </main>
201
+ </div>
202
+ <script>
203
+ // Fetch chat history and populate the sidebar
204
+ async function fetchChatHistory() {
205
+ try {
206
+ const response = await fetch("/chat/history");
207
+ if (!response.ok) {
208
+ throw new Error("Failed to fetch chat history.");
209
+ }
210
+
211
+ const history = await response.json();
212
+ const historyList = document.getElementById("chatHistoryList");
213
+ historyList.innerHTML = "";
214
+
215
+ history.forEach(chat => {
216
+ const listItem = document.createElement("li");
217
+ listItem.textContent = chat.message;
218
+ listItem.onclick = () => loadChat(chat);
219
+ historyList.appendChild(listItem);
220
+ });
221
+ } catch (error) {
222
+ console.error("Error fetching chat history:", error);
223
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
225
+
226
+ // Send a new message
227
+ async function sendMessage(event) {
228
+ event.preventDefault();
229
+ const messageInput = document.getElementById("messageInput");
230
+ const message = messageInput.value.trim();
231
+
232
+ if (!message) return;
233
+
234
+ // Add user message to the chat window
235
+ addMessageToChatWindow(message, "user-message");
236
+
237
+ try {
238
+ const response = await fetch("/chat", {
239
+ method: "POST",
240
+ headers: {"Content-Type": "application/json"},
241
+ body: JSON.stringify({message}),
242
+ });
243
+
244
+ const data = await response.json();
245
+ addMessageToChatWindow(data.response, "bot-response");
246
+ } catch (error) {
247
+ console.error("Error sending message:", error);
248
+ }
249
+
250
+ messageInput.value = "";
251
  }
252
 
253
+ // Add a message to the chat window
254
+ function addMessageToChatWindow(message, className) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  const chatWindow = document.getElementById("chatWindow");
256
+ const bubble = document.createElement("div");
257
+ bubble.className = `chat-bubble ${className}`;
258
+ bubble.textContent = message;
259
+ chatWindow.appendChild(bubble);
260
+ chatWindow.scrollTop = chatWindow.scrollHeight;
261
+ }
262
+
263
+ // Start a new chat session
264
+ async function startNewChat() {
265
+ try {
266
+ await fetch("/chat/new", {method: "POST"});
267
+ const chatWindow = document.getElementById("chatWindow");
268
+ chatWindow.innerHTML = "";
269
+ } catch (error) {
270
+ console.error("Error starting new chat:", error);
271
+ }
272
  }
 
273
 
274
+ // Initialize
275
+ document.addEventListener("DOMContentLoaded", () => {
276
+ fetchChatHistory();
277
+ });
278
 
279
+ </script>
280
  </body>
281
  </html>
backend/app/templates/dashboard.html CHANGED
@@ -3,111 +3,111 @@
3
  {% block title %}Dashboard{% endblock %}
4
 
5
  {% block content %}
6
- <div class="container-fluid">
7
- <!-- Overview Statistics -->
8
- <div class="row">
9
- <div class="col-12 col-sm-6 col-md-3">
10
- <div class="info-box">
11
  <span class="info-box-icon text-bg-primary shadow-sm">
12
  <i class="bi bi-clipboard-data"></i>
13
  </span>
14
- <div class="info-box-content">
15
- <span class="info-box-text">Tasks</span>
16
- <span class="info-box-number" id="tasksCount">0</span>
 
17
  </div>
18
  </div>
19
- </div>
20
- <div class="col-12 col-sm-6 col-md-3">
21
- <div class="info-box">
22
  <span class="info-box-icon text-bg-success shadow-sm">
23
  <i class="bi bi-box-seam"></i>
24
  </span>
25
- <div class="info-box-content">
26
- <span class="info-box-text">Inventory Items</span>
27
- <span class="info-box-number" id="inventoryCount">0</span>
 
28
  </div>
29
  </div>
30
- </div>
31
- <div class="col-12 col-sm-6 col-md-3">
32
- <div class="info-box">
33
  <span class="info-box-icon text-bg-danger shadow-sm">
34
  <i class="bi bi-heart-pulse-fill"></i>
35
  </span>
36
- <div class="info-box-content">
37
- <span class="info-box-text">Health Records</span>
38
- <span class="info-box-number" id="healthRecordsCount">0</span>
 
39
  </div>
40
  </div>
41
  </div>
42
- </div>
43
 
44
- <!-- Recent Updates Section -->
45
- <div class="row mt-4">
46
- <div class="col-lg-6">
47
- <div class="card">
48
- <div class="card-header bg-primary text-white">
49
- <h3 class="card-title">Recent Tasks</h3>
50
- </div>
51
- <div class="card-body">
52
- <ul id="recentTasks" class="list-group">
53
- <li class="list-group-item">No recent tasks available.</li>
54
- </ul>
 
55
  </div>
56
  </div>
57
- </div>
58
- <div class="col-lg-6">
59
- <div class="card">
60
- <div class="card-header bg-success text-white">
61
- <h3 class="card-title">Latest Health Records</h3>
62
- </div>
63
- <div class="card-body">
64
- <ul id="recentHealthRecords" class="list-group">
65
- <li class="list-group-item">No recent health records available.</li>
66
- </ul>
67
  </div>
68
  </div>
69
  </div>
70
  </div>
71
- </div>
72
 
73
- <script>
74
- async function loadDashboardData() {
75
- const token = sessionStorage.getItem('access_token');
76
- if (!token) {
77
- window.location.href = "/login";
78
- return;
79
- }
80
 
81
- try {
82
- const response = await fetch('/dashboard/data', {
83
- headers: { 'Authorization': 'Bearer ' + token }
84
- });
85
 
86
- if (response.ok) {
87
- const data = await response.json();
88
 
89
- // Update Statistics
90
- document.getElementById('tasksCount').innerText = data.tasksCount || 0;
91
- document.getElementById('inventoryCount').innerText = data.inventoryCount || 0;
92
- document.getElementById('healthRecordsCount').innerText = data.healthRecordsCount || 0;
93
 
94
- // Populate Recent Tasks
95
- document.getElementById('recentTasks').innerHTML = data.recentTasks.length
96
- ? data.recentTasks.map(task => `<li class="list-group-item">${task.description} (Due: ${new Date(task.due_date).toLocaleDateString()})</li>`).join('')
97
- : '<li class="list-group-item">No recent tasks available.</li>';
98
 
99
- // Populate Recent Health Records
100
- document.getElementById('recentHealthRecords').innerHTML = data.recentHealthRecords.length
101
- ? data.recentHealthRecords.map(record => `<li class="list-group-item">${record.disease_type} (Logged: ${new Date(record.diagnosis_date).toLocaleDateString()})</li>`).join('')
102
- : '<li class="list-group-item">No recent health records available.</li>';
103
- } else {
104
- console.error("Error fetching dashboard data:", response.statusText);
 
 
 
 
105
  }
106
- } catch (error) {
107
- console.error("Error loading dashboard:", error);
108
- }
109
- }
110
 
111
- document.addEventListener("DOMContentLoaded", loadDashboardData);
112
- </script>
113
  {% endblock %}
 
3
  {% block title %}Dashboard{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="container-fluid">
7
+ <!-- Overview Statistics -->
8
+ <div class="row">
9
+ <div class="col-12 col-sm-6 col-md-3">
10
+ <div class="info-box">
11
  <span class="info-box-icon text-bg-primary shadow-sm">
12
  <i class="bi bi-clipboard-data"></i>
13
  </span>
14
+ <div class="info-box-content">
15
+ <span class="info-box-text">Tasks</span>
16
+ <span class="info-box-number" id="tasksCount">0</span>
17
+ </div>
18
  </div>
19
  </div>
20
+ <div class="col-12 col-sm-6 col-md-3">
21
+ <div class="info-box">
 
22
  <span class="info-box-icon text-bg-success shadow-sm">
23
  <i class="bi bi-box-seam"></i>
24
  </span>
25
+ <div class="info-box-content">
26
+ <span class="info-box-text">Inventory Items</span>
27
+ <span class="info-box-number" id="inventoryCount">0</span>
28
+ </div>
29
  </div>
30
  </div>
31
+ <div class="col-12 col-sm-6 col-md-3">
32
+ <div class="info-box">
 
33
  <span class="info-box-icon text-bg-danger shadow-sm">
34
  <i class="bi bi-heart-pulse-fill"></i>
35
  </span>
36
+ <div class="info-box-content">
37
+ <span class="info-box-text">Health Records</span>
38
+ <span class="info-box-number" id="healthRecordsCount">0</span>
39
+ </div>
40
  </div>
41
  </div>
42
  </div>
 
43
 
44
+ <!-- Recent Updates Section -->
45
+ <div class="row mt-4">
46
+ <div class="col-lg-6">
47
+ <div class="card">
48
+ <div class="card-header bg-primary text-white">
49
+ <h3 class="card-title">Recent Tasks</h3>
50
+ </div>
51
+ <div class="card-body">
52
+ <ul id="recentTasks" class="list-group">
53
+ <li class="list-group-item">No recent tasks available.</li>
54
+ </ul>
55
+ </div>
56
  </div>
57
  </div>
58
+ <div class="col-lg-6">
59
+ <div class="card">
60
+ <div class="card-header bg-success text-white">
61
+ <h3 class="card-title">Latest Health Records</h3>
62
+ </div>
63
+ <div class="card-body">
64
+ <ul id="recentHealthRecords" class="list-group">
65
+ <li class="list-group-item">No recent health records available.</li>
66
+ </ul>
67
+ </div>
68
  </div>
69
  </div>
70
  </div>
71
  </div>
 
72
 
73
+ <script>
74
+ async function loadDashboardData() {
75
+ const token = sessionStorage.getItem('access_token');
76
+ if (!token) {
77
+ window.location.href = "/login";
78
+ return;
79
+ }
80
 
81
+ try {
82
+ const response = await fetch('/dashboard/data', {
83
+ headers: {'Authorization': 'Bearer ' + token}
84
+ });
85
 
86
+ if (response.ok) {
87
+ const data = await response.json();
88
 
89
+ // Update Statistics
90
+ document.getElementById('tasksCount').innerText = data.tasksCount || 0;
91
+ document.getElementById('inventoryCount').innerText = data.inventoryCount || 0;
92
+ document.getElementById('healthRecordsCount').innerText = data.healthRecordsCount || 0;
93
 
94
+ // Populate Recent Tasks
95
+ document.getElementById('recentTasks').innerHTML = data.recentTasks.length
96
+ ? data.recentTasks.map(task => `<li class="list-group-item">${task.description} (Due: ${new Date(task.due_date).toLocaleDateString()})</li>`).join('')
97
+ : '<li class="list-group-item">No recent tasks available.</li>';
98
 
99
+ // Populate Recent Health Records
100
+ document.getElementById('recentHealthRecords').innerHTML = data.recentHealthRecords.length
101
+ ? data.recentHealthRecords.map(record => `<li class="list-group-item">${record.disease_type} (Logged: ${new Date(record.diagnosis_date).toLocaleDateString()})</li>`).join('')
102
+ : '<li class="list-group-item">No recent health records available.</li>';
103
+ } else {
104
+ console.error("Error fetching dashboard data:", response.statusText);
105
+ }
106
+ } catch (error) {
107
+ console.error("Error loading dashboard:", error);
108
+ }
109
  }
 
 
 
 
110
 
111
+ document.addEventListener("DOMContentLoaded", loadDashboardData);
112
+ </script>
113
  {% endblock %}
backend/app/templates/group/manage_group.html CHANGED
@@ -3,60 +3,63 @@
3
  {% block title %}Manage Group{% endblock %}
4
 
5
  {% block content %}
6
- <div class="container mt-4">
7
 
8
- <!-- Group Details Section -->
9
- <div class="card mb-4" id="groupDetailsSection">
10
- <div class="card-header">Group Details</div>
11
- <div class="card-body">
12
- <p><strong>Farm Name:</strong> <span id="farmName"></span></p>
13
- <button id="addFarmerButton" class="btn btn-primary" onclick="showAddFarmerForm()">Add Farmer</button>
 
14
  </div>
15
- </div>
16
 
17
- <!-- Add Farmer Form (Hidden initially) -->
18
- <div class="card mb-4" id="addFarmerSection" style="display: none;">
19
- <div class="card-header">Add Farmer to Group</div>
20
- <div class="card-body">
21
- <form id="addFarmerForm" onsubmit="addFarmer(event)">
22
- <div class="form-group">
23
- <label for="farmer_username">Farmer Username</label>
24
- <input type="text" id="farmer_username" class="form-control" placeholder="Enter farmer username" required>
25
- </div>
26
- <div class="form-group">
27
- <label for="farmer_email">Farmer Email</label>
28
- <input type="email" id="farmer_email" class="form-control" placeholder="Enter farmer email" required>
29
- </div>
30
- <div class="form-group">
31
- <label for="farmer_password">Password</label>
32
- <input type="password" id="farmer_password" class="form-control" placeholder="Set a password for the farmer" required>
33
- </div>
34
- <button type="submit" class="btn btn-success mt-2">Add Farmer</button>
35
- <button type="button" class="btn btn-secondary mt-2" onclick="hideAddFarmerForm()">Cancel</button>
36
- </form>
 
 
 
 
37
  </div>
38
- </div>
39
 
40
- <!-- Farmers List -->
41
- <div class="card">
42
- <div class="card-header">Farmers in Group</div>
43
- <div class="card-body">
44
- <table class="table table-striped" id="farmersTable">
45
- <thead>
46
  <tr>
47
  <th>Username</th>
48
  <th>Email</th>
49
  <th>Actions</th>
50
  </tr>
51
- </thead>
52
- <tbody>
53
  <!-- Farmers will be loaded here via JavaScript -->
54
- </tbody>
55
- </table>
 
56
  </div>
57
  </div>
58
- </div>
59
 
60
- <script src="../static/js/group.js"></script>
61
 
62
  {% endblock %}
 
3
  {% block title %}Manage Group{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="container mt-4">
7
 
8
+ <!-- Group Details Section -->
9
+ <div class="card mb-4" id="groupDetailsSection">
10
+ <div class="card-header">Group Details</div>
11
+ <div class="card-body">
12
+ <p><strong>Farm Name:</strong> <span id="farmName"></span></p>
13
+ <button id="addFarmerButton" class="btn btn-primary" onclick="showAddFarmerForm()">Add Farmer</button>
14
+ </div>
15
  </div>
 
16
 
17
+ <!-- Add Farmer Form (Hidden initially) -->
18
+ <div class="card mb-4" id="addFarmerSection" style="display: none;">
19
+ <div class="card-header">Add Farmer to Group</div>
20
+ <div class="card-body">
21
+ <form id="addFarmerForm" onsubmit="addFarmer(event)">
22
+ <div class="form-group">
23
+ <label for="farmer_username">Farmer Username</label>
24
+ <input type="text" id="farmer_username" class="form-control" placeholder="Enter farmer username"
25
+ required>
26
+ </div>
27
+ <div class="form-group">
28
+ <label for="farmer_email">Farmer Email</label>
29
+ <input type="email" id="farmer_email" class="form-control" placeholder="Enter farmer email"
30
+ required>
31
+ </div>
32
+ <div class="form-group">
33
+ <label for="farmer_password">Password</label>
34
+ <input type="password" id="farmer_password" class="form-control"
35
+ placeholder="Set a password for the farmer" required>
36
+ </div>
37
+ <button type="submit" class="btn btn-success mt-2">Add Farmer</button>
38
+ <button type="button" class="btn btn-secondary mt-2" onclick="hideAddFarmerForm()">Cancel</button>
39
+ </form>
40
+ </div>
41
  </div>
 
42
 
43
+ <!-- Farmers List -->
44
+ <div class="card">
45
+ <div class="card-header">Farmers in Group</div>
46
+ <div class="card-body">
47
+ <table class="table table-striped" id="farmersTable">
48
+ <thead>
49
  <tr>
50
  <th>Username</th>
51
  <th>Email</th>
52
  <th>Actions</th>
53
  </tr>
54
+ </thead>
55
+ <tbody>
56
  <!-- Farmers will be loaded here via JavaScript -->
57
+ </tbody>
58
+ </table>
59
+ </div>
60
  </div>
61
  </div>
 
62
 
63
+ <script src="../static/js/group.js"></script>
64
 
65
  {% endblock %}
backend/app/templates/health/log_health.html CHANGED
@@ -3,31 +3,33 @@
3
  {% block title %}Log Health Record{% endblock %}
4
 
5
  {% block content %}
6
- <div class="card">
7
- <div class="card-body">
8
- <h3 class="card-title">Log Health Record with Disease Detection</h3>
9
- <form id="logHealthForm" onsubmit="detectAndLogHealthRecord(event)">
10
- <!-- Image Upload -->
11
- <div class="form-group">
12
- <label for="image" class="form-label">Upload Image for Disease Detection</label>
13
- <input type="file" id="image" class="form-control" accept="image/*" required>
14
- <small class="form-text text-muted">Supported formats: JPG, PNG. Ensure the image is clear.</small>
15
- </div>
16
- <!-- Detected Disease Type -->
17
- <div class="form-group mt-3">
18
- <label for="disease_type" class="form-label">Detected Disease Type</label>
19
- <input type="text" id="disease_type" class="form-control" readonly placeholder="Disease will be auto-detected">
20
- </div>
21
- <!-- Recommendation -->
22
- <div class="form-group mt-3">
23
- <label for="recommendation" class="form-label">Recommendation</label>
24
- <textarea id="recommendation" class="form-control" rows="4" readonly placeholder="Recommendation will be auto-generated"></textarea>
25
- </div>
26
- <!-- Submit Button -->
27
- <button type="submit" class="btn btn-dark mt-3">Log Health Record</button>
28
- </form>
 
 
 
29
  </div>
30
- </div>
31
 
32
- <script src="../static/js/health.js"></script>
33
  {% endblock %}
 
3
  {% block title %}Log Health Record{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="card">
7
+ <div class="card-body">
8
+ <h3 class="card-title">Log Health Record with Disease Detection</h3>
9
+ <form id="logHealthForm" onsubmit="detectAndLogHealthRecord(event)">
10
+ <!-- Image Upload -->
11
+ <div class="form-group">
12
+ <label for="image" class="form-label">Upload Image for Disease Detection</label>
13
+ <input type="file" id="image" class="form-control" accept="image/*" required>
14
+ <small class="form-text text-muted">Supported formats: JPG, PNG. Ensure the image is clear.</small>
15
+ </div>
16
+ <!-- Detected Disease Type -->
17
+ <div class="form-group mt-3">
18
+ <label for="disease_type" class="form-label">Detected Disease Type</label>
19
+ <input type="text" id="disease_type" class="form-control" readonly
20
+ placeholder="Disease will be auto-detected">
21
+ </div>
22
+ <!-- Recommendation -->
23
+ <div class="form-group mt-3">
24
+ <label for="recommendation" class="form-label">Recommendation</label>
25
+ <textarea id="recommendation" class="form-control" rows="4" readonly
26
+ placeholder="Recommendation will be auto-generated"></textarea>
27
+ </div>
28
+ <!-- Submit Button -->
29
+ <button type="submit" class="btn btn-dark mt-3">Log Health Record</button>
30
+ </form>
31
+ </div>
32
  </div>
 
33
 
34
+ <script src="../static/js/health.js"></script>
35
  {% endblock %}
backend/app/templates/health/manage_health.html CHANGED
@@ -3,68 +3,70 @@
3
  {% block title %}Manage Health Records{% endblock %}
4
 
5
  {% block content %}
6
- <div class="card">
7
- <div class="card-body">
8
- <table class="table table-bordered table-hover" id="healthRecordsTable">
9
- <thead class="table-primary">
10
  <tr>
11
  <th>Disease Type</th>
12
  <th>Recommendation</th>
13
  <th>Diagnosis Date</th>
14
  <th>Actions</th>
15
  </tr>
16
- </thead>
17
- <tbody>
18
  <!-- Rows will be populated by JavaScript -->
19
- </tbody>
20
- </table>
 
21
  </div>
22
- </div>
23
 
24
- <!-- Update Health Record Modal -->
25
- <div class="modal fade" id="updateHealthModal" tabindex="-1" aria-labelledby="updateHealthModalLabel" aria-hidden="true">
26
- <div class="modal-dialog">
27
- <div class="modal-content">
28
- <div class="modal-header">
29
- <h5 class="modal-title" id="updateHealthModalLabel">Update Health Record</h5>
30
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
31
- </div>
32
- <div class="modal-body">
33
- <form id="updateHealthForm" onsubmit="updateHealthRecord(event)">
34
- <input type="hidden" id="updateRecordId">
35
- <div class="form-group">
36
- <label for="updateDiseaseType">Disease Type</label>
37
- <input type="text" id="updateDiseaseType" class="form-control" readonly>
38
- </div>
39
- <div class="form-group mt-3">
40
- <label for="updateRecommendation">Recommendation</label>
41
- <textarea id="updateRecommendation" class="form-control" rows="4" readonly></textarea>
42
- </div>
43
- <button type="submit" class="btn btn-primary mt-3">Update Record</button>
44
- </form>
 
 
45
  </div>
46
  </div>
47
  </div>
48
- </div>
49
 
50
- <!-- Delete Confirmation Modal -->
51
- <div class="modal fade" id="deleteHealthModal" tabindex="-1" aria-labelledby="deleteHealthModalLabel" aria-hidden="true">
52
- <div class="modal-dialog">
53
- <div class="modal-content">
54
- <div class="modal-header">
55
- <h5 class="modal-title" id="deleteHealthModalLabel">Delete Health Record</h5>
56
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
57
- </div>
58
- <div class="modal-body">
59
- <p>Are you sure you want to delete this health record? This action cannot be undone.</p>
60
- </div>
61
- <div class="modal-footer">
62
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
63
- <button type="button" class="btn btn-danger" onclick="deleteHealthRecord()">Delete</button>
 
 
64
  </div>
65
  </div>
66
  </div>
67
- </div>
68
 
69
- <script src="../static/js/health.js"></script>
70
  {% endblock %}
 
3
  {% block title %}Manage Health Records{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="card">
7
+ <div class="card-body">
8
+ <table class="table table-bordered table-hover" id="healthRecordsTable">
9
+ <thead class="table-primary">
10
  <tr>
11
  <th>Disease Type</th>
12
  <th>Recommendation</th>
13
  <th>Diagnosis Date</th>
14
  <th>Actions</th>
15
  </tr>
16
+ </thead>
17
+ <tbody>
18
  <!-- Rows will be populated by JavaScript -->
19
+ </tbody>
20
+ </table>
21
+ </div>
22
  </div>
 
23
 
24
+ <!-- Update Health Record Modal -->
25
+ <div class="modal fade" id="updateHealthModal" tabindex="-1" aria-labelledby="updateHealthModalLabel"
26
+ aria-hidden="true">
27
+ <div class="modal-dialog">
28
+ <div class="modal-content">
29
+ <div class="modal-header">
30
+ <h5 class="modal-title" id="updateHealthModalLabel">Update Health Record</h5>
31
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
32
+ </div>
33
+ <div class="modal-body">
34
+ <form id="updateHealthForm" onsubmit="updateHealthRecord(event)">
35
+ <input type="hidden" id="updateRecordId">
36
+ <div class="form-group">
37
+ <label for="updateDiseaseType">Disease Type</label>
38
+ <input type="text" id="updateDiseaseType" class="form-control" readonly>
39
+ </div>
40
+ <div class="form-group mt-3">
41
+ <label for="updateRecommendation">Recommendation</label>
42
+ <textarea id="updateRecommendation" class="form-control" rows="4" readonly></textarea>
43
+ </div>
44
+ <button type="submit" class="btn btn-primary mt-3">Update Record</button>
45
+ </form>
46
+ </div>
47
  </div>
48
  </div>
49
  </div>
 
50
 
51
+ <!-- Delete Confirmation Modal -->
52
+ <div class="modal fade" id="deleteHealthModal" tabindex="-1" aria-labelledby="deleteHealthModalLabel"
53
+ aria-hidden="true">
54
+ <div class="modal-dialog">
55
+ <div class="modal-content">
56
+ <div class="modal-header">
57
+ <h5 class="modal-title" id="deleteHealthModalLabel">Delete Health Record</h5>
58
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
59
+ </div>
60
+ <div class="modal-body">
61
+ <p>Are you sure you want to delete this health record? This action cannot be undone.</p>
62
+ </div>
63
+ <div class="modal-footer">
64
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
65
+ <button type="button" class="btn btn-danger" onclick="deleteHealthRecord()">Delete</button>
66
+ </div>
67
  </div>
68
  </div>
69
  </div>
 
70
 
71
+ <script src="../static/js/health.js"></script>
72
  {% endblock %}
backend/app/templates/inventory/add_inventory.html CHANGED
@@ -4,52 +4,52 @@
4
 
5
  {% block content %}
6
 
7
- <div class="card">
8
- <div class="card-body">
9
- <form id="addInventoryForm" onsubmit="addInventoryItem(event)">
10
- <!-- Item Name Input -->
11
- <div class="form-group mt-3">
12
- <label for="item_name">Item Name</label>
13
- <input
14
- class="form-control"
15
- id="item_name"
16
- placeholder="Enter item name"
17
- required
18
- type="text">
19
- </div>
20
-
21
- <!-- Quantity Input -->
22
- <div class="form-group mt-3">
23
- <label for="quantity">Quantity</label>
24
- <input
25
- class="form-control"
26
- id="quantity"
27
- placeholder="Enter quantity"
28
- required
29
- type="number"
30
- min="1">
31
- </div>
32
-
33
- <!-- Category Selection -->
34
- <div class="form-group mt-3">
35
- <label for="category">Category</label>
36
- <select
37
- class="form-control"
38
- id="category"
39
- required>
40
- <option value="" disabled selected>Select category</option>
41
- <option value="Poultry Animal">Poultry Animal</option>
42
- <option value="Feed">Feed</option>
43
- <option value="Farm Tool">Farm Tool</option>
44
- </select>
45
- </div>
46
-
47
-
48
- <!-- Submit Button -->
49
- <button class="btn btn-primary mt-3" type="submit">Add Item</button>
50
- </form>
 
51
  </div>
52
- </div>
53
 
54
- <script src="../static/js/inventory.js"></script>
55
  {% endblock %}
 
4
 
5
  {% block content %}
6
 
7
+ <div class="card">
8
+ <div class="card-body">
9
+ <form id="addInventoryForm" onsubmit="addInventoryItem(event)">
10
+ <!-- Item Name Input -->
11
+ <div class="form-group mt-3">
12
+ <label for="item_name">Item Name</label>
13
+ <input
14
+ class="form-control"
15
+ id="item_name"
16
+ placeholder="Enter item name"
17
+ required
18
+ type="text">
19
+ </div>
20
+
21
+ <!-- Quantity Input -->
22
+ <div class="form-group mt-3">
23
+ <label for="quantity">Quantity</label>
24
+ <input
25
+ class="form-control"
26
+ id="quantity"
27
+ placeholder="Enter quantity"
28
+ required
29
+ type="number"
30
+ min="1">
31
+ </div>
32
+
33
+ <!-- Category Selection -->
34
+ <div class="form-group mt-3">
35
+ <label for="category">Category</label>
36
+ <select
37
+ class="form-control"
38
+ id="category"
39
+ required>
40
+ <option value="" disabled selected>Select category</option>
41
+ <option value="Poultry Animal">Poultry Animal</option>
42
+ <option value="Feed">Feed</option>
43
+ <option value="Farm Tool">Farm Tool</option>
44
+ </select>
45
+ </div>
46
+
47
+
48
+ <!-- Submit Button -->
49
+ <button class="btn btn-primary mt-3" type="submit">Add Item</button>
50
+ </form>
51
+ </div>
52
  </div>
 
53
 
54
+ <script src="../static/js/inventory.js"></script>
55
  {% endblock %}
backend/app/templates/inventory/view_inventory.html CHANGED
@@ -4,10 +4,10 @@
4
 
5
  {% block content %}
6
 
7
- <div class="card">
8
- <div class="card-body">
9
- <table class="table table-striped table-bordered" id="inventoryTable">
10
- <thead class="table-dark">
11
  <tr>
12
  <th>Item Name</th>
13
  <th>Quantity</th>
@@ -15,73 +15,76 @@
15
  <th>Last Updated</th>
16
  <th>Actions</th>
17
  </tr>
18
- </thead>
19
- <tbody>
20
  <!-- Rows will be dynamically populated by JavaScript -->
21
- </tbody>
22
- </table>
 
23
  </div>
24
- </div>
25
 
26
- <!-- Update Inventory Modal -->
27
- <div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
28
- <div class="modal-dialog">
29
- <div class="modal-content">
30
- <div class="modal-header bg-secondary text-white">
31
- <h5 class="modal-title" id="updateModalLabel">Update Inventory Item</h5>
32
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
33
- </div>
34
- <div class="modal-body">
35
- <form id="updateInventoryForm" onsubmit="updateInventoryItem(event)">
36
- <input type="hidden" id="updateItemId">
37
- <div class="form-group mb-3">
38
- <label for="updateItemName" class="form-label">Item Name</label>
39
- <input type="text" id="updateItemName" class="form-control" placeholder="Enter item name" required>
40
- </div>
41
- <div class="form-group mb-3">
42
- <label for="updateQuantity" class="form-label">Quantity</label>
43
- <input type="number" id="updateQuantity" class="form-control" placeholder="Enter quantity" required>
44
- </div>
45
- <div class="form-group mb-3">
46
- <label for="updateCategory" class="form-label">Category</label>
47
- <select id="updateCategory" class="form-control" required>
48
- <option value="" disabled selected>Select Category</option>
49
- <option value="Poultry Animal">Poultry Animal</option>
50
- <option value="Feed">Feed</option>
51
- <option value="Farm Tool">Farm Tool</option>
52
- </select>
53
- </div>
54
- <div class="form-group mb-3">
55
- <label for="updateStatus" class="form-label">Status</label>
56
- <input type="text" id="updateStatus" class="form-control" placeholder="Enter status" required>
57
- </div>
58
- <div class="d-grid">
59
- <button type="submit" class="btn btn-dark">Update Item</button>
60
- </div>
61
- </form>
 
 
 
 
62
  </div>
63
  </div>
64
  </div>
65
- </div>
66
 
67
- <!-- Delete Confirmation Modal -->
68
- <div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
69
- <div class="modal-dialog">
70
- <div class="modal-content">
71
- <div class="modal-header bg-danger text-white">
72
- <h5 class="modal-title" id="deleteModalLabel">Delete Inventory Item</h5>
73
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
74
- </div>
75
- <div class="modal-body">
76
- <p class="text-danger">Are you sure you want to delete this item? This action cannot be undone.</p>
77
- </div>
78
- <div class="modal-footer">
79
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
80
- <button type="button" class="btn btn-danger" onclick="deleteInventoryItem()">Delete</button>
 
81
  </div>
82
  </div>
83
  </div>
84
- </div>
85
 
86
- <script src="../static/js/inventory.js"></script>
87
  {% endblock %}
 
4
 
5
  {% block content %}
6
 
7
+ <div class="card">
8
+ <div class="card-body">
9
+ <table class="table table-striped table-bordered" id="inventoryTable">
10
+ <thead class="table-dark">
11
  <tr>
12
  <th>Item Name</th>
13
  <th>Quantity</th>
 
15
  <th>Last Updated</th>
16
  <th>Actions</th>
17
  </tr>
18
+ </thead>
19
+ <tbody>
20
  <!-- Rows will be dynamically populated by JavaScript -->
21
+ </tbody>
22
+ </table>
23
+ </div>
24
  </div>
 
25
 
26
+ <!-- Update Inventory Modal -->
27
+ <div class="modal fade" id="updateModal" tabindex="-1" aria-labelledby="updateModalLabel" aria-hidden="true">
28
+ <div class="modal-dialog">
29
+ <div class="modal-content">
30
+ <div class="modal-header bg-secondary text-white">
31
+ <h5 class="modal-title" id="updateModalLabel">Update Inventory Item</h5>
32
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
33
+ </div>
34
+ <div class="modal-body">
35
+ <form id="updateInventoryForm" onsubmit="updateInventoryItem(event)">
36
+ <input type="hidden" id="updateItemId">
37
+ <div class="form-group mb-3">
38
+ <label for="updateItemName" class="form-label">Item Name</label>
39
+ <input type="text" id="updateItemName" class="form-control" placeholder="Enter item name"
40
+ required>
41
+ </div>
42
+ <div class="form-group mb-3">
43
+ <label for="updateQuantity" class="form-label">Quantity</label>
44
+ <input type="number" id="updateQuantity" class="form-control" placeholder="Enter quantity"
45
+ required>
46
+ </div>
47
+ <div class="form-group mb-3">
48
+ <label for="updateCategory" class="form-label">Category</label>
49
+ <select id="updateCategory" class="form-control" required>
50
+ <option value="" disabled selected>Select Category</option>
51
+ <option value="Poultry Animal">Poultry Animal</option>
52
+ <option value="Feed">Feed</option>
53
+ <option value="Farm Tool">Farm Tool</option>
54
+ </select>
55
+ </div>
56
+ <div class="form-group mb-3">
57
+ <label for="updateStatus" class="form-label">Status</label>
58
+ <input type="text" id="updateStatus" class="form-control" placeholder="Enter status"
59
+ required>
60
+ </div>
61
+ <div class="d-grid">
62
+ <button type="submit" class="btn btn-dark">Update Item</button>
63
+ </div>
64
+ </form>
65
+ </div>
66
  </div>
67
  </div>
68
  </div>
 
69
 
70
+ <!-- Delete Confirmation Modal -->
71
+ <div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
72
+ <div class="modal-dialog">
73
+ <div class="modal-content">
74
+ <div class="modal-header bg-danger text-white">
75
+ <h5 class="modal-title" id="deleteModalLabel">Delete Inventory Item</h5>
76
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
77
+ </div>
78
+ <div class="modal-body">
79
+ <p class="text-danger">Are you sure you want to delete this item? This action cannot be undone.</p>
80
+ </div>
81
+ <div class="modal-footer">
82
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
83
+ <button type="button" class="btn btn-danger" onclick="deleteInventoryItem()">Delete</button>
84
+ </div>
85
  </div>
86
  </div>
87
  </div>
 
88
 
89
+ <script src="../static/js/inventory.js"></script>
90
  {% endblock %}
backend/app/templates/landing.html CHANGED
@@ -95,8 +95,10 @@
95
  </section>
96
 
97
  <script crossorigin="anonymous"
98
- integrity="sha256-x5Mj2wYeSa9WVOK+EK8Z5rmXHFZ+MOY8r4eW8AKzpXU=" src="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0-beta2/dist/js/adminlte.min.js"></script>
 
99
  <script crossorigin="anonymous"
100
- integrity="sha256-qq1ob4lpAizCQs1tkv5gttMXUlgpiHyvG3JcCIktRvs=" src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/js/all.min.js"></script>
 
101
  </body>
102
  </html>
 
95
  </section>
96
 
97
  <script crossorigin="anonymous"
98
+ integrity="sha256-x5Mj2wYeSa9WVOK+EK8Z5rmXHFZ+MOY8r4eW8AKzpXU="
99
+ src="https://cdn.jsdelivr.net/npm/admin-lte@4.0.0-beta2/dist/js/adminlte.min.js"></script>
100
  <script crossorigin="anonymous"
101
+ integrity="sha256-qq1ob4lpAizCQs1tkv5gttMXUlgpiHyvG3JcCIktRvs="
102
+ src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/js/all.min.js"></script>
103
  </body>
104
  </html>
backend/app/templates/main/base.html CHANGED
@@ -8,13 +8,18 @@
8
  <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@fontsource/source-sans-3@5.0.12/index.css"
9
  integrity="sha256-tXJfXfp6Ewt1ilPzLDtQnJV4hclT9XuaZUKyUvmyr+Q=" rel="stylesheet"><!--end::Fonts-->
10
  <!--begin::Third Party Plugin(OverlayScrollbars)-->
11
- <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/styles/overlayscrollbars.min.css"
 
12
  integrity="sha256-dSokZseQNT08wYEWiz5iLI8QPlKxG+TswNRD8k35cpg=" rel="stylesheet">
13
  <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Third Party Plugin(Bootstrap Icons)-->
14
- <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.min.css"
 
15
  integrity="sha256-Qsx5lrStHZyR9REqhUF8iQt73X06c8LGIUPzpOhwRrI=" rel="stylesheet">
16
  <!--end::Third Party Plugin(Bootstrap Icons)-->
17
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/css/fontawesome.min.css" integrity="sha256-XfA0ppGOANs88Ds+9FqVLy3xIGzT/25K/VLmRRxE9ow=" crossorigin="anonymous"><!--begin::Required Plugin(AdminLTE)-->
 
 
 
18
  </head> <!--end::Head--> <!--begin::Body-->
19
 
20
  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
@@ -61,17 +66,21 @@
61
 
62
  <script src="../static/js/auth.js"></script>
63
  <script crossorigin="anonymous"
64
- integrity="sha256-H2VM7BKda+v2Z4+DRy69uknwxjyDRhszjXFhsL4gD3w=" src="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/browser/overlayscrollbars.browser.es6.min.js"></script>
 
65
  <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Required Plugin(popperjs for Bootstrap 5)-->
66
  <script crossorigin="anonymous"
67
- integrity="sha256-whL0tQWoY1Ku1iskqPFvmZ+CHsvmRWx/PIoEvIeWh4I=" src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
 
68
  <!--end::Required Plugin(popperjs for Bootstrap 5)--><!--begin::Required Plugin(Bootstrap 5)-->
69
  <script crossorigin="anonymous"
70
- integrity="sha256-YMa+wAM6QkVyz999odX7lPRxkoYAan8suedu4k2Zur8=" src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"></script>
 
71
  <!--end::Required Plugin(Bootstrap 5)--><!--begin::Required Plugin(AdminLTE)-->
72
  <script src="../static/js/adminlte.js"></script> <!--end::Required Plugin(AdminLTE)-->
73
  <!--begin::OverlayScrollbars Configure-->
74
- <script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/js/all.min.js" integrity="sha256-qq1ob4lpAizCQs1tkv5gttMXUlgpiHyvG3JcCIktRvs=" crossorigin="anonymous"></script>
 
75
  <script>
76
  const SELECTOR_SIDEBAR_WRAPPER = ".sidebar-wrapper";
77
  const Default = {
 
8
  <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@fontsource/source-sans-3@5.0.12/index.css"
9
  integrity="sha256-tXJfXfp6Ewt1ilPzLDtQnJV4hclT9XuaZUKyUvmyr+Q=" rel="stylesheet"><!--end::Fonts-->
10
  <!--begin::Third Party Plugin(OverlayScrollbars)-->
11
+ <link crossorigin="anonymous"
12
+ href="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/styles/overlayscrollbars.min.css"
13
  integrity="sha256-dSokZseQNT08wYEWiz5iLI8QPlKxG+TswNRD8k35cpg=" rel="stylesheet">
14
  <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Third Party Plugin(Bootstrap Icons)-->
15
+ <link crossorigin="anonymous"
16
+ href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.min.css"
17
  integrity="sha256-Qsx5lrStHZyR9REqhUF8iQt73X06c8LGIUPzpOhwRrI=" rel="stylesheet">
18
  <!--end::Third Party Plugin(Bootstrap Icons)-->
19
+ <link rel="stylesheet"
20
+ href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/css/fontawesome.min.css"
21
+ integrity="sha256-XfA0ppGOANs88Ds+9FqVLy3xIGzT/25K/VLmRRxE9ow=" crossorigin="anonymous">
22
+ <!--begin::Required Plugin(AdminLTE)-->
23
  </head> <!--end::Head--> <!--begin::Body-->
24
 
25
  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
 
66
 
67
  <script src="../static/js/auth.js"></script>
68
  <script crossorigin="anonymous"
69
+ integrity="sha256-H2VM7BKda+v2Z4+DRy69uknwxjyDRhszjXFhsL4gD3w="
70
+ src="https://cdn.jsdelivr.net/npm/overlayscrollbars@2.3.0/browser/overlayscrollbars.browser.es6.min.js"></script>
71
  <!--end::Third Party Plugin(OverlayScrollbars)--><!--begin::Required Plugin(popperjs for Bootstrap 5)-->
72
  <script crossorigin="anonymous"
73
+ integrity="sha256-whL0tQWoY1Ku1iskqPFvmZ+CHsvmRWx/PIoEvIeWh4I="
74
+ src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
75
  <!--end::Required Plugin(popperjs for Bootstrap 5)--><!--begin::Required Plugin(Bootstrap 5)-->
76
  <script crossorigin="anonymous"
77
+ integrity="sha256-YMa+wAM6QkVyz999odX7lPRxkoYAan8suedu4k2Zur8="
78
+ src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"></script>
79
  <!--end::Required Plugin(Bootstrap 5)--><!--begin::Required Plugin(AdminLTE)-->
80
  <script src="../static/js/adminlte.js"></script> <!--end::Required Plugin(AdminLTE)-->
81
  <!--begin::OverlayScrollbars Configure-->
82
+ <script src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/js/all.min.js"
83
+ integrity="sha256-qq1ob4lpAizCQs1tkv5gttMXUlgpiHyvG3JcCIktRvs=" crossorigin="anonymous"></script>
84
  <script>
85
  const SELECTOR_SIDEBAR_WRAPPER = ".sidebar-wrapper";
86
  const Default = {
backend/app/templates/main/partials/sidebar.html CHANGED
@@ -26,8 +26,10 @@
26
  <p>Inventory<i class="nav-arrow bi bi-chevron-right"></i></p>
27
  </a>
28
  <ul class="nav nav-treeview">
29
- <li class="nav-item"><a class="nav-link" href="/additem"><i class="far fa-circle nav-icon"></i> Add Inventory</a></li>
30
- <li class="nav-item"><a class="nav-link" href="/items"><i class="far fa-circle nav-icon"></i> Manage Inventory</a></li>
 
 
31
  </ul>
32
  </li>
33
 
@@ -38,8 +40,10 @@
38
  <p>Health Monitoring<i class="nav-arrow bi bi-chevron-right"></i></p>
39
  </a>
40
  <ul class="nav nav-treeview">
41
- <li class="nav-item"><a class="nav-link" href="/addrecord"><i class="far fa-circle nav-icon"></i> Add Health Record</a></li>
42
- <li class="nav-item"><a class="nav-link" href="/hrecords"><i class="far fa-circle nav-icon"></i> Manage Health Records</a></li>
 
 
43
  </ul>
44
  </li>
45
 
@@ -51,23 +55,26 @@
51
  </a>
52
  <ul class="nav nav-treeview">
53
  {% if is_admin %}
54
- <li class="nav-item"><a class="nav-link" href="/addtask"><i class="far fa-circle nav-icon"></i> Add Task</a></li>
 
55
  {% endif %}
56
- <li class="nav-item"><a class="nav-link" href="/tasks"><i class="far fa-circle nav-icon"></i> Manage Tasks</a></li>
 
57
  </ul>
58
  </li>
59
 
60
  <!-- Group Management (Visible only to Admins) -->
61
  {% if is_admin %}
62
- <li class="nav-item">
63
- <a class="nav-link" href="#">
64
- <i class="nav-icon fas fa-users"></i>
65
- <p>Group Management<i class="nav-arrow bi bi-chevron-right"></i></p>
66
- </a>
67
- <ul class="nav nav-treeview">
68
- <li class="nav-item"><a class="nav-link" href="/mangroup"><i class="far fa-circle nav-icon"></i> Manage Groups</a></li>
69
- </ul>
70
- </li>
 
71
  {% endif %}
72
 
73
  </ul>
 
26
  <p>Inventory<i class="nav-arrow bi bi-chevron-right"></i></p>
27
  </a>
28
  <ul class="nav nav-treeview">
29
+ <li class="nav-item"><a class="nav-link" href="/additem"><i class="far fa-circle nav-icon"></i>
30
+ Add Inventory</a></li>
31
+ <li class="nav-item"><a class="nav-link" href="/items"><i class="far fa-circle nav-icon"></i>
32
+ Manage Inventory</a></li>
33
  </ul>
34
  </li>
35
 
 
40
  <p>Health Monitoring<i class="nav-arrow bi bi-chevron-right"></i></p>
41
  </a>
42
  <ul class="nav nav-treeview">
43
+ <li class="nav-item"><a class="nav-link" href="/addrecord"><i
44
+ class="far fa-circle nav-icon"></i> Add Health Record</a></li>
45
+ <li class="nav-item"><a class="nav-link" href="/hrecords"><i class="far fa-circle nav-icon"></i>
46
+ Manage Health Records</a></li>
47
  </ul>
48
  </li>
49
 
 
55
  </a>
56
  <ul class="nav nav-treeview">
57
  {% if is_admin %}
58
+ <li class="nav-item"><a class="nav-link" href="/addtask"><i
59
+ class="far fa-circle nav-icon"></i> Add Task</a></li>
60
  {% endif %}
61
+ <li class="nav-item"><a class="nav-link" href="/tasks"><i class="far fa-circle nav-icon"></i>
62
+ Manage Tasks</a></li>
63
  </ul>
64
  </li>
65
 
66
  <!-- Group Management (Visible only to Admins) -->
67
  {% if is_admin %}
68
+ <li class="nav-item">
69
+ <a class="nav-link" href="#">
70
+ <i class="nav-icon fas fa-users"></i>
71
+ <p>Group Management<i class="nav-arrow bi bi-chevron-right"></i></p>
72
+ </a>
73
+ <ul class="nav nav-treeview">
74
+ <li class="nav-item"><a class="nav-link" href="/mangroup"><i
75
+ class="far fa-circle nav-icon"></i> Manage Groups</a></li>
76
+ </ul>
77
+ </li>
78
  {% endif %}
79
 
80
  </ul>
backend/app/templates/todo/add_task.html CHANGED
@@ -3,57 +3,57 @@
3
  {% block title %}Add Task{% endblock %}
4
 
5
  {% block content %}
6
- <div class="container mt-4">
7
- <div class="card">
8
- <div class="card-body">
9
- <form id="addTaskForm" onsubmit="addTask(event)">
10
- <!-- Task Description -->
11
- <div class="form-group">
12
- <label for="task_description">Task Description</label>
13
- <input
14
- type="text"
15
- id="task_description"
16
- class="form-control"
17
- placeholder="Enter task description"
18
- required
19
- >
20
- </div>
21
 
22
- <!-- Assign To -->
23
- <div class="form-group mt-3">
24
- <label for="assigned_to">Assign To (Optional)</label>
25
- <select
26
- id="assigned_to"
27
- class="form-control">
28
- <option value="">No Assignment</option>
29
- </select>
30
- </div>
31
 
32
- <!-- Due Date -->
33
- <div class="form-group mt-3">
34
- <label for="due_date">Due Date</label>
35
- <input
36
- type="datetime-local"
37
- id="due_date"
38
- class="form-control"
39
- required
40
- >
41
- </div>
42
 
43
- <!-- Submit Button -->
44
- <button
45
- type="submit"
46
- class="btn btn-primary mt-3">
47
- Add Task
48
- </button>
49
- </form>
 
50
  </div>
51
  </div>
52
- </div>
53
 
54
- <script src="../static/js/tasks.js"></script>
55
- <script>
56
- // Initialize farmers when the page loads
57
- document.addEventListener('DOMContentLoaded', fetchFarmers);
58
- </script>
59
  {% endblock %}
 
3
  {% block title %}Add Task{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="container mt-4">
7
+ <div class="card">
8
+ <div class="card-body">
9
+ <form id="addTaskForm" onsubmit="addTask(event)">
10
+ <!-- Task Description -->
11
+ <div class="form-group">
12
+ <label for="task_description">Task Description</label>
13
+ <input
14
+ type="text"
15
+ id="task_description"
16
+ class="form-control"
17
+ placeholder="Enter task description"
18
+ required
19
+ >
20
+ </div>
21
 
22
+ <!-- Assign To -->
23
+ <div class="form-group mt-3">
24
+ <label for="assigned_to">Assign To (Optional)</label>
25
+ <select
26
+ id="assigned_to"
27
+ class="form-control">
28
+ <option value="">No Assignment</option>
29
+ </select>
30
+ </div>
31
 
32
+ <!-- Due Date -->
33
+ <div class="form-group mt-3">
34
+ <label for="due_date">Due Date</label>
35
+ <input
36
+ type="datetime-local"
37
+ id="due_date"
38
+ class="form-control"
39
+ required
40
+ >
41
+ </div>
42
 
43
+ <!-- Submit Button -->
44
+ <button
45
+ type="submit"
46
+ class="btn btn-primary mt-3">
47
+ Add Task
48
+ </button>
49
+ </form>
50
+ </div>
51
  </div>
52
  </div>
 
53
 
54
+ <script src="../static/js/tasks.js"></script>
55
+ <script>
56
+ // Initialize farmers when the page loads
57
+ document.addEventListener('DOMContentLoaded', fetchFarmers);
58
+ </script>
59
  {% endblock %}
backend/app/templates/todo/manage_tasks.html CHANGED
@@ -3,13 +3,13 @@
3
  {% block title %}Manage Tasks{% endblock %}
4
 
5
  {% block content %}
6
- <div class="container mt-4">
7
 
8
- <!-- Task Table -->
9
- <div class="card">
10
- <div class="card-body">
11
- <table class="table table-striped" id="tasksTable">
12
- <thead>
13
  <tr>
14
  <th>Description</th>
15
  <th>Assigned To</th>
@@ -17,81 +17,83 @@
17
  <th>Due Date</th>
18
  <th>Actions</th>
19
  </tr>
20
- </thead>
21
- <tbody>
22
  <!-- Tasks will be dynamically loaded here -->
23
- </tbody>
24
- </table>
 
25
  </div>
26
  </div>
27
- </div>
28
 
29
- <!-- Update Task Modal -->
30
- <div class="modal fade" id="updateTaskModal" tabindex="-1" aria-labelledby="updateTaskModalLabel" aria-hidden="true">
31
- <div class="modal-dialog">
32
- <div class="modal-content">
33
- <div class="modal-header">
34
- <h5 class="modal-title" id="updateTaskModalLabel">Update Task</h5>
35
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
36
- </div>
37
- <div class="modal-body">
38
- <form id="updateTaskForm" onsubmit="updateTask(event)">
39
- <input type="hidden" id="updateTaskId">
40
- <div class="form-group">
41
- <label for="updateTaskDescription">Task Description</label>
42
- <input type="text" id="updateTaskDescription" class="form-control" required>
43
- </div>
44
- <div class="form-group mt-3">
45
- <label for="updateAssignedTo">Assigned To</label>
46
- <input type="text" id="updateAssignedTo" class="form-control" required>
47
- </div>
48
- <div class="form-group mt-3">
49
- <label for="updateCreatedAt">Created At</label>
50
- <input type="datetime-local" id="updateCreatedAt" class="form-control" required>
51
- </div>
52
- <div class="form-group mt-3">
53
- <label for="updateDueDate">Due Date</label>
54
- <input type="datetime-local" id="updateDueDate" class="form-control" required>
55
- </div>
56
- <div class="form-group mt-3">
57
- <label for="updateStatus">Status</label>
58
- <select id="updateStatus" class="form-control" required>
59
- <option value="pending">Pending</option>
60
- <option value="in-progress">In Progress</option>
61
- <option value="completed">Completed</option>
62
- <option value="overdue">Overdue</option>
63
- </select>
64
- </div>
65
- <button type="submit" class="btn btn-primary mt-3">Update Task</button>
66
- </form>
 
 
67
  </div>
68
  </div>
69
  </div>
70
- </div>
71
 
72
 
73
- <!-- Delete Task Modal -->
74
- <div class="modal fade" id="deleteTaskModal" tabindex="-1" aria-labelledby="deleteTaskModalLabel" aria-hidden="true">
75
- <div class="modal-dialog">
76
- <div class="modal-content">
77
- <div class="modal-header">
78
- <h5 class="modal-title" id="deleteTaskModalLabel">Delete Task</h5>
79
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
80
- </div>
81
- <div class="modal-body">
82
- Are you sure you want to delete this task?
83
- </div>
84
- <div class="modal-footer">
85
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
86
- <button type="button" class="btn btn-danger" onclick="deleteTask()">Delete</button>
 
 
87
  </div>
88
  </div>
89
  </div>
90
- </div>
91
 
92
- <script>
93
- // Pass the user's role and ID dynamically to the JavaScript
94
 
95
- </script>
96
- <script src="../static/js/tasks.js"></script>
97
  {% endblock %}
 
3
  {% block title %}Manage Tasks{% endblock %}
4
 
5
  {% block content %}
6
+ <div class="container mt-4">
7
 
8
+ <!-- Task Table -->
9
+ <div class="card">
10
+ <div class="card-body">
11
+ <table class="table table-striped" id="tasksTable">
12
+ <thead>
13
  <tr>
14
  <th>Description</th>
15
  <th>Assigned To</th>
 
17
  <th>Due Date</th>
18
  <th>Actions</th>
19
  </tr>
20
+ </thead>
21
+ <tbody>
22
  <!-- Tasks will be dynamically loaded here -->
23
+ </tbody>
24
+ </table>
25
+ </div>
26
  </div>
27
  </div>
 
28
 
29
+ <!-- Update Task Modal -->
30
+ <div class="modal fade" id="updateTaskModal" tabindex="-1" aria-labelledby="updateTaskModalLabel"
31
+ aria-hidden="true">
32
+ <div class="modal-dialog">
33
+ <div class="modal-content">
34
+ <div class="modal-header">
35
+ <h5 class="modal-title" id="updateTaskModalLabel">Update Task</h5>
36
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
37
+ </div>
38
+ <div class="modal-body">
39
+ <form id="updateTaskForm" onsubmit="updateTask(event)">
40
+ <input type="hidden" id="updateTaskId">
41
+ <div class="form-group">
42
+ <label for="updateTaskDescription">Task Description</label>
43
+ <input type="text" id="updateTaskDescription" class="form-control" required>
44
+ </div>
45
+ <div class="form-group mt-3">
46
+ <label for="updateAssignedTo">Assigned To</label>
47
+ <input type="text" id="updateAssignedTo" class="form-control" required>
48
+ </div>
49
+ <div class="form-group mt-3">
50
+ <label for="updateCreatedAt">Created At</label>
51
+ <input type="datetime-local" id="updateCreatedAt" class="form-control" required>
52
+ </div>
53
+ <div class="form-group mt-3">
54
+ <label for="updateDueDate">Due Date</label>
55
+ <input type="datetime-local" id="updateDueDate" class="form-control" required>
56
+ </div>
57
+ <div class="form-group mt-3">
58
+ <label for="updateStatus">Status</label>
59
+ <select id="updateStatus" class="form-control" required>
60
+ <option value="pending">Pending</option>
61
+ <option value="in-progress">In Progress</option>
62
+ <option value="completed">Completed</option>
63
+ <option value="overdue">Overdue</option>
64
+ </select>
65
+ </div>
66
+ <button type="submit" class="btn btn-primary mt-3">Update Task</button>
67
+ </form>
68
+ </div>
69
  </div>
70
  </div>
71
  </div>
 
72
 
73
 
74
+ <!-- Delete Task Modal -->
75
+ <div class="modal fade" id="deleteTaskModal" tabindex="-1" aria-labelledby="deleteTaskModalLabel"
76
+ aria-hidden="true">
77
+ <div class="modal-dialog">
78
+ <div class="modal-content">
79
+ <div class="modal-header">
80
+ <h5 class="modal-title" id="deleteTaskModalLabel">Delete Task</h5>
81
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
82
+ </div>
83
+ <div class="modal-body">
84
+ Are you sure you want to delete this task?
85
+ </div>
86
+ <div class="modal-footer">
87
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
88
+ <button type="button" class="btn btn-danger" onclick="deleteTask()">Delete</button>
89
+ </div>
90
  </div>
91
  </div>
92
  </div>
 
93
 
94
+ <script>
95
+ // Pass the user's role and ID dynamically to the JavaScript
96
 
97
+ </script>
98
+ <script src="../static/js/tasks.js"></script>
99
  {% endblock %}
test_main.http CHANGED
@@ -35,7 +35,10 @@ Content-Type: application/json
35
 
36
  {
37
  "group_name": "Test Farm Group",
38
- "farmers": ["farmer_id_1", "farmer_id_2"],
 
 
 
39
  "created_by": "admin_id"
40
  }
41
 
 
35
 
36
  {
37
  "group_name": "Test Farm Group",
38
+ "farmers": [
39
+ "farmer_id_1",
40
+ "farmer_id_2"
41
+ ],
42
  "created_by": "admin_id"
43
  }
44