import React, { useState } from 'react'; import { render, Box, Text, useApp, useInput } from 'ink'; import chalk from 'chalk'; import { getCategories } from '../src/services/misc/getCategories.js'; import { closePool } from '../src/db/mssqlClient.js'; import '../src/config/env.js'; const e = React.createElement; const VISIBLE_ROWS = 20; function flattenTree(nodes, depth = 0, out = []) { for (const node of nodes) { out.push({ ...node, depth }); flattenTree(node.children, depth + 1, out); } return out; } function formatRow(row) { const indent = ' '.repeat(row.depth); const count = chalk.gray(` (${row.count})`); return `${indent}${row.cName ?? '—'}${count} ${chalk.dim(String(row.kKategorie))}`; } const CategoryBrowser = ({ rows }) => { const { exit } = useApp(); const [selected, setSelected] = useState(0); const windowStart = Math.max(0, Math.min(selected - Math.floor(VISIBLE_ROWS / 2), rows.length - VISIBLE_ROWS)); const visible = rows.slice(windowStart, windowStart + VISIBLE_ROWS); const current = rows[selected]; const quit = () => { closePool() .catch(() => {}) .finally(() => { exit(); process.exit(0); }); }; useInput((input, key) => { if (input === 'q' || (key.ctrl && input === 'c')) { quit(); return; } if (key.upArrow) { setSelected((s) => Math.max(0, s - 1)); } if (key.downArrow) { setSelected((s) => Math.min(rows.length - 1, s + 1)); } }); return e(Box, { flexDirection: 'column' }, e(Text, null, chalk.cyan.bold(`=== Categories (${rows.length}) ===`)), e(Box, { marginTop: 1, flexDirection: 'column' }, visible.map((row, index) => { const absoluteIndex = windowStart + index; const prefix = absoluteIndex === selected ? chalk.cyan('> ') : ' '; const label = absoluteIndex === selected ? chalk.cyan.bold(formatRow(row)) : formatRow(row); return e(Text, { key: row.kKategorie }, prefix, label); }) ), rows.length > VISIBLE_ROWS ? e(Text, { dimColor: true }, `Showing ${windowStart + 1}-${windowStart + visible.length} of ${rows.length}`) : null, current ? e(Box, { marginTop: 1, flexDirection: 'column' }, e(Text, { dimColor: true }, `kKategorie: ${current.kKategorie} parent: ${current.kOberKategorie} sort: ${current.nSort ?? '—'} articles: ${current.count}` ) ) : null, e(Box, { marginTop: 1 }, e(Text, null, chalk.gray('↑↓ navigate, q exit'))) ); }; try { const { tree } = await getCategories(); const rows = flattenTree(tree); render(e(CategoryBrowser, { rows })); } catch (error) { console.error(chalk.red(`Error: ${error.message}`)); await closePool().catch(() => {}); process.exit(1); }