- 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 <noreply@anthropic.com>
90 lines
3.1 KiB
JavaScript
90 lines
3.1 KiB
JavaScript
import { useEffect, useState } from "react";
|
|
import { motion } from "framer-motion";
|
|
import { FaCog, FaSave } from "react-icons/fa";
|
|
import { api } from "../API/api";
|
|
import { useLoading } from "../Context/LoadingContext";
|
|
|
|
const SettingsPage = () => {
|
|
const { setLoading } = useLoading();
|
|
const [settingsData, setSettingsData] = useState([]);
|
|
|
|
useEffect(() => { fetchSettings(); }, []);
|
|
|
|
const fetchSettings = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const res = await api.get("/client/get-settings");
|
|
setSettingsData(res);
|
|
} catch (e) { console.error(e); }
|
|
setLoading(false);
|
|
};
|
|
|
|
const handleUpdate = async (transid, newValue) => {
|
|
try {
|
|
setLoading(true);
|
|
await api.post("/admin/update-settings", { transid, value: newValue });
|
|
alert("Setting updated successfully");
|
|
fetchSettings();
|
|
} catch (e) { console.error(e); }
|
|
setLoading(false);
|
|
};
|
|
|
|
return (
|
|
<div className="page-wrapper">
|
|
<motion.div className="mb-8" initial={{ opacity: 0, y: -15 }} animate={{ opacity: 1, y: 0 }}>
|
|
<div className="flex items-center gap-3">
|
|
<div
|
|
className="w-10 h-10 rounded-xl flex items-center justify-center"
|
|
style={{ background: "linear-gradient(135deg, #10b981, #059669)", boxShadow: "0 4px 15px rgba(16,185,129,0.3)" }}
|
|
>
|
|
<FaCog className="w-4 h-4 text-white" />
|
|
</div>
|
|
<div>
|
|
<h1 className="page-title"><span className="gradient-text">General Settings</span></h1>
|
|
<p className="page-subtitle">System-wide configuration values</p>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
|
|
<div className="mb-6 h-px" style={{ background: "linear-gradient(90deg, rgba(16,185,129,0.4), transparent)" }} />
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5">
|
|
{settingsData.map((item, i) => (
|
|
<motion.div
|
|
key={item.transid}
|
|
className="rounded-2xl p-5"
|
|
style={{ background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.08)" }}
|
|
initial={{ opacity: 0, y: 15 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: i * 0.06 }}
|
|
>
|
|
<label className="label mb-3">{item.name}</label>
|
|
<input
|
|
type="text"
|
|
value={item.value}
|
|
placeholder={item.name}
|
|
onChange={(e) => {
|
|
setSettingsData(settingsData.map((s) =>
|
|
s.transid === item.transid ? { ...s, value: e.target.value } : s
|
|
));
|
|
}}
|
|
className="input-field mb-3"
|
|
/>
|
|
<motion.button
|
|
onClick={() => handleUpdate(item.transid, item.value)}
|
|
className="btn-primary flex items-center gap-2 w-full justify-center"
|
|
style={{ padding: "0.55rem 1rem", fontSize: "0.8rem" }}
|
|
whileHover={{ scale: 1.02 }}
|
|
whileTap={{ scale: 0.97 }}
|
|
>
|
|
<FaSave className="w-3 h-3" /> Update
|
|
</motion.button>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SettingsPage;
|