Skip to content

Commit

Permalink
Merge pull request #991 from haseebzaki-07/new_branch_7
Browse files Browse the repository at this point in the history
Add agriproducts page
  • Loading branch information
manikumarreddyu authored Nov 10, 2024
2 parents 638b0fc + a2abfbe commit 88246fc
Show file tree
Hide file tree
Showing 16 changed files with 479 additions and 36 deletions.
File renamed without changes
Binary file added frontend/public/rent-assets/plow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added frontend/public/rent-assets/seeder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/rent-assets/sprayer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added frontend/public/rent-assets/tractor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/AgroRentAI/HeroSectionRent.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { motion } from 'framer-motion';
import img1 from "./rent-assets/tp.png";
import img1 from "/rent-assets/tp.png";

export default function HeroSectionRent() {
const [searchTerm, setSearchTerm] = useState('');
Expand Down
139 changes: 104 additions & 35 deletions frontend/src/AgroRentAI/components/AgriProductListing.jsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,117 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { motion, AnimatePresence } from "framer-motion";
import ProductCard from "./ProductCard";
import ProductModal from "./ProductModal";
import productsBg from "../rent-assets/productsBg.png"
import ProductCard from "./sub-components/ProductCard";
import PriceCalculator from "./sub-components/PriceCalculator";
import Recommendations from "./sub-components/Recommendations";
import CompareProducts from "./sub-components/CompareProducts";
import SearchBar from "./sub-components/SearchBar";
import ProductModal from "./sub-components/ProductModal";

// Mock Data (instead of fetching from API)
const mockProducts = [
{
_id: "1",
name: "Tractor",
description: "A high-performance tractor for large farms.",
price: 100,
image: "/rent-assets/tractor.png",
seller: {
name: "John Doe",
contact: "123-456-7890",
location: "California",
coordinates: { lat: 36.7783, lon: -119.4179 }, // Example coordinates
},
category: ["Farming", "Heavy Equipment"],
rentalDurationOptions: ["hourly", "daily", "weekly"],
availabilityStatus: "available", // Options: "available", "rented", "maintenance"
rating: 4.5, // Added rating for product
},
{
_id: "2",
name: "Seeder",
description: "Efficient seeding tool for fast planting.",
price: 30,
image: "/rent-assets/seeder.png",
seller: {
name: "Jane Smith",
contact: "987-654-3210",
location: "Texas",
coordinates: { lat: 31.9686, lon: -99.9018 },
},
category: ["Farming", "Planting Tools"],
rentalDurationOptions: ["daily", "weekly"],
availabilityStatus: "rented", // Currently rented
rating: 4.0,
},
{
_id: "3",
name: "Sprayer",
description: "High-pressure sprayer for pesticides.",
price: 40,
image: "/rent-assets/sprayer.png",
seller: {
name: "Alice Brown",
contact: "456-789-1230",
location: "Florida",
coordinates: { lat: 27.9944, lon: -81.7603 },
},
category: ["Farming", "Pesticide Tools"],
rentalDurationOptions: ["hourly", "daily", "weekly"],
availabilityStatus: "available",
rating: 4.8,
},
{
_id: "4",
name: "Plow",
description: "Heavy-duty plow for tilling large plots.",
price: 70,
image: "/rent-assets/plow.png",
seller: {
name: "Bob Green",
contact: "654-321-9870",
location: "Ohio",
coordinates: { lat: 40.4173, lon: -82.9071 },
},
category: ["Farming", "Tillage Tools"],
rentalDurationOptions: ["daily", "weekly"],
availabilityStatus: "maintenance", // Under maintenance
rating: 4.2,
},
];

const AgriProductListing = () => {
const [products, setProducts] = useState([]);
const [products, setProducts] = useState(mockProducts); // Use mock data here
const [selectedProduct, setSelectedProduct] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
const fetchProducts = async () => {
try {
const response = await axios.get("https://agrotech-ai-11j3.onrender.com/api/products");
setProducts(response.data);
} catch (err) {
console.error("Error fetching products:", err);
setError("Error fetching products");
}
};
fetchProducts();
// Normally, here we would fetch data from an API, but we'll use mock data instead.
// const fetchProducts = async () => {
// try {
// const response = await axios.get("https://api.example.com/products");
// setProducts(response.data);
// } catch (err) {
// console.error("Error fetching products:", err);
// setError("Error fetching products");
// }
// };
// fetchProducts();
}, []);

// Framer Motion animation variants
const cardVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};

const modalVariants = {
hidden: { opacity: 0, scale: 0.8 },
visible: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.8 },
};

