Skip to main content

Overview

The Shared module (shared.js) provides common utilities used across all components. It handles Progressive Web App (PWA) installation prompts, service worker registration for offline functionality, and utility functions for formatting and user notifications.

Responsibilities

  • Capture and handle PWA install prompts
  • Register service worker for offline capability
  • Format monetary values consistently
  • Display toast notifications to users

PWA Installation

beforeinstallprompt Event Handler

Captures the browser’s PWA install prompt and shows a custom install button.
let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;
  const installBtn = document.getElementById('installBtn');
  if (installBtn) {
    installBtn.classList.remove('hidden');
    installBtn.addEventListener('click', async () => {
      if (!deferredPrompt) return;
      deferredPrompt.prompt();
      await deferredPrompt.userChoice;
      deferredPrompt = null;
      installBtn.classList.add('hidden');
    });
  }
});
Behavior:
  1. Prevent Default: Prevents automatic browser install prompt
  2. Store Prompt: Saves the install prompt event in deferredPrompt
  3. Show Button: Reveals the #installBtn element by removing hidden class
  4. Click Handler: Attaches event listener to install button
  5. Trigger Prompt: When clicked, shows the native install dialog
  6. Wait for Choice: Awaits user’s decision (install or cancel)
  7. Cleanup: Clears deferredPrompt and hides button after user decides
Required DOM Element:
  • #installBtn - Button element for triggering PWA install
Browser Support: This event fires when:
  • App meets PWA criteria (manifest, service worker, HTTPS)
  • User hasn’t already installed the app
  • Browser supports PWA installation (Chrome, Edge, Samsung Internet, etc.)

Service Worker Registration

Service Worker Setup

Registers the service worker for offline functionality and caching.
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('./sw.js', { scope: './' })
      .catch(console.error);
  });
}
Behavior:
  1. Feature Detection: Checks if browser supports service workers
  2. Wait for Load: Defers registration until page fully loads
  3. Register Worker: Registers sw.js with root scope
  4. Error Handling: Logs registration errors to console
Service Worker File:
  • Path: ./sw.js (relative to HTML page)
  • Scope: ./ (controls all pages in the app)
Why Wait for Load? Delaying service worker registration until after page load prevents it from competing for bandwidth with critical resources during initial page load.

Utility Functions

money(n)

Formats a number as a currency string with 2 decimal places.
n
number | string
required
The number to format as currency
Returns: string - Formatted number with exactly 2 decimal places
export function money(n) {
  return (Math.round(Number(n) * 100) / 100).toFixed(2);
}
Examples:
money(10)          // "10.00"
money(99.9)        // "99.90"
money(123.456)     // "123.46" (rounds up)
money(123.454)     // "123.45" (rounds down)
money("50")        // "50.00" (accepts strings)
money(0.1 + 0.2)   // "0.30" (handles float precision)
Implementation Details:
  1. Converts input to number with Number(n)
  2. Multiplies by 100 to shift decimals
  3. Rounds to nearest integer with Math.round()
  4. Divides by 100 to restore decimal position
  5. Formats to exactly 2 decimal places with toFixed(2)
Why This Approach? This method avoids floating-point precision errors and ensures consistent currency formatting throughout the application.

showToast(message, type)

Displays a temporary notification toast to the user.
message
string
required
The message text to display in the toast
type
'success' | 'error'
default:"'success'"
The type of toast, affecting background color
export function showToast(message, type = 'success') {
  const toast = document.createElement('div');
  toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg text-white font-medium shadow-lg z-50 ${
    type === 'success' ? 'bg-green-600' : 'bg-red-600'
  }`;
  toast.textContent = message;
  document.body.appendChild(toast);
  setTimeout(() => toast.remove(), 3000);
}
Behavior:
  1. Create Element: Dynamically creates a <div> element
  2. Style Toast: Applies Tailwind CSS classes for positioning and styling
  3. Color Based on Type:
    • success → Green background (bg-green-600)
    • error → Red background (bg-red-600)
  4. Set Message: Inserts message as text content
  5. Show Toast: Appends to document body
  6. Auto-Remove: Removes toast after 3 seconds
Visual Properties:
  • Position: Fixed, bottom-right corner
  • Offset: 1rem (16px) from bottom and right edges
  • Padding: 1.5rem horizontal, 0.75rem vertical
  • Border radius: 0.5rem (8px)
  • Text: White, medium weight
  • Shadow: Large shadow for depth
  • Z-index: 50 (appears above most content)
Examples:
// Success notification (green)
showToast('Product added successfully', 'success');

// Error notification (red)
showToast('Cart is empty', 'error');

// Default is success
showToast('Operation completed');
Usage Across Components:
  • POS: Cart operations, checkout confirmation
  • Products: Add/delete product feedback
  • Dashboard: General notifications

Module Exports

The shared module exports two utility functions:
export { money, showToast };
Import Examples:
// Import both functions
import { money, showToast } from './shared.js';

// Import only what's needed
import { money } from './shared.js';

Browser Compatibility

Service Worker

Supported:
  • Chrome 40+
  • Firefox 44+
  • Safari 11.1+
  • Edge 17+
Not Supported:
  • Internet Explorer (any version)
  • Older mobile browsers

PWA Install Prompt

Supported:
  • Chrome 68+ (Android)
  • Chrome 73+ (Desktop)
  • Edge 79+
  • Samsung Internet 4+
Limited/Not Supported:
  • Safari (uses different install mechanism)
  • Firefox (no native prompt support)

Security Considerations

HTTPS Requirement

Service workers and PWA features require HTTPS (or localhost for development):
// Only works on:
// - https://example.com
// - http://localhost
// - http://127.0.0.1

Service Worker Scope

The service worker registered with scope: './' can only control:
  • Pages in the same directory
  • Pages in subdirectories
  • Cannot control parent directories

Initialization Order

The shared module sets up global functionality immediately on import:
  1. PWA Prompt: Listens for beforeinstallprompt event (fires when browser determines app is installable)
  2. Service Worker: Registers on window.load event (after page resources load)
  3. Exports: Makes money() and showToast() available to other modules

Best Practices

Using money()

// Always use money() for currency display
`₹${money(price)}`              // Good
`₹${price.toFixed(2)}`         // Avoid - doesn't round properly
`₹${price}`                    // Bad - inconsistent decimals

Using showToast()

// Provide clear, actionable messages
showToast('Product added to cart', 'success');           // Good
showToast('Done', 'success');                            // Too vague

// Use appropriate types
showToast('Cart is empty', 'error');                     // Good - error state
showToast('Sale completed successfully!', 'success');    // Good - success state
showToast('Processing...', 'success');                   // Avoid - use for completed actions

Build docs developers (and LLMs) love