import React, { useState, useEffect } from 'react'; import { render, Box, Text, useApp, useInput } from 'ink'; import TextInput from 'ink-text-input'; import chalk from 'chalk'; import * as googleAuth from '../src/db/googleAuth.js'; import '../src/config/env.js'; const e = React.createElement; const MODES = { MENU: 'menu', ADD: 'add', REMOVE: 'remove', LIST: 'list', DONE: 'done', ERROR: 'error', }; const Menu = ({ onSelect }) => { const [selected, setSelected] = useState(0); const options = [ { label: 'List allowed emails', value: 'list' }, { label: 'Add email', value: 'add' }, { label: 'Remove email', value: 'remove' }, { label: 'Quit', value: 'quit' }, ]; useInput((_input, key) => { if (key.upArrow) setSelected((s) => Math.max(0, s - 1)); if (key.downArrow) setSelected((s) => Math.min(options.length - 1, s + 1)); if (key.return) onSelect(options[selected].value); }); return e(Box, { flexDirection: 'column' }, options.map((opt, i) => e(Text, { key: opt.value }, i === selected ? chalk.cyan('> ') : ' ', i === selected ? chalk.cyan.bold(opt.label) : opt.label ) ) ); }; const App = () => { const { exit } = useApp(); const [mode, setMode] = useState(MODES.MENU); const [email, setEmail] = useState(''); const [message, setMessage] = useState(''); const [error, setError] = useState(''); const [emails, setEmails] = useState(null); useEffect(() => { if (mode !== MODES.LIST) { return; } setEmails(null); googleAuth.listAllowedEmails() .then(setEmails) .catch((err) => finish(false, err.message)); }, [mode]); const finish = (success, text) => { if (success) { setMessage(text); setMode(MODES.DONE); } else { setError(text); setMode(MODES.ERROR); } setTimeout(() => { exit(); process.exit(success ? 0 : 1); }, 100); }; const handleMenu = (action) => { if (action === 'quit') { exit(); process.exit(0); } setEmail(''); setMode(action); }; const handleAdd = async () => { try { const trimmed = email.trim(); if (!trimmed || !trimmed.includes('@')) { finish(false, 'Invalid email address'); return; } await googleAuth.addAllowedEmail(trimmed); finish(true, `Added ${trimmed.toLowerCase()} to google_auth`); } catch (err) { finish(false, err.message); } }; const handleRemove = async () => { try { const trimmed = email.trim(); if (!trimmed) { finish(false, 'Email is required'); return; } const removed = await googleAuth.removeAllowedEmail(trimmed); finish(true, removed ? `Removed ${trimmed.toLowerCase()}` : `Email not found: ${trimmed}`); } catch (err) { finish(false, err.message); } }; if (mode === MODES.DONE) { return e(Text, null, chalk.green(message)); } if (mode === MODES.ERROR) { return e(Text, null, chalk.red(`Error: ${error}`)); } if (mode === MODES.LIST) { if (!emails) { return e(Text, null, chalk.gray('Loading...')); } if (emails.length === 0) { finish(true, 'No allowed emails in google_auth'); return e(Text, null, chalk.yellow('No allowed emails...')); } return e(Box, { flexDirection: 'column' }, e(Text, null, chalk.cyan.bold('Allowed emails:')), ...emails.map((row) => e(Text, { key: row.id }, ` ${row.email}`)), e(Box, { marginTop: 1 }, e(Text, null, chalk.gray('Press any key to exit'))), e(ExitOnKey, { onExit: () => { exit(); process.exit(0); } }) ); } if (mode === MODES.ADD) { return e(Box, { flexDirection: 'column' }, e(Text, null, chalk.cyan.bold('Add allowed email')), e(Box, null, e(Text, null, 'Email: '), e(TextInput, { value: email, onChange: setEmail, onSubmit: handleAdd }) ) ); } if (mode === MODES.REMOVE) { return e(Box, { flexDirection: 'column' }, e(Text, null, chalk.cyan.bold('Remove allowed email')), e(Box, null, e(Text, null, 'Email: '), e(TextInput, { value: email, onChange: setEmail, onSubmit: handleRemove }) ) ); } return e(Box, { flexDirection: 'column' }, e(Box, { marginBottom: 1 }, e(Text, null, chalk.cyan.bold('=== Google Auth Email Manager ===')) ), e(Menu, { onSelect: handleMenu }) ); }; const ExitOnKey = ({ onExit }) => { useInput(onExit); return null; }; render(e(App));