From 83c5bfe00452f3e3a4781f56db1579f8075a9d27 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 08:19:16 +0200 Subject: [PATCH 1/2] feat: Add types generated by Supabase CLI --- src/shared/types/supabase.ts | 345 +++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 src/shared/types/supabase.ts diff --git a/src/shared/types/supabase.ts b/src/shared/types/supabase.ts new file mode 100644 index 0000000..7469c75 --- /dev/null +++ b/src/shared/types/supabase.ts @@ -0,0 +1,345 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[]; + +export type Database = { + // Allows to automatically instanciate createClient with right options + // instead of createClient(URL, KEY) + __InternalSupabase: { + PostgrestVersion: '12.2.12 (cd3cf9e)'; + }; + public: { + Tables: { + accesses: { + Row: { + boat_id: string; + created_at: string; + id: string; + role: Database['public']['Enums']['access_role']; + user_id: string; + }; + Insert: { + boat_id: string; + created_at?: string; + id?: string; + role?: Database['public']['Enums']['access_role']; + user_id: string; + }; + Update: { + boat_id?: string; + created_at?: string; + id?: string; + role?: Database['public']['Enums']['access_role']; + user_id?: string; + }; + Relationships: [ + { + foreignKeyName: 'accesses_boat_id_fkey'; + columns: ['boat_id']; + isOneToOne: false; + referencedRelation: 'boats'; + referencedColumns: ['id']; + }, + ]; + }; + boats: { + Row: { + created_at: string; + created_by: string; + id: string; + name: string | null; + }; + Insert: { + created_at?: string; + created_by: string; + id?: string; + name?: string | null; + }; + Update: { + created_at?: string; + created_by?: string; + id?: string; + name?: string | null; + }; + Relationships: []; + }; + equipment_attachments: { + Row: { + description: string | null; + equipment_id: string; + file_name: string; + file_path: string; + file_type: string | null; + id: string; + uploaded_at: string; + }; + Insert: { + description?: string | null; + equipment_id: string; + file_name: string; + file_path: string; + file_type?: string | null; + id?: string; + uploaded_at?: string; + }; + Update: { + description?: string | null; + equipment_id?: string; + file_name?: string; + file_path?: string; + file_type?: string | null; + id?: string; + uploaded_at?: string; + }; + Relationships: [ + { + foreignKeyName: 'attachments_equipment_id_fkey'; + columns: ['equipment_id']; + isOneToOne: false; + referencedRelation: 'equipments'; + referencedColumns: ['id']; + }, + ]; + }; + equipments: { + Row: { + boat_id: string; + brand: string | null; + created_at: string; + description: string | null; + id: string; + model: string | null; + name: string; + purchase_date: string | null; + purchase_value: number | null; + serial_number: string | null; + system_key: string; + warranty_end_date: string | null; + }; + Insert: { + boat_id: string; + brand?: string | null; + created_at?: string; + description?: string | null; + id?: string; + model?: string | null; + name: string; + purchase_date?: string | null; + purchase_value?: number | null; + serial_number?: string | null; + system_key: string; + warranty_end_date?: string | null; + }; + Update: { + boat_id?: string; + brand?: string | null; + created_at?: string; + description?: string | null; + id?: string; + model?: string | null; + name?: string; + purchase_date?: string | null; + purchase_value?: number | null; + serial_number?: string | null; + system_key?: string; + warranty_end_date?: string | null; + }; + Relationships: [ + { + foreignKeyName: 'equipments_boat_id_fkey'; + columns: ['boat_id']; + isOneToOne: false; + referencedRelation: 'boats'; + referencedColumns: ['id']; + }, + ]; + }; + interventions: { + Row: { + boat_id: string; + created_at: string; + date: string; + description: string | null; + id: string; + title: string; + }; + Insert: { + boat_id: string; + created_at?: string; + date: string; + description?: string | null; + id?: string; + title: string; + }; + Update: { + boat_id?: string; + created_at?: string; + date?: string; + description?: string | null; + id?: string; + title?: string; + }; + Relationships: [ + { + foreignKeyName: 'interventions_boat_id_fkey'; + columns: ['boat_id']; + isOneToOne: false; + referencedRelation: 'boats'; + referencedColumns: ['id']; + }, + ]; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + check_equipment_access: { + Args: { equipment_id: string }; + Returns: boolean; + }; + has_boat_access: { + Args: { boat: string }; + Returns: boolean; + }; + }; + Enums: { + access_role: 'owner' | 'operator' | 'viewer'; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +}; + +type DatabaseWithoutInternals = Omit; + +type DefaultSchema = DatabaseWithoutInternals[Extract< + keyof Database, + 'public' +>]; + +export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema['Tables'] & DefaultSchema['Views']) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views']) + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends { + Row: infer R; + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] & + DefaultSchema['Views']) + ? (DefaultSchema['Tables'] & + DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R; + } + ? R + : never + : never; + +export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema['Tables'] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends { + Insert: infer I; + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] + ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I; + } + ? I + : never + : never; + +export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema['Tables'] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends { + Update: infer U; + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] + ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends { + Update: infer U; + } + ? U + : never + : never; + +export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema['Enums'] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums'] + : never = never, +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums'] + ? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions] + : never; + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema['CompositeTypes'] + | { schema: keyof DatabaseWithoutInternals }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes'] + ? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] + : never; + +export const Constants = { + public: { + Enums: { + access_role: ['owner', 'operator', 'viewer'], + }, + }, +} as const; From f0b8237a64a696ffcddd63f61203ce795f800603 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 10:27:53 +0200 Subject: [PATCH 2/2] feat: Use types generated by Supabase --- src/boats/components/access-list.tsx | 7 ++--- .../components/equipment-actions-menu.tsx | 2 +- ...ment.tsx => equipment-attachment-list.tsx} | 28 ++++++++----------- src/equipments/pages/add.tsx | 3 +- src/equipments/pages/edit.tsx | 9 ++---- src/equipments/pages/list.tsx | 2 +- src/equipments/pages/show.tsx | 4 +-- src/interventions/pages/edit.tsx | 9 ++---- src/models/equipment.ts | 10 ------- src/shared/types/models.ts | 15 ++++++++++ 10 files changed, 39 insertions(+), 50 deletions(-) rename src/equipments/components/{equipment-attachment.tsx => equipment-attachment-list.tsx} (86%) delete mode 100644 src/models/equipment.ts create mode 100644 src/shared/types/models.ts diff --git a/src/boats/components/access-list.tsx b/src/boats/components/access-list.tsx index 69618b2..d72a773 100644 --- a/src/boats/components/access-list.tsx +++ b/src/boats/components/access-list.tsx @@ -4,17 +4,14 @@ import { useState } from 'react'; import { AddAccess } from './add-access'; -interface IAccesses { - id: string; - user_id: string; -} +import type { Access } from '@/shared/types/models'; const AccessList = () => { const { data: accesses, isLoading, isError, - } = useList({ + } = useList({ resource: 'accesses', }); diff --git a/src/equipments/components/equipment-actions-menu.tsx b/src/equipments/components/equipment-actions-menu.tsx index f67127e..fb7e815 100644 --- a/src/equipments/components/equipment-actions-menu.tsx +++ b/src/equipments/components/equipment-actions-menu.tsx @@ -4,7 +4,7 @@ import { Button, Dropdown, type MenuProps, Modal } from 'antd'; import type { FC } from 'react'; import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; -import type { Equipment } from '@/models/equipment'; +import type { Equipment } from '@/shared/types/models'; interface EquipmentActionsMenuProps { equipment: Equipment; diff --git a/src/equipments/components/equipment-attachment.tsx b/src/equipments/components/equipment-attachment-list.tsx similarity index 86% rename from src/equipments/components/equipment-attachment.tsx rename to src/equipments/components/equipment-attachment-list.tsx index 0a2e75e..8e5fcaa 100644 --- a/src/equipments/components/equipment-attachment.tsx +++ b/src/equipments/components/equipment-attachment-list.tsx @@ -18,28 +18,24 @@ import type { FC } from 'react'; import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; import { supabaseClient as supabase } from '@/core/utils/supabaseClient'; +import type { EquipmentAttachment } from '@/shared/types/models'; -type Attachment = { - id: string; - file_name: string; - file_path: string; - uploaded_at: string; -}; - -type EquipmentAttachmentProps = { +type EquipmentAttachmentListProps = { equipmentId?: string; }; -const EquipmentAttachment: FC = ({ equipmentId }) => { +const EquipmentAttachmentList: FC = ({ + equipmentId, +}) => { const { translate } = useTranslation(); const { data: boat } = useCurrentBoat(); - const { data: attachments } = useList({ + const { data: attachments } = useList({ resource: 'equipment_attachments', filters: [{ field: 'equipment_id', operator: 'eq', value: equipmentId }], }); - const { mutate: createAttachment } = useCreate({ + const { mutate: createAttachment } = useCreate({ resource: 'equipment_attachments', }); @@ -62,7 +58,7 @@ const EquipmentAttachment: FC = ({ equipmentId }) => { }); if (uploadError) { - throw new Error('Error uploading file: ' + uploadError.message); + throw new Error(`Error uploading file: ${uploadError.message}`); } createAttachment({ @@ -80,13 +76,13 @@ const EquipmentAttachment: FC = ({ equipmentId }) => { } }; - const onDownload = async (attachment: Attachment) => { + const onDownload = async (attachment: EquipmentAttachment) => { const { data, error } = await supabase.storage .from('boat_attachments') .createSignedUrl(attachment.file_path, 3600); if (error) { - console.error('Error creating signed URL:', error.message); + console.error(`Error creating signed URL: ${error.message}`); return; } @@ -102,7 +98,7 @@ const EquipmentAttachment: FC = ({ equipmentId }) => { } }; - const onDelete = async (attachment: Attachment) => { + const onDelete = async (attachment: EquipmentAttachment) => { try { await supabase.storage .from('boat_attachments') @@ -166,4 +162,4 @@ const EquipmentAttachment: FC = ({ equipmentId }) => { ); }; -export { EquipmentAttachment }; +export { EquipmentAttachmentList }; diff --git a/src/equipments/pages/add.tsx b/src/equipments/pages/add.tsx index 3c6463a..5f34c96 100644 --- a/src/equipments/pages/add.tsx +++ b/src/equipments/pages/add.tsx @@ -3,6 +3,7 @@ import { useGo, useTranslation } from '@refinedev/core'; import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; import { EquipmentForm } from '@/equipments/components/equipment-form'; +import type { InsertEquipment } from '@/shared/types/models'; interface EquipmentFormValues { [key: string]: any; @@ -13,7 +14,7 @@ const AddEquipment = () => { const { translate } = useTranslation(); const go = useGo(); - const { formProps, saveButtonProps, onFinish } = useForm({ + const { formProps, saveButtonProps, onFinish } = useForm({ resource: 'equipments', action: 'create', redirect: false, diff --git a/src/equipments/pages/edit.tsx b/src/equipments/pages/edit.tsx index be35c2f..0f3c03a 100644 --- a/src/equipments/pages/edit.tsx +++ b/src/equipments/pages/edit.tsx @@ -3,17 +3,12 @@ import { useTranslation } from '@refinedev/core'; import { useParams } from 'react-router'; import { EquipmentForm } from '@/equipments/components/equipment-form'; - -interface Equipment { - id: string; - title: string; - description: string; -} +import type { UpdateEquipment } from '@/shared/types/models'; const EditEquipment = () => { const { equipmentId } = useParams<{ equipmentId: string }>(); const { translate } = useTranslation(); - const { formProps, saveButtonProps, onFinish } = useForm({ + const { formProps, saveButtonProps, onFinish } = useForm({ resource: 'equipments', action: 'edit', id: equipmentId, diff --git a/src/equipments/pages/list.tsx b/src/equipments/pages/list.tsx index 7861ae9..d33ada8 100644 --- a/src/equipments/pages/list.tsx +++ b/src/equipments/pages/list.tsx @@ -4,10 +4,10 @@ import { Button, Card, Empty, List } from 'antd'; import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; import { boatSystemList } from '@/boats/utils/boat-system'; import { EquipmentActionsMenu } from '@/equipments/components/equipment-actions-menu'; -import type { Equipment } from '@/models/equipment'; import { PageContent } from '@/shared/components/page-content'; import { PageHeader } from '@/shared/components/page-header'; import { SectionHeader } from '@/shared/components/section-header'; +import type { Equipment } from '@/shared/types/models'; const getEquipmentSubtitle = (equipment: Equipment) => { return ( diff --git a/src/equipments/pages/show.tsx b/src/equipments/pages/show.tsx index 36fd56b..4af853c 100644 --- a/src/equipments/pages/show.tsx +++ b/src/equipments/pages/show.tsx @@ -4,7 +4,7 @@ import dayjs from 'dayjs'; import { useParams } from 'react-router'; import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; -import { EquipmentAttachment } from '@/equipments/components/equipment-attachment'; +import { EquipmentAttachmentList } from '@/equipments/components/equipment-attachment-list'; import { PageHeader } from '@/shared/components/page-header'; const ShowEquipment = () => { @@ -88,7 +88,7 @@ const ShowEquipment = () => { ) : null} - + ); }; diff --git a/src/interventions/pages/edit.tsx b/src/interventions/pages/edit.tsx index b3d0759..1cbfc5e 100644 --- a/src/interventions/pages/edit.tsx +++ b/src/interventions/pages/edit.tsx @@ -2,16 +2,11 @@ import { Edit, useForm } from '@refinedev/antd'; import { useParams } from 'react-router'; import { InterventionForm } from '@/interventions/components/intervention-form'; - -interface Intervention { - id: string; - title: string; - description: string; -} +import type { UpdateIntervention } from '@/shared/types/models'; const EditIntervention = () => { const { interventionId } = useParams<{ interventionId: string }>(); - const { formProps, saveButtonProps, onFinish } = useForm({ + const { formProps, saveButtonProps, onFinish } = useForm({ resource: 'interventions', action: 'edit', id: interventionId, diff --git a/src/models/equipment.ts b/src/models/equipment.ts deleted file mode 100644 index c8f42fc..0000000 --- a/src/models/equipment.ts +++ /dev/null @@ -1,10 +0,0 @@ -interface Equipment { - id: string; - name: string; - description: string; - system_key: string; - brand?: string; - model?: string; -} - -export type { Equipment }; diff --git a/src/shared/types/models.ts b/src/shared/types/models.ts new file mode 100644 index 0000000..4668429 --- /dev/null +++ b/src/shared/types/models.ts @@ -0,0 +1,15 @@ +import type { + Tables, + TablesInsert, + TablesUpdate, +} from '@/shared/types/supabase'; + +export type Equipment = Tables<'equipments'>; +export type InsertEquipment = TablesInsert<'equipments'>; +export type UpdateEquipment = TablesUpdate<'equipments'>; + +export type EquipmentAttachment = Tables<'equipment_attachments'>; + +export type Access = Tables<'accesses'>; + +export type UpdateIntervention = TablesUpdate<'interventions'>;