Files
household-bot/apps/miniapp/src/App.tsx
whekin 94a5904f54 feat(miniapp): refine UI and add utility bill management
- Fix collapsible padding and button spacing
- Add subtotal to balance card
- Add utility bill management for admins
- Fix lints and type checks across the monorepo
- Implement rejectPendingHouseholdMember in repository and service
2026-03-13 05:52:34 +04:00

127 lines
4.1 KiB
TypeScript

import { Route, Router } from '@solidjs/router'
import { Match, Switch } from 'solid-js'
import { I18nProvider, useI18n } from './contexts/i18n-context'
import { SessionProvider, useSession, joinDeepLink } from './contexts/session-context'
import { DashboardProvider, useDashboard } from './contexts/dashboard-context'
import { AppShell } from './components/layout/shell'
import { LoadingState } from './components/session/loading-state'
import { BlockedState } from './components/session/blocked-state'
import { OnboardingState } from './components/session/onboarding-state'
import HomeRoute from './routes/home'
import BalancesRoute from './routes/balances'
import LedgerRoute from './routes/ledger'
import SettingsRoute from './routes/settings'
function AppContent() {
const { session, onboardingSession, blockedSession, joining, handleJoinHousehold } = useSession()
const { copy } = useI18n()
return (
<Switch>
<Match when={session().status === 'loading'}>
<main class="shell shell--centered">
<LoadingState
badge={copy().loadingBadge}
title={copy().loadingTitle}
body={copy().loadingBody}
/>
</main>
</Match>
<Match when={session().status === 'blocked'}>
<main class="shell shell--centered">
<BlockedState
badge={copy().loadingBadge}
title={
blockedSession()?.reason === 'telegram_only'
? copy().telegramOnlyTitle
: copy().unexpectedErrorTitle
}
body={
blockedSession()?.reason === 'telegram_only'
? copy().telegramOnlyBody
: copy().unexpectedErrorBody
}
reloadLabel={copy().reload}
onReload={() => window.location.reload()}
/>
</main>
</Match>
<Match when={session().status === 'onboarding'}>
<main class="shell shell--centered">
<OnboardingState
badge={copy().loadingBadge}
title={
onboardingSession()?.mode === 'pending'
? copy().pendingTitle
: onboardingSession()?.mode === 'open_from_group'
? copy().openFromGroupTitle
: copy().joinTitle
}
body={
onboardingSession()?.mode === 'pending'
? copy().pendingBody.replace(
'{household}',
onboardingSession()?.householdName ?? copy().householdFallback
)
: onboardingSession()?.mode === 'open_from_group'
? copy().openFromGroupBody
: copy().joinBody.replace(
'{household}',
onboardingSession()?.householdName ?? copy().householdFallback
)
}
canJoin={onboardingSession()?.mode === 'join_required'}
joining={joining()}
joinActionLabel={copy().joinAction}
joiningLabel={copy().joining}
botLinkLabel={copy().botLinkAction}
botLink={joinDeepLink()}
reloadLabel={copy().reload}
onJoin={handleJoinHousehold}
onReload={() => window.location.reload()}
/>
</main>
</Match>
<Match when={session().status === 'ready'}>
<DashboardProvider>
<AuthenticatedApp />
</DashboardProvider>
</Match>
</Switch>
)
}
function AuthenticatedApp() {
const { initData } = useSession()
const { loadDashboardData } = useDashboard()
// Load dashboard data once the component mounts
const data = initData()
void loadDashboardData(data ?? '', true)
return (
<Router root={AppShell}>
<Route path="/" component={HomeRoute} />
<Route path="/balances" component={BalancesRoute} />
<Route path="/ledger" component={LedgerRoute} />
<Route path="/settings" component={SettingsRoute} />
</Router>
)
}
function App() {
return (
<I18nProvider>
<SessionProvider>
<AppContent />
</SessionProvider>
</I18nProvider>
)
}
export default App