Files
medreport_mrb2b/packages/features/team-accounts/src/server/api.ts
Helena b4b75438d2 Fix: add application_role to account-related fields (#48)
* Fix: fix accounts view, menu

* add migration

* add application_role to account-related fields
2025-08-14 11:40:53 +03:00

318 lines
6.9 KiB
TypeScript

import { SupabaseClient } from '@supabase/supabase-js';
import { Database } from '@kit/supabase/database';
import { UpdateHealthBenefitData } from './types';
/**
* 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 getTeamAccount
* @description Get the account data for the given slug.
* @param slug
*/
async getTeamAccount(slug: string) {
const { data, error } = await this.client
.schema('medreport')
.from('accounts')
.select('*')
.eq('slug', slug)
.single();
if (error) {
throw error;
}
return data;
}
/**
* @name getTeamAccountById
* @description Check if the user is already in the account.
* @param accountId
*/
async getTeamAccountById(accountId: string) {
const { data, error } = await this.client
.schema('medreport')
.from('accounts')
.select('*')
.eq('id', accountId)
.single();
if (error) {
throw error;
}
return data;
}
/**
* @name getSubscription
* @description Get the subscription data for the account.
* @param accountId
*/
async getSubscription(accountId: string) {
const { data, error } = await this.client
.schema('medreport')
.from('subscriptions')
.select('*, items: subscription_items !inner (*)')
.eq('account_id', accountId)
.maybeSingle();
if (error) {
throw error;
}
return data;
}
/**
* Get the orders data for the given account.
* @param accountId
*/
async getOrder(accountId: string) {
const response = await this.client
.schema('medreport')
.from('orders')
.select('*, items: order_items !inner (*)')
.eq('account_id', accountId)
.maybeSingle();
if (response.error) {
throw response.error;
}
return response.data;
}
/**
* @name getAccountWorkspace
* @description Get the account workspace data.
* @param slug
*/
async getAccountWorkspace(slug: string, userId: string) {
const accountPromise = this.client
.schema('medreport')
.rpc('team_account_workspace', {
account_slug: slug,
});
const accountsPromise = this.client
.schema('medreport')
.from('accounts_memberships')
.select(
`
account_id,
user_accounts (
id,
role,
name,
slug,
picture_url,
application_role
)
`,
)
.eq('user_id', userId)
.eq('account_role', 'owner');
const [accountResult, accountsResult] = await Promise.all([
accountPromise,
accountsPromise,
]);
if (accountResult.error) {
return {
error: accountResult.error,
data: null,
};
}
if (accountsResult.error) {
return {
error: accountsResult.error,
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,
},
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['medreport']['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
.schema('medreport')
.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
.schema('medreport')
.from('billing_customers')
.select('customer_id')
.eq('account_id', accountId)
.maybeSingle();
if (error) {
throw error;
}
return data?.customer_id;
}
/**
* @name getInvitation
* @description Get the invitation data from the invite token.
* @param adminClient - The admin client instance. Since the user is not yet part of the account, we need to use an admin client to read the pending membership
* @param token - The invitation token.
*/
async getInvitation(adminClient: SupabaseClient<Database>, token: string) {
const { data: invitation, error } = await adminClient
.schema('medreport')
.from('invitations')
.select<
string,
{
id: string;
account: {
id: string;
name: string;
slug: string;
picture_url: string;
};
}
>(
'id, expires_at, account: account_id !inner (id, name, slug, picture_url)',
)
.eq('invite_token', token)
.gte('expires_at', new Date().toISOString())
.single();
if (error ?? !invitation) {
return null;
}
return invitation;
}
/**
* @name updateHealthBenefit
* @description Update health benefits for the team account
*/
async updateHealthBenefit(data: UpdateHealthBenefitData) {
const { error } = await this.client
.schema('medreport')
.from('company_params')
.update({
benefit_occurance: data.occurance,
benefit_amount: data.amount,
updated_at: new Date().toISOString(),
})
.eq('account_id', data.accountId);
if (error) {
throw error;
}
}
/**
* @name getTeamAccountParams
* @description Get health benefits for the team account
*/
async getTeamAccountParams(accountId: string) {
const { data, error } = await this.client
.schema('medreport')
.from('company_params')
.select('*')
.eq('account_id', accountId)
.single();
if (error) {
throw error;
}
return data;
}
async getMembers(accountSlug: string) {
const members = await this.client
.schema('medreport')
.rpc('get_account_members', {
account_slug: accountSlug,
});
if (members.error) {
throw members.error;
}
return members.data;
}
}
export function createTeamAccountsApi(client: SupabaseClient<Database>) {
return new TeamAccountsApi(client);
}