Enterprise-Grade Wholesale Distribution Management System
A comprehensive full-stack solution handling complex business workflows including multi-tier user management, dynamic pricing, order processing, financial tracking, and automated notifications.
Built from scratch as a full-stack developer, this platform revolutionizes B2B wholesale operations
Sophisticated role-based access control with Superadmin, Admin, and Buyer roles. Dynamic user connections and granular permissions.
Real-time price calculations with buyer-specific discounts (rabat), automated price change tracking and notifications.
Complete order lifecycle from creation to fulfillment with status tracking, modifications, and professional PDF/Excel exports.
Dual-channel notifications (email + in-app) with smart routing, rate limiting, and automatic synchronization.
Real-time invoice management, balance monitoring, and automated ERP synchronization with daily reports.
Material-UI based interface with responsive design, smooth animations, and optimized performance for large datasets.
Modern, scalable architecture built with best practices and performance in mind
React-based SPA with Redux Toolkit for state management and RTK Query for API caching
PHP REST API with JWT authentication and role-based access control
MySQL database with optimized queries, proper indexing, and automated synchronization
Comprehensive feature set covering every aspect of B2B operations
Secure JWT-based authentication with role-based access control, password reset functionality, and session management.
// JWT Authentication Implementation const getAuthToken = () => localStorage.getItem('jwtToken'); export const mainApi = createApi({ baseQuery: fetchBaseQuery({ baseUrl: BASE_API_URL, prepareHeaders: (headers) => { const token = getAuthToken(); if (token) { headers.set('authorization', `Bearer ${token}`); } return headers; } }) });
Complete password reset workflow with email verification, secure token generation, and automatic admin notifications.
Hierarchical product organization (Family β Line β Group β Product) with advanced search, filtering, and real-time price calculations.
// Optimized Product Query with Buyer-Specific Pricing SELECT p.id, p.naziv, p.cena, (p.cena * (1 - COALESCE(r.rabat, 0) / 100)) AS final_price, p.stanje, p.jm, g.naziv AS group_name FROM Proizvodi p LEFT JOIN cene_kupci_rabat r ON p.grupa_id = r.grupa_id AND r.kupac_id = :buyer_id WHERE p.grupa_id = :group_id ORDER BY p.naziv
Complete order lifecycle management with creation, modification, status tracking, and professional exports.
Client-side PDF and Excel generation with custom styling, company branding, and complex layouts.
// PDF Generation with React-PDF import { Document, Page, Text, View } from '@react-pdf/renderer'; const PDFDocument = ({ orderData }) => ( <Document> <Page size="A4" style={styles.page}> <View style={styles.header}> <Text style={styles.title}>PorudΕΎbina #{orderData.id}</Text> </View> <View style={styles.table}> {orderData.items.map(item => ( <View style={styles.row} key={item.id}> <Text>{item.name}</Text> <Text>{item.quantity} x {item.price}</Text> </View> ))} </View> </Page> </Document> );
Comprehensive dual-channel notification system with email and in-app notifications, smart routing, and automatic synchronization.
// Notification Polling Implementation const { data: countData } = useGetNotificationCountQuery( undefined, { pollingInterval: 30000 // Poll every 30 seconds } ); // Backend: Automated Price Change Detection (track_price_changes.php) // - Runs daily via cron at 5 AM // - Compares current vs previous prices // - Creates notifications for affected buyers // - Filters by buyer's product group access // - Sends emails with retry logic and rate limiting // New feature: Buyer notification preferences stored in database // - Buyers can opt-in/out of specific notification types // - Notification preferences synced with platform notifications
Real-time financial tracking with automated ERP synchronization, invoice management, and balance monitoring.
Dynamic price list generation with buyer-specific discounts, PDF/Excel exports, and automated price change tracking.
Comprehensive admin dashboard for user management, product CRUD operations, image uploads, and document management.
// Image Compression & Upload import Compressor from 'compressorjs'; const compressImage = (file) => { return new Promise((resolve, reject) => { new Compressor(file, { quality: 0.6, maxWidth: 1920, maxHeight: 1080, success: (compressedFile) => resolve(compressedFile), error: (err) => reject(err) }); }); }; // Typically reduces file size by 70%
Modern React architecture with performance optimizations and best practices
// Optimistic UI Update with Rollback const [updateOrder] = useUpdateOrderMutation(); const handleStatusChange = async (orderId, newStatus) => { // Optimistically update UI immediately const patchResult = dispatch( mainApi.util.updateQueryData('getOrders', undefined, (draft) => { const order = draft.find(o => o.id === orderId); if (order) { order.status = newStatus; } }) ); try { // Make actual API call await updateOrder({ id: orderId, status: newStatus }).unwrap(); } catch (error) { // Rollback on error patchResult.undo(); showErrorNotification('Failed to update order'); } };
// Custom hook for debounced search const useDebounce = (value, delay = 300) => { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => clearTimeout(handler); }, [value, delay]); return debouncedValue; }; // Usage in SearchBar component const [searchTerm, setSearchTerm] = useState(''); const debouncedSearch = useDebounce(searchTerm, 300); // Only triggers API call after 300ms of no typing useEffect(() => { if (debouncedSearch) { fetchProducts(debouncedSearch); } }, [debouncedSearch]);
Robust PHP REST API with security, optimization, and automation
// Typical API endpoint structure (get_orders.php) require_once '../includes/db.php'; require_once '../includes/validation.php'; // 1. Verify JWT token $token = getBearerToken(); $decoded = verifyJWT($token); if (!$decoded) { http_response_code(401); echo json_encode(['error' => 'Unauthorized']); exit; } // 2. Check role-based permissions $role = $decoded->role; if (!in_array($role, ['admin', 'superadmin'])) { http_response_code(403); echo json_encode(['error' => 'Forbidden']); exit; } // 3. Validate and sanitize inputs $buyer_id = filter_input(INPUT_GET, 'buyer_id', FILTER_SANITIZE_STRING); // 4. Execute query with prepared statement $stmt = $conn->prepare(" SELECT o.*, u.company_name FROM orders o JOIN users u ON o.buyer_id = u.buyer_id WHERE o.buyer_id = :buyer_id ORDER BY o.created_at DESC "); $stmt->bindParam(':buyer_id', $buyer_id, PDO::PARAM_STR); $stmt->execute(); // 5. Return standardized JSON response $orders = $stmt->fetchAll(PDO::FETCH_ASSOC); http_response_code(200); echo json_encode($orders);
// track_price_changes.php - Runs daily at 5 AM via cron // 1. Detect price changes by comparing current vs previous prices $sql = " SELECT p.id, p.naziv, p.grupa_id, g.naziv as group_name, p.cena as current_price, pp.cena as previous_price FROM Proizvodi p JOIN Grupe g ON p.grupa_id = g.id LEFT JOIN Proizvodi_previous pp ON p.id = pp.id WHERE p.cena != pp.cena OR pp.cena IS NULL "; // 2. For each changed product, find affected buyers foreach ($changed_products as $product) { // Get buyers with rabat for this product group $buyers = getBuyersForGroup($product['grupa_id']); foreach ($buyers as $buyer) { // 3. Create email notification entry createPriceChangeNotification($buyer, $product); } } // 4. Email sending handled by separate cron (send_price_change_email_resend.php) // - Runs every 3 minutes between 5-12 AM // - Rate limited to 10 emails/second // - Creates platform notifications after successful email send // - Retry logic for failed emails
Measurable results and technical excellence