Skip to content

ediril/collectiq

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 

Repository files navigation

A complete, self-contained waitlist component with email collection, rate limiting, spam protection, and database management.

This package contains two separate components:

  • WaitlistComponent - Complete email collection form with built-in rate limiting
  • RateLimitComponent - Standalone rate limiting that can be used independently

Features

  • âś… Email Validation - Client and server-side validation
  • âś… Rate Limiting - Prevents abuse with configurable time windows
  • âś… Spam Protection - Honeypot field to catch bots
  • âś… Database Management - SQLite databases for waitlist and rate limiting
  • âś… IP Detection - Handles proxies and load balancers
  • âś… Responsive Design - Mobile-friendly styling
  • âś… Animation Effects - Smooth shimmer and fade animations
  • âś… Self-Contained - All assets and data within component folder

Quick Start

1. Add the component to your project as a git submodule:

$ git submodule add https://github.com/ediril/collectiq.git
$ git submodule add https://github.com/ediril/collectiq.git <custom folder>

2. Choose Your Component

Waitlist Component (Complete email collection with rate limiting)

Basic Integration:

Option A: Manual Asset Loading (Traditional)

<?php require_once 'collectiq/components/waitlist/WaitlistComponent.php'; ?>
<!DOCTYPE html>
<html>
<head>
    <!-- Put this before the app CSS in case you need to override its values -->
    <link rel="stylesheet" href="/collectiq/components/waitlist/assets/waitlist.css">
</head>
<body>
    <?php 
    $waitlist = new WaitlistComponent();
    echo $waitlist->renderForm(); 
    ?>
    
    <script src="/collectiq/components/waitlist/assets/waitlist.js"></script>
</body>
</html>

Option B: Automatic Asset Loading with Cache Busting (Recommended)

<?php require_once 'collectiq/components/waitlist/WaitlistComponent.php'; ?>
<!DOCTYPE html>
<html>
<head>
    <?php 
    $waitlist = new WaitlistComponent();
    echo $waitlist->renderStyles(); // Auto-versioned CSS
    ?>
</head>
<body>
    <?php echo $waitlist->renderForm(); ?>
    
    <?php echo $waitlist->renderScripts(); // Auto-versioned JS ?>
</body>
</html>

Option C: All-in-One (CSS + Form + JS)

<?php 
require_once 'collectiq/component/WaitlistComponent.php';
$waitlist = new WaitlistComponent();
echo $waitlist->renderForm('waitlist-form', 'Enter your email...', 'Join', true);
?>

3. Ensure Endpoint is Accessible

Make sure /collectiq/components/waitlist/endpoint.php is accessible from your web root.

4. Asset Management

The component includes automatic cache busting to ensure browsers load updated CSS/JS files:

New Asset Methods

  • renderStyles() - Outputs CSS with content-based hash (e.g., waitlist.css?v=abc12345)
  • renderScripts() - Outputs JS with content-based hash (e.g., waitlist.js?v=def67890)
  • Hash only changes when file content actually changes
  • Works with Apache, Nginx, and development servers

Why Use Auto-Versioned Assets?

  • Better caching - Browsers cache until content actually changes
  • No stale files - Users always get the latest version after updates
  • Automatic detection - Works with different server configurations
  • No manual versioning - Hash updates automatically

5. How to Update

$ git submodule update --remote

Advanced Usage

Custom Form Options

$waitlist = new WaitlistComponent();

// Custom form with different text
echo $waitlist->renderForm(
    'Enter your email address...',  // Placeholder text
    'Subscribe Now'                 // Button text
);

Custom Database Paths

$waitlist = new WaitlistComponent(
    '/custom/path/waitlist.db',     # Waitlist database
    '/custom/path/rate_limit.db',   # Rate limit database  
    120                             # Rate limit window (seconds)
);

Multiple Forms on Same Page

<!-- Form 1: Newsletter -->
<div id="newsletter-section">
    <?php echo $waitlist->renderForm('Newsletter signup...', 'Subscribe'); ?>
</div>

<!-- Form 2: Beta Access -->
<div id="beta-section">
    <?php echo $waitlist->renderForm('Get beta access...', 'Join Beta'); ?>
</div>

<!-- All forms are automatically initialized -->

Standalone Endpoint

Use the component as a pure API:

fetch('/collectiq/components/waitlist/endpoint.php', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email: 'user@example.com' })
})
.then(response => response.json())
.then(data => console.log(data));

