diff --git a/.env.local.example b/.env.local.example index 1f86435..f9df858 100644 --- a/.env.local.example +++ b/.env.local.example @@ -1,10 +1,3 @@ -# Gemini AI Configuration -GEMINI_API_KEY=your_gemini_api_key_here +# Note: No environment variables required for this version +# All configuration is managed through the admin panel -# Cloudinary Configuration -# Get these from https://cloudinary.com/console -VITE_CLOUDINARY_CLOUD_NAME=your_cloud_name -VITE_CLOUDINARY_UPLOAD_PRESET=your_unsigned_upload_preset - -# Note: Do not commit the actual .env.local file -# Copy this file to .env.local and fill in your actual values diff --git a/App.tsx b/App.tsx index 5b91548..b5d070e 100644 --- a/App.tsx +++ b/App.tsx @@ -1,8 +1,6 @@ import React, { useState, useEffect, useMemo, useRef } from 'react'; import { ICONS, PRODUCTS as INITIAL_PRODUCTS, CATEGORIES, WHATSAPP_NUMBER as INITIAL_WA, ADMIN_PASSCODE, HERO_SLIDES } from './constants'; -import { Product, Message, GroundingSource, Category } from './types'; -import { gemini } from './services/geminiService'; -import { uploadImage } from './services/cloudinaryService'; +import { Product, Category } from './types'; type ViewType = 'home' | 'products' | 'detail' | 'admin' | 'about'; type ThemeType = 'light' | 'dark'; @@ -103,7 +101,7 @@ const Header = React.memo(({ isScrolled, searchQuery, setSearchQuery, view, setV aria-label="Toggle Theme" className="p-3 rounded-2xl border border-black/5 dark:border-white/10 bg-black/5 dark:bg-white/5 hover:border-nexlyn transition-all text-slate-600 dark:text-slate-400 focus:outline-none focus:ring-2 focus:ring-nexlyn" > - {theme === 'dark' ? : } + {theme === 'dark' ? : } @@ -230,51 +228,12 @@ const AdminView = ({ products, setProducts, waNumber, setWaNumber, address, setAddress, - aboutContent, setAboutContent + aboutContent, setAboutContent, + banners, setBanners }: any) => { const [passInput, setPassInput] = useState(''); const [editProduct, setEditProduct] = useState | null>(null); - const [uploadProgress, setUploadProgress] = useState(false); - const [imagePreview, setImagePreview] = useState(null); - - // Handle file upload to Cloudinary - const handleImageUpload = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file || !editProduct) return; - - // Validate file type - if (!file.type.startsWith('image/')) { - alert('Please upload an image file'); - return; - } - - // Validate file size (max 5MB) - if (file.size > 5 * 1024 * 1024) { - alert('Image size must be less than 5MB'); - return; - } - - setUploadProgress(true); - - try { - // Create local preview - const reader = new FileReader(); - reader.onloadend = () => { - setImagePreview(reader.result as string); - }; - reader.readAsDataURL(file); - - // Upload to Cloudinary - const imageUrl = await uploadImage(file); - setEditProduct({...editProduct, imageUrl}); - - } catch (error) { - console.error('Upload failed:', error); - alert('Upload failed. Please try again or use a URL instead.'); - } finally { - setUploadProgress(false); - } - }; + const [editBanner, setEditBanner] = useState | null>(null); const stats = useMemo(() => ({ total: products.length, @@ -382,6 +341,34 @@ const AdminView = ({ ))} + +
+
+

Home Page Banners

+ +
+ +
+ {banners.map((banner: HeroSlide, idx: number) => ( +
+
+
+
{banner.title.substring(0, 40)}...
+
{banner.categoryId}
+
+
+ + +
+
+

{banner.subtitle.substring(0, 80)}...

+
+ ))} +
+
)} @@ -408,22 +395,19 @@ const AdminView = ({
- + {/* Image Preview */} - {(editProduct.imageUrl || imagePreview) && ( + {editProduct.imageUrl && (
Product preview
)} - {/* Upload Options */} -
- {/* File Upload */} -
- - -
- - {/* Manual URL Entry (fallback) */} -
- - setEditProduct({...editProduct, imageUrl: e.target.value})} - placeholder="https://example.com/image.jpg" - className="w-full bg-black/5 dark:bg-white/5 border border-black/10 dark:border-white/10 p-4 rounded-xl text-sm font-bold focus:border-nexlyn focus:outline-none transition-colors" - /> -
+ {/* URL Input */} +
+ setEditProduct({...editProduct, imageUrl: e.target.value})} + placeholder="https://example.com/product-image.jpg" + className="w-full bg-black/5 dark:bg-white/5 border border-black/10 dark:border-white/10 p-5 rounded-2xl text-sm font-bold focus:border-nexlyn focus:outline-none transition-colors" + /> +

Enter a direct URL to the product image

@@ -502,6 +453,64 @@ const AdminView = ({ )} + + {editBanner && ( +
+
+
+

Banner Editor

+ +
+
+
+ + setEditBanner({...editBanner, title: e.target.value})} className="w-full bg-black/5 dark:bg-white/5 border border-black/10 dark:border-white/10 p-5 rounded-2xl text-sm font-bold focus:border-nexlyn focus:outline-none transition-colors uppercase" /> +
+
+ +