From d9a54be4c8f534357ad94a362b5d2db9ef85ae33 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Tue, 28 Oct 2025 12:00:45 +0100 Subject: [PATCH] Improve invites --- apps/main/src/hooks/invite.ts | 3 +- packages/shared/src/types/database.types.ts | 1083 +++++++++-------- sql/27_add_is_pending_to_invites.sql | 10 + sql/28_modify_trigger.sql | 49 + ...29_add_created_at_col_to_tablo_invites.sql | 10 + sql/30_new_trigger_on_login.sql | 59 + 6 files changed, 679 insertions(+), 535 deletions(-) create mode 100644 sql/27_add_is_pending_to_invites.sql create mode 100644 sql/28_modify_trigger.sql create mode 100644 sql/29_add_created_at_col_to_tablo_invites.sql create mode 100644 sql/30_new_trigger_on_login.sql diff --git a/apps/main/src/hooks/invite.ts b/apps/main/src/hooks/invite.ts index f7244fd..3abf2e9 100644 --- a/apps/main/src/hooks/invite.ts +++ b/apps/main/src/hooks/invite.ts @@ -7,9 +7,8 @@ export const useInviteUser = () => { const api = useAuthedApi(); const { mutate, isPending } = useMutation({ mutationFn: async ({ email, tablo_id }: { email: string; tablo_id: string }) => { - const { data } = await api.post("/api/v1/tablos/invite", { + const { data } = await api.post(`/api/v1/tablos/invite/${tablo_id}`, { email, - tablo_id, }); return data; }, diff --git a/packages/shared/src/types/database.types.ts b/packages/shared/src/types/database.types.ts index acd4bda..5c4ad28 100644 --- a/packages/shared/src/types/database.types.ts +++ b/packages/shared/src/types/database.types.ts @@ -1,742 +1,759 @@ -export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] export type Database = { // Allows to automatically instantiate createClient with right options // instead of createClient(URL, KEY) __InternalSupabase: { - PostgrestVersion: "13.0.4"; - }; + PostgrestVersion: "13.0.4" + } public: { Tables: { availabilities: { Row: { - availability_data: Json; - created_at: string; - exceptions: Json | null; - id: number; - updated_at: string; - user_id: string; - }; + availability_data: Json + created_at: string + exceptions: Json | null + id: number + updated_at: string + user_id: string + } Insert: { - availability_data?: Json; - created_at?: string; - exceptions?: Json | null; - id?: number; - updated_at?: string; - user_id: string; - }; + availability_data?: Json + created_at?: string + exceptions?: Json | null + id?: number + updated_at?: string + user_id: string + } Update: { - availability_data?: Json; - created_at?: string; - exceptions?: Json | null; - id?: number; - updated_at?: string; - user_id?: string; - }; - Relationships: []; - }; + availability_data?: Json + created_at?: string + exceptions?: Json | null + id?: number + updated_at?: string + user_id?: string + } + Relationships: [] + } calendar_subscriptions: { Row: { - created_at: string | null; - id: string; - tablo_id: string; - token: string; - }; + created_at: string | null + id: string + tablo_id: string + token: string + } Insert: { - created_at?: string | null; - id?: string; - tablo_id: string; - token: string; - }; + created_at?: string | null + id?: string + tablo_id: string + token: string + } Update: { - created_at?: string | null; - id?: string; - tablo_id?: string; - token?: string; - }; + created_at?: string | null + id?: string + tablo_id?: string + token?: string + } Relationships: [ { - foreignKeyName: "calendar_subscriptions_tablo_id_fkey"; - columns: ["tablo_id"]; - isOneToOne: true; - referencedRelation: "events_and_tablos"; - referencedColumns: ["tablo_id"]; + foreignKeyName: "calendar_subscriptions_tablo_id_fkey" + columns: ["tablo_id"] + isOneToOne: true + referencedRelation: "events_and_tablos" + referencedColumns: ["tablo_id"] }, { - foreignKeyName: "calendar_subscriptions_tablo_id_fkey"; - columns: ["tablo_id"]; - isOneToOne: true; - referencedRelation: "tablos"; - referencedColumns: ["id"]; + foreignKeyName: "calendar_subscriptions_tablo_id_fkey" + columns: ["tablo_id"] + isOneToOne: true + referencedRelation: "tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "calendar_subscriptions_tablo_id_fkey"; - columns: ["tablo_id"]; - isOneToOne: true; - referencedRelation: "user_tablos"; - referencedColumns: ["id"]; + foreignKeyName: "calendar_subscriptions_tablo_id_fkey" + columns: ["tablo_id"] + isOneToOne: true + referencedRelation: "user_tablos" + referencedColumns: ["id"] }, - ]; - }; + ] + } devis: { Row: { - client_email: string; - created_at: string; - date: string; - due_date: string; - id: string; - items: Json; - notes: string | null; - number: string; - status: Database["public"]["Enums"]["devis_status"]; - subtotal: number; - tax: number; - terms: string | null; - total: number; - updated_at: string; - user_id: string; - }; + client_email: string + created_at: string + date: string + due_date: string + id: string + items: Json + notes: string | null + number: string + status: Database["public"]["Enums"]["devis_status"] + subtotal: number + tax: number + terms: string | null + total: number + updated_at: string + user_id: string + } Insert: { - client_email: string; - created_at?: string; - date: string; - due_date: string; - id?: string; - items?: Json; - notes?: string | null; - number: string; - status?: Database["public"]["Enums"]["devis_status"]; - subtotal: number; - tax: number; - terms?: string | null; - total: number; - updated_at?: string; - user_id: string; - }; + client_email: string + created_at?: string + date: string + due_date: string + id?: string + items?: Json + notes?: string | null + number: string + status?: Database["public"]["Enums"]["devis_status"] + subtotal: number + tax: number + terms?: string | null + total: number + updated_at?: string + user_id: string + } Update: { - client_email?: string; - created_at?: string; - date?: string; - due_date?: string; - id?: string; - items?: Json; - notes?: string | null; - number?: string; - status?: Database["public"]["Enums"]["devis_status"]; - subtotal?: number; - tax?: number; - terms?: string | null; - total?: number; - updated_at?: string; - user_id?: string; - }; - Relationships: []; - }; + client_email?: string + created_at?: string + date?: string + due_date?: string + id?: string + items?: Json + notes?: string | null + number?: string + status?: Database["public"]["Enums"]["devis_status"] + subtotal?: number + tax?: number + terms?: string | null + total?: number + updated_at?: string + user_id?: string + } + Relationships: [] + } event_types: { Row: { - config: Json; - created_at: string | null; - deleted_at: string | null; - id: string; - is_active: boolean; - standard_name: string | null; - updated_at: string | null; - user_id: string; - }; + config: Json + created_at: string | null + deleted_at: string | null + id: string + is_active: boolean + standard_name: string | null + updated_at: string | null + user_id: string + } Insert: { - config?: Json; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - is_active?: boolean; - standard_name?: string | null; - updated_at?: string | null; - user_id: string; - }; + config?: Json + created_at?: string | null + deleted_at?: string | null + id?: string + is_active?: boolean + standard_name?: string | null + updated_at?: string | null + user_id: string + } Update: { - config?: Json; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - is_active?: boolean; - standard_name?: string | null; - updated_at?: string | null; - user_id?: string; - }; - Relationships: []; - }; + config?: Json + created_at?: string | null + deleted_at?: string | null + id?: string + is_active?: boolean + standard_name?: string | null + updated_at?: string | null + user_id?: string + } + Relationships: [] + } events: { Row: { - created_at: string | null; - created_by: string; - deleted_at: string | null; - description: string | null; - end_time: string | null; - id: string; - start_date: string; - start_time: string; - tablo_id: string; - title: string; - }; + created_at: string | null + created_by: string + deleted_at: string | null + description: string | null + end_time: string | null + id: string + start_date: string + start_time: string + tablo_id: string + title: string + } Insert: { - created_at?: string | null; - created_by: string; - deleted_at?: string | null; - description?: string | null; - end_time?: string | null; - id?: string; - start_date: string; - start_time: string; - tablo_id: string; - title: string; - }; + created_at?: string | null + created_by: string + deleted_at?: string | null + description?: string | null + end_time?: string | null + id?: string + start_date: string + start_time: string + tablo_id: string + title: string + } Update: { - created_at?: string | null; - created_by?: string; - deleted_at?: string | null; - description?: string | null; - end_time?: string | null; - id?: string; - start_date?: string; - start_time?: string; - tablo_id?: string; - title?: string; - }; + created_at?: string | null + created_by?: string + deleted_at?: string | null + description?: string | null + end_time?: string | null + id?: string + start_date?: string + start_time?: string + tablo_id?: string + title?: string + } Relationships: [ { - foreignKeyName: "fk_events_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "events_and_tablos"; - referencedColumns: ["tablo_id"]; + foreignKeyName: "fk_events_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "events_and_tablos" + referencedColumns: ["tablo_id"] }, { - foreignKeyName: "fk_events_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_events_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_events_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "user_tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_events_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] }, - ]; - }; + ] + } feedbacks: { Row: { - created_at: string | null; - fd_type: string; - id: number; - message: string; - user_id: string; - }; + created_at: string | null + fd_type: string + id: number + message: string + user_id: string + } Insert: { - created_at?: string | null; - fd_type: string; - id?: number; - message: string; - user_id: string; - }; + created_at?: string | null + fd_type: string + id?: number + message: string + user_id: string + } Update: { - created_at?: string | null; - fd_type?: string; - id?: number; - message?: string; - user_id?: string; - }; - Relationships: []; - }; + created_at?: string | null + fd_type?: string + id?: number + message?: string + user_id?: string + } + Relationships: [] + } note_access: { Row: { - created_at: string | null; - id: number; - is_active: boolean | null; - note_id: string; - tablo_id: string | null; - updated_at: string | null; - user_id: string; - }; + created_at: string | null + id: number + is_active: boolean | null + note_id: string + tablo_id: string | null + updated_at: string | null + user_id: string + } Insert: { - created_at?: string | null; - id?: number; - is_active?: boolean | null; - note_id: string; - tablo_id?: string | null; - updated_at?: string | null; - user_id: string; - }; + created_at?: string | null + id?: number + is_active?: boolean | null + note_id: string + tablo_id?: string | null + updated_at?: string | null + user_id: string + } Update: { - created_at?: string | null; - id?: number; - is_active?: boolean | null; - note_id?: string; - tablo_id?: string | null; - updated_at?: string | null; - user_id?: string; - }; + created_at?: string | null + id?: number + is_active?: boolean | null + note_id?: string + tablo_id?: string | null + updated_at?: string | null + user_id?: string + } Relationships: [ { - foreignKeyName: "fk_note_access_note_id"; - columns: ["note_id"]; - isOneToOne: false; - referencedRelation: "notes"; - referencedColumns: ["id"]; + foreignKeyName: "fk_note_access_note_id" + columns: ["note_id"] + isOneToOne: false + referencedRelation: "notes" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_note_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "events_and_tablos"; - referencedColumns: ["tablo_id"]; + foreignKeyName: "fk_note_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "events_and_tablos" + referencedColumns: ["tablo_id"] }, { - foreignKeyName: "fk_note_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_note_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_note_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "user_tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_note_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] }, - ]; - }; + ] + } notes: { Row: { - content: string | null; - created_at: string | null; - deleted_at: string | null; - id: string; - title: string; - updated_at: string | null; - user_id: string; - }; + content: string | null + created_at: string | null + deleted_at: string | null + id: string + title: string + updated_at: string | null + user_id: string + } Insert: { - content?: string | null; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - title: string; - updated_at?: string | null; - user_id: string; - }; + content?: string | null + created_at?: string | null + deleted_at?: string | null + id?: string + title: string + updated_at?: string | null + user_id: string + } Update: { - content?: string | null; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - title?: string; - updated_at?: string | null; - user_id?: string; - }; - Relationships: []; - }; + content?: string | null + created_at?: string | null + deleted_at?: string | null + id?: string + title?: string + updated_at?: string | null + user_id?: string + } + Relationships: [] + } profiles: { Row: { - avatar_url: string | null; - email: string | null; - first_name: string | null; - id: string; - is_temporary: boolean; - last_name: string | null; - name: string | null; - short_user_id: string; - }; + avatar_url: string | null + email: string | null + first_name: string | null + id: string + is_temporary: boolean + last_name: string | null + last_signed_in: string | null + name: string | null + short_user_id: string + } Insert: { - avatar_url?: string | null; - email?: string | null; - first_name?: string | null; - id: string; - is_temporary?: boolean; - last_name?: string | null; - name?: string | null; - short_user_id: string; - }; + avatar_url?: string | null + email?: string | null + first_name?: string | null + id: string + is_temporary?: boolean + last_name?: string | null + last_signed_in?: string | null + name?: string | null + short_user_id: string + } Update: { - avatar_url?: string | null; - email?: string | null; - first_name?: string | null; - id?: string; - is_temporary?: boolean; - last_name?: string | null; - name?: string | null; - short_user_id?: string; - }; - Relationships: []; - }; + avatar_url?: string | null + email?: string | null + first_name?: string | null + id?: string + is_temporary?: boolean + last_name?: string | null + last_signed_in?: string | null + name?: string | null + short_user_id?: string + } + Relationships: [] + } shared_notes: { Row: { - created_at: string | null; - is_public: boolean | null; - note_id: string; - updated_at: string | null; - user_id: string; - }; + created_at: string | null + is_public: boolean | null + note_id: string + updated_at: string | null + user_id: string + } Insert: { - created_at?: string | null; - is_public?: boolean | null; - note_id: string; - updated_at?: string | null; - user_id: string; - }; + created_at?: string | null + is_public?: boolean | null + note_id: string + updated_at?: string | null + user_id: string + } Update: { - created_at?: string | null; - is_public?: boolean | null; - note_id?: string; - updated_at?: string | null; - user_id?: string; - }; + created_at?: string | null + is_public?: boolean | null + note_id?: string + updated_at?: string | null + user_id?: string + } Relationships: [ { - foreignKeyName: "fk_shared_notes_note_id"; - columns: ["note_id"]; - isOneToOne: true; - referencedRelation: "notes"; - referencedColumns: ["id"]; + foreignKeyName: "fk_shared_notes_note_id" + columns: ["note_id"] + isOneToOne: true + referencedRelation: "notes" + referencedColumns: ["id"] }, - ]; - }; + ] + } tablo_access: { Row: { - created_at: string | null; - granted_by: string; - id: number; - is_active: boolean | null; - is_admin: boolean | null; - tablo_id: string; - user_id: string; - }; + created_at: string | null + granted_by: string + id: number + is_active: boolean | null + is_admin: boolean | null + tablo_id: string + user_id: string + } Insert: { - created_at?: string | null; - granted_by: string; - id?: number; - is_active?: boolean | null; - is_admin?: boolean | null; - tablo_id: string; - user_id: string; - }; + created_at?: string | null + granted_by: string + id?: number + is_active?: boolean | null + is_admin?: boolean | null + tablo_id: string + user_id: string + } Update: { - created_at?: string | null; - granted_by?: string; - id?: number; - is_active?: boolean | null; - is_admin?: boolean | null; - tablo_id?: string; - user_id?: string; - }; + created_at?: string | null + granted_by?: string + id?: number + is_active?: boolean | null + is_admin?: boolean | null + tablo_id?: string + user_id?: string + } Relationships: [ { - foreignKeyName: "fk_tablo_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "events_and_tablos"; - referencedColumns: ["tablo_id"]; + foreignKeyName: "fk_tablo_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "events_and_tablos" + referencedColumns: ["tablo_id"] }, { - foreignKeyName: "fk_tablo_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_tablo_access_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "user_tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_access_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_tablo_access_user_id_from_profiles"; - columns: ["user_id"]; - isOneToOne: false; - referencedRelation: "profiles"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_access_user_id_from_profiles" + columns: ["user_id"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["id"] }, - ]; - }; + ] + } tablo_invites: { Row: { - id: number; - invite_token: string; - invited_by: string; - invited_email: string; - tablo_id: string; - }; + created_at: string + id: number + invite_token: string + invited_by: string + invited_email: string + is_pending: boolean + tablo_id: string + } Insert: { - id?: number; - invite_token: string; - invited_by: string; - invited_email: string; - tablo_id: string; - }; + created_at?: string + id?: number + invite_token: string + invited_by: string + invited_email: string + is_pending?: boolean + tablo_id: string + } Update: { - id?: number; - invite_token?: string; - invited_by?: string; - invited_email?: string; - tablo_id?: string; - }; + created_at?: string + id?: number + invite_token?: string + invited_by?: string + invited_email?: string + is_pending?: boolean + tablo_id?: string + } Relationships: [ { - foreignKeyName: "fk_tablo_invitations_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "events_and_tablos"; - referencedColumns: ["tablo_id"]; + foreignKeyName: "fk_tablo_invitations_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "events_and_tablos" + referencedColumns: ["tablo_id"] }, { - foreignKeyName: "fk_tablo_invitations_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_invitations_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "tablos" + referencedColumns: ["id"] }, { - foreignKeyName: "fk_tablo_invitations_tablo_id"; - columns: ["tablo_id"]; - isOneToOne: false; - referencedRelation: "user_tablos"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_invitations_tablo_id" + columns: ["tablo_id"] + isOneToOne: false + referencedRelation: "user_tablos" + referencedColumns: ["id"] }, - ]; - }; + ] + } tablos: { Row: { - color: string | null; - created_at: string | null; - deleted_at: string | null; - id: string; - image: string | null; - name: string; - owner_id: string; - position: number; - status: string; - }; + color: string | null + created_at: string | null + deleted_at: string | null + id: string + image: string | null + name: string + owner_id: string + position: number + status: string + } Insert: { - color?: string | null; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - image?: string | null; - name: string; - owner_id: string; - position?: number; - status?: string; - }; + color?: string | null + created_at?: string | null + deleted_at?: string | null + id?: string + image?: string | null + name: string + owner_id: string + position?: number + status?: string + } Update: { - color?: string | null; - created_at?: string | null; - deleted_at?: string | null; - id?: string; - image?: string | null; - name?: string; - owner_id?: string; - position?: number; - status?: string; - }; - Relationships: []; - }; + color?: string | null + created_at?: string | null + deleted_at?: string | null + id?: string + image?: string | null + name?: string + owner_id?: string + position?: number + status?: string + } + Relationships: [] + } user_introductions: { Row: { - config: Json; - created_at: string | null; - updated_at: string | null; - user_id: string; - }; + config: Json + created_at: string | null + updated_at: string | null + user_id: string + } Insert: { - config?: Json; - created_at?: string | null; - updated_at?: string | null; - user_id: string; - }; + config?: Json + created_at?: string | null + updated_at?: string | null + user_id: string + } Update: { - config?: Json; - created_at?: string | null; - updated_at?: string | null; - user_id?: string; - }; - Relationships: []; - }; - }; + config?: Json + created_at?: string | null + updated_at?: string | null + user_id?: string + } + Relationships: [] + } + } Views: { events_and_tablos: { Row: { - description: string | null; - end_time: string | null; - event_id: string | null; - start_date: string | null; - start_time: string | null; - tablo_color: string | null; - tablo_id: string | null; - tablo_name: string | null; - tablo_status: string | null; - title: string | null; - }; - Relationships: []; - }; + description: string | null + end_time: string | null + event_id: string | null + start_date: string | null + start_time: string | null + tablo_color: string | null + tablo_id: string | null + tablo_name: string | null + tablo_status: string | null + title: string | null + } + Relationships: [] + } user_tablos: { Row: { - access_level: string | null; - color: string | null; - created_at: string | null; - deleted_at: string | null; - id: string | null; - image: string | null; - is_admin: boolean | null; - name: string | null; - position: number | null; - status: string | null; - user_id: string | null; - }; + access_level: string | null + color: string | null + created_at: string | null + deleted_at: string | null + id: string | null + image: string | null + is_admin: boolean | null + name: string | null + position: number | null + status: string | null + user_id: string | null + } Relationships: [ { - foreignKeyName: "fk_tablo_access_user_id_from_profiles"; - columns: ["user_id"]; - isOneToOne: false; - referencedRelation: "profiles"; - referencedColumns: ["id"]; + foreignKeyName: "fk_tablo_access_user_id_from_profiles" + columns: ["user_id"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["id"] }, - ]; - }; - }; + ] + } + } Functions: { - generate_random_string: { Args: { length?: number }; Returns: string }; - }; + generate_random_string: { Args: { length?: number }; Returns: string } + } Enums: { - devis_status: "draft" | "sent" | "accepted" | "rejected" | "expired"; - }; + devis_status: "draft" | "sent" | "accepted" | "rejected" | "expired" + } CompositeTypes: { time_range: { - start_time: string | null; - end_time: string | null; - }; - }; - }; -}; + start_time: string | null + end_time: string | null + } + } + } +} -type DatabaseWithoutInternals = Omit; +type DatabaseWithoutInternals = Omit -type DefaultSchema = DatabaseWithoutInternals[Extract]; +type DefaultSchema = DatabaseWithoutInternals[Extract] export type Tables< DefaultSchemaTableNameOrOptions extends | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R; + Row: infer R } ? R : never - : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) - ? (DefaultSchema["Tables"] & DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] 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< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I; + Insert: infer I } ? I : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Insert: infer I; + Insert: infer I } ? I : never - : never; + : never export type TablesUpdate< DefaultSchemaTableNameOrOptions extends | keyof DefaultSchema["Tables"] | { schema: keyof DatabaseWithoutInternals }, TableName extends DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, > = DefaultSchemaTableNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U; + Update: infer U } ? U : never : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { - Update: infer U; + Update: infer U } ? U : never - : never; + : never export type Enums< DefaultSchemaEnumNameOrOptions extends | keyof DefaultSchema["Enums"] | { schema: keyof DatabaseWithoutInternals }, EnumName extends DefaultSchemaEnumNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] : never = never, > = DefaultSchemaEnumNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] - : never; + : never export type CompositeTypes< PublicCompositeTypeNameOrOptions extends | keyof DefaultSchema["CompositeTypes"] | { schema: keyof DatabaseWithoutInternals }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] : never = never, > = PublicCompositeTypeNameOrOptions extends { - schema: keyof DatabaseWithoutInternals; + schema: keyof DatabaseWithoutInternals } ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] - : never; + : never export const Constants = { public: { @@ -744,4 +761,4 @@ export const Constants = { devis_status: ["draft", "sent", "accepted", "rejected", "expired"], }, }, -} as const; +} as const diff --git a/sql/27_add_is_pending_to_invites.sql b/sql/27_add_is_pending_to_invites.sql new file mode 100644 index 0000000..429b6c0 --- /dev/null +++ b/sql/27_add_is_pending_to_invites.sql @@ -0,0 +1,10 @@ +-- Add is_pending column to tablo_invites table +ALTER TABLE tablo_invites +ADD COLUMN IF NOT EXISTS is_pending BOOLEAN DEFAULT FALSE NOT NULL; + +-- Add comment to document the column +COMMENT ON COLUMN tablo_invites.is_pending IS + 'When TRUE, the invite is pending acceptance. When FALSE, the invite has been accepted or rejected.'; + +-- Create index for performance when querying pending invites +CREATE INDEX IF NOT EXISTS idx_tablo_invites_is_pending ON tablo_invites(is_pending); \ No newline at end of file diff --git a/sql/28_modify_trigger.sql b/sql/28_modify_trigger.sql new file mode 100644 index 0000000..2417370 --- /dev/null +++ b/sql/28_modify_trigger.sql @@ -0,0 +1,49 @@ +-- Modify the handle_new_user trigger to set is_temporary based on app_metadata.role +CREATE OR REPLACE FUNCTION + public.handle_new_user() + RETURNS TRIGGER AS + $$ + DECLARE + name TEXT; + first_name TEXT; + last_name TEXT; + is_temp BOOLEAN; + BEGIN + -- Extract first_name and last_name from metadata + first_name = new.raw_user_meta_data ->> 'first_name'; + last_name = new.raw_user_meta_data ->> 'last_name'; + + -- Determine the full name + IF new.raw_user_meta_data ->> 'name' IS NOT NULL + THEN + name = new.raw_user_meta_data ->> 'name'; + -- If name is provided but not first/last, try to split it + IF first_name IS NULL AND last_name IS NULL AND name IS NOT NULL THEN + first_name = SPLIT_PART(name, ' ', 1); + IF ARRAY_LENGTH(STRING_TO_ARRAY(name, ' '), 1) > 1 THEN + last_name = SUBSTRING(name FROM LENGTH(SPLIT_PART(name, ' ', 1)) + 2); + END IF; + END IF; + ELSE + name = CONCAT(first_name, ' ', last_name); + END IF; + + -- Check if the role is 'invited_user' in app_metadata + IF COALESCE(new.raw_user_meta_data->>'role', '') = 'invited_user' + THEN + is_temp = TRUE; + ELSE + is_temp = FALSE; + END IF; + + INSERT INTO public.profiles (id, name, email, avatar_url, first_name, last_name, is_temporary) + VALUES (new.id, name, new.email, new.raw_user_meta_data ->> 'avatar_url', first_name, last_name, is_temp); + + RETURN new; +END; + $$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Add comment to document the change +COMMENT ON FUNCTION public.handle_new_user() IS + 'Trigger function that creates a profile when a new user is created. Sets is_temporary=true for users with app_metadata.role=invited_user'; + diff --git a/sql/29_add_created_at_col_to_tablo_invites.sql b/sql/29_add_created_at_col_to_tablo_invites.sql new file mode 100644 index 0000000..fd4d356 --- /dev/null +++ b/sql/29_add_created_at_col_to_tablo_invites.sql @@ -0,0 +1,10 @@ +-- Add created_at column to tablo_invites table +ALTER TABLE tablo_invites +ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL; + +-- Add comment to document the column +COMMENT ON COLUMN tablo_invites.created_at IS + 'Timestamp when the invite was created'; + +-- Create index for performance when querying by creation date +CREATE INDEX IF NOT EXISTS idx_tablo_invites_created_at ON tablo_invites(created_at); \ No newline at end of file diff --git a/sql/30_new_trigger_on_login.sql b/sql/30_new_trigger_on_login.sql new file mode 100644 index 0000000..f700cd7 --- /dev/null +++ b/sql/30_new_trigger_on_login.sql @@ -0,0 +1,59 @@ +-- Add last_signed_in column to profiles table +ALTER TABLE profiles +ADD COLUMN IF NOT EXISTS last_signed_in TIMESTAMP WITH TIME ZONE; + +-- Add comment to document the column +COMMENT ON COLUMN profiles.last_signed_in IS + 'Timestamp when the user last signed in, updated from auth.users.last_sign_in_at'; + + +-- Create function to update last_signed_in column on profiles table +CREATE OR REPLACE FUNCTION public.create_last_signed_in_on_profiles() + RETURNS TRIGGER AS $$ + BEGIN + IF (NEW.last_sign_in_at is null) THEN + RETURN NULL; + ELSE + UPDATE public.profiles + SET last_signed_in = NEW.last_sign_in_at + WHERE id = (NEW.id)::uuid; + RETURN NEW; + END IF; + END; + $$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create trigger to update last_signed_in column on profiles table +CREATE TRIGGER trigger_on_last_signed_in + AFTER UPDATE ON auth.users + FOR EACH ROW + EXECUTE FUNCTION public.create_last_signed_in_on_profiles(); + +-- Create function to update tablo_invites is_pending for temporary users +CREATE OR REPLACE FUNCTION public.update_tablo_invites_on_login() + RETURNS TRIGGER AS $$ + BEGIN + -- Check if the user is temporary and update pending invites + UPDATE public.tablo_invites + SET is_pending = FALSE + WHERE invited_email = NEW.email + AND is_pending = TRUE + AND EXISTS ( + SELECT 1 FROM public.profiles + WHERE id = (NEW.id)::uuid + AND is_temporary = TRUE + ); + RETURN NEW; + END; + $$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create trigger to update tablo_invites on user login +CREATE TRIGGER trigger_update_tablo_invites_on_login + AFTER UPDATE ON auth.users + FOR EACH ROW + EXECUTE FUNCTION public.update_tablo_invites_on_login(); + +-- Add comment to document the trigger +COMMENT ON TRIGGER trigger_update_tablo_invites_on_login ON auth.users IS + 'Automatically sets is_pending=false for tablo_invites when a temporary user signs in'; + +-- Trigger after login: https://github.com/orgs/supabase/discussions/7463 \ No newline at end of file