UNPKG

ticket-selector

Version:

A professional stadium seat selection widget with multi-language support

531 lines (415 loc) • 18.6 kB
# TicketSelector Widget [![Version](https://img.shields.io/badge/version-1.0.8-blue.svg)](https://github.com/IBP-LLC/ticket-selector/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![JavaScript](https://img.shields.io/badge/JavaScript-ES6+-brightgreen.svg)](https://github.com/IBP-LLC/ticket-selector) [![Bundle Size](https://img.shields.io/badge/bundle%20size-~56KB-brightgreen.svg)](https://github.com/IBP-LLC/ticket-selector) [![CSS Size](https://img.shields.io/badge/CSS%20size-~8KB-blue.svg)](https://github.com/IBP-LLC/ticket-selector) A professional stadium seat selection widget with multi-language support and comprehensive functionality. Perfect for event ticketing systems, stadium booking platforms, and venue management applications. ## ✨ Features - šŸŽÆ **Interactive seat selection** with real-time feedback and visual indicators - šŸŒ **Multi-language support** (English, Azerbaijani, and more) with automatic browser detection - šŸ”„ **Pan and zoom controls** with smooth animations and fullscreen mode - šŸ“± **Responsive design** that works flawlessly on all devices and screen sizes - šŸŽØ **Customizable styling** with BEM CSS methodology and SCSS variables - ⚔ **Professional build system** with minification, tree-shaking, and optimization - 🧩 **Modular architecture** with ES6 modules and bundled dependencies - šŸ”§ **Event-driven API** for seamless integration with any backend system - šŸŽŖ **Dynamic sector loading** with loading states and error handling - šŸ–±ļø **Advanced tooltips** with seat information and availability status ## šŸš€ Installation ### Via Local Files (Recommended) Download and include the built files from the dist directory: ```html <!-- Include CSS --> <link rel="stylesheet" href="../dist/ticket-selector.min.css"> <!-- Include JavaScript (Panzoom is bundled) --> <script src="../dist/ticket-selector.js"></script> ``` ### Alternative Installation 1. Clone the repository and build the project: ```bash git clone https://github.com/IBP-LLC/ticket-selector.git cd ticket-selector npm install npm run build ``` 2. Include the CSS and JS files in your project: ```html <link rel="stylesheet" href="path/to/dist/ticket-selector.min.css"> <script src="path/to/dist/ticket-selector.js"></script> ``` ## šŸ“– Quick Start ### 1. HTML Structure ```html <div id="ticket-selector" class="ticket-select"> <div class="ticket-select__container"> <div class="ticket-select__wrapper"> <div class="ticket-select__viewport"> <div class="ticket-select__content"> <div class="ticket-select__stadium"> <img src="stadium.jpg" alt="Stadium" class="ticket-select__stadium-image"> <div class="ticket-select__stadium-overlay"> <svg class="ticket-select__stadium-svg" viewBox="0 0 1000 600"> <!-- Define your stadium sectors --> <path class="ticket-select__sector" data-sector-id="1" data-sector-color="blue" d="M100,100 L300,100 L300,200 L100,200 Z"/> <path class="ticket-select__sector" data-sector-id="2" data-sector-color="red" d="M100,400 L300,400 L300,500 L100,500 Z"/> <path class="ticket-select__sector" data-sector-id="3" data-sector-color="green" d="M400,100 L600,100 L600,200 L400,200 Z"/> <!-- Add more sectors... --> </svg> </div> </div> </div> </div> <!-- Info bar with seat counter --> <div class="ticket-select__info"> <span class="ticket-select__selected-count">No seats selected</span> <a href="#" disabled class="ticket-select__info-btn">Buy <span data-ticket-selector-count style="display: none;"></span></a> </div> </div> </div> </div> ``` ### 2. Initialize the Widget ```javascript const ticketSelector = new TicketSelector('#ticket-selector', { lang: 'en', // 'en', 'az' or auto-detect showControls: true, showInfo: true, maxSeat: Infinity // Maximum number of seats that can be selected (default: Infinity) }); // Initialize sector summaries for dynamic loading ticketSelector.addEventListener('ready', (event) => { console.log(`TicketSelector v${event.detail.version} is ready!`); // Load sector summaries to update HTML attributes dynamically const sectorSummaries = { '1': { name: 'North Stand', price: '100 USD', availability: { available: 45, total: 50 }, disabled: false }, '2': { name: 'South Stand', price: '80 USD', availability: { available: 0, total: 30 }, disabled: true } }; ticketSelector.loadSectorSummaries(sectorSummaries); }); // Listen for sector clicks ticketSelector.addEventListener('sectorClick', async (event) => { const { sectorId, sectorName, element } = event.detail; // Show loading state ticketSelector.showLoading('Loading seats...'); try { // Load sector data from your API const response = await fetch(`/api/sectors/${sectorId}/seats`); const sectorData = await response.json(); // Load seats into the widget ticketSelector.setSectorData(sectorData, { sectorId, sectorName, sectorColor: element.dataset.sectorColor }); } catch (error) { console.error('Failed to load sector:', error); alert('Failed to load seat information. Please try again.'); } }); // Get selected seats when user is ready to proceed document.querySelector('.ticket-select__info-btn').addEventListener('click', () => { const selectedSeats = ticketSelector.getSelectedSeats(); console.log('User selected:', selectedSeats); // Process the selection... processTicketSelection(selectedSeats); }); ``` ## šŸ“š API Reference ### Constructor Options ```javascript new TicketSelector(container, options) ``` | Option | Type | Default | Description | |--------|------|---------|-------------| | `lang` | string | auto-detect | Language code ('en', 'az', 'tr') | | `showControls` | boolean | `true` | Show zoom/pan/fullscreen controls | | `showInfo` | boolean | `true` | Show selected seats counter | | `maxSeat` | number | `Infinity` | Maximum number of seats that can be selected | ### Methods #### `setSectorData(sectorData, sectorInfo?)` Load seats for a specific sector with detailed configuration. ```javascript const sectorData = { id: 'north-stand', name: 'North Stand', price: '100 USD', availability: { available: 45, total: 50 }, disabled: false, seats: [ { id: 1, name: 'Row 1', data: [ { id: 1001, available: true }, { id: 1002, available: false }, { id: 1003, available: true, skipLeft: 2 }, // Gap before seat { id: 1004, available: true, skipRight: 1 }, // Gap after seat { id: 1005, available: true, number: 15 } // Manual seat number ] }, { id: 2, name: 'Row 2', data: [ { id: 2001, available: true }, { id: 2002, available: true } ] } ] }; ticketSelector.setSectorData(sectorData, { sectorId: '1', sectorName: 'North Stand', sectorColor: 'blue' // Applies color theme to seats }); ``` **Seat Data Properties:** | Property | Type | Description | |----------|------|-------------| | `id` | number | Unique seat identifier (required) | | `available` | boolean | Whether seat is available for selection | | `skipLeft` | number | Number of empty spaces before this seat | | `skipRight` | number | Number of empty spaces after this seat | | `number` | number | Manual seat number (optional - if not provided, auto-numbered) | #### `getSelectedSeats()` Returns array of selected seats with comprehensive information. ```javascript const selectedSeats = ticketSelector.getSelectedSeats(); // Returns: // [ // { // sector: "North Stand", // row: 1, // seat: 3, // seatId: "seat-1003", // price: "50 USD", // category: "Standard" // } // ] ``` #### `setLanguage(lang)` Change language dynamically with instant UI updates. ```javascript ticketSelector.setLanguage('az'); // Switch to Azerbaijani ticketSelector.setLanguage('en'); // Switch to English ``` #### `showLoading(message?)` Display loading state with optional custom message. ```javascript ticketSelector.showLoading('Loading seat data...'); ``` #### `destroy()` Clean up the widget and remove all event listeners. ```javascript ticketSelector.destroy(); ``` ### Events #### `sectorClick` Triggered when a sector/zone is clicked in the stadium view. ```javascript ticketSelector.addEventListener('sectorClick', (event) => { const { sectorId, sectorName, element } = event.detail; console.log(`User clicked on ${sectorName} (ID: ${sectorId})`); }); ``` ## šŸ› ļø Development ### Prerequisites - Node.js 16+ - npm, yarn, or pnpm ### Setup ```bash git clone https://github.com/IBP-LLC/ticket-selector.git cd ticket-selector npm install # or yarn install / pnpm install ``` ### Development Server ```bash npm run dev ``` This will start: - šŸ“¦ **Rollup** in watch mode (JavaScript bundling) - šŸŽØ **Sass** in watch mode (CSS compilation) - šŸ”„ **PostCSS** processor (CSS optimization) - 🌐 **Live server** at `http://localhost:8080` with hot reload ### Build Commands ```bash npm run build # Production build npm run clean # Clean dist folder npm run lint # Run ESLint npm run lint:fix # Fix linting issues npm run format # Format code with Prettier npm run test # Run tests (when available) ``` ### Package Manager Support The project works with any modern package manager: ```bash # npm npm install && npm run dev # yarn yarn install && yarn dev # pnpm pnpm install && pnpm dev ``` ## šŸ“ Project Structure ``` src/ ā”œā”€ā”€ TicketSelector.js # Main widget class ā”œā”€ā”€ i18n/ # Internationalization │ ā”œā”€ā”€ index.js # I18n system core │ └── translations.js # All language translations └── styles/ # SCSS styles ā”œā”€ā”€ main.scss # Main stylesheet └── _variables.scss # SCSS variables & theming dist/ # Built files (generated) ā”œā”€ā”€ ticket-selector.js # UMD bundle ā”œā”€ā”€ ticket-selector.esm.js # ES module bundle ā”œā”€ā”€ ticket-selector.min.css # Minified CSS └── *.map # Source maps examples/ # Usage examples ā”œā”€ā”€ index.html # Basic implementation example └── stadium.jpg # Sample stadium image docs/ # Documentation (generated) tests/ # Test files (when available) ``` ## 🌐 Browser Support | Browser | Version | |---------|---------| | Chrome/Chromium | 60+ | | Firefox | 55+ | | Safari | 12+ | | Edge | 79+ | | iOS Safari | 12+ | | Android WebView | 60+ | ## šŸŽØ Customization ### CSS Variables ```css :root { --ticket-select-primary: #2175bf; --ticket-select-secondary: #f8ad02; --ticket-select-success: #0a8837; --ticket-select-danger: #bb2932; --ticket-select-bg: #f1f1f1; --ticket-select-white: #ffffff; } ``` ### Theming The widget supports custom color schemes through SCSS variables and CSS custom properties. See `src/styles/_variables.scss` for all available options. ## šŸ“ˆ Performance - **Bundle size**: ~56KB minified (includes Panzoom) - **CSS size**: ~8KB minified - **Zero external dependencies** - everything is bundled - **Tree-shakeable** ES modules - **Optimized rendering** with efficient DOM updates - **Smooth initialization** with loading states - **Mobile optimized** with touch event support ## šŸ”„ Changelog ### v1.0.8 (Latest) - šŸŽÆ **Maximum Seat Selection**: New `maxSeat` option to limit the number of seats that can be selected - āš ļø **Seat Limit Warnings**: Informative tooltip notifications when maximum seat limit is reached - šŸŒ **Multi-language Seat Limits**: Added translations for seat limit messages in English, Azerbaijani, and Turkish - šŸ”§ **Sector Drag Fix**: Fixed click event triggering after pan/zoom drag on sector paths - šŸ–±ļø **Improved Drag Detection**: Separate drag handling for sectors and seats to prevent false clicks - ✨ **Better UX for Limits**: Visual feedback with cursor changes and informative tooltips - šŸ“ **Drag Threshold Optimization**: Consistent 5px drag threshold for both sectors and seats ### v1.0.7 - šŸ”¢ **Manual Seat Numbering**: Added optional `number` property for custom seat numbering from backend - šŸ”§ **Flexible Numbering System**: Backend can now override automatic seat numbers - šŸ“ˆ **Enhanced Data Structure**: Seats can now have custom numbers from backend - šŸ“š **Documentation Updates**: Added seat data properties table with `number` parameter - šŸ’” **Example Implementation**: Updated examples to show manual seat numbering usage - šŸ”„ **Backward Compatibility**: Automatic numbering still works when `number` is not provided ### v1.0.6 - šŸ–¼ļø **Stadium Image Support**: Added stadium image support in the widget - ✨ **Enhanced Seat Styling**: Visual improvements and seat styling enhancements - šŸ› **Bug Fixes**: Various minor bugs and performance optimizations ### v1.0.5 - šŸŽÆ **Dynamic Seat Counter**: Purchase button now shows selected seat count (e.g., "Buy (3)") - šŸ”„ **Enhanced Button States**: Purchase button automatically enables/disables based on seat selection - 🚫 **Improved Disabled Sectors**: Better visual feedback for unavailable sectors - šŸŽØ **Button UX Improvements**: Disabled by default when no seats selected, dynamic count display - ✨ **Sector Interaction Refinements**: Better hover states and cursor feedback - šŸ› ļø **CSS & JavaScript Enhancements**: Improved styling consistency and responsive behavior ### v1.0.4 - šŸ”„ **Dynamic Sector Loading**: Backend/mock data integration for sector information - 🚫 **Disabled Sector Functionality**: Visual feedback and proper state management - šŸ“„ **Custom HTML Preservation**: Info section content maintained during updates - šŸ¤– **Automated Version Updates**: Husky hooks for version management - šŸ·ļø **Enhanced Tooltips**: Improved sector tooltip system with price and availability - šŸŒ **Better Internationalization**: Enhanced multi-language support ### v1.0.3 - šŸŒ **Multi-language Support**: Added English, Azerbaijani, and Turkish language support - šŸ”§ **Dynamic Internationalization**: Professional i18n system implementation - ⚔ **Professional Build System**: Automated workflows and build optimizations - šŸŽØ **Code Formatting**: Improved style consistency and formatting - šŸ› ļø **Error Handling**: Better user feedback and error management - šŸ“– **Enhanced Documentation**: Improved examples and documentation ### v1.0.2 - šŸ“± **Mobile Touch Support**: Added touchend events for perfect mobile interaction - ⚔ **Instant UI Feedback**: Viewport class applied immediately on sector click for responsive UI - šŸ”„ **Improved Loading States**: CSS-based loading control with instant visual feedback - 🚫 **Touch/Click Conflict Fix**: Prevented event conflicts with preventDefault for smooth mobile experience - šŸŽÆ **Enhanced Mobile UX**: Complete mobile user experience optimization ### v1.0.1 - šŸ“¦ **Bundled Panzoom**: No more external CDN dependencies - panzoom is now included in the bundle - šŸ”„ **Initial Loading**: Added professional loading screen during widget initialization - šŸŽÆ **Version Tracking**: Added version property to constructor for debugging and tracking - šŸš€ **Ready Event**: Widget now emits 'ready' event when fully initialized - šŸ› ļø **Improved Error Handling**: Better error messages and loading states - ⚔ **Self-contained**: Widget is now completely standalone with no external dependencies ### v1.0.0 - ✨ Initial release with full functionality - šŸŒ Multi-language support (EN, AZ) - šŸ–¼ļø Fullscreen mode with cross-browser compatibility - šŸ“± Responsive design for all screen sizes - ⚔ Professional build system with hot reload - šŸŽÆ Interactive seat selection with visual feedback - šŸ”§ Event-driven API for easy integration - šŸ“– Comprehensive documentation and examples ## šŸ¤ Contributing We welcome contributions! Please follow these steps: 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 3. Make your changes and add tests if applicable 4. Run `npm run lint` and `npm run build` to ensure code quality 5. Commit your changes (`git commit -m 'Add amazing feature'`) 6. Push to the branch (`git push origin feature/amazing-feature`) 7. Open a Pull Request ### Development Guidelines - Follow the existing code style and use Prettier for formatting - Add JSDoc comments for new public methods - Ensure backward compatibility when possible - Update documentation for any API changes ## šŸ“„ License MIT License - see [LICENSE](LICENSE) file for details. ## šŸ†˜ Support - šŸ“§ Email: support@ibp-llc.com - šŸ› Bug reports: [GitHub Issues](https://github.com/IBP-LLC/ticket-selector/issues) - šŸ’¬ Discussions: [GitHub Discussions](https://github.com/IBP-LLC/ticket-selector/discussions) - šŸ“– Documentation: [GitHub Wiki](https://github.com/IBP-LLC/ticket-selector/wiki) ## šŸ™ Acknowledgments - [Panzoom](https://github.com/timmywil/panzoom) for zoom and pan functionality - All contributors who help improve this project --- <div align="center"> <strong>Made with ā¤ļø by IBP LLC</strong> </div>