import { Box, Text, useApp } from 'ink' import Spinner from 'ink-spinner' import React, { useEffect, useState } from 'react' import { filterInactiveRepositories, sortByInactivity } from '../lib/filters.js' import { GitHubClient } from '../lib/github.js' import type { AppState, GitHubOptions } from '../types/index.js' import { Confirm } from './Confirm.js' import { RepoList } from './RepoList.js' interface AppProps { options: GitHubOptions } export const App: React.FC = ({ options }) => { const { exit } = useApp() const [state, setState] = useState({ loading: true, loadingMessage: 'Loading repositories...', repositories: [], selectedRepos: [], error: null, confirmMode: false, updating: false, updatedCount: 0, }) useEffect(() => { loadRepositories() }, []) const loadRepositories = async () => { try { const client = new GitHubClient(options.token) // Get user info await client.getAuthenticatedUser() // Get all public repositories setState((prev) => ({ ...prev, loading: true, loadingMessage: 'Fetching public repositories...', })) const repos = await client.getAllPublicRepositories(options.limit) // Update loading message setState((prev) => ({ ...prev, loadingMessage: `Analyzing ${repos.length} repositories...`, })) // Filter inactive repositories const filtered = await filterInactiveRepositories(repos, client) const sorted = sortByInactivity(filtered) setState((prev) => ({ ...prev, loading: false, repositories: sorted, selectedRepos: sorted, })) } catch (error) { setState((prev) => ({ ...prev, loading: false, error: error instanceof Error ? error.message : 'Unknown error occurred', })) } } const handleConfirm = async () => { setState((prev) => ({ ...prev, updating: true })) const client = new GitHubClient(options.token) let successCount = 0 for (const repo of state.selectedRepos) { const success = await client.makeRepositoryPrivate( repo.owner.login, repo.name, options.dryRun, ) if (success) { successCount++ setState((prev) => ({ ...prev, updatedCount: successCount })) } } setState((prev) => ({ ...prev, updating: false })) // Show completion message and exit const timer = setTimeout(() => { exit() }, 2000) return () => clearTimeout(timer) } const handleCancel = () => { exit() } if (state.loading) { return ( {state.loadingMessage} ) } if (state.error) { return ( Error: {state.error} Make sure your GitHub token is valid and has the necessary permissions. ) } if (state.updating) { return ( {' '} Updating repositories... ({state.updatedCount}/ {state.selectedRepos.length}) {options.dryRun && ( Running in dry-run mode - no changes will be made )} ) } if (state.updatedCount > 0) { return ( ✓ Successfully updated {state.updatedCount} repositories to private! {options.dryRun && ( This was a dry run - no actual changes were made )} ) } return ( GitHub Repository Cleanup Tool {state.repositories.length > 0 && !state.confirmMode && ( Press Enter to proceed with making these repositories private )} {state.repositories.length > 0 && ( )} ) }