diff --git a/DATABASE_SETUP.md b/DATABASE_SETUP.md deleted file mode 100644 index c88e0d89..00000000 --- a/DATABASE_SETUP.md +++ /dev/null @@ -1,180 +0,0 @@ -# Database Setup Guide - -This document provides instructions for setting up and configuring the PostgreSQL database for the inventory management system. - -## Environment Variables - -The application requires the following PostgreSQL environment variables to be set: - -- `DATABASE_URL` - PostgreSQL connection string in the format `postgresql://username:password@host:port/database` -- `PGHOST` - PostgreSQL server hostname -- `PGUSER` - PostgreSQL username -- `PGPASSWORD` - PostgreSQL password -- `PGDATABASE` - PostgreSQL database name -- `PGPORT` - PostgreSQL server port (defaults to 5432) - -## Deployment Configuration - -When deploying the application, you need to configure the database connection in one of two ways: - -### Option 1: Using DATABASE_URL (Recommended) - -1. Go to your Replit project's "Secrets" tab in the Tools panel -2. Add a new secret with key `DATABASE_URL` and value in the format: - ``` - postgresql://username:password@host:port/database - ``` -3. Save the secret - -### Option 2: Using Individual PostgreSQL Parameters - -If you prefer to set individual parameters (for better secret management): - -1. Go to your Replit project's "Secrets" tab in the Tools panel -2. Add the following secrets: - - `PGHOST` - Your PostgreSQL server hostname - - `PGUSER` - Your PostgreSQL username - - `PGPASSWORD` - Your PostgreSQL password - - `PGDATABASE` - Your PostgreSQL database name - - `PGPORT` - Your PostgreSQL server port (optional, defaults to 5432) -3. Save all secrets - -The application will automatically detect and use these individual parameters if `DATABASE_URL` is not set. - -## Automatic Setup - -The application will automatically: - -1. Check database connection on startup -2. Create required tables if they don't exist -3. Set up database schema using Drizzle ORM - -If you encounter database connection issues, please verify your environment variables are correctly set. - -## Manual Database Initialization - -If you need to manually initialize the database: - -```bash -# Run the database setup script -node setup-db.js - -# OR manually use Drizzle to push the schema -npm run db:push -``` - -## Database Schema - -The database uses the following schema (defined in `shared/schema.ts`): - -- `users` - User accounts and authentication -- `inventoryItems` - Inventory product information -- `categories` - Product categories -- `warehouses` - Warehouse/location information -- `suppliers` - Supplier information -- `stockMovements` - Inventory movement history -- `purchaseRequisitions` - Purchase requisition records -- `purchaseOrders` - Purchase order records -- `reorderRequests` - Restock request records -- `appSettings` - Application configuration settings -- `customRoles` - Custom user roles -- `permissions` - Role-based access control permissions -- `userAccessLogs` - Security and access logging - -## Adding Custom Database Seed Data - -To add test data to your database, you can run SQL queries using the provided PostgreSQL connection: - -```sql --- Example: Add a test inventory item -INSERT INTO inventory_items (name, sku, description, price, quantity, category_id) -VALUES ('Test Product', 'TEST001', 'Test product description', 99.99, 100, 1); -``` - -## Troubleshooting - -### Connection Issues - -If you encounter connection errors: - -1. Verify your PostgreSQL server is running -2. Ensure your environment variables are correctly set -3. Check network connectivity to the database server -4. Verify firewall settings allow connections to PostgreSQL port - -### Schema Issues - -If you encounter schema errors: - -1. Run `npm run db:push` to update the schema -2. Check for any migration errors in the console -3. Verify the database user has sufficient permissions - -### Performance Optimization - -For production environments: - -1. Enable PostgreSQL connection pooling -2. Configure appropriate pool size based on expected load -3. Consider using a managed PostgreSQL service for production deployments - -## Advanced Configuration - -### Connection Pooling - -The application uses connection pooling to improve performance. You can configure the pool by modifying the `db.ts` file: - -```typescript -export const pool = new Pool({ - connectionString: process.env.DATABASE_URL, - max: 20, // Maximum number of clients in the pool - idleTimeoutMillis: 30000, // How long a client is allowed to remain idle before being closed - connectionTimeoutMillis: 2000, // How long to wait for a connection -}); -``` - -### SSL Configuration - -For secure connections, you can enable SSL by adding the following to your connection options: - -```typescript -export const pool = new Pool({ - connectionString: process.env.DATABASE_URL, - ssl: { - rejectUnauthorized: false // Set to true in production with proper certificates - } -}); -``` - -## Setting Up For Development - -1. Install PostgreSQL locally or use a Docker container -2. Create a database for the application -3. Set up the required environment variables -4. Run the application to initialize the schema - -## Production Considerations - -1. Use a managed PostgreSQL service (AWS RDS, Google Cloud SQL, etc.) -2. Set up proper database backups -3. Configure high availability and failover -4. Implement database monitoring -5. Use secure connection strings and store credentials safely - -## Replit Deployment Configuration - -When deploying your application on Replit: - -1. Navigate to the "Secrets" tab in your Replit project (lock icon in the tools panel) -2. Add the following secrets: - - `DATABASE_URL` (if using the connection string approach) - - Or individual parameters: `PGHOST`, `PGUSER`, `PGPASSWORD`, `PGDATABASE`, `PGPORT` -3. Click "Add new secret" for each entry -4. Format the DATABASE_URL as: `postgresql://username:password@host:port/database` -5. Make sure your PostgreSQL server allows connections from Replit's IP ranges -6. For Neon Database or similar serverless PostgreSQL services: - - Use the connection string from your database provider dashboard - - Ensure WebSocket support is enabled (for Neon Database) - - Set SSL mode appropriately (usually `{ rejectUnauthorized: false }`) - -The application will automatically use these environment variables during deployment and runtime. \ No newline at end of file diff --git a/DESKTOP_APP_SETUP.md b/DESKTOP_APP_SETUP.md deleted file mode 100644 index 8f3f2ecd..00000000 --- a/DESKTOP_APP_SETUP.md +++ /dev/null @@ -1,195 +0,0 @@ -# Desktop Application Setup Guide - -This document provides instructions for setting up and building the Electron desktop version of the inventory management system. - -## Overview - -The inventory management system can be run as: -1. A web application hosted on a server -2. A desktop application using Electron - -The desktop version provides: -- Better performance for local usage -- Offline capabilities with local data synchronization -- Native operating system integration -- Secure local database for sensitive inventory data - -## Prerequisites - -Before building the desktop application, ensure you have: - -- Node.js (v18.x or later) installed -- npm (v9.x or later) installed -- Git installed -- Required build tools for your operating system: - - Windows: Visual Studio Build Tools - - macOS: Xcode Command Line Tools - - Linux: GCC and related build packages - -## Development Setup - -### 1. Install Dependencies - -First, install all required dependencies: - -```bash -npm install -``` - -### 2. Run in Development Mode - -To run the application in development mode: - -```bash -# Start the development server and Electron app -npm run electron:dev - -# OR use the provided script -./start-electron-dev.sh -``` - -This will start: -- The Express backend server -- The Electron application connected to the backend - -### 3. Making Changes - -When developing the desktop application: - -- Web/UI changes: Modify files in the `client/src` directory -- Electron-specific changes: Modify files in the `electron` directory -- Backend changes: Modify files in the `server` directory - -## Building for Distribution - -### 1. Prerequisites for Building - -Ensure your environment is set up correctly: - -```bash -# Install required global packages -npm install -g electron-builder -``` - -### 2. Build Process - -To build the desktop application: - -```bash -# Build for the current platform -npm run electron:build - -# OR use the provided script -./build-electron.sh -``` - -This will: -1. Build the React frontend using Vite -2. Compile the server-side code with esbuild -3. Package everything with Electron builder - -### 3. Platform-Specific Builds - -To build for specific platforms: - -```bash -# Windows -npm run electron:build:win - -# macOS -npm run electron:build:mac - -# Linux -npm run electron:build:linux -``` - -The build outputs will be available in the `dist` directory. - -## Deployment Configuration - -### Local Database Setup - -The desktop application uses SQLite for local data storage. This is automatically configured when the application is installed. - -### Data Synchronization - -Configure synchronization settings in the application: - -1. Navigate to Settings > Sync -2. Enter your server URL -3. Configure sync frequency and options -4. Enable offline mode if needed - -### Auto Updates - -The application supports auto-updates: - -1. Host the update files on a server -2. Configure `electron-builder.json` with the update URL -3. Build the application with auto-update support enabled - -## Troubleshooting - -### Common Issues - -#### Application Won't Start - -- Check logs in `%APPDATA%/inventory-manager/logs` (Windows) or `~/Library/Logs/inventory-manager` (macOS) -- Verify all dependencies are installed -- Check permissions on installation directory - -#### Database Errors - -- Check SQLite database file integrity -- Verify user has write permissions to the database directory -- Try resetting the database from Settings > Advanced - -#### Sync Problems - -- Verify server URL is correct -- Check network connectivity -- Ensure server API is compatible with client version - -## Advanced Configuration - -### Custom Installation - -You can customize the installation directory and other options in `electron-builder.json`: - -```json -{ - "appId": "com.yourcompany.inventory-manager", - "productName": "Inventory Manager", - "directories": { - "output": "dist" - }, - "win": { - "target": ["nsis"], - "icon": "build/icon.ico" - }, - "mac": { - "target": ["dmg"], - "icon": "build/icon.icns" - }, - "linux": { - "target": ["AppImage", "deb"], - "icon": "build/icon.png" - } -} -``` - -### Custom Database Location - -To change where data is stored: - -1. Modify `electron/db.js` to specify a custom database path -2. Rebuild the application - -### Security Considerations - -For enhanced security: - -1. Enable data encryption in Settings > Security -2. Use strong passwords for application access -3. Regularly backup your database -4. Keep the application updated to the latest version \ No newline at end of file diff --git a/PROJECT_OVERVIEW.txt b/PROJECT_OVERVIEW.txt new file mode 100644 index 00000000..8b56a052 --- /dev/null +++ b/PROJECT_OVERVIEW.txt @@ -0,0 +1,129 @@ +SkillRadius Codebase Overview +============================= + +This repository now contains a web-first freelancer marketplace UI. The legacy +inventory, billing, reporting, and Electron desktop code has been removed to +focus on the SkillRadius experience. + +Top-level files +--------------- +- package.json + Defines client-only scripts (dev/build/preview/check) for the Vite UI. +- tsconfig.json / tsconfig.check.json + TypeScript configuration; check config scopes typechecking to client/shared. +- vite.config.ts + Vite configuration for the client app and path aliases. +- tailwind.config.ts / postcss.config.js / theme.json + Styling and theme configuration for the UI. + +Client application (client/) +--------------------------- +- client/index.html + HTML entry point for the Vite app. + +- client/src/main.tsx + React entry point; mounts the app and global styles. + +- client/src/App.tsx + Router + layout composition. Routes include: + - / + - /discover + - /jobs + - /messages + - /reviews + - /profile + - /settings + - /auth + +Pages (client/src/pages/) +------------------------- +- home.tsx + Marketplace landing page: hero, stats, map placeholder, filters, and + freelancer cards. + +- discover.tsx + Search + filter screen with a map placeholder. + +- jobs.tsx + Jobs list and β€œpost a job” action. + +- messages.tsx + Messaging inbox view with conversations. + +- reviews.tsx + Client feedback list with star ratings. + +- profile.tsx + Freelancer profile details, verification, reputation, and availability. + +- settings.tsx + Account preferences for notifications, availability, and safety. + +- auth-page.tsx + Sign-in screen with basic login inputs and brand messaging. + +- not-found.tsx + Fallback 404 screen. + +Components (client/src/components/) +---------------------------------- +- sidebar.tsx + Navigation for the SkillRadius routes. + +- header.tsx + Top header layout for the app pages. + +- layout/desktop-layout.tsx + Main layout wrapper (sidebar + header + content area). + +- page-header.tsx + Shared header component for sections. + +- theme-provider.tsx + Theme state and toggles. + +- ui/ + Shadcn UI primitives (buttons, cards, inputs, badges, tabs, etc.). + +Contexts (client/src/contexts/) +------------------------------- +- tutorial-context.tsx / TutorialContext.tsx + Walkthrough/tutorial context; still present but currently UI-only. + +Hooks (client/src/hooks/) +------------------------- +- use-auth.tsx + Auth hooks with login/logout flow used on the auth page and protected routes. + +- use-mobile.tsx + Responsive helper hook. + +- use-toast.ts + Toast notification helper. + +Library (client/src/lib/) +------------------------- +- queryClient.ts + React Query client configuration and API helper. + +- protected-route.tsx + Route guard component for authenticated pages. + +- utils.ts + Utility helpers (class name merging, formatting, etc.). + +- config.ts + Feature flag management for web-only behavior. + +- document-generator.ts + Browser-first PDF/CSV/Excel generation helpers. + +Shared (shared/) +---------------- +- shared/ holds shared types, schemas, and utilities consumed by the client. + +Notes +----- +- Electron/desktop code, server APIs, inventory/billing/reporting modules, + and related assets have been removed. +- The app is now a client-only, web-first SkillRadius marketplace UI. diff --git a/attached_assets/Pasted--Step-1-Database-Schema-Updated-with-Profile-Picture-Storage-Your-users-table-should-include-a--1743502078295.txt b/attached_assets/Pasted--Step-1-Database-Schema-Updated-with-Profile-Picture-Storage-Your-users-table-should-include-a--1743502078295.txt deleted file mode 100644 index 8f059e68..00000000 --- a/attached_assets/Pasted--Step-1-Database-Schema-Updated-with-Profile-Picture-Storage-Your-users-table-should-include-a--1743502078295.txt +++ /dev/null @@ -1,167 +0,0 @@ -πŸ”Ή Step 1: Database Schema (Updated with Profile Picture Storage) -Your users table should include a profile picture URL field: - -sql -Copy -Edit -CREATE TABLE users ( - id SERIAL PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - email VARCHAR(100) UNIQUE NOT NULL, - password_hash TEXT NOT NULL, - profile_picture TEXT, -- URL of the profile picture (Stored in Cloud) - role VARCHAR(20) DEFAULT 'user', - created_at TIMESTAMP DEFAULT NOW() -); -πŸ”Ή Step 2: Upload Profile Pictures (Backend API) -Storage Options: -βœ… Cloudinary (Recommended) -βœ… AWS S3 -βœ… Firebase Storage - -Install Required Libraries (Node.js Example) -sh -Copy -Edit -npm install multer cloudinary dotenv express -Backend API for Uploading Profile Pictures -javascript -Copy -Edit -const express = require("express"); -const multer = require("multer"); -const cloudinary = require("cloudinary").v2; -const { CloudinaryStorage } = require("multer-storage-cloudinary"); -require("dotenv").config(); - -const app = express(); -app.use(express.json()); - -// Configure Cloudinary -cloudinary.config({ - cloud_name: process.env.CLOUDINARY_CLOUD_NAME, - api_key: process.env.CLOUDINARY_API_KEY, - api_secret: process.env.CLOUDINARY_API_SECRET, -}); - -// Multer Storage for Cloudinary -const storage = new CloudinaryStorage({ - cloudinary, - params: { - folder: "profile_pictures", - allowed_formats: ["jpg", "png", "jpeg"], - }, -}); -const upload = multer({ storage }); - -// Profile Picture Upload API -app.post("/upload-profile", upload.single("profile_picture"), async (req, res) => { - try { - const imageUrl = req.file.path; - res.json({ success: true, imageUrl }); - } catch (error) { - res.status(500).json({ success: false, message: "Upload failed" }); - } -}); - -// Start Server -app.listen(3000, () => console.log("Server running on port 3000")); -πŸ”Ή Step 3: Update Profile Picture URL in the Database -Modify User Profile API to Store Image URL -javascript -Copy -Edit -const updateProfile = async (req, res) => { - const { userId, username, email, profilePicture } = req.body; - - const updatedUser = await User.findByIdAndUpdate( - userId, - { username, email, profile_picture: profilePicture }, - { new: true } - ); - - res.json(updatedUser); -}; -πŸ”Ή Step 4: Frontend (React) Profile Picture Upload -Install Axios for API Requests -sh -Copy -Edit -npm install axios -React Component for Profile Picture Upload -jsx -Copy -Edit -import { useState } from "react"; -import axios from "axios"; - -export default function ProfilePictureUpload() { - const [image, setImage] = useState(null); - const [uploading, setUploading] = useState(false); - - const handleUpload = async (event) => { - setUploading(true); - const file = event.target.files[0]; - const formData = new FormData(); - formData.append("profile_picture", file); - - try { - const response = await axios.post("/upload-profile", formData); - console.log("Uploaded Image URL:", response.data.imageUrl); - } catch (error) { - console.error("Upload Failed", error); - } finally { - setUploading(false); - } - }; - - return ( -
- - {uploading &&

Uploading...

} -
- ); -} -πŸ”Ή Step 5: Profile Management Features -Users should be able to: -βœ… Edit Profile Info (Name, Email, Address) -βœ… Change Profile Picture -βœ… Set Preferences (Dark Mode, Notifications, etc.) -βœ… Reset Password -βœ… View Account Activity - -Profile Page (React) -jsx -Copy -Edit -import { useState, useEffect } from "react"; -import axios from "axios"; - -export default function Profile() { - const [user, setUser] = useState(null); - - useEffect(() => { - axios.get("/api/profile").then(response => setUser(response.data)); - }, []); - - if (!user) return

Loading...

; - - return ( -
-

{user.username}

- Profile -

Email: {user.email}

-
- ); -} -πŸ”Ή Step 6: User Settings & Security Features -βœ” Privacy Settings – Make profile public/private -βœ” Notification Preferences – Email/SMS alerts -βœ” Multi-Factor Authentication (MFA) – Extra security for logins -βœ” Dark Mode & UI Customization - -🎯 Final Steps -βœ… Setup Backend API for Profile Management -βœ… Enable Profile Picture Upload to Cloudinary -βœ… Build React Frontend for User Profiles -βœ… Add Security Features (MFA, Privacy Settings, etc.) \ No newline at end of file diff --git a/attached_assets/Pasted-1-Advanced-Inventory-Management-Real-Time-Inventory-Sync-Automatically-update-stock-levels-acro-1743321664353.txt b/attached_assets/Pasted-1-Advanced-Inventory-Management-Real-Time-Inventory-Sync-Automatically-update-stock-levels-acro-1743321664353.txt deleted file mode 100644 index 37c6b3ed..00000000 --- a/attached_assets/Pasted-1-Advanced-Inventory-Management-Real-Time-Inventory-Sync-Automatically-update-stock-levels-acro-1743321664353.txt +++ /dev/null @@ -1,41 +0,0 @@ -1. Advanced Inventory Management -βœ… Real-Time Inventory Sync – Automatically update stock levels across multiple locations and sales channels. -βœ… AI-Powered Stock Optimization – Machine learning to suggest reorder quantities based on sales trends. -βœ… Automated Stock Transfers – If one warehouse is low, the system can suggest or automate stock transfers. -βœ… Multi-Warehouse and Multi-Location Tracking – Real-time tracking of stock in multiple locations. -βœ… Batch & Expiry Tracking – Ideal for perishable goods and medical supplies. - -2. AI & Automation Enhancements -βœ… Predictive Restocking – AI-driven demand forecasting to prevent stockouts. -βœ… Smart Notifications – Get alerts for stock depletion, slow-moving products, or excess stock. -βœ… Auto-Generated Purchase Orders – AI can suggest or auto-create POs when stock is low. -βœ… Supplier Performance Tracking – Rate and track supplier reliability based on delivery time, defect rate, and cost trends. -βœ… Auto-Categorization – AI can classify products based on purchase patterns. - -3. Advanced Reporting & Analytics -βœ… Smart Dashboards – AI-based trend analysis to provide insights into stock performance. -βœ… Custom Reports – Users can generate reports based on SKU, supplier, warehouse, or time period. -βœ… Cost Analysis & Profit Tracking – Helps determine which inventory is the most profitable. -βœ… Loss Prevention Analytics – Detects potential fraud or shrinkage trends. - -4. High-Level Integration Capabilities -βœ… ERP & Accounting Software Integration – Seamless sync with SAP, Oracle, Sage, and QuickBooks. -βœ… POS & E-commerce Integration – Connect with Shopify, WooCommerce, Amazon, or retail POS systems. -βœ… API Access for Custom Integrations – Allows businesses to integrate their own tools. -βœ… IoT & RFID Support – Automate tracking using RFID tags or IoT sensors for real-time visibility. - -5. Security, Compliance & Backup -βœ… Role-Based Access Control (RBAC) – Different user access levels to prevent unauthorized changes. -βœ… Automated Data Backups – Daily cloud backups for security. -βœ… Audit Trail & Change Logs – Full visibility on who made what changes and when. -βœ… Compliance Features – Adhere to industry standards like ISO, GDPR, or FDA regulations (for medical and food inventory). - -6. Smart Mobile & Web App Features -βœ… Voice-Controlled Inventory Search – Users can speak to the app to find products. -βœ… AI Chatbot for Support – An assistant that helps with queries, stock levels, or purchase orders. -βœ… Augmented Reality (AR) for Warehouse Navigation – Helps workers find products using AR mapping. -βœ… Offline Mode – The app should work even without an internet connection, syncing once online. - -7. Blockchain for High Security (Optional but Future-Proofing) -βœ… Tamper-Proof Inventory Logs – Blockchain records each inventory movement securely. -βœ… Smart Contracts for Procurement – Automated supplier agreements based on predefined conditions. \ No newline at end of file diff --git a/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743434758051.txt b/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743434758051.txt deleted file mode 100644 index 78041c4b..00000000 --- a/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743434758051.txt +++ /dev/null @@ -1,149 +0,0 @@ -Core Inventory Management (Database + Backend) πŸ“¦ -πŸ’‘ Features: -βœ… AI Image Recognition for Item Entry -βœ… Voice Command Stock Management -βœ… Geo-Fencing for Stock Tracking - -πŸ› οΈ Tech Stack: - -Backend: Node.js (Express.js) or Python (FastAPI/Django) for fast processing - -Database: PostgreSQL (Structured data) + MongoDB (Unstructured metadata like images) - -Storage: AWS S3 or Firebase for storing item images - -AI Integration: OpenAI Vision API or Google Cloud Vision for recognizing inventory items - -Voice Processing: Google Speech-to-Text API for voice commands - -Geo-Fencing: Google Maps API + Firebase Realtime Database for location tracking - -πŸ”Ή Settings to Include: -βœ” Custom Item Categories & Tags -βœ” Configurable Units of Measure (kg, liters, boxes) -βœ” Adjustable Inventory Thresholds - -2️⃣ Automation & AI Features (AI + ML Models) πŸ€– -πŸ’‘ Features: -βœ… AI-Powered Theft & Fraud Detection -βœ… Dynamic Pricing Adjustments -βœ… Predictive Maintenance Alerts - -πŸ› οΈ Tech Stack: - -AI Models: TensorFlow or PyTorch (for demand forecasting and fraud detection) - -Automation Framework: Apache Airflow (for scheduling and automation) - -Predictive Analytics: AWS SageMaker or Google Vertex AI - -AI Pricing Models: OpenAI API or Reinforcement Learning algorithms - -πŸ”Ή Settings to Include: -βœ” AI-Based Reordering Sensitivity (User can adjust AI predictions) -βœ” Fraud Risk Level (Low, Medium, High) -βœ” Real-Time Pricing Rules - -3️⃣ Reporting & Analytics (Real-Time Data Processing) πŸ“Š -πŸ’‘ Features: -βœ… Real-Time Inventory Heatmaps -βœ… Competitor Inventory Benchmarking -βœ… AI-Generated Actionable Insights - -πŸ› οΈ Tech Stack: - -Data Processing: Apache Kafka + Apache Spark (for real-time analytics) - -Visualization: Tableau, Power BI, or Grafana (for dashboards) - -Big Data Storage: Google BigQuery or AWS Redshift - -Competitor Benchmarking: Scrapy or Selenium (for web scraping competitor pricing) - -πŸ”Ή Settings to Include: -βœ” Customizable Report Filters (Time Range, Product Category) -βœ” Data Export Formats (PDF, Excel, CSV) -βœ” AI Insights Frequency (Daily, Weekly, Monthly) - -4️⃣ Integration Features (APIs & External Systems) πŸ”„ -πŸ’‘ Features: -βœ… Smart ERP Plug-and-Play Modules -βœ… IoT-Enabled Inventory Updates -βœ… Social Commerce Integration - -πŸ› οΈ Tech Stack: - -API Management: GraphQL or REST API using Apollo Server or FastAPI - -ERP Integration: Odoo, SAP, or Oracle NetSuite (via REST APIs) - -IoT Connectivity: MQTT Protocol + AWS IoT Core - -E-commerce Sync: Shopify/WooCommerce/Amazon APIs - -πŸ”Ή Settings to Include: -βœ” Toggle Integrations On/Off (ERP, E-commerce, IoT) -βœ” API Key Management for Secure External Connections -βœ” Sync Frequency Settings (Live, 1-Hour, Daily) - -5️⃣ Security & Access Control (Authentication & Compliance) πŸ” -πŸ’‘ Features: -βœ… AI-Driven Role-Based Permissions -βœ… Biometric Authentication for High-Risk Actions -βœ… Smart Device Access Control - -πŸ› οΈ Tech Stack: - -Authentication: Firebase Auth, Auth0, or AWS Cognito (for secure login) - -Biometric Security: Android Biometric API, Apple Face ID API - -Audit Logs & Security Monitoring: ELK Stack (Elasticsearch, Logstash, Kibana) - -Blockchain-Based Ledger: Hyperledger Fabric for tamper-proof inventory records - -πŸ”Ή Settings to Include: -βœ” User Role Management (Admin, Manager, Staff, Auditor) -βœ” MFA Enable/Disable Option -βœ” Auto-Logout Timer (Adjustable) - -6️⃣ Mobile & Cloud Features (Cross-Platform Usability) πŸ“±β˜ -πŸ’‘ Features: -βœ… Offline Mode with Smart Sync -βœ… Wearable Integration (Smartwatches & AR Glasses) -βœ… AI-Powered Voice Assistant - -πŸ› οΈ Tech Stack: - -Mobile App: Flutter (Dart) or React Native for cross-platform development - -Cloud Backend: Firebase Firestore + AWS Lambda (Serverless) - -AR Integration: ARKit (iOS) + ARCore (Android) - -Wearable Connectivity: Google WearOS + Apple WatchKit - -πŸ”Ή Settings to Include: -βœ” Offline Sync Frequency (Immediate, Manual, Scheduled) -βœ” Voice Command Sensitivity -βœ” Toggle Wearable Features On/Off - -7️⃣ Advanced Features (Futuristic & Enterprise-Level) πŸš€ -πŸ’‘ Features: -βœ… Drone-Powered Stock Audits -βœ… AI-Driven Inventory Auto-Classification -βœ… Digital Twin for Warehouse Simulation - -πŸ› οΈ Tech Stack: - -Drone Integration: DJI SDK or OpenCV for image-based inventory scanning - -Digital Twin Simulation: Unity3D + NVIDIA Omniverse - -RFID & IoT Sensors: Azure IoT Hub or AWS IoT Greengrass - -πŸ”Ή Settings to Include: -βœ” Digital Twin Simulation Speed (Normal, Fast) -βœ” Drone Audit Frequency -βœ” RFID Scan Distance Adjustment - diff --git a/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743435690258.txt b/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743435690258.txt deleted file mode 100644 index 78041c4b..00000000 --- a/attached_assets/Pasted-Core-Inventory-Management-Database-Backend-Features-AI-Image-Recognition-for-Item-Entry-1743435690258.txt +++ /dev/null @@ -1,149 +0,0 @@ -Core Inventory Management (Database + Backend) πŸ“¦ -πŸ’‘ Features: -βœ… AI Image Recognition for Item Entry -βœ… Voice Command Stock Management -βœ… Geo-Fencing for Stock Tracking - -πŸ› οΈ Tech Stack: - -Backend: Node.js (Express.js) or Python (FastAPI/Django) for fast processing - -Database: PostgreSQL (Structured data) + MongoDB (Unstructured metadata like images) - -Storage: AWS S3 or Firebase for storing item images - -AI Integration: OpenAI Vision API or Google Cloud Vision for recognizing inventory items - -Voice Processing: Google Speech-to-Text API for voice commands - -Geo-Fencing: Google Maps API + Firebase Realtime Database for location tracking - -πŸ”Ή Settings to Include: -βœ” Custom Item Categories & Tags -βœ” Configurable Units of Measure (kg, liters, boxes) -βœ” Adjustable Inventory Thresholds - -2️⃣ Automation & AI Features (AI + ML Models) πŸ€– -πŸ’‘ Features: -βœ… AI-Powered Theft & Fraud Detection -βœ… Dynamic Pricing Adjustments -βœ… Predictive Maintenance Alerts - -πŸ› οΈ Tech Stack: - -AI Models: TensorFlow or PyTorch (for demand forecasting and fraud detection) - -Automation Framework: Apache Airflow (for scheduling and automation) - -Predictive Analytics: AWS SageMaker or Google Vertex AI - -AI Pricing Models: OpenAI API or Reinforcement Learning algorithms - -πŸ”Ή Settings to Include: -βœ” AI-Based Reordering Sensitivity (User can adjust AI predictions) -βœ” Fraud Risk Level (Low, Medium, High) -βœ” Real-Time Pricing Rules - -3️⃣ Reporting & Analytics (Real-Time Data Processing) πŸ“Š -πŸ’‘ Features: -βœ… Real-Time Inventory Heatmaps -βœ… Competitor Inventory Benchmarking -βœ… AI-Generated Actionable Insights - -πŸ› οΈ Tech Stack: - -Data Processing: Apache Kafka + Apache Spark (for real-time analytics) - -Visualization: Tableau, Power BI, or Grafana (for dashboards) - -Big Data Storage: Google BigQuery or AWS Redshift - -Competitor Benchmarking: Scrapy or Selenium (for web scraping competitor pricing) - -πŸ”Ή Settings to Include: -βœ” Customizable Report Filters (Time Range, Product Category) -βœ” Data Export Formats (PDF, Excel, CSV) -βœ” AI Insights Frequency (Daily, Weekly, Monthly) - -4️⃣ Integration Features (APIs & External Systems) πŸ”„ -πŸ’‘ Features: -βœ… Smart ERP Plug-and-Play Modules -βœ… IoT-Enabled Inventory Updates -βœ… Social Commerce Integration - -πŸ› οΈ Tech Stack: - -API Management: GraphQL or REST API using Apollo Server or FastAPI - -ERP Integration: Odoo, SAP, or Oracle NetSuite (via REST APIs) - -IoT Connectivity: MQTT Protocol + AWS IoT Core - -E-commerce Sync: Shopify/WooCommerce/Amazon APIs - -πŸ”Ή Settings to Include: -βœ” Toggle Integrations On/Off (ERP, E-commerce, IoT) -βœ” API Key Management for Secure External Connections -βœ” Sync Frequency Settings (Live, 1-Hour, Daily) - -5️⃣ Security & Access Control (Authentication & Compliance) πŸ” -πŸ’‘ Features: -βœ… AI-Driven Role-Based Permissions -βœ… Biometric Authentication for High-Risk Actions -βœ… Smart Device Access Control - -πŸ› οΈ Tech Stack: - -Authentication: Firebase Auth, Auth0, or AWS Cognito (for secure login) - -Biometric Security: Android Biometric API, Apple Face ID API - -Audit Logs & Security Monitoring: ELK Stack (Elasticsearch, Logstash, Kibana) - -Blockchain-Based Ledger: Hyperledger Fabric for tamper-proof inventory records - -πŸ”Ή Settings to Include: -βœ” User Role Management (Admin, Manager, Staff, Auditor) -βœ” MFA Enable/Disable Option -βœ” Auto-Logout Timer (Adjustable) - -6️⃣ Mobile & Cloud Features (Cross-Platform Usability) πŸ“±β˜ -πŸ’‘ Features: -βœ… Offline Mode with Smart Sync -βœ… Wearable Integration (Smartwatches & AR Glasses) -βœ… AI-Powered Voice Assistant - -πŸ› οΈ Tech Stack: - -Mobile App: Flutter (Dart) or React Native for cross-platform development - -Cloud Backend: Firebase Firestore + AWS Lambda (Serverless) - -AR Integration: ARKit (iOS) + ARCore (Android) - -Wearable Connectivity: Google WearOS + Apple WatchKit - -πŸ”Ή Settings to Include: -βœ” Offline Sync Frequency (Immediate, Manual, Scheduled) -βœ” Voice Command Sensitivity -βœ” Toggle Wearable Features On/Off - -7️⃣ Advanced Features (Futuristic & Enterprise-Level) πŸš€ -πŸ’‘ Features: -βœ… Drone-Powered Stock Audits -βœ… AI-Driven Inventory Auto-Classification -βœ… Digital Twin for Warehouse Simulation - -πŸ› οΈ Tech Stack: - -Drone Integration: DJI SDK or OpenCV for image-based inventory scanning - -Digital Twin Simulation: Unity3D + NVIDIA Omniverse - -RFID & IoT Sensors: Azure IoT Hub or AWS IoT Greengrass - -πŸ”Ή Settings to Include: -βœ” Digital Twin Simulation Speed (Normal, Fast) -βœ” Drone Audit Frequency -βœ” RFID Scan Distance Adjustment - diff --git a/build-electron.sh b/build-electron.sh deleted file mode 100755 index a17328a9..00000000 --- a/build-electron.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Build Electron application - -# Check if production flag is provided -if [ "$1" == "--production" ]; then - echo "Building Electron application for production..." - node scripts/build-electron.js --production -else - echo "Building Electron application for development testing..." - node scripts/build-electron.js -fi - -echo "Build complete. Check the dist_electron directory for the output." \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 20dc8019..239e6e6b 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,47 +1,28 @@ import React from "react"; import { Switch, Route } from "wouter"; -import { queryClient } from "./lib/queryClient"; import { QueryClientProvider } from "@tanstack/react-query"; -import { Toaster } from "@/components/ui/toaster"; -import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; +import { Toaster } from "@/components/ui/toaster"; import { RefreshCw } from "lucide-react"; -import NotFound from "@/pages/not-found"; -import Dashboard from "@/pages/dashboard"; -import Inventory from "@/pages/inventory"; -import InventoryItemDetail from "@/pages/inventory-item"; -import OrdersPage from "@/pages/orders"; -import SuppliersPage from "@/pages/suppliers"; -import Reports from "@/pages/reports"; -import SettingsPage from "@/pages/settings"; -import UserRolesPage from "@/pages/user-roles"; -import Home from "@/pages/home"; -import ReorderPage from "@/pages/reorder"; -import AuthPage from "@/pages/auth-page"; -import BarcodeScannerPage from "@/pages/barcode-scanner-page"; -import RealTimeUpdatesPage from "@/pages/real-time-updates-page"; -import SyncTestPage from "@/pages/sync-test-page"; -import SyncDashboard from "@/pages/sync-dashboard"; -import DownloadPage from "@/pages/download"; -import BillingPage from "@/pages/billing"; -import ProfilePage from "@/pages/profile"; -import ImageRecognitionPage from "@/pages/image-recognition-page"; -import DocumentExtractorPage from "@/pages/document-extractor-page"; -import WarehousesPage from "@/pages/warehouses"; +import { queryClient } from "./lib/queryClient"; import { ThemeProvider } from "@/components/theme-provider"; -import { useState, useEffect } from "react"; import { TutorialProvider } from "@/contexts/tutorial-context"; -import { TutorialSteps } from "@/components/tutorial/tutorial-steps"; import { AuthProvider } from "@/hooks/use-auth"; import { ProtectedRoute } from "@/lib/protected-route"; -import { isElectronEnvironment } from "./lib/electron-bridge"; -import { ElectronProvider } from "./contexts/electron-provider"; -import { TitleBar, UpdateNotification } from "./components/electron"; import { DesktopLayout } from "./components/layout/desktop-layout"; +import NotFound from "@/pages/not-found"; +import Home from "@/pages/home"; +import Discover from "@/pages/discover"; +import JobsPage from "@/pages/jobs"; +import MessagesPage from "@/pages/messages"; +import ReviewsPage from "@/pages/reviews"; +import ProfilePage from "@/pages/profile"; +import SettingsPage from "@/pages/settings"; +import AuthPage from "@/pages/auth-page"; -// Error boundary component -class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean, error: Error | null}> { - constructor(props: {children: React.ReactNode}) { +class ErrorBoundary extends React.Component<{ children: React.ReactNode }, { hasError: boolean; error: Error | null }> { + constructor(props: { children: React.ReactNode }) { super(props); this.state = { hasError: false, error: null }; } @@ -64,11 +45,7 @@ class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasErr
{this.state.error?.message || "An unexpected error occurred"}
- @@ -86,25 +63,12 @@ function Router() { return ( - - - - - - - - - - - - - - - + + + + - - - + @@ -114,60 +78,31 @@ function Router() { function AppLayout({ children }: { children: React.ReactNode }) { return ( - {children} ); } -// Function to set up Electron-specific features -function setupElectronApp() { - if (isElectronEnvironment()) { - // Add a class to the HTML element to allow for Electron-specific styling - document.documentElement.classList.add('electron-app'); - - // Disable drag and drop file behavior that may interfere with the app - document.addEventListener('dragover', (e) => e.preventDefault()); - document.addEventListener('drop', (e) => e.preventDefault()); - - // Override the context menu for custom behavior if needed - // document.addEventListener('contextmenu', (e) => e.preventDefault()); - } -} - function App() { - // Set up Electron-specific HTML classes when in Electron environment - useEffect(() => { - setupElectronApp(); - }, []); - return ( - + - -
- - - - - {(params) => { - // Don't wrap non-auth routes with AppLayout - const pathname = params["*"] || ""; - if (pathname === "auth") return null; - return ( - - - - ); - }} - -
- - -
+
+ + + + + {(params) => { + const pathname = params["*"] || ""; + if (pathname === "auth") return null; + return ; + }} + +
+
diff --git a/client/src/components/analytics/demand-forecast.tsx b/client/src/components/analytics/demand-forecast.tsx deleted file mode 100644 index da6d95fa..00000000 --- a/client/src/components/analytics/demand-forecast.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import React, { useState } from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { format, parseISO, subMonths, addMonths } from 'date-fns'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Skeleton } from '@/components/ui/skeleton'; -import { CalendarIcon, ChevronLeft, ChevronRight, RefreshCw } from 'lucide-react'; -import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; -import { DateRangePicker } from '@/components/ui/date-range-picker'; -import { useDateRangeParams } from '@/hooks/use-date-range-params'; - -interface DemandForecastPoint { - date: string; - itemId: number; - itemName: string; - historical: number | null; - forecast: number | null; - accuracy: number | null; -} - -interface DemandForecastProps { - itemId: number; - itemName: string; -} - -export function DemandForecast({ itemId, itemName }: DemandForecastProps) { - const { dateRange, updateDateRange, range, updateRange } = useDateRangeParams(90); - const [view, setView] = useState<'3m' | '6m' | '12m'>('3m'); - - // Build query parameters - const queryParams = new URLSearchParams(); - - if (dateRange?.from) { - queryParams.append("startDate", format(dateRange.from, "yyyy-MM-dd")); - } - - if (dateRange?.to) { - queryParams.append("endDate", format(dateRange.to, "yyyy-MM-dd")); - } - - // Fetch forecast data - const { data, isLoading, error, refetch } = useQuery({ - queryKey: [`/api/analytics/demand-forecast/${itemId}`, queryParams.toString()], - queryFn: async () => { - const response = await fetch(`/api/analytics/demand-forecast/${itemId}?${queryParams.toString()}`); - if (!response.ok) { - throw new Error('Failed to fetch demand forecast'); - } - return response.json() as Promise; - }, - }); - - const handleViewChange = (newView: '3m' | '6m' | '12m') => { - setView(newView); - - const today = new Date(); - let newFrom: Date; - - switch (newView) { - case '3m': - newFrom = subMonths(today, 2); - break; - case '6m': - newFrom = subMonths(today, 5); - break; - case '12m': - newFrom = subMonths(today, 11); - break; - } - - updateDateRange({ - from: newFrom, - to: addMonths(today, 1) - }); - }; - - if (error) { - return ( - - - Demand Forecast - - -
-

Error loading forecast data.

-
-
-
- ); - } - - // Calculate average accuracy from forecast data - const averageAccuracy = data && data.length > 0 - ? data.reduce((acc, point) => { - return point.accuracy !== null ? acc + point.accuracy : acc; - }, 0) / data.filter(point => point.accuracy !== null).length - : null; - - return ( - - -
-
- Demand Forecast -

- Historical and predicted demand for {itemName} -

-
-
- - -
-
-
- -
- - - -
- - {isLoading ? ( -
- -
- ) : data && data.length > 0 ? ( - <> -
-
-

Forecast Accuracy

-

- {averageAccuracy !== null - ? `${Math.round(averageAccuracy * 100)}%` - : 'N/A'} -

-
-
-

Next Month Forecast

-

- {data.find(d => d.forecast !== null)?.forecast || 'N/A'} -

-
-
- -
- - ({ - ...d, - date: format(parseISO(d.date), 'MMM dd') - }))} - margin={{ top: 5, right: 30, left: 20, bottom: 5 }} - > - - - - [value, 'Units']} - labelFormatter={(label) => `Date: ${label}`} - /> - - - - - -
- -
-

- - Historical: Actual demand based on past stock movements -

-

- - Forecast: Predicted future demand based on historical patterns -

-
- - ) : ( -
- No forecast data available for this item. -
- )} -
-
- ); -} \ No newline at end of file diff --git a/client/src/components/analytics/inventory-value.tsx b/client/src/components/analytics/inventory-value.tsx deleted file mode 100644 index 6835a2f6..00000000 --- a/client/src/components/analytics/inventory-value.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import React, { useMemo } from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Skeleton } from '@/components/ui/skeleton'; -import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend } from 'recharts'; -import { formatCurrency } from '@/lib/utils'; - -interface InventoryValueItem { - id: number; - name: string; - quantity: number; - cost: number; - value: number; -} - -interface InventoryValueData { - totalValue: number; - totalItems: number; - items: InventoryValueItem[]; -} - -export function InventoryValue() { - // Fetch inventory value data - const { data, isLoading, error } = useQuery({ - queryKey: ['/api/analytics/inventory-value'], - queryFn: async () => { - const response = await fetch('/api/analytics/inventory-value'); - if (!response.ok) { - throw new Error('Failed to fetch inventory value data'); - } - return response.json() as Promise; - }, - }); - - // Prepare data for the chart - const chartData = useMemo(() => { - if (!data || !data.items || data.items.length === 0) return []; - - // Group smaller items into "Other" category - const topItems = data.items.slice(0, 6); // Take top 6 items - const otherItems = data.items.slice(6); // The rest become "Other" - - const result = topItems.map(item => ({ - name: item.name, - value: item.value, - })); - - // Add "Other" category if we have more than 6 items - if (otherItems.length > 0) { - const otherValue = otherItems.reduce((sum, item) => sum + item.value, 0); - result.push({ - name: 'Other', - value: otherValue, - }); - } - - return result; - }, [data]); - - // Color scale for the chart - const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#8884d8', '#82ca9d', '#bbb']; - - // Custom tooltip for the chart - const CustomTooltip = ({ active, payload }: any) => { - if (active && payload && payload.length) { - return ( -
-

{payload[0].name}

-

- Value: {formatCurrency(payload[0].value)} -

- {data && ( -

- ({((payload[0].value / data.totalValue) * 100).toFixed(1)}% of total) -

- )} -
- ); - } - return null; - }; - - if (error) { - return ( - - - Inventory Value - - -
-

Error loading inventory value data.

-
-
-
- ); - } - - return ( - - - Inventory Value Distribution - - - {isLoading ? ( -
-
- - -
- -
- ) : data ? ( - <> -
-
-

Total Value

-

{formatCurrency(data.totalValue)}

-
-
-

Total Items

-

{data.totalItems.toLocaleString()}

-
-
- - {chartData.length > 0 ? ( -
- - - - {chartData.map((entry, index) => ( - - ))} - - } /> - { - // Truncate long names and show tooltip on hover - return value.length > 10 ? `${value.substring(0, 10)}...` : value; - }} - wrapperStyle={{ - paddingTop: '10px', - width: '100%', - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'center', - gap: '10px' - }} - /> - - -
- ) : ( -
- No inventory value data available. -
- )} - - ) : ( -
- No inventory value data available. -
- )} -
-
- ); -} \ No newline at end of file diff --git a/client/src/components/analytics/top-items.tsx b/client/src/components/analytics/top-items.tsx deleted file mode 100644 index 41266344..00000000 --- a/client/src/components/analytics/top-items.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import React from 'react'; -import { useQuery } from '@tanstack/react-query'; -import { useLocation } from 'wouter'; -import { format } from 'date-fns'; -import { useDateRangeParams } from '@/hooks/use-date-range-params'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { DateRangePicker } from '@/components/ui/date-range-picker'; -import { Badge } from '@/components/ui/badge'; -import { Skeleton } from '@/components/ui/skeleton'; -import { Button } from '@/components/ui/button'; -import { ExternalLink } from 'lucide-react'; -import { formatCurrency } from '@/lib/utils'; -import { type InventoryItem } from '@shared/schema'; - -export function TopItems() { - const [, setLocation] = useLocation(); - const { dateRange, updateDateRange, range, updateRange } = useDateRangeParams(30); - - // Build query parameters - const queryParams = new URLSearchParams(); - queryParams.append("limit", "8"); // Show top 8 items - - if (dateRange?.from) { - queryParams.append("startDate", format(dateRange.from, "yyyy-MM-dd")); - } - - if (dateRange?.to) { - queryParams.append("endDate", format(dateRange.to, "yyyy-MM-dd")); - } - - // Fetch top items - const { data, isLoading, error } = useQuery({ - queryKey: ['/api/analytics/top-items', queryParams.toString()], - queryFn: async () => { - const response = await fetch(`/api/analytics/top-items?${queryParams.toString()}`); - if (!response.ok) { - throw new Error('Failed to fetch top items'); - } - return response.json() as Promise; - }, - }); - - if (error) { - return ( - - - Top Items by Demand - - -
-

Error loading top items data.

-
-
-
- ); - } - - return ( - - -
- Top Items by Demand -
- -
-
-
- - {isLoading ? ( -
- {Array.from({ length: 5 }).map((_, i) => ( -
- -
- - -
- -
- ))} -
- ) : data && data.length > 0 ? ( - <> -
- {data.map((item) => ( -
-
- {item.name.substring(0, 2).toUpperCase()} -
-
-

{item.name}

-

SKU: {item.sku}

-
- - {item.quantity} in stock - - -
- ))} -
-
- -
- - ) : ( -
- No data available for the selected period. -
- )} -
-
- ); -} \ No newline at end of file diff --git a/client/src/components/barcode/barcode-generator.tsx b/client/src/components/barcode/barcode-generator.tsx deleted file mode 100644 index 6524a989..00000000 --- a/client/src/components/barcode/barcode-generator.tsx +++ /dev/null @@ -1,318 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react'; -import { Card, CardContent, CardFooter } from '@/components/ui/card'; -import { Label } from '@/components/ui/label'; -import { Input } from '@/components/ui/input'; -import { Button } from '@/components/ui/button'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { useToast } from '@/hooks/use-toast'; -import { QrCode, Barcode, Printer, Download, Copy } from 'lucide-react'; - -// Import barcode generator libraries directly to ensure they're available -import JsBarcode from 'jsbarcode'; -import QRCode from 'qrcode'; - -type BarcodeFormat = 'CODE128' | 'CODE39' | 'EAN13' | 'EAN8' | 'UPC' | 'ITF14'; - -interface BarcodeGeneratorProps { - initialValue?: string; - onClose?: () => void; -} - -export function BarcodeGenerator({ initialValue = '', onClose }: BarcodeGeneratorProps) { - const [tab, setTab] = useState('barcode'); - const [value, setValue] = useState(initialValue); - const [format, setFormat] = useState('CODE128'); - const [size, setSize] = useState('medium'); - const barcodeRef = useRef(null); - const qrcodeRef = useRef(null); - const { toast } = useToast(); - - // No need to load libraries dynamically anymore since we're importing them directly - - // Generate barcode/QR code whenever value, format, or size changes - useEffect(() => { - if (!value) return; - - const generateCode = async () => { - try { - if (tab === 'barcode' && barcodeRef.current && JsBarcode) { - JsBarcode(barcodeRef.current, value, { - format, - width: getWidthFromSize(size), - height: getHeightFromSize(size), - displayValue: true, - fontOptions: 'bold', - fontSize: getSizeFontFromSize(size), - margin: 10, - }); - } else if (tab === 'qrcode' && qrcodeRef.current && QRCode) { - qrcodeRef.current.innerHTML = ''; - await QRCode.toCanvas( - qrcodeRef.current.appendChild(document.createElement('canvas')), - value, - { - width: getQRSizeFromSize(size), - margin: 1, - color: { - dark: '#000000', - light: '#ffffff', - }, - } - ); - } - } catch (err) { - console.error('Error generating code:', err); - toast({ - title: 'Generation Error', - description: err instanceof Error ? err.message : String(err), - variant: 'destructive', - }); - } - }; - - generateCode(); - }, [tab, value, format, size, toast]); - - // Helper functions for size conversions - const getWidthFromSize = (size: string): number => { - switch (size) { - case 'small': return 1; - case 'large': return 3; - default: return 2; - } - }; - - const getHeightFromSize = (size: string): number => { - switch (size) { - case 'small': return 30; - case 'large': return 80; - default: return 60; - } - }; - - const getSizeFontFromSize = (size: string): number => { - switch (size) { - case 'small': return 12; - case 'large': return 20; - default: return 16; - } - }; - - const getQRSizeFromSize = (size: string): number => { - switch (size) { - case 'small': return 128; - case 'large': return 256; - default: return 200; - } - }; - - // Print the generated code - const handlePrint = () => { - const printWindow = window.open('', '_blank'); - if (!printWindow) { - toast({ - title: 'Print Error', - description: 'Unable to open print window. Please check your browser settings.', - variant: 'destructive', - }); - return; - } - - const codeElement = tab === 'barcode' - ? barcodeRef.current - : qrcodeRef.current?.querySelector('canvas'); - - if (!codeElement) return; - - const dataUrl = codeElement.toDataURL('image/png'); - - printWindow.document.write(` - - - - Print ${tab === 'barcode' ? 'Barcode' : 'QR Code'} - - - - ${tab === 'barcode' ? 'Barcode' : 'QR Code'} -
${value}
- - - `); - - printWindow.document.close(); - }; - - // Download the generated code as a PNG image - const handleDownload = () => { - const codeElement = tab === 'barcode' - ? barcodeRef.current - : qrcodeRef.current?.querySelector('canvas'); - - if (!codeElement) return; - - const dataUrl = codeElement.toDataURL('image/png'); - const downloadLink = document.createElement('a'); - downloadLink.href = dataUrl; - downloadLink.download = `${tab}-${value}.png`; - document.body.appendChild(downloadLink); - downloadLink.click(); - document.body.removeChild(downloadLink); - - toast({ - title: 'Download Complete', - description: `${tab === 'barcode' ? 'Barcode' : 'QR Code'} has been downloaded.`, - }); - }; - - // Copy the generated code to clipboard - const handleCopy = () => { - navigator.clipboard.writeText(value).then( - () => { - toast({ - title: 'Copied to Clipboard', - description: `Value "${value}" has been copied to clipboard.`, - }); - }, - (err) => { - console.error('Error copying to clipboard:', err); - toast({ - title: 'Copy Error', - description: 'Failed to copy to clipboard.', - variant: 'destructive', - }); - } - ); - }; - - return ( - -
-

- Generate {tab === 'barcode' ? 'Barcode' : 'QR Code'} -

-
- - - - - - Barcode - - - - QR Code - - - - -
-
- - setValue(e.target.value)} - /> -
- - {tab === 'barcode' && ( -
- - -
- )} - -
- - -
- -
-
- {tab === 'barcode' ? ( -
- {value ? ( - - ) : ( -
- -

Enter a value to generate barcode

-
- )} -
- ) : ( -
- {!value && ( -
- -

Enter a value to generate QR code

-
- )} -
- )} -
-
-
-
- - - - - - -
-
- ); -} \ No newline at end of file diff --git a/client/src/components/barcode/barcode-scanner.tsx b/client/src/components/barcode/barcode-scanner.tsx deleted file mode 100644 index de5f8d5c..00000000 --- a/client/src/components/barcode/barcode-scanner.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Card, CardContent } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { useBarcodeScanner, ScannerType, ScanResult } from '@/hooks/use-barcode-scanner'; -import { Loader2, QrCode, Barcode, Camera, X } from 'lucide-react'; -import { isElectronEnvironment } from '@/lib/electron-bridge'; - -interface BarcodeScannerProps { - onScan?: (result: ScanResult) => void; - onClose?: () => void; - defaultTab?: ScannerType; -} - -export function BarcodeScanner({ - onScan, - onClose, - defaultTab = 'auto' -}: BarcodeScannerProps) { - const [tab, setTab] = useState(defaultTab); - const [scannerElementId] = useState(`scanner-${Math.random().toString(36).substring(2, 11)}`); - const { isScanning, lastScan, error, startScanning, stopScanning } = useBarcodeScanner(); - - // Handle scan result - useEffect(() => { - if (lastScan && onScan) { - onScan(lastScan); - } - }, [lastScan, onScan]); - - // Stop scanner on unmount - useEffect(() => { - return () => { - if (isScanning) { - stopScanning(); - } - }; - }, [isScanning, stopScanning]); - - // Handle tab change - const handleTabChange = (value: string) => { - if (isScanning) { - stopScanning(); - } - setTab(value as ScannerType); - }; - - // Start scanning with the selected type - const handleStartScanning = async () => { - await startScanning(scannerElementId, tab); - }; - - return ( - -
-

Scan Barcode/QR Code

- {onClose && ( - - )} -
- - - - Auto Detect - Barcode - QR Code - - - -
-

- Automatically detect and scan barcodes or QR codes. -

-
-
- - -
-

- Scan linear barcodes: UPC, EAN, Code 128, Code 39, etc. -

-
-
- - -
-

- Scan QR codes only. -

-
-
-
- - - {/* Scanner video container */} -
- {!isScanning && !isElectronEnvironment() && ( -
- -

- Click 'Start Scanning' to activate camera -

-
- )} - - {!isScanning && isElectronEnvironment() && ( -
- {tab === 'qrcode' ? ( - - ) : ( - - )} -

- Click 'Start Scanning' to open the scanner -

-
- )} - - {error && ( -
-
-

- {error.message} -

- -
-
- )} -
- - {/* Last scan result */} - {lastScan && ( -
-
-
- {lastScan.format.includes('QR') ? ( - - ) : ( - - )} -
-
-

{lastScan.format}

-

{lastScan.text}

-
-
-
- )} - - {/* Action buttons */} -
- - -
-
-
- ); -} \ No newline at end of file diff --git a/client/src/components/barcode/index.tsx b/client/src/components/barcode/index.tsx deleted file mode 100644 index 55e81400..00000000 --- a/client/src/components/barcode/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export { BarcodeScanner } from './barcode-scanner'; -export { BarcodeGenerator } from './barcode-generator'; \ No newline at end of file diff --git a/client/src/components/billing/invoice-dialog.tsx b/client/src/components/billing/invoice-dialog.tsx deleted file mode 100644 index 18fb100b..00000000 --- a/client/src/components/billing/invoice-dialog.tsx +++ /dev/null @@ -1,927 +0,0 @@ -import { useState, useEffect } from "react"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { useMutation, useQuery } from "@tanstack/react-query"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { useToast } from "@/hooks/use-toast"; -import { apiRequest, queryClient } from "@/lib/queryClient"; -import { format, addDays } from "date-fns"; -import { Calendar } from "@/components/ui/calendar"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { CalendarIcon, FileText, Plus, Trash } from "lucide-react"; -import { cn } from "@/lib/utils"; -import { - Table, - TableBody, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Badge } from "@/components/ui/badge"; - -// Invoice validation schema -const invoiceFormSchema = z.object({ - customerId: z.number({ - required_error: "Customer is required", - }), - dueDate: z.date({ - required_error: "Due date is required", - }), - status: z.enum(["DRAFT", "SENT", "PAID", "PARTIALLY_PAID", "OVERDUE", "CANCELLED", "VOID"], { - required_error: "Status is required", - }).default("DRAFT"), - notes: z.string().nullable().optional(), - invoiceNumber: z.string().optional(), - subtotal: z.number().optional(), - taxAmount: z.number().optional(), - discountAmount: z.number().optional(), - total: z.number().optional(), - amountPaid: z.number().optional(), - dueAmount: z.number().optional(), - items: z.array( - z.object({ - id: z.number().optional(), - itemId: z.number(), - description: z.string(), - quantity: z.number().min(0.01, "Quantity must be greater than 0"), - unitPrice: z.number().min(0, "Unit price must be 0 or greater"), - discount: z.number().min(0, "Discount must be 0 or greater").max(100, "Discount cannot exceed 100%").optional().nullable(), - taxRate: z.number().min(0, "Tax rate must be 0 or greater").max(100, "Tax rate cannot exceed 100%").optional().nullable(), - taxAmount: z.number().optional().nullable(), - totalPrice: z.number(), - }) - ).optional(), -}); - -type InvoiceFormValues = z.infer; - -// Invoice line item schema -const invoiceItemSchema = z.object({ - itemId: z.number(), - description: z.string().min(1, "Description is required"), - quantity: z.number().min(0.01, "Quantity must be greater than 0"), - unitPrice: z.number().min(0, "Unit price must be 0 or greater"), - discount: z.number().min(0, "Discount must be 0 or greater").max(100, "Discount cannot exceed 100%").default(0), - taxRate: z.number().min(0, "Tax rate must be 0 or greater").max(100, "Tax rate cannot exceed 100%").default(0), -}); - -type InvoiceItemValues = z.infer; - -export function InvoiceDialog({ open, onClose, invoice }) { - const { toast } = useToast(); - const [items, setItems] = useState([]); - const [newItemDialogOpen, setNewItemDialogOpen] = useState(false); - - // Calculate totals - const calculateSubtotal = (items) => { - return items.reduce((sum, item) => sum + (item.totalPrice || 0), 0); - }; - - const calculateTaxTotal = (items) => { - return items.reduce((sum, item) => sum + (item.taxAmount || 0), 0); - }; - - // Calculate item total price - const calculateItemTotalPrice = (quantity: number, unitPrice: number, discount: number = 0, taxRate: number = 0) => { - const lineTotal = quantity * unitPrice; - const discountAmount = (lineTotal * discount) / 100; - const subtotalAfterDiscount = lineTotal - discountAmount; - const taxAmount = (subtotalAfterDiscount * taxRate) / 100; - - return { - totalPrice: subtotalAfterDiscount + taxAmount, - taxAmount - }; - }; - - // Default values for the form - const defaultValues: Partial = { - customerId: 0, - dueDate: addDays(new Date(), 30), - status: "DRAFT", - notes: "", - items: [], - }; - - // Fetch inventory items query - const { data: inventoryItems = [] } = useQuery({ - queryKey: ["/api/inventory"], - queryFn: async () => { - const response = await apiRequest("GET", "/api/inventory"); - if (!response.ok) { - throw new Error("Failed to fetch inventory items"); - } - return response.json(); - }, - enabled: open, - }); - - // Fetch customers query - const { data: customers = [] } = useQuery({ - queryKey: ["/api/customers"], - queryFn: async () => { - const response = await apiRequest("GET", "/api/customers"); - if (!response.ok) { - throw new Error("Failed to fetch customers"); - } - return response.json(); - }, - enabled: open, - }); - - // Set up form - const form = useForm({ - resolver: zodResolver(invoiceFormSchema), - defaultValues: invoice ? { ...invoice } : defaultValues, - }); - - // Initialize form with invoice data if editing - useEffect(() => { - if (invoice) { - const formattedInvoice = { - ...invoice, - dueDate: new Date(invoice.dueDate) - }; - - form.reset(formattedInvoice); - setItems(invoice.items || []); - } else { - form.reset(defaultValues); - setItems([]); - } - }, [invoice, form]); - - // New item form - const newItemForm = useForm({ - resolver: zodResolver(invoiceItemSchema), - defaultValues: { - itemId: 0, - description: "", - quantity: 1, - unitPrice: 0, - discount: 0, - taxRate: 0 - }, - }); - - // Update item description and unit price when inventory item changes - const handleInventoryItemChange = (itemId: number) => { - const inventoryItem = inventoryItems.find(item => item.id === itemId); - if (inventoryItem) { - newItemForm.setValue("description", inventoryItem.name || ""); - newItemForm.setValue("unitPrice", inventoryItem.price || 0); - } - }; - - // Calculate item total price when values change - useEffect(() => { - const subscription = newItemForm.watch((value) => { - const quantity = parseFloat(value.quantity?.toString() || "0"); - const unitPrice = parseFloat(value.unitPrice?.toString() || "0"); - const discount = parseFloat(value.discount?.toString() || "0"); - const taxRate = parseFloat(value.taxRate?.toString() || "0"); - - if (quantity && unitPrice) { - const { totalPrice, taxAmount } = calculateItemTotalPrice(quantity, unitPrice, discount, taxRate); - newItemForm.setValue("totalPrice", totalPrice); - } - }); - - return () => subscription.unsubscribe(); - }, [newItemForm]); - - // Add new line item - const handleAddItem = (data: InvoiceItemValues) => { - const { totalPrice, taxAmount } = calculateItemTotalPrice( - data.quantity, - data.unitPrice, - data.discount, - data.taxRate - ); - - const newItem = { - ...data, - totalPrice, - taxAmount - }; - - const updatedItems = [...items, newItem]; - setItems(updatedItems); - - // Update form values - form.setValue("items", updatedItems); - form.setValue("subtotal", calculateSubtotal(updatedItems)); - form.setValue("taxAmount", calculateTaxTotal(updatedItems)); - form.setValue("total", calculateSubtotal(updatedItems)); - - // Close dialog and reset form - setNewItemDialogOpen(false); - newItemForm.reset({ - itemId: 0, - description: "", - quantity: 1, - unitPrice: 0, - discount: 0, - taxRate: 0 - }); - }; - - // Remove line item - const handleRemoveItem = (index: number) => { - const updatedItems = [...items]; - updatedItems.splice(index, 1); - setItems(updatedItems); - - // Update form values - form.setValue("items", updatedItems); - form.setValue("subtotal", calculateSubtotal(updatedItems)); - form.setValue("taxAmount", calculateTaxTotal(updatedItems)); - form.setValue("total", calculateSubtotal(updatedItems)); - }; - - // Create or update invoice mutation - const invoiceMutation = useMutation({ - mutationFn: async (data: InvoiceFormValues) => { - // Calculate totals - const subtotal = calculateSubtotal(data.items || []); - const taxAmount = calculateTaxTotal(data.items || []); - const total = subtotal; - const dueAmount = total - (data.amountPaid || 0); - - // Prepare data for submission - const invoiceData = { - ...data, - subtotal, - taxAmount, - total, - dueAmount - }; - - let res; - - if (invoice?.id) { - // Update existing invoice - res = await apiRequest("PATCH", `/api/invoices/${invoice.id}`, invoiceData); - } else { - // Create new invoice - res = await apiRequest("POST", "/api/invoices", invoiceData); - } - - if (!res.ok) throw new Error(invoice?.id ? "Failed to update invoice" : "Failed to create invoice"); - - return await res.json(); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ["/api/invoices"] }); - - if (invoice?.id) { - queryClient.invalidateQueries({ queryKey: ["/api/invoices", invoice.id] }); - } - - toast({ - title: invoice?.id ? "Invoice updated" : "Invoice created", - description: invoice?.id ? "Invoice has been updated successfully" : "New invoice has been created successfully", - }); - - onClose(true); - }, - onError: (error) => { - toast({ - title: "Error", - description: `Failed to ${invoice?.id ? "update" : "create"} invoice: ${error.message}`, - variant: "destructive", - }); - }, - }); - - // Form submission - const onSubmit = (data: InvoiceFormValues) => { - invoiceMutation.mutate(data); - }; - - // Format currency - const formatCurrency = (amount: number) => { - return `$${amount.toFixed(2)}`; - }; - - // Get status badge - const getStatusBadge = (status: string) => { - let badgeVariant; - switch (status) { - case "PAID": - badgeVariant = "success"; - break; - case "PARTIALLY_PAID": - badgeVariant = "warning"; - break; - case "OVERDUE": - badgeVariant = "destructive"; - break; - case "DRAFT": - badgeVariant = "outline"; - break; - case "SENT": - badgeVariant = "default"; - break; - case "CANCELLED": - case "VOID": - badgeVariant = "secondary"; - break; - default: - badgeVariant = "outline"; - } - - // Convert status to user-friendly format - const statusText = status - .split("_") - .map((word) => word.charAt(0) + word.slice(1).toLowerCase()) - .join(" "); - - return ( - - {statusText} - - ); - }; - - return ( - !open && onClose(false)}> - - - - - {invoice?.id ? "Edit Invoice" : "Create New Invoice"} - - - {invoice?.id ? `Editing invoice #${invoice.invoiceNumber || invoice.id}` : "Enter the details for a new invoice"} - - - -
- -
-
- {/* Customer Selection */} - ( - - Customer - - - - )} - /> - - {/* Due Date */} - ( - - Due Date - - - - - - - - - - - - - )} - /> - - {/* Status (only for edit) */} - {invoice?.id && ( - ( - - Status - - - - )} - /> - )} - - {/* Notes */} - ( - - Notes - -