const { useState, useEffect, createContext, useContext, useRef } = React;
const Icon = ({ name, className, style }) => ;
const Package = (p) => ;
const Search = (p) => ;
const MapPin = (p) => ;
const Truck = (p) => ;
const CheckCircle2 = (p) => ;
const Clock = (p) => ;
const Globe = (p) => ;
const User = (p) => ;
const LogOut = (p) => ;
const Plus = (p) => ;
const Edit2 = (p) => ;
const Trash2 = (p) => ;
const Send = (p) => ;
const MessageSquare = (p) => ;
const Menu = (p) => ;
const X = (p) => ;
const Info = (p) => ;
const TrendingUp = (p) => ;
// --- MULTI-LANGUAGE DICTIONARY ---
const translations = {
en: {
hero_title: "Global Logistics & Tracking",
hero_subtitle: "Track your shipment instantly with real-time updates and seamless communication.",
track_placeholder: "Enter Tracking Number...",
track_btn: "Track Package",
admin_login: "Admin Login",
language: "Language",
status: "Status",
from: "From",
to: "To",
est_delivery: "Est. Delivery",
chat_with_us: "Chat with us",
send: "Send",
type_msg: "Type a message...",
not_found: "Tracking number not found.",
pending: "Pending",
in_transit: "In Transit",
delivered: "Delivered",
dashboard: "Dashboard",
manage_trackings: "Manage Trackings",
create_new: "Create New",
logout: "Logout",
save: "Save"
},
es: {
hero_title: "Logística y Seguimiento Global",
hero_subtitle: "Rastree su envío al instante con actualizaciones en tiempo real.",
track_placeholder: "Ingrese el número de seguimiento...",
track_btn: "Rastrear",
admin_login: "Acceso Admin",
language: "Idioma",
status: "Estado",
from: "De",
to: "A",
est_delivery: "Entrega Est.",
chat_with_us: "Chatea con nosotros",
send: "Enviar",
type_msg: "Escribe un mensaje...",
not_found: "Número no encontrado.",
pending: "Pendiente",
in_transit: "En Tránsito",
delivered: "Entregado",
dashboard: "Panel",
manage_trackings: "Gestionar Envíos",
create_new: "Crear Nuevo",
logout: "Cerrar sesión",
save: "Guardar"
},
fr: {
hero_title: "Logistique et Suivi Mondial",
hero_subtitle: "Suivez votre envoi instantanément avec des mises à jour en temps réel.",
track_placeholder: "Entrez le numéro de suivi...",
track_btn: "Suivre",
admin_login: "Connexion Admin",
language: "Langue",
status: "Statut",
from: "De",
to: "À",
est_delivery: "Livraison Est.",
chat_with_us: "Discutez avec nous",
send: "Envoyer",
type_msg: "Tapez un message...",
not_found: "Numéro de suivi introuvable.",
pending: "En attente",
in_transit: "En transit",
delivered: "Livré",
dashboard: "Tableau de bord",
manage_trackings: "Gérer les suivis",
create_new: "Créer un nouveau",
logout: "Déconnexion",
save: "Enregistrer"
}
};
const I18nContext = createContext();
const useI18n = () => useContext(I18nContext);
// --- MAIN APP COMPONENT ---
function App() {
const [lang, setLang] = useState('en');
const [view, setView] = useState(() => {
return window.location.hash.includes('#admin') ? 'admin' : 'home';
}); // home, admin
const t = translations[lang];
useEffect(() => {
const handleHashChange = () => {
if (window.location.hash.includes('#admin')) {
setView('admin');
} else {
setView('home');
}
};
window.addEventListener('hashchange', handleHashChange);
return () => window.removeEventListener('hashchange', handleHashChange);
}, []);
const changeLang = (l) => setLang(l);
const handleViewChange = (v) => {
if (v === 'admin') window.location.hash = '#admin';
else window.location.hash = '';
setView(v);
};
return (
{view === 'home' && }
{view === 'admin' && }
);
}
// --- NAVBAR ---
function Navbar({ view, setView }) {
const { t, lang, changeLang } = useI18n();
const [showLang, setShowLang] = useState(false);
return (
setShowLang(!showLang)} className="flex items-center text-slate-600 hover:text-slate-900 transition">
{lang}
{showLang && (
{['en', 'es', 'fr'].map(l => (
{ changeLang(l); setShowLang(false); }} className="block w-full text-left px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 transition">
{l.toUpperCase()}
))}
)}
);
}
// --- USER HOME ---
function UserHome() {
const { t } = useI18n();
const [trackingNumber, setTrackingNumber] = useState('');
const [trackingData, setTrackingData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSearch = async (e) => {
e.preventDefault();
if(!trackingNumber.trim()) return;
setLoading(true); setError(''); setTrackingData(null);
try {
const res = await fetch(`api.php?action=get_tracking_details&tn=${trackingNumber}`);
const data = await res.json();
if(data.status === 'success') {
setTrackingData(data.data);
} else {
setError(t.not_found);
}
} catch (err) {
setError("Network error.");
}
setLoading(false);
};
// Auto-refresh tracking data
useEffect(() => {
let interval;
if(trackingData) {
interval = setInterval(async () => {
const res = await fetch(`api.php?action=get_tracking_details&tn=${trackingData.tracking_number}`);
const data = await res.json();
if(data.status === 'success') {
setTrackingData(data.data);
}
}, 5000); // refresh every 5 sec
}
return () => clearInterval(interval);
}, [trackingData?.tracking_number]);
return (
{/* Background Grid & Blobs */}
{!trackingData ? (
{/* Floating decorative elements */}
{/* New Premium Floating Widgets */}
Next-Generation Global Logistics
{t.hero_title.split(' ').slice(0, -2).join(' ')}
{t.hero_title.split(' ').slice(-2).join(' ')}
{t.hero_subtitle}
{error &&
{error}
}
) : (
setTrackingData(null)} />
)}
{!trackingData && (
<>
{/* Companies Marquee */}
Trusted by Global Industry Leaders
{/* Duplicate for infinite effect */}
AMAZON
FEDEX
DHL
UPS
MAERSK
EBAY
WALMART
ALIEXPRESS
AMAZON
FEDEX
DHL
UPS
MAERSK
EBAY
WALMART
ALIEXPRESS
{/* Stats Section */}
{/* Features / How it works */}
Why Choose LogisX?
Experience the next generation of global logistics with real-time tracking, unmatched security, and lightning-fast delivery speeds.
Global Network
Our infrastructure spans across 150+ countries, ensuring your packages reach any corner of the globe securely and on time.
Real-Time Updates
Never wonder where your package is. Get instant status updates directly to your screen with precise GPS timestamps.
Live Support
Directly chat with our dispatchers and admin team regarding your specific tracking number in real-time, 24/7.
{/* Premium Services */}
Our Premium Services
We offer end-to-end logistics solutions tailored for businesses of all sizes. From standard parcels to heavy freight.
View All Services
{[
{ title: 'Air Freight', icon: 'plane', color: 'brand', text: 'brand-600', desc: 'Fastest delivery for your urgent global shipments.' },
{ title: 'Ocean Freight', icon: 'ship', color: 'cyan', text: 'cyan-600', desc: 'Cost-effective solutions for massive cargo volumes.' },
{ title: 'Road Transport', icon: 'truck', color: 'yellow', text: 'yellow-600', desc: 'Reliable cross-border and domestic trucking.' },
{ title: 'Warehousing', icon: 'warehouse', color: 'purple', text: 'purple-600', desc: 'Secure storage and fulfillment centers worldwide.' }
].map((s, i) => (
))}
{/* Testimonials */}
What Our Clients Say
"LogisX changed how we track shipments. The real-time updates and live support chat are absolutely incredible!"
S
Sarah JenkinsCEO, RetailCo
"Unmatched delivery speeds and an admin panel that is out of this world. Highly recommend to any logistics business."
M
Mark ThompsonOperations Manager
"The best tracking system we have ever used. The UI is simply beautiful and so easy to navigate."
A
Amanda R.E-commerce Seller
{/* Call to Action */}
Ready to revolutionize your supply chain?
Join thousands of businesses that trust LogisX for reliable, fast, and transparent global shipping.
Create an Account
Contact Sales
{/* Footer */}
window.scrollTo({top: 0, behavior: 'smooth'})}>
LogisX
© {new Date().getFullYear()} All rights reserved.
>
)}
);
}
function TrackingView({ data, onBack }) {
const { t } = useI18n();
return (
← Back to Search
{/* Left Column: Tracking Timeline */}
{data.tracking_number}
{data.current_status}
{data.updated_at}
Carrier
{data.carrier_name || 'LogisX Express'}
{/* Route Summary */}
{t.from}
{data.from_location}
{(()=>{
const progressValue = (data.progress !== null && data.progress !== undefined && data.progress !== '') ? `${data.progress}%` : (data.current_status === 'Delivered' ? '100%' : '50%');
return (
);
})()}
{t.to}
{data.to_location}
{/* Timeline */}
Tracking History
{data.updates && data.updates.map((up, i) => (
{up.status_text}
{up.timestamp} • {up.location}
{up.note &&
{up.note}
}
))}
{/* Right Column: Details & Chat */}
Shipment Details
Reference No.
{data.reference_number || 'N/A'}
Pieces
{data.pieces || '1'}
Package Type
{data.package_type || 'Standard Box'}
Weight
{data.weight || 'N/A'}
Pickup Time
{data.pickup_time || 'Pending'}
Departure Time
{data.departure_time || 'Pending'}
{t.est_delivery}
{data.estimated_delivery || 'Pending'}
{/* Chat Widget inside page */}
);
}
// --- CHAT BOX COMPONENT ---
function ChatBox({ trackingNumber, role }) {
const { t } = useI18n();
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [templates, setTemplates] = useState([]);
const chatContainerRef = useRef(null);
const sessionStart = useRef(Date.now());
const loadChat = async () => {
const sinceParam = role === 'user' ? `&since=${sessionStart.current}` : '';
const res = await fetch(`api.php?action=get_chat&tn=${trackingNumber}${sinceParam}`);
const data = await res.json();
if(data.status === 'success') {
setMessages(data.data);
}
};
useEffect(() => {
loadChat();
if (role === 'admin') {
fetch('api.php?action=get_chat_templates')
.then(r => r.json())
.then(d => { if(d.status === 'success') setTemplates(d.data); });
}
const interval = setInterval(loadChat, 3000); // Polling for real-time chat
return () => clearInterval(interval);
}, [trackingNumber, role]);
useEffect(() => {
if(chatContainerRef.current) {
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
}
}, [messages]);
const sendMsg = async (e, forceMsg = null) => {
if(e) e.preventDefault();
const msgText = forceMsg || input;
if(!msgText.trim()) return;
if(!forceMsg) setInput('');
// Optimistic UI update
setMessages(prev => [...prev, { sender: role, message: msgText, created_at: new Date().toISOString() }]);
await fetch('api.php?action=send_chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ tracking_number: trackingNumber, message: msgText })
});
loadChat();
};
return (
{messages.map((m, i) => {
const isMe = m.sender === role;
return (
{new Date(m.created_at).toLocaleTimeString()}
)
})}
{role === 'admin' && templates.length > 0 && (
{templates.map(tpl => (
sendMsg(null, tpl.message)} className="text-xs whitespace-nowrap bg-indigo-50 text-indigo-700 hover:bg-indigo-100 border border-indigo-200 px-3 py-1.5 rounded-full transition font-medium">
{tpl.title}
))}
)}
);
}
// --- ADMIN APP ---
function AdminApp() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('api.php?action=check_auth')
.then(res => res.json())
.then(data => {
if(data.status === 'success') setIsAuthenticated(true);
setLoading(false);
});
}, []);
if(loading) return ;
if(!isAuthenticated) return setIsAuthenticated(true)} />;
return setIsAuthenticated(false)} />;
}
function AdminLogin({ onLogin }) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleLogin = async (e) => {
e.preventDefault();
const res = await fetch('api.php?action=admin_login', {
method: 'POST',
body: JSON.stringify({ username, password })
});
const data = await res.json();
if(data.status === 'success') onLogin();
else setError(data.message);
};
return (
Admin Access
{error &&
{error}
}
);
}
function AdminDashboard({ onLogout }) {
const [stats, setStats] = useState(null);
const [trackings, setTrackings] = useState([]);
const [view, setView] = useState('list'); // list, create, edit
const [selectedTracking, setSelectedTracking] = useState(null);
const [activeChatTn, setActiveChatTn] = useState(null);
const loadData = async () => {
const resStats = await fetch('api.php?action=get_admin_stats');
const dStats = await resStats.json();
if(dStats.status === 'success') setStats(dStats.data);
const resTrk = await fetch('api.php?action=get_trackings');
const dTrk = await resTrk.json();
if(dTrk.status === 'success') setTrackings(dTrk.data);
};
useEffect(() => {
loadData();
const intv = setInterval(loadData, 10000);
return () => clearInterval(intv);
}, []);
const logout = async () => {
await fetch('api.php?action=admin_logout');
onLogout();
};
return (
{/* Sidebar */}
Menu
setView('list')} className={`flex items-center px-4 py-2 md:py-3 rounded-lg md:mb-2 transition whitespace-nowrap ${view==='list'?'bg-brand-50 text-brand-700 font-semibold':'text-slate-600 hover:bg-slate-50'}`}>
Trackings
setView('create')} className={`flex items-center px-4 py-2 md:py-3 rounded-lg md:mb-2 transition whitespace-nowrap ${view==='create'?'bg-brand-50 text-brand-700 font-semibold':'text-slate-600 hover:bg-slate-50'}`}>
Create New
setView('templates')} className={`flex items-center px-4 py-2 md:py-3 rounded-lg md:mb-2 transition whitespace-nowrap ${view==='templates'?'bg-brand-50 text-brand-700 font-semibold':'text-slate-600 hover:bg-slate-50'}`}>
Chat Templates
Active Chats
{stats?.active_chats?.map(c => (
setActiveChatTn(c.tracking_number)} className={`w-full flex items-center px-4 py-2 rounded-lg text-sm transition ${activeChatTn===c.tracking_number ? 'bg-indigo-50 text-indigo-700 font-semibold' : 'text-slate-600 hover:bg-slate-50'}`}>
{c.tracking_number}
))}
Logout
{/* Main Content */}
{stats && view === 'list' && (
Total Trackings
{stats.total}
Delivered
{stats.delivered}
)}
{view === 'templates' &&
}
{view === 'list' && (
Tracking No.
From/To
Status
Actions
{trackings.map(t => (
{t.tracking_number}
{t.from_location}
↓ {t.to_location}
{t.current_status}
{setSelectedTracking(t); setView('edit');}} className="p-2 text-slate-500 hover:text-indigo-600 hover:bg-indigo-50 rounded-lg mr-2 transition">
{
if(confirm('Delete?')) {
await fetch('api.php?action=delete_tracking', {method:'POST', body: JSON.stringify({id: t.id})});
loadData();
}
}} className="p-2 text-slate-500 hover:text-red-600 hover:bg-red-50 rounded-lg transition">
))}
)}
{(view === 'create' || view === 'edit') && (
{ setView('list'); loadData(); }}
onCancel={() => setView('list')}
/>
)}
{/* Floating Admin Chat Modal */}
{activeChatTn && (
Chat: {activeChatTn}
setActiveChatTn(null)} className="text-slate-500 hover:text-slate-900">
)}
);
}
function TrackingForm({ tracking, onSaved, onCancel }) {
const isEdit = !!tracking;
const [form, setForm] = useState(tracking || {
sender_name: '', sender_address: '', receiver_name: '', receiver_address: '',
from_location: '', to_location: '', weight: '', package_type: '', estimated_delivery: '',
carrier_name: 'LogisX Express', reference_number: '', pickup_time: '', departure_time: '', pieces: '1', created_at: '', progress: ''
});
// Status update logic (only for edit)
const [newStatus, setNewStatus] = useState('');
const [newLocation, setNewLocation] = useState('');
const [newNote, setNewNote] = useState('');
const [newTimestamp, setNewTimestamp] = useState('');
const [updates, setUpdates] = useState([]);
useEffect(() => {
if(isEdit) loadUpdates();
}, [tracking]);
const loadUpdates = async () => {
const res = await fetch(`api.php?action=get_tracking_details&tn=${tracking.tracking_number}`);
const data = await res.json();
if(data.status === 'success') setUpdates(data.data.updates || []);
};
const handleSubmit = async (e) => {
e.preventDefault();
const action = isEdit ? 'update_tracking' : 'create_tracking';
await fetch(`api.php?action=${action}`, {
method: 'POST',
body: JSON.stringify(form)
});
onSaved();
};
const handleAddStatus = async () => {
if(!newStatus) return;
await fetch(`api.php?action=add_status`, {
method: 'POST',
body: JSON.stringify({ tracking_id: tracking.id, status_text: newStatus, location: newLocation, note: newNote, timestamp: newTimestamp })
});
setNewStatus(''); setNewLocation(''); setNewNote(''); setNewTimestamp('');
loadUpdates();
onSaved(); // just to refresh parent
};
const handleDeleteStatus = async (updateId) => {
if(!confirm('Delete this status update?')) return;
await fetch(`api.php?action=delete_status`, {
method: 'POST',
body: JSON.stringify({ update_id: updateId, tracking_id: tracking.id })
});
loadUpdates();
onSaved();
};
const handleChange = (e) => setForm({...form, [e.target.name]: e.target.value});
return (
{isEdit ? 'Edit Tracking' : 'Create Tracking'} {isEdit && #{tracking.tracking_number} }
Cancel
{isEdit && (
Add Status Update
Manage History
{updates.map(up => (
{up.status_text}
{up.timestamp} • {up.location}
{up.note &&
{up.note}
}
handleDeleteStatus(up.id)} className="text-slate-400 hover:text-red-500 transition ml-2">
))}
)}
);
}
function AdminTemplates() {
const [templates, setTemplates] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [editId, setEditId] = useState(null);
const [title, setTitle] = useState('');
const [message, setMessage] = useState('');
const loadTemplates = async () => {
const res = await fetch('api.php?action=get_chat_templates');
const data = await res.json();
if(data.status === 'success') setTemplates(data.data);
};
useEffect(() => { loadTemplates(); }, []);
const handleSave = async (e) => {
e.preventDefault();
await fetch('api.php?action=save_chat_template', {
method: 'POST',
body: JSON.stringify({ id: editId, title, message })
});
setIsEditing(false);
setEditId(null);
setTitle('');
setMessage('');
loadTemplates();
};
const handleDelete = async (id) => {
if(!confirm('Are you sure you want to delete this template?')) return;
await fetch('api.php?action=delete_chat_template', {
method: 'POST',
body: JSON.stringify({ id })
});
loadTemplates();
};
const setAutoReply = async (id) => {
await fetch('api.php?action=set_auto_reply', {
method: 'POST',
body: JSON.stringify({ id })
});
loadTemplates();
};
return (
Chat Templates & Auto-Reply
{!isEditing && (
setIsEditing(true)} className="bg-brand-600 hover:bg-brand-700 text-white px-4 py-2 rounded-lg font-medium transition shadow-sm flex items-center">
Add Template
)}
{isEditing ? (
) : (
Auto-Reply Configuration
Select one template as an "Auto-Reply". When a user sends a message, the system will automatically reply with that template instantly. Set to "None" to disable auto-replies.
setAutoReply(null)} className={`px-4 py-2 rounded-lg text-sm font-semibold transition border ${!templates.find(t=>t.is_auto_reply==1) ? 'bg-slate-800 text-white border-slate-800' : 'bg-white text-slate-600 border-slate-300 hover:bg-slate-50'}`}>Disable Auto-Reply
{templates.map(tpl => (
{tpl.is_auto_reply == 1 && (
Active Auto-Reply
)}
{tpl.title}
{tpl.message}
setAutoReply(tpl.id)} className={`text-sm font-medium ${tpl.is_auto_reply == 1 ? 'text-slate-400 cursor-not-allowed' : 'text-brand-600 hover:text-brand-700'}`} disabled={tpl.is_auto_reply == 1}>
{tpl.is_auto_reply == 1 ? 'Current Auto-Reply' : 'Set as Auto-Reply'}
{ setTitle(tpl.title); setMessage(tpl.message); setEditId(tpl.id); setIsEditing(true); }} className="text-slate-400 hover:text-indigo-600 transition p-1">
handleDelete(tpl.id)} className="text-slate-400 hover:text-red-500 transition p-1">
))}
{templates.length === 0 && (
No chat templates created yet.
)}
)}
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( );