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:
2026-03-14 08:51:53 +04:00
parent 771d64aa4e
commit 488a488137
45 changed files with 2236 additions and 101 deletions

View File

@@ -1033,6 +1033,46 @@ a {
font-weight: 600;
}
.copyable-detail {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: 6px;
border: 0;
background: transparent;
color: inherit;
font: inherit;
cursor: pointer;
transition: background-color 150ms ease;
}
.copyable-detail:hover {
background: rgba(0, 0, 0, 0.04);
}
.copyable-detail svg {
opacity: 0.65;
transition:
opacity 120ms ease,
transform 120ms ease,
color 120ms ease;
}
.copyable-detail:hover svg {
opacity: 0.9;
}
.copyable-detail.is-copied svg {
opacity: 1;
color: var(--status-credit);
transform: scale(1.1);
}
.copyable-detail.is-copied {
background: rgba(34, 197, 94, 0.12);
}
.balance-card__remaining {
padding-top: var(--spacing-sm);
margin-top: var(--spacing-sm);
@@ -1696,3 +1736,55 @@ a {
.balance-item--accent {
border-color: var(--accent-border);
}
/* ── Toast Notifications ─────────────────────── */
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(0);
background: var(--text-primary);
color: var(--bg-root);
padding: 12px 20px;
border-radius: 999px;
font-size: var(--text-sm);
font-weight: 500;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
z-index: var(--z-toast);
animation: toast-slide-up 200ms ease-out;
max-width: calc(100vw - 48px);
text-align: center;
}
.toast--success {
background: var(--status-credit);
color: #fff;
}
.toast--info {
background: var(--text-primary);
color: var(--bg-root);
}
.toast--error {
background: var(--status-danger);
color: #fff;
}
.toast__message {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@keyframes toast-slide-up {
from {
opacity: 0;
transform: translateX(-50%) translateY(16px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}