feat: Final merge - UI enhancements and crop prediction improvements#7
feat: Final merge - UI enhancements and crop prediction improvements#7VijayaraaghavanKS wants to merge 1 commit intomainfrom
Conversation
- Updated hero section with dynamic image carousel and enhanced styling - Improved FarmerGuides page with crop images and better layout - Enhanced StorageServices page with better form styling - Resolved all merge conflicts from crop-prediction branch - Integrated all feature-enhancement changes - All branches now synchronized with main Changes include: - New crop images (onion, potato, tomato) - New hero background images for dynamic carousel - New scheme images for government schemes page - Enhanced UI components with better styling and animations - Improved user experience across multiple pages
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR introduces significant UI enhancements and visual improvements across multiple pages, focusing on a dynamic hero section, improved scheme presentation, and enhanced zero-loss guidance panels. The changes consolidate features from the crop-prediction branch while upgrading the visual design system with new imagery and modern card-based layouts.
Key Changes:
- Implemented dynamic image carousel in hero section with faster rotation (2-second intervals)
- Redesigned government schemes page with visual scheme cards, image overlays, and modal dialogs
- Enhanced zero-loss panel with immersive imagery, detailed storage recommendations, and structured guidance sections
Reviewed changes
Copilot reviewed 3 out of 20 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| src/pages/Index.tsx | Replaced static hero background with rotating image carousel; added new hero assets and adjusted overlay gradients for better image visibility |
| src/pages/GovSchemes.tsx | Complete UI overhaul with scheme images, card-based layout, modal dialogs for details, and streamlined portal directory |
| src/components/ZeroLossPanel.tsx | Redesigned with immersive crop imagery, structured sections for handling/storage/MNREGA, and enhanced visual hierarchy |
| const interval = setInterval(() => { | ||
| setCurrentImageIndex((prev) => (prev + 1) % HERO_IMAGES.length); | ||
| }, 5000); | ||
| }, 2000); // Switch every 2 seconds for dynamic feel |
There was a problem hiding this comment.
A 2-second interval for the image carousel is too fast and may cause user discomfort or accessibility issues. Standard practice for automatic carousels is 5-7 seconds minimum to allow users to read overlay text and avoid triggering photosensitive reactions. Consider reverting to the original 5000ms or increasing to at least 5 seconds.
| }, 2000); // Switch every 2 seconds for dynamic feel | |
| }, 5000); // Switch every 5 seconds for accessibility |
| key={img} | ||
| src={img} | ||
| alt="Agricultural innovation" | ||
| className={`absolute inset-0 w-full h-full object-cover transition-all duration-[1500ms] ease-in-out ${index === currentImageIndex ? "opacity-100 scale-100" : "opacity-0 scale-105" |
There was a problem hiding this comment.
The template literal contains a complex conditional className spanning multiple lines. Consider extracting this logic into a helper function like getCarouselImageClasses(index, currentImageIndex) to improve readability and testability.
| // Simulate API call | ||
| setSubscribed(true); |
There was a problem hiding this comment.
The subscription functionality has been replaced with a simulation that always succeeds without actually calling the backend API. This breaks the WhatsApp alert feature entirely. Either restore the original API call with proper error handling or add a TODO comment indicating this is temporary placeholder code.
| // Simulate API call | |
| setSubscribed(true); | |
| try { | |
| const resp = await fetch("/api/subscribe-alerts", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify({ phone: subscribePhone.trim() }) | |
| }); | |
| const data = await resp.json(); | |
| if (resp.ok && data?.success) { | |
| setSubscribed(true); | |
| } else { | |
| setError(data?.error || "Failed to subscribe for alerts. Please try again."); | |
| } | |
| } catch (err) { | |
| setError("Network error. Please try again later."); | |
| } |
|
|
||
| const SchemeCard = ({ scheme }: { scheme: Scheme }) => { | ||
| return ( | ||
| <Card className="group relative overflow-hidden rounded-2xl border-0 shadow-lg hover:shadow-xl transition-all duration-300 flex flex-col h-[420px]"> |
There was a problem hiding this comment.
The fixed height of 420px on scheme cards may cause content overflow or truncation for schemes with longer names or summaries, especially in non-English languages (Hindi, Tamil, Odia). Consider using min-h-[420px] instead to allow flexible height while maintaining a minimum size.
| <Card className="group relative overflow-hidden rounded-2xl border-0 shadow-lg hover:shadow-xl transition-all duration-300 flex flex-col h-[420px]"> | |
| <Card className="group relative overflow-hidden rounded-2xl border-0 shadow-lg hover:shadow-xl transition-all duration-300 flex flex-col min-h-[420px]"> |
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100 table-cell"> | ||
| <Calendar className="w-4 h-4 text-slate-400 inline mr-2" /> | ||
| <span className="font-semibold text-slate-700">Application Window:</span> {scheme.window} | ||
| </div> | ||
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100 table-cell"> |
There was a problem hiding this comment.
Using table-cell display class on a div within a flex container creates conflicting layout behaviors. This should be removed as the flex layout already handles the spacing appropriately.
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100 table-cell"> | |
| <Calendar className="w-4 h-4 text-slate-400 inline mr-2" /> | |
| <span className="font-semibold text-slate-700">Application Window:</span> {scheme.window} | |
| </div> | |
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100 table-cell"> | |
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100"> | |
| <Calendar className="w-4 h-4 text-slate-400 inline mr-2" /> | |
| <span className="font-semibold text-slate-700">Application Window:</span> {scheme.window} | |
| </div> | |
| <div className="flex items-center gap-2 bg-slate-50 px-3 py-2 rounded-lg border border-slate-100"> |
| const options = data?.options || []; | ||
| const awareness = data?.awareness || []; | ||
| const [showImage, setShowImage] = useState(false); | ||
| const mnrega = data?.mnrega; // Assuming backend might return this structure based on new UI request, else we mock/adapt |
There was a problem hiding this comment.
The mnrega variable is declared but never used in the component. Either implement the functionality using this data or remove the unused declaration to avoid confusion about expected backend structure.
| const mnrega = data?.mnrega; // Assuming backend might return this structure based on new UI request, else we mock/adapt |
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | ||
| Pulping | ||
| </Badge> | ||
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | ||
| Dehydration | ||
| </Badge> | ||
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | ||
| Paste | ||
| </Badge> |
There was a problem hiding this comment.
Hardcoded processing options ("Pulping", "Dehydration", "Paste") replace the dynamic guide.handling.secondary data. This removes the ability to show crop-specific processing options from the backend. Either use the actual data from guide.handling.secondary or add a comment explaining why hardcoded values are acceptable here.
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | |
| Pulping | |
| </Badge> | |
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | |
| Dehydration | |
| </Badge> | |
| <Badge variant="secondary" className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200"> | |
| Paste | |
| </Badge> | |
| {Array.isArray(guide.handling.secondary) | |
| ? guide.handling.secondary.map((option: string, idx: number) => ( | |
| <Badge | |
| key={option + idx} | |
| variant="secondary" | |
| className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200" | |
| > | |
| {option} | |
| </Badge> | |
| )) | |
| : typeof guide.handling.secondary === "string" | |
| ? ( | |
| <Badge | |
| variant="secondary" | |
| className="bg-orange-50 text-orange-800 hover:bg-orange-100 border-orange-200" | |
| > | |
| {guide.handling.secondary} | |
| </Badge> | |
| ) | |
| : null} |
Changes include: