From 56dd06b0f7e0b59d25322d8e90ea40e641c7d09c Mon Sep 17 00:00:00 2001 From: MOHAN Date: Sat, 13 Jun 2026 16:53:05 +0530 Subject: [PATCH] =?UTF-8?q?Complete=20UI/UX=20redesign=20=E2=80=94=20vibra?= =?UTF-8?q?nt=20dark=20theme=20with=20orange/amber=20brand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New collapsible sidebar (64px → 220px on hover) replaces top header - Vibrant dark purple base (#0c0a1e) with glassmorphism cards - Orange/amber gradient brand color throughout - Redesigned Login page with floating orbs and glass card - New AdminDashboard with gradient icon cards - Partners/Clients/Mapping cards with modern hover effects - AddPartner/ManagePartner forms with section-based glass layout - ManageFilesPage with drag-upload zone and media grid - ManageFilesOrderPage with collapsible screen groups and toggle UI - SettingsPage with card-per-setting layout - Shared CSS design system (glass-card, btn-primary, input-field, etc.) Co-Authored-By: Claude Sonnet 4.6 --- src/App.jsx | 110 +-- src/Components/AdminDashboardComponent.jsx | 172 ++-- src/Components/ClientsPageCardComponent.jsx | 164 ++-- src/Components/MappingComponent.jsx | 147 ++-- src/Components/PartnersPageCardComponent.jsx | 182 ++-- src/Components/Sidebar.jsx | 142 +++ src/Pages/AddPartner.jsx | 435 ++++----- src/Pages/AdminDashboard.jsx | 68 +- src/Pages/ClientPartnerMapping.jsx | 70 +- src/Pages/ClientsPage.jsx | 69 +- src/Pages/Login.jsx | 248 ++++-- src/Pages/ManageFilesOrderPage.jsx | 344 ++++---- src/Pages/ManageFilesPage.jsx | 198 ++--- src/Pages/ManagePartner.jsx | 874 +++++++------------ src/Pages/PartnersPage.jsx | 120 +-- src/Pages/SettingsPage.jsx | 100 +-- src/index.css | 137 ++- 17 files changed, 1702 insertions(+), 1878 deletions(-) create mode 100644 src/Components/Sidebar.jsx diff --git a/src/App.jsx b/src/App.jsx index 7f77291..4d62f31 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -11,85 +11,59 @@ import AddClient from "./Pages/AddClient"; import ManageClient from "./Pages/ManageClient"; import ClientPartnerMapping from "./Pages/ClientPartnerMapping"; import NewAdConfiguration from "./Pages/NewAdConfiguration"; -import Header from "./Components/Header"; import ManageFilesOrder from "./Pages/ManageFilesOrderPage"; import SettingsPage from "./Pages/SettingsPage"; import YouTubePlayer from "./Pages/YT"; +import Sidebar from "./Components/Sidebar"; + +const ProtectedRoute = ({ children }) => { + const location = useLocation(); + const storedLogin = localStorage.getItem("loggedIn"); + let isLoggedIn = false; + if (storedLogin) { + try { + const parsed = JSON.parse(storedLogin); + const expired = Date.now() - parsed.timestamp > 1 * 60 * 60 * 1000; + isLoggedIn = parsed.value && !expired; + if (!isLoggedIn) localStorage.removeItem("loggedIn"); + } catch { + localStorage.removeItem("loggedIn"); + } + } + return isLoggedIn ? children : ; +}; const Layout = () => { const location = useLocation(); - const getLoginState = () => { - const storedLogin = JSON.parse(localStorage.getItem('loggedIn')); - if (storedLogin && storedLogin.value) { - const expirationTime = 1 * 60 * 60 * 1000; // 1 hour expiration - if (Date.now() - storedLogin.timestamp < expirationTime) { - return true; - } else { - localStorage.removeItem('loggedIn'); // Expired, remove - return false; - } - } - return false; - }; - - const isLoggedIn = getLoginState(); - - const hideHeaderRoutes = ["/", "/login"]; + const hideSidebarRoutes = ["/", "/login"]; const isAdsPage = location.pathname.startsWith("/ads/"); - - - - // App.js - const ProtectedRoute = ({ children }) => { - const location = useLocation(); - const storedLogin = localStorage.getItem('loggedIn'); - let isLoggedIn = false; // Default to false - - if (storedLogin) { - try { - const parsedLogin = JSON.parse(storedLogin); - isLoggedIn = parsedLogin.value; // Access the 'value' property - } catch (error) { - console.error("Error parsing login data:", error); - // Handle parsing error (e.g., clear localStorage) - localStorage.removeItem('loggedIn'); - } - } - - console.log(isLoggedIn); // Log the boolean value - - const isStaticFile = location.pathname.endsWith('.css') || location.pathname.endsWith('.js'); - - if (isStaticFile) { - return children; // Allow access to static files - } - - return isLoggedIn ? children : ; - }; + const showSidebar = !hideSidebarRoutes.includes(location.pathname) && !isAdsPage; return ( <> - {!hideHeaderRoutes.includes(location.pathname) && !isAdsPage &&
} - - } /> - } /> - } /> - } /> + {showSidebar && } +
+ + } /> + } /> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> - } /> - + } /> + +
); }; @@ -102,4 +76,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/Components/AdminDashboardComponent.jsx b/src/Components/AdminDashboardComponent.jsx index 24b2461..2408541 100644 --- a/src/Components/AdminDashboardComponent.jsx +++ b/src/Components/AdminDashboardComponent.jsx @@ -1,95 +1,89 @@ -import React from 'react' import { motion } from "framer-motion"; +import { FaBuilding, FaUsers, FaTv, FaCog } from "react-icons/fa"; +import { useNavigate } from "react-router-dom"; -import { FaPlus, FaCircle } from "react-icons/fa"; -import { useNavigate } from 'react-router-dom'; +const cards = [ + { + icon: FaBuilding, + label: "Partners", + description: "Manage restaurant partners", + path: "/partners", + gradient: "linear-gradient(135deg, #f97316, #f59e0b)", + glow: "rgba(249,115,22,0.3)", + bg: "rgba(249,115,22,0.08)", + border: "rgba(249,115,22,0.15)", + }, + { + icon: FaUsers, + label: "Clients", + description: "Manage advertising clients", + path: "/clients", + gradient: "linear-gradient(135deg, #a855f7, #6366f1)", + glow: "rgba(168,85,247,0.3)", + bg: "rgba(168,85,247,0.08)", + border: "rgba(168,85,247,0.15)", + }, + { + icon: FaTv, + label: "Ads Configuration", + description: "Configure ad campaigns", + path: "/Client-Partner-Mapping", + gradient: "linear-gradient(135deg, #06b6d4, #3b82f6)", + glow: "rgba(6,182,212,0.3)", + bg: "rgba(6,182,212,0.08)", + border: "rgba(6,182,212,0.15)", + }, + { + icon: FaCog, + label: "General Settings", + description: "System configuration", + path: "/settings", + gradient: "linear-gradient(135deg, #10b981, #059669)", + glow: "rgba(16,185,129,0.3)", + bg: "rgba(16,185,129,0.08)", + border: "rgba(16,185,129,0.15)", + }, +]; export default function AdminDashboardComponent() { - const navigate = useNavigate(); - return ( + const navigate = useNavigate(); - <> -
- - navigate("/Partners")} - > -
- -
- {/* */} -

Partners

-
-
- - navigate("/Clients")} - > -
- - -
- {/* */} -

