/* HopAIO Dashboard - main app */ const { useState, useEffect, useRef, useMemo, useCallback } = React; // ---------- Icons (inline SVG) ---------- const I = { dash: (p) => , tasks: (p) => , checkout: (p) => , monitor: (p) => , docs: (p) => , settings: (p) => , search: (p) => , key: (p) => , download: (p) => , pause: (p) => , play: (p) => , stop: (p) => , refresh: (p) => , filter: (p) => , copy: (p) => , ext: (p) => }; // ---------- Site catalog (real data from docs) ---------- const SITES = [ { code: 'alza', name: 'Alza', region: 'CZ/DE/AT/HU', color: '#ff6900' }, { code: 'mediaexpert', name: 'Mediaexpert', region: 'PL', color: '#e2061b' }, { code: 'mediamarkt', name: 'MediaMarkt', region: 'NL', color: '#df0000' }, { code: 'mediamarkt_de', name: 'MediaMarkt DE', region: 'DE', color: '#df0000' }, { code: 'empik', name: 'Empik', region: 'PL', color: '#ed1c24' }, { code: 'elbenwald', name: 'Elbenwald', region: 'DE/EU', color: '#7c5fff' }, { code: 'basketballemotion', name: 'BasketballEmotion', region: 'ES/EU', color: '#ff8000' }, { code: 'futbolemotion', name: 'FutbolEmotion', region: 'ES/EU', color: '#0064ff' }, { code: 'mycomics', name: 'MyComics', region: 'IT', color: '#ffd400' }, { code: 'fantasiastore', name: 'Fantasiastore', region: 'IT', color: '#9c27b0' }, { code: 'gamesisland', name: 'Games Island', region: 'DE/EU', color: '#00bcd4' }, { code: 'proshop', name: 'Proshop', region: 'DE/AT/NL/DK', color: '#27ae60' }, { code: 'solebox', name: 'Solebox', region: 'DE/EU', color: '#ff4081' }, { code: 'footshop', name: 'Footshop', region: 'CZ/EU', color: '#1a73e8' }, { code: 'skatedeluxe', name: 'Skatedeluxe', region: 'DE/EU', color: '#f57c00' }, { code: 'sportvision', name: 'Sportvision', region: 'CZ', color: '#e91e63' }, { code: 'sportsshoes', name: 'SportsShoes', region: 'UK/EU', color: '#1976d2' }, { code: 'frasers', name: 'Frasers (SD/Game/Flannels)', region: 'UK/EU', color: '#444' }, { code: 'skstore', name: 'SK Store / WSS', region: 'PL/EU', color: '#00897b' }, { code: 'zalando', name: 'Zalando', region: 'EU', color: '#ff6900' }, { code: 'secretlair', name: 'Secret Lair', region: 'EU', color: '#e23b3b' }, { code: 'lowkey', name: 'Lowkey', region: 'HU/CZ', color: '#888888' }, { code: 'endclothing', name: 'END. Clothing', region: 'UK/EU', color: '#000000' }, { code: 'travisscott', name: 'Travis Scott (DRAW)', region: 'US', color: '#b59169' }]; const siteByCode = (c) => SITES.find((s) => s.code === c) || { name: c, color: '#444', region: '—' }; // ---------- LOGIN ---------- // Normalize matches license_core.normalize_key() on the Python side: strip // every non-alnum char and uppercase. The dashboard's JSON files are written // at data/checkouts/.json so the two halves agree on the path. // Hosted dashboard backend. Defaults to the production host so the dashboard // works when opened from disk or any other origin. Override per-deployment by // setting window.HOP_API_BASE in an inline