mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
refactor(miniapp): simplify dashboard layout and controls
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Match, Switch, createMemo, createSignal, onMount } from 'solid-js'
|
||||
import { Match, Show, Switch, createMemo, createSignal, onMount } from 'solid-js'
|
||||
|
||||
import { dictionary, type Locale } from './i18n'
|
||||
import {
|
||||
@@ -38,10 +38,8 @@ import {
|
||||
type MiniAppDashboard,
|
||||
type MiniAppPendingMember
|
||||
} from './miniapp-api'
|
||||
import { Button, Field, Modal } from './components/ui'
|
||||
import { HeroBanner } from './components/layout/hero-banner'
|
||||
import { Button, Field, MiniChip, Modal } from './components/ui'
|
||||
import { NavigationTabs } from './components/layout/navigation-tabs'
|
||||
import { ProfileCard } from './components/layout/profile-card'
|
||||
import { TopBar } from './components/layout/top-bar'
|
||||
import { BlockedState } from './components/session/blocked-state'
|
||||
import { LoadingState } from './components/session/loading-state'
|
||||
@@ -2337,10 +2335,7 @@ function App() {
|
||||
currentMemberLine={currentMemberLine()}
|
||||
utilityTotalMajor={utilityTotalMajor()}
|
||||
purchaseTotalMajor={purchaseTotalMajor()}
|
||||
memberBalanceVisuals={memberBalanceVisuals()}
|
||||
purchaseChart={purchaseInvestmentChart()}
|
||||
memberBaseDueMajor={memberBaseDueMajor}
|
||||
memberRemainingClass={memberRemainingClass}
|
||||
ledgerTitle={ledgerTitle}
|
||||
ledgerPrimaryAmount={ledgerPrimaryAmount}
|
||||
ledgerSecondaryAmount={ledgerSecondaryAmount}
|
||||
@@ -2426,25 +2421,30 @@ function App() {
|
||||
</Match>
|
||||
|
||||
<Match when={session().status === 'ready'}>
|
||||
<HeroBanner
|
||||
badges={[
|
||||
readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge,
|
||||
readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag,
|
||||
readySession()?.member.status
|
||||
<section class="app-context-row">
|
||||
<div class="app-context-meta">
|
||||
<MiniChip>
|
||||
{readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge}
|
||||
</MiniChip>
|
||||
<MiniChip muted>
|
||||
{readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag}
|
||||
</MiniChip>
|
||||
<MiniChip muted>
|
||||
{readySession()?.member.status
|
||||
? memberStatusLabel(readySession()!.member.status)
|
||||
: copy().memberStatusActive
|
||||
]}
|
||||
title={`${copy().welcome}, ${readySession()?.telegramUser.firstName ?? readySession()?.member.displayName}`}
|
||||
body={copy().overviewBody}
|
||||
action={
|
||||
readySession()?.mode === 'live'
|
||||
? {
|
||||
label: copy().manageProfileAction,
|
||||
onClick: () => setProfileEditorOpen(true)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
: copy().memberStatusActive}
|
||||
</MiniChip>
|
||||
</div>
|
||||
<Show when={readySession()?.mode === 'live'}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="app-context-row__action"
|
||||
onClick={() => setProfileEditorOpen(true)}
|
||||
>
|
||||
{copy().manageProfileAction}
|
||||
</Button>
|
||||
</Show>
|
||||
</section>
|
||||
|
||||
<NavigationTabs
|
||||
items={
|
||||
@@ -2459,21 +2459,7 @@ function App() {
|
||||
onChange={setActiveNav}
|
||||
/>
|
||||
|
||||
<section class="content-grid">
|
||||
<ProfileCard
|
||||
displayName={readySession()?.member.displayName ?? ''}
|
||||
roleLabel={readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag}
|
||||
statusSummary={copy().memberStatusSummary.replace(
|
||||
'{status}',
|
||||
readySession()?.member.status
|
||||
? memberStatusLabel(readySession()!.member.status)
|
||||
: copy().memberStatusActive
|
||||
)}
|
||||
modeBadge={readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge}
|
||||
localeBadge={locale().toUpperCase()}
|
||||
/>
|
||||
<div class="content-stack">{renderPanel()}</div>
|
||||
</section>
|
||||
<section class="content-stack">{renderPanel()}</section>
|
||||
<Modal
|
||||
open={profileEditorOpen()}
|
||||
title={copy().displayNameLabel}
|
||||
|
||||
@@ -13,7 +13,7 @@ type Props = {
|
||||
export function TopBar(props: Props) {
|
||||
return (
|
||||
<section class="topbar">
|
||||
<div>
|
||||
<div class="topbar__copy">
|
||||
<p class="eyebrow">{props.subtitle}</p>
|
||||
<h1>{props.title}</h1>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as Dialog from '@kobalte/core/dialog'
|
||||
import { Show, type JSX, type ParentProps } from 'solid-js'
|
||||
|
||||
import { XIcon } from './icons'
|
||||
|
||||
export function Modal(
|
||||
props: ParentProps<{
|
||||
open: boolean
|
||||
@@ -24,8 +26,8 @@ export function Modal(
|
||||
{(description) => <Dialog.Description>{description()}</Dialog.Description>}
|
||||
</Show>
|
||||
</div>
|
||||
<Dialog.CloseButton class="ui-button ui-button--icon">
|
||||
<span aria-hidden="true">x</span>
|
||||
<Dialog.CloseButton class="ui-button ui-button--icon modal-close-button">
|
||||
<XIcon />
|
||||
<span class="sr-only">{props.closeLabel}</span>
|
||||
</Dialog.CloseButton>
|
||||
</header>
|
||||
|
||||
@@ -65,3 +65,12 @@ export function GlobeIcon(props: IconProps) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function XIcon(props: IconProps) {
|
||||
return (
|
||||
<svg {...iconProps(props)}>
|
||||
<path d="m6 6 12 12" />
|
||||
<path d="M18 6 6 18" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,12 @@ button {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.topbar__copy {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.topbar h1,
|
||||
@@ -94,7 +99,8 @@ button {
|
||||
}
|
||||
|
||||
.topbar h1 {
|
||||
font-size: clamp(2rem, 5vw, 3rem);
|
||||
font-size: clamp(1.55rem, 4.4vw, 2.35rem);
|
||||
line-height: 0.96;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
@@ -117,14 +123,15 @@ button {
|
||||
.locale-switch--compact {
|
||||
justify-items: end;
|
||||
min-width: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.locale-switch__buttons {
|
||||
display: inline-grid;
|
||||
grid-auto-flow: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px;
|
||||
gap: 4px;
|
||||
padding: 3px;
|
||||
border: 1px solid rgb(255 255 255 / 0.1);
|
||||
border-radius: 999px;
|
||||
background: rgb(255 255 255 / 0.04);
|
||||
@@ -135,8 +142,8 @@ button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: rgb(247 179 137 / 0.88);
|
||||
}
|
||||
|
||||
@@ -154,13 +161,17 @@ button {
|
||||
|
||||
.locale-switch__buttons button {
|
||||
border-radius: 999px;
|
||||
min-width: 42px;
|
||||
padding: 7px 10px;
|
||||
font-size: 0.78rem;
|
||||
min-width: 36px;
|
||||
padding: 6px 8px;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.locale-switch__buttons--inline {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.locale-switch__buttons button.is-active,
|
||||
.nav-grid button.is-active {
|
||||
border-color: rgb(247 179 137 / 0.7);
|
||||
@@ -263,15 +274,22 @@ button {
|
||||
}
|
||||
|
||||
.ui-button--primary {
|
||||
border-color: rgb(247 179 137 / 0.42);
|
||||
background: rgb(247 179 137 / 0.16);
|
||||
border-color: rgb(247 179 137 / 0.52);
|
||||
background: rgb(247 179 137 / 0.18);
|
||||
color: #fff4ea;
|
||||
}
|
||||
|
||||
.ui-button--secondary,
|
||||
.ui-button--secondary {
|
||||
background: rgb(255 255 255 / 0.04);
|
||||
}
|
||||
|
||||
.ui-button--ghost,
|
||||
.ui-button--icon {
|
||||
background: rgb(255 255 255 / 0.04);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.ui-button--ghost {
|
||||
border-color: rgb(255 255 255 / 0.08);
|
||||
}
|
||||
|
||||
.ui-button--danger {
|
||||
@@ -296,13 +314,19 @@ button {
|
||||
.nav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
gap: 6px;
|
||||
margin-top: 12px;
|
||||
padding: 4px;
|
||||
border: 1px solid rgb(255 255 255 / 0.08);
|
||||
border-radius: 18px;
|
||||
background: rgb(255 255 255 / 0.03);
|
||||
}
|
||||
|
||||
.nav-grid button {
|
||||
border-radius: 18px;
|
||||
padding: 14px 8px;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
min-height: 38px;
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
@@ -314,12 +338,13 @@ button {
|
||||
.content-stack {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.summary-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
@@ -342,9 +367,11 @@ button {
|
||||
.stat-card,
|
||||
.activity-row,
|
||||
.utility-bill-row {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
border: 1px solid rgb(255 255 255 / 0.08);
|
||||
border-radius: 18px;
|
||||
padding: 14px;
|
||||
padding: 16px;
|
||||
background: rgb(255 255 255 / 0.03);
|
||||
}
|
||||
|
||||
@@ -367,7 +394,7 @@ button {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: start;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.balance-item strong,
|
||||
@@ -382,7 +409,7 @@ button {
|
||||
.ledger-item p,
|
||||
.activity-row p,
|
||||
.utility-bill-row p {
|
||||
margin-top: 6px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.balance-status.is-credit {
|
||||
@@ -409,7 +436,6 @@ button {
|
||||
.balance-breakdown {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.member-visual-list {
|
||||
@@ -596,32 +622,8 @@ button {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.section-switch {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.section-switch button {
|
||||
border: 1px solid rgb(255 255 255 / 0.12);
|
||||
border-radius: 16px;
|
||||
min-height: 44px;
|
||||
padding: 10px 12px;
|
||||
background: rgb(255 255 255 / 0.04);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.section-switch button.is-active {
|
||||
border-color: rgb(247 179 137 / 0.7);
|
||||
background: rgb(247 179 137 / 0.14);
|
||||
}
|
||||
|
||||
.admin-layout {
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.admin-hero {
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.admin-summary-grid,
|
||||
@@ -636,24 +638,6 @@ button {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.admin-section__header {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.admin-section__header h3 {
|
||||
margin: 0;
|
||||
font-family: 'Space Grotesk', 'IBM Plex Sans', sans-serif;
|
||||
letter-spacing: -0.04em;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.admin-section__header p {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.admin-sublist {
|
||||
margin-top: 12px;
|
||||
}
|
||||
@@ -728,10 +712,9 @@ button {
|
||||
.panel-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.ledger-compact-card {
|
||||
@@ -806,7 +789,7 @@ button {
|
||||
overflow: auto;
|
||||
border: 1px solid rgb(255 255 255 / 0.1);
|
||||
border-radius: 24px;
|
||||
padding: 18px;
|
||||
padding: 16px;
|
||||
background:
|
||||
linear-gradient(180deg, rgb(255 255 255 / 0.07), rgb(255 255 255 / 0.03)), rgb(18 26 36 / 0.96);
|
||||
box-shadow: 0 28px 80px rgb(0 0 0 / 0.35);
|
||||
@@ -815,7 +798,7 @@ button {
|
||||
.modal-sheet__header {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 12px;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
@@ -827,17 +810,25 @@ button {
|
||||
}
|
||||
|
||||
.modal-sheet__header p {
|
||||
margin-top: 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.modal-sheet__body {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
margin-top: 18px;
|
||||
gap: 14px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.modal-sheet__footer {
|
||||
margin-top: 18px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.modal-close-button {
|
||||
align-self: start;
|
||||
width: 36px;
|
||||
min-width: 36px;
|
||||
min-height: 36px;
|
||||
border-color: rgb(255 255 255 / 0.08);
|
||||
}
|
||||
|
||||
.editor-grid {
|
||||
@@ -952,6 +943,29 @@ button {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.balance-item > p + .ledger-list,
|
||||
.balance-item > p + .balance-list {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.app-context-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.app-context-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.app-context-row__action {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 760px) {
|
||||
.shell {
|
||||
max-width: 920px;
|
||||
@@ -976,10 +990,6 @@ button {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.admin-summary-grid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.admin-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
@@ -999,10 +1009,6 @@ button {
|
||||
.balance-item--wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.section-switch {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 980px) {
|
||||
@@ -1025,21 +1031,17 @@ button {
|
||||
}
|
||||
|
||||
.topbar {
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.locale-switch {
|
||||
justify-items: stretch;
|
||||
width: 100%;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.locale-switch--compact {
|
||||
justify-items: start;
|
||||
}
|
||||
|
||||
.locale-switch__buttons {
|
||||
justify-self: start;
|
||||
justify-items: end;
|
||||
}
|
||||
|
||||
.nav-grid {
|
||||
@@ -1054,10 +1056,6 @@ button {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.admin-section__header {
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.activity-row header,
|
||||
.ledger-compact-card header,
|
||||
.ledger-item header,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { For, Show } from 'solid-js'
|
||||
|
||||
import { FinanceSummaryCards } from '../components/finance/finance-summary-cards'
|
||||
import { FinanceVisuals } from '../components/finance/finance-visuals'
|
||||
import type { MiniAppDashboard } from '../miniapp-api'
|
||||
|
||||
type Props = {
|
||||
@@ -12,32 +11,7 @@ type Props = {
|
||||
currentMemberLine: MiniAppDashboard['members'][number] | null
|
||||
utilityTotalMajor: string
|
||||
purchaseTotalMajor: string
|
||||
memberBalanceVisuals: {
|
||||
member: MiniAppDashboard['members'][number]
|
||||
totalMinor: bigint
|
||||
barWidthPercent: number
|
||||
segments: {
|
||||
key: string
|
||||
label: string
|
||||
amountMajor: string
|
||||
amountMinor: bigint
|
||||
widthPercent: number
|
||||
}[]
|
||||
}[]
|
||||
purchaseChart: {
|
||||
totalMajor: string
|
||||
slices: {
|
||||
key: string
|
||||
label: string
|
||||
amountMajor: string
|
||||
color: string
|
||||
percentage: number
|
||||
dasharray: string
|
||||
dashoffset: string
|
||||
}[]
|
||||
}
|
||||
memberBaseDueMajor: (member: MiniAppDashboard['members'][number]) => string
|
||||
memberRemainingClass: (member: MiniAppDashboard['members'][number]) => string
|
||||
ledgerTitle: (entry: MiniAppDashboard['ledger'][number]) => string
|
||||
ledgerPrimaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string
|
||||
ledgerSecondaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string | null
|
||||
@@ -91,17 +65,7 @@ export function HomeScreen(props: Props) {
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<Show
|
||||
when={props.currentMemberLine}
|
||||
fallback={
|
||||
<article class="balance-item">
|
||||
<header>
|
||||
<strong>{props.copy.overviewTitle ?? ''}</strong>
|
||||
</header>
|
||||
<p>{props.copy.overviewBody ?? ''}</p>
|
||||
</article>
|
||||
}
|
||||
>
|
||||
<Show when={props.currentMemberLine}>
|
||||
{(member) => (
|
||||
<article class="balance-item balance-item--accent">
|
||||
<header>
|
||||
@@ -110,7 +74,6 @@ export function HomeScreen(props: Props) {
|
||||
{member().remainingMajor} {props.dashboard!.currency}
|
||||
</span>
|
||||
</header>
|
||||
<p>{props.copy.yourBalanceBody ?? ''}</p>
|
||||
<p>
|
||||
{props.copy.shareRent ?? ''}: {props.dashboard!.rentSourceAmountMajor}{' '}
|
||||
{props.dashboard!.rentSourceCurrency}
|
||||
@@ -154,23 +117,6 @@ export function HomeScreen(props: Props) {
|
||||
)}
|
||||
</Show>
|
||||
|
||||
<FinanceVisuals
|
||||
dashboard={props.dashboard}
|
||||
memberVisuals={props.memberBalanceVisuals}
|
||||
purchaseChart={props.purchaseChart}
|
||||
remainingClass={props.memberRemainingClass}
|
||||
labels={{
|
||||
financeVisualsTitle: props.copy.financeVisualsTitle ?? '',
|
||||
financeVisualsBody: props.copy.financeVisualsBody ?? '',
|
||||
membersCount: props.copy.membersCount ?? '',
|
||||
purchaseInvestmentsTitle: props.copy.purchaseInvestmentsTitle ?? '',
|
||||
purchaseInvestmentsBody: props.copy.purchaseInvestmentsBody ?? '',
|
||||
purchaseInvestmentsEmpty: props.copy.purchaseInvestmentsEmpty ?? '',
|
||||
purchaseTotalLabel: props.copy.purchaseTotalLabel ?? '',
|
||||
purchaseShareLabel: props.copy.purchaseShareLabel ?? ''
|
||||
}}
|
||||
/>
|
||||
|
||||
<article class="balance-item balance-item--wide">
|
||||
<header>
|
||||
<strong>{props.copy.latestActivityTitle ?? ''}</strong>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
PlusIcon,
|
||||
SettingsIcon
|
||||
} from '../components/ui'
|
||||
import { NavigationTabs } from '../components/layout/navigation-tabs'
|
||||
import type {
|
||||
MiniAppAdminCycleState,
|
||||
MiniAppAdminSettingsPayload,
|
||||
@@ -175,63 +176,21 @@ export function HouseScreen(props: Props) {
|
||||
|
||||
return (
|
||||
<div class="admin-layout">
|
||||
<article class="balance-item balance-item--accent admin-hero">
|
||||
<header>
|
||||
<strong>{props.copy.householdSettingsTitle ?? ''}</strong>
|
||||
<span>{props.adminSettings?.settings.settlementCurrency ?? '—'}</span>
|
||||
</header>
|
||||
<p>{props.copy.householdSettingsBody ?? ''}</p>
|
||||
<div class="admin-summary-grid">
|
||||
<article class="stat-card">
|
||||
<span>{props.copy.billingCycleTitle ?? ''}</span>
|
||||
<strong>{props.cycleState?.cycle?.period ?? props.copy.billingCycleEmpty ?? ''}</strong>
|
||||
</article>
|
||||
<article class="stat-card">
|
||||
<span>{props.copy.settlementCurrency ?? ''}</span>
|
||||
<strong>{props.adminSettings?.settings.settlementCurrency ?? '—'}</strong>
|
||||
</article>
|
||||
<article class="stat-card">
|
||||
<span>{props.copy.membersCount ?? ''}</span>
|
||||
<strong>{String(props.adminSettings?.members.length ?? 0)}</strong>
|
||||
</article>
|
||||
<article class="stat-card">
|
||||
<span>{props.copy.pendingRequests ?? ''}</span>
|
||||
<strong>{String(props.pendingMembers.length)}</strong>
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="section-switch">
|
||||
<For
|
||||
each={
|
||||
<NavigationTabs
|
||||
items={
|
||||
[
|
||||
['billing', props.copy.houseSectionBilling],
|
||||
['utilities', props.copy.houseSectionUtilities],
|
||||
['members', props.copy.houseSectionMembers],
|
||||
['topics', props.copy.houseSectionTopics]
|
||||
{ key: 'billing', label: props.copy.houseSectionBilling ?? '' },
|
||||
{ key: 'utilities', label: props.copy.houseSectionUtilities ?? '' },
|
||||
{ key: 'members', label: props.copy.houseSectionMembers ?? '' },
|
||||
{ key: 'topics', label: props.copy.houseSectionTopics ?? '' }
|
||||
] as const
|
||||
}
|
||||
>
|
||||
{([key, label]) => (
|
||||
<button
|
||||
classList={{ 'is-active': props.activeHouseSection === key }}
|
||||
type="button"
|
||||
onClick={() => props.onChangeHouseSection(key)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
active={props.activeHouseSection}
|
||||
onChange={props.onChangeHouseSection}
|
||||
/>
|
||||
|
||||
<Show when={props.activeHouseSection === 'billing'}>
|
||||
<section class="admin-section">
|
||||
<header class="admin-section__header">
|
||||
<div>
|
||||
<h3>{props.copy.billingCycleTitle ?? ''}</h3>
|
||||
<p>{props.copy.billingSettingsTitle ?? ''}</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="admin-grid">
|
||||
<article class="balance-item">
|
||||
<header>
|
||||
@@ -310,8 +269,7 @@ export function HouseScreen(props: Props) {
|
||||
<strong>{props.copy.householdLanguage ?? ''}</strong>
|
||||
<span>{props.householdDefaultLocale.toUpperCase()}</span>
|
||||
</header>
|
||||
<p>{props.copy.householdSettingsBody ?? ''}</p>
|
||||
<div class="locale-switch__buttons">
|
||||
<div class="locale-switch__buttons locale-switch__buttons--inline">
|
||||
<button
|
||||
classList={{ 'is-active': props.householdDefaultLocale === 'en' }}
|
||||
type="button"
|
||||
@@ -530,12 +488,6 @@ export function HouseScreen(props: Props) {
|
||||
|
||||
<Show when={props.activeHouseSection === 'utilities'}>
|
||||
<section class="admin-section">
|
||||
<header class="admin-section__header">
|
||||
<div>
|
||||
<h3>{props.copy.utilityCategoriesTitle ?? ''}</h3>
|
||||
<p>{props.copy.utilityCategoriesBody ?? ''}</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="admin-grid">
|
||||
<article class="balance-item">
|
||||
<header>
|
||||
@@ -861,12 +813,6 @@ export function HouseScreen(props: Props) {
|
||||
|
||||
<Show when={props.activeHouseSection === 'members'}>
|
||||
<section class="admin-section">
|
||||
<header class="admin-section__header">
|
||||
<div>
|
||||
<h3>{props.copy.adminsTitle ?? ''}</h3>
|
||||
<p>{props.copy.adminsBody ?? ''}</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="admin-grid">
|
||||
<article class="balance-item admin-card--wide">
|
||||
<header>
|
||||
@@ -1118,12 +1064,6 @@ export function HouseScreen(props: Props) {
|
||||
|
||||
<Show when={props.activeHouseSection === 'topics'}>
|
||||
<section class="admin-section">
|
||||
<header class="admin-section__header">
|
||||
<div>
|
||||
<h3>{props.copy.topicBindingsTitle ?? ''}</h3>
|
||||
<p>{props.copy.topicBindingsBody ?? ''}</p>
|
||||
</div>
|
||||
</header>
|
||||
<div class="admin-grid">
|
||||
<article class="balance-item admin-card--wide">
|
||||
<header>
|
||||
|
||||
Reference in New Issue
Block a user