mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 10:24:02 +00:00
feat(miniapp): add billing review tools and house sections
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,10 @@ export const dictionary = {
|
||||
balances: 'Balances',
|
||||
ledger: 'Ledger',
|
||||
house: 'House',
|
||||
houseSectionBilling: 'Billing',
|
||||
houseSectionUtilities: 'Utilities',
|
||||
houseSectionMembers: 'Members',
|
||||
houseSectionTopics: 'Topics',
|
||||
welcome: 'Welcome back',
|
||||
adminTag: 'Admin',
|
||||
residentTag: 'Resident',
|
||||
@@ -69,6 +73,22 @@ export const dictionary = {
|
||||
emptyDashboard: 'No billing cycle is ready yet.',
|
||||
latestActivityTitle: 'Latest activity',
|
||||
latestActivityEmpty: 'Recent utility and purchase entries will appear here.',
|
||||
purchaseReviewTitle: 'Purchases',
|
||||
purchaseReviewBody: 'Edit or remove purchases if the bot recorded the wrong item.',
|
||||
paymentsAdminTitle: 'Payments',
|
||||
paymentsAdminBody: 'Add, fix, or remove payment records for the current cycle.',
|
||||
paymentsAddAction: 'Add payment',
|
||||
addingPayment: 'Adding payment…',
|
||||
paymentKind: 'Payment kind',
|
||||
paymentAmount: 'Payment amount',
|
||||
paymentMember: 'Member',
|
||||
paymentSaveAction: 'Save payment',
|
||||
paymentDeleteAction: 'Delete payment',
|
||||
deletingPayment: 'Deleting payment…',
|
||||
purchaseSaveAction: 'Save purchase',
|
||||
purchaseDeleteAction: 'Delete purchase',
|
||||
deletingPurchase: 'Deleting purchase…',
|
||||
savingPurchase: 'Saving purchase…',
|
||||
householdSettingsTitle: 'Household settings',
|
||||
householdSettingsBody: 'Control household defaults and approve roommates who requested access.',
|
||||
topicBindingsTitle: 'Topic bindings',
|
||||
@@ -171,6 +191,10 @@ export const dictionary = {
|
||||
balances: 'Баланс',
|
||||
ledger: 'Леджер',
|
||||
house: 'Дом',
|
||||
houseSectionBilling: 'Биллинг',
|
||||
houseSectionUtilities: 'Коммуналка',
|
||||
houseSectionMembers: 'Участники',
|
||||
houseSectionTopics: 'Топики',
|
||||
welcome: 'С возвращением',
|
||||
adminTag: 'Админ',
|
||||
residentTag: 'Житель',
|
||||
@@ -204,6 +228,23 @@ export const dictionary = {
|
||||
emptyDashboard: 'Пока нет готового billing cycle.',
|
||||
latestActivityTitle: 'Последняя активность',
|
||||
latestActivityEmpty: 'Здесь появятся последние коммунальные платежи и покупки.',
|
||||
purchaseReviewTitle: 'Покупки',
|
||||
purchaseReviewBody:
|
||||
'Здесь можно исправить или удалить покупку, если бот распознал её неправильно.',
|
||||
paymentsAdminTitle: 'Оплаты',
|
||||
paymentsAdminBody: 'Добавляй, исправляй или удаляй оплаты за текущий цикл.',
|
||||
paymentsAddAction: 'Добавить оплату',
|
||||
addingPayment: 'Добавляем оплату…',
|
||||
paymentKind: 'Тип оплаты',
|
||||
paymentAmount: 'Сумма оплаты',
|
||||
paymentMember: 'Участник',
|
||||
paymentSaveAction: 'Сохранить оплату',
|
||||
paymentDeleteAction: 'Удалить оплату',
|
||||
deletingPayment: 'Удаляем оплату…',
|
||||
purchaseSaveAction: 'Сохранить покупку',
|
||||
purchaseDeleteAction: 'Удалить покупку',
|
||||
deletingPurchase: 'Удаляем покупку…',
|
||||
savingPurchase: 'Сохраняем покупку…',
|
||||
householdSettingsTitle: 'Настройки household',
|
||||
householdSettingsBody: 'Здесь можно менять язык household и подтверждать новых соседей.',
|
||||
topicBindingsTitle: 'Привязанные топики',
|
||||
|
||||
@@ -327,6 +327,26 @@ 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;
|
||||
}
|
||||
@@ -396,7 +416,8 @@ button {
|
||||
padding: 12px 14px;
|
||||
background: rgb(255 255 255 / 0.04);
|
||||
color: inherit;
|
||||
line-height: 1.35;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.settings-field__value {
|
||||
@@ -452,6 +473,13 @@ button {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.activity-row p,
|
||||
.ledger-item p,
|
||||
.utility-bill-row p,
|
||||
.balance-item p {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
@media (min-width: 760px) {
|
||||
.shell {
|
||||
max-width: 920px;
|
||||
@@ -498,6 +526,10 @@ button {
|
||||
.balance-item--wide {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.section-switch {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 980px) {
|
||||
|
||||
@@ -96,6 +96,7 @@ export interface MiniAppDashboard {
|
||||
id: string
|
||||
kind: 'purchase' | 'utility' | 'payment'
|
||||
title: string
|
||||
memberId: string | null
|
||||
paymentKind: 'rent' | 'utilities' | null
|
||||
amountMajor: string
|
||||
currency: 'USD' | 'GEL'
|
||||
@@ -731,3 +732,118 @@ export async function deleteMiniAppUtilityBill(
|
||||
|
||||
return payload.cycleState
|
||||
}
|
||||
|
||||
export async function updateMiniAppPurchase(
|
||||
initData: string,
|
||||
input: {
|
||||
purchaseId: string
|
||||
description: string
|
||||
amountMajor: string
|
||||
currency: 'USD' | 'GEL'
|
||||
}
|
||||
): Promise<void> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/purchases/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
initData,
|
||||
...input
|
||||
})
|
||||
})
|
||||
|
||||
const payload = (await response.json()) as { ok: boolean; authorized?: boolean; error?: string }
|
||||
if (!response.ok || !payload.authorized) {
|
||||
throw new Error(payload.error ?? 'Failed to update purchase')
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteMiniAppPurchase(initData: string, purchaseId: string): Promise<void> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/purchases/delete`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
initData,
|
||||
purchaseId
|
||||
})
|
||||
})
|
||||
|
||||
const payload = (await response.json()) as { ok: boolean; authorized?: boolean; error?: string }
|
||||
if (!response.ok || !payload.authorized) {
|
||||
throw new Error(payload.error ?? 'Failed to delete purchase')
|
||||
}
|
||||
}
|
||||
|
||||
export async function addMiniAppPayment(
|
||||
initData: string,
|
||||
input: {
|
||||
memberId: string
|
||||
kind: 'rent' | 'utilities'
|
||||
amountMajor: string
|
||||
currency: 'USD' | 'GEL'
|
||||
}
|
||||
): Promise<void> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/payments/add`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
initData,
|
||||
...input
|
||||
})
|
||||
})
|
||||
|
||||
const payload = (await response.json()) as { ok: boolean; authorized?: boolean; error?: string }
|
||||
if (!response.ok || !payload.authorized) {
|
||||
throw new Error(payload.error ?? 'Failed to add payment')
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateMiniAppPayment(
|
||||
initData: string,
|
||||
input: {
|
||||
paymentId: string
|
||||
memberId: string
|
||||
kind: 'rent' | 'utilities'
|
||||
amountMajor: string
|
||||
currency: 'USD' | 'GEL'
|
||||
}
|
||||
): Promise<void> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/payments/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
initData,
|
||||
...input
|
||||
})
|
||||
})
|
||||
|
||||
const payload = (await response.json()) as { ok: boolean; authorized?: boolean; error?: string }
|
||||
if (!response.ok || !payload.authorized) {
|
||||
throw new Error(payload.error ?? 'Failed to update payment')
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteMiniAppPayment(initData: string, paymentId: string): Promise<void> {
|
||||
const response = await fetch(`${apiBaseUrl()}/api/miniapp/admin/payments/delete`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
initData,
|
||||
paymentId
|
||||
})
|
||||
})
|
||||
|
||||
const payload = (await response.json()) as { ok: boolean; authorized?: boolean; error?: string }
|
||||
if (!response.ok || !payload.authorized) {
|
||||
throw new Error(payload.error ?? 'Failed to delete payment')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user