mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #1048 from appwrite/feat-add-members-usage-page
Feat: add members count to usage page
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { tierToPlan } from '$lib/stores/billing';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import ChangeOrganizationTierCloud from '$routes/console/changeOrganizationTierCloud.svelte';
|
||||
import { Card } from '..';
|
||||
|
||||
export let service: string;
|
||||
export let eventSource: string;
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<slot>
|
||||
<div class="u-flex u-flex-vertical u-main-center u-cross-center u-gap-8">
|
||||
<h6 class="body-text-1 u-bold u-trim-1">Upgrade to add {service}</h6>
|
||||
<p class="text u-text-center">
|
||||
Upgrade to a {tierToPlan(BillingPlan.PRO).name} plan to add {service} to your organization
|
||||
</p>
|
||||
|
||||
<Button
|
||||
class="u-margin-block-start-16"
|
||||
secondary
|
||||
fullWidthMobile
|
||||
on:click={() => {
|
||||
trackEvent('click_organization_upgrade', {
|
||||
from: 'button',
|
||||
source: eventSource
|
||||
});
|
||||
wizard.start(ChangeOrganizationTierCloud);
|
||||
}}>
|
||||
Upgrade
|
||||
</Button>
|
||||
</div>
|
||||
</slot>
|
||||
</Card>
|
||||
@@ -1,2 +1,3 @@
|
||||
export { default as PaymentBoxes } from './paymentBoxes.svelte';
|
||||
export { default as CouponInput } from './couponInput.svelte';
|
||||
export { default as EmptyCardCloud } from './emptyCardCloud.svelte';
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
export let items = [];
|
||||
export let limit = 5;
|
||||
export let hideFooter = false;
|
||||
|
||||
let offset = 0;
|
||||
|
||||
@@ -10,9 +11,11 @@
|
||||
$: paginatedItems = items.slice(offset, offset + limit);
|
||||
</script>
|
||||
|
||||
<slot {paginatedItems} />
|
||||
<slot {paginatedItems} {limit} />
|
||||
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {total}</p>
|
||||
<PaginationInline {limit} bind:offset sum={total} hidePages />
|
||||
</div>
|
||||
{#if !hideFooter}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {total}</p>
|
||||
<PaginationInline {limit} bind:offset sum={total} hidePages />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import TotalMembers from './totalMembers.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -298,6 +299,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
<TotalMembers members={data?.organizationMembers} />
|
||||
|
||||
<p class="text common-section u-color-text-gray">
|
||||
Metrics are estimates updated every 24 hours and may not accurately reflect your invoice.
|
||||
|
||||
@@ -36,9 +36,10 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
endDate = currentInvoice.to;
|
||||
}
|
||||
|
||||
const [invoices, usage] = await Promise.all([
|
||||
const [invoices, usage, organizationMembers] = await Promise.all([
|
||||
sdk.forConsole.billing.listInvoices(org.$id, [Query.orderDesc('from')]),
|
||||
sdk.forConsole.billing.listUsage(params.organization, startDate, endDate)
|
||||
sdk.forConsole.billing.listUsage(params.organization, startDate, endDate),
|
||||
sdk.forConsole.teams.listMemberships(params.organization)
|
||||
]);
|
||||
|
||||
const queries: string[] = [];
|
||||
@@ -58,6 +59,7 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
organizationUsage: usage,
|
||||
projectNames: projectNames.projects,
|
||||
invoices,
|
||||
currentInvoice
|
||||
currentInvoice,
|
||||
organizationMembers
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<script lang="ts">
|
||||
import { tooltip } from '$lib/actions/tooltip';
|
||||
import { AvatarInitials, CardGrid, Heading, Paginator } from '$lib/components';
|
||||
import { EmptyCardCloud } from '$lib/components/billing';
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import {
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableCellHead,
|
||||
TableCellText,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableScroll
|
||||
} from '$lib/elements/table';
|
||||
import { toLocaleDate } from '$lib/helpers/date';
|
||||
import { formatCurrency } from '$lib/helpers/numbers';
|
||||
import { plansInfo, tierToPlan } from '$lib/stores/billing';
|
||||
import { newMemberModal, organization } from '$lib/stores/organization';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
|
||||
export let members: Models.MembershipList;
|
||||
|
||||
$: total = members?.total ?? 0;
|
||||
$: plan = $plansInfo?.get($organization?.billingPlan);
|
||||
</script>
|
||||
|
||||
<CardGrid>
|
||||
<Heading tag="h6" size="7">Members</Heading>
|
||||
|
||||
<p class="text">The number of members in your organization.</p>
|
||||
<svelte:fragment slot="aside">
|
||||
{#if $organization.billingPlan !== BillingPlan.STARTER}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
<span class="heading-level-4">{total}</span>
|
||||
<span class="body-text-1 u-bold">Members</span>
|
||||
</p>
|
||||
<Button secondary on:click={() => newMemberModal.set(true)}>
|
||||
<span class="icon-plus"></span> <span class="text">Invite</span>
|
||||
</Button>
|
||||
</div>
|
||||
<p class="body-text-2">
|
||||
Unlimited
|
||||
<span
|
||||
class="icon-info"
|
||||
use:tooltip={{
|
||||
content: `You can add unlimited organization members on the ${tierToPlan($organization.billingPlan).name} plan for ${formatCurrency(plan.addons.member.price)} each per billing period.`
|
||||
}}></span>
|
||||
</p>
|
||||
</div>
|
||||
<Paginator
|
||||
items={members.memberships}
|
||||
let:paginatedItems
|
||||
hideFooter={members?.total <= 5}>
|
||||
<TableScroll noMargin noStyles>
|
||||
<TableHeader>
|
||||
<TableCellHead>Members</TableCellHead>
|
||||
<TableCellHead>Joined</TableCellHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each paginatedItems as member}
|
||||
<TableRow>
|
||||
<TableCell title="name">
|
||||
<div class="u-flex u-gap-12 u-cross-center">
|
||||
<AvatarInitials size={32} name={member.userName} />
|
||||
<span class="text u-trim">
|
||||
{member.userName ? member.userName : member.userEmail}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCellText title="joined">
|
||||
{member.joined
|
||||
? toLocaleDate(member.joined)
|
||||
: toLocaleDate(member.$createdAt)}
|
||||
</TableCellText>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</TableScroll>
|
||||
</Paginator>
|
||||
{:else}
|
||||
<EmptyCardCloud service="members" eventSource="organization_usage" />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
Reference in New Issue
Block a user