Refactor billing services with new AccountsApi
The billing services have been refactored to use the new AccountsApi and TeamAccountsApi. All methods that were previously defined in each billing service, including getting customer ID, getting permissions, etc., have been transferred to these APIs. This change improves the modularity and organization of the code.
This commit is contained in:
@@ -12,7 +12,8 @@
|
||||
"./personal-account-dropdown": "./src/components/personal-account-dropdown.tsx",
|
||||
"./account-selector": "./src/components/account-selector.tsx",
|
||||
"./personal-account-settings": "./src/components/personal-account-settings/index.ts",
|
||||
"./hooks/*": "./src/hooks/*.ts"
|
||||
"./hooks/*": "./src/hooks/*.ts",
|
||||
"./api": "./src/server/api.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-table": "^8.16.0",
|
||||
|
||||
107
packages/features/accounts/src/server/api.ts
Normal file
107
packages/features/accounts/src/server/api.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
|
||||
/**
|
||||
* Class representing an API for interacting with user accounts.
|
||||
* @constructor
|
||||
* @param {SupabaseClient<Database>} client - The Supabase client instance.
|
||||
*/
|
||||
class AccountsApi {
|
||||
constructor(private readonly client: SupabaseClient<Database>) {}
|
||||
|
||||
async getAccountWorkspace() {
|
||||
const { data, error } = await this.client
|
||||
.from('user_account_workspace')
|
||||
.select(`*`)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async loadUserAccounts() {
|
||||
const { data: accounts, error } = await this.client
|
||||
.from('user_accounts')
|
||||
.select(`name, slug, picture_url`);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return accounts.map(({ name, slug, picture_url }) => {
|
||||
return {
|
||||
label: name,
|
||||
value: slug,
|
||||
image: picture_url,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getSubscriptionData
|
||||
* Get the subscription data for the given user.
|
||||
* @param accountId
|
||||
*/
|
||||
getSubscriptionData(accountId: string) {
|
||||
return this.client
|
||||
.from('subscriptions')
|
||||
.select('*, items: subscription_items !inner (*)')
|
||||
.eq('account_id', accountId)
|
||||
.maybeSingle()
|
||||
.then((response) => {
|
||||
if (response.error) {
|
||||
throw response.error;
|
||||
}
|
||||
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the orders data for the given account.
|
||||
* @param accountId
|
||||
*/
|
||||
getOrdersData(accountId: string) {
|
||||
return this.client
|
||||
.from('orders')
|
||||
.select('*, items: order_items !inner (*)')
|
||||
.eq('account_id', accountId)
|
||||
.maybeSingle()
|
||||
.then((response) => {
|
||||
if (response.error) {
|
||||
throw response.error;
|
||||
}
|
||||
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getBillingCustomerId
|
||||
* Get the billing customer ID for the given user.
|
||||
* If the user does not have a billing customer ID, it will return null.
|
||||
* @param accountId
|
||||
*/
|
||||
getBillingCustomerId(accountId: string) {
|
||||
return this.client
|
||||
.from('billing_customers')
|
||||
.select('customer_id')
|
||||
.eq('account_id', accountId)
|
||||
.maybeSingle()
|
||||
.then((response) => {
|
||||
if (response.error) {
|
||||
throw response.error;
|
||||
}
|
||||
|
||||
return response.data?.customer_id;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function createAccountsApi(client: SupabaseClient<Database>) {
|
||||
return new AccountsApi(client);
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"exports": {
|
||||
"./api": "./src/server/api.ts",
|
||||
"./components": "./src/components/index.ts",
|
||||
"./webhooks": "./src/server/services/webhooks/index.ts"
|
||||
},
|
||||
|
||||
142
packages/features/team-accounts/src/server/api.ts
Normal file
142
packages/features/team-accounts/src/server/api.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
|
||||
/**
|
||||
* Class representing an API for interacting with team accounts.
|
||||
* @constructor
|
||||
* @param {SupabaseClient<Database>} client - The Supabase client instance.
|
||||
*/
|
||||
export class TeamAccountsApi {
|
||||
constructor(private readonly client: SupabaseClient<Database>) {}
|
||||
|
||||
/**
|
||||
* @name getAccountWorkspace
|
||||
* @description Get the account workspace data.
|
||||
* @param slug
|
||||
*/
|
||||
async getAccountWorkspace(slug: string) {
|
||||
const accountPromise = this.client.rpc('team_account_workspace', {
|
||||
account_slug: slug,
|
||||
});
|
||||
|
||||
const accountsPromise = this.client.from('user_accounts').select('*');
|
||||
|
||||
const [
|
||||
accountResult,
|
||||
accountsResult,
|
||||
{
|
||||
data: { user },
|
||||
},
|
||||
] = await Promise.all([
|
||||
accountPromise,
|
||||
accountsPromise,
|
||||
this.client.auth.getUser(),
|
||||
]);
|
||||
|
||||
if (accountResult.error) {
|
||||
return {
|
||||
error: accountResult.error,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (accountsResult.error) {
|
||||
return {
|
||||
error: accountsResult.error,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return {
|
||||
error: new Error('User is not logged in'),
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
const accountData = accountResult.data[0];
|
||||
|
||||
if (!accountData) {
|
||||
return {
|
||||
error: new Error('Account data not found'),
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
account: accountData,
|
||||
accounts: accountsResult.data,
|
||||
user,
|
||||
},
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name hasPermission
|
||||
* @description Check if the user has permission to manage billing for the account.
|
||||
*/
|
||||
async hasPermission(params: {
|
||||
accountId: string;
|
||||
userId: string;
|
||||
permission: Database['public']['Enums']['app_permissions'];
|
||||
}) {
|
||||
const { data, error } = await this.client.rpc('has_permission', {
|
||||
account_id: params.accountId,
|
||||
user_id: params.userId,
|
||||
permission_name: params.permission,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getMembersCount
|
||||
* @description Get the number of members in the account.
|
||||
* @param accountId
|
||||
*/
|
||||
async getMembersCount(accountId: string) {
|
||||
const { count, error } = await this.client
|
||||
.from('accounts_memberships')
|
||||
.select('*', {
|
||||
head: true,
|
||||
count: 'exact',
|
||||
})
|
||||
.eq('account_id', accountId);
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name getCustomerId
|
||||
* @description Get the billing customer ID for the given account.
|
||||
* @param accountId
|
||||
*/
|
||||
async getCustomerId(accountId: string) {
|
||||
const { data, error } = await this.client
|
||||
.from('billing_customers')
|
||||
.select('customer_id')
|
||||
.eq('account_id', accountId)
|
||||
.maybeSingle();
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data?.customer_id;
|
||||
}
|
||||
}
|
||||
|
||||
export function createTeamAccountsApi(client: SupabaseClient<Database>) {
|
||||
return new TeamAccountsApi(client);
|
||||
}
|
||||
Reference in New Issue
Block a user