RateLimit Component (Standalone)

Use the rate limiting functionality independently:

<?php
require_once 'collectiq/components/ratelimit/RateLimitComponent.php';

// Initialize with custom settings
$rateLimit = new RateLimitComponent('/path/to/rate_limit.db', 60); // 60 second window

// Check if request is allowed
if ($rateLimit->checkRateLimit()) {
    // Process the request
    echo "Request allowed";
} else {
    // Rate limit exceeded
    http_response_code(429);
    echo "Too many requests";
}

RateLimit Component Methods

$rateLimit = new RateLimitComponent($dbPath, $window);

// Set rate limit window
$rateLimit->setWindow(120); // 2 minutes

// Get current window setting
$window = $rateLimit->getWindow();

// Check rate limit for current IP
$allowed = $rateLimit->checkRateLimit();

// Check rate limit for specific IP
$allowed = $rateLimit->checkRateLimit('192.168.1.100');

// Get remaining time until next request allowed
$seconds = $rateLimit->getRemainingTime();

// Create database table (automatic, but can be called manually)
$rateLimit->createDatabaseTable();

RateLimit Component Features

  • IP-based limiting - Tracks requests per IP address
  • Configurable windows - Set custom time windows (seconds)
  • Automatic cleanup - Removes expired entries
  • Proxy support - Handles X-Forwarded-For headers
  • Manual IP testing - Test rate limits for specific IPs
  • Remaining time - Check how long until next request allowed

Configuration Options

Rate Limiting

Default: 1 request per 60 seconds per IP address

The rate limit prevents spam and abuse while allowing legitimate users to retry if needed.

Adjusting Rate Limits

// Constructor: new WaitlistComponent($dbPath, $rateLimitDbPath, $windowSeconds)

// 30 seconds (more permissive)
$waitlist = new WaitlistComponent(null, null, 30);

// 2 minutes (default recommended)  
$waitlist = new WaitlistComponent(null, null, 120);

// 5 minutes (stricter)
$waitlist = new WaitlistComponent(null, null, 300);

// 10 minutes (very strict)
$waitlist = new WaitlistComponent(null, null, 600);

In Your Project

Update your component initialization:

// In index.php or wherever you create the component
// Change from:
$waitlist = new WaitlistComponent();

// To (for 2-minute rate limit):
$waitlist = new WaitlistComponent(null, null, 120);

Rate Limit Behavior

  • Tracks requests per IP address
  • Returns {"success": false, "message": "too many requests"} when exceeded
  • Automatically cleans up old entries
  • Works with proxy headers (X-Forwarded-For)

Database Location

By default, databases are stored in components/*/data/. To use custom paths:

$waitlist = new WaitlistComponent(
    __DIR__ . '/custom/waitlist.db',
    __DIR__ . '/custom/rate_limit.db'
);

API Responses

Success Response

{
    "success": true
}

Error Responses

// Rate limited
{
    "success": false,
    "message": "too many requests"
}

// Invalid email
{
    "success": false,
    "message": "Invalid email address"
}

// Bot detected (honeypot)
{
    "success": true,
    "message": "not human"
}

Database Schema

Waitlist Table

CREATE TABLE waitlist (
    email TEXT PRIMARY KEY,
    ip TEXT,
    ts INTEGER DEFAULT (unixepoch()),
    dt TEXT GENERATED ALWAYS AS (datetime(ts, 'unixepoch')) STORED
);

Rate Limit Table

CREATE TABLE rate_limit (
    ip TEXT PRIMARY KEY,
    window_start INTEGER
);

Customization

Styling

The component uses CSS classes prefixed with collectiq- to avoid conflicts with your existing styles. You can override these styles in your own CSS:

/* Override the main form container */
.collectiq-waitlist-form {
    max-width: 400px;
    gap: 0.5rem;
    /* Your custom styles */
}

/* Override the input container */
.collectiq-input-container {
    border: 2px solid #your-color;
    border-radius: 10px;
    /* Custom input styling */
}

