Merged Omabse's changes.
This commit is contained in:
@@ -162,7 +162,7 @@ const SubjectSection = () => {
|
||||
>
|
||||
<div className="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 md:w-9 md:h-9 text-gray-500 bg-gray-100 rounded-lg dark:bg-gray-800 dark:text-gray-200">
|
||||
<FaReplyAll className="text-base sm:text-xl" />
|
||||
<span class="sr-only">Check icon</span>
|
||||
<span className="sr-only">Check icon</span>
|
||||
</div>
|
||||
<div className="ms-3 text-base sm:text-xl font-bold text-black font-sans">
|
||||
See all
|
||||
|
||||
@@ -60,16 +60,16 @@ const Testimonial = () => {
|
||||
<div className="flex flex-col sm:flex-row justify-around mt-8 h-auto">
|
||||
|
||||
<ScrollReveal direction="up">
|
||||
<div class="max-w-sm p-6 backdrop-blur-sm rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="max-w-sm p-6 backdrop-blur-md rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<svg class="w-7 h-7 text-gray-200 dark:text-gray-400 mb-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M18 5h-.7c.229-.467.349-.98.351-1.5a3.5 3.5 0 0 0-3.5-3.5c-1.717 0-3.215 1.2-4.331 2.481C8.4.842 6.949 0 5.5 0A3.5 3.5 0 0 0 2 3.5c.003.52.123 1.033.351 1.5H2a2 2 0 0 0-2 2v3a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V7a2 2 0 0 0-2-2ZM8.058 5H5.5a1.5 1.5 0 0 1 0-3c.9 0 2 .754 3.092 2.122-.219.337-.392.635-.534.878Zm6.1 0h-3.742c.933-1.368 2.371-3 3.739-3a1.5 1.5 0 0 1 0 3h.003ZM11 13H9v7h2v-7Zm-4 0H2v5a2 2 0 0 0 2 2h3v-7Zm6 0v7h3a2 2 0 0 0 2-2v-5h-5Z"/>
|
||||
</svg>
|
||||
<a href="#">
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white">Need a help in Claim?</h5>
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white">Excellent Dashboards</h5>
|
||||
</a>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Go to this step by step guideline process on how to certify for your weekly benefits:</p>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Our descriptive dashboards give insights into your crop's health and keeps track of your burning expenses</p>
|
||||
<a href="#" class="inline-flex font-medium items-center text-blue-600 hover:underline">
|
||||
See our guideline
|
||||
Check Out
|
||||
<svg class="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
|
||||
</svg>
|
||||
@@ -79,16 +79,16 @@ const Testimonial = () => {
|
||||
|
||||
|
||||
<ScrollReveal direction="up">
|
||||
<div class="max-w-sm p-6 backdrop-blur-sm rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="max-w-sm p-6 backdrop-blur-md rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<svg class="w-7 h-7 text-gray-200 dark:text-gray-400 mb-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M18 5h-.7c.229-.467.349-.98.351-1.5a3.5 3.5 0 0 0-3.5-3.5c-1.717 0-3.215 1.2-4.331 2.481C8.4.842 6.949 0 5.5 0A3.5 3.5 0 0 0 2 3.5c.003.52.123 1.033.351 1.5H2a2 2 0 0 0-2 2v3a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V7a2 2 0 0 0-2-2ZM8.058 5H5.5a1.5 1.5 0 0 1 0-3c.9 0 2 .754 3.092 2.122-.219.337-.392.635-.534.878Zm6.1 0h-3.742c.933-1.368 2.371-3 3.739-3a1.5 1.5 0 0 1 0 3h.003ZM11 13H9v7h2v-7Zm-4 0H2v5a2 2 0 0 0 2 2h3v-7Zm6 0v7h3a2 2 0 0 0 2-2v-5h-5Z"/>
|
||||
</svg>
|
||||
<a href="#">
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white">Need a help in Claim?</h5>
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white"> Crop Disease Prediction </h5>
|
||||
</a>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Go to this step by step guideline process on how to certify for your weekly benefits:</p>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Predict the possible crop diseases based on their shown symptoms</p>
|
||||
<a href="#" class="inline-flex font-medium items-center text-blue-600 hover:underline">
|
||||
See our guideline
|
||||
Check Out
|
||||
<svg class="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
|
||||
</svg>
|
||||
@@ -97,16 +97,16 @@ const Testimonial = () => {
|
||||
</ScrollReveal>
|
||||
|
||||
<ScrollReveal direction="up">
|
||||
<div class="max-w-sm p-6 backdrop-blur-sm rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="max-w-sm p-6 backdrop-blur-md rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
|
||||
<svg class="w-7 h-7 text-gray-200 dark:text-gray-400 mb-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M18 5h-.7c.229-.467.349-.98.351-1.5a3.5 3.5 0 0 0-3.5-3.5c-1.717 0-3.215 1.2-4.331 2.481C8.4.842 6.949 0 5.5 0A3.5 3.5 0 0 0 2 3.5c.003.52.123 1.033.351 1.5H2a2 2 0 0 0-2 2v3a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1V7a2 2 0 0 0-2-2ZM8.058 5H5.5a1.5 1.5 0 0 1 0-3c.9 0 2 .754 3.092 2.122-.219.337-.392.635-.534.878Zm6.1 0h-3.742c.933-1.368 2.371-3 3.739-3a1.5 1.5 0 0 1 0 3h.003ZM11 13H9v7h2v-7Zm-4 0H2v5a2 2 0 0 0 2 2h3v-7Zm6 0v7h3a2 2 0 0 0 2-2v-5h-5Z"/>
|
||||
</svg>
|
||||
<a href="#">
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white">Need a help in Claim?</h5>
|
||||
<h5 class="mb-2 text-2xl font-semibold tracking-tight text-gray-50 dark:text-white">Crop Planner</h5>
|
||||
</a>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Go to this step by step guideline process on how to certify for your weekly benefits:</p>
|
||||
<p class="mb-3 font-normal text-gray-50 dark:text-gray-400">Based on previous season's crop and used pertilizers and pesticides, plan what crops would best suit the present state of your soil</p>
|
||||
<a href="#" class="inline-flex font-medium items-center text-blue-600 hover:underline">
|
||||
See our guideline
|
||||
Check Out
|
||||
<svg class="w-3 h-3 ms-2.5 rtl:rotate-[270deg]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11v4.833A1.166 1.166 0 0 1 13.833 17H2.167A1.167 1.167 0 0 1 1 15.833V4.167A1.166 1.166 0 0 1 2.167 3h4.618m4.447-2H17v5.768M9.111 8.889l7.778-7.778"/>
|
||||
</svg>
|
||||
|
||||
@@ -109,7 +109,7 @@ const ResetPassword = () => {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-base px-5 py-2.5 mb-2 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-900"
|
||||
className="focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-base px-5 py-2.5 mb-2 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-900"
|
||||
>
|
||||
Reset Password
|
||||
</button>
|
||||
@@ -127,5 +127,4 @@ const ResetPassword = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResetPassword;
|
||||
|
||||
@@ -1,202 +1,23 @@
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Piechart from "../../components/monitoring charts/Piechart";
|
||||
import TotalSpent from "../../components/TotalSpent";
|
||||
import FarmList from "../../components/FarmList";
|
||||
import AddFarm from "./Farm/AddFarm";
|
||||
|
||||
const Dashboard = () => {
|
||||
return (
|
||||
<>
|
||||
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<div className="flex flex-col justify-center items-center mb-4">
|
||||
<h2 className="text-2xl font-bold font-sans border-b-2 py-2">
|
||||
Upcoming Sessions{" "}
|
||||
</h2>
|
||||
<div className="bg-gray-300 w-full h-52 rounded-lg"></div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<h3 className="text-lg font-medium">Recent Activity</h3>
|
||||
<p className="text-gray-500 text-sm mt-2">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-4 mt-4">
|
||||
<input type="range" className="w-full h-auto" readOnly:true/>
|
||||
<div className="bg-gray-100 rounded-lg p-4 flex justify-between items-center">
|
||||
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6 text-green-500"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M13 7l5 5m0 0l-5 5m5-5H6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="ml-2 font-medium">Topup</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="text-gray-500 text-sm">06:24:45 AM</span>
|
||||
<span className="ml-2 text-green-500 text-sm">+$5,553</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-lg font-medium">Weekly Summary</h3>
|
||||
<div className="grid grid-cols-8 gap-2 mt-4">
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Sun</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Mon</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Tue</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Wed</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Thu</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Fri</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Sat</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col justify-between items-center bg-gray-100 rounded-lg p-2">
|
||||
<span className="text-gray-500 text-xs">Completed</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-8 gap-2 mt-2">
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-16"></div>
|
||||
<div className="bg-gray-300 h-4"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-16"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-20"></div>
|
||||
<div className="bg-gray-300 h-8"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-12"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-12"></div>
|
||||
<div className="bg-gray-300 h-12"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-20"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-24"></div>
|
||||
<div className="bg-gray-300 h-4"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-8"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-16"></div>
|
||||
<div className="bg-gray-300 h-12"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-16"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-16"></div>
|
||||
<div className="bg-gray-300 h-4"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-24"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-green-500 rounded-t-lg h-8"></div>
|
||||
<div className="bg-gray-300 h-16"></div>
|
||||
<div className="bg-red-500 rounded-b-lg h-20"></div>
|
||||
</div>
|
||||
<div
|
||||
className="col-span-1 flex flex-col justify-between items-center rounded-lg p-2"
|
||||
style={{ height: "100px" }}
|
||||
>
|
||||
<div className="bg-gray-300 h-24"></div>
|
||||
<div className="bg-gray-300 h-24"></div>
|
||||
<div className="bg-gray-300 h-24"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-lg font-medium">Notifications</h3>
|
||||
<div className="grid grid-cols-1 gap-4 mt-4">
|
||||
<div className="bg-gray-100 rounded-lg p-4 flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6 text-green-500"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M13 7l5 5m0 0l-5 5m5-5H6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="ml-2 font-medium">Topup</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="text-gray-500 text-sm">06:24:45 AM</span>
|
||||
<span className="ml-2 text-green-500 text-sm">+$5,553</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 mt-4">
|
||||
<div className="bg-gray-100 rounded-lg p-4 flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6 text-green-500"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M13 7l5 5m0 0l-5 5m5-5H6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="ml-2 font-medium">Topup</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="text-gray-500 text-sm">06:24:45 AM</span>
|
||||
<span className="ml-2 text-green-500 text-sm">+$5,553</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<div className="mb-4 flex justify-end space-x-4">
|
||||
<AddFarm />
|
||||
</div>
|
||||
</>
|
||||
|
||||
<div className="mb-4 flex space-x-4">
|
||||
<Piechart />
|
||||
<TotalSpent />
|
||||
</div>
|
||||
<FarmList />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const AddCrop = ({ farmId }) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
const [farm, setFarm] = useState(farmId);
|
||||
const [harvestDate, setHarvestDate] = useState("");
|
||||
const [growthStage, setGrowthStage] = useState("Planted");
|
||||
|
||||
const [healthStatus, setHealthStatus] = useState("");
|
||||
const [image, setImage] = useState(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState("");
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setUploading(true);
|
||||
setError("");
|
||||
setSuccess("");
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("name", name);
|
||||
formData.append("farm", farm);
|
||||
formData.append("harvestDate", harvestDate);
|
||||
formData.append("growthStage", growthStage);
|
||||
formData.append("healthStatus", healthStatus);
|
||||
if (image) {
|
||||
formData.append("image", image);
|
||||
}
|
||||
console.log(formData);
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8000/api/v1/crop`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: formData,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to create crop");
|
||||
}
|
||||
setSuccess("Crop created successfully!");
|
||||
// Reset form fields
|
||||
setName("");
|
||||
setFarm("");
|
||||
setHarvestDate("");
|
||||
setGrowthStage("");
|
||||
setHealthStatus("");
|
||||
setImage(null);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="block text-white bg-green-500 hover:bg-green-600 focus:ring-4 focus:outline-none focus:ring-green-300 rounded-lg text-sm px-5 py-2.5 text-center h-10 font-extrabold"
|
||||
type="button"
|
||||
>
|
||||
Add New Crop
|
||||
</button>
|
||||
|
||||
{isModalOpen && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center overflow-y-auto overflow-x-hidden">
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
></div>
|
||||
{/* Modal Content */}
|
||||
<div className="relative w-full max-w-2xl mx-4">
|
||||
<div className="relative bg-white rounded-xl shadow-lg">
|
||||
{/* Decorative SVG Elements */}
|
||||
<div className="absolute right-0 top-0 h-full w-48 overflow-hidden pointer-events-none">
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-16 fill-green-100"
|
||||
>
|
||||
<path d="M0,0 Q100,200 0,400 Q100,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-8 fill-green-200/40"
|
||||
>
|
||||
<path d="M0,0 Q80,200 0,400 Q80,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-12 top-20 w-16 h-16 fill-green-300/30"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-16 top-48 w-12 h-12 fill-green-400/20"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
{/* Modal Header */}
|
||||
<div className="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
|
||||
<h3 className="text-2xl font-semibold text-gray-800">
|
||||
Add New Crop
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 inline-flex justify-center items-center"
|
||||
>
|
||||
<svg
|
||||
className="w-3 h-3"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 14 14"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
{/* Modal Body */}
|
||||
<div className="p-4 md:p-5">
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Crop Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="Rice"
|
||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="harvestDate"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Harvest Date
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
id="harvestDate"
|
||||
value={harvestDate}
|
||||
onChange={(e) => setHarvestDate(e.target.value)}
|
||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="growthStage"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Growth Stage
|
||||
</label>
|
||||
<select
|
||||
id="growthStage"
|
||||
value={growthStage}
|
||||
onChange={(e) => setGrowthStage(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 rounded-md border-gray-300 shadow-sm"
|
||||
required
|
||||
>
|
||||
<option value="Planted">Planted</option>
|
||||
<option value="Growing">Growing</option>
|
||||
<option value="Ready to Harvest">Ready to Harvest</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="healthStatus"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Health Status
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="healthStatus"
|
||||
value={healthStatus}
|
||||
onChange={(e) => setHealthStatus(e.target.value)}
|
||||
placeholder="Healthy"
|
||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="image"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Crop Image
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
id="image"
|
||||
accept="image/*"
|
||||
onChange={(e) => setImage(e.target.files[0])}
|
||||
className="mt-1 block w-full"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition"
|
||||
>
|
||||
{uploading ? "Uploading..." : "Create Crop"}
|
||||
</button>
|
||||
</div>
|
||||
{error && <p className="text-red-600">{error}</p>}
|
||||
{success && <p className="text-green-600">{success}</p>}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddCrop;
|
||||
@@ -0,0 +1,250 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const AddFarm = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [farmName, setFarmName] = useState("");
|
||||
const [location, setLocation] = useState("");
|
||||
const [waterContent, setWaterContent] = useState("");
|
||||
const [sizeContent, setSizeContent] = useState("");
|
||||
const [soilType, setSoilType] = useState("");
|
||||
const [error, setError] = useState(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
const navigator = useNavigate();
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const farmData = {
|
||||
name: farmName,
|
||||
location,
|
||||
waterContent,
|
||||
soilType,
|
||||
size: sizeContent,
|
||||
};
|
||||
|
||||
console.log(farmData);
|
||||
|
||||
try {
|
||||
const response = await fetch("http://localhost:8000/api/v1/farm", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(farmData),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to add farm");
|
||||
}
|
||||
|
||||
navigator("farmpage");
|
||||
setSuccess(true);
|
||||
setError(null);
|
||||
setIsModalOpen(false);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
setSuccess(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="block text-white bg-green-600 hover:bg-green-700 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center"
|
||||
type="button"
|
||||
>
|
||||
Add New Farm
|
||||
</button>
|
||||
|
||||
{isModalOpen && (
|
||||
<div className="fixed inset-0 z-50 overflow-y-auto overflow-x-hidden flex items-center justify-center">
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
></div>
|
||||
|
||||
<div className="relative w-full max-w-2xl mx-4">
|
||||
<div className="relative bg-white rounded-xl shadow-lg">
|
||||
{/* Decorative Leaves */}
|
||||
<div className="absolute right-0 top-0 h-full w-48 overflow-hidden pointer-events-none">
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-16 fill-green-100"
|
||||
>
|
||||
<path d="M0,0 Q100,200 0,400 Q100,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-8 fill-green-200/40"
|
||||
>
|
||||
<path d="M0,0 Q80,200 0,400 Q80,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-12 top-20 w-16 h-16 fill-green-300/30"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-16 top-48 w-12 h-12 fill-green-400/20"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Modal Header */}
|
||||
<div className="flex items-center justify-between p-4 md:p-5 border-b rounded-t border-gray-200">
|
||||
<h3 className="text-2xl font-semibold text-gray-800">
|
||||
Add New Farm
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 inline-flex justify-center items-center"
|
||||
>
|
||||
<svg
|
||||
className="w-3 h-3"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 14 14"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Modal Body */}
|
||||
<div className="p-4 md:p-5">
|
||||
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="farmName"
|
||||
className="block text-sm font-semibold text-gray-700 mb-2"
|
||||
>
|
||||
Farm Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="farmName"
|
||||
value={farmName}
|
||||
onChange={(e) => setFarmName(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-lg border border-gray-200 focus:ring-2 focus:ring-green-400 focus:border-transparent transition duration-200 ease-in-out bg-white/80"
|
||||
placeholder="Enter farm name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="location"
|
||||
className="block text-sm font-semibold text-gray-700 mb-2"
|
||||
>
|
||||
Location
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="location"
|
||||
value={location}
|
||||
onChange={(e) => setLocation(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-lg border border-gray-200 focus:ring-2 focus:ring-green-400 focus:border-transparent transition duration-200 ease-in-out bg-white/80"
|
||||
placeholder="Enter location"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="waterContent"
|
||||
className="block text-sm font-semibold text-gray-700 mb-2"
|
||||
>
|
||||
Water Content
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="waterContent"
|
||||
value={waterContent}
|
||||
onChange={(e) => setWaterContent(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-lg border border-gray-200 focus:ring-2 focus:ring-green-400 focus:border-transparent transition duration-200 ease-in-out bg-white/80"
|
||||
placeholder="Enter water content"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="waterContent"
|
||||
className="block text-sm font-semibold text-gray-700 mb-2"
|
||||
>
|
||||
Size of Land
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="waterContent"
|
||||
value={sizeContent}
|
||||
onChange={(e) => setSizeContent(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-lg border border-gray-200 focus:ring-2 focus:ring-green-400 focus:border-transparent transition duration-200 ease-in-out bg-white/80"
|
||||
placeholder="Enter water content"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="soilType"
|
||||
className="block text-sm font-semibold text-gray-700 mb-2"
|
||||
>
|
||||
Soil Type
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="soilType"
|
||||
value={soilType}
|
||||
onChange={(e) => setSoilType(e.target.value)}
|
||||
className="w-full px-4 py-3 rounded-lg border border-gray-200 focus:ring-2 focus:ring-green-400 focus:border-transparent transition duration-200 ease-in-out bg-white/80"
|
||||
placeholder="Enter soil type"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-green-600 hover:bg-green-700 text-white font-semibold py-3 px-6 rounded-lg transition duration-200 ease-in-out transform hover:scale-[1.02] focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-offset-2"
|
||||
>
|
||||
Add Farm
|
||||
</button>
|
||||
|
||||
{error && (
|
||||
<p className="mt-4 text-red-500 text-sm bg-red-50 p-3 rounded-lg">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
{success && (
|
||||
<p className="mt-4 text-green-500 text-sm bg-green-50 p-3 rounded-lg">
|
||||
Farm added successfully!
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddFarm;
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
const CropTable = ({ farmId }) => {
|
||||
const [crops, setCrops] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
useEffect(() => {
|
||||
const fetchCrops = async () => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`http://localhost:8000/api/v1/crop/farm/${farmId}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch crops");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setCrops(data || []);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCrops();
|
||||
}, [farmId]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[400px]">
|
||||
Loading crops...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mt-4">
|
||||
<p className="text-red-600">Error: {error}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (crops.length === 0) {
|
||||
return (
|
||||
<div className="text-center py-8 bg-gray-50 rounded-lg">
|
||||
<h2 className="text-xl font-semibold text-gray-600">No crops found</h2>
|
||||
<p className="text-gray-500 mt-2">
|
||||
Start by adding some crops to your farm
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-lg border border-gray-200 bg-white shadow">
|
||||
<div className="px-4 py-5 sm:px-6">
|
||||
<h1 className="text-2xl font-semibold text-gray-900">Crops Table</h1>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-sm font-medium text-gray-500 uppercase tracking-wider">
|
||||
Image
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-sm font-medium text-gray-500 uppercase tracking-wider">
|
||||
Name
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-sm font-medium text-gray-500 uppercase tracking-wider">
|
||||
Growth Stage
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-sm font-medium text-gray-500 uppercase tracking-wider">
|
||||
Health Status
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-sm font-medium text-gray-500 uppercase tracking-wider">
|
||||
Harvest Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200">
|
||||
{crops.map((crop) => (
|
||||
<tr key={crop._id} className="hover:bg-gray-50">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="h-12 w-12 rounded-full overflow-hidden">
|
||||
{crop.image ? (
|
||||
<img
|
||||
src={crop.image}
|
||||
alt={crop.name}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="h-full w-full bg-gray-200 flex items-center justify-center">
|
||||
<span className="text-gray-500 text-xs">No image</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm font-medium text-gray-900">
|
||||
{crop.name}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span
|
||||
className="inline-flex px-2 py-1 text-sm font-medium rounded-full"
|
||||
style={{
|
||||
backgroundColor:
|
||||
crop.growthStage === "Planted"
|
||||
? "rgb(220, 252, 231)"
|
||||
: crop.growthStage === "Growing"
|
||||
? "rgb(254, 249, 195)"
|
||||
: "rgb(224, 242, 254)",
|
||||
color:
|
||||
crop.growthStage === "Planted"
|
||||
? "rgb(22, 101, 52)"
|
||||
: crop.growthStage === "Growing"
|
||||
? "rgb(113, 63, 18)"
|
||||
: "rgb(3, 105, 161)",
|
||||
}}
|
||||
>
|
||||
{crop.growthStage}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm text-gray-900">
|
||||
{crop.healthStatus}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm text-gray-900">
|
||||
{new Date(crop.harvestDate).toLocaleDateString()}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CropTable;
|
||||
@@ -0,0 +1,243 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const AddCrop = ({ farmId }) => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
const [farm, setFarm] = useState(farmId);
|
||||
const [harvestDate, setHarvestDate] = useState("");
|
||||
const [growthStage, setGrowthStage] = useState("Planted");
|
||||
const [healthStatus, setHealthStatus] = useState("");
|
||||
const [image, setImage] = useState(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState("");
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setUploading(true);
|
||||
setError("");
|
||||
setSuccess("");
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("name", name);
|
||||
formData.append("farm", farm);
|
||||
formData.append("harvestDate", harvestDate);
|
||||
formData.append("growthStage", growthStage);
|
||||
formData.append("healthStatus", healthStatus);
|
||||
if (image) {
|
||||
formData.append("image", image);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8000/api/v1/crop`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: formData,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to create crop");
|
||||
}
|
||||
setSuccess("Crop created successfully!");
|
||||
setName("");
|
||||
setFarm("");
|
||||
setHarvestDate("");
|
||||
setGrowthStage("");
|
||||
setHealthStatus("");
|
||||
setImage(null);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
className="block text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center"
|
||||
type="button"
|
||||
>
|
||||
Add New Crop
|
||||
</button>
|
||||
|
||||
{isModalOpen && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center overflow-y-auto overflow-x-hidden">
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
></div>
|
||||
<div className="relative w-full max-w-3xl mx-4">
|
||||
<div className="relative bg-white rounded-xl shadow-lg">
|
||||
{/* Decorative SVG Elements - Moved further right */}
|
||||
<div className="z-0 absolute right-0 top-0 h-full w-32 overflow-hidden pointer-events-none">
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-16 fill-green-100"
|
||||
>
|
||||
<path d="M0,0 Q100,200 0,400 Q100,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 200 800"
|
||||
className="absolute right-0 h-full transform translate-x-8 fill-green-200/40"
|
||||
>
|
||||
<path d="M0,0 Q80,200 0,400 Q80,600 0,800 L200,800 L200,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-12 top-20 w-16 h-16 fill-green-300/30"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="absolute right-16 top-48 w-12 h-12 fill-green-400/20"
|
||||
>
|
||||
<path d="M50,0 Q100,50 50,100 Q0,50 50,0 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Modal Header */}
|
||||
<div className="flex items-center justify-between p-6 border-b rounded-t border-gray-200">
|
||||
<h3 className="text-2xl font-semibold text-gray-800">
|
||||
Add New Crop
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm z-100 w-8 h-8 inline-flex justify-center items-center"
|
||||
>
|
||||
<svg
|
||||
className="w-3 h-3"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 14 14"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Modal Body */}
|
||||
<div className="p-6">
|
||||
<form onSubmit={handleSubmit} className="space-y-6 max-w-2xl">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium text-gray-700 mb-2"
|
||||
>
|
||||
Crop Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="Rice"
|
||||
className="block w-full px-4 py-3 rounded-lg border border-gray-300 shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="harvestDate"
|
||||
className="block text-sm font-medium text-gray-700 mb-2"
|
||||
>
|
||||
Harvest Date
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
id="harvestDate"
|
||||
value={harvestDate}
|
||||
onChange={(e) => setHarvestDate(e.target.value)}
|
||||
className="block w-full px-4 py-3 rounded-lg border border-gray-300 shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="growthStage"
|
||||
className="block text-sm font-medium text-gray-700 mb-2"
|
||||
>
|
||||
Growth Stage
|
||||
</label>
|
||||
<select
|
||||
id="growthStage"
|
||||
value={growthStage}
|
||||
onChange={(e) => setGrowthStage(e.target.value)}
|
||||
className="block w-full px-4 py-3 rounded-lg border border-gray-300 shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
>
|
||||
<option value="Planted">Planted</option>
|
||||
<option value="Growing">Growing</option>
|
||||
<option value="Ready to Harvest">Ready to Harvest</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="healthStatus"
|
||||
className="block text-sm font-medium text-gray-700 mb-2"
|
||||
>
|
||||
Health Status
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="healthStatus"
|
||||
value={healthStatus}
|
||||
onChange={(e) => setHealthStatus(e.target.value)}
|
||||
placeholder="Healthy"
|
||||
className="block w-full px-4 py-3 rounded-lg border border-gray-300 shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="image"
|
||||
className="block text-sm font-medium text-gray-700 mb-2"
|
||||
>
|
||||
Crop Image
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
id="image"
|
||||
accept="image/*"
|
||||
onChange={(e) => setImage(e.target.files[0])}
|
||||
className="block w-full px-4 py-3 rounded-lg border border-gray-300 shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pt-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full z-100 bg-green-600 text-white px-6 py-3 rounded-lg hover:bg-green-700 transition duration-200 font-medium"
|
||||
>
|
||||
{uploading ? "Uploading..." : "Create Crop"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error && <p className="text-red-600 mt-4">{error}</p>}
|
||||
{success && <p className="text-green-600 mt-4">{success}</p>}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddCrop;
|
||||
@@ -0,0 +1,67 @@
|
||||
import AddCrop from "./AddCrop";
|
||||
|
||||
const Farm = ({ farmData, farmId }) => {
|
||||
console.log("Farm id is : ", farmId);
|
||||
return (
|
||||
<div className="w-full ">
|
||||
<div className="flex justify-between">
|
||||
<h1 className="text-2xl font-bold mb-4 m-3">{farmData.name}</h1>
|
||||
<AddCrop farmId={farmId}></AddCrop>
|
||||
</div>
|
||||
|
||||
<table className="min-w-full text-left">
|
||||
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||
<tr>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Farm Name
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Location
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Type
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Size (acres)
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Water Content
|
||||
</th>
|
||||
<th scope="col" className="px-6 py-3">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr className="odd:bg-white even:bg-gray-50 dark:odd:bg-gray-900 dark:even:bg-gray-800 border-b dark:border-gray-700">
|
||||
{/* Clicking on the name cell can navigate to a more detailed view if needed */}
|
||||
<td
|
||||
className="px-6 py-4 cursor-pointer hover:text-blue-600 transition"
|
||||
onClick={() => {
|
||||
// Navigate to a detailed view for this farm if desired
|
||||
navigate(`farmpage/${farmData._id}`);
|
||||
}}
|
||||
>
|
||||
{farmData.name}
|
||||
</td>
|
||||
<td className="px-6 py-4">{farmData.location}</td>
|
||||
<td className="px-6 py-4">{farmData.soilType}</td>
|
||||
<td className="px-6 py-4">{farmData.size}</td>
|
||||
<td className="px-6 py-4">{farmData.waterContent}</td>
|
||||
<td className="px-6 py-4">
|
||||
<button
|
||||
onClick={() =>
|
||||
navigate(`/user/dashboard/updatefarm?farmId=${farmData._id}`)
|
||||
}
|
||||
className="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Farm;
|
||||
@@ -0,0 +1,67 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import Farm from "./Farm";
|
||||
import CropTable from "./CropTable";
|
||||
|
||||
export default function FarmPage() {
|
||||
const { farmId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [farmData, setFarmData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetching() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`http://localhost:8000/api/v1/farm/${farmId}`,
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
const jsonData = await response.json();
|
||||
console.log(jsonData);
|
||||
setFarmData(jsonData);
|
||||
} catch (error) {
|
||||
console.error("Error fetching farm data: ", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetching();
|
||||
}, [farmId]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<p>Loading farm data...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!farmData) {
|
||||
return (
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<p>No farm data found.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
console.log("My farm id is : ", farmId);
|
||||
|
||||
return (
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
{/* Back Button */}
|
||||
|
||||
<div className="mb-4 flex justify-end">
|
||||
<Farm farmData={farmData} farmId={farmId}></Farm>
|
||||
</div>
|
||||
<div>
|
||||
<CropTable farmId={farmId}></CropTable>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const UpdateFarm = () => {
|
||||
const [farmName, setFarmName] = useState("");
|
||||
const [location, setLocation] = useState("");
|
||||
const [waterContent, setWaterContent] = useState("");
|
||||
const [soilType, setSoilType] = useState("");
|
||||
const [sizeContent, setSizeContent] = useState("");
|
||||
const [error, setError] = useState(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const farmData = {
|
||||
name: farmName,
|
||||
location,
|
||||
waterContent,
|
||||
soilType,
|
||||
size: sizeContent,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
"http://localhost:8000/api/v1/farm/67b9b3a1b68365aa35ae0e5f",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(farmData),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to Update the farm");
|
||||
}
|
||||
|
||||
setSuccess(true);
|
||||
setError(null);
|
||||
// navigate to the dashboard:
|
||||
navigate("/dashboard");
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
setSuccess(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<h1 className="w-full text-center text-2xl font-bold my-5">
|
||||
Update farm
|
||||
</h1>
|
||||
|
||||
<div className="mb-4 flex justify-end space-x-4">
|
||||
<form className="max-w-md mx-auto w-80" onSubmit={handleSubmit}>
|
||||
<div className="mb-5">
|
||||
<label
|
||||
htmlFor="farmName"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Farm Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="farmName"
|
||||
value={farmName}
|
||||
onChange={(e) => setFarmName(e.target.value)}
|
||||
className="shadow-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<label
|
||||
htmlFor="location"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Location
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="location"
|
||||
value={location}
|
||||
onChange={(e) => setLocation(e.target.value)}
|
||||
className="shadow-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<label
|
||||
htmlFor="waterContent"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Water Content
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="waterContent"
|
||||
value={waterContent}
|
||||
onChange={(e) => setWaterContent(e.target.value)}
|
||||
className="shadow-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<label
|
||||
htmlFor="soilType"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Soil Type
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="soilType"
|
||||
value={soilType}
|
||||
onChange={(e) => setSoilType(e.target.value)}
|
||||
className="shadow-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<label
|
||||
htmlFor="soilType"
|
||||
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Size of Land
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="soilType"
|
||||
value={sizeContent}
|
||||
onChange={(e) => setSizeContent(e.target.value)}
|
||||
className="shadow-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||
>
|
||||
Add Farm
|
||||
</button>
|
||||
{error && <p className="mt-4 text-red-500 text-sm">{error}</p>}
|
||||
{success && (
|
||||
<p className="mt-4 text-green-500 text-sm">
|
||||
Farm Updated successfully!
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateFarm;
|
||||
@@ -36,7 +36,7 @@ const MainUserPanel = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto p-4 ">
|
||||
<div className="flex items-center mb-4 md:hidden">
|
||||
<div className="flex items-center mb-4 md:hidden ">
|
||||
<img
|
||||
src={`${user.avatar}`}
|
||||
alt="Profile Picture"
|
||||
@@ -45,7 +45,7 @@ const MainUserPanel = () => {
|
||||
<span className="text-lg font-medium">Hello, {user.name}</span>
|
||||
</div>
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="w-1.5/12 md:w-3/12 bg-white rounded-lg shadow p-4">
|
||||
<div className="w-1.5/12 bg-white md:w-3/12 rounded-lg shadow p-4">
|
||||
<div className="hidden md:flex items-center mb-4">
|
||||
<img
|
||||
src={`${user.avatar}`}
|
||||
@@ -198,7 +198,7 @@ const MainUserPanel = () => {
|
||||
<button
|
||||
data-collapse-toggle="navbar-user"
|
||||
type="button"
|
||||
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
|
||||
className="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
|
||||
aria-controls="navbar-user"
|
||||
aria-expanded="false"
|
||||
>
|
||||
@@ -221,30 +221,30 @@ const MainUserPanel = () => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div className="mb-4">
|
||||
<img
|
||||
src={`${user.avatar}`}
|
||||
alt="Profile Picture"
|
||||
class="rounded-full w-24 h-24 mx-auto"
|
||||
className="rounded-full w-24 h-24 mx-auto"
|
||||
/>
|
||||
<h4 class="text-lg font-medium mt-2">{user.name}</h4>
|
||||
{/* <span class="text-gray-500 text-sm">@thomasdox</span> */}
|
||||
<p class="text-gray-500 text-sm mt-2">
|
||||
<h4 className="text-lg font-medium mt-2">{user.name}</h4>
|
||||
{/* <span className="text-gray-500 text-sm">@thomasdox</span> */}
|
||||
<p className="text-gray-500 text-sm mt-2">
|
||||
Join on {user.createdAt && user.createdAt.substring(0, 10)}
|
||||
</p>
|
||||
<p class="text-gray-500 text-sm mt-2">
|
||||
<p className="text-gray-500 text-sm mt-2">
|
||||
{user.description == null &&
|
||||
"I am a Senior Software Engineer at Google and also mentored 50+ students to get there dream job."}
|
||||
</p>
|
||||
<div class="flex justify-center mt-4">
|
||||
<button class="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded mr-2">
|
||||
<div className="flex justify-center mt-4">
|
||||
<button className="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded mr-2">
|
||||
<FaHome className="text-lg font-extrabold" />
|
||||
</button>
|
||||
<button class="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded mr-2">
|
||||
<button className="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded mr-2">
|
||||
<IoMdSettings className="text-lg font-extrabold" />
|
||||
</button>
|
||||
<button
|
||||
class="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
className="bg-gray-300 hover:bg-gray-400 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
onClick={handleLogOut}
|
||||
>
|
||||
<RiLogoutBoxLine className="text-lg font-extrabold" />
|
||||
|
||||
@@ -55,45 +55,43 @@ const MentorSessionCard = ({ session }) => {
|
||||
const realTimeString = timeStringtoRealTime(schduledTime);
|
||||
|
||||
return (
|
||||
<>
|
||||
<li class="flex flex-col gap-5 w-full h-auto max-h-28 px-3 py-1 rounded-md hover:bg-slate-100 border-b-2">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-8 h-8 rounded-full"
|
||||
src="/images/profile.jpeg"
|
||||
alt="Neil image"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0 ms-4">
|
||||
<p class="text-sm font-medium text-gray-900 truncate dark:text-white">
|
||||
{user.role === "user" ? mentorName : studentName}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500 truncate dark:text-gray-400">
|
||||
{user.role === "user" ? mentorMail : studentMail}
|
||||
<li className="flex flex-col gap-5 w-full h-auto max-h-28 px-3 py-1 rounded-md hover:bg-slate-100 border-b-2">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
className="w-8 h-8 rounded-full"
|
||||
src="/images/profile.jpeg"
|
||||
alt="Neil image"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 ms-4">
|
||||
<p className="text-sm font-medium text-gray-900 truncate dark:text-white">
|
||||
{user.role === "user" ? mentorName : studentName}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 truncate dark:text-gray-400">
|
||||
{user.role === "user" ? mentorMail : studentMail}
|
||||
</p>
|
||||
</div>
|
||||
<div className="inline-flex items-center text-base font-semibold text-gray-900 dark:text-white">
|
||||
₹{amountPaid}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center">
|
||||
<div>
|
||||
<p className="text-gray-500">
|
||||
{timeStringToDayName(schduledTime)},
|
||||
{realTimeString.substring(21, 26) +
|
||||
" " +
|
||||
realTimeString.substring(30)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="inline-flex items-center text-base font-semibold text-gray-900 dark:text-white">
|
||||
₹{amountPaid}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="flex items-center">
|
||||
<div>
|
||||
<p className="text-gray-500">
|
||||
{timeStringToDayName(schduledTime)},
|
||||
{realTimeString.substring(21, 26) +
|
||||
" " +
|
||||
realTimeString.substring(30)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<p className="text-gray-500">{realTimeString.substring(0, 18)}</p>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<p className="text-gray-500">{realTimeString.substring(0, 18)}</p>
|
||||
</div>
|
||||
</li>
|
||||
</>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// MonitoringPage.jsx
|
||||
import React from "react";
|
||||
import MetricsCard from "../../components/monitoring charts/MetricCard";
|
||||
import PerformanceChart from "../../components/monitoring charts/PerformanceChart";
|
||||
import AlertsPanel from "../../components/monitoring charts/AlertsPanel";
|
||||
import ActivityFeed from "../../components/monitoring charts/ActivityField";
|
||||
import Piechart from "../../components/monitoring charts/Piechart";
|
||||
|
||||
const MonitoringPage = () => {
|
||||
return (
|
||||
<div className="w-full bg-white rounded-lg shadow p-4">
|
||||
<div className="p-6">
|
||||
{/* Summary Metrics */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
|
||||
<MetricsCard title="Active Farms" value="12" />
|
||||
<MetricsCard title="Total Yield" value="3500 kg" />
|
||||
<MetricsCard title="Alerts" value="3" />
|
||||
<MetricsCard title="Uptime" value="99.9%" />
|
||||
</div>
|
||||
|
||||
{/* Performance Trend Chart */}
|
||||
<div className="mb-6 bg-white p-4 rounded-lg shadow">
|
||||
<h2 className="text-lg font-semibold mb-2">Performance Trend</h2>
|
||||
<PerformanceChart />
|
||||
</div>
|
||||
<div className="mb-6 bg-white p-4 rounded-lg shadow">
|
||||
<h2 className="text-lg font-semibold mb-2">Performance Trend</h2>
|
||||
<Piechart></Piechart>
|
||||
</div>
|
||||
|
||||
{/* Alerts and Activity Feed */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="bg-white p-4 rounded-lg shadow">
|
||||
<h2 className="text-lg font-semibold mb-2">Alerts</h2>
|
||||
<AlertsPanel />
|
||||
</div>
|
||||
<div className="bg-white p-4 rounded-lg shadow">
|
||||
<h2 className="text-lg font-semibold mb-2">Recent Activity</h2>
|
||||
<ActivityFeed />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MonitoringPage;
|
||||
@@ -95,15 +95,15 @@ const Settings = () => {
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={handleAvatar}>
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<img src={formData.avatar && `${formData.avatar}`} alt="" />
|
||||
<label
|
||||
for="dropzone-file"
|
||||
class="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600"
|
||||
htmlFor="dropzone-file"
|
||||
className="flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600"
|
||||
>
|
||||
<div class="flex flex-col items-center justify-center pt-5 pb-6 ">
|
||||
<div className="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<svg
|
||||
class="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
|
||||
className="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
@@ -111,24 +111,24 @@ const Settings = () => {
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
|
||||
/>
|
||||
</svg>
|
||||
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
{avatar ? (
|
||||
<span class="font-semibold">
|
||||
Avatar uploaded successfulky
|
||||
<span className="font-semibold">
|
||||
Avatar uploaded successfully
|
||||
</span>
|
||||
) : (
|
||||
<span class="font-semibold">
|
||||
<span className="font-semibold">
|
||||
Click to upload and press Upload button
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
SVG, PNG, JPG or GIF (MAX. 800x400px)
|
||||
</p>
|
||||
<button
|
||||
@@ -141,7 +141,7 @@ const Settings = () => {
|
||||
<input
|
||||
id="dropzone-file"
|
||||
type="file"
|
||||
class="hidden"
|
||||
className="hidden"
|
||||
onChange={(e) => {
|
||||
setAvatar(e.target.files[0]);
|
||||
//console.log(e.target.files[0]);
|
||||
|
||||
Reference in New Issue
Block a user