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} client - The Supabase client instance. */ export class TeamAccountsApi { constructor(private readonly client: SupabaseClient) {} /** * @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, 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) { return new TeamAccountsApi(client); }