From 4a3ed75da1e4c015f2a5e5707c648c4b218aeb62 Mon Sep 17 00:00:00 2001 From: BoHsuu <115441679+Huygon764@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:41:32 +0700 Subject: [PATCH 1/4] refactor: improve layout and responsiveness in Quest and Batch components (#200) - Updated QuestPage layout for better responsiveness with max-width and padding adjustments. - Changed BatchTransactions and TransactionSummary components to use flexbox for improved item alignment and responsiveness. - Enhanced QuestCard to allow for flexible width. - Added titles for new routes in the Title component. --- .../components/Batch/BatchContainer.tsx | 6 +--- .../components/Batch/TransactionSummary.tsx | 31 +++++-------------- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/packages/nextjs/components/Batch/BatchContainer.tsx b/packages/nextjs/components/Batch/BatchContainer.tsx index febcefc..93cecd6 100644 --- a/packages/nextjs/components/Batch/BatchContainer.tsx +++ b/packages/nextjs/components/Batch/BatchContainer.tsx @@ -179,11 +179,7 @@ function BatchTransactions({ {/* Recipient */}
{matchedContact ? ( - +
= ({
{/* Header Section */}
- Batch transactions + Batch transactions
Transactions summary @@ -58,7 +58,10 @@ const TransactionSummary: React.FC = ({ ); return ( -
+
{/* Amount with Token Icon */}
{transaction.tokenIcon && ( @@ -74,26 +77,14 @@ const TransactionSummary: React.FC = ({ {/* Arrow */}
- Arrow Right + Arrow Right
{/* Recipient */}
{matchedContact ? (
- avatar + avatar {matchedContact.name} {"(" + `${formatAddress(transaction.recipient, { start: 3, end: 3 }) + ")"}`} @@ -101,13 +92,7 @@ const TransactionSummary: React.FC = ({
) : ( - avatar + avatar {formatAddress(transaction.recipient, { start: 3, end: 3 })} )} From e3ae7719dce56d6a2417b3e0d1532605b5373a78 Mon Sep 17 00:00:00 2001 From: BoHsuu <115441679+Huygon764@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:27:44 +0700 Subject: [PATCH 2/4] Refactor/extract magic numbers to constants (#203) * refactor: adjust z-index values across various components for improved UI layering * feat: add timing constants for HTTP timeouts, cache TTL, and retry delays - Introduced new timing constants in `timing.ts` for backend and nextjs packages. - Updated index files to export the new timing constants for better accessibility. refactor: replace hardcoded values with timing constants for retries and timeouts - Updated various services and modules to utilize new timing constants for retries and timeouts, improving maintainability and consistency across the codebase. - Adjusted `waitForReceiptWithRetry`, `PriceService`, `ZenTransferService`, `TransactionService`, and `ZkVerifyService` to use centralized timing configurations. refactor: replace hardcoded values with timing constants across components and hooks - Updated various components and hooks to utilize new timing constants for polling intervals, refetch intervals, and timeouts, enhancing maintainability and consistency throughout the codebase. - Adjusted `NotificationItem`, `ClaimSection`, `EditAccountModal`, and several hooks to reference centralized timing configurations. refactor: standardize formatting and improve component styles - Refactored various components to enhance code readability by standardizing formatting, including consistent indentation and spacing. - Updated styles across components to utilize new shadow and height constants for improved UI consistency. - Adjusted text sizes in multiple components to ensure uniformity in typography. --- packages/nextjs/services/api/apiClient.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nextjs/services/api/apiClient.ts b/packages/nextjs/services/api/apiClient.ts index cc8ed2c..12f469b 100644 --- a/packages/nextjs/services/api/apiClient.ts +++ b/packages/nextjs/services/api/apiClient.ts @@ -4,6 +4,7 @@ import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestCo import { API_BASE_URL } from "~~/constants"; import { API_TIMEOUT_DEFAULT, API_TIMEOUT_ZK } from "~~/constants/timing"; import { formatErrorMessage } from "~~/utils/formatError"; +import { API_TIMEOUT_DEFAULT, API_TIMEOUT_ZK } from "~~/constants/timing"; const AUTHORIZATION_HEADER = (accessToken: string) => `Bearer ${accessToken}`; From ed00cf104112703a55f4b2a8bbaaedbccd546311 Mon Sep 17 00:00:00 2001 From: BoHsuu <115441679+Huygon764@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:29:00 +0700 Subject: [PATCH 3/4] refactor: enhance component structure and user feedback in NewAccount sections (#206) - Updated ChooseNetwork component to include wallet connection checks and commitment validation, enhancing user experience with appropriate notifications. - Adjusted StatusContainer to allow copying of commitment addresses to clipboard for better usability. - Enhanced Sidebar component to incorporate wallet connection status in navigation logic. --- .../components/Batch/BatchContainer.tsx | 6 +++- .../components/Batch/TransactionSummary.tsx | 31 ++++++++++++++----- packages/nextjs/services/api/apiClient.ts | 1 - 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/nextjs/components/Batch/BatchContainer.tsx b/packages/nextjs/components/Batch/BatchContainer.tsx index 93cecd6..febcefc 100644 --- a/packages/nextjs/components/Batch/BatchContainer.tsx +++ b/packages/nextjs/components/Batch/BatchContainer.tsx @@ -179,7 +179,11 @@ function BatchTransactions({ {/* Recipient */}
{matchedContact ? ( - +
= ({
{/* Header Section */}
- Batch transactions + Batch transactions
Transactions summary @@ -58,10 +58,7 @@ const TransactionSummary: React.FC = ({ ); return ( -
+
{/* Amount with Token Icon */}
{transaction.tokenIcon && ( @@ -77,14 +74,26 @@ const TransactionSummary: React.FC = ({ {/* Arrow */}
- Arrow Right + Arrow Right
{/* Recipient */}
{matchedContact ? (
- avatar + avatar {matchedContact.name} {"(" + `${formatAddress(transaction.recipient, { start: 3, end: 3 }) + ")"}`} @@ -92,7 +101,13 @@ const TransactionSummary: React.FC = ({
) : ( - avatar + avatar {formatAddress(transaction.recipient, { start: 3, end: 3 })} )} diff --git a/packages/nextjs/services/api/apiClient.ts b/packages/nextjs/services/api/apiClient.ts index 12f469b..cc8ed2c 100644 --- a/packages/nextjs/services/api/apiClient.ts +++ b/packages/nextjs/services/api/apiClient.ts @@ -4,7 +4,6 @@ import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestCo import { API_BASE_URL } from "~~/constants"; import { API_TIMEOUT_DEFAULT, API_TIMEOUT_ZK } from "~~/constants/timing"; import { formatErrorMessage } from "~~/utils/formatError"; -import { API_TIMEOUT_DEFAULT, API_TIMEOUT_ZK } from "~~/constants/timing"; const AUTHORIZATION_HEADER = (accessToken: string) => `Bearer ${accessToken}`; From b6924df833b9b2105216ea402d6fb60e426e7c79 Mon Sep 17 00:00:00 2001 From: BoHsuu <115441679+Huygon764@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:00:52 +0700 Subject: [PATCH 4/4] feat: filter Base accounts and show creator EOA wallet in partner report (#220) --- .../backend/src/partner/partner.service.ts | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/packages/backend/src/partner/partner.service.ts b/packages/backend/src/partner/partner.service.ts index b81970f..4692fe6 100644 --- a/packages/backend/src/partner/partner.service.ts +++ b/packages/backend/src/partner/partner.service.ts @@ -3,12 +3,16 @@ import { PrismaService } from '@/database/prisma.service'; import { AccountReportDto } from './dto/account-report.dto'; import { getChainById } from '@polypay/shared'; +const BASE_CHAIN_IDS = [8453, 84532]; + @Injectable() export class PartnerService { constructor(private readonly prisma: PrismaService) {} async generateAccountReport(dto: AccountReportDto): Promise { - const where: Record = {}; + const where: Record = { + chainId: { notIn: BASE_CHAIN_IDS }, + }; if (dto.startDate || dto.endDate) { where.createdAt = {}; @@ -26,38 +30,70 @@ export class PartnerService { const accounts = await this.prisma.account.findMany({ where, - select: { address: true, createdAt: true, chainId: true }, + include: { + signers: { + include: { user: true }, + orderBy: { createdAt: 'asc' }, + }, + }, orderBy: { createdAt: 'desc' }, }); - return this.generateCSV(accounts, dto.includeChainId); + // Get creator (or first signer as fallback) commitment for each account + const commitments = accounts + .map((a) => { + const creator = a.signers.find((s) => s.isCreator); + return (creator || a.signers[0])?.user.commitment; + }) + .filter((c): c is string => !!c); + const addressMap = await this.buildCommitmentToAddressMap(commitments); + + return this.generateCSV(accounts, addressMap, dto.includeChainId); } - private getExplorerAddressUrl(chainId: number, address: string): string { - try { - const chain = getChainById(chainId); - return `${chain.blockExplorers!.default.url}/address/${address}`; - } catch { - return address; - } + private async buildCommitmentToAddressMap( + commitments: string[], + ): Promise> { + if (commitments.length === 0) return new Map(); + + const uniqueCommitments = [...new Set(commitments)]; + const loginHistories = await this.prisma.loginHistory.findMany({ + where: { commitment: { in: uniqueCommitments } }, + orderBy: { createdAt: 'desc' }, + distinct: ['commitment'], + }); + + return new Map( + loginHistories.map((lh) => [lh.commitment, lh.walletAddress]), + ); } private generateCSV( - accounts: { address: string; createdAt: Date; chainId: number }[], + accounts: { + address: string; + createdAt: Date; + chainId: number; + signers: { + isCreator: boolean; + user: { commitment: string }; + }[]; + }[], + addressMap: Map, includeChainId?: boolean, ): string { const totalLine = [`Total Accounts,${accounts.length}`, '']; const header = includeChainId - ? 'Address,Explorer Address,Created At,Chain ID,Chain Name' - : 'Address,Explorer Address,Created At'; + ? 'Multisig Account Address,EOA,Created At,Chain ID,Chain Name' + : 'Multisig Account Address,EOA,Created At'; const rows = accounts.map((account) => { - const addressLink = this.getExplorerAddressUrl( - account.chainId, - account.address, - ); - const base = `${account.address},${addressLink},${account.createdAt.toISOString()}`; + const creator = account.signers.find((s) => s.isCreator); + const commitment = (creator || account.signers[0])?.user.commitment; + const eoaWallet = commitment + ? addressMap.get(commitment) || 'UNKNOWN' + : 'UNKNOWN'; + const base = `${account.address},${eoaWallet},${account.createdAt.toISOString()}`; if (includeChainId) { let chainName: string; try {