Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -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 `<Table />` for entity lists, `<Form />` for add/edit pages, and `<Button />` for actions.

## Translations usage
- All translations are stored in `public/locales/` in JSON files.
- Use `translate` function from `useTranslate` hook from Refine to access translations in components.
- Always provide translations for both English and French.
- Split each part of key into a json object inside locale files, e.g., `common.deleteBoat.button` will be `{ "common": { "deleteBoat": { "button": "The translation for the key" }}}`.
- Refine use i18next under the hood, follow its conventions for pluralization and interpolation.

## Project-specific best practices
- To get information about the current boat, use the `useCurrentBoat` hook from `src/boats/hooks/use-current-boat.tsx`.
98 changes: 68 additions & 30 deletions public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,46 +76,46 @@
"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",
"notification": {
"success": {
"message": "Your boat has been created.",
"description": "Success"
},
"error": {
"message": "There was an error while creating your boat.",
"description": "Error"
}
},
"form": {
"labels": {
"name": "Name"
},
"validation": {
"name_required": "Boat name is required."
}
}
},
"menu": {
"dashboard": "Dashboard",
"interventions": "Interventions",
"equipments": "Equipments",
"settings": "Settings"
},
"dashboard": {
"title": "Dashboard"
},
"systems": {
"select": {
"placeholder": "Select a system"
Expand Down Expand Up @@ -207,16 +207,54 @@
"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",
"access": "Access"
},
"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."
},
"deleteBoat": {
"button": "Delete boat",
"modalTitle": "Confirm deletion",
"modalText": "To confirm deletion, please type the name of the boat:",
"inputPlaceholder": "Boat name",
"okText": "Delete",
"cancelText": "Cancel",
"success": "Boat deleted",
"error": "Error while deleting"
}
},
"access": {
Expand Down
104 changes: 71 additions & 33 deletions public/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,46 +76,46 @@
"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",
"notification": {
"success": {
"description": "Succès",
"message": "Votre bateau a été créé avec succès."
},
"error": {
"description": "Une erreur est survenue lors de la création de votre bateau.",
"message": "Erreur"
}
},
"form": {
"labels": {
"name": "Nom"
},
"validation": {
"name_required": "Le nom du bateau est requis."
}
}
},
"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"
Expand Down Expand Up @@ -174,13 +174,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 ?"
Expand All @@ -207,16 +207,54 @@
"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",
"access": "Accès"
},
"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."
},
"deleteBoat": {
"button": "Supprimer le bateau",
"modalTitle": "Confirmer la suppression",
"modalText": "Pour confirmer la suppression, veuillez saisir le nom du bateau :",
"inputPlaceholder": "Nom du bateau",
"okText": "Supprimer",
"cancelText": "Annuler",
"success": "Bateau supprimé",
"error": "Erreur lors de la suppression"
}
},
"access": {
Expand Down
7 changes: 3 additions & 4 deletions src/auth/components/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useLogout } from '@refinedev/core';
import { useLogout, useTranslate } from '@refinedev/core';
import type { FC } from 'react';
import { useTranslation } from '@refinedev/core';

interface LogoutButtonProps {
style?: React.CSSProperties;
Expand All @@ -9,11 +8,11 @@ interface LogoutButtonProps {
export const LogoutButton: FC<LogoutButtonProps> = ({ style }) => {
const { mutate: logout } = useLogout();

const { translate } = useTranslation();
const translate = useTranslate();

return (
<button type="button" style={style} onClick={() => logout()}>
{translate('LogoutButton.label')}
{translate('auth.logout')}
</button>
);
};
4 changes: 2 additions & 2 deletions src/auth/pages/login.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { GoogleOutlined } from '@ant-design/icons';
import { AuthPage } from '@refinedev/antd';
import { useTranslation } from '@refinedev/core';
import { useTranslate } from '@refinedev/core';

const Login = () => {
const { translate } = useTranslation();
const translate = useTranslate();

return (
<AuthPage
Expand Down
Loading