refactor(miniapp): remove placeholder shell cards

This commit is contained in:
2026-03-09 17:12:21 +04:00
parent 16f9981fee
commit eb0143f132
3 changed files with 146 additions and 64 deletions

View File

@@ -107,6 +107,14 @@ function joinDeepLink(): string | null {
return `https://t.me/${context.botUsername}?start=join_${encodeURIComponent(context.joinToken)}`
}
function dashboardMemberCount(dashboard: MiniAppDashboard | null): string {
return dashboard ? String(dashboard.members.length) : '—'
}
function dashboardLedgerCount(dashboard: MiniAppDashboard | null): string {
return dashboard ? String(dashboard.ledger.length) : '—'
}
function App() {
const [locale, setLocale] = createSignal<Locale>('en')
const [session, setSession] = createSignal<SessionState>({
@@ -479,6 +487,12 @@ function App() {
case 'house':
return readySession()?.member.isAdmin ? (
<div class="balance-list">
<article class="balance-item">
<header>
<strong>{copy().householdSettingsTitle}</strong>
</header>
<p>{copy().householdSettingsBody}</p>
</article>
<article class="balance-item">
<header>
<strong>{copy().householdLanguage}</strong>
@@ -544,22 +558,75 @@ function App() {
)}
</div>
) : (
copy().houseEmpty
<div class="balance-list">
<article class="balance-item">
<header>
<strong>{copy().residentHouseTitle}</strong>
</header>
<p>{copy().residentHouseBody}</p>
</article>
</div>
)
default:
return (
<ShowDashboard
dashboard={dashboard()}
fallback={<p>{copy().summaryBody}</p>}
render={(data) => (
<>
<p>
{copy().totalDue}: {data.totalDueMajor} {data.currency}
</p>
<p>{copy().summaryBody}</p>
</>
)}
/>
<div class="home-grid">
<article class="stat-card">
<span>{copy().totalDue}</span>
<strong>
{dashboard() ? `${dashboard()!.totalDueMajor} ${dashboard()!.currency}` : '—'}
</strong>
</article>
<article class="stat-card">
<span>{copy().membersCount}</span>
<strong>{dashboardMemberCount(dashboard())}</strong>
</article>
<article class="stat-card">
<span>{copy().ledgerEntries}</span>
<strong>{dashboardLedgerCount(dashboard())}</strong>
</article>
{readySession()?.member.isAdmin ? (
<article class="stat-card">
<span>{copy().pendingRequests}</span>
<strong>{String(pendingMembers().length)}</strong>
</article>
) : null}
<article class="balance-item">
<header>
<strong>{copy().overviewTitle}</strong>
</header>
<p>{copy().overviewBody}</p>
</article>
<article class="balance-item">
<header>
<strong>{copy().latestActivityTitle}</strong>
</header>
<ShowDashboard
dashboard={dashboard()}
fallback={<p>{copy().latestActivityEmpty}</p>}
render={(data) =>
data.ledger.length === 0 ? (
<p>{copy().latestActivityEmpty}</p>
) : (
<div class="ledger-list">
{data.ledger.slice(0, 3).map((entry) => (
<article class="ledger-item">
<header>
<strong>{entry.title}</strong>
<span>
{entry.amountMajor} {data.currency}
</span>
</header>
<p>{entry.actorDisplayName ?? 'Household'}</p>
</article>
))}
</div>
)
}
/>
</article>
</div>
)
}
}
@@ -601,7 +668,7 @@ function App() {
<Switch>
<Match when={session().status === 'loading'}>
<section class="hero-card">
<span class="pill">{copy().navHint}</span>
<span class="pill">{copy().loadingBadge}</span>
<h2>{copy().loadingTitle}</h2>
<p>{copy().loadingBody}</p>
</section>
@@ -609,7 +676,7 @@ function App() {
<Match when={session().status === 'blocked'}>
<section class="hero-card">
<span class="pill">{copy().navHint}</span>
<span class="pill">{copy().loadingBadge}</span>
<h2>
{blockedSession()?.reason === 'telegram_only'
? copy().telegramOnlyTitle
@@ -628,7 +695,7 @@ function App() {
<Match when={session().status === 'onboarding'}>
<section class="hero-card">
<span class="pill">{copy().navHint}</span>
<span class="pill">{copy().loadingBadge}</span>
<h2>
{onboardingSession()?.mode === 'pending'
? copy().pendingTitle
@@ -681,7 +748,7 @@ function App() {
<section class="hero-card">
<div class="hero-card__meta">
<span class="pill">
{readySession()?.mode === 'demo' ? copy().demoBadge : copy().navHint}
{readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge}
</span>
<span class="pill pill--muted">
{readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag}
@@ -692,7 +759,7 @@ function App() {
{copy().welcome},{' '}
{readySession()?.telegramUser.firstName ?? readySession()?.member.displayName}
</h2>
<p>{copy().sectionBody}</p>
<p>{copy().overviewBody}</p>
</section>
<nav class="nav-grid">
@@ -716,25 +783,10 @@ function App() {
<section class="content-grid">
<article class="panel panel--wide">
<p class="eyebrow">{copy().summaryTitle}</p>
<p class="eyebrow">{copy().overviewTitle}</p>
<h3>{readySession()?.member.displayName}</h3>
<div>{renderPanel()}</div>
</article>
<article class="panel">
<p class="eyebrow">{copy().cardAccess}</p>
<p>{copy().cardAccessBody}</p>
</article>
<article class="panel">
<p class="eyebrow">{copy().cardLocale}</p>
<p>{copy().cardLocaleBody}</p>
</article>
<article class="panel">
<p class="eyebrow">{copy().cardNext}</p>
<p>{copy().cardNextBody}</p>
</article>
</section>
</Match>
</Switch>

View File

@@ -6,7 +6,9 @@ export const dictionary = {
appSubtitle: 'Shared home dashboard',
loadingTitle: 'Checking your household access',
loadingBody: 'Validating Telegram session and membership…',
loadingBadge: 'Secure session',
demoBadge: 'Demo mode',
liveBadge: 'Live household',
joinTitle: 'Welcome to your household',
joinBody:
'You are not a member of {household} yet. Send a join request and wait for admin approval.',
@@ -33,28 +35,28 @@ export const dictionary = {
balances: 'Balances',
ledger: 'Ledger',
house: 'House',
navHint: 'Shell v1',
welcome: 'Welcome back',
adminTag: 'Admin',
residentTag: 'Resident',
summaryTitle: 'Current shell',
summaryBody:
'Balances, ledger, and house wiki will land in the next tickets. This shell focuses on verified access, navigation, and mobile layout.',
overviewTitle: 'Current cycle',
overviewBody:
'Use the sections below to review balances, ledger entries, and household access.',
totalDue: 'Total due',
membersCount: 'Members',
ledgerEntries: 'Ledger entries',
pendingRequests: 'Pending requests',
shareRent: 'Rent',
shareUtilities: 'Utilities',
shareOffset: 'Shared buys',
ledgerTitle: 'Included ledger',
emptyDashboard: 'No billing cycle is ready yet.',
cardAccess: 'Access',
cardAccessBody: 'Telegram identity verified and matched to a household member.',
cardLocale: 'Locale',
cardLocaleBody: 'Switch RU/EN immediately without reloading the shell.',
cardNext: 'Next up',
cardNextBody: 'Balances, ledger, and house pages will plug into this navigation.',
sectionTitle: 'Ready for the next features',
sectionBody:
'This layout is intentionally narrow and mobile-first so it behaves well inside the Telegram webview.',
latestActivityTitle: 'Latest activity',
latestActivityEmpty: 'Recent utility and purchase entries will appear here.',
householdSettingsTitle: 'Household settings',
householdSettingsBody: 'Control household defaults and approve roommates who requested access.',
residentHouseTitle: 'Household access',
residentHouseBody:
'Your admins manage household settings and approvals here. You can still switch your own language above.',
pendingMembersTitle: 'Pending members',
pendingMembersBody:
'Approve roommates here after they request access from the group join flow.',
@@ -64,14 +66,16 @@ export const dictionary = {
pendingMemberHandle: '@{username}',
balancesEmpty: 'Balances will appear here once the dashboard API lands.',
ledgerEmpty: 'Ledger entries will appear here after the finance view is connected.',
houseEmpty: 'House rules, Wi-Fi info, and practical notes will live here.'
houseEmpty: 'Household details will appear here.'
},
ru: {
appTitle: 'Kojori House',
appSubtitle: 'Панель общего дома',
loadingTitle: 'Проверяем доступ к дому',
loadingBody: 'Проверяем Telegram-сессию и членство…',
loadingBadge: 'Защищённая сессия',
demoBadge: 'Демо режим',
liveBadge: 'Живой household',
joinTitle: 'Добро пожаловать домой',
joinBody:
'Ты пока не участник {household}. Отправь заявку на вступление и дождись подтверждения админа.',
@@ -98,28 +102,27 @@ export const dictionary = {
balances: 'Баланс',
ledger: 'Леджер',
house: 'Дом',
navHint: 'Shell v1',
welcome: 'С возвращением',
adminTag: 'Админ',
residentTag: 'Житель',
summaryTitle: 'Текущая оболочка',
summaryBody:
'Баланс, леджер и вики дома появятся в следующих тикетах. Сейчас приоритет — проверенный доступ, навигация и мобильный layout.',
overviewTitle: 'Текущий цикл',
overviewBody: 'Ниже можно посмотреть балансы, записи леджера и доступ к household.',
totalDue: 'Итого к оплате',
membersCount: 'Участники',
ledgerEntries: 'Записи леджера',
pendingRequests: 'Ожидают подтверждения',
shareRent: 'Аренда',
shareUtilities: 'Коммуналка',
shareOffset: 'Общие покупки',
ledgerTitle: 'Вошедшие операции',
emptyDashboard: 'Пока нет готового billing cycle.',
cardAccess: 'Доступ',
cardAccessBody: 'Telegram-личность подтверждена и сопоставлена с участником household.',
cardLocale: 'Локаль',
cardLocaleBody: 'RU/EN переключаются сразу, без перезагрузки.',
cardNext: 'Дальше',
cardNextBody: 'Баланс, леджер и страницы дома подключатся к этой навигации.',
sectionTitle: 'Основа готова для следующих функций',
sectionBody:
'Этот layout специально сделан узким и mobile-first, чтобы хорошо жить внутри Telegram webview.',
latestActivityTitle: 'Последняя активность',
latestActivityEmpty: 'Здесь появятся последние коммунальные платежи и покупки.',
householdSettingsTitle: 'Настройки household',
householdSettingsBody: 'Здесь можно менять язык household и подтверждать новых соседей.',
residentHouseTitle: 'Доступ к household',
residentHouseBody:
'Настройки household и подтверждение заявок управляются админами. Свой язык можно менять переключателем выше.',
pendingMembersTitle: 'Ожидающие участники',
pendingMembersBody:
'Подтверждай соседей здесь после того, как они отправят заявку через кнопку подключения.',
@@ -129,6 +132,6 @@ export const dictionary = {
pendingMemberHandle: '@{username}',
balancesEmpty: 'Баланс появится здесь, когда подключим dashboard API.',
ledgerEmpty: 'Записи леджера появятся здесь после подключения finance view.',
houseEmpty: 'Правила дома, Wi-Fi и полезные инструкции будут здесь.'
houseEmpty: 'Детали household появятся здесь.'
}
} satisfies Record<Locale, Record<string, string>>

View File

@@ -228,13 +228,15 @@ button {
}
.balance-list,
.ledger-list {
.ledger-list,
.home-grid {
display: grid;
gap: 12px;
}
.balance-item,
.ledger-item {
.ledger-item,
.stat-card {
border: 1px solid rgb(255 255 255 / 0.08);
border-radius: 18px;
padding: 14px;
@@ -260,6 +262,27 @@ button {
margin-top: 6px;
}
.home-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.stat-card {
display: grid;
gap: 8px;
}
.stat-card span {
color: #c6c2bb;
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.stat-card strong {
font-family: 'Space Grotesk', 'IBM Plex Sans', sans-serif;
font-size: clamp(1.2rem, 4vw, 1.7rem);
}
.panel--wide {
min-height: 170px;
}
@@ -275,6 +298,10 @@ button {
grid-template-columns: 1.3fr 1fr 1fr;
}
.home-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.panel--wide {
grid-column: 1 / -1;
}