diff --git a/packages/backend/server/src/modules/users/resolver.ts b/packages/backend/server/src/modules/users/resolver.ts index cc3a529f4..806fa41ca 100644 --- a/packages/backend/server/src/modules/users/resolver.ts +++ b/packages/backend/server/src/modules/users/resolver.ts @@ -8,10 +8,12 @@ import { Args, Field, ID, + Int, Mutation, ObjectType, Query, registerEnumType, + ResolveField, Resolver, } from '@nestjs/graphql'; import type { User } from '@prisma/client'; @@ -156,6 +158,17 @@ export class UserResolver { return user; } + @Throttle({ default: { limit: 10, ttl: 60 } }) + @ResolveField(() => Int, { + name: 'invoiceCount', + description: 'Get user invoice count', + }) + async invoiceCount(@CurrentUser() user: UserType) { + return this.prisma.userInvoice.count({ + where: { userId: user.id }, + }); + } + @Throttle({ default: { limit: 10, diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index dc68b19d1..7e735b488 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -23,6 +23,9 @@ type UserType { """User password has been set""" hasPassword: Boolean token: TokenType! + + """Get user invoice count""" + invoiceCount: Int! subscription: UserSubscription invoices(take: Int = 8, skip: Int): [UserInvoice!]! } diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx index a99e6f709..c698d7767 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/billing/index.tsx @@ -1,3 +1,4 @@ +import { Pagination } from '@affine/component/member-components'; import { SettingHeader, SettingRow, @@ -6,6 +7,7 @@ import { import { cancelSubscriptionMutation, createCustomerPortalMutation, + getInvoicesCountQuery, type InvoicesQuery, invoicesQuery, InvoiceStatus, @@ -41,6 +43,8 @@ enum DescriptionI18NKey { Yearly = 'com.affine.payment.billing-setting.current-plan.description.yearly', } +const INVOICE_PAGE_SIZE = 12; + const getMessageKey = ( plan: SubscriptionPlan, recurring: SubscriptionRecurring @@ -334,27 +338,40 @@ const CancelSubscription = ({ loading }: { loading?: boolean }) => { const BillingHistory = () => { const t = useAFFiNEI18N(); + const { data: invoicesCountQueryResult } = useQuery({ + query: getInvoicesCountQuery, + }); + + const [skip, setSkip] = useState(0); + const { data: invoicesQueryResult } = useQuery({ query: invoicesQuery, - variables: { - skip: 0, - take: 12, - }, + variables: { skip, take: INVOICE_PAGE_SIZE }, }); const invoices = invoicesQueryResult.currentUser?.invoices ?? []; + const invoiceCount = invoicesCountQueryResult.currentUser?.invoiceCount ?? 0; return ( -
- {t['com.affine.payment.billing-setting.no-invoice']()} -
- ) : ( - // TODO: pagination - invoices.map(invoice => ( -+ {t['com.affine.payment.billing-setting.no-invoice']()} +
+ ) : ( + invoices.map(invoice => ( +