return (
<div className="min-h-screen flex flex-col items-center py-10 mt-16 bg-cover bg-center"
style={{ backgroundImage: `url(${productsBg})` }}>

<div className="min-h-screen flex flex-col items-center py-10 mt-16 bg-cover bg-center">

<motion.h1
className="text-4xl font-bold text-white mb-8"
className="text-4xl font-bold text-green-700 mb-8"
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
Agricultural Products
Agricultural Products for Rent
</motion.h1>

<SearchBar />

{error ? (
<motion.p className="text-red-500" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
{error}
Expand All @@ -57,25 +121,30 @@ const AgriProductListing = () => {
{products.map((product, index) => (
<motion.div
key={product._id}
variants={cardVariants}
initial="hidden"
animate="visible"
variants={{ hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0 } }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="border-2 border-green-500 rounded-lg shadow-lg overflow-hidden"
>
<ProductCard product={product} onClick={() => setSelectedProduct(product)} />
</motion.div>
))}
</div>
)}

<PriceCalculator />

<Recommendations products={products} />

<CompareProducts products={products} />

<AnimatePresence>
{selectedProduct && (
<motion.div
variants={modalVariants}
initial="hidden"
animate="visible"
exit="exit"
variants={{ hidden: { opacity: 0, scale: 0.8 }, visible: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 } }}
transition={{ duration: 0.3 }}
className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";

const CompareProducts = ({ products }) => {
const compareItems = products.slice(0, 2); // Comparing the first two products

return (
<div className="my-8 p-6 bg-white rounded-lg shadow-lg max-w-6xl mx-auto">
<h3 className="text-2xl font-semibold text-center mb-6">Compare Products</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-8">
{compareItems.map((product) => (
<div
key={product._id}
className="border-2 border-green-500 p-6 rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300"
>
<img
src={product.image || "/path/to/default-image.png"}
alt={product.name}
className="w-full h-48 object-cover rounded-lg mb-4"
/>
<h4 className="text-xl font-bold text-gray-800">{product.name}</h4>
<p className="text-sm text-gray-600 mb-4">{product.description}</p>
<div className="flex items-center justify-between">
<p className="text-xl font-semibold text-green-600">{`$${product.price} per day`}</p>
<button className="bg-green-500 text-white px-4 py-2 rounded-lg hover:bg-green-600 transition-colors">
Compare
</button>
</div>
</div>
))}
</div>
</div>
);
};

export default CompareProducts;
123 changes: 123 additions & 0 deletions frontend/src/AgroRentAI/components/sub-components/PriceCalculator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useState } from "react";

const PriceCalculator = () => {
const [quantity, setQuantity] = useState(1);
const [duration, setDuration] = useState("daily");
const [discountCode, setDiscountCode] = useState("");
const [currency, setCurrency] = useState("USD");

const pricePerDay = 50; // Base price per day for simplicity

// Price calculation based on duration
const durations = {
hourly: 5,
daily: 50,
weekly: 300,
monthly: 1200,
};

const calculatePrice = () => {
let totalPrice = durations[duration] * quantity;

// Applying a discount code (example logic)
if (discountCode === "DISCOUNT10") {
totalPrice *= 0.9; // Apply a 10% discount
}

// Adding currency conversion (just for demonstration)
if (currency === "EUR") {
totalPrice *= 0.85; // Conversion rate from USD to EUR
}

return totalPrice.toFixed(2);
};

return (
<div className="my-8 p-6 bg-white rounded-lg shadow-2xl max-w-6xl mx-auto">
<h3 className="text-2xl font-semibold mb-6 text-center">Price Calculator</h3>

<div className="space-y-4">
{/* Horizontal Flex Container for Fields */}
<div className="flex space-x-8 items-center">
{/* Quantity Field */}
<div className="w-1/4">
<label className="block text-lg font-medium mb-2">Quantity:</label>
<input
type="number"
value={quantity}
onChange={(e) => setQuantity(Number(e.target.value))}
min="1"
className="w-full p-3 rounded-lg border-2 border-green-500"
placeholder="Enter quantity"
/>
</div>

{/* Duration Field */}
<div className="w-1/4">
<label className="block text-lg font-medium mb-2">Duration:</label>
<select
value={duration}
onChange={(e) => setDuration(e.target.value)}
className="w-full p-3 rounded-lg border-2 border-green-500"
>
<option value="hourly">Hourly</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
</div>

{/* Discount Code Field */}
<div className="w-1/4">
<label className="block text-lg font-medium mb-2">Discount Code (Optional):</label>
<input
type="text"
value={discountCode}
onChange={(e) => setDiscountCode(e.target.value)}
className="w-full p-3 rounded-lg border-2 border-green-500"
placeholder="Enter discount code"
/>
</div>

{/* Currency Selector */}
<div className="w-1/4">
<label className="block text-lg font-medium mb-2">Currency:</label>
<select
value={currency}
onChange={(e) => setCurrency(e.target.value)}
className="w-full p-3 rounded-lg border-2 border-green-500"
>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
</select>
</div>
</div>

{/* Price Breakdown */}
<div className="mt-8">
<div className="flex justify-between mb-2">
<span className="font-medium">Base Price:</span>
<span>{`${durations[duration]} per ${duration}`}</span>
</div>
<div className="flex justify-between mb-2">
<span className="font-medium">Quantity:</span>
<span>{quantity}</span>
</div>
{discountCode && discountCode === "DISCOUNT10" && (
<div className="flex justify-between text-green-600 font-medium mb-2" >
<span>Discount Applied:</span>
<span>-10%</span>
</div>
)}
<div className="border-t-2 border-gray-200 my-4"></div>
<div className="flex justify-between text-xl font-semibold text-green-600">
<span>Total Price:</span>
<span>{currency === "USD" ? `$${calculatePrice()}` : `€${calculatePrice()}`}</span>
</div>
</div>
</div>
</div>
);
};

export default PriceCalculator;
Loading

0 comments on commit 88246fc

Please sign in to comment.