UNPKG

react-miami-stickers

Version:

Interactive CLI tool for gathering user information for Miami stickers

295 lines (294 loc) • 10.3 kB
#!/usr/bin/env node import inquirer from 'inquirer'; import chalk from 'chalk'; import figlet from 'figlet'; import ora from 'ora'; import axios from 'axios'; import fs from 'fs/promises'; const API_BASE_URL = 'https://aegis.exon.dev/api/rm'; const sleep = (ms = 1000) => new Promise((resolve) => setTimeout(resolve, ms)); // Check if running in admin mode const isAdminMode = process.argv.includes('--admin'); async function checkEmailExists(email) { try { const response = await axios.get(`${API_BASE_URL}?email=${encodeURIComponent(email)}`); return response.data.exists === true; } catch (error) { if (error.response?.status === 404) { return false; } // For any other errors, let the registration continue but log the error console.log(chalk.yellow('Warning: Could not verify email uniqueness. Proceeding anyway...')); return false; } } async function exportToCSV(data) { const headers = ['ID', 'Email', 'First Name', 'Last Name', 'Address Line 1', 'Address Line 2', 'City', 'State', 'ZIP Code', 'Created At', 'Updated At']; const rows = data.map(item => [ item.id, item.email, item.first_name, item.last_name, item.address_line1, item.address_line2 || '', item.city, item.state, item.zip_code, item.created_at, item.updated_at ]); const csvContent = [ headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) ].join('\n'); const fileName = `waitlist_export_${new Date().toISOString().split('T')[0]}.csv`; await fs.writeFile(fileName, csvContent); return fileName; } async function adminMode() { const { apiKey } = await inquirer.prompt([ { type: 'password', name: 'apiKey', message: chalk.yellow('Please enter the API key:'), validate: (input) => { if (!input) return 'API key is required'; return true; } } ]); const spinner = ora('Fetching waitlist data...').start(); try { const response = await axios.get(`${API_BASE_URL}?API_KEY=${apiKey}`); spinner.succeed('Data fetched successfully!'); const fileName = await exportToCSV(response.data.data); console.log(chalk.green(`\nData exported to ${fileName} successfully! šŸ“Š`)); process.exit(0); } catch (error) { spinner.fail('Failed to fetch data'); if (error.response?.status === 401) { console.error(chalk.red('Invalid API key')); } else { console.error(chalk.red('An error occurred while fetching data')); } process.exit(1); } } async function welcome() { console.clear(); const title = chalk.bold.cyan(figlet.textSync('reactMiami', { font: 'Standard', horizontalLayout: 'fitted', })); console.log(title); console.log(chalk.bold.magenta('🌓 Welcome to the Miami Stickers Registration! Let\'s get you set up! šŸ–ļø')); await sleep(); } async function getUserInfo() { const questions = [ { type: 'input', name: 'firstName', message: chalk.green('What is your first name?'), validate: (input) => { if (input.length < 2) { return 'Please enter a valid first name (at least 2 characters)'; } return true; }, }, { type: 'input', name: 'lastName', message: chalk.green('What is your last name?'), validate: (input) => { if (input.length < 2) { return 'Please enter a valid last name (at least 2 characters)'; } return true; }, }, { type: 'input', name: 'email', message: chalk.blue('What is your email address?'), validate: (input) => { const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; if (!emailRegex.test(input)) { return 'Please enter a valid email address (e.g., user@example.com)'; } return true; }, }, { type: 'input', name: 'phone', message: chalk.yellow('What is your phone number?'), validate: (input) => { const cleanPhone = input.replace(/[\s()-]/g, ''); const phoneRegex = /^(\+?1)?[0-9]{10}$/; if (!phoneRegex.test(cleanPhone)) { return 'Please enter a valid 10-digit phone number (e.g., 123-456-7890)'; } return true; }, }, { type: 'input', name: 'addressLine1', message: chalk.magenta('Address Line 1 (Street address)'), validate: (input) => { if (input.length < 5) { return 'Please enter a valid street address'; } return true; }, }, { type: 'input', name: 'addressLine2', message: chalk.magenta('Address Line 2 (Apt, Suite, etc.) - Optional'), }, { type: 'input', name: 'city', message: chalk.magenta('City'), validate: (input) => { if (input.length < 2) { return 'Please enter a valid city name'; } return true; }, }, { type: 'input', name: 'state', message: chalk.magenta('State (2-letter code)'), validate: (input) => { const stateRegex = /^[A-Z]{2}$/i; if (!stateRegex.test(input)) { return 'Please enter a valid 2-letter state code (e.g., FL)'; } return true; }, filter: (input) => input.toUpperCase(), }, { type: 'input', name: 'zipCode', message: chalk.magenta('ZIP Code'), validate: (input) => { const zipRegex = /^\d{5}(-\d{4})?$/; if (!zipRegex.test(input)) { return 'Please enter a valid ZIP code (e.g., 12345 or 12345-6789)'; } return true; }, } ]; return inquirer.prompt(questions); } async function confirmDetails(userInfo) { console.clear(); console.log(chalk.cyan.bold('\nšŸ“‹ Please review your information:\n')); console.log(chalk.green('Name: ') + `${userInfo.firstName} ${userInfo.lastName}`); console.log(chalk.blue('Email: ') + userInfo.email); console.log(chalk.yellow('Phone: ') + userInfo.phone); console.log(chalk.magenta('Address:')); console.log(chalk.magenta(' Street: ') + userInfo.addressLine1); if (userInfo.addressLine2) { console.log(chalk.magenta(' Unit/Suite: ') + userInfo.addressLine2); } console.log(chalk.magenta(' City: ') + userInfo.city); console.log(chalk.magenta(' State: ') + userInfo.state); console.log(chalk.magenta(' ZIP: ') + userInfo.zipCode); const { isConfirmed } = await inquirer.prompt([ { type: 'confirm', name: 'isConfirmed', message: chalk.cyan('\nIs this information correct?'), default: true, }, ]); if (isConfirmed) { const spinner = ora('Checking email availability...').start(); try { const exists = await checkEmailExists(userInfo.email); spinner.stop(); if (exists) { console.log(chalk.red('\nThis email is already registered. Please use a different email address.')); await sleep(2000); return false; } return true; } catch (error) { spinner.fail('Error checking email availability'); console.log(chalk.yellow('\nUnable to verify email. Please try again.')); await sleep(2000); return false; } } return false; } async function submitToAPI(userInfo) { const spinner = ora('Submitting your information...').start(); try { const formattedUserInfo = { email: userInfo.email, firstName: userInfo.firstName, lastName: userInfo.lastName, phone: userInfo.phone, address: { line1: userInfo.addressLine1, line2: userInfo.addressLine2 || '', city: userInfo.city, state: userInfo.state, zipCode: userInfo.zipCode } }; const response = await axios.post(API_BASE_URL, formattedUserInfo); await sleep(); spinner.succeed('Successfully submitted your information! šŸŽ‰'); console.log(chalk.green.bold('\nThank you for registering! You\'ll receive your Miami stickers soon! 🌓')); } catch (error) { spinner.fail('Something went wrong!'); if (error.response?.data?.error) { console.error(chalk.red(`Error: ${error.response.data.error}`)); } else { console.error(chalk.red('An unexpected error occurred. Please try again later.')); } process.exit(1); } } async function main() { try { if (isAdminMode) { await adminMode(); return; } await welcome(); let isConfirmed = false; let userInfo; while (!isConfirmed) { userInfo = await getUserInfo(); isConfirmed = await confirmDetails(userInfo); if (!isConfirmed) { console.log(chalk.yellow('\nLet\'s enter your information again...\n')); await sleep(1000); } } await submitToAPI(userInfo); } catch (error) { console.error(chalk.red('An error occurred:'), error); process.exit(1); } } main();