From 251f2a4ef10a6d5c725877ad1b8056e104246523 Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 22 Jun 2025 15:22:07 +0300 Subject: [PATCH 1/7] B2B-30: adds personal code to account, company admins invites members --- .env | 2 + app/admin/accounts/page.tsx | 2 +- .../_components/home-menu-navigation.tsx | 32 +- .../(user)/_lib/server/load-user-workspace.ts | 7 +- app/home/(user)/page.tsx | 12 +- app/home/[account]/layout.tsx | 4 +- app/home/[account]/page.tsx | 3 +- app/join/page.tsx | 5 +- lib/database.types.ts | 2635 +++++++++-------- package.json | 2 +- .../components/personal-account-dropdown.tsx | 8 +- packages/features/accounts/src/server/api.ts | 52 +- .../src/components/admin-account-page.tsx | 10 +- .../src/components/admin-accounts-table.tsx | 8 + .../components/admin-create-user-dialog.tsx | 22 +- .../src/components/admin-members-table.tsx | 2 +- .../src/lib/server/admin-server-actions.ts | 12 +- .../schema/create-user-profile.schema.ts | 10 + .../lib/server/schema/create-user.schema.ts | 3 + .../src/components/password-sign-up-form.tsx | 25 + .../components/sign-up-methods-container.tsx | 2 + .../auth/src/hooks/use-sign-up-flow.ts | 2 +- .../src/schemas/password-sign-up.schema.ts | 3 + packages/features/team-accounts/package.json | 1 + .../src/components/company-guard.tsx | 32 + .../team-accounts/src/components/index.ts | 1 + .../invitations/account-invitations-table.tsx | 8 + .../members/account-members-table.tsx | 10 +- .../invite-members-dialog-container.tsx | 32 +- packages/features/team-accounts/src/index.ts | 1 + .../src/schema/invite-members.schema.ts | 3 + .../team-invitations-server-actions.ts | 47 +- .../src/server/utils/is-company-admin.ts | 24 + packages/supabase/src/database.types.ts | 2635 +++++++++-------- .../hooks/use-sign-up-with-email-password.ts | 9 +- public/locales/en/billing.json | 8 +- public/locales/en/common.json | 10 +- public/locales/en/teams.json | 63 +- public/locales/et/billing.json | 8 +- public/locales/et/common.json | 10 +- public/locales/et/marketing.json | 2 +- public/locales/et/teams.json | 63 +- public/locales/ru/billing.json | 8 +- public/locales/ru/common.json | 10 +- public/locales/ru/teams.json | 63 +- ...618163951_alter_accounts_personal_code.sql | 5 + ...70525_add_personal_code_to_invitations.sql | 146 + .../20250620191934_is_company_admin.sql | 22 + ...rsonal_code_to_account_on_email_signup.sql | 53 + ...d_rpc_get_invitations_with_account_ids.sql | 20 + 50 files changed, 3546 insertions(+), 2611 deletions(-) create mode 100644 packages/features/admin/src/lib/server/schema/create-user-profile.schema.ts create mode 100644 packages/features/team-accounts/src/components/company-guard.tsx create mode 100644 packages/features/team-accounts/src/index.ts create mode 100644 packages/features/team-accounts/src/server/utils/is-company-admin.ts create mode 100644 supabase/migrations/20250618163951_alter_accounts_personal_code.sql create mode 100644 supabase/migrations/20250619170525_add_personal_code_to_invitations.sql create mode 100644 supabase/migrations/20250620191934_is_company_admin.sql create mode 100644 supabase/migrations/20250621195718_add_personal_code_to_account_on_email_signup.sql create mode 100644 supabase/migrations/20250622115016_add_rpc_get_invitations_with_account_ids.sql diff --git a/.env b/.env index 164e333..f279691 100644 --- a/.env +++ b/.env @@ -40,6 +40,8 @@ NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS=true NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true NEXT_PUBLIC_LANGUAGE_PRIORITY=application NEXT_PUBLIC_ENABLE_NOTIFICATIONS=true +NEXT_PUBLIC_REALTIME_NOTIFICATIONS=true + # NEXTJS NEXT_TELEMETRY_DISABLED=1 diff --git a/app/admin/accounts/page.tsx b/app/admin/accounts/page.tsx index 21c1104..688987f 100644 --- a/app/admin/accounts/page.tsx +++ b/app/admin/accounts/page.tsx @@ -55,7 +55,7 @@ async function AccountsPage(props: AdminAccountsPageProps) { } if (query) { - queryBuilder.or(`name.ilike.%${query}%,email.ilike.%${query}%`); + queryBuilder.or(`name.ilike.%${query}%,email.ilike.%${query}%,personal_code.ilike.%${query}%`); } return queryBuilder; diff --git a/app/home/(user)/_components/home-menu-navigation.tsx b/app/home/(user)/_components/home-menu-navigation.tsx index d91e498..bb53b77 100644 --- a/app/home/(user)/_components/home-menu-navigation.tsx +++ b/app/home/(user)/_components/home-menu-navigation.tsx @@ -1,13 +1,9 @@ -import { - BorderedNavigationMenu, - BorderedNavigationMenuItem, -} from '@kit/ui/bordered-navigation-menu'; + import { If } from '@kit/ui/if'; import { AppLogo } from '~/components/app-logo'; import { ProfileAccountDropdownContainer } from '~/components/personal-account-dropdown-container'; import featuresFlagConfig from '~/config/feature-flags.config'; -import { personalAccountNavigationConfig } from '~/config/personal-account-navigation.config'; // home imports import { HomeAccountSelector } from '../_components/home-account-selector'; @@ -17,41 +13,17 @@ import { type UserWorkspace } from '../_lib/server/load-user-workspace'; export function HomeMenuNavigation(props: { workspace: UserWorkspace }) { const { workspace, user, accounts } = props.workspace; - const routes = personalAccountNavigationConfig.routes.reduce< - Array<{ - path: string; - label: string; - Icon?: React.ReactNode; - end?: boolean | ((path: string) => boolean); - }> - >((acc, item) => { - if ('children' in item) { - return [...acc, ...item.children]; - } - - if ('divider' in item) { - return acc; - } - - return [...acc, item]; - }, []); - return (
- - {routes.map((route) => ( - - ))} -
- + diff --git a/app/home/(user)/_lib/server/load-user-workspace.ts b/app/home/(user)/_lib/server/load-user-workspace.ts index b48e37d..2a9db62 100644 --- a/app/home/(user)/_lib/server/load-user-workspace.ts +++ b/app/home/(user)/_lib/server/load-user-workspace.ts @@ -28,15 +28,20 @@ async function workspaceLoader() { const workspacePromise = api.getAccountWorkspace(); - const [accounts, workspace, user] = await Promise.all([ + // TODO!: remove before deploy to prod + const tempAccountsPromise = () => api.loadTempUserAccounts(); + + const [accounts, workspace, user, tempVisibleAccounts] = await Promise.all([ accountsPromise(), workspacePromise, requireUserInServerComponent(), + tempAccountsPromise() ]); return { accounts, workspace, user, + tempVisibleAccounts }; } diff --git a/app/home/(user)/page.tsx b/app/home/(user)/page.tsx index 3327e1f..9015e90 100644 --- a/app/home/(user)/page.tsx +++ b/app/home/(user)/page.tsx @@ -1,4 +1,3 @@ -import { PageBody } from '@kit/ui/page'; import { Trans } from '@kit/ui/trans'; import { createI18nServerInstance } from '~/lib/i18n/i18n.server'; @@ -6,6 +5,8 @@ import { withI18n } from '~/lib/i18n/with-i18n'; // local imports import { HomeLayoutPageHeader } from './_components/home-page-header'; +import { use } from 'react'; +import { loadUserWorkspace } from './_lib/server/load-user-workspace'; export const generateMetadata = async () => { const i18n = await createI18nServerInstance(); @@ -17,14 +18,21 @@ export const generateMetadata = async () => { }; function UserHomePage() { + const { tempVisibleAccounts } = use(loadUserWorkspace()); return ( <> } description={} /> + {tempVisibleAccounts.length && ( + <> + Member of companies: +
{JSON.stringify(tempVisibleAccounts, null, 2)}
+ + )} + - ); } diff --git a/app/home/[account]/layout.tsx b/app/home/[account]/layout.tsx index ffefb5f..f4ffec6 100644 --- a/app/home/[account]/layout.tsx +++ b/app/home/[account]/layout.tsx @@ -4,7 +4,7 @@ import { cookies } from 'next/headers'; import { z } from 'zod'; -import { TeamAccountWorkspaceContextProvider } from '@kit/team-accounts/components'; +import { CompanyGuard, TeamAccountWorkspaceContextProvider } from '@kit/team-accounts/components'; import { Page, PageMobileNavigation, PageNavigation } from '@kit/ui/page'; import { SidebarProvider } from '@kit/ui/shadcn-sidebar'; @@ -144,4 +144,4 @@ async function getLayoutState(account: string) { }; } -export default withI18n(TeamWorkspaceLayout); +export default withI18n(CompanyGuard(TeamWorkspaceLayout)); diff --git a/app/home/[account]/page.tsx b/app/home/[account]/page.tsx index 982f21a..4684ea3 100644 --- a/app/home/[account]/page.tsx +++ b/app/home/[account]/page.tsx @@ -9,6 +9,7 @@ import { withI18n } from '~/lib/i18n/with-i18n'; import { DashboardDemo } from './_components/dashboard-demo'; import { TeamAccountLayoutPageHeader } from './_components/team-account-layout-page-header'; +import { CompanyGuard } from '@/packages/features/team-accounts/src/components'; interface TeamAccountHomePageProps { params: Promise<{ account: string }>; @@ -41,4 +42,4 @@ function TeamAccountHomePage({ params }: TeamAccountHomePageProps) { ); } -export default withI18n(TeamAccountHomePage); +export default withI18n(CompanyGuard(TeamAccountHomePage)); diff --git a/app/join/page.tsx b/app/join/page.tsx index 6fa5c77..ffe4674 100644 --- a/app/join/page.tsx +++ b/app/join/page.tsx @@ -109,10 +109,7 @@ async function JoinTeamAccountPage(props: JoinTeamAccountPageProps) { const signOutNext = `${pathsConfig.auth.signIn}?invite_token=${token}`; // once the user accepts the invitation, we redirect them to the account home page - const accountHome = pathsConfig.app.accountHome.replace( - '[account]', - invitation.account.slug, - ); + const accountHome = pathsConfig.app.home; const email = auth.data.email ?? ''; diff --git a/lib/database.types.ts b/lib/database.types.ts index 452ae7b..96430a7 100644 --- a/lib/database.types.ts +++ b/lib/database.types.ts @@ -4,1439 +4,1652 @@ export type Json = | boolean | null | { [key: string]: Json | undefined } - | Json[]; + | Json[] export type Database = { + audit: { + Tables: { + log_entries: { + Row: { + changed_at: string + changed_by: string | null + changed_by_role: string | null + changed_data: Json | null + id: number + operation: string + record_key: number | null + row_data: Json | null + schema_name: string + table_name: string + } + Insert: { + changed_at?: string + changed_by?: string | null + changed_by_role?: string | null + changed_data?: Json | null + id?: number + operation: string + record_key?: number | null + row_data?: Json | null + schema_name: string + table_name: string + } + Update: { + changed_at?: string + changed_by?: string | null + changed_by_role?: string | null + changed_data?: Json | null + id?: number + operation?: string + record_key?: number | null + row_data?: Json | null + schema_name?: string + table_name?: string + } + Relationships: [] + } + sync_entries: { + Row: { + changed_by_role: string + comment: string | null + created_at: string + id: number + operation: string + status: string + } + Insert: { + changed_by_role: string + comment?: string | null + created_at?: string + id?: number + operation: string + status: string + } + Update: { + changed_by_role?: string + comment?: string | null + created_at?: string + id?: number + operation?: string + status?: string + } + Relationships: [] + } + } + Views: { + [_ in never]: never + } + Functions: { + [_ in never]: never + } + Enums: { + sync_status: "SUCCESS" | "FAIL" + } + CompositeTypes: { + [_ in never]: never + } + } graphql_public: { Tables: { - [_ in never]: never; - }; + [_ in never]: never + } Views: { - [_ in never]: never; - }; + [_ in never]: never + } Functions: { graphql: { Args: { - operationName?: string; - query?: string; - variables?: Json; - extensions?: Json; - }; - Returns: Json; - }; - }; + operationName?: string + query?: string + variables?: Json + extensions?: Json + } + Returns: Json + } + } Enums: { - [_ in never]: never; - }; + [_ in never]: never + } CompositeTypes: { - [_ in never]: never; - }; - }; + [_ in never]: never + } + } public: { Tables: { accounts: { Row: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + personal_code: string | null + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } Insert: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name: string + personal_code?: string | null + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } Update: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name?: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; - Relationships: []; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name?: string + personal_code?: string | null + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } + Relationships: [] + } accounts_memberships: { Row: { - account_id: string; - account_role: string; - created_at: string; - created_by: string | null; - updated_at: string; - updated_by: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at: string + created_by: string | null + updated_at: string + updated_by: string | null + user_id: string + } Insert: { - account_id: string; - account_role: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id: string + } Update: { - account_id?: string; - account_role?: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id?: string; - }; + account_id?: string + account_role?: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id?: string + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['account_role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["account_role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] + }, + ] + } + analyses: { + Row: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab: string | null + created_at: string + id: number + order: number + parent_analysis_element_id: number + tehik_loinc_name: string | null + tehik_short_loinc: string | null + updated_at: string | null + } + Insert: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab?: string | null + created_at?: string + id?: number + order: number + parent_analysis_element_id: number + tehik_loinc_name?: string | null + tehik_short_loinc?: string | null + updated_at?: string | null + } + Update: { + analysis_id_oid?: string + analysis_id_original?: string + analysis_name_lab?: string | null + created_at?: string + id?: number + order?: number + parent_analysis_element_id?: number + tehik_loinc_name?: string | null + tehik_short_loinc?: string | null + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analyses_parent_analysis_element_id_fkey" + columns: ["parent_analysis_element_id"] + isOneToOne: false + referencedRelation: "analysis_elements" + referencedColumns: ["id"] + }, + ] + } + analysis_elements: { + Row: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab: string | null + created_at: string + id: number + material_groups: Json[] | null + order: number + parent_analysis_group_id: number + tehik_loinc_name: string + tehik_short_loinc: string + updated_at: string | null + } + Insert: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab?: string | null + created_at?: string + id?: number + material_groups?: Json[] | null + order: number + parent_analysis_group_id: number + tehik_loinc_name: string + tehik_short_loinc: string + updated_at?: string | null + } + Update: { + analysis_id_oid?: string + analysis_id_original?: string + analysis_name_lab?: string | null + created_at?: string + id?: number + material_groups?: Json[] | null + order?: number + parent_analysis_group_id?: number + tehik_loinc_name?: string + tehik_short_loinc?: string + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analysis_elements_parent_analysis_group_id_fkey" + columns: ["parent_analysis_group_id"] + isOneToOne: false + referencedRelation: "analysis_groups" + referencedColumns: ["id"] + }, + ] + } + analysis_groups: { + Row: { + created_at: string + id: number + name: string + order: number + original_id: string + updated_at: string | null + } + Insert: { + created_at?: string + id?: number + name: string + order: number + original_id: string + updated_at?: string | null + } + Update: { + created_at?: string + id?: number + name?: string + order?: number + original_id?: string + updated_at?: string | null + } + Relationships: [] + } + analysis_orders: { + Row: { + analysis_element_ids: number[] | null + analysis_ids: number[] | null + created_at: string + id: number + status: Database["public"]["Enums"]["analysis_order_status"] + user_id: string + } + Insert: { + analysis_element_ids?: number[] | null + analysis_ids?: number[] | null + created_at?: string + id?: number + status: Database["public"]["Enums"]["analysis_order_status"] + user_id: string + } + Update: { + analysis_element_ids?: number[] | null + analysis_ids?: number[] | null + created_at?: string + id?: number + status?: Database["public"]["Enums"]["analysis_order_status"] + user_id?: string + } + Relationships: [] + } + analysis_response_elements: { + Row: { + analysis_element_original_id: string + analysis_response_id: number + created_at: string + id: number + norm_lower: number | null + norm_lower_included: boolean | null + norm_status: number | null + norm_upper: number | null + norm_upper_included: boolean | null + original_response_element: Json + response_time: string + response_value: Json + unit: string | null + updated_at: string | null + } + Insert: { + analysis_element_original_id: string + analysis_response_id: number + created_at?: string + id?: number + norm_lower?: number | null + norm_lower_included?: boolean | null + norm_status?: number | null + norm_upper?: number | null + norm_upper_included?: boolean | null + original_response_element: Json + response_time: string + response_value: Json + unit?: string | null + updated_at?: string | null + } + Update: { + analysis_element_original_id?: string + analysis_response_id?: number + created_at?: string + id?: number + norm_lower?: number | null + norm_lower_included?: boolean | null + norm_status?: number | null + norm_upper?: number | null + norm_upper_included?: boolean | null + original_response_element?: Json + response_time?: string + response_value?: Json + unit?: string | null + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analysis_response_element_analysis_response_id_fkey" + columns: ["analysis_response_id"] + isOneToOne: false + referencedRelation: "analysis_responses" + referencedColumns: ["id"] + }, + ] + } + analysis_responses: { + Row: { + analysis_order_id: number + created_at: string + id: number + order_number: string + order_status: Database["public"]["Enums"]["analysis_order_status"] + updated_at: string | null + user_id: string + } + Insert: { + analysis_order_id: number + created_at?: string + id?: number + order_number: string + order_status: Database["public"]["Enums"]["analysis_order_status"] + updated_at?: string | null + user_id: string + } + Update: { + analysis_order_id?: number + created_at?: string + id?: number + order_number?: string + order_status?: Database["public"]["Enums"]["analysis_order_status"] + updated_at?: string | null + user_id?: string + } + Relationships: [ + { + foreignKeyName: "analysis_responses_analysis_order_id_fkey" + columns: ["analysis_order_id"] + isOneToOne: false + referencedRelation: "analysis_orders" + referencedColumns: ["id"] + }, + ] + } billing_customers: { Row: { - account_id: string; - customer_id: string; - email: string | null; - id: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email: string | null + id: number + provider: Database["public"]["Enums"]["billing_provider"] + } Insert: { - account_id: string; - customer_id: string; - email?: string | null; - id?: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email?: string | null + id?: number + provider: Database["public"]["Enums"]["billing_provider"] + } Update: { - account_id?: string; - customer_id?: string; - email?: string | null; - id?: number; - provider?: Database['public']['Enums']['billing_provider']; - }; + account_id?: string + customer_id?: string + email?: string | null + id?: number + provider?: Database["public"]["Enums"]["billing_provider"] + } Relationships: [ { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, - ]; - }; + { + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] + }, + { + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + ] + } + codes: { + Row: { + analysis_element_id: number | null + analysis_group_id: number | null + analysis_id: number | null + coefficient: number + created_at: string + hk_code: string + hk_code_multiplier: number + id: number + price: number + updated_at: string | null + } + Insert: { + analysis_element_id?: number | null + analysis_group_id?: number | null + analysis_id?: number | null + coefficient: number + created_at?: string + hk_code: string + hk_code_multiplier: number + id?: number + price: number + updated_at?: string | null + } + Update: { + analysis_element_id?: number | null + analysis_group_id?: number | null + analysis_id?: number | null + coefficient?: number + created_at?: string + hk_code?: string + hk_code_multiplier?: number + id?: number + price?: number + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "codes_analysis_element_id_fkey" + columns: ["analysis_element_id"] + isOneToOne: false + referencedRelation: "analysis_elements" + referencedColumns: ["id"] + }, + { + foreignKeyName: "codes_analysis_group_id_fkey" + columns: ["analysis_group_id"] + isOneToOne: false + referencedRelation: "analysis_groups" + referencedColumns: ["id"] + }, + { + foreignKeyName: "codes_analysis_id_fkey" + columns: ["analysis_id"] + isOneToOne: false + referencedRelation: "analyses" + referencedColumns: ["id"] + }, + ] + } config: { Row: { - billing_provider: Database['public']['Enums']['billing_provider']; - enable_account_billing: boolean; - enable_team_account_billing: boolean; - enable_team_accounts: boolean; - }; + billing_provider: Database["public"]["Enums"]["billing_provider"] + enable_account_billing: boolean + enable_team_account_billing: boolean + enable_team_accounts: boolean + } Insert: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } Update: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; - Relationships: []; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } + Relationships: [] + } invitations: { Row: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + personal_code: string | null + role: string + updated_at: string + } Insert: { - account_id: string; - created_at?: string; - email: string; - expires_at?: string; - id?: number; - invite_token: string; - invited_by: string; - role: string; - updated_at?: string; - }; + account_id: string + created_at?: string + email: string + expires_at?: string + id?: number + invite_token: string + invited_by: string + personal_code?: string | null + role: string + updated_at?: string + } Update: { - account_id?: string; - created_at?: string; - email?: string; - expires_at?: string; - id?: number; - invite_token?: string; - invited_by?: string; - role?: string; - updated_at?: string; - }; + account_id?: string + created_at?: string + email?: string + expires_at?: string + id?: number + invite_token?: string + invited_by?: string + personal_code?: string | null + role?: string + updated_at?: string + } Relationships: [ { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'invitations_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "invitations_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] + }, + ] + } nonces: { Row: { - client_token: string; - created_at: string; - description: string | null; - expires_at: string; - id: string; - last_verification_at: string | null; - last_verification_ip: unknown | null; - last_verification_user_agent: string | null; - metadata: Json | null; - nonce: string; - purpose: string; - revoked: boolean; - revoked_reason: string | null; - scopes: string[] | null; - tags: string[] | null; - used_at: string | null; - user_id: string | null; - verification_attempts: number; - }; + client_token: string + created_at: string + expires_at: string + id: string + last_verification_at: string | null + last_verification_ip: unknown | null + last_verification_user_agent: string | null + metadata: Json | null + nonce: string + purpose: string + revoked: boolean + revoked_reason: string | null + scopes: string[] | null + used_at: string | null + user_id: string | null + verification_attempts: number + } Insert: { - client_token: string; - created_at?: string; - description?: string | null; - expires_at: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce: string; - purpose: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; + client_token: string + created_at?: string + expires_at: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown | null + last_verification_user_agent?: string | null + metadata?: Json | null + nonce: string + purpose: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } Update: { - client_token?: string; - created_at?: string; - description?: string | null; - expires_at?: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce?: string; - purpose?: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; - Relationships: []; - }; + client_token?: string + created_at?: string + expires_at?: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown | null + last_verification_user_agent?: string | null + metadata?: Json | null + nonce?: string + purpose?: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } + Relationships: [] + } notifications: { Row: { - account_id: string; - body: string; - channel: Database['public']['Enums']['notification_channel']; - created_at: string; - dismissed: boolean; - expires_at: string | null; - id: number; - link: string | null; - type: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel: Database["public"]["Enums"]["notification_channel"] + created_at: string + dismissed: boolean + expires_at: string | null + id: number + link: string | null + type: Database["public"]["Enums"]["notification_type"] + } Insert: { - account_id: string; - body: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Update: { - account_id?: string; - body?: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id?: string + body?: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Relationships: [ { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, - ]; - }; + { + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] + }, + { + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + ] + } order_items: { Row: { - created_at: string; - id: string; - order_id: string; - price_amount: number | null; - product_id: string; - quantity: number; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + order_id: string + price_amount: number | null + product_id: string + quantity: number + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - order_id: string; - price_amount?: number | null; - product_id: string; - quantity?: number; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + order_id: string + price_amount?: number | null + product_id: string + quantity?: number + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - order_id?: string; - price_amount?: number | null; - product_id?: string; - quantity?: number; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + order_id?: string + price_amount?: number | null + product_id?: string + quantity?: number + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'order_items_order_id_fkey'; - columns: ['order_id']; - isOneToOne: false; - referencedRelation: 'orders'; - referencedColumns: ['id']; + foreignKeyName: "order_items_order_id_fkey" + columns: ["order_id"] + isOneToOne: false + referencedRelation: "orders" + referencedColumns: ["id"] }, - ]; - }; + ] + } orders: { Row: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } Insert: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at?: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at?: string + } Update: { - account_id?: string; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency?: string; - id?: string; - status?: Database['public']['Enums']['payment_status']; - total_amount?: number; - updated_at?: string; - }; + account_id?: string + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency?: string + id?: string + status?: Database["public"]["Enums"]["payment_status"] + total_amount?: number + updated_at?: string + } Relationships: [ { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'orders_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "orders_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] + }, + ] + } role_permissions: { Row: { - id: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Insert: { - id?: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id?: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Update: { - id?: number; - permission?: Database['public']['Enums']['app_permissions']; - role?: string; - }; + id?: number + permission?: Database["public"]["Enums"]["app_permissions"] + role?: string + } Relationships: [ { - foreignKeyName: 'role_permissions_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "role_permissions_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; + ] + } roles: { Row: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Insert: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Update: { - hierarchy_level?: number; - name?: string; - }; - Relationships: []; - }; + hierarchy_level?: number + name?: string + } + Relationships: [] + } subscription_items: { Row: { - created_at: string; - id: string; - interval: string; - interval_count: number; - price_amount: number | null; - product_id: string; - quantity: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + interval: string + interval_count: number + price_amount: number | null + product_id: string + quantity: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - interval: string; - interval_count: number; - price_amount?: number | null; - product_id: string; - quantity?: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + interval: string + interval_count: number + price_amount?: number | null + product_id: string + quantity?: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - interval?: string; - interval_count?: number; - price_amount?: number | null; - product_id?: string; - quantity?: number; - subscription_id?: string; - type?: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + interval?: string + interval_count?: number + price_amount?: number | null + product_id?: string + quantity?: number + subscription_id?: string + type?: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'subscription_items_subscription_id_fkey'; - columns: ['subscription_id']; - isOneToOne: false; - referencedRelation: 'subscriptions'; - referencedColumns: ['id']; + foreignKeyName: "subscription_items_subscription_id_fkey" + columns: ["subscription_id"] + isOneToOne: false + referencedRelation: "subscriptions" + referencedColumns: ["id"] }, - ]; - }; + ] + } subscriptions: { Row: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } Insert: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at?: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at?: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Update: { - account_id?: string; - active?: boolean; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - cancel_at_period_end?: boolean; - created_at?: string; - currency?: string; - id?: string; - period_ends_at?: string; - period_starts_at?: string; - status?: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id?: string + active?: boolean + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end?: boolean + created_at?: string + currency?: string + id?: string + period_ends_at?: string + period_starts_at?: string + status?: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Relationships: [ { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'subscriptions_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; - }; + { + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "subscriptions_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] + }, + ] + } + } Views: { + invitations_with_accounts: { + Row: { + account_id: string | null + invite_token: string | null + personal_code: string | null + } + Relationships: [] + } + invitations_with_personal_accounts: { + Row: { + account_id: string | null + account_slug: string | null + invite_token: string | null + personal_code: string | null + } + Relationships: [] + } user_account_workspace: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; + id: string | null + name: string | null + picture_url: string | null subscription_status: - | Database['public']['Enums']['subscription_status'] - | null; - }; - Relationships: []; - }; + | Database["public"]["Enums"]["subscription_status"] + | null + } + Relationships: [] + } user_accounts: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; - role: string | null; - slug: string | null; - }; + id: string | null + name: string | null + picture_url: string | null + role: string | null + slug: string | null + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; - }; + ] + } + } Functions: { accept_invitation: { - Args: { - token: string; - user_id: string; - }; - Returns: string; - }; + Args: { token: string; user_id: string } + Returns: string + } add_invitations_to_account: { Args: { - account_slug: string; - invitations: Database['public']['CompositeTypes']['invitation'][]; - }; - Returns: Database['public']['Tables']['invitations']['Row'][]; - }; + account_slug: string + invitations: Database["public"]["CompositeTypes"]["invitation"][] + } + Returns: Database["public"]["Tables"]["invitations"]["Row"][] + } can_action_account_member: { - Args: { - target_team_account_id: string; - target_user_id: string; - }; - Returns: boolean; - }; + Args: { target_team_account_id: string; target_user_id: string } + Returns: boolean + } + check_personal_code_exists: { + Args: { code: string } + Returns: boolean + } create_invitation: { - Args: { - account_id: string; - email: string; - role: string; - }; + Args: { account_id: string; email: string; role: string } Returns: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + personal_code: string | null + role: string + updated_at: string + } + } create_nonce: { Args: { - p_user_id?: string; - p_purpose?: string; - p_expires_in_seconds?: number; - p_metadata?: Json; - p_description?: string; - p_tags?: string[]; - p_scopes?: string[]; - p_revoke_previous?: boolean; - }; - Returns: Json; - }; + p_user_id?: string + p_purpose?: string + p_expires_in_seconds?: number + p_metadata?: Json + p_scopes?: string[] + p_revoke_previous?: boolean + } + Returns: Json + } create_team_account: { - Args: { - account_name: string; - }; + Args: { account_name: string } Returns: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + personal_code: string | null + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } + } get_account_invitations: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: number; - email: string; - account_id: string; - invited_by: string; - role: string; - created_at: string; - updated_at: string; - expires_at: string; - inviter_name: string; - inviter_email: string; - }[]; - }; + id: number + email: string + account_id: string + invited_by: string + role: string + created_at: string + updated_at: string + expires_at: string + personal_code: string + inviter_name: string + inviter_email: string + }[] + } get_account_members: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - user_id: string; - account_id: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - name: string; - email: string; - picture_url: string; - created_at: string; - updated_at: string; - }[]; - }; + id: string + user_id: string + account_id: string + role: string + role_hierarchy_level: number + primary_owner_user_id: string + name: string + email: string + personal_code: string + picture_url: string + created_at: string + updated_at: string + }[] + } get_config: { - Args: Record; - Returns: Json; - }; + Args: Record + Returns: Json + } + get_invitations_with_account_ids: { + Args: { company_id: string; personal_codes: string[] } + Returns: { + invite_token: string + personal_code: string + account_id: string + }[] + } get_nonce_status: { - Args: { - p_id: string; - }; - Returns: Json; - }; + Args: { p_id: string } + Returns: Json + } get_upper_system_role: { - Args: Record; - Returns: string; - }; + Args: Record + Returns: string + } has_active_subscription: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } has_more_elevated_role: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; + target_user_id: string + target_account_id: string + role_name: string + } + Returns: boolean + } has_permission: { Args: { - user_id: string; - account_id: string; - permission_name: Database['public']['Enums']['app_permissions']; - }; - Returns: boolean; - }; + user_id: string + account_id: string + permission_name: Database["public"]["Enums"]["app_permissions"] + } + Returns: boolean + } has_role_on_account: { - Args: { - account_id: string; - account_role?: string; - }; - Returns: boolean; - }; + Args: { account_id: string; account_role?: string } + Returns: boolean + } has_same_role_hierarchy_level: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; - install_extensions: { - Args: Record; - Returns: undefined; - }; + target_user_id: string + target_account_id: string + role_name: string + } + Returns: boolean + } is_aal2: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_account_owner: { - Args: { - account_id: string; - }; - Returns: boolean; - }; + Args: { account_id: string } + Returns: boolean + } is_account_team_member: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } + is_company_admin: { + Args: { account_slug: string } + Returns: boolean + } is_mfa_compliant: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_set: { - Args: { - field_name: string; - }; - Returns: boolean; - }; + Args: { field_name: string } + Returns: boolean + } is_super_admin: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_team_member: { - Args: { - account_id: string; - user_id: string; - }; - Returns: boolean; - }; + Args: { account_id: string; user_id: string } + Returns: boolean + } revoke_nonce: { - Args: { - p_id: string; - p_reason?: string; - }; - Returns: boolean; - }; + Args: { p_id: string; p_reason?: string } + Returns: boolean + } team_account_workspace: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - name: string; - picture_url: string; - slug: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - subscription_status: Database['public']['Enums']['subscription_status']; - permissions: Database['public']['Enums']['app_permissions'][]; - }[]; - }; + id: string + name: string + picture_url: string + slug: string + role: string + role_hierarchy_level: number + primary_owner_user_id: string + subscription_status: Database["public"]["Enums"]["subscription_status"] + permissions: Database["public"]["Enums"]["app_permissions"][] + }[] + } transfer_team_account_ownership: { - Args: { - target_account_id: string; - new_owner_id: string; - }; - Returns: undefined; - }; + Args: { target_account_id: string; new_owner_id: string } + Returns: undefined + } upsert_order: { Args: { - target_account_id: string; - target_customer_id: string; - target_order_id: string; - status: Database['public']['Enums']['payment_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - total_amount: number; - currency: string; - line_items: Json; - }; + target_account_id: string + target_customer_id: string + target_order_id: string + status: Database["public"]["Enums"]["payment_status"] + billing_provider: Database["public"]["Enums"]["billing_provider"] + total_amount: number + currency: string + line_items: Json + } Returns: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } + } upsert_subscription: { Args: { - target_account_id: string; - target_customer_id: string; - target_subscription_id: string; - active: boolean; - status: Database['public']['Enums']['subscription_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - currency: string; - period_starts_at: string; - period_ends_at: string; - line_items: Json; - trial_starts_at?: string; - trial_ends_at?: string; - }; + target_account_id: string + target_customer_id: string + target_subscription_id: string + active: boolean + status: Database["public"]["Enums"]["subscription_status"] + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + currency: string + period_starts_at: string + period_ends_at: string + line_items: Json + trial_starts_at?: string + trial_ends_at?: string + } Returns: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } + } verify_nonce: { Args: { - p_token: string; - p_purpose: string; - p_user_id?: string; - p_required_scopes?: string[]; - p_max_verification_attempts?: number; - p_ip?: unknown; - p_user_agent?: string; - }; - Returns: Json; - }; - }; + p_token: string + p_purpose: string + p_user_id?: string + p_required_scopes?: string[] + p_max_verification_attempts?: number + p_ip?: unknown + p_user_agent?: string + } + Returns: Json + } + } Enums: { + analysis_order_status: + | "QUEUED" + | "ON_HOLD" + | "PROCESSING" + | "COMPLETED" + | "REJECTED" + | "CANCELLED" app_permissions: - | 'roles.manage' - | 'billing.manage' - | 'settings.manage' - | 'members.manage' - | 'invites.manage'; - billing_provider: 'stripe' | 'lemon-squeezy' | 'paddle'; - notification_channel: 'in_app' | 'email'; - notification_type: 'info' | 'warning' | 'error'; - payment_status: 'pending' | 'succeeded' | 'failed'; - subscription_item_type: 'flat' | 'per_seat' | 'metered'; + | "roles.manage" + | "billing.manage" + | "settings.manage" + | "members.manage" + | "invites.manage" + billing_provider: "stripe" | "lemon-squeezy" | "paddle" + notification_channel: "in_app" | "email" + notification_type: "info" | "warning" | "error" + payment_status: "pending" | "succeeded" | "failed" + subscription_item_type: "flat" | "per_seat" | "metered" subscription_status: - | 'active' - | 'trialing' - | 'past_due' - | 'canceled' - | 'unpaid' - | 'incomplete' - | 'incomplete_expired' - | 'paused'; - }; + | "active" + | "trialing" + | "past_due" + | "canceled" + | "unpaid" + | "incomplete" + | "incomplete_expired" + | "paused" + } CompositeTypes: { invitation: { - email: string | null; - role: string | null; - }; - }; - }; - storage: { - Tables: { - buckets: { - Row: { - allowed_mime_types: string[] | null; - avif_autodetection: boolean | null; - created_at: string | null; - file_size_limit: number | null; - id: string; - name: string; - owner: string | null; - owner_id: string | null; - public: boolean | null; - updated_at: string | null; - }; - Insert: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id: string; - name: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; - Update: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id?: string; - name?: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; - Relationships: []; - }; - migrations: { - Row: { - executed_at: string | null; - hash: string; - id: number; - name: string; - }; - Insert: { - executed_at?: string | null; - hash: string; - id: number; - name: string; - }; - Update: { - executed_at?: string | null; - hash?: string; - id?: number; - name?: string; - }; - Relationships: []; - }; - objects: { - Row: { - bucket_id: string | null; - created_at: string | null; - id: string; - last_accessed_at: string | null; - metadata: Json | null; - name: string | null; - owner: string | null; - owner_id: string | null; - path_tokens: string[] | null; - updated_at: string | null; - user_metadata: Json | null; - version: string | null; - }; - Insert: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; - Update: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; - Relationships: [ - { - foreignKeyName: 'objects_bucketId_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - ]; - }; - s3_multipart_uploads: { - Row: { - bucket_id: string; - created_at: string; - id: string; - in_progress_size: number; - key: string; - owner_id: string | null; - upload_signature: string; - user_metadata: Json | null; - version: string; - }; - Insert: { - bucket_id: string; - created_at?: string; - id: string; - in_progress_size?: number; - key: string; - owner_id?: string | null; - upload_signature: string; - user_metadata?: Json | null; - version: string; - }; - Update: { - bucket_id?: string; - created_at?: string; - id?: string; - in_progress_size?: number; - key?: string; - owner_id?: string | null; - upload_signature?: string; - user_metadata?: Json | null; - version?: string; - }; - Relationships: [ - { - foreignKeyName: 's3_multipart_uploads_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - ]; - }; - s3_multipart_uploads_parts: { - Row: { - bucket_id: string; - created_at: string; - etag: string; - id: string; - key: string; - owner_id: string | null; - part_number: number; - size: number; - upload_id: string; - version: string; - }; - Insert: { - bucket_id: string; - created_at?: string; - etag: string; - id?: string; - key: string; - owner_id?: string | null; - part_number: number; - size?: number; - upload_id: string; - version: string; - }; - Update: { - bucket_id?: string; - created_at?: string; - etag?: string; - id?: string; - key?: string; - owner_id?: string | null; - part_number?: number; - size?: number; - upload_id?: string; - version?: string; - }; - Relationships: [ - { - foreignKeyName: 's3_multipart_uploads_parts_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - { - foreignKeyName: 's3_multipart_uploads_parts_upload_id_fkey'; - columns: ['upload_id']; - isOneToOne: false; - referencedRelation: 's3_multipart_uploads'; - referencedColumns: ['id']; - }, - ]; - }; - }; - Views: { - [_ in never]: never; - }; - Functions: { - can_insert_object: { - Args: { - bucketid: string; - name: string; - owner: string; - metadata: Json; - }; - Returns: undefined; - }; - extension: { - Args: { - name: string; - }; - Returns: string; - }; - filename: { - Args: { - name: string; - }; - Returns: string; - }; - foldername: { - Args: { - name: string; - }; - Returns: string[]; - }; - get_size_by_bucket: { - Args: Record; - Returns: { - size: number; - bucket_id: string; - }[]; - }; - list_multipart_uploads_with_delimiter: { - Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - next_key_token?: string; - next_upload_token?: string; - }; - Returns: { - key: string; - id: string; - created_at: string; - }[]; - }; - list_objects_with_delimiter: { - Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - start_after?: string; - next_token?: string; - }; - Returns: { - name: string; - id: string; - metadata: Json; - updated_at: string; - }[]; - }; - operation: { - Args: Record; - Returns: string; - }; - search: { - Args: { - prefix: string; - bucketname: string; - limits?: number; - levels?: number; - offsets?: number; - search?: string; - sortcolumn?: string; - sortorder?: string; - }; - Returns: { - name: string; - id: string; - updated_at: string; - created_at: string; - last_accessed_at: string; - metadata: Json; - }[]; - }; - }; - Enums: { - [_ in never]: never; - }; - CompositeTypes: { - [_ in never]: never; - }; - }; -}; + email: string | null + role: string | null + personal_code: string | null + } + } + } +} -type PublicSchema = Database[Extract]; +type DefaultSchema = Database[Extract] export type Tables< - PublicTableNameOrOptions extends - | keyof (PublicSchema['Tables'] & PublicSchema['Views']) + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views']) + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { - Row: infer R; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & - PublicSchema['Views']) - ? (PublicSchema['Tables'] & - PublicSchema['Views'])[PublicTableNameOrOptions] extends { - Row: infer R; + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R } ? R : never - : never; + : never export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Insert: infer I; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I } ? I : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Insert: infer I; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I } ? I : never - : never; + : never export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Update: infer U; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U } ? U : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Update: infer U; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U } ? U : never - : never; + : never export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema['Enums'] + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] | { schema: keyof Database }, - EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] : never = never, -> = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] - ? PublicSchema['Enums'][PublicEnumNameOrOptions] - : never; +> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never export type CompositeTypes< PublicCompositeTypeNameOrOptions extends - | keyof PublicSchema['CompositeTypes'] + | keyof DefaultSchema["CompositeTypes"] | { schema: keyof Database }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database; + schema: keyof Database } - ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] : never = never, > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } - ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] - : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] - ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] - : never; + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + audit: { + Enums: { + sync_status: ["SUCCESS", "FAIL"], + }, + }, + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + analysis_order_status: [ + "QUEUED", + "ON_HOLD", + "PROCESSING", + "COMPLETED", + "REJECTED", + "CANCELLED", + ], + app_permissions: [ + "roles.manage", + "billing.manage", + "settings.manage", + "members.manage", + "invites.manage", + ], + billing_provider: ["stripe", "lemon-squeezy", "paddle"], + notification_channel: ["in_app", "email"], + notification_type: ["info", "warning", "error"], + payment_status: ["pending", "succeeded", "failed"], + subscription_item_type: ["flat", "per_seat", "metered"], + subscription_status: [ + "active", + "trialing", + "past_due", + "canceled", + "unpaid", + "incomplete", + "incomplete_expired", + "paused", + ], + }, + }, +} as const + diff --git a/package.json b/package.json index be13199..dfc2d5f 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "supabase:db:diff": "supabase db diff", "supabase:deploy": "supabase link --project-ref $SUPABASE_PROJECT_REF && supabase db push", "supabase:typegen": "pnpm run supabase:typegen:packages && pnpm run supabase:typegen:app", - "supabase:typegen:packages": "supabase gen types typescript --local > ../../packages/supabase/src/database.types.ts", + "supabase:typegen:packages": "supabase gen types typescript --local > ./packages/supabase/src/database.types.ts", "supabase:typegen:app": "supabase gen types typescript --local > ./lib/database.types.ts", "supabase:db:dump:local": "supabase db dump --local --data-only", "sync-data:dev": "NODE_ENV=local ts-node jobs/sync-analysis-groups.ts" diff --git a/packages/features/accounts/src/components/personal-account-dropdown.tsx b/packages/features/accounts/src/components/personal-account-dropdown.tsx index ea2733d..c1a7128 100644 --- a/packages/features/accounts/src/components/personal-account-dropdown.tsx +++ b/packages/features/accounts/src/components/personal-account-dropdown.tsx @@ -10,7 +10,7 @@ import { ChevronsUpDown, Home, LogOut, - MessageCircleQuestion, + UserCircle, Shield, } from 'lucide-react'; @@ -170,12 +170,12 @@ export function PersonalAccountDropdown({ - + - + diff --git a/packages/features/accounts/src/server/api.ts b/packages/features/accounts/src/server/api.ts index 50b9ad4..35a4465 100644 --- a/packages/features/accounts/src/server/api.ts +++ b/packages/features/accounts/src/server/api.ts @@ -47,23 +47,61 @@ class AccountsApi { } /** - * @name loadUserAccounts - * Load the user accounts. - */ + * @name loadUserAccounts + * Load only user-owned accounts (not just memberships). + */ async loadUserAccounts() { + const authUser = await this.client.auth.getUser(); + + const { + data, + error: userError, + } = authUser + + if (userError) { + throw userError; + } + + const { user } = data; + const { data: accounts, error } = await this.client - .from('user_accounts') - .select(`name, slug, picture_url`); + .from('accounts_memberships') + .select(` + account_id, + user_accounts ( + name, + slug, + picture_url + ) + `) + .eq('user_id', user.id) + .eq('account_role', 'owner'); if (error) { throw error; } - return accounts.map(({ name, slug, picture_url }) => { + return accounts.map(({ user_accounts }) => ({ + label: user_accounts.name, + value: user_accounts.slug, + image: user_accounts.picture_url, + })); + } + + + async loadTempUserAccounts() { + const { data: accounts, error } = await this.client + .from('user_accounts') + .select(`name, slug`); + + if (error) { + throw error; + } + + return accounts.map(({ name, slug }) => { return { label: name, value: slug, - image: picture_url, }; }); } diff --git a/packages/features/admin/src/components/admin-account-page.tsx b/packages/features/admin/src/components/admin-account-page.tsx index ea114be..0930ad2 100644 --- a/packages/features/admin/src/components/admin-account-page.tsx +++ b/packages/features/admin/src/components/admin-account-page.tsx @@ -28,6 +28,12 @@ import { AdminMembersTable } from './admin-members-table'; import { AdminMembershipsTable } from './admin-memberships-table'; import { AdminReactivateUserDialog } from './admin-reactivate-user-dialog'; +import { + AccountInvitationsTable, + AccountMembersTable, + InviteMembersDialogContainer, +} from '@kit/team-accounts/components'; + type Account = Tables<'accounts'>; type Membership = Tables<'accounts_memberships'>; @@ -146,8 +152,6 @@ async function PersonalAccountPage(props: { account: Account }) {
- -
Companies @@ -213,7 +217,7 @@ async function TeamAccountPage(props: {
- Company Employees + Company Members
diff --git a/packages/features/admin/src/components/admin-accounts-table.tsx b/packages/features/admin/src/components/admin-accounts-table.tsx index 06a14c7..a6ee29e 100644 --- a/packages/features/admin/src/components/admin-accounts-table.tsx +++ b/packages/features/admin/src/components/admin-accounts-table.tsx @@ -179,6 +179,14 @@ function getColumns(): ColumnDef[] { header: 'Email', accessorKey: 'email', }, + { + id: 'personalCode', + header: 'Personal Code', + accessorKey: 'personalCode', + cell: ({ row }) => { + return row.original.personal_code ?? '-'; + }, + }, { id: 'type', header: 'Type', diff --git a/packages/features/admin/src/components/admin-create-user-dialog.tsx b/packages/features/admin/src/components/admin-create-user-dialog.tsx index bc21c4a..0b71f81 100644 --- a/packages/features/admin/src/components/admin-create-user-dialog.tsx +++ b/packages/features/admin/src/components/admin-create-user-dialog.tsx @@ -48,8 +48,9 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) { email: '', password: '', emailConfirm: false, + personalCode: '' }, - mode: 'onChange', + mode: 'onBlur', }); const onSubmit = (data: CreateUserSchemaType) => { @@ -98,6 +99,25 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) { + ( + + Personal code + + + + + + + )} + /> + ( diff --git a/packages/features/admin/src/components/admin-members-table.tsx b/packages/features/admin/src/components/admin-members-table.tsx index 8d256be..d970645 100644 --- a/packages/features/admin/src/components/admin-members-table.tsx +++ b/packages/features/admin/src/components/admin-members-table.tsx @@ -52,7 +52,7 @@ function getColumns(): ColumnDef[] { { header: 'Role', cell: ({ row }) => { - return row.original.role === 'owner' ? 'HR' : 'Employee'; + return row.original.role === 'owner' ? 'Admin' : 'Member'; }, }, { diff --git a/packages/features/admin/src/lib/server/admin-server-actions.ts b/packages/features/admin/src/lib/server/admin-server-actions.ts index cac9ae9..7da94b9 100644 --- a/packages/features/admin/src/lib/server/admin-server-actions.ts +++ b/packages/features/admin/src/lib/server/admin-server-actions.ts @@ -160,7 +160,7 @@ export const deleteAccountAction = adminAction( */ export const createUserAction = adminAction( enhanceAction( - async ({ email, password, emailConfirm }) => { + async ({ email, password, emailConfirm, personalCode }) => { const adminClient = getSupabaseServerAdminClient(); const logger = await getLogger(); @@ -182,6 +182,16 @@ export const createUserAction = adminAction( `Super Admin has successfully created a new user`, ); + const { error: accountError } = await adminClient + .from('accounts') + .update({ personal_code: personalCode }) + .eq('id', data.user.id); + + if (accountError) { + logger.error({ accountError }, 'Error inserting personal code to accounts'); + throw new Error(`Error saving personal code: ${accountError.message}`); + } + revalidateAdmin(); return { diff --git a/packages/features/admin/src/lib/server/schema/create-user-profile.schema.ts b/packages/features/admin/src/lib/server/schema/create-user-profile.schema.ts new file mode 100644 index 0000000..03e971d --- /dev/null +++ b/packages/features/admin/src/lib/server/schema/create-user-profile.schema.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +export const CreateUserProfileSchema = z.object({ + personalCode: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, { + message: 'Invalid Estonian personal code format', + }), +}); + +export type CreateUserProfileSchemaType = z.infer; + diff --git a/packages/features/admin/src/lib/server/schema/create-user.schema.ts b/packages/features/admin/src/lib/server/schema/create-user.schema.ts index 586474f..9b05b4e 100644 --- a/packages/features/admin/src/lib/server/schema/create-user.schema.ts +++ b/packages/features/admin/src/lib/server/schema/create-user.schema.ts @@ -1,6 +1,9 @@ import { z } from 'zod'; export const CreateUserSchema = z.object({ + personalCode: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, { + message: 'Invalid Estonian personal code format', + }), email: z.string().email({ message: 'Please enter a valid email address' }), password: z .string() diff --git a/packages/features/auth/src/components/password-sign-up-form.tsx b/packages/features/auth/src/components/password-sign-up-form.tsx index dbba6ea..1b29b97 100644 --- a/packages/features/auth/src/components/password-sign-up-form.tsx +++ b/packages/features/auth/src/components/password-sign-up-form.tsx @@ -30,6 +30,7 @@ interface PasswordSignUpFormProps { displayTermsCheckbox?: boolean; onSubmit: (params: { + personalCode: string; email: string; password: string; repeatPassword: string; @@ -48,6 +49,7 @@ export function PasswordSignUpForm({ const form = useForm({ resolver: zodResolver(PasswordSignUpSchema), defaultValues: { + personalCode: '', email: defaultValues?.email ?? '', password: '', repeatPassword: '', @@ -60,6 +62,29 @@ export function PasswordSignUpForm({ className={'flex w-full flex-col gap-y-4'} onSubmit={form.handleSubmit(onSubmit)} > + ( + + + + + + + + + + + + )} + /> redirect(redirectUrl)} /> diff --git a/packages/features/auth/src/hooks/use-sign-up-flow.ts b/packages/features/auth/src/hooks/use-sign-up-flow.ts index a6ba52e..1732b68 100644 --- a/packages/features/auth/src/hooks/use-sign-up-flow.ts +++ b/packages/features/auth/src/hooks/use-sign-up-flow.ts @@ -8,6 +8,7 @@ import { useAppEvents } from '@kit/shared/events'; import { useSignUpWithEmailAndPassword } from '@kit/supabase/hooks/use-sign-up-with-email-password'; type SignUpCredentials = { + personalCode: string; email: string; password: string; }; @@ -46,7 +47,6 @@ export function usePasswordSignUpFlow({ emailRedirectTo, captchaToken, }); - // emit event to track sign up appEvents.emit({ type: 'user.signedUp', diff --git a/packages/features/auth/src/schemas/password-sign-up.schema.ts b/packages/features/auth/src/schemas/password-sign-up.schema.ts index 828924d..b2fcab4 100644 --- a/packages/features/auth/src/schemas/password-sign-up.schema.ts +++ b/packages/features/auth/src/schemas/password-sign-up.schema.ts @@ -4,6 +4,9 @@ import { RefinedPasswordSchema, refineRepeatPassword } from './password.schema'; export const PasswordSignUpSchema = z .object({ + personalCode: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, { + message: 'Invalid Estonian personal code format', + }), email: z.string().email(), password: RefinedPasswordSchema, repeatPassword: RefinedPasswordSchema, diff --git a/packages/features/team-accounts/package.json b/packages/features/team-accounts/package.json index 002b1c0..2cfb254 100644 --- a/packages/features/team-accounts/package.json +++ b/packages/features/team-accounts/package.json @@ -9,6 +9,7 @@ "typecheck": "tsc --noEmit" }, "exports": { + ".": "./src/index.ts", "./api": "./src/server/api.ts", "./components": "./src/components/index.ts", "./hooks/*": "./src/hooks/*.ts", diff --git a/packages/features/team-accounts/src/components/company-guard.tsx b/packages/features/team-accounts/src/components/company-guard.tsx new file mode 100644 index 0000000..c146073 --- /dev/null +++ b/packages/features/team-accounts/src/components/company-guard.tsx @@ -0,0 +1,32 @@ +import { notFound } from 'next/navigation'; + +import { getSupabaseServerClient } from '@kit/supabase/server-client'; +import { isCompanyAdmin } from '../server/utils/is-company-admin'; +import { isSuperAdmin } from '@kit/admin' + +type LayoutOrPageComponent = React.ComponentType; + +/** + * CompanyGuard is a server component wrapper that checks if the user is a company admin before rendering the component. + * If the user is not a company admin, we redirect to a 404. + * @param Component - The Page or Layout component to wrap + */ +export function CompanyGuard( + Component: LayoutOrPageComponent, +) { + return async function AdminGuardServerComponentWrapper(params: Params) { + //@ts-ignore + const { account } = await params.params; + const client = getSupabaseServerClient(); + const [isUserSuperAdmin, isUserCompanyAdmin] = await Promise.all( + [isSuperAdmin(client), isCompanyAdmin(client, account)] + ); + + console.log({ isUserSuperAdmin, isUserCompanyAdmin , params: account}) + if (isUserSuperAdmin || isUserCompanyAdmin) { + return ; + } + // if the user is not a company admin, we redirect to a 404 + notFound(); + }; +} diff --git a/packages/features/team-accounts/src/components/index.ts b/packages/features/team-accounts/src/components/index.ts index 63d3ece..a3b9b09 100644 --- a/packages/features/team-accounts/src/components/index.ts +++ b/packages/features/team-accounts/src/components/index.ts @@ -6,3 +6,4 @@ export * from './settings/team-account-settings-container'; export * from './invitations/accept-invitation-container'; export * from './create-team-account-dialog'; export * from './team-account-workspace-context'; +export * from './company-guard'; diff --git a/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx b/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx index a3c9c9a..45a7a2a 100644 --- a/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx +++ b/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx @@ -107,6 +107,14 @@ function useGetColumns(permissions: { ); }, }, + { + header: t('personalCode'), + cell: ({ row }) => { + const { personal_code } = row.original; + + return personal_code; + }, + }, { header: t('roleLabel'), cell: ({ row }) => { diff --git a/packages/features/team-accounts/src/components/members/account-members-table.tsx b/packages/features/team-accounts/src/components/members/account-members-table.tsx index a01155e..5473213 100644 --- a/packages/features/team-accounts/src/components/members/account-members-table.tsx +++ b/packages/features/team-accounts/src/components/members/account-members-table.tsx @@ -87,7 +87,8 @@ export function AccountMembersTable({ return ( displayName.includes(searchString) || - member.role.toLowerCase().includes(searchString) + member.role.toLowerCase().includes(searchString) || + (member.personal_code || '').includes(searchString) ); }) .sort((prev, next) => { @@ -160,6 +161,13 @@ function useGetColumns( return row.original.email ?? '-'; }, }, + { + header: t('personalCode'), + accessorKey: 'personal_code', + cell: ({ row }) => { + return row.original.personal_code ?? '-'; + }, + }, { header: t('roleLabel'), cell: ({ row }) => { diff --git a/packages/features/team-accounts/src/components/members/invite-members-dialog-container.tsx b/packages/features/team-accounts/src/components/members/invite-members-dialog-container.tsx index 8d793a6..2b221e4 100644 --- a/packages/features/team-accounts/src/components/members/invite-members-dialog-container.tsx +++ b/packages/features/team-accounts/src/components/members/invite-members-dialog-container.tsx @@ -66,7 +66,7 @@ export function InviteMembersDialogContainer({ {children} - e.preventDefault()}> + e.preventDefault()}> @@ -142,13 +142,39 @@ function InviteMembersForm({ {fieldArray.fields.map((field, index) => { const isFirst = index === 0; + const personalCodeInputName = `invitations.${index}.personal_code` as const; const emailInputName = `invitations.${index}.email` as const; const roleInputName = `invitations.${index}.role` as const; return (
-
+
+ { + return ( + + + {t('Personal code')} + + + + + + + + + ); + }} + /> +
+
{ @@ -273,5 +299,5 @@ function InviteMembersForm({ } function createEmptyInviteModel() { - return { email: '', role: 'member' as Role }; + return { email: '', role: 'member' as Role, personal_code: '' }; } diff --git a/packages/features/team-accounts/src/index.ts b/packages/features/team-accounts/src/index.ts new file mode 100644 index 0000000..63554f6 --- /dev/null +++ b/packages/features/team-accounts/src/index.ts @@ -0,0 +1 @@ +export * from './server/utils/is-company-admin'; \ No newline at end of file diff --git a/packages/features/team-accounts/src/schema/invite-members.schema.ts b/packages/features/team-accounts/src/schema/invite-members.schema.ts index 4c5f67e..bde399f 100644 --- a/packages/features/team-accounts/src/schema/invite-members.schema.ts +++ b/packages/features/team-accounts/src/schema/invite-members.schema.ts @@ -3,6 +3,9 @@ import { z } from 'zod'; const InviteSchema = z.object({ email: z.string().email(), role: z.string().min(1).max(100), + personal_code: z.string().regex(/^[1-6]\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\d$/, { + message: 'Invalid Estonian personal code format', + }), }); export const InviteMembersSchema = z diff --git a/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts b/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts index 2e210c2..6ca6a6a 100644 --- a/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts +++ b/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts @@ -16,6 +16,8 @@ import { RenewInvitationSchema } from '../../schema/renew-invitation.schema'; import { UpdateInvitationSchema } from '../../schema/update-invitation.schema'; import { createAccountInvitationsService } from '../services/account-invitations.service'; import { createAccountPerSeatBillingService } from '../services/account-per-seat-billing.service'; +import { createNotificationsApi } from '@kit/notifications/api'; +import { getLogger } from '@kit/shared/logger'; /** * @name createInvitationsAction @@ -23,14 +25,55 @@ import { createAccountPerSeatBillingService } from '../services/account-per-seat */ export const createInvitationsAction = enhanceAction( async (params) => { + const logger = await getLogger(); const client = getSupabaseServerClient(); + const serviceClient = getSupabaseServerAdminClient(); - // Create the service const service = createAccountInvitationsService(client); + const api = createNotificationsApi(serviceClient); - // send invitations await service.sendInvitations(params); + const { invitations: invitationParams, accountSlug } = params; + const personalCodes = invitationParams.map(({ personal_code }) => personal_code); + + const { data: company, error: companyError } = await client + .from('accounts') + .select('id') + .eq('slug', accountSlug); + + logger.debug({ company, companyError, personalCodes }) + + if (companyError || !company?.length || !company[0]) { + throw new Error(`Failed to fetch company id: ${companyError?.message || 'not found'}`); + } + + const { data: invitations, error: invitationError } = await serviceClient.rpc( + 'get_invitations_with_account_ids', + { + company_id: company[0].id, + personal_codes: personalCodes, + } + ); + + logger.debug({ invitations, invitationError }) + + if (invitationError) { + throw new Error(`Failed to fetch invitations with accounts: ${invitationError.message}`); + } + + const notificationPromises = invitations + .map(({ invite_token, account_id }) => + api.createNotification({ + account_id: account_id!, + body: `You are invited to join the company: ${accountSlug}`, + link: `/join?invite_token=${invite_token}`, + }) + ); + + await Promise.all(notificationPromises); + + logger.info('All invitation notifications are sent') revalidateMemberPage(); return { diff --git a/packages/features/team-accounts/src/server/utils/is-company-admin.ts b/packages/features/team-accounts/src/server/utils/is-company-admin.ts new file mode 100644 index 0000000..9ac4a22 --- /dev/null +++ b/packages/features/team-accounts/src/server/utils/is-company-admin.ts @@ -0,0 +1,24 @@ +import { SupabaseClient } from '@supabase/supabase-js'; + +import { Database } from '@kit/supabase/database'; + +/** + * @name isCompanyAdmin + * @description Check if the current user is a super admin. + * @param client + */ +export async function isCompanyAdmin(client: SupabaseClient, accountSlug: string) { + try { + const { data, error } = await client.rpc('is_company_admin', { + account_slug: accountSlug, + }); + + if (error) { + throw error; + } + + return data; + } catch { + return false; + } +} diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts index 452ae7b..96430a7 100644 --- a/packages/supabase/src/database.types.ts +++ b/packages/supabase/src/database.types.ts @@ -4,1439 +4,1652 @@ export type Json = | boolean | null | { [key: string]: Json | undefined } - | Json[]; + | Json[] export type Database = { + audit: { + Tables: { + log_entries: { + Row: { + changed_at: string + changed_by: string | null + changed_by_role: string | null + changed_data: Json | null + id: number + operation: string + record_key: number | null + row_data: Json | null + schema_name: string + table_name: string + } + Insert: { + changed_at?: string + changed_by?: string | null + changed_by_role?: string | null + changed_data?: Json | null + id?: number + operation: string + record_key?: number | null + row_data?: Json | null + schema_name: string + table_name: string + } + Update: { + changed_at?: string + changed_by?: string | null + changed_by_role?: string | null + changed_data?: Json | null + id?: number + operation?: string + record_key?: number | null + row_data?: Json | null + schema_name?: string + table_name?: string + } + Relationships: [] + } + sync_entries: { + Row: { + changed_by_role: string + comment: string | null + created_at: string + id: number + operation: string + status: string + } + Insert: { + changed_by_role: string + comment?: string | null + created_at?: string + id?: number + operation: string + status: string + } + Update: { + changed_by_role?: string + comment?: string | null + created_at?: string + id?: number + operation?: string + status?: string + } + Relationships: [] + } + } + Views: { + [_ in never]: never + } + Functions: { + [_ in never]: never + } + Enums: { + sync_status: "SUCCESS" | "FAIL" + } + CompositeTypes: { + [_ in never]: never + } + } graphql_public: { Tables: { - [_ in never]: never; - }; + [_ in never]: never + } Views: { - [_ in never]: never; - }; + [_ in never]: never + } Functions: { graphql: { Args: { - operationName?: string; - query?: string; - variables?: Json; - extensions?: Json; - }; - Returns: Json; - }; - }; + operationName?: string + query?: string + variables?: Json + extensions?: Json + } + Returns: Json + } + } Enums: { - [_ in never]: never; - }; + [_ in never]: never + } CompositeTypes: { - [_ in never]: never; - }; - }; + [_ in never]: never + } + } public: { Tables: { accounts: { Row: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + personal_code: string | null + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } Insert: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name: string + personal_code?: string | null + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } Update: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name?: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; - Relationships: []; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name?: string + personal_code?: string | null + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } + Relationships: [] + } accounts_memberships: { Row: { - account_id: string; - account_role: string; - created_at: string; - created_by: string | null; - updated_at: string; - updated_by: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at: string + created_by: string | null + updated_at: string + updated_by: string | null + user_id: string + } Insert: { - account_id: string; - account_role: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id: string + } Update: { - account_id?: string; - account_role?: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id?: string; - }; + account_id?: string + account_role?: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id?: string + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['account_role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["account_role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] + }, + ] + } + analyses: { + Row: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab: string | null + created_at: string + id: number + order: number + parent_analysis_element_id: number + tehik_loinc_name: string | null + tehik_short_loinc: string | null + updated_at: string | null + } + Insert: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab?: string | null + created_at?: string + id?: number + order: number + parent_analysis_element_id: number + tehik_loinc_name?: string | null + tehik_short_loinc?: string | null + updated_at?: string | null + } + Update: { + analysis_id_oid?: string + analysis_id_original?: string + analysis_name_lab?: string | null + created_at?: string + id?: number + order?: number + parent_analysis_element_id?: number + tehik_loinc_name?: string | null + tehik_short_loinc?: string | null + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analyses_parent_analysis_element_id_fkey" + columns: ["parent_analysis_element_id"] + isOneToOne: false + referencedRelation: "analysis_elements" + referencedColumns: ["id"] + }, + ] + } + analysis_elements: { + Row: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab: string | null + created_at: string + id: number + material_groups: Json[] | null + order: number + parent_analysis_group_id: number + tehik_loinc_name: string + tehik_short_loinc: string + updated_at: string | null + } + Insert: { + analysis_id_oid: string + analysis_id_original: string + analysis_name_lab?: string | null + created_at?: string + id?: number + material_groups?: Json[] | null + order: number + parent_analysis_group_id: number + tehik_loinc_name: string + tehik_short_loinc: string + updated_at?: string | null + } + Update: { + analysis_id_oid?: string + analysis_id_original?: string + analysis_name_lab?: string | null + created_at?: string + id?: number + material_groups?: Json[] | null + order?: number + parent_analysis_group_id?: number + tehik_loinc_name?: string + tehik_short_loinc?: string + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analysis_elements_parent_analysis_group_id_fkey" + columns: ["parent_analysis_group_id"] + isOneToOne: false + referencedRelation: "analysis_groups" + referencedColumns: ["id"] + }, + ] + } + analysis_groups: { + Row: { + created_at: string + id: number + name: string + order: number + original_id: string + updated_at: string | null + } + Insert: { + created_at?: string + id?: number + name: string + order: number + original_id: string + updated_at?: string | null + } + Update: { + created_at?: string + id?: number + name?: string + order?: number + original_id?: string + updated_at?: string | null + } + Relationships: [] + } + analysis_orders: { + Row: { + analysis_element_ids: number[] | null + analysis_ids: number[] | null + created_at: string + id: number + status: Database["public"]["Enums"]["analysis_order_status"] + user_id: string + } + Insert: { + analysis_element_ids?: number[] | null + analysis_ids?: number[] | null + created_at?: string + id?: number + status: Database["public"]["Enums"]["analysis_order_status"] + user_id: string + } + Update: { + analysis_element_ids?: number[] | null + analysis_ids?: number[] | null + created_at?: string + id?: number + status?: Database["public"]["Enums"]["analysis_order_status"] + user_id?: string + } + Relationships: [] + } + analysis_response_elements: { + Row: { + analysis_element_original_id: string + analysis_response_id: number + created_at: string + id: number + norm_lower: number | null + norm_lower_included: boolean | null + norm_status: number | null + norm_upper: number | null + norm_upper_included: boolean | null + original_response_element: Json + response_time: string + response_value: Json + unit: string | null + updated_at: string | null + } + Insert: { + analysis_element_original_id: string + analysis_response_id: number + created_at?: string + id?: number + norm_lower?: number | null + norm_lower_included?: boolean | null + norm_status?: number | null + norm_upper?: number | null + norm_upper_included?: boolean | null + original_response_element: Json + response_time: string + response_value: Json + unit?: string | null + updated_at?: string | null + } + Update: { + analysis_element_original_id?: string + analysis_response_id?: number + created_at?: string + id?: number + norm_lower?: number | null + norm_lower_included?: boolean | null + norm_status?: number | null + norm_upper?: number | null + norm_upper_included?: boolean | null + original_response_element?: Json + response_time?: string + response_value?: Json + unit?: string | null + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "analysis_response_element_analysis_response_id_fkey" + columns: ["analysis_response_id"] + isOneToOne: false + referencedRelation: "analysis_responses" + referencedColumns: ["id"] + }, + ] + } + analysis_responses: { + Row: { + analysis_order_id: number + created_at: string + id: number + order_number: string + order_status: Database["public"]["Enums"]["analysis_order_status"] + updated_at: string | null + user_id: string + } + Insert: { + analysis_order_id: number + created_at?: string + id?: number + order_number: string + order_status: Database["public"]["Enums"]["analysis_order_status"] + updated_at?: string | null + user_id: string + } + Update: { + analysis_order_id?: number + created_at?: string + id?: number + order_number?: string + order_status?: Database["public"]["Enums"]["analysis_order_status"] + updated_at?: string | null + user_id?: string + } + Relationships: [ + { + foreignKeyName: "analysis_responses_analysis_order_id_fkey" + columns: ["analysis_order_id"] + isOneToOne: false + referencedRelation: "analysis_orders" + referencedColumns: ["id"] + }, + ] + } billing_customers: { Row: { - account_id: string; - customer_id: string; - email: string | null; - id: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email: string | null + id: number + provider: Database["public"]["Enums"]["billing_provider"] + } Insert: { - account_id: string; - customer_id: string; - email?: string | null; - id?: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email?: string | null + id?: number + provider: Database["public"]["Enums"]["billing_provider"] + } Update: { - account_id?: string; - customer_id?: string; - email?: string | null; - id?: number; - provider?: Database['public']['Enums']['billing_provider']; - }; + account_id?: string + customer_id?: string + email?: string | null + id?: number + provider?: Database["public"]["Enums"]["billing_provider"] + } Relationships: [ { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, - ]; - }; + { + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] + }, + { + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + ] + } + codes: { + Row: { + analysis_element_id: number | null + analysis_group_id: number | null + analysis_id: number | null + coefficient: number + created_at: string + hk_code: string + hk_code_multiplier: number + id: number + price: number + updated_at: string | null + } + Insert: { + analysis_element_id?: number | null + analysis_group_id?: number | null + analysis_id?: number | null + coefficient: number + created_at?: string + hk_code: string + hk_code_multiplier: number + id?: number + price: number + updated_at?: string | null + } + Update: { + analysis_element_id?: number | null + analysis_group_id?: number | null + analysis_id?: number | null + coefficient?: number + created_at?: string + hk_code?: string + hk_code_multiplier?: number + id?: number + price?: number + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "codes_analysis_element_id_fkey" + columns: ["analysis_element_id"] + isOneToOne: false + referencedRelation: "analysis_elements" + referencedColumns: ["id"] + }, + { + foreignKeyName: "codes_analysis_group_id_fkey" + columns: ["analysis_group_id"] + isOneToOne: false + referencedRelation: "analysis_groups" + referencedColumns: ["id"] + }, + { + foreignKeyName: "codes_analysis_id_fkey" + columns: ["analysis_id"] + isOneToOne: false + referencedRelation: "analyses" + referencedColumns: ["id"] + }, + ] + } config: { Row: { - billing_provider: Database['public']['Enums']['billing_provider']; - enable_account_billing: boolean; - enable_team_account_billing: boolean; - enable_team_accounts: boolean; - }; + billing_provider: Database["public"]["Enums"]["billing_provider"] + enable_account_billing: boolean + enable_team_account_billing: boolean + enable_team_accounts: boolean + } Insert: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } Update: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; - Relationships: []; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } + Relationships: [] + } invitations: { Row: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + personal_code: string | null + role: string + updated_at: string + } Insert: { - account_id: string; - created_at?: string; - email: string; - expires_at?: string; - id?: number; - invite_token: string; - invited_by: string; - role: string; - updated_at?: string; - }; + account_id: string + created_at?: string + email: string + expires_at?: string + id?: number + invite_token: string + invited_by: string + personal_code?: string | null + role: string + updated_at?: string + } Update: { - account_id?: string; - created_at?: string; - email?: string; - expires_at?: string; - id?: number; - invite_token?: string; - invited_by?: string; - role?: string; - updated_at?: string; - }; + account_id?: string + created_at?: string + email?: string + expires_at?: string + id?: number + invite_token?: string + invited_by?: string + personal_code?: string | null + role?: string + updated_at?: string + } Relationships: [ { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'invitations_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "invitations_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] + }, + ] + } nonces: { Row: { - client_token: string; - created_at: string; - description: string | null; - expires_at: string; - id: string; - last_verification_at: string | null; - last_verification_ip: unknown | null; - last_verification_user_agent: string | null; - metadata: Json | null; - nonce: string; - purpose: string; - revoked: boolean; - revoked_reason: string | null; - scopes: string[] | null; - tags: string[] | null; - used_at: string | null; - user_id: string | null; - verification_attempts: number; - }; + client_token: string + created_at: string + expires_at: string + id: string + last_verification_at: string | null + last_verification_ip: unknown | null + last_verification_user_agent: string | null + metadata: Json | null + nonce: string + purpose: string + revoked: boolean + revoked_reason: string | null + scopes: string[] | null + used_at: string | null + user_id: string | null + verification_attempts: number + } Insert: { - client_token: string; - created_at?: string; - description?: string | null; - expires_at: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce: string; - purpose: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; + client_token: string + created_at?: string + expires_at: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown | null + last_verification_user_agent?: string | null + metadata?: Json | null + nonce: string + purpose: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } Update: { - client_token?: string; - created_at?: string; - description?: string | null; - expires_at?: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce?: string; - purpose?: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; - Relationships: []; - }; + client_token?: string + created_at?: string + expires_at?: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown | null + last_verification_user_agent?: string | null + metadata?: Json | null + nonce?: string + purpose?: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } + Relationships: [] + } notifications: { Row: { - account_id: string; - body: string; - channel: Database['public']['Enums']['notification_channel']; - created_at: string; - dismissed: boolean; - expires_at: string | null; - id: number; - link: string | null; - type: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel: Database["public"]["Enums"]["notification_channel"] + created_at: string + dismissed: boolean + expires_at: string | null + id: number + link: string | null + type: Database["public"]["Enums"]["notification_type"] + } Insert: { - account_id: string; - body: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Update: { - account_id?: string; - body?: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id?: string + body?: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Relationships: [ { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, - ]; - }; + { + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] + }, + { + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + ] + } order_items: { Row: { - created_at: string; - id: string; - order_id: string; - price_amount: number | null; - product_id: string; - quantity: number; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + order_id: string + price_amount: number | null + product_id: string + quantity: number + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - order_id: string; - price_amount?: number | null; - product_id: string; - quantity?: number; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + order_id: string + price_amount?: number | null + product_id: string + quantity?: number + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - order_id?: string; - price_amount?: number | null; - product_id?: string; - quantity?: number; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + order_id?: string + price_amount?: number | null + product_id?: string + quantity?: number + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'order_items_order_id_fkey'; - columns: ['order_id']; - isOneToOne: false; - referencedRelation: 'orders'; - referencedColumns: ['id']; + foreignKeyName: "order_items_order_id_fkey" + columns: ["order_id"] + isOneToOne: false + referencedRelation: "orders" + referencedColumns: ["id"] }, - ]; - }; + ] + } orders: { Row: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } Insert: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at?: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at?: string + } Update: { - account_id?: string; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency?: string; - id?: string; - status?: Database['public']['Enums']['payment_status']; - total_amount?: number; - updated_at?: string; - }; + account_id?: string + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency?: string + id?: string + status?: Database["public"]["Enums"]["payment_status"] + total_amount?: number + updated_at?: string + } Relationships: [ { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'orders_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; + { + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "orders_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] + }, + ] + } role_permissions: { Row: { - id: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Insert: { - id?: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id?: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Update: { - id?: number; - permission?: Database['public']['Enums']['app_permissions']; - role?: string; - }; + id?: number + permission?: Database["public"]["Enums"]["app_permissions"] + role?: string + } Relationships: [ { - foreignKeyName: 'role_permissions_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "role_permissions_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; + ] + } roles: { Row: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Insert: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Update: { - hierarchy_level?: number; - name?: string; - }; - Relationships: []; - }; + hierarchy_level?: number + name?: string + } + Relationships: [] + } subscription_items: { Row: { - created_at: string; - id: string; - interval: string; - interval_count: number; - price_amount: number | null; - product_id: string; - quantity: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + interval: string + interval_count: number + price_amount: number | null + product_id: string + quantity: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - interval: string; - interval_count: number; - price_amount?: number | null; - product_id: string; - quantity?: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + interval: string + interval_count: number + price_amount?: number | null + product_id: string + quantity?: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - interval?: string; - interval_count?: number; - price_amount?: number | null; - product_id?: string; - quantity?: number; - subscription_id?: string; - type?: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + interval?: string + interval_count?: number + price_amount?: number | null + product_id?: string + quantity?: number + subscription_id?: string + type?: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'subscription_items_subscription_id_fkey'; - columns: ['subscription_id']; - isOneToOne: false; - referencedRelation: 'subscriptions'; - referencedColumns: ['id']; + foreignKeyName: "subscription_items_subscription_id_fkey" + columns: ["subscription_id"] + isOneToOne: false + referencedRelation: "subscriptions" + referencedColumns: ["id"] }, - ]; - }; + ] + } subscriptions: { Row: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } Insert: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at?: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at?: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Update: { - account_id?: string; - active?: boolean; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - cancel_at_period_end?: boolean; - created_at?: string; - currency?: string; - id?: string; - period_ends_at?: string; - period_starts_at?: string; - status?: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id?: string + active?: boolean + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end?: boolean + created_at?: string + currency?: string + id?: string + period_ends_at?: string + period_starts_at?: string + status?: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Relationships: [ { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "invitations_with_personal_accounts" + referencedColumns: ["account_id"] }, { - foreignKeyName: 'subscriptions_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, - ]; - }; - }; + { + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] + }, + { + foreignKeyName: "subscriptions_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] + }, + ] + } + } Views: { + invitations_with_accounts: { + Row: { + account_id: string | null + invite_token: string | null + personal_code: string | null + } + Relationships: [] + } + invitations_with_personal_accounts: { + Row: { + account_id: string | null + account_slug: string | null + invite_token: string | null + personal_code: string | null + } + Relationships: [] + } user_account_workspace: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; + id: string | null + name: string | null + picture_url: string | null subscription_status: - | Database['public']['Enums']['subscription_status'] - | null; - }; - Relationships: []; - }; + | Database["public"]["Enums"]["subscription_status"] + | null + } + Relationships: [] + } user_accounts: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; - role: string | null; - slug: string | null; - }; + id: string | null + name: string | null + picture_url: string | null + role: string | null + slug: string | null + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; - }; + ] + } + } Functions: { accept_invitation: { - Args: { - token: string; - user_id: string; - }; - Returns: string; - }; + Args: { token: string; user_id: string } + Returns: string + } add_invitations_to_account: { Args: { - account_slug: string; - invitations: Database['public']['CompositeTypes']['invitation'][]; - }; - Returns: Database['public']['Tables']['invitations']['Row'][]; - }; + account_slug: string + invitations: Database["public"]["CompositeTypes"]["invitation"][] + } + Returns: Database["public"]["Tables"]["invitations"]["Row"][] + } can_action_account_member: { - Args: { - target_team_account_id: string; - target_user_id: string; - }; - Returns: boolean; - }; + Args: { target_team_account_id: string; target_user_id: string } + Returns: boolean + } + check_personal_code_exists: { + Args: { code: string } + Returns: boolean + } create_invitation: { - Args: { - account_id: string; - email: string; - role: string; - }; + Args: { account_id: string; email: string; role: string } Returns: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + personal_code: string | null + role: string + updated_at: string + } + } create_nonce: { Args: { - p_user_id?: string; - p_purpose?: string; - p_expires_in_seconds?: number; - p_metadata?: Json; - p_description?: string; - p_tags?: string[]; - p_scopes?: string[]; - p_revoke_previous?: boolean; - }; - Returns: Json; - }; + p_user_id?: string + p_purpose?: string + p_expires_in_seconds?: number + p_metadata?: Json + p_scopes?: string[] + p_revoke_previous?: boolean + } + Returns: Json + } create_team_account: { - Args: { - account_name: string; - }; + Args: { account_name: string } Returns: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + personal_code: string | null + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } + } get_account_invitations: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: number; - email: string; - account_id: string; - invited_by: string; - role: string; - created_at: string; - updated_at: string; - expires_at: string; - inviter_name: string; - inviter_email: string; - }[]; - }; + id: number + email: string + account_id: string + invited_by: string + role: string + created_at: string + updated_at: string + expires_at: string + personal_code: string + inviter_name: string + inviter_email: string + }[] + } get_account_members: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - user_id: string; - account_id: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - name: string; - email: string; - picture_url: string; - created_at: string; - updated_at: string; - }[]; - }; + id: string + user_id: string + account_id: string + role: string + role_hierarchy_level: number + primary_owner_user_id: string + name: string + email: string + personal_code: string + picture_url: string + created_at: string + updated_at: string + }[] + } get_config: { - Args: Record; - Returns: Json; - }; + Args: Record + Returns: Json + } + get_invitations_with_account_ids: { + Args: { company_id: string; personal_codes: string[] } + Returns: { + invite_token: string + personal_code: string + account_id: string + }[] + } get_nonce_status: { - Args: { - p_id: string; - }; - Returns: Json; - }; + Args: { p_id: string } + Returns: Json + } get_upper_system_role: { - Args: Record; - Returns: string; - }; + Args: Record + Returns: string + } has_active_subscription: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } has_more_elevated_role: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; + target_user_id: string + target_account_id: string + role_name: string + } + Returns: boolean + } has_permission: { Args: { - user_id: string; - account_id: string; - permission_name: Database['public']['Enums']['app_permissions']; - }; - Returns: boolean; - }; + user_id: string + account_id: string + permission_name: Database["public"]["Enums"]["app_permissions"] + } + Returns: boolean + } has_role_on_account: { - Args: { - account_id: string; - account_role?: string; - }; - Returns: boolean; - }; + Args: { account_id: string; account_role?: string } + Returns: boolean + } has_same_role_hierarchy_level: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; - install_extensions: { - Args: Record; - Returns: undefined; - }; + target_user_id: string + target_account_id: string + role_name: string + } + Returns: boolean + } is_aal2: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_account_owner: { - Args: { - account_id: string; - }; - Returns: boolean; - }; + Args: { account_id: string } + Returns: boolean + } is_account_team_member: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } + is_company_admin: { + Args: { account_slug: string } + Returns: boolean + } is_mfa_compliant: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_set: { - Args: { - field_name: string; - }; - Returns: boolean; - }; + Args: { field_name: string } + Returns: boolean + } is_super_admin: { - Args: Record; - Returns: boolean; - }; + Args: Record + Returns: boolean + } is_team_member: { - Args: { - account_id: string; - user_id: string; - }; - Returns: boolean; - }; + Args: { account_id: string; user_id: string } + Returns: boolean + } revoke_nonce: { - Args: { - p_id: string; - p_reason?: string; - }; - Returns: boolean; - }; + Args: { p_id: string; p_reason?: string } + Returns: boolean + } team_account_workspace: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - name: string; - picture_url: string; - slug: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - subscription_status: Database['public']['Enums']['subscription_status']; - permissions: Database['public']['Enums']['app_permissions'][]; - }[]; - }; + id: string + name: string + picture_url: string + slug: string + role: string + role_hierarchy_level: number + primary_owner_user_id: string + subscription_status: Database["public"]["Enums"]["subscription_status"] + permissions: Database["public"]["Enums"]["app_permissions"][] + }[] + } transfer_team_account_ownership: { - Args: { - target_account_id: string; - new_owner_id: string; - }; - Returns: undefined; - }; + Args: { target_account_id: string; new_owner_id: string } + Returns: undefined + } upsert_order: { Args: { - target_account_id: string; - target_customer_id: string; - target_order_id: string; - status: Database['public']['Enums']['payment_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - total_amount: number; - currency: string; - line_items: Json; - }; + target_account_id: string + target_customer_id: string + target_order_id: string + status: Database["public"]["Enums"]["payment_status"] + billing_provider: Database["public"]["Enums"]["billing_provider"] + total_amount: number + currency: string + line_items: Json + } Returns: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } + } upsert_subscription: { Args: { - target_account_id: string; - target_customer_id: string; - target_subscription_id: string; - active: boolean; - status: Database['public']['Enums']['subscription_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - currency: string; - period_starts_at: string; - period_ends_at: string; - line_items: Json; - trial_starts_at?: string; - trial_ends_at?: string; - }; + target_account_id: string + target_customer_id: string + target_subscription_id: string + active: boolean + status: Database["public"]["Enums"]["subscription_status"] + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + currency: string + period_starts_at: string + period_ends_at: string + line_items: Json + trial_starts_at?: string + trial_ends_at?: string + } Returns: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } + } verify_nonce: { Args: { - p_token: string; - p_purpose: string; - p_user_id?: string; - p_required_scopes?: string[]; - p_max_verification_attempts?: number; - p_ip?: unknown; - p_user_agent?: string; - }; - Returns: Json; - }; - }; + p_token: string + p_purpose: string + p_user_id?: string + p_required_scopes?: string[] + p_max_verification_attempts?: number + p_ip?: unknown + p_user_agent?: string + } + Returns: Json + } + } Enums: { + analysis_order_status: + | "QUEUED" + | "ON_HOLD" + | "PROCESSING" + | "COMPLETED" + | "REJECTED" + | "CANCELLED" app_permissions: - | 'roles.manage' - | 'billing.manage' - | 'settings.manage' - | 'members.manage' - | 'invites.manage'; - billing_provider: 'stripe' | 'lemon-squeezy' | 'paddle'; - notification_channel: 'in_app' | 'email'; - notification_type: 'info' | 'warning' | 'error'; - payment_status: 'pending' | 'succeeded' | 'failed'; - subscription_item_type: 'flat' | 'per_seat' | 'metered'; + | "roles.manage" + | "billing.manage" + | "settings.manage" + | "members.manage" + | "invites.manage" + billing_provider: "stripe" | "lemon-squeezy" | "paddle" + notification_channel: "in_app" | "email" + notification_type: "info" | "warning" | "error" + payment_status: "pending" | "succeeded" | "failed" + subscription_item_type: "flat" | "per_seat" | "metered" subscription_status: - | 'active' - | 'trialing' - | 'past_due' - | 'canceled' - | 'unpaid' - | 'incomplete' - | 'incomplete_expired' - | 'paused'; - }; + | "active" + | "trialing" + | "past_due" + | "canceled" + | "unpaid" + | "incomplete" + | "incomplete_expired" + | "paused" + } CompositeTypes: { invitation: { - email: string | null; - role: string | null; - }; - }; - }; - storage: { - Tables: { - buckets: { - Row: { - allowed_mime_types: string[] | null; - avif_autodetection: boolean | null; - created_at: string | null; - file_size_limit: number | null; - id: string; - name: string; - owner: string | null; - owner_id: string | null; - public: boolean | null; - updated_at: string | null; - }; - Insert: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id: string; - name: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; - Update: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id?: string; - name?: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; - Relationships: []; - }; - migrations: { - Row: { - executed_at: string | null; - hash: string; - id: number; - name: string; - }; - Insert: { - executed_at?: string | null; - hash: string; - id: number; - name: string; - }; - Update: { - executed_at?: string | null; - hash?: string; - id?: number; - name?: string; - }; - Relationships: []; - }; - objects: { - Row: { - bucket_id: string | null; - created_at: string | null; - id: string; - last_accessed_at: string | null; - metadata: Json | null; - name: string | null; - owner: string | null; - owner_id: string | null; - path_tokens: string[] | null; - updated_at: string | null; - user_metadata: Json | null; - version: string | null; - }; - Insert: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; - Update: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; - Relationships: [ - { - foreignKeyName: 'objects_bucketId_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - ]; - }; - s3_multipart_uploads: { - Row: { - bucket_id: string; - created_at: string; - id: string; - in_progress_size: number; - key: string; - owner_id: string | null; - upload_signature: string; - user_metadata: Json | null; - version: string; - }; - Insert: { - bucket_id: string; - created_at?: string; - id: string; - in_progress_size?: number; - key: string; - owner_id?: string | null; - upload_signature: string; - user_metadata?: Json | null; - version: string; - }; - Update: { - bucket_id?: string; - created_at?: string; - id?: string; - in_progress_size?: number; - key?: string; - owner_id?: string | null; - upload_signature?: string; - user_metadata?: Json | null; - version?: string; - }; - Relationships: [ - { - foreignKeyName: 's3_multipart_uploads_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - ]; - }; - s3_multipart_uploads_parts: { - Row: { - bucket_id: string; - created_at: string; - etag: string; - id: string; - key: string; - owner_id: string | null; - part_number: number; - size: number; - upload_id: string; - version: string; - }; - Insert: { - bucket_id: string; - created_at?: string; - etag: string; - id?: string; - key: string; - owner_id?: string | null; - part_number: number; - size?: number; - upload_id: string; - version: string; - }; - Update: { - bucket_id?: string; - created_at?: string; - etag?: string; - id?: string; - key?: string; - owner_id?: string | null; - part_number?: number; - size?: number; - upload_id?: string; - version?: string; - }; - Relationships: [ - { - foreignKeyName: 's3_multipart_uploads_parts_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; - }, - { - foreignKeyName: 's3_multipart_uploads_parts_upload_id_fkey'; - columns: ['upload_id']; - isOneToOne: false; - referencedRelation: 's3_multipart_uploads'; - referencedColumns: ['id']; - }, - ]; - }; - }; - Views: { - [_ in never]: never; - }; - Functions: { - can_insert_object: { - Args: { - bucketid: string; - name: string; - owner: string; - metadata: Json; - }; - Returns: undefined; - }; - extension: { - Args: { - name: string; - }; - Returns: string; - }; - filename: { - Args: { - name: string; - }; - Returns: string; - }; - foldername: { - Args: { - name: string; - }; - Returns: string[]; - }; - get_size_by_bucket: { - Args: Record; - Returns: { - size: number; - bucket_id: string; - }[]; - }; - list_multipart_uploads_with_delimiter: { - Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - next_key_token?: string; - next_upload_token?: string; - }; - Returns: { - key: string; - id: string; - created_at: string; - }[]; - }; - list_objects_with_delimiter: { - Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - start_after?: string; - next_token?: string; - }; - Returns: { - name: string; - id: string; - metadata: Json; - updated_at: string; - }[]; - }; - operation: { - Args: Record; - Returns: string; - }; - search: { - Args: { - prefix: string; - bucketname: string; - limits?: number; - levels?: number; - offsets?: number; - search?: string; - sortcolumn?: string; - sortorder?: string; - }; - Returns: { - name: string; - id: string; - updated_at: string; - created_at: string; - last_accessed_at: string; - metadata: Json; - }[]; - }; - }; - Enums: { - [_ in never]: never; - }; - CompositeTypes: { - [_ in never]: never; - }; - }; -}; + email: string | null + role: string | null + personal_code: string | null + } + } + } +} -type PublicSchema = Database[Extract]; +type DefaultSchema = Database[Extract] export type Tables< - PublicTableNameOrOptions extends - | keyof (PublicSchema['Tables'] & PublicSchema['Views']) + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views']) + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { - Row: infer R; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & - PublicSchema['Views']) - ? (PublicSchema['Tables'] & - PublicSchema['Views'])[PublicTableNameOrOptions] extends { - Row: infer R; + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R } ? R : never - : never; + : never export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Insert: infer I; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I } ? I : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Insert: infer I; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I } ? I : never - : never; + : never export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Update: infer U; +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U } ? U : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Update: infer U; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U } ? U : never - : never; + : never export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema['Enums'] + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] | { schema: keyof Database }, - EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] : never = never, -> = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] - ? PublicSchema['Enums'][PublicEnumNameOrOptions] - : never; +> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never export type CompositeTypes< PublicCompositeTypeNameOrOptions extends - | keyof PublicSchema['CompositeTypes'] + | keyof DefaultSchema["CompositeTypes"] | { schema: keyof Database }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database; + schema: keyof Database } - ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] : never = never, > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } - ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] - : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] - ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] - : never; + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + audit: { + Enums: { + sync_status: ["SUCCESS", "FAIL"], + }, + }, + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + analysis_order_status: [ + "QUEUED", + "ON_HOLD", + "PROCESSING", + "COMPLETED", + "REJECTED", + "CANCELLED", + ], + app_permissions: [ + "roles.manage", + "billing.manage", + "settings.manage", + "members.manage", + "invites.manage", + ], + billing_provider: ["stripe", "lemon-squeezy", "paddle"], + notification_channel: ["in_app", "email"], + notification_type: ["info", "warning", "error"], + payment_status: ["pending", "succeeded", "failed"], + subscription_item_type: ["flat", "per_seat", "metered"], + subscription_status: [ + "active", + "trialing", + "past_due", + "canceled", + "unpaid", + "incomplete", + "incomplete_expired", + "paused", + ], + }, + }, +} as const + diff --git a/packages/supabase/src/hooks/use-sign-up-with-email-password.ts b/packages/supabase/src/hooks/use-sign-up-with-email-password.ts index 821482f..a387d0e 100644 --- a/packages/supabase/src/hooks/use-sign-up-with-email-password.ts +++ b/packages/supabase/src/hooks/use-sign-up-with-email-password.ts @@ -3,6 +3,7 @@ import { useMutation } from '@tanstack/react-query'; import { useSupabase } from './use-supabase'; interface Credentials { + personalCode: string; email: string; password: string; emailRedirectTo: string; @@ -14,13 +15,17 @@ export function useSignUpWithEmailAndPassword() { const mutationKey = ['auth', 'sign-up-with-email-password']; const mutationFn = async (params: Credentials) => { - const { emailRedirectTo, captchaToken, ...credentials } = params; - + const { emailRedirectTo, captchaToken, personalCode, ...credentials } = params; + + // TODO?: should be a validation of unique personal code before registration const response = await client.auth.signUp({ ...credentials, options: { emailRedirectTo, captchaToken, + data: { + personalCode + } }, }); diff --git a/public/locales/en/billing.json b/public/locales/en/billing.json index 84c849e..b9f6155 100644 --- a/public/locales/en/billing.json +++ b/public/locales/en/billing.json @@ -12,12 +12,12 @@ "cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.", "renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}", "noPermissionsAlertHeading": "You don't have permissions to change the billing settings", - "noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.", + "noPermissionsAlertBody": "Please contact your account admin to change the billing settings for your account.", "checkoutSuccessTitle": "Done! You're all set.", "checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.", "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", - "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", + "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account admin.", "manageTeamPlan": "Manage your Company Plan", "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per company employee", + "perTeamMember": "Per company member", "perUnit": "Per {{unit}} usage", - "teamMembers": "Company Employees", + "teamMembers": "Company Members", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 8aade69..ccf6df6 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Company Employees", - "membersTabDescription": "Here you can manage the employees of your company.", + "accountMembers": "Company Members", + "membersTabDescription": "Here you can manage the members of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Employees", + "members": "Members", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -67,10 +67,10 @@ }, "roles": { "owner": { - "label": "Owner" + "label": "Admin" }, "member": { - "label": "Employee" + "label": "Member" } }, "otp": { diff --git a/public/locales/en/teams.json b/public/locales/en/teams.json index d09d78d..6a683e2 100644 --- a/public/locales/en/teams.json +++ b/public/locales/en/teams.json @@ -13,7 +13,7 @@ "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Employees" + "pageTitle": "Members" }, "billing": { "pageTitle": "Billing" @@ -23,17 +23,17 @@ "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Employees", + "membersTabLabel": "Members", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", "roleLabel": "Role", - "primaryOwnerLabel": "Primary Owner", + "primaryOwnerLabel": "Primary Admin", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite employees to your Company", + "inviteMembersPageSubheading": "Invite members to your Company", "createTeamModalHeading": "Create Company", - "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "createTeamModalDescription": "Create a new Company to manage your projects and members.", "teamNameLabel": "Company Name", "teamNameDescription": "Your company name should be unique and descriptive", "createTeamSubmitLabel": "Create Company", @@ -44,34 +44,34 @@ "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Employees invited successfully!", + "inviteMembersSuccess": "Members invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting employees...", + "inviteMembersLoading": "Inviting members...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", - "removeMemberSuccessMessage": "Employee removed successfully", + "removeMemberModalDescription": "Remove this member from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Member removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", - "removeMemberLoadingMessage": "Removing employee...", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", + "removeMemberLoadingMessage": "Removing member...", "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Employee's Role", + "updateMemberRoleModalHeading": "Update Member's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", + "transferOwnershipDescription": "Transfer ownership of the company account to another member.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary admin of the company account.", "deleteInvitation": "Delete Invitation", "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", @@ -92,21 +92,21 @@ "teamLogoInputHeading": "Upload your company's Logo", "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", "updateTeamSubmitLabel": "Update Company", - "inviteMembersHeading": "Invite Employees to your Company", - "inviteMembersDescription": "Invite employees to your company by entering their email and role.", - "emailPlaceholder": "employee@email.com", - "membersPageHeading": "Employees", - "inviteMembersButton": "Invite Employees", - "invitingMembers": "Inviting employees...", - "inviteMembersSuccessMessage": "Employees invited successfully", - "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", + "inviteMembersHeading": "Invite Members to your Company", + "inviteMembersDescription": "Invite member to your company by entering their email and role.", + "emailPlaceholder": "member@email.com", + "membersPageHeading": "Members", + "inviteMembersButton": "Invite Members", + "invitingMembers": "Inviting members...", + "inviteMembersSuccessMessage": "Members invited successfully", + "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading employees...", - "loadMembersError": "Sorry, we couldn't fetch your company's employees.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", - "loadingInvitedMembers": "Loading invited employees...", + "loadingMembers": "Loading members...", + "loadMembersError": "Sorry, we couldn't fetch your company's members.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited members.", + "loadingInvitedMembers": "Loading invited members...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", @@ -126,13 +126,13 @@ "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", - "searchMembersPlaceholder": "Search employees", + "searchMembersPlaceholder": "Search members", "createTeamErrorHeading": "Sorry, we couldn't create your company.", "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,7 +144,7 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company admin to renew the invite.", "backToHome": "Back to Home", "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", @@ -159,5 +159,6 @@ "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", - "specialCharactersError": "This name cannot contain special characters. Please choose a different one." + "specialCharactersError": "This name cannot contain special characters. Please choose a different one.", + "personalCode": "Personal Code" } diff --git a/public/locales/et/billing.json b/public/locales/et/billing.json index 84c849e..b9f6155 100644 --- a/public/locales/et/billing.json +++ b/public/locales/et/billing.json @@ -12,12 +12,12 @@ "cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.", "renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}", "noPermissionsAlertHeading": "You don't have permissions to change the billing settings", - "noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.", + "noPermissionsAlertBody": "Please contact your account admin to change the billing settings for your account.", "checkoutSuccessTitle": "Done! You're all set.", "checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.", "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", - "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", + "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account admin.", "manageTeamPlan": "Manage your Company Plan", "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per company employee", + "perTeamMember": "Per company member", "perUnit": "Per {{unit}} usage", - "teamMembers": "Company Employees", + "teamMembers": "Company Members", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/et/common.json b/public/locales/et/common.json index 8aade69..ccf6df6 100644 --- a/public/locales/et/common.json +++ b/public/locales/et/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Company Employees", - "membersTabDescription": "Here you can manage the employees of your company.", + "accountMembers": "Company Members", + "membersTabDescription": "Here you can manage the members of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Employees", + "members": "Members", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -67,10 +67,10 @@ }, "roles": { "owner": { - "label": "Owner" + "label": "Admin" }, "member": { - "label": "Employee" + "label": "Member" } }, "otp": { diff --git a/public/locales/et/marketing.json b/public/locales/et/marketing.json index 3deb11a..a214fc2 100644 --- a/public/locales/et/marketing.json +++ b/public/locales/et/marketing.json @@ -36,5 +36,5 @@ "contactErrorDescription": "An error occurred while sending your message. Please try again later", "footerDescription": "Here you can add a description about your company or product", "copyright": "© Copyright {{year}} {{product}}. All Rights Reserved.", - "heroSubtitle": "Lihtne, mugav ja kiire ülevaade oma tervisest" + "heroSubtitle": "A simple, convenient, and quick overview of your health condition" } diff --git a/public/locales/et/teams.json b/public/locales/et/teams.json index d09d78d..9500fd3 100644 --- a/public/locales/et/teams.json +++ b/public/locales/et/teams.json @@ -13,7 +13,7 @@ "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Employees" + "pageTitle": "Members" }, "billing": { "pageTitle": "Billing" @@ -23,17 +23,17 @@ "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Employees", + "membersTabLabel": "Members", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", "roleLabel": "Role", - "primaryOwnerLabel": "Primary Owner", + "primaryOwnerLabel": "Primary Admin", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite employees to your Company", + "inviteMembersPageSubheading": "Invite members to your Company", "createTeamModalHeading": "Create Company", - "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "createTeamModalDescription": "Create a new Company to manage your projects and members.", "teamNameLabel": "Company Name", "teamNameDescription": "Your company name should be unique and descriptive", "createTeamSubmitLabel": "Create Company", @@ -44,34 +44,34 @@ "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Employees invited successfully!", + "inviteMembersSuccess": "Members invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting employees...", + "inviteMembersLoading": "Inviting members...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", - "removeMemberSuccessMessage": "Employee removed successfully", + "removeMemberModalDescription": "Remove this member from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Member removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", - "removeMemberLoadingMessage": "Removing employee...", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", + "removeMemberLoadingMessage": "Removing member...", "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Employee's Role", + "updateMemberRoleModalHeading": "Update Member's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", + "transferOwnershipDescription": "Transfer ownership of the company account to another member.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary admin of the company account.", "deleteInvitation": "Delete Invitation", "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", @@ -92,21 +92,21 @@ "teamLogoInputHeading": "Upload your company's Logo", "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", "updateTeamSubmitLabel": "Update Company", - "inviteMembersHeading": "Invite Employees to your Company", - "inviteMembersDescription": "Invite employees to your company by entering their email and role.", - "emailPlaceholder": "employee@email.com", - "membersPageHeading": "Employees", - "inviteMembersButton": "Invite Employees", - "invitingMembers": "Inviting employees...", - "inviteMembersSuccessMessage": "Employees invited successfully", - "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", + "inviteMembersHeading": "Invite Members to your Company", + "inviteMembersDescription": "Invite member to your company by entering their email and role.", + "emailPlaceholder": "member@email.com", + "membersPageHeading": "Members", + "inviteMembersButton": "Invite Members", + "invitingMembers": "Inviting members...", + "inviteMembersSuccessMessage": "Members invited successfully", + "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading employees...", - "loadMembersError": "Sorry, we couldn't fetch your company's employees.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", - "loadingInvitedMembers": "Loading invited employees...", + "loadingMembers": "Loading members...", + "loadMembersError": "Sorry, we couldn't fetch your company's members.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited members.", + "loadingInvitedMembers": "Loading invited members...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", @@ -126,13 +126,13 @@ "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", - "searchMembersPlaceholder": "Search employees", + "searchMembersPlaceholder": "Search members", "createTeamErrorHeading": "Sorry, we couldn't create your company.", "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,7 +144,7 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company admin to renew the invite.", "backToHome": "Back to Home", "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", @@ -159,5 +159,6 @@ "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", - "specialCharactersError": "This name cannot contain special characters. Please choose a different one." + "specialCharactersError": "This name cannot contain special characters. Please choose a different one.", + "personalCode": "Isikukood" } diff --git a/public/locales/ru/billing.json b/public/locales/ru/billing.json index 84c849e..b9f6155 100644 --- a/public/locales/ru/billing.json +++ b/public/locales/ru/billing.json @@ -12,12 +12,12 @@ "cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.", "renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}", "noPermissionsAlertHeading": "You don't have permissions to change the billing settings", - "noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.", + "noPermissionsAlertBody": "Please contact your account admin to change the billing settings for your account.", "checkoutSuccessTitle": "Done! You're all set.", "checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.", "checkoutSuccessBackButton": "Proceed to App", "cannotManageBillingAlertTitle": "You cannot manage billing", - "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.", + "cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account admin.", "manageTeamPlan": "Manage your Company Plan", "manageTeamPlanDescription": "Choose a plan that fits your company's needs. You can upgrade or downgrade your plan at any time.", "basePlan": "Base Plan", @@ -34,9 +34,9 @@ "redirectingToPayment": "Redirecting to checkout. Please wait...", "proceedToPayment": "Proceed to Payment", "startTrial": "Start Trial", - "perTeamMember": "Per company employee", + "perTeamMember": "Per company member", "perUnit": "Per {{unit}} usage", - "teamMembers": "Company Employees", + "teamMembers": "Company Members", "includedUpTo": "Up to {{upTo}} {{unit}} included in the plan", "fromPreviousTierUpTo": "for each {{unit}} for the next {{ upTo }} {{ unit }}", "andAbove": "above {{ previousTier }} {{ unit }}", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index 8aade69..ccf6df6 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -1,8 +1,8 @@ { "homeTabLabel": "Home", "homeTabDescription": "Welcome to your home page", - "accountMembers": "Company Employees", - "membersTabDescription": "Here you can manage the employees of your company.", + "accountMembers": "Company Members", + "membersTabDescription": "Here you can manage the members of your company.", "billingTabLabel": "Billing", "billingTabDescription": "Manage your billing and subscription", "dashboardTabLabel": "Dashboard", @@ -58,7 +58,7 @@ "routes": { "home": "Home", "account": "Account", - "members": "Employees", + "members": "Members", "billing": "Billing", "dashboard": "Dashboard", "settings": "Settings", @@ -67,10 +67,10 @@ }, "roles": { "owner": { - "label": "Owner" + "label": "Admin" }, "member": { - "label": "Employee" + "label": "Member" } }, "otp": { diff --git a/public/locales/ru/teams.json b/public/locales/ru/teams.json index d09d78d..5a63f7e 100644 --- a/public/locales/ru/teams.json +++ b/public/locales/ru/teams.json @@ -13,7 +13,7 @@ "dangerZoneDescription": "This section contains actions that are irreversible" }, "members": { - "pageTitle": "Employees" + "pageTitle": "Members" }, "billing": { "pageTitle": "Billing" @@ -23,17 +23,17 @@ "creatingTeam": "Creating Company...", "personalAccount": "Personal Account", "searchAccount": "Search Account...", - "membersTabLabel": "Employees", + "membersTabLabel": "Members", "memberName": "Name", "youLabel": "You", "emailLabel": "Email", "roleLabel": "Role", - "primaryOwnerLabel": "Primary Owner", + "primaryOwnerLabel": "Primary Admin", "joinedAtLabel": "Joined at", "invitedAtLabel": "Invited at", - "inviteMembersPageSubheading": "Invite employees to your Company", + "inviteMembersPageSubheading": "Invite members to your Company", "createTeamModalHeading": "Create Company", - "createTeamModalDescription": "Create a new Company to manage your projects and employees.", + "createTeamModalDescription": "Create a new Company to manage your projects and members.", "teamNameLabel": "Company Name", "teamNameDescription": "Your company name should be unique and descriptive", "createTeamSubmitLabel": "Create Company", @@ -44,34 +44,34 @@ "createTeamDropdownLabel": "New company", "changeRole": "Change Role", "removeMember": "Remove from Account", - "inviteMembersSuccess": "Employees invited successfully!", + "inviteMembersSuccess": "Members invited successfully!", "inviteMembersError": "Sorry, we encountered an error! Please try again", - "inviteMembersLoading": "Inviting employees...", + "inviteMembersLoading": "Inviting members...", "removeInviteButtonLabel": "Remove invite", "addAnotherMemberButtonLabel": "Add another one", "inviteMembersButtonLabel": "Send Invites", "removeMemberModalHeading": "You are removing this user", - "removeMemberModalDescription": "Remove this employee from the company. They will no longer have access to the company.", - "removeMemberSuccessMessage": "Employee removed successfully", + "removeMemberModalDescription": "Remove this member from the company. They will no longer have access to the company.", + "removeMemberSuccessMessage": "Member removed successfully", "removeMemberErrorMessage": "Sorry, we encountered an error. Please try again", - "removeMemberErrorHeading": "Sorry, we couldn't remove the selected employee.", - "removeMemberLoadingMessage": "Removing employee...", + "removeMemberErrorHeading": "Sorry, we couldn't remove the selected member.", + "removeMemberLoadingMessage": "Removing member...", "removeMemberSubmitLabel": "Remove User from Company", "chooseDifferentRoleError": "Role is the same as the current one", "updateRole": "Update Role", "updateRoleLoadingMessage": "Updating role...", "updateRoleSuccessMessage": "Role updated successfully", "updatingRoleErrorMessage": "Sorry, we encountered an error. Please try again.", - "updateMemberRoleModalHeading": "Update Employee's Role", + "updateMemberRoleModalHeading": "Update Member's Role", "updateMemberRoleModalDescription": "Change the role of the selected member. The role determines the permissions of the member.", "roleMustBeDifferent": "Role must be different from the current one", "memberRoleInputLabel": "Member role", "updateRoleDescription": "Pick a role for this member.", "updateRoleSubmitLabel": "Update Role", "transferOwnership": "Transfer Ownership", - "transferOwnershipDescription": "Transfer ownership of the company account to another employee.", + "transferOwnershipDescription": "Transfer ownership of the company account to another member.", "transferOwnershipInputLabel": "Please type TRANSFER to confirm the transfer of ownership.", - "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary owner of the company account.", + "transferOwnershipInputDescription": "By transferring ownership, you will no longer be the primary admin of the company account.", "deleteInvitation": "Delete Invitation", "deleteInvitationDialogDescription": "You are about to delete the invitation. The user will no longer be able to join the company account.", "deleteInviteSuccessMessage": "Invite deleted successfully", @@ -92,21 +92,21 @@ "teamLogoInputHeading": "Upload your company's Logo", "teamLogoInputSubheading": "Please choose a photo to upload as your company logo.", "updateTeamSubmitLabel": "Update Company", - "inviteMembersHeading": "Invite Employees to your Company", - "inviteMembersDescription": "Invite employees to your company by entering their email and role.", - "emailPlaceholder": "employee@email.com", - "membersPageHeading": "Employees", - "inviteMembersButton": "Invite Employees", - "invitingMembers": "Inviting employees...", - "inviteMembersSuccessMessage": "Employees invited successfully", - "inviteMembersErrorMessage": "Sorry, employees could not be invited. Please try again.", + "inviteMembersHeading": "Invite Members to your Company", + "inviteMembersDescription": "Invite member to your company by entering their email and role.", + "emailPlaceholder": "member@email.com", + "membersPageHeading": "Members", + "inviteMembersButton": "Invite Members", + "invitingMembers": "Inviting members...", + "inviteMembersSuccessMessage": "Members invited successfully", + "inviteMembersErrorMessage": "Sorry, members could not be invited. Please try again.", "pendingInvitesHeading": "Pending Invites", "pendingInvitesDescription": " Here you can manage the pending invitations to your company.", "noPendingInvites": "No pending invites found", - "loadingMembers": "Loading employees...", - "loadMembersError": "Sorry, we couldn't fetch your company's employees.", - "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited employees.", - "loadingInvitedMembers": "Loading invited employees...", + "loadingMembers": "Loading members...", + "loadMembersError": "Sorry, we couldn't fetch your company's members.", + "loadInvitedMembersError": "Sorry, we couldn't fetch your company's invited members.", + "loadingInvitedMembers": "Loading invited members...", "invitedBadge": "Invited", "duplicateInviteEmailError": "You have already entered this email address", "invitingOwnAccountError": "Hey, that's your email!", @@ -126,13 +126,13 @@ "leaveTeamDisclaimer": "You are leaving the company {{ teamName }}. You will no longer have access to it.", "deleteTeamErrorHeading": "Sorry, we couldn't delete your company.", "leaveTeamErrorHeading": "Sorry, we couldn't leave your company.", - "searchMembersPlaceholder": "Search employees", + "searchMembersPlaceholder": "Search members", "createTeamErrorHeading": "Sorry, we couldn't create your company.", "createTeamErrorMessage": "We encountered an error creating your company. Please try again.", "transferTeamErrorHeading": "Sorry, we couldn't transfer ownership of your company account.", "transferTeamErrorMessage": "We encountered an error transferring ownership of your company account. Please try again.", - "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected employee.", - "updateRoleErrorMessage": "We encountered an error updating the role of the selected employee. Please try again.", + "updateRoleErrorHeading": "Sorry, we couldn't update the role of the selected member.", + "updateRoleErrorMessage": "We encountered an error updating the role of the selected member. Please try again.", "searchInvitations": "Search Invitations", "updateInvitation": "Update Invitation", "removeInvitation": "Remove Invitation", @@ -144,7 +144,7 @@ "active": "Active", "inviteStatus": "Status", "inviteNotFoundOrExpired": "Invite not found or expired", - "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company HR to renew the invite.", + "inviteNotFoundOrExpiredDescription": "The invite you are looking for is either expired or does not exist. Please contact the company admin to renew the invite.", "backToHome": "Back to Home", "renewInvitationDialogDescription": "You are about to renew the invitation to {{ email }}. The user will be able to join the company.", "renewInvitationErrorTitle": "Sorry, we couldn't renew the invitation.", @@ -159,5 +159,6 @@ "leaveTeamInputLabel": "Please type LEAVE to confirm leaving the company.", "leaveTeamInputDescription": "By leaving the company, you will no longer have access to it.", "reservedNameError": "This name is reserved. Please choose a different one.", - "specialCharactersError": "This name cannot contain special characters. Please choose a different one." + "specialCharactersError": "This name cannot contain special characters. Please choose a different one.", + "personalCode": "Личный код" } diff --git a/supabase/migrations/20250618163951_alter_accounts_personal_code.sql b/supabase/migrations/20250618163951_alter_accounts_personal_code.sql new file mode 100644 index 0000000..f9075a6 --- /dev/null +++ b/supabase/migrations/20250618163951_alter_accounts_personal_code.sql @@ -0,0 +1,5 @@ +alter table public.accounts +add column if not exists personal_code char(11) unique; + +alter table public.invitations +add column if not exists personal_code char(11) unique; \ No newline at end of file diff --git a/supabase/migrations/20250619170525_add_personal_code_to_invitations.sql b/supabase/migrations/20250619170525_add_personal_code_to_invitations.sql new file mode 100644 index 0000000..073830a --- /dev/null +++ b/supabase/migrations/20250619170525_add_personal_code_to_invitations.sql @@ -0,0 +1,146 @@ +drop function if exists public.add_invitations_to_account(text, public.invitation[]); + +drop type if exists public.invitation; + +create type public.invitation as ( + email text, + role text, + personal_code char(11) +); + +create or replace function public.add_invitations_to_account ( + account_slug text, + invitations public.invitation[] +) returns public.invitations[] + set search_path = '' +as $$ +declare + new_invitation public.invitations; + all_invitations public.invitations[] := array[]::public.invitations[]; + invite_token text; + invite public.invitation; +begin + foreach invite in array invitations loop + invite_token := extensions.uuid_generate_v4(); + + insert into public.invitations ( + email, + account_id, + invited_by, + role, + invite_token, + personal_code + ) + values ( + invite.email, + (select id from public.accounts where slug = account_slug), + auth.uid(), + invite.role, + invite_token, + invite.personal_code + ) + returning * into new_invitation; + + all_invitations := array_append(all_invitations, new_invitation); + end loop; + + return all_invitations; +end; +$$ language plpgsql; + +grant execute on function public.add_invitations_to_account(text, public.invitation[]) to authenticated; + +drop function if exists public.get_account_invitations(text); + +create function public.get_account_invitations (account_slug text) +returns table ( + id integer, + email varchar(255), + account_id uuid, + invited_by uuid, + role varchar(50), + created_at timestamptz, + updated_at timestamptz, + expires_at timestamptz, + personal_code char(11), + inviter_name varchar, + inviter_email varchar +) +set search_path = '' +as $$ +begin + return query + select + invitation.id, + invitation.email, + invitation.account_id, + invitation.invited_by, + invitation.role, + invitation.created_at, + invitation.updated_at, + invitation.expires_at, + invitation.personal_code, + account.name, + account.email + from + public.invitations as invitation + join public.accounts as account on invitation.account_id = account.id + where + account.slug = account_slug; +end; +$$ language plpgsql; + +grant execute on function public.get_account_invitations(text) to authenticated, service_role; + + +drop function if exists public.get_account_members(text); + +-- Functions "public.get_account_members" +-- Function to get the members of an account by the account slug +create + or replace function public.get_account_members (account_slug text) returns table ( + id uuid, + user_id uuid, + account_id uuid, + role varchar(50), + role_hierarchy_level int, + primary_owner_user_id uuid, + name varchar, + email varchar, + personal_code char(11), + picture_url varchar, + created_at timestamptz, + updated_at timestamptz + ) language plpgsql + set + search_path = '' as $$ +begin + return QUERY + select + acc.id, + am.user_id, + am.account_id, + am.account_role, + r.hierarchy_level, + a.primary_owner_user_id, + acc.name, + acc.email, + acc.personal_code, + acc.picture_url, + am.created_at, + am.updated_at + from + public.accounts_memberships am + join public.accounts a on a.id = am.account_id + join public.accounts acc on acc.id = am.user_id + join public.roles r on r.name = am.account_role + where + a.slug = account_slug; + +end; + +$$; + +grant + execute on function public.get_account_members (text) to authenticated, + service_role; diff --git a/supabase/migrations/20250620191934_is_company_admin.sql b/supabase/migrations/20250620191934_is_company_admin.sql new file mode 100644 index 0000000..3ccbeb0 --- /dev/null +++ b/supabase/migrations/20250620191934_is_company_admin.sql @@ -0,0 +1,22 @@ +create or replace function public.is_company_admin(account_slug text) +returns boolean +set search_path = '' +language plpgsql +as $$ +declare + is_owner boolean; +begin + select exists ( + select 1 + from public.accounts_memberships am + join public.accounts a on a.id = am.account_id + where am.user_id = auth.uid() + and am.account_role = 'owner' + and a.slug = account_slug + ) into is_owner; + + return is_owner; +end; +$$; + +grant execute on function public.is_company_admin(text) to authenticated, service_role; diff --git a/supabase/migrations/20250621195718_add_personal_code_to_account_on_email_signup.sql b/supabase/migrations/20250621195718_add_personal_code_to_account_on_email_signup.sql new file mode 100644 index 0000000..eba364d --- /dev/null +++ b/supabase/migrations/20250621195718_add_personal_code_to_account_on_email_signup.sql @@ -0,0 +1,53 @@ +create or replace function kit.setup_new_user() +returns trigger +language plpgsql +security definer +set search_path = '' +as $$ +declare + user_name text; + picture_url text; + personal_code text; +begin + if new.raw_user_meta_data ->> 'name' is not null then + user_name := new.raw_user_meta_data ->> 'name'; + end if; + + if user_name is null and new.email is not null then + user_name := split_part(new.email, '@', 1); + end if; + + if user_name is null then + user_name := ''; + end if; + + if new.raw_user_meta_data ->> 'avatar_url' is not null then + picture_url := new.raw_user_meta_data ->> 'avatar_url'; + else + picture_url := null; + end if; + + personal_code := new.raw_user_meta_data ->> 'personalCode'; + + insert into public.accounts ( + id, + primary_owner_user_id, + name, + is_personal_account, + picture_url, + email, + personal_code + ) + values ( + new.id, + new.id, + user_name, + true, + picture_url, + new.email, + personal_code + ); + + return new; +end; +$$; diff --git a/supabase/migrations/20250622115016_add_rpc_get_invitations_with_account_ids.sql b/supabase/migrations/20250622115016_add_rpc_get_invitations_with_account_ids.sql new file mode 100644 index 0000000..a972122 --- /dev/null +++ b/supabase/migrations/20250622115016_add_rpc_get_invitations_with_account_ids.sql @@ -0,0 +1,20 @@ +create or replace function public.get_invitations_with_account_ids( + company_id uuid, + personal_codes text[] +) +returns table ( + invite_token text, + personal_code text, + account_id uuid +) +language sql +as $$ + select + i.invite_token, + i.personal_code, + a.id as account_id + from public.invitations i + join public.accounts a on a.personal_code = i.personal_code + where i.account_id = company_id + and i.personal_code = any(personal_codes); +$$; From a8dbc98b6231969f6ea1fc1ae416044cfb2957d8 Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Thu, 26 Jun 2025 19:46:15 +0300 Subject: [PATCH 2/7] B2B-30: clean code --- app/home/(user)/_components/home-menu-navigation.tsx | 1 - .../features/admin/src/components/admin-create-user-dialog.tsx | 2 +- .../features/team-accounts/src/components/company-guard.tsx | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/home/(user)/_components/home-menu-navigation.tsx b/app/home/(user)/_components/home-menu-navigation.tsx index bb53b77..7d78633 100644 --- a/app/home/(user)/_components/home-menu-navigation.tsx +++ b/app/home/(user)/_components/home-menu-navigation.tsx @@ -1,4 +1,3 @@ - import { If } from '@kit/ui/if'; import { AppLogo } from '~/components/app-logo'; diff --git a/packages/features/admin/src/components/admin-create-user-dialog.tsx b/packages/features/admin/src/components/admin-create-user-dialog.tsx index 0b71f81..5b4bffc 100644 --- a/packages/features/admin/src/components/admin-create-user-dialog.tsx +++ b/packages/features/admin/src/components/admin-create-user-dialog.tsx @@ -109,7 +109,7 @@ export function AdminCreateUserDialog(props: React.PropsWithChildren) { diff --git a/packages/features/team-accounts/src/components/company-guard.tsx b/packages/features/team-accounts/src/components/company-guard.tsx index c146073..6762439 100644 --- a/packages/features/team-accounts/src/components/company-guard.tsx +++ b/packages/features/team-accounts/src/components/company-guard.tsx @@ -22,7 +22,6 @@ export function CompanyGuard( [isSuperAdmin(client), isCompanyAdmin(client, account)] ); - console.log({ isUserSuperAdmin, isUserCompanyAdmin , params: account}) if (isUserSuperAdmin || isUserCompanyAdmin) { return ; } From fbbc2f87603a191d2254f99a17f4ea930627bcdd Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Sun, 29 Jun 2025 19:25:50 +0300 Subject: [PATCH 3/7] B2B-31: refactor profile menu, header --- .../_components/home-menu-navigation.tsx | 39 +++++++------ .../team-account-navigation-menu.tsx | 35 +++++------ .../server/team-account-workspace.loader.ts | 9 +-- app/home/[account]/layout.tsx | 2 +- .../personal-account-dropdown-container.tsx | 8 ++- .../src/components/account-selector.tsx | 10 ++-- .../components/personal-account-dropdown.tsx | 58 ++++++++++++++++--- .../src/components/notifications-popover.tsx | 4 +- .../features/team-accounts/src/server/api.ts | 19 +++++- packages/ui/src/makerkit/page.tsx | 2 +- packages/ui/src/makerkit/profile-avatar.tsx | 2 +- public/locales/en/billing.json | 3 + public/locales/et/billing.json | 5 +- public/locales/ru/billing.json | 5 +- 14 files changed, 132 insertions(+), 69 deletions(-) diff --git a/app/home/(user)/_components/home-menu-navigation.tsx b/app/home/(user)/_components/home-menu-navigation.tsx index 7d78633..33e2408 100644 --- a/app/home/(user)/_components/home-menu-navigation.tsx +++ b/app/home/(user)/_components/home-menu-navigation.tsx @@ -1,38 +1,41 @@ -import { If } from '@kit/ui/if'; - import { AppLogo } from '~/components/app-logo'; import { ProfileAccountDropdownContainer } from '~/components/personal-account-dropdown-container'; -import featuresFlagConfig from '~/config/feature-flags.config'; +import { Trans } from '@kit/ui/trans'; // home imports -import { HomeAccountSelector } from '../_components/home-account-selector'; import { UserNotifications } from '../_components/user-notifications'; import { type UserWorkspace } from '../_lib/server/load-user-workspace'; +import { Button } from '@kit/ui/button'; +import { ShoppingCart } from 'lucide-react'; export function HomeMenuNavigation(props: { workspace: UserWorkspace }) { const { workspace, user, accounts } = props.workspace; - + console.log('HomeMenuNavigation', accounts) return (
+ {/* searbar */} +
+ {/* TODO: implement account budget */} + + {/* TODO: implement cart */} + - - - - - -
- -
+
); diff --git a/app/home/[account]/_components/team-account-navigation-menu.tsx b/app/home/[account]/_components/team-account-navigation-menu.tsx index 4eb9747..ba20d8d 100644 --- a/app/home/[account]/_components/team-account-navigation-menu.tsx +++ b/app/home/[account]/_components/team-account-navigation-menu.tsx @@ -6,16 +6,22 @@ import { import { AppLogo } from '~/components/app-logo'; import { ProfileAccountDropdownContainer } from '~/components/personal-account-dropdown-container'; import { getTeamAccountSidebarConfig } from '~/config/team-account-navigation.config'; -import { TeamAccountAccountsSelector } from '~/home/[account]/_components/team-account-accounts-selector'; // local imports import { TeamAccountWorkspace } from '../_lib/server/team-account-workspace.loader'; import { TeamAccountNotifications } from './team-account-notifications'; +import { useMemo } from 'react'; export function TeamAccountNavigationMenu(props: { workspace: TeamAccountWorkspace; }) { - const { account, user, accounts } = props.workspace; + const { account, user, accounts: rawAccounts } = props.workspace; + + const accounts = useMemo(() => rawAccounts.map((account) => ({ + label: account.name, + value: account.slug, + image: account.picture_url, + })),[rawAccounts]) const routes = getTeamAccountSidebarConfig(account.slug).routes.reduce< Array<{ @@ -40,7 +46,6 @@ export function TeamAccountNavigationMenu(props: {
- {routes.map((route) => ( @@ -48,26 +53,14 @@ export function TeamAccountNavigationMenu(props: {
-
+
- - ({ - label: account.name, - value: account.slug, - image: account.picture_url, - }))} + - -
- -
); diff --git a/app/home/[account]/_lib/server/team-account-workspace.loader.ts b/app/home/[account]/_lib/server/team-account-workspace.loader.ts index 4a38994..7ca21ed 100644 --- a/app/home/[account]/_lib/server/team-account-workspace.loader.ts +++ b/app/home/[account]/_lib/server/team-account-workspace.loader.ts @@ -28,12 +28,8 @@ export const loadTeamWorkspace = cache(workspaceLoader); async function workspaceLoader(accountSlug: string) { const client = getSupabaseServerClient(); const api = createTeamAccountsApi(client); - - const [workspace, user] = await Promise.all([ - api.getAccountWorkspace(accountSlug), - requireUserInServerComponent(), - ]); - + const user = await requireUserInServerComponent(); + const workspace = await api.getAccountWorkspace(accountSlug, user.id); // we cannot find any record for the selected account // so we redirect the user to the home page if (!workspace.data?.account) { @@ -42,6 +38,7 @@ async function workspaceLoader(accountSlug: string) { return { ...workspace.data, + accounts: workspace.data.accounts.map(({ user_accounts }) => ({...user_accounts})), user, }; } diff --git a/app/home/[account]/layout.tsx b/app/home/[account]/layout.tsx index f4ffec6..cbb77d1 100644 --- a/app/home/[account]/layout.tsx +++ b/app/home/[account]/layout.tsx @@ -30,7 +30,7 @@ function TeamWorkspaceLayout({ children, params }: TeamWorkspaceLayoutProps) { return {children}; } - return {children}; + return {children}; } function SidebarLayout({ diff --git a/components/personal-account-dropdown-container.tsx b/components/personal-account-dropdown-container.tsx index 50b28bc..bf4d2d2 100644 --- a/components/personal-account-dropdown-container.tsx +++ b/components/personal-account-dropdown-container.tsx @@ -26,6 +26,11 @@ export function ProfileAccountDropdownContainer(props: { name: string | null; picture_url: string | null; }; + accounts: { + label: string | null; + value: string | null; + image?: string | null; +}[] }) { const signOut = useSignOut(); const user = useUser(props.user); @@ -34,7 +39,7 @@ export function ProfileAccountDropdownContainer(props: { if (!userData) { return null; } - + console.log(props.accounts) return ( signOut.mutateAsync()} showProfileName={props.showProfileName} /> diff --git a/packages/features/accounts/src/components/account-selector.tsx b/packages/features/accounts/src/components/account-selector.tsx index 909a929..ab7965f 100644 --- a/packages/features/accounts/src/components/account-selector.tsx +++ b/packages/features/accounts/src/components/account-selector.tsx @@ -112,10 +112,10 @@ export function AccountSelector({ role="combobox" aria-expanded={open} className={cn( - 'dark:shadow-primary/10 group w-full min-w-0 px-2 lg:w-auto lg:max-w-fit', + 'dark:shadow-primary/10 group w-full min-w-0 px-4 py-2 h-10 border-1 lg:w-auto lg:max-w-fit', { 'justify-start': !collapsed, - 'm-auto justify-center px-2 lg:w-full': collapsed, + 'm-auto justify-center px-4 lg:w-full': collapsed, }, className, )} @@ -124,7 +124,7 @@ export function AccountSelector({ condition={selected} fallback={ - + + ); diff --git a/packages/features/accounts/src/components/personal-account-dropdown.tsx b/packages/features/accounts/src/components/personal-account-dropdown.tsx index c1a7128..39705ca 100644 --- a/packages/features/accounts/src/components/personal-account-dropdown.tsx +++ b/packages/features/accounts/src/components/personal-account-dropdown.tsx @@ -28,6 +28,9 @@ import { Trans } from '@kit/ui/trans'; import { cn } from '@kit/ui/utils'; import { usePersonalAccountData } from '../hooks/use-personal-account-data'; +import { Avatar, AvatarFallback, AvatarImage } from '@kit/ui/avatar'; + +const PERSONAL_ACCOUNT_SLUG = 'personal'; export function PersonalAccountDropdown({ className, @@ -37,6 +40,7 @@ export function PersonalAccountDropdown({ paths, features, account, + accounts }: { user: User; @@ -45,7 +49,11 @@ export function PersonalAccountDropdown({ name: string | null; picture_url: string | null; }; - + accounts: { + label: string | null; + value: string | null; + image?: string | null; + }[]; signOutRequested: () => unknown; paths: { @@ -95,7 +103,7 @@ export function PersonalAccountDropdown({ className ?? '', { ['active:bg-secondary/50 items-center gap-4 rounded-md' + - ' hover:bg-secondary p-2 transition-colors']: showProfileName, + ' hover:bg-secondary p-0 m-0 transition-colors border-1 rounded-md px-4 py-1 h-10']: showProfileName, }, )} > @@ -119,12 +127,6 @@ export function PersonalAccountDropdown({ {displayName} - - {signedInAsLabel} -
+ 0}> + + + + + {(accounts ?? []).map((account) => ( + + +
+ + + + + {account.label ? account.label[0] : ''} + + + + + {account.label} + +
+ +
+ ))} +
+ + + - + diff --git a/app/home/[account]/_components/team-account-navigation-menu.tsx b/app/home/[account]/_components/team-account-navigation-menu.tsx index 214ca1b..c09a19a 100644 --- a/app/home/[account]/_components/team-account-navigation-menu.tsx +++ b/app/home/[account]/_components/team-account-navigation-menu.tsx @@ -46,11 +46,6 @@ export function TeamAccountNavigationMenu(props: {
- - {routes.map((route) => ( - - ))} -
diff --git a/app/home/[account]/layout.tsx b/app/home/[account]/layout.tsx index cbb77d1..f597a3b 100644 --- a/app/home/[account]/layout.tsx +++ b/app/home/[account]/layout.tsx @@ -30,7 +30,7 @@ function TeamWorkspaceLayout({ children, params }: TeamWorkspaceLayoutProps) { return {children}; } - return {children}; + return {children}; } function SidebarLayout({ @@ -113,7 +113,32 @@ function HeaderLayout({
- {children} + + + + + + + + + +
+ +
+
+ + {children} +
+
); diff --git a/supabase/migrations/20250630163951_alter_accounts_personal_code.sql b/supabase/migrations/20250630163951_alter_accounts_personal_code.sql index f9075a6..e03b58a 100644 --- a/supabase/migrations/20250630163951_alter_accounts_personal_code.sql +++ b/supabase/migrations/20250630163951_alter_accounts_personal_code.sql @@ -1,5 +1,8 @@ -alter table public.accounts -add column if not exists personal_code char(11) unique; +ALTER TABLE public.accounts +ADD CONSTRAINT accounts_personal_code_unique UNIQUE (personal_code); -alter table public.invitations -add column if not exists personal_code char(11) unique; \ No newline at end of file +ALTER TABLE public.invitations +ALTER COLUMN personal_code TYPE text; + +ALTER TABLE public.invitations +ADD CONSTRAINT invitations_personal_code_unique UNIQUE (personal_code); \ No newline at end of file diff --git a/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql b/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql index 073830a..5efde2e 100644 --- a/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql +++ b/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql @@ -62,7 +62,7 @@ returns table ( created_at timestamptz, updated_at timestamptz, expires_at timestamptz, - personal_code char(11), + personal_code text, inviter_name varchar, inviter_email varchar ) From c4eaaca161d2c510f49c8f81dfe9790854b12c9f Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Wed, 2 Jul 2025 09:22:03 +0300 Subject: [PATCH 6/7] B2B-30: fix conflict in rpc function --- ...630163951_alter_accounts_personal_code.sql | 27 ++++++++++++++++--- ...70525_add_personal_code_to_invitations.sql | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/supabase/migrations/20250630163951_alter_accounts_personal_code.sql b/supabase/migrations/20250630163951_alter_accounts_personal_code.sql index e03b58a..2a6fde1 100644 --- a/supabase/migrations/20250630163951_alter_accounts_personal_code.sql +++ b/supabase/migrations/20250630163951_alter_accounts_personal_code.sql @@ -1,8 +1,27 @@ -ALTER TABLE public.accounts -ADD CONSTRAINT accounts_personal_code_unique UNIQUE (personal_code); +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'accounts_personal_code_unique' + ) THEN + ALTER TABLE public.accounts + ADD CONSTRAINT accounts_personal_code_unique UNIQUE (personal_code); + END IF; +END$$; ALTER TABLE public.invitations ALTER COLUMN personal_code TYPE text; -ALTER TABLE public.invitations -ADD CONSTRAINT invitations_personal_code_unique UNIQUE (personal_code); \ No newline at end of file +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM pg_constraint + WHERE conname = 'invitations_personal_code_unique' + ) THEN + ALTER TABLE public.invitations + ADD CONSTRAINT invitations_personal_code_unique UNIQUE (personal_code); + END IF; +END$$; + diff --git a/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql b/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql index 5efde2e..2170efb 100644 --- a/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql +++ b/supabase/migrations/20250630170525_add_personal_code_to_invitations.sql @@ -107,7 +107,7 @@ create primary_owner_user_id uuid, name varchar, email varchar, - personal_code char(11), + personal_code text, picture_url varchar, created_at timestamptz, updated_at timestamptz From 27e9053a996e18c97dd0f7ee4515dd2a75e946c5 Mon Sep 17 00:00:00 2001 From: devmc-ee Date: Wed, 2 Jul 2025 18:22:42 +0300 Subject: [PATCH 7/7] B2B-30: clean code --- app/home/(user)/_components/home-menu-navigation.tsx | 2 +- .../features/accounts/src/components/account-selector.tsx | 6 +++--- .../notifications/src/components/notifications-popover.tsx | 4 ++-- packages/ui/src/makerkit/profile-avatar.tsx | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/home/(user)/_components/home-menu-navigation.tsx b/app/home/(user)/_components/home-menu-navigation.tsx index 6ac1742..e8776a1 100644 --- a/app/home/(user)/_components/home-menu-navigation.tsx +++ b/app/home/(user)/_components/home-menu-navigation.tsx @@ -28,7 +28,7 @@ export function HomeMenuNavigation(props: { workspace: UserWorkspace }) { />
-