diff --git a/.DS_Store b/.DS_Store index 9d2444a7..b3b5687b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Ritz/.DS_Store b/Ritz/.DS_Store index f1462a45..33a52a4f 100644 Binary files a/Ritz/.DS_Store and b/Ritz/.DS_Store differ diff --git a/Ritz/Ritz.psd b/Ritz/Ritz.psd index 55a2b48a..e5e5771c 100644 Binary files a/Ritz/Ritz.psd and b/Ritz/Ritz.psd differ diff --git a/Ritz/download.png b/Ritz/download.png new file mode 100644 index 00000000..ee3afd25 Binary files /dev/null and b/Ritz/download.png differ diff --git a/Ritz/image-removebg-preview (6) copy.png b/Ritz/image-removebg-preview (6) copy.png new file mode 100644 index 00000000..612d8bbd Binary files /dev/null and b/Ritz/image-removebg-preview (6) copy.png differ diff --git a/frontend/src/assets/front.png b/frontend/src/assets/front.png new file mode 100644 index 00000000..6d0a636e Binary files /dev/null and b/frontend/src/assets/front.png differ diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index e0dd5394..006c482d 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -1,7 +1,58 @@ -import { Bell, Search, Settings, HelpCircle, Calendar } from 'lucide-react'; -import { Link } from 'react-router-dom'; +import { useState, useEffect, useRef } from 'react'; +import { + Bell, + Search, + Settings, + HelpCircle, + Calendar, + LayoutDashboard, + Store, + ShoppingBag, + History, + Users, + Package, + Layers, + FileText, + MessageSquare, + Wallet, + Ticket, + Cpu, + UserCheck, + TrendingUp, + ChevronRight +} from 'lucide-react'; +import { Link, useNavigate } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; + +const PAGES = [ + { label: 'General Dashboard', path: '/dashboard', category: 'Analytics', icon: }, + { label: 'Store Dashboard', path: '/store-dashboard', category: 'Analytics', icon: }, + { label: 'Active Orders', path: '/sale/orders', category: 'Sales', icon: }, + { label: 'Archived Bills', path: '/sale/archived-bills', category: 'Sales', icon: }, + { label: 'Manage Products', path: '/inventory/products', category: 'Inventory', icon: }, + { label: 'Base Menu', path: '/inventory/base', category: 'Inventory', icon: }, + { label: 'Ritz Overview', path: '/ritz/overview', category: 'Finance', icon: }, + { label: 'Manage Wallets', path: '/ritz/wallets', category: 'Finance', icon: }, + { label: 'Coupon Codes', path: '/ritz/coupons', category: 'Finance', icon: }, + { label: 'Reports & Analytics', path: '/reports', category: 'Support', icon: }, + { label: 'Customer Feedback', path: '/feedback', category: 'Support', icon: }, + { label: 'Staff Management', path: '/stores/staffs', category: 'Team', icon: }, + { label: 'Store Terminals', path: '/stores/terminals', category: 'System', icon: }, + { label: 'System Settings', path: '/settings', category: 'System', icon: }, +]; const Header = () => { + const navigate = useNavigate(); + const searchRef = useRef(null); + const [searchTerm, setSearchTerm] = useState(''); + const [showResults, setShowResults] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(0); + + const filteredPages = PAGES.filter(page => + page.label.toLowerCase().includes(searchTerm.toLowerCase()) || + page.category.toLowerCase().includes(searchTerm.toLowerCase()) + ).slice(0, 8); + const currentDate = new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', @@ -9,16 +60,97 @@ const Header = () => { day: 'numeric', }); + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (searchRef.current && !searchRef.current.contains(event.target as Node)) { + setShowResults(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'ArrowDown') { + setSelectedIndex(prev => (prev + 1) % filteredPages.length); + } else if (e.key === 'ArrowUp') { + setSelectedIndex(prev => (prev - 1 + filteredPages.length) % filteredPages.length); + } else if (e.key === 'Enter' && filteredPages[selectedIndex]) { + handleNavigate(filteredPages[selectedIndex].path); + } else if (e.key === 'Escape') { + setShowResults(false); + } + }; + + const handleNavigate = (path: string) => { + navigate(path); + setSearchTerm(''); + setShowResults(false); + }; + return ( -
+
-
- +
+ { + setSearchTerm(e.target.value); + setShowResults(true); + setSelectedIndex(0); + }} + onFocus={() => setShowResults(true)} + onKeyDown={handleKeyDown} /> + + + {showResults && searchTerm && ( + + {filteredPages.length > 0 ? ( +
+ {filteredPages.map((page, index) => ( + + ))} +
+ ) : ( +
+ +

No matching pages found

+
+ )} +
+ )} +
@@ -34,7 +166,7 @@ const Header = () => { - + diff --git a/ordering_site/src/pages/CheckoutScreen.css b/ordering_site/src/pages/CheckoutScreen.css index 09920acf..de0498b0 100644 --- a/ordering_site/src/pages/CheckoutScreen.css +++ b/ordering_site/src/pages/CheckoutScreen.css @@ -38,43 +38,66 @@ cursor: default; } -.ritz-payment-card.insufficient { - opacity: 0.8; - border-style: dashed; - background: rgba(239, 68, 68, 0.02); +.ritz-payment-card.insufficient-state { + border: 1px solid rgba(244, 63, 94, 0.3); + background: rgba(244, 63, 94, 0.03); + position: relative; + overflow: hidden; } -.ritz-icon { - background: #6366f1; +.ritz-payment-card.insufficient-state::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 4px; + background: #f43f5e; +} + +.status-badge-premium { + font-size: 0.65rem; + font-weight: 900; + padding: 0.25rem 0.75rem; + border-radius: 99px; + text-transform: uppercase; + letter-spacing: 0.05em; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); +} + +.status-badge-premium.error { + background: #f43f5e; color: white; } +.payment-icon.ritz-token-avatar { + background: transparent; + width: 54px; + height: 54px; + transform: scale(1.1); + filter: drop-shadow(0 4px 12px rgba(99, 102, 241, 0.2)); +} + +.token-image-main { + width: 100%; + height: 100%; + object-fit: contain; +} + .payment-name-row { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 0.5rem; -} - -.status-badge { - font-size: 0.7rem; - font-weight: 800; - padding: 0.2rem 0.6rem; - border-radius: 20px; - text-transform: uppercase; -} - -.status-badge.error { - background: rgba(239, 68, 68, 0.1); - color: #ef4444; + margin-bottom: 4px; } .wallet-balance-info { display: flex; align-items: center; - gap: 0.4rem; - font-size: 0.85rem; - color: var(--text-secondary); + gap: 6px; + font-size: 0.8rem; + color: #64748b; + font-weight: 500; } .balance-val { @@ -82,40 +105,49 @@ color: #6366f1; } +.insufficient-val { + color: #f43f5e !important; + text-decoration: line-through; + opacity: 0.7; +} + .add-tokens-checkout-btn { width: 100%; - margin-top: 1rem; + margin-top: 12px; background: white; - border: 1px dashed #6366f1; + border: 1.5px dashed rgba(99, 102, 241, 0.4); padding: 1rem; - border-radius: 16px; + border-radius: 18px; display: flex; align-items: center; justify-content: space-between; color: #6366f1; cursor: pointer; - transition: all 0.2s ease; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .add-tokens-checkout-btn:active { background: rgba(99, 102, 241, 0.05); + transform: scale(0.98); } .add-tokens-checkout-btn .btn-content { display: flex; align-items: center; - gap: 0.75rem; - font-weight: 700; + gap: 10px; + font-weight: 800; + font-size: 0.9rem; } .payment-security-note { display: flex; align-items: center; justify-content: center; - gap: 0.5rem; + gap: 6px; margin-top: 1.5rem; - color: var(--text-secondary); - font-size: 0.8rem; + color: #94a3b8; + font-size: 0.75rem; + font-weight: 500; } .ritz-text { @@ -123,26 +155,66 @@ font-weight: 800; } -.insufficient-warning { +.insufficient-warning-premium { margin: 1.5rem; - padding: 1rem; - background: rgba(255, 149, 0, 0.1); - border-radius: 16px; + padding: 1.25rem; + background: white; + border: 1px solid rgba(244, 63, 94, 0.1); + border-radius: 24px; display: flex; align-items: center; - gap: 1rem; - color: #cc7700; + gap: 1.25rem; + box-shadow: 0 12px 30px -10px rgba(244, 63, 94, 0.15); } -.warning-text h3 { - font-size: 0.95rem; - font-weight: 700; - margin-bottom: 0.1rem; +.token-warning-visual { + width: 60px; + height: 60px; + position: relative; + background: transparent; + filter: drop-shadow(0 6px 15px rgba(244, 63, 94, 0.2)); } -.warning-text p { +.token-image-mini { + width: 100%; + height: 100%; + object-fit: contain; + transform: rotate(-10deg); +} + +.warning-icon-overlay { + position: absolute; + bottom: -2px; + right: -2px; + width: 24px; + height: 24px; + background: #f43f5e; + color: white; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid white; + box-shadow: 0 4px 8px rgba(244, 63, 94, 0.3); +} + +.shortfall-amount { + font-size: 1rem; + font-weight: 800; + color: #334155; + margin-bottom: 0.25rem; +} + +.shortfall-amount .highlight { + color: #f43f5e; + font-size: 1.1rem; +} + +.warning-instruction { font-size: 0.8rem; - opacity: 0.9; + font-weight: 500; + color: #64748b; + margin: 0; } .ritz-order-btn { diff --git a/ordering_site/src/pages/CheckoutScreen.tsx b/ordering_site/src/pages/CheckoutScreen.tsx index abeb9f70..823f3c3b 100644 --- a/ordering_site/src/pages/CheckoutScreen.tsx +++ b/ordering_site/src/pages/CheckoutScreen.tsx @@ -8,6 +8,7 @@ import { ShieldCheck, PlusCircle } from 'lucide-react'; +import tokenImage from '../assets/display_ritz.png'; import { motion, AnimatePresence } from 'framer-motion'; import Header from '../components/Header'; import StockConflictModal from '../components/StockConflictModal'; @@ -139,21 +140,29 @@ const CheckoutScreen: React.FC = () => {
-
-
- +
+
+ Ritz Token
Pay with Ritz Tokens {isInsufficient && ( - Insufficient Balance + + Insufficient + )}
- - Current Balance: - R{currentBalance.toLocaleString()} + + Your Balance: + + R{currentBalance.toLocaleString()} +
{!isInsufficient && ( @@ -194,13 +203,24 @@ const CheckoutScreen: React.FC = () => {
{isInsufficient && ( -
- -
- Short by R{(totalPrice - currentBalance).toLocaleString()} -

Add more tokens to complete your order.

+ +
+ +
+ +
-
+
+
+ Short by R{(totalPrice - currentBalance).toLocaleString()} +
+

Add tokens to your wallet to complete this order.

+
+ )}