Clients

-
-
- - navigate("/Client-Partner-Mapping")} - > -
- -
- {/* */} -

Ads Configuration

-
-
- - navigate("/Settings")} - > -
- -
- {/* */} -

Configure General Settings

-
-
- -
- - - ) + return ( +
+ {cards.map(({ icon: Icon, label, description, path, gradient, glow, bg, border }, i) => ( + navigate(path)} + className="rounded-2xl p-6 cursor-pointer flex flex-col gap-4" + style={{ background: bg, border: `1px solid ${border}`, transition: "all 0.2s" }} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ delay: i * 0.08 }} + whileHover={{ + scale: 1.03, + boxShadow: `0 16px 40px ${glow}`, + borderColor: border.replace("0.15", "0.4"), + }} + whileTap={{ scale: 0.98 }} + > +
+ +
+
+

{label}

+

{description}

+
+
+ Open → +
+
+ ))} +
+ ); } diff --git a/src/Components/ClientsPageCardComponent.jsx b/src/Components/ClientsPageCardComponent.jsx index fd13643..4cf3719 100644 --- a/src/Components/ClientsPageCardComponent.jsx +++ b/src/Components/ClientsPageCardComponent.jsx @@ -1,87 +1,95 @@ -import React from 'react' import { motion } from "framer-motion"; - -import { FaPlus, FaCircle } from "react-icons/fa"; +import { FaPlus, FaTrash, FaUser } from "react-icons/fa"; import { api } from "../API/api"; -import { useNavigate } from 'react-router-dom'; -import { useLoading } from '../Context/LoadingContext'; +import { useNavigate } from "react-router-dom"; +import { useLoading } from "../Context/LoadingContext"; export default function ClientsCardComponent({ Data, setUpd }) { - const navigate = useNavigate(); - const { setLoading } = useLoading(); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + const handleDelete = async (clientid) => { + try { + setLoading(true); + await api.delete(`/admin/delete-client/${clientid}`); + setUpd(clientid); + } catch (error) { + console.error("Error deleting client:", error); + } + setLoading(false); + }; - const handleDelete = async (clientid) => { - console.log(clientid) - try { - setLoading(true); - const response = await api.delete(`/admin/delete-client/${clientid}`); - console.log(response); - setUpd(clientid) - } catch (error) { - console.error("Error fetching files:", error); - } - setLoading(false) - }; + return ( +
+ {/* Add card */} + navigate("/add-client")} + > +
+ +
+

Add New Client

+
+ {/* Client cards */} + {Data?.map((client, i) => ( + navigate(`/manage-client/${client.transid}`)} + > +
+ +
+
+

{client.name}

+

Client

+
- - return ( - - <> -
- - navigate("/add-client")} - > -
- -

Add New Client

-
-
- {Data?.map((client) => ( - navigate(`/manage-client/${client.transid}`)} - > - - {/* Red Delete Button at Top Right Corner */} - - -
- -
-

{client.name}

-
-
- - ))} -
- - - ) + +
+ ))} +
+ ); } diff --git a/src/Components/MappingComponent.jsx b/src/Components/MappingComponent.jsx index 1897434..59cef77 100644 --- a/src/Components/MappingComponent.jsx +++ b/src/Components/MappingComponent.jsx @@ -1,87 +1,70 @@ -import React from 'react' import { motion } from "framer-motion"; +import { FaPlus, FaTv } from "react-icons/fa"; +import { useNavigate } from "react-router-dom"; -import { FaPlus, FaCircle } from "react-icons/fa"; -import { api } from "../API/api"; -import { useNavigate } from 'react-router-dom'; -import { useLoading } from '../Context/LoadingContext'; +export default function MappingComponent({ Data }) { + const navigate = useNavigate(); -export default function MappingComponent({ Data, setUpd }) { - const navigate = useNavigate(); - const { setLoading } = useLoading(); + return ( +
+ {/* Add card */} + navigate("/new-ad-configuration")} + > +
+ +
+

+ Add / Edit Ad Configuration +

+
- - const handleDelete = async (clientid) => { - console.log(clientid) - try { - setLoading(true); - const response = await api.delete(`/admin/delete-client/${clientid}`); - console.log(response); - setUpd(clientid) - } catch (error) { - console.error("Error fetching files:", error); - } - setLoading(false) - }; - - - - return ( - - <> -
- - navigate("/new-ad-configuration")} - > -
- -

Add / Edit Ad Configuration

-
-
- {Data?.map((client) => ( - navigate(`/ads-order-configuration/${client.transid}`)} - > - - - {/* */} - -
- -
-

{client.name}

-
-
- - ))} -
- - - ) + {/* Partner cards */} + {Data?.map((client, i) => ( + navigate(`/ads-order-configuration/${client.transid}`)} + > +
+ +
+
+

{client.name}

+

Configure ads →

+
+
+ ))} +
+ ); } diff --git a/src/Components/PartnersPageCardComponent.jsx b/src/Components/PartnersPageCardComponent.jsx index 84a953f..2996e28 100644 --- a/src/Components/PartnersPageCardComponent.jsx +++ b/src/Components/PartnersPageCardComponent.jsx @@ -1,92 +1,110 @@ -import React from 'react' import { motion } from "framer-motion"; - -import { FaPlus, FaCircle } from "react-icons/fa"; +import { FaPlus, FaTrash, FaClock } from "react-icons/fa"; import { api } from "../API/api"; -import { useNavigate } from 'react-router-dom'; -import { useLoading } from '../Context/LoadingContext'; +import { useNavigate } from "react-router-dom"; +import { useLoading } from "../Context/LoadingContext"; export default function PartnersCardComponent({ Data, setUpd }) { - const navigate = useNavigate(); - const { setLoading } = useLoading(); + const navigate = useNavigate(); + const { setLoading } = useLoading(); + const handleDelete = async (partnerid) => { + try { + setLoading(true); + await api.delete(`/admin/delete-partner/${partnerid}`); + setUpd(partnerid); + } catch (error) { + console.error("Error deleting partner:", error); + } + setLoading(false); + }; - const handleDelete = async (partnerid) => { - console.log(partnerid) - try { - setLoading(true); - const response = await api.delete(`/admin/delete-partner/${partnerid}`); - console.log(response); - setUpd(partnerid) - } catch (error) { - console.error("Error fetching files:", error); - } - setLoading(false) - }; + return ( +
+ {/* Add card */} + navigate("/add-partner")} + > +
+ +
+

Add New Partner

+
+ {/* Partner cards */} + {Data?.map((client, i) => ( + navigate(`/manage-partner/${client.transid}`)} + > + {/* Thumbnail */} +
+
+
+ {/* Info */} +
+

{client.name}

+ {(client.open_time || client.close_time) && ( +
+ + {client.open_time} – {client.close_time} +
+ )} +
- - return ( - - <> -
- - navigate("/add-partner")} - > -
- -

Add New Partner

-
-
- {Data?.map((client) => ( - navigate(`/manage-partner/${client.transid}`)} - > - - {/* Red Delete Button at Top Right Corner */} - -
- -
-

{client.name}

-

🕒 {client.open_time} - {client.close_time}

- - {/*
- - {client.is_active ? "Active" : "Inactive"} -
*/} -
-
- ))} -
- - - ) + {/* Delete */} + + + ))} +
+ ); } diff --git a/src/Components/Sidebar.jsx b/src/Components/Sidebar.jsx new file mode 100644 index 0000000..7d257dc --- /dev/null +++ b/src/Components/Sidebar.jsx @@ -0,0 +1,142 @@ +import { useState } from "react"; +import { Link, useLocation, useNavigate } from "react-router-dom"; +import { motion, AnimatePresence } from "framer-motion"; +import { + FaTachometerAlt, FaBuilding, FaUsers, FaTv, FaCog, FaSignOutAlt, +} from "react-icons/fa"; + +const navItems = [ + { icon: FaTachometerAlt, label: "Dashboard", path: "/admin-dashboard" }, + { icon: FaBuilding, label: "Partners", path: "/partners" }, + { icon: FaUsers, label: "Clients", path: "/clients" }, + { icon: FaTv, label: "Ads Config",path: "/Client-Partner-Mapping" }, + { icon: FaCog, label: "Settings", path: "/settings" }, +]; + +const NavItem = ({ icon: Icon, label, path, expanded }) => { + const location = useLocation(); + const isActive = + location.pathname.toLowerCase() === path.toLowerCase() || + location.pathname.toLowerCase().startsWith(path.toLowerCase() + "/"); + + return ( + { if (!isActive) e.currentTarget.style.background = "rgba(255,255,255,0.05)"; }} + onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = ""; }} + > + {isActive && ( + + )} + + + {expanded && ( + + {label} + + )} + + + ); +}; + +const Sidebar = () => { + const [expanded, setExpanded] = useState(false); + const navigate = useNavigate(); + + const handleLogout = () => { + localStorage.removeItem("loggedIn"); + navigate("/login"); + }; + + return ( + setExpanded(true)} + onMouseLeave={() => setExpanded(false)} + animate={{ width: expanded ? 220 : 64 }} + transition={{ duration: 0.25, ease: "easeInOut" }} + className="fixed left-0 top-0 h-full z-50 flex flex-col overflow-hidden" + style={{ + background: "linear-gradient(180deg, #100c24 0%, #160e30 100%)", + borderRight: "1px solid rgba(249,115,22,0.1)", + boxShadow: "4px 0 30px rgba(0,0,0,0.5)", + }} + > + {/* Logo row */} +
+ Dine360 + + {expanded && ( + +

Dine 360 Ads

+

Admin Panel

+
+ )} +
+
+ + {/* Nav */} + + + {/* Logout */} +
+ +
+
+ ); +}; + +export default Sidebar; diff --git a/src/Pages/AddPartner.jsx b/src/Pages/AddPartner.jsx index 1c2a20c..8f1f61e 100644 --- a/src/Pages/AddPartner.jsx +++ b/src/Pages/AddPartner.jsx @@ -1,310 +1,199 @@ import { useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { motion } from "framer-motion"; -import { FaArrowLeft } from "react-icons/fa"; +import { FaArrowLeft, FaBuilding } from "react-icons/fa"; import { api } from "../API/api"; import { useLoading } from "../Context/LoadingContext"; -import Select from 'react-select'; -import canada_cities from '../assets/canada_cities.json'; +import Select from "react-select"; +import canada_cities from "../assets/canada_cities.json"; + +const selectStyles = { + control: (b) => ({ + ...b, + background: "rgba(255,255,255,0.05)", + border: "1px solid rgba(255,255,255,0.1)", + borderRadius: "0.75rem", + padding: "4px", + boxShadow: "none", + "&:hover": { borderColor: "rgba(249,115,22,0.4)" }, + }), + menu: (b) => ({ + ...b, + background: "#1a1530", + border: "1px solid rgba(255,255,255,0.1)", + borderRadius: "0.75rem", + zIndex: 99, + }), + option: (b, s) => ({ + ...b, + background: s.isSelected ? "rgba(249,115,22,0.2)" : s.isFocused ? "rgba(255,255,255,0.05)" : "transparent", + color: s.isSelected ? "#fb923c" : "#f1f5f9", + }), + singleValue: (b) => ({ ...b, color: "#f1f5f9" }), + input: (b) => ({ ...b, color: "#f1f5f9" }), + placeholder: (b) => ({ ...b, color: "#475569" }), +}; const AddPartner = () => { const [uploading, setUploading] = useState(false); const [formData, setFormData] = useState({ - name: "", - open_time: "", - close_time: "", - image: null, - address: "", - city: "", - state: "", - pincode: "", - screens: "", + name: "", open_time: "", close_time: "", image: null, + address: "", city: "", state: "", pincode: "", screens: "", }); + const [selectedProvince, setSelectedProvince] = useState(null); + const [selectedCity, setSelectedCity] = useState(null); const { setLoading } = useLoading(); const navigate = useNavigate(); - const handleChange = (e) => { - const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - }; + const provinceOptions = useMemo( + () => Object.keys(canada_cities).map((p) => ({ value: p, label: p })), + [] + ); + const cityOptions = useMemo( + () => selectedProvince ? canada_cities[selectedProvince.value].map((c) => ({ value: c, label: c })) : [], + [selectedProvince] + ); + const handleChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value }); + const handleFileChange = (e) => setFormData({ ...formData, image: e.target.files[0] }); + const handleProvinceChange = (o) => { setSelectedProvince(o); setSelectedCity(null); setFormData({ ...formData, state: o?.value || "" }); }; + const handleCityChange = (o) => { setSelectedCity(o); setFormData({ ...formData, city: o?.value || "" }); }; - const handleFileUpload = async (file,id) => { + const handleFileUpload = async (file, id) => { if (!file) return; - setUploading(true); - const formData = new FormData(); - formData.append("file", file); - formData.append("file_name", file.name); - formData.append("client_id", id); // Attach client ID - + const fd = new FormData(); + fd.append("file", file); + fd.append("file_name", file.name); + fd.append("client_id", id); try { - console.log(formData) - setLoading(true) - await api.post("/files/update-partner-logo", formData, { - headers: { "Content-Type": "multipart/form-data" }, - }); + setLoading(true); + await api.post("/files/update-partner-logo", fd, { headers: { "Content-Type": "multipart/form-data" } }); navigate("/partners"); - - // Refresh file list after each successful upload - //fetchFiles(); - } catch (error) { - console.error(`File upload failed for ${file.name}:`, error); - // Optionally, you could add some user feedback here for individual file failures + } catch (e) { + console.error(e); } finally { - setUploading(false); // Keep this false, as we're handling individual uploads - setLoading(false) + setUploading(false); + setLoading(false); } }; - const handleFileChange = async (e) => { - - setFormData({ ...formData, image: e.target.files[0] }); - }; const handleSubmit = async (e) => { e.preventDefault(); try { - console.log("iuytg") setLoading(true); - var data = await api.post("/admin/add-partner", formData); - console.log(data) - console.log("iuytg") - await handleFileUpload(formData.image,data.id); - navigate("/Partners"); - } catch (error) { - console.error("Error adding Partner:", error); + const data = await api.post("/admin/add-partner", formData); + await handleFileUpload(formData.image, data.id); + navigate("/partners"); + } catch (e) { + console.error(e); } setLoading(false); }; - const [selectedProvince, setSelectedProvince] = useState(null); - const [selectedCity, setSelectedCity] = useState(null); - - const provinceOptions = useMemo( - () => - Object.keys(canada_cities).map((province) => ({ - value: province, - label: province, - })), - [canada_cities] - ); - - const cityOptions = useMemo( - () => - selectedProvince - ? canada_cities[selectedProvince.value].map((city) => ({ - value: city, - label: city, - })) - : [], - [selectedProvince, canada_cities] - ); - - const handleProvinceChange = (selectedOption) => { - setSelectedProvince(selectedOption); - setSelectedCity(null); - setFormData({ ...formData, state: selectedOption?.value || "" }); // Update state in formData - }; - - const handleCityChange = (selectedOption) => { - setSelectedCity(selectedOption); - setFormData({ ...formData, city: selectedOption?.value || "" }); // Update city in formData - }; - return ( -
- navigate("/admin-dashboard")} - > - Back - - - ➕ Add New Partner - -
-
- - - - - - - - - - - - - - - - - ({ - ...provided, - backgroundColor: '#374151', - color: 'white', - borderRadius: '0.5rem', - padding: '0.5rem', - border: 'none', - }), - option: (provided, state) => ({ - ...provided, - backgroundColor: state.isSelected ? '#1f2937' : '#374151', - color: 'white', - }), - singleValue: (provided) => ({ - ...provided, - color: 'white', - }), - input: (provided) => ({ - ...provided, - color: 'white', - }), - placeholder: (provided) => ({ - ...provided, - color: 'white', - }), - }} - placeholder="Select City" - isDisabled={!selectedProvince} - /> - - - - - - -
- + {/* Header */} + + +
+
+ +
+
+

