Refactored classes according to new convention

This commit is contained in:
giancarlo
2024-04-23 00:10:12 +08:00
parent 70da6ef1fa
commit 17e0781581
30 changed files with 351 additions and 131 deletions

View File

@@ -6,7 +6,7 @@ import { enhanceAction } from '@kit/next/actions';
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
import { PersonalAccountCheckoutSchema } from '../schema/personal-account-checkout.schema';
import { UserBillingService } from './user-billing.service';
import { createUserBillingService } from './user-billing.service';
/**
* @name createPersonalAccountCheckoutSession
@@ -14,7 +14,8 @@ import { UserBillingService } from './user-billing.service';
*/
export const createPersonalAccountCheckoutSession = enhanceAction(
async function (data) {
const service = new UserBillingService(getSupabaseServerActionClient());
const client = getSupabaseServerActionClient();
const service = createUserBillingService(client);
return await service.createCheckoutSession(data);
},
@@ -24,10 +25,14 @@ export const createPersonalAccountCheckoutSession = enhanceAction(
);
/**
* @name createPersonalAccountBillingPortalSession
* @description Creates a billing Portal session for a personal account
*/
export async function createPersonalAccountBillingPortalSession() {
const service = new UserBillingService(getSupabaseServerActionClient());
const client = getSupabaseServerActionClient();
const service = createUserBillingService(client);
// get url to billing portal
const url = await service.createBillingPortalSession();
return redirect(url);

View File

@@ -17,7 +17,15 @@ import { Database } from '~/lib/database.types';
import { PersonalAccountCheckoutSchema } from '../schema/personal-account-checkout.schema';
export class UserBillingService {
export function createUserBillingService(client: SupabaseClient<Database>) {
return new UserBillingService(client);
}
/**
* @name UserBillingService
* @description Service for managing billing for personal accounts.
*/
class UserBillingService {
private readonly namespace = 'billing.personal-account';
constructor(private readonly client: SupabaseClient<Database>) {}

View File

@@ -11,7 +11,7 @@ import {
TeamBillingPortalSchema,
TeamCheckoutSchema,
} from '../schema/team-billing.schema';
import { TeamBillingService } from './team-billing.service';
import { createTeamBillingService } from './team-billing.service';
/**
* @name createTeamAccountCheckoutSession
@@ -21,7 +21,9 @@ export async function createTeamAccountCheckoutSession(
params: z.infer<typeof TeamCheckoutSchema>,
) {
const data = TeamCheckoutSchema.parse(params);
const service = new TeamBillingService(getSupabaseServerActionClient());
const client = getSupabaseServerActionClient();
const service = createTeamBillingService(client);
return service.createCheckout(data);
}
@@ -33,7 +35,9 @@ export async function createTeamAccountCheckoutSession(
*/
export async function createBillingPortalSession(formData: FormData) {
const params = TeamBillingPortalSchema.parse(Object.fromEntries(formData));
const service = new TeamBillingService(getSupabaseServerActionClient());
const client = getSupabaseServerActionClient();
const service = createTeamBillingService(client);
// get url to billing portal
const url = await service.createBillingPortalSession(params);

View File

@@ -18,7 +18,15 @@ import { Database } from '~/lib/database.types';
import { TeamCheckoutSchema } from '../schema/team-billing.schema';
export class TeamBillingService {
export function createTeamBillingService(client: SupabaseClient<Database>) {
return new TeamBillingService(client);
}
/**
* @name TeamBillingService
* @description Service for managing billing for team accounts.
*/
class TeamBillingService {
private readonly namespace = 'billing.team-account';
constructor(private readonly client: SupabaseClient<Database>) {}

View File

@@ -0,0 +1,91 @@
import 'server-only';
import { SupabaseClient } from '@supabase/supabase-js';
import { Database } from '~/lib/database.types';
import { loadTeamWorkspace } from '../../../_lib/server/team-account-workspace.loader';
/**
* Load data for the members page
* @param client
* @param slug
*/
export async function loadMembersPageData(
client: SupabaseClient<Database>,
slug: string,
) {
return Promise.all([
loadTeamWorkspace(slug),
loadAccountMembers(client, slug),
loadInvitations(client, slug),
loadUser(client),
canAddMember,
]);
}
/**
* @name canAddMember
* @description Check if the current user can add a member to the account
*
* This needs additional logic to determine if the user can add a member to the account
* Please implement the logic and return a boolean value
*
* The same check needs to be added when creating an invitation
*
*/
async function canAddMember() {
return Promise.resolve(true);
}
async function loadUser(client: SupabaseClient<Database>) {
const { data, error } = await client.auth.getUser();
if (error) {
throw error;
}
return data.user;
}
/**
* Load account members
* @param client
* @param account
*/
async function loadAccountMembers(
client: SupabaseClient<Database>,
account: string,
) {
const { data, error } = await client.rpc('get_account_members', {
account_slug: account,
});
if (error) {
console.error(error);
throw error;
}
return data ?? [];
}
/**
* Load account invitations
* @param client
* @param account
*/
async function loadInvitations(
client: SupabaseClient<Database>,
account: string,
) {
const { data, error } = await client.rpc('get_account_invitations', {
account_slug: account,
});
if (error) {
console.error(error);
throw error;
}
return data ?? [];
}

View File

@@ -1,5 +1,3 @@
import { SupabaseClient } from '@supabase/supabase-js';
import { PlusCircle } from 'lucide-react';
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
@@ -20,12 +18,11 @@ import { If } from '@kit/ui/if';
import { PageBody } from '@kit/ui/page';
import { Trans } from '@kit/ui/trans';
import { Database } from '~/lib/database.types';
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
import { withI18n } from '~/lib/i18n/with-i18n';
import { AccountLayoutHeader } from '../_components/account-layout-header';
import { loadTeamWorkspace } from '../_lib/server/team-account-workspace.loader';
import { loadMembersPageData } from './_lib/server/members-page.loader';
interface Params {
params: {
@@ -33,57 +30,6 @@ interface Params {
};
}
async function loadUser(client: SupabaseClient<Database>) {
const { data, error } = await client.auth.getUser();
if (error) {
throw error;
}
return data.user;
}
async function loadAccountMembers(
client: SupabaseClient<Database>,
account: string,
) {
const { data, error } = await client.rpc('get_account_members', {
account_slug: account,
});
if (error) {
console.error(error);
throw error;
}
return data ?? [];
}
async function loadInvitations(
client: SupabaseClient<Database>,
account: string,
) {
const { data, error } = await client.rpc('get_account_invitations', {
account_slug: account,
});
if (error) {
console.error(error);
throw error;
}
return data ?? [];
}
async function loadData(client: SupabaseClient<Database>, slug: string) {
return Promise.all([
loadTeamWorkspace(slug),
loadAccountMembers(client, slug),
loadInvitations(client, slug),
loadUser(client),
]);
}
export const generateMetadata = async () => {
const i18n = await createI18nServerInstance();
const title = i18n.t('teams:members.pageTitle');
@@ -96,10 +42,8 @@ export const generateMetadata = async () => {
async function TeamAccountMembersPage({ params }: Params) {
const client = getSupabaseServerComponentClient();
const [{ account }, members, invitations, user] = await loadData(
client,
params.account,
);
const [{ account }, members, invitations, user, canAddMember] =
await loadMembersPageData(client, params.account);
const canManageRoles = account.permissions.includes('roles.manage');
const canManageInvitations = account.permissions.includes('invites.manage');
@@ -131,7 +75,7 @@ async function TeamAccountMembersPage({ params }: Params) {
</CardDescription>
</div>
<If condition={canManageInvitations}>
<If condition={canManageInvitations && canAddMember}>
<InviteMembersDialogContainer
userRoleHierarchy={currentUserRoleHierarchy}
accountId={account.id}