/* Override the submit button */
.collectiq-submit-btn {
    background: linear-gradient(45deg, #your-color1, #your-color2);
    border-radius: 25px;
    font-size: 1.2rem;
    /* Custom button styling */
}

/* Override button hover state */
.collectiq-submit-btn:hover {
    background: linear-gradient(45deg, #your-hover-color1, #your-hover-color2);
    transform: translateY(-2px);
}

/* Override button active state */
.collectiq-submit-btn:active {
    background: linear-gradient(45deg, #your-active-color1, #your-active-color2);
    transform: translateY(0px);
}

/* Override button text */
.collectiq-submit-btn span {
    font-weight: bold;
    text-transform: uppercase;
}

/* Override input field */
.collectiq-input {
    font-size: 1.1rem;
    color: #your-text-color;
    /* Custom input field styling */
}

/* Override placeholder text */
.collectiq-input::placeholder {
    color: rgba(0, 0, 0, 0.6); /* Dark placeholder for light backgrounds */
}

/* Override success message - may need !important for some properties */
.collectiq-input-container.collectiq-thank-you {
    background-color: #your-success-color !important;
    color: #your-success-text-color !important;
    /* Custom success message styling */
}

Key CSS Classes Available for Override:

  • .collectiq-waitlist-form - Main form container
  • .collectiq-input-container - Input wrapper with border effects
  • .collectiq-input - Email input field
  • .collectiq-submit-btn - Submit button
  • .collectiq-shimmer-container - Button shimmer effect container
  • .collectiq-shimmer - Animated shimmer effect
  • .collectiq-highlight - Button highlight effect
  • .collectiq-backdrop - Button backdrop
  • .collectiq-thank-you - Success message styling

Example: Custom Button Colors

.collectiq-waitlist-form button {
    background: linear-gradient(135deg, #ff6b6b, #ee5a24);
}

.collectiq-waitlist-form button:hover .collectiq-highlight {
    box-shadow: inset 0 -6px 10px rgba(255, 255, 255, 0.4);
}

Example: Different Input Styling

.collectiq-input-container {
    border: none;
    background: rgba(255, 255, 255, 0.1);
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.collectiq-waitlist-form input {
    padding: 1.2rem;
    font-size: 1.1rem;
}

Example: Disable Button Effects

/* Disable shimmer effect */
.collectiq-submit-btn .collectiq-shimmer-container {
    display: none;
}

/* Disable backdrop effect */
.collectiq-submit-btn .collectiq-backdrop {
    display: none;
}

/* Disable highlight effect on hover */
.collectiq-submit-btn:hover .collectiq-highlight {
    box-shadow: none;
}

/* Disable highlight effect on active */
.collectiq-submit-btn:active .collectiq-highlight {
    box-shadow: none;
}

/* Disable all button effects at once */
.collectiq-submit-btn .collectiq-shimmer-container,
.collectiq-submit-btn .collectiq-backdrop,
.collectiq-submit-btn .collectiq-highlight {
    display: none;
}

Example: Placeholder Text Styling

The default placeholder color is designed for dark backgrounds. For light backgrounds, you'll need to override it:

/* Default (for dark backgrounds) */
.collectiq-waitlist-form input::placeholder {
    color: rgba(255, 255, 255, 0.4); /* Light white */
}

/* For light backgrounds */
.collectiq-waitlist-form input::placeholder {
    color: rgba(0, 0, 0, 0.6); /* Dark gray */
}

/* For specific forms */
#my-form .collectiq-waitlist-form input::placeholder {
    color: #666;
}

JavaScript Behavior

Extend the WaitlistHandler class:

class CustomWaitlistHandler extends WaitlistHandler {
    showSuccessMessage(form) {
        // Custom success message
        alert('Welcome to our waitlist!');
    }
}

// Use custom handler
new CustomWaitlistHandler('my-form');

Security Features

  1. Rate Limiting - Prevents spam and abuse
  2. Honeypot Protection - Hidden field catches bots
  3. Email Validation - Server-side validation
  4. IP Tracking - Logs IP addresses for monitoring
  5. SQL Injection Protection - Prepared statements
  6. Proxy Support - Handles X-Forwarded-For headers

Deployment Notes

  1. Ensure PHP SQLite extension is installed
  2. Make components/*/data/ writable by web server
  3. Database files are created automatically on first use
  4. Consider backing up the data/ folder regularly

Troubleshooting

Form Not Submitting

  • Check that waitlist.js is loaded
  • Verify endpoint URL is correct
  • Check browser console for JavaScript errors

Database Errors

  • Ensure data/ directory is writable
  • Check PHP SQLite extension is installed
  • Verify file permissions

Rate Limiting Issues

  • Check server system time is correct
  • Verify IP detection is working properly
  • Consider adjusting rate limit window

About

Email address collection component

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published