Add New Partner

+

Fill in the details to register a new partner

+
+
+
+ +
+ + {/* Form */} + +
+

+ Basic Information +

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

+ Location +

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + {uploading ? "Saving..." : "Add Partner"} + + +
+
); }; -export default AddPartner; \ No newline at end of file +export default AddPartner; diff --git a/src/Pages/AdminDashboard.jsx b/src/Pages/AdminDashboard.jsx index cacff3d..47caa74 100644 --- a/src/Pages/AdminDashboard.jsx +++ b/src/Pages/AdminDashboard.jsx @@ -1,55 +1,31 @@ -import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; import { motion } from "framer-motion"; -import { FaPlus, FaCircle } from "react-icons/fa"; -import { api } from "../API/api"; -import { useLoading } from "../Context/LoadingContext"; -import HoveringCardComponent from "../Components/HoveringCardComponent"; import AdminDashboardComponent from "../Components/AdminDashboardComponent"; const AdminDashboard = () => { - const [clients, setClients] = useState([]); - const navigate = useNavigate(); - const { setLoading } = useLoading(); + return ( +
+ {/* Header */} + +

+ Admin Dashboard +

+

Welcome back — manage your Dine 360 Ads platform

+
- // useEffect(() => { - // const fetchClients = async () => { - // try { - // setLoading(true); - // const response = await api.get("/admin/clients"); + {/* Divider */} +
- // const updatedClients = response.map(client => ({ - // ...client, - // is_active: client.status === "Offline" ? null : true, - // })); - - // setClients(updatedClients); - - - // } catch (error) { - // console.error("Error fetching clients:", error); - // } finally { - // setLoading(false); - // } - // }; - // fetchClients(); - // }, []); - - return ( -
- - 🏢 Admin Dashboard - Client List - - -
- -
-
- ); + +
+ ); }; export default AdminDashboard; diff --git a/src/Pages/ClientPartnerMapping.jsx b/src/Pages/ClientPartnerMapping.jsx index 73b3cf2..7d9b620 100644 --- a/src/Pages/ClientPartnerMapping.jsx +++ b/src/Pages/ClientPartnerMapping.jsx @@ -1,53 +1,39 @@ - import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; import { motion } from "framer-motion"; -import { FaPlus, FaCircle } from "react-icons/fa"; import { api } from "../API/api"; import { useLoading } from "../Context/LoadingContext"; -import PartnersCardComponent from "../Components/PartnersPageCardComponent"; -import ClientsCardComponent from "../Components/ClientsPageCardComponent"; import MappingComponent from "../Components/MappingComponent"; const ClientPartnerMapping = () => { - const [clients, setClients] = useState([]); - const [upd, setUpd] = useState(0); - const navigate = useNavigate(); - const { setLoading } = useLoading(); + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0); + const { setLoading } = useLoading(); - useEffect(() => { - const fetchClients = async () => { - try { - setLoading(true); - const response = await api.get("/admin/partners"); + useEffect(() => { + const fetch = async () => { + try { + setLoading(true); + const response = await api.get("/admin/partners"); + setClients(response); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + fetch(); + }, [upd]); - setClients(response); - - - } catch (error) { - console.error("Error fetching clients:", error); - } finally { - setLoading(false); - } - }; - fetchClients(); - }, [upd]); - - return ( -
- - Ads Configuration - - - - -
- ); + return ( +
+ +

Ads Configuration

+

Configure ad campaigns per partner and screen

+
+
+ +
+ ); }; -export default ClientPartnerMapping - +export default ClientPartnerMapping; diff --git a/src/Pages/ClientsPage.jsx b/src/Pages/ClientsPage.jsx index 95d8bf9..acb07f5 100644 --- a/src/Pages/ClientsPage.jsx +++ b/src/Pages/ClientsPage.jsx @@ -1,52 +1,39 @@ - import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; import { motion } from "framer-motion"; -import { FaPlus, FaCircle } from "react-icons/fa"; import { api } from "../API/api"; import { useLoading } from "../Context/LoadingContext"; -import PartnersCardComponent from "../Components/PartnersPageCardComponent"; import ClientsCardComponent from "../Components/ClientsPageCardComponent"; const ClientsPage = () => { - const [clients, setClients] = useState([]); - const [upd, setUpd] = useState(0); - const navigate = useNavigate(); - const { setLoading } = useLoading(); + const [clients, setClients] = useState([]); + const [upd, setUpd] = useState(0); + const { setLoading } = useLoading(); - useEffect(() => { - const fetchClients = async () => { - try { - setLoading(true); - const response = await api.get("/admin/clients"); + useEffect(() => { + const fetch = async () => { + try { + setLoading(true); + const response = await api.get("/admin/clients"); + setClients(response); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + fetch(); + }, [upd]); - setClients(response); - - - } catch (error) { - console.error("Error fetching clients:", error); - } finally { - setLoading(false); - } - }; - fetchClients(); - }, [upd]); - - return ( -
- - Clients List - - - - -
- ); + return ( +
+ +

Clients

+

Manage all advertising clients

+
+
+ +
+ ); }; -export default ClientsPage - +export default ClientsPage; diff --git a/src/Pages/Login.jsx b/src/Pages/Login.jsx index c1a98a3..62189aa 100644 --- a/src/Pages/Login.jsx +++ b/src/Pages/Login.jsx @@ -1,7 +1,7 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { motion } from "framer-motion"; -import { FaLock, FaUser } from "react-icons/fa"; +import { FaLock, FaUser, FaFire } from "react-icons/fa"; const Login = () => { const [username, setUsername] = useState(""); @@ -12,117 +12,175 @@ const Login = () => { const handleLogin = (e) => { e.preventDefault(); if (username === "admin" && password === "admin") { - localStorage.setItem('loggedIn', JSON.stringify({ - timestamp: Date.now(), - value: true, - })); + localStorage.setItem("loggedIn", JSON.stringify({ timestamp: Date.now(), value: true })); navigate("/admin-dashboard"); } else { - setError("❌ Invalid credentials! Try again."); + setError("Invalid credentials. Please try again."); } }; - const [floors, setFloors] = useState([]); - - useEffect(() => { - const a = "482beca79d9c005"; - const b = "b8778f51fcca82b"; - const authHeader = `token ${a}:${b}`; -const url = "http://82.25.105.135:8004/api/resource/Dine360%20Room?fields=%5B%22*%22%5D&limit_page_length=100&filters=%5B%5B%22floor%22%2C%22%3D%22%2C%223%22%5D%5D"; - - fetch(url, { - headers: { - Authorization: authHeader, - }, - }) - .then((res) => res.json()) - .then((data) => { - setFloors(data.data); - console.log("regr", data.data) - }) - .catch((err) => console.error(err)); - }, []); - return ( -
+
+ {/* Background orbs */} +
+
+
+ + {/* Card */} - {/* Animated Heading */} - - 🔐 Admin Login - - - {/* Input Fields */} -
-
- - setUsername(e.target.value)} - /> -
- -
- - setPassword(e.target.value)} - /> -
- - {/* Error Message Animation */} - {error && ( + {/* Logo + Brand */} +
+ + Dine360 + + + Welcome Back + - {error} + Sign in to Dine 360 Ads Admin - )} +
- {/* Login Button */} - - 🚀 Login - -
-
+ {/* Username */} +
+ +
+ + setUsername(e.target.value)} + className="input-field" + style={{ paddingLeft: "2.5rem" }} + required + /> +
+
- {/* Floating Emojis Animation */} - - 🔑 - + {/* Password */} +
+ +
+ + setPassword(e.target.value)} + className="input-field" + style={{ paddingLeft: "2.5rem" }} + required + /> +
+
- - 🔥 + {/* Error */} + {error && ( + + + {error} + + )} + + {/* Submit */} + + + Sign In + + +
+ + {/* Tagline */} +

+ Dine 360 Ads · Digital Signage Platform +

); diff --git a/src/Pages/ManageFilesOrderPage.jsx b/src/Pages/ManageFilesOrderPage.jsx index 777be4c..c57c4f3 100644 --- a/src/Pages/ManageFilesOrderPage.jsx +++ b/src/Pages/ManageFilesOrderPage.jsx @@ -1,253 +1,233 @@ -import { useEffect, useState, useRef, useMemo } from "react"; +import { useEffect, useState, useMemo } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { motion, AnimatePresence, Reorder } from "framer-motion"; -import { FaArrowUp, FaArrowDown } from "react-icons/fa"; +import { FaArrowUp, FaArrowDown, FaArrowLeft, FaSave, FaChevronDown, FaChevronRight } from "react-icons/fa"; import { api } from "../API/api"; import { useLoading } from "../Context/LoadingContext"; import ViewPartnerAdsConfiguration from "../Components/ViewPartnerAdsConfiguration"; const ManageFilesOrder = () => { const { id } = useParams(); - const BACKEND = 'https://backend.dine360ads.com/'; + const BACKEND = "https://backend.dine360ads.com/"; const [files, setFiles] = useState([]); const [openScreens, setOpenScreens] = useState({}); const navigate = useNavigate(); const { setLoading } = useLoading(); - // Fetch and sort files useEffect(() => { (async () => { try { setLoading(true); - const response = await api.get(`/admin/partner-ads?partnerid=${id}`); - console.log(response) - const sorted = response.sort((a, b) => { - const nameA = a?.screenname || ''; - const nameB = b?.screenname || ''; - return nameA.localeCompare(nameB, undefined, { numeric: true }); - }); - + const res = await api.get(`/admin/partner-ads?partnerid=${id}`); + const sorted = res.sort((a, b) => (a?.screenname || "").localeCompare(b?.screenname || "", undefined, { numeric: true })); setFiles(sorted); - console.log("FILESSSSSSSSSSSSS<",sorted) - } catch (error) { - console.error("Error fetching files:", error); - } finally { - setLoading(false); - } + } catch (e) { console.error(e); } + finally { setLoading(false); } })(); }, [id, setLoading]); - // Group files by screenname const filesByScreen = useMemo(() => files.reduce((acc, file) => { const key = file.screenname; acc[key] = acc[key] || []; acc[key].push(file); return acc; - }, {}), - [files] + }, {}), [files] ); - // Toggle collapse for screen - const toggleScreen = (screen) => { - setOpenScreens(prev => ({ ...prev, [screen]: !prev[screen] })); - }; - - // Merge reordered group back into files array + const toggleScreen = (s) => setOpenScreens(prev => ({ ...prev, [s]: !prev[s] })); const handleGroupReorder = (screen, newGroup) => { - const other = files.filter(f => f.screenname !== screen); - setFiles([...other, ...newGroup]); + setFiles([...files.filter(f => f.screenname !== screen), ...newGroup]); }; - - // Save flattened order const saveOrder = async () => { try { setLoading(true); await api.post("/admin/reorder-partner-ads", files); alert("Order saved successfully"); - } catch (error) { - console.error("Error saving order:", error); - alert("Error saving order. Check console for details."); - } finally { - setLoading(false); - } + } catch (e) { console.error(e); alert("Error saving order."); } + finally { setLoading(false); } }; - // Checkbox handlers update flat files state - const handleToggleMainAd = (file, checked) => { - setFiles(files.map(f => - f.file_path === file.file_path && file.screenid === f.screenid? { ...f, ismainad: checked ? 1 : 0 } : f - )); - }; - const handleToggleCarousel = (file, checked) => { - setFiles(files.map(f => - f.file_path === file.file_path && file.screenid === f.screenid? { ...f, iscarousel: checked ? 1 : 0 } : f - )); - }; - const handleToggleInHouse = (file, checked) => { - setFiles(files.map(f => - f.file_path === file.file_path && file.screenid === f.screenid? { ...f, isinhousead: checked ? 1 : 0 } : f - )); - }; + const handleToggleMainAd = (file, checked) => + setFiles(files.map(f => f.file_path === file.file_path && file.screenid === f.screenid ? { ...f, ismainad: checked ? 1 : 0 } : f)); + const handleToggleCarousel = (file, checked) => + setFiles(files.map(f => f.file_path === file.file_path && file.screenid === f.screenid ? { ...f, iscarousel: checked ? 1 : 0 } : f)); + const handleToggleInHouse = (file, checked) => + setFiles(files.map(f => f.file_path === file.file_path && file.screenid === f.screenid ? { ...f, isinhousead: checked ? 1 : 0 } : f)); - // Move up/down within a screen group const groupMoveUp = (screen, index) => { - const group = filesByScreen[screen]; + const group = [...filesByScreen[screen]]; if (index <= 0) return; - const newGroup = [...group]; - [newGroup[index - 1], newGroup[index]] = [newGroup[index], newGroup[index - 1]]; - handleGroupReorder(screen, newGroup); + [group[index - 1], group[index]] = [group[index], group[index - 1]]; + handleGroupReorder(screen, group); }; const groupMoveDown = (screen, index) => { - const group = filesByScreen[screen]; + const group = [...filesByScreen[screen]]; if (index >= group.length - 1) return; - const newGroup = [...group]; - [newGroup[index], newGroup[index + 1]] = [newGroup[index + 1], newGroup[index]]; - handleGroupReorder(screen, newGroup); + [group[index], group[index + 1]] = [group[index + 1], group[index]]; + handleGroupReorder(screen, group); }; - return ( -
- ( +