diff --git a/package.json b/package.json index eebc545976..d315115e42 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@f08cb74", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8", "@faker-js/faker": "^9.9.0", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a4161ed87..85e4ab769e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ importers: specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -269,8 +269,8 @@ packages: peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -284,8 +284,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -3709,7 +3709,7 @@ snapshots: dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@077179c(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@3a17fe8(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3722,7 +3722,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@077179c(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@3a17fe8(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 8fd03090e7..5bbbfe77b4 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -22,6 +22,7 @@ export enum Dependencies { CREDIT = 'dependency:credit', INVOICES = 'dependency:invoices', ADDRESS = 'dependency:address', + BILLING_AGGREGATION = 'dependency:billing_aggregation', UPGRADE_PLAN = 'dependency:upgrade_plan', ORGANIZATIONS = 'dependency:organizations', PAYMENT_METHODS = 'dependency:paymentMethods', diff --git a/src/lib/sdk/billing.ts b/src/lib/sdk/billing.ts index 0361f59101..f3f0a0b583 100644 --- a/src/lib/sdk/billing.ts +++ b/src/lib/sdk/billing.ts @@ -934,12 +934,24 @@ export class Billing { ); } - async getAggregation(organizationId: string, aggregationId: string): Promise { + async getAggregation( + organizationId: string, + aggregationId: string, + limit?: number, + offset?: number + ): Promise { const path = `/organizations/${organizationId}/aggregations/${aggregationId}`; - const params = { + const params: { + organizationId: string; + aggregationId: string; + limit?: number; + offset?: number; + } = { organizationId, aggregationId }; + if (typeof limit === 'number') params.limit = limit; + if (typeof offset === 'number') params.offset = offset; const uri = new URL(this.client.config.endpoint + path); return await this.client.call( 'get', diff --git a/src/routes/(console)/organization-[organization]/billing/+page.svelte b/src/routes/(console)/organization-[organization]/billing/+page.svelte index e749892505..421f48efc7 100644 --- a/src/routes/(console)/organization-[organization]/billing/+page.svelte +++ b/src/routes/(console)/organization-[organization]/billing/+page.svelte @@ -133,7 +133,10 @@ availableCredit={data?.availableCredit} currentPlan={data?.currentPlan} nextPlan={data?.nextPlan} - currentAggregation={data?.billingAggregation} /> + currentAggregation={data?.billingAggregation} + limit={data?.limit} + offset={data?.offset} + aggregationKey={data?.aggregationKey} /> {:else} { +import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; + +export const load: PageLoad = async ({ parent, depends, url, route }) => { const { organization, scopes, currentPlan, countryList, locale } = await parent(); if (!scopes.includes('billing.read')) { @@ -19,6 +21,8 @@ export const load: PageLoad = async ({ parent, depends }) => { depends(Dependencies.CREDIT); depends(Dependencies.INVOICES); depends(Dependencies.ADDRESS); + //aggregation reloads on page param changes + depends(Dependencies.BILLING_AGGREGATION); const billingAddressId = (organization as Organization)?.billingAddressId; const billingAddressPromise: Promise
= billingAddressId @@ -34,9 +38,14 @@ export const load: PageLoad = async ({ parent, depends }) => { */ let billingAggregation = null; try { + const currentPage = getPage(url) || 1; + const limit = getLimit(url, route, 5); + const offset = pageToOffset(currentPage, limit); billingAggregation = await sdk.forConsole.billing.getAggregation( organization.$id, - (organization as Organization)?.billingAggregationId + (organization as Organization)?.billingAggregationId, + limit, + offset ); } catch (e) { // ignore error @@ -84,6 +93,9 @@ export const load: PageLoad = async ({ parent, depends }) => { areCreditsSupported, countryList, locale, - nextPlan: billingPlanDowngrade + nextPlan: billingPlanDowngrade, + // expose pagination for components + limit: getLimit(url, route, 5), + offset: pageToOffset(getPage(url) || 1, getLimit(url, route, 5)) }; }; diff --git a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte index 6a4a43f01c..c49d52a759 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummary.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummary.svelte @@ -1,6 +1,6 @@ {#if $organization} - - {currentPlan.name} plan - - {#if totalAmount > 0} - - Next payment of {formatCurrency(totalAmount)} - will occur on - {toLocaleDate($organization?.billingNextInvoiceDate)}. - - {/if} - -
- - Current billing cycle ({new Date( - $organization?.billingCurrentInvoiceDate - ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}-{new Date( - $organization?.billingNextInvoiceDate - ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}) - - - Estimate, subject to change based on usage. - -
- -
- - {#each billingData as row} - - {#each columns as col} - - {#if col.id === 'item'} -
+ {#key aggregationKey} + + {currentPlan.name} plan + + {#if totalAmount > 0} + + Next payment of {formatCurrency(totalAmount)} + will occur on + {toLocaleDate($organization?.billingNextInvoiceDate)}. + + {/if} + +
+ + Current billing cycle ({new Date( + $organization?.billingCurrentInvoiceDate + ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}-{new Date( + $organization?.billingNextInvoiceDate + ).toLocaleDateString('en', { day: 'numeric', month: 'short' })}) + + + Estimate, subject to change based on usage. + +
+ +
+ + {#each billingData as row} + + {#each columns as col} + + {#if col.id === 'item'} +
+ {#if row.badge} + + + {row.cells?.[col.id] ?? ''} + + + + {:else} + + {row.cells?.[col.id] ?? ''} + + {/if} +
+ {:else} {row.cells?.[col.id] ?? ''} -
- {:else} - - {row.cells?.[col.id] ?? ''} - - {/if} - - {/each} - - - {#if row.children} - {#each row.children as child (child.id)} - - {/each} -
- {/each} - {/if} - -
- {/each} - {#if availableCredit > 0} - - - - - - Credits - - - + + +
+
+ {#if child.progressData && child.progressData.length > 0 && child.maxValue} + + {/if} +
+
+ {#if child.cells?.usage?.includes(' / ')} + {@const usageParts = ( + child.cells?.usage ?? '' + ).split(' / ')} + + {usageParts[0]} + + + {' / '} + + + {usageParts[1]} + + {:else} + + {child.cells?.usage ?? ''} + + {/if} +
+
+
+ + + {child.cells?.price ?? ''} + + + + {/each} + {/if} + + + {/each} + {#if totalProjects > projectsLimit} + + +
+ +
+
+ + +
+ {/if} + {#if availableCredit > 0} + + + + + + Credits + + + + + + + + + -{formatCurrency(creditsApplied)} + + + + {/if} + + + + Total -
- + + - -{formatCurrency(creditsApplied)} - -
- {/if} - - - - - Total - - - - - - - - - {formatCurrency(totalAmount)} - - - -
-
- - -
- {#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION} -
- {#if !currentPlan?.usagePerProject} - - {/if} - -
- {:else} -
- {#if $organization?.billingPlanDowngrade !== null} - - {:else} + + + + {formatCurrency(totalAmount)} + + + + +
+ + +
+ {#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION} + + {#if !currentPlan?.usagePerProject} + + {/if} - {/if} - {#if !currentPlan?.usagePerProject} - - {/if} -
- {/if} -
-
+ + {:else} + + {#if $organization?.billingPlanDowngrade !== null} + + {:else} + + {/if} + {#if !currentPlan?.usagePerProject} + + {/if} + + {/if} + + + {/key} {/if} @@ -668,50 +743,7 @@ flex-shrink: 0; } - /* mobile table wrapper for horizontal scroll */ - .table-wrapper.is-mobile { - overflow-x: auto; - -webkit-overflow-scrolling: touch; - margin: 0 -1rem; - padding: 0 1rem; - } - - /* reset mobile overrides - use desktop layout in scrollable container */ - .table-wrapper.is-mobile :global(.child-row) { - grid-template-columns: var(--original-grid-template) !important; - min-width: 600px; /* ensure minimum width for proper layout */ - } - - .table-wrapper.is-mobile :global(.usage-cell-content) { - flex-direction: row !important; - align-items: center !important; - gap: 0.75rem !important; - padding-left: 1rem !important; - min-height: 2rem !important; - } - - .table-wrapper.is-mobile :global(.usage-progress-section) { - width: 200px !important; - flex-shrink: 0 !important; - } - - .table-wrapper.is-mobile :global(.usage-progress-section .progressbar__container) { - width: 200px !important; - max-width: 200px !important; - } - @media (max-width: 768px) { - .actions-mobile { - justify-content: flex-start !important; - gap: 8px !important; - } - - .actions-mobile :global(a), - .actions-mobile :global(button) { - padding: 6px 12px !important; - font-size: 14px !important; - border-radius: 8px !important; - } .billing-cycle-header { flex-direction: column; gap: 8px; @@ -733,4 +765,11 @@ background: unset !important; } } + + /* reducingh size of paginator */ + .pagination-left { + display: inline-block; + transform: scale(0.95); + transform-origin: left center; + } diff --git a/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte b/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte index 18fdd81ccb..083aff4445 100644 --- a/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte +++ b/src/routes/(console)/organization-[organization]/billing/planSummaryOld.svelte @@ -199,7 +199,7 @@ disabled={$organization?.markedForDeletion} href={$upgradeURL} on:click={() => - trackEvent('click_organization_plan_update', { + trackEvent(Click.OrganizationClickUpgrade, { from: 'button', source: 'billing_tab' })}>