Improve admin panel and sale countdown banner
- Remove 'apply to all' option from sale manager - only selected items - Fix PLA Translucent to be spool-only (no refill option) - Sale countdown shows actual max percentage from database - Update banner design: blue-purple-orange gradient instead of red - Remove fire emoji and promotional text - Make percentage number larger and yellow for emphasis - Change 'do' to 'od' in discount text - Add shimmer animation for subtle effect
This commit is contained in:
@@ -9,7 +9,12 @@ interface TimeLeft {
|
||||
seconds: number;
|
||||
}
|
||||
|
||||
export function SaleCountdown() {
|
||||
interface SaleCountdownProps {
|
||||
hasActiveSale: boolean;
|
||||
maxSalePercentage?: number;
|
||||
}
|
||||
|
||||
export function SaleCountdown({ hasActiveSale, maxSalePercentage = 5 }: SaleCountdownProps) {
|
||||
const [timeLeft, setTimeLeft] = useState<TimeLeft>({ days: 0, hours: 0, minutes: 0, seconds: 0 });
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
@@ -58,15 +63,21 @@ export function SaleCountdown() {
|
||||
return <div className="h-24" />; // Placeholder to prevent hydration mismatch
|
||||
}
|
||||
|
||||
// Only show countdown if there are active sales
|
||||
if (!hasActiveSale) return null;
|
||||
|
||||
const isActive = timeLeft.days > 0 || timeLeft.hours > 0 || timeLeft.minutes > 0 || timeLeft.seconds > 0;
|
||||
|
||||
if (!isActive) return null;
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-red-500 to-red-600 text-white py-4 px-6 rounded-lg shadow-lg mb-8 animate-pulse">
|
||||
<div className="text-center">
|
||||
<h3 className="text-lg sm:text-xl font-bold mb-2">🔥 AKCIJA SE ZAVRŠAVA!</h3>
|
||||
<p className="text-sm sm:text-base mb-3">Popust od 5% važi još:</p>
|
||||
<div className="relative bg-gradient-to-r from-blue-500 via-purple-500 to-orange-500 text-white py-4 px-6 rounded-lg shadow-lg mb-8 overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent animate-shimmer"></div>
|
||||
<div className="relative text-center z-10">
|
||||
<h3 className="text-xl sm:text-2xl font-bold mb-2">AKCIJA SE ZAVRŠAVA!</h3>
|
||||
<p className="text-sm sm:text-base mb-3">
|
||||
Popust od <span className="text-2xl sm:text-3xl font-extrabold text-yellow-300 mx-1">{maxSalePercentage}%</span> važi još:
|
||||
</p>
|
||||
|
||||
<div className="flex justify-center gap-2 sm:gap-4">
|
||||
<div className="bg-white/20 backdrop-blur rounded-lg px-2 sm:px-3 py-2 min-w-[60px] sm:min-w-[70px]">
|
||||
@@ -89,10 +100,6 @@ export function SaleCountdown() {
|
||||
<div className="text-xs sm:text-sm opacity-90">sek</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-xs sm:text-sm mt-3 opacity-90">
|
||||
Poruči sada i uštedi na Bambu Lab filamentima!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -14,13 +14,17 @@ export function SaleManager({ filaments, selectedFilaments, onSaleUpdate }: Sale
|
||||
const [saleStartDate, setSaleStartDate] = useState('');
|
||||
const [saleEndDate, setSaleEndDate] = useState('');
|
||||
const [enableSale, setEnableSale] = useState(true);
|
||||
const [applyToAll, setApplyToAll] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSaleUpdate = async () => {
|
||||
if (selectedFilaments.size === 0) {
|
||||
alert('Molimo izaberite filamente za primenu popusta');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const filamentIds = applyToAll ? undefined : Array.from(selectedFilaments);
|
||||
const filamentIds = Array.from(selectedFilaments);
|
||||
|
||||
try {
|
||||
await filamentService.updateBulkSale({
|
||||
@@ -45,7 +49,6 @@ export function SaleManager({ filaments, selectedFilaments, onSaleUpdate }: Sale
|
||||
setSaleStartDate('');
|
||||
setSaleEndDate('');
|
||||
setEnableSale(true);
|
||||
setApplyToAll(false);
|
||||
} catch (error) {
|
||||
console.error('Error updating sale:', error);
|
||||
alert('Greška pri ažuriranju popusta');
|
||||
@@ -79,23 +82,9 @@ export function SaleManager({ filaments, selectedFilaments, onSaleUpdate }: Sale
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="flex items-center gap-2 mb-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={applyToAll}
|
||||
onChange={(e) => setApplyToAll(e.target.checked)}
|
||||
className="w-4 h-4 text-purple-600"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">
|
||||
Primeni na sve filamente
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{!applyToAll && (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
Izabrano: {selectedFilaments.size} filament{selectedFilaments.size === 1 ? '' : 'a'}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
Izabrano: {selectedFilaments.size} filament{selectedFilaments.size === 1 ? '' : 'a'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -166,7 +155,7 @@ export function SaleManager({ filaments, selectedFilaments, onSaleUpdate }: Sale
|
||||
<button
|
||||
onClick={handleSaleUpdate}
|
||||
className="px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600 disabled:opacity-50"
|
||||
disabled={loading || (!applyToAll && selectedFilaments.size === 0)}
|
||||
disabled={loading || selectedFilaments.size === 0}
|
||||
>
|
||||
{loading ? 'Ažuriranje...' : 'Primeni'}
|
||||
</button>
|
||||
|
||||
@@ -28,4 +28,18 @@
|
||||
.no-transitions * {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shimmer animation for sale banner */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-shimmer {
|
||||
animation: shimmer 3s ease-in-out infinite;
|
||||
}
|
||||
Reference in New Issue
Block a user