mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 12:04:02 +00:00
feat: add quick payment action and improve copy button UX
Mini App Home Screen: - Add 'Record Payment' button to utilities and rent period cards - Pre-fill payment amount with member's share (rentShare/utilityShare) - Modal dialog with amount input and currency display - Toast notifications for copy and payment success/failure feedback Copy Button Improvements: - Increase spacing between icon and text (4px → 8px) - Add hover background and padding for better touch target - Green background highlight when copied (in addition to icon color change) - Toast notification appears when copying any value Backend: - Add /api/miniapp/payments/add endpoint for quick payments - Payment notifications sent to 'reminders' topic in Telegram - Include member name, payment type, amount, and period in notification Files: - New: apps/miniapp/src/components/ui/toast.tsx - Modified: apps/miniapp/src/routes/home.tsx, apps/miniapp/src/index.css, apps/miniapp/src/theme.css, apps/miniapp/src/i18n.ts, apps/bot/src/miniapp-billing.ts, apps/bot/src/server.ts Quality Gates: ✅ format, lint, typecheck, build, test Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
type HouseholdMemberRecord,
|
||||
type HouseholdPaymentBalanceAdjustmentPolicy,
|
||||
type HouseholdPendingMemberRecord,
|
||||
type HouseholdRentPaymentDestination,
|
||||
type HouseholdTelegramChatRecord,
|
||||
type HouseholdTopicBindingRecord,
|
||||
type HouseholdTopicRole,
|
||||
@@ -218,6 +219,38 @@ function toCurrencyCode(raw: string): CurrencyCode {
|
||||
return normalized
|
||||
}
|
||||
|
||||
function normalizeOptionalString(value: unknown): string | null {
|
||||
if (typeof value !== 'string') return null
|
||||
const trimmed = value.trim()
|
||||
return trimmed.length > 0 ? trimmed : null
|
||||
}
|
||||
|
||||
function parseRentPaymentDestinations(
|
||||
value: unknown
|
||||
): readonly HouseholdRentPaymentDestination[] | null {
|
||||
if (value === null || value === undefined) return null
|
||||
if (!Array.isArray(value)) return null
|
||||
|
||||
return value
|
||||
.map((entry): HouseholdRentPaymentDestination | null => {
|
||||
if (!entry || typeof entry !== 'object') return null
|
||||
const record = entry as Record<string, unknown>
|
||||
const label = normalizeOptionalString(record.label) ?? ''
|
||||
const account = normalizeOptionalString(record.account) ?? ''
|
||||
if (!label || !account) return null
|
||||
|
||||
return {
|
||||
label,
|
||||
recipientName: normalizeOptionalString(record.recipientName),
|
||||
bankName: normalizeOptionalString(record.bankName),
|
||||
account,
|
||||
note: normalizeOptionalString(record.note),
|
||||
link: normalizeOptionalString(record.link)
|
||||
}
|
||||
})
|
||||
.filter((entry): entry is HouseholdRentPaymentDestination => Boolean(entry))
|
||||
}
|
||||
|
||||
function toHouseholdBillingSettingsRecord(row: {
|
||||
householdId: string
|
||||
settlementCurrency: string
|
||||
@@ -229,6 +262,7 @@ function toHouseholdBillingSettingsRecord(row: {
|
||||
utilitiesDueDay: number
|
||||
utilitiesReminderDay: number
|
||||
timezone: string
|
||||
rentPaymentDestinations: unknown
|
||||
}): HouseholdBillingSettingsRecord {
|
||||
return {
|
||||
householdId: row.householdId,
|
||||
@@ -242,7 +276,8 @@ function toHouseholdBillingSettingsRecord(row: {
|
||||
rentWarningDay: row.rentWarningDay,
|
||||
utilitiesDueDay: row.utilitiesDueDay,
|
||||
utilitiesReminderDay: row.utilitiesReminderDay,
|
||||
timezone: row.timezone
|
||||
timezone: row.timezone,
|
||||
rentPaymentDestinations: parseRentPaymentDestinations(row.rentPaymentDestinations)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,7 +991,8 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
rentWarningDay: schema.householdBillingSettings.rentWarningDay,
|
||||
utilitiesDueDay: schema.householdBillingSettings.utilitiesDueDay,
|
||||
utilitiesReminderDay: schema.householdBillingSettings.utilitiesReminderDay,
|
||||
timezone: schema.householdBillingSettings.timezone
|
||||
timezone: schema.householdBillingSettings.timezone,
|
||||
rentPaymentDestinations: schema.householdBillingSettings.rentPaymentDestinations
|
||||
})
|
||||
.from(schema.householdBillingSettings)
|
||||
.where(eq(schema.householdBillingSettings.householdId, householdId))
|
||||
@@ -1040,6 +1076,11 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
timezone: input.timezone
|
||||
}
|
||||
: {}),
|
||||
...(input.rentPaymentDestinations !== undefined
|
||||
? {
|
||||
rentPaymentDestinations: input.rentPaymentDestinations
|
||||
}
|
||||
: {}),
|
||||
updatedAt: instantToDate(nowInstant())
|
||||
})
|
||||
.where(eq(schema.householdBillingSettings.householdId, input.householdId))
|
||||
@@ -1054,7 +1095,8 @@ export function createDbHouseholdConfigurationRepository(databaseUrl: string): {
|
||||
rentWarningDay: schema.householdBillingSettings.rentWarningDay,
|
||||
utilitiesDueDay: schema.householdBillingSettings.utilitiesDueDay,
|
||||
utilitiesReminderDay: schema.householdBillingSettings.utilitiesReminderDay,
|
||||
timezone: schema.householdBillingSettings.timezone
|
||||
timezone: schema.householdBillingSettings.timezone,
|
||||
rentPaymentDestinations: schema.householdBillingSettings.rentPaymentDestinations
|
||||
})
|
||||
|
||||
const row = rows[0]
|
||||
|
||||
Reference in New Issue
Block a user