From 03b4dce353b16ff9e9a457f48e3cfa1fa0267183 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 19:12:39 +0200 Subject: [PATCH 1/7] feat: Add notificationProvider to Refine from Ant Design --- src/core/components/app-provider.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/components/app-provider.tsx b/src/core/components/app-provider.tsx index 3282cd0..0f5e771 100644 --- a/src/core/components/app-provider.tsx +++ b/src/core/components/app-provider.tsx @@ -1,3 +1,4 @@ +import { useNotificationProvider } from '@refinedev/antd'; import { Refine } from '@refinedev/core'; import routerProvider from '@refinedev/react-router'; import { dataProvider } from '@refinedev/supabase'; @@ -27,6 +28,7 @@ const AppProvider: FC = ({ children }) => { authProvider={authProvider} routerProvider={routerProvider} i18nProvider={i18nProvider} + notificationProvider={useNotificationProvider} > {children} From ba48503358b16cf8f155c8a515339bb244b079e7 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 14:42:07 +0200 Subject: [PATCH 2/7] chore: Add instructions for Github Copilot --- .github/copilot-instructions.md | 66 +++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..0f311ab --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,66 @@ +# VesselVigil — AI Agent Instructions + +This document guides AI agents to contribute effectively to the VesselVigil project. + +## Overview +- **VesselVigil** is an open-source application for managing boat maintenance: tracking interventions, inventory of parts, access and account management. +- Architecture: + - Frontend : **React + TypeScript** with **Vite** + - Backend : **Supabase** for database and authentication. +- Folders structure: + - The project uses a **feature-based architecture**. This improves modularity and makes it easier to work on a specific feature without affecting others. + - `src/boats/`, `src/equipments/`, `src/interventions/`: each main business domain (boats, equipments, interventions) is organized in its own folder containing all related components, pages, hooks, and utils. + - `src/core/`: layout, provider, global routing. + - `src/shared/`: reusable components and common types. + - `supabase/`: SQL schemas, migrations, seeds. + +## Conventions and patterns +- **Pages**: each entity has a `pages/` folder for main views (e.g., `add.tsx`, `list.tsx`, `dashboard.tsx`). +- **Components**: reusable, organized by entity in `components/`. +- **Hooks**: business logic in `hooks/` (e.g., `use-current-boat.tsx`). +- **Utils**: business helpers in `utils/`. +- **Types**: centralized in `src/shared/types/`. +- **I18n**: translation files in `public/locales/`. +- **Authentication**: handled via Supabase and Refine, see `src/auth/providers/auth-provider.ts`. + +## React librairies +- **Refine**: used for data management and UI components. +- **Ant Design**: UI components library. +- **React Router**: for routing. + +## React usage +- Use **functional components** with hooks. +- Use **TypeScript** for type safety. +- Use kebab-case for file names (e.g., `add-boat.tsx`, `boat-list.tsx`). +- Use **named exports** for components. +- Export components at the bottom of the file. +- Use PascalCase for component names (e.g., `AddBoat`, `BoatList`). +- One component per file, with the file name matching the component name. + +## Supabase usage +- **Supabase client**: Always access Supabase using the helper in `src/core/utils/supabaseClient.ts`. Do not instantiate Supabase clients elsewhere. +- **Database schemas**: All table and relationship definitions are stored in `supabase/schemas/`. Update these files when changing the database structure. +- **Migrations**: SQL migration scripts are located in `supabase/migrations/`. These scripts are generated from the schema files and must be applied to keep the Supabase database up to date. + +## Refine usage +- Use Refine hooks (e.g., `useList`, `useDelete`, `useCreate`) for all Supabase data operations. Avoid direct Supabase client calls except in utilities. +- Organize Refine logic by feature: hooks and pages for each entity (boats, equipments, interventions). +- Prefer declarative data fetching and mutation via Refine, and leverage its built-in error/loading states. +- Example: To list boats, use `useList` in `src/boats/pages/list.tsx`. +- To navigate between pages, use the `useGo` hook or the `Link` component from Refine. + +## Ant Design usage +- Use Ant Design components for all UI elements unless a custom component is required. +- Customize Ant Design components using props and the project's global styles (`src/global.css`). +- Organize UI components by feature in their respective `components/` folders. +- Example: Use `` for entity lists, `` for add/edit pages, and ` + + + {`${translate('settings.common.deleteBoat.modalText')} `} + {boatName} + + setInputName(e.target.value)} + /> + + + ); +}; diff --git a/src/boats/pages/settings/common.tsx b/src/boats/pages/settings/common.tsx index 1b6f67c..9b80d4c 100644 --- a/src/boats/pages/settings/common.tsx +++ b/src/boats/pages/settings/common.tsx @@ -1,6 +1,6 @@ import { useTranslation } from '@refinedev/core'; -import { Button } from 'antd'; +import { BoatDeleteButton } from '@/boats/components/boat-delete-button'; import { SettingsLayout } from '@/boats/components/settings-layout'; import { SectionHeader } from '@/shared/components/section-header'; @@ -14,15 +14,7 @@ const CommonSettings = () => { title={translate('settings.common.dangerZone.title')} subtitle={translate('settings.common.dangerZone.description')} /> - + ); From b130fc818672160475f1f4206043250c892599f0 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 15:36:47 +0200 Subject: [PATCH 4/7] feat: Allow user to rename a boat --- public/locales/en.json | 6 +++ public/locales/fr.json | 6 +++ src/boats/pages/settings/common.tsx | 68 +++++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index 7106761..a00bbfb 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -214,6 +214,12 @@ }, "common": { "title": "General Settings", + "rename": { + "label": "Boat name", + "save": "Rename", + "success": "Boat name updated successfully.", + "error": "Error updating boat name." + }, "dangerZone": { "title": "Danger Zone", "description": "Danger zone Be wary of the following features as they cannot be undone." diff --git a/public/locales/fr.json b/public/locales/fr.json index 4af7ad4..c04e5fa 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -214,6 +214,12 @@ }, "common": { "title": "Paramètres généraux", + "rename": { + "label": "Nom du bateau", + "save": "Renommer", + "success": "Nom du bateau mis à jour avec succès.", + "error": "Erreur lors de la mise à jour du nom du bateau." + }, "dangerZone": { "title": "Zone de danger", "description": "Zone de danger : Faites attention aux fonctionnalités suivantes car elles sont irréversibles." diff --git a/src/boats/pages/settings/common.tsx b/src/boats/pages/settings/common.tsx index 9b80d4c..74c7e23 100644 --- a/src/boats/pages/settings/common.tsx +++ b/src/boats/pages/settings/common.tsx @@ -1,21 +1,73 @@ -import { useTranslation } from '@refinedev/core'; +import { useTranslation, useUpdate } from '@refinedev/core'; +import { Button, Col, Form, Input, Row } from 'antd'; +import { useEffect, useState } from 'react'; +import { useParams } from 'react-router'; import { BoatDeleteButton } from '@/boats/components/boat-delete-button'; import { SettingsLayout } from '@/boats/components/settings-layout'; +import { useCurrentBoat } from '@/boats/hooks/use-current-boat'; import { SectionHeader } from '@/shared/components/section-header'; const CommonSettings = () => { const { translate } = useTranslation(); + const { boatId } = useParams(); + const { data, isLoading } = useCurrentBoat(); + const [name, setName] = useState(''); + const { mutate, isLoading: isUpdating } = useUpdate(); + + useEffect(() => { + if (data?.data?.name) { + setName(data.data.name); + } + }, [data]); + + const handleSave = () => { + if (!name.trim()) return; + mutate({ + resource: 'boats', + id: boatId, + values: { name }, + successNotification: () => ({ + message: translate('settings.common.rename.success'), + type: 'success', + }), + errorNotification: () => ({ + message: translate('settings.common.rename.error'), + type: 'error', + }), + }); + }; return ( -
- - -
+ + +
+ + setName(e.target.value)} + disabled={isLoading || isUpdating} + /> + + + + + + + + + ); }; From cdbd93524cca4fcc2c9d9b0a492475f4d65f8be5 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 18:35:15 +0200 Subject: [PATCH 5/7] refactor: Follow features based arrangement for translation --- public/locales/en.json | 67 +++++++++-------- public/locales/fr.json | 73 ++++++++++--------- src/auth/components/logout-button.tsx | 5 +- src/boats/pages/dashboard.tsx | 2 +- src/boats/pages/list.tsx | 2 +- .../components/intervention-form.tsx | 9 ++- src/interventions/pages/add.tsx | 2 +- src/interventions/pages/edit.tsx | 7 +- src/interventions/pages/list.tsx | 6 +- src/interventions/pages/show.tsx | 4 +- 10 files changed, 101 insertions(+), 76 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index a00bbfb..f290476 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -76,46 +76,31 @@ "buttons": { "submit": "Update" } - }, - "dashboard": { - "title": "Tableau de bord" - } - }, - "LogoutButton": { - "label": "Logout" - }, - "ListBoat": { - "title": "Your boats", - "add": "Create a new boat" - }, - "AddBoat": { - "title": "Add a new boat", - "labels": { - "name": "Name" } }, - "InterventionList": { - "title": "Intervention List", - "add": "Add an intervention" - }, - "AddIntervention": { - "title": "Add an intervention", - "labels": { - "title": "Title", - "date": "Date", - "description": "Description" - } - }, - "InterventionShow": { - "edit": "Edit Intervention" + "auth": { + "logout": "Logout" }, "boats": { + "list": { + "title": "Your boats", + "add": "Create a new boat" + }, + "add": { + "title": "Add a new boat", + "labels": { + "name": "Name" + } + }, "menu": { "dashboard": "Dashboard", "interventions": "Interventions", "equipments": "Equipments", "settings": "Settings" }, + "dashboard": { + "title": "Dashboard" + }, "systems": { "select": { "placeholder": "Select a system" @@ -207,6 +192,28 @@ "add": "Add an attachment" } }, + "interventions": { + "list": { + "title": "Intervention List", + "add": "Add an intervention" + }, + "add": { + "title": "Add an intervention" + }, + "show": { + "edit": "Edit Intervention" + }, + "edit": { + "title": "Edit Intervention" + }, + "form": { + "labels": { + "title": "Title", + "date": "Date", + "description": "Description" + } + } + }, "settings": { "menu": { "common": "General", diff --git a/public/locales/fr.json b/public/locales/fr.json index c04e5fa..b23b135 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -76,46 +76,31 @@ "buttons": { "submit": "Mettre à jour" } - }, - "dashboard": { - "title": "Tableau de bord" - } - }, - "LogoutButton": { - "label": "Déconnexion" - }, - "ListBoat": { - "title": "Vos bateaux", - "add": "Ajouter un nouveau bateau" - }, - "AddBoat": { - "title": "Ajouter un nouveau bateau", - "labels": { - "name": "Nom" - } - }, - "InterventionList": { - "title": "Liste des interventions", - "add": "Ajouter une intervention" - }, - "AddIntervention": { - "title": "Ajouter une intervention", - "labels": { - "title": "Titre", - "date": "Date", - "description": "Description" } }, - "InterventionShow": { - "edit": "Modifier l'intervention" + "auth": { + "logout": "Déconnexion" }, "boats": { + "list": { + "title": "Vos bateaux", + "add": "Ajouter un nouveau bateau" + }, + "add": { + "title": "Ajouter un nouveau bateau", + "labels": { + "name": "Nom" + } + }, "menu": { "dashboard": "Tableau de bord", "interventions": "Interventions", "equipments": "Équipements", "settings": "Paramètres" }, + "dashboard": { + "title": "Tableau de bord" + }, "systems": { "select": { "placeholder": "Sélectionnez un système" @@ -174,13 +159,13 @@ "add": { "title": "Ajouter un équipement" }, + "edit": { + "title": "Modifier l'équipement" + }, "show": { "title": "Détails de l'équipement", "edit": "Modifier l'équipement" }, - "edit": { - "title": "Modifier l'équipement" - }, "delete": { "confirmTitle": "Confirmer la suppression", "confirmContent": "Voulez-vous vraiment supprimer cet équipement ?" @@ -207,6 +192,28 @@ "add": "Ajouter une pièce jointe" } }, + "interventions": { + "list": { + "title": "Liste des interventions", + "add": "Ajouter une intervention" + }, + "add": { + "title": "Ajouter une intervention" + }, + "show": { + "edit": "Modifier l'intervention" + }, + "edit": { + "title": "Editer l'intervention" + }, + "form": { + "labels": { + "title": "Titre", + "date": "Date", + "description": "Description" + } + } + }, "settings": { "menu": { "common": "Général", diff --git a/src/auth/components/logout-button.tsx b/src/auth/components/logout-button.tsx index e1d3100..7962433 100644 --- a/src/auth/components/logout-button.tsx +++ b/src/auth/components/logout-button.tsx @@ -1,6 +1,5 @@ -import { useLogout } from '@refinedev/core'; +import { useLogout, useTranslation } from '@refinedev/core'; import type { FC } from 'react'; -import { useTranslation } from '@refinedev/core'; interface LogoutButtonProps { style?: React.CSSProperties; @@ -13,7 +12,7 @@ export const LogoutButton: FC = ({ style }) => { return ( ); }; diff --git a/src/boats/pages/dashboard.tsx b/src/boats/pages/dashboard.tsx index bb6cdbb..c5fe1f9 100644 --- a/src/boats/pages/dashboard.tsx +++ b/src/boats/pages/dashboard.tsx @@ -4,7 +4,7 @@ import { PageHeader } from '@/shared/components/page-header'; const BoatDashboard = () => { const { translate } = useTranslation(); - return ; + return ; }; export { BoatDashboard }; diff --git a/src/boats/pages/list.tsx b/src/boats/pages/list.tsx index a62248b..1892660 100644 --- a/src/boats/pages/list.tsx +++ b/src/boats/pages/list.tsx @@ -14,7 +14,7 @@ const ListBoat = () => { return ( - + {boats?.data?.map((boat) => ( diff --git a/src/interventions/components/intervention-form.tsx b/src/interventions/components/intervention-form.tsx index 94cd10b..48703fc 100644 --- a/src/interventions/components/intervention-form.tsx +++ b/src/interventions/components/intervention-form.tsx @@ -16,17 +16,20 @@ const InterventionForm: FC = ({ return (
- + ({ value: value ? dayjs(value) : null })} > diff --git a/src/interventions/pages/add.tsx b/src/interventions/pages/add.tsx index 6fe116e..2aca6c7 100644 --- a/src/interventions/pages/add.tsx +++ b/src/interventions/pages/add.tsx @@ -27,7 +27,7 @@ const AddIntervention = () => { return ( diff --git a/src/interventions/pages/edit.tsx b/src/interventions/pages/edit.tsx index 1cbfc5e..fc22898 100644 --- a/src/interventions/pages/edit.tsx +++ b/src/interventions/pages/edit.tsx @@ -1,4 +1,5 @@ import { Edit, useForm } from '@refinedev/antd'; +import { useTranslate } from '@refinedev/core'; import { useParams } from 'react-router'; import { InterventionForm } from '@/interventions/components/intervention-form'; @@ -11,9 +12,13 @@ const EditIntervention = () => { action: 'edit', id: interventionId, }); + const translate = useTranslate(); return ( - + ); diff --git a/src/interventions/pages/list.tsx b/src/interventions/pages/list.tsx index 3358810..6fc892c 100644 --- a/src/interventions/pages/list.tsx +++ b/src/interventions/pages/list.tsx @@ -16,10 +16,12 @@ const InterventionList = () => { return ( <> - + } /> diff --git a/src/interventions/pages/show.tsx b/src/interventions/pages/show.tsx index 866f10e..507e08d 100644 --- a/src/interventions/pages/show.tsx +++ b/src/interventions/pages/show.tsx @@ -24,7 +24,9 @@ const ShowIntervention = () => { - + } /> From dc201a3c252d47da1ff84e2b002264bbd8f061f4 Mon Sep 17 00:00:00 2001 From: cballevre Date: Wed, 30 Jul 2025 18:53:34 +0200 Subject: [PATCH 6/7] refactor: Replace useTranslation by useTranslate hook --- src/auth/components/logout-button.tsx | 4 ++-- src/auth/pages/login.tsx | 4 ++-- src/boats/components/access-list.tsx | 7 +++---- src/boats/components/boat-delete-button.tsx | 4 ++-- src/boats/components/boat-menu.tsx | 4 ++-- src/boats/components/boat-system-select.tsx | 4 ++-- src/boats/components/settings-menu.tsx | 4 ++-- src/boats/pages/add.tsx | 4 ++-- src/boats/pages/dashboard.tsx | 4 ++-- src/boats/pages/list.tsx | 4 ++-- src/boats/pages/settings/access.tsx | 4 ++-- src/boats/pages/settings/common.tsx | 4 ++-- src/equipments/components/equipment-actions-menu.tsx | 4 ++-- src/equipments/components/equipment-attachment-list.tsx | 4 ++-- src/equipments/components/equipment-form.tsx | 4 ++-- src/equipments/pages/add.tsx | 4 ++-- src/equipments/pages/edit.tsx | 4 ++-- src/equipments/pages/list.tsx | 4 ++-- src/equipments/pages/show.tsx | 4 ++-- src/interventions/components/intervention-form.tsx | 4 ++-- src/interventions/pages/add.tsx | 4 ++-- src/interventions/pages/list.tsx | 4 ++-- src/interventions/pages/show.tsx | 4 ++-- 23 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/auth/components/logout-button.tsx b/src/auth/components/logout-button.tsx index 7962433..0b3415c 100644 --- a/src/auth/components/logout-button.tsx +++ b/src/auth/components/logout-button.tsx @@ -1,4 +1,4 @@ -import { useLogout, useTranslation } from '@refinedev/core'; +import { useLogout, useTranslate } from '@refinedev/core'; import type { FC } from 'react'; interface LogoutButtonProps { @@ -8,7 +8,7 @@ interface LogoutButtonProps { export const LogoutButton: FC = ({ style }) => { const { mutate: logout } = useLogout(); - const { translate } = useTranslation(); + const translate = useTranslate(); return (