diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 01d4331..3180466 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -52,8 +52,28 @@ Pour le front-end, les exigences de qualité sont les suivantes : - Documentation en français pour les nouvelles fonctionnalités (si applicable) - Référence : [documentation guidelines](./instructions/documentation.instruction.md) +## Design System + +Le projet utilise un design system défini. Toujours s'y conformer lors de toute modification de l'interface. + +- Référence complète : [design system](../docs/design-system.md) +- Règles Copilot : [design system instructions](./instructions/design-system.instruction.md) + +### Résumé des tokens obligatoires + +| Token Tailwind | Hex | Usage | +|----------------|-----------|-------------------------------| +| `primary` | `#059669` | Boutons, CTA, éléments actifs | +| `secondary` | `#064E3B` | Hover, accents sombres | +| `tertiary` | `#10B981` | Badges, icônes | +| `neutral` | `#F8FAFC` | Fonds de page, surfaces | + +- Polices : `font-headline` (Manrope) pour les titres, `font-body`/`font-label` (Inter) pour le reste +- **Ne jamais** utiliser `emerald-*` pour les éléments interactifs + ## Références - **Tickets** : [issues guidelines](./instructions/issues.instruction.md) - **Commits** : [commit guidelines](./instructions/general-commit.instruction.md) - **Tests** : [run tests](./instructions/run-tests.instruction.md) +- **Design System** : [design system instructions](./instructions/design-system.instruction.md) diff --git a/.github/instructions/design-system.instruction.md b/.github/instructions/design-system.instruction.md new file mode 100644 index 0000000..3706107 --- /dev/null +++ b/.github/instructions/design-system.instruction.md @@ -0,0 +1,116 @@ +--- +applyTo: "Front-End/src/**" +--- + +# Design System — Règles Copilot + +Référence complète : [`docs/design-system.md`](../../docs/design-system.md) + +## Couleurs — tokens Tailwind obligatoires + +Utiliser **toujours** ces tokens pour les éléments interactifs : + +| Token | Hex | Remplace | +|-------------|-----------|-----------------------------------| +| `primary` | `#059669` | `emerald-600`, `emerald-500` | +| `secondary` | `#064E3B` | `emerald-700`, `emerald-800` | +| `tertiary` | `#10B981` | `emerald-400`, `emerald-500` | +| `neutral` | `#F8FAFC` | Fonds neutres | + +**Ne jamais écrire** `bg-emerald-*`, `text-emerald-*`, `border-emerald-*` pour des éléments interactifs. + +### Patterns corrects + +```jsx +// Bouton + +``` + +- Taille par défaut : `size={20}` inline, `size={24}` boutons standalone +- Couleur via `className="text-*"` uniquement — jamais le prop `color` +- Icône seule : ajouter `aria-label` pour l'accessibilité + +--- + +## Responsive & PWA + +**Mobile-first** : les styles de base ciblent le mobile, on étend avec `sm:` / `md:` / `lg:`. + +```jsx +// Layout +
+ +// Grille +
+ +// Bouton full-width mobile + + +
+ ) : ( +
+ + +
+ )} + + + ); + })} + + +
+ ); + } + )} )} diff --git a/Front-End/src/app/[locale]/admin/subscriptions/createSubscription/page.js b/Front-End/src/app/[locale]/admin/subscriptions/createSubscription/page.js index 929f518..cba992c 100644 --- a/Front-End/src/app/[locale]/admin/subscriptions/createSubscription/page.js +++ b/Front-End/src/app/[locale]/admin/subscriptions/createSubscription/page.js @@ -34,12 +34,13 @@ import { import { fetchRegistrationFileGroups, fetchRegistrationSchoolFileMasters, - fetchRegistrationParentFileMasters + fetchRegistrationParentFileMasters, } from '@/app/actions/registerFileGroupAction'; import { fetchProfiles } from '@/app/actions/authAction'; import { useClasses } from '@/context/ClassesContext'; import { useCsrfToken } from '@/context/CsrfContext'; -import { FE_ADMIN_SUBSCRIPTIONS_URL, BASE_URL } from '@/utils/Url'; +import { FE_ADMIN_SUBSCRIPTIONS_URL } from '@/utils/Url'; +import { getSecureFileUrl } from '@/utils/fileUrl'; import { useNotification } from '@/context/NotificationContext'; export default function CreateSubscriptionPage() { @@ -181,7 +182,9 @@ export default function CreateSubscriptionPage() { formDataRef.current = formData; }, [formData]); - useEffect(() => { setStudentsPage(1); }, [students]); + useEffect(() => { + setStudentsPage(1); + }, [students]); useEffect(() => { if (!formData.guardianEmail) { @@ -530,7 +533,7 @@ export default function CreateSubscriptionPage() { 'Succès' ); router.push(FE_ADMIN_SUBSCRIPTIONS_URL); - }) + }) .catch((error) => { setIsLoading(false); logger.error('Erreur lors de la mise à jour du dossier:', error); @@ -714,7 +717,10 @@ export default function CreateSubscriptionPage() { }; const studentsTotalPages = Math.ceil(students.length / ITEMS_PER_PAGE); - const pagedStudents = students.slice((studentsPage - 1) * ITEMS_PER_PAGE, studentsPage * ITEMS_PER_PAGE); + const pagedStudents = students.slice( + (studentsPage - 1) * ITEMS_PER_PAGE, + studentsPage * ITEMS_PER_PAGE + ); if (isLoading === true) { return ; // Affichez le composant Loader @@ -884,12 +890,12 @@ export default function CreateSubscriptionPage() {
{row.photo ? ( {`${row.first_name} diff --git a/Front-End/src/app/[locale]/admin/subscriptions/page.js b/Front-End/src/app/[locale]/admin/subscriptions/page.js index b534fc5..d69931a 100644 --- a/Front-End/src/app/[locale]/admin/subscriptions/page.js +++ b/Front-End/src/app/[locale]/admin/subscriptions/page.js @@ -37,8 +37,8 @@ import { FE_ADMIN_SUBSCRIPTIONS_EDIT_URL, FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL, FE_ADMIN_SUBSCRIPTIONS_CREATE_URL, - BASE_URL, } from '@/utils/Url'; +import { getSecureFileUrl } from '@/utils/fileUrl'; import DjangoCSRFToken from '@/components/DjangoCSRFToken'; import { useCsrfToken } from '@/context/CsrfContext'; @@ -114,15 +114,29 @@ export default function Page({ params: { locale } }) { // Valide le refus const handleRefuse = () => { if (!refuseReason.trim()) { - showNotification('Merci de préciser la raison du refus.', 'error', 'Erreur'); + showNotification( + 'Merci de préciser la raison du refus.', + 'error', + 'Erreur' + ); return; } const formData = new FormData(); - formData.append('data', JSON.stringify({ status: RegistrationFormStatus.STATUS_ARCHIVED, notes: refuseReason })); - + formData.append( + 'data', + JSON.stringify({ + status: RegistrationFormStatus.STATUS_ARCHIVED, + notes: refuseReason, + }) + ); + editRegisterForm(rowToRefuse.student.id, formData, csrfToken) .then(() => { - showNotification('Le dossier a été refusé et archivé.', 'success', 'Succès'); + showNotification( + 'Le dossier a été refusé et archivé.', + 'success', + 'Succès' + ); setReloadFetch(true); setIsRefusePopupOpen(false); }) @@ -713,12 +727,12 @@ export default function Page({ params: { locale } }) {
{row.student.photo ? ( {`${row.student.first_name} @@ -953,7 +967,9 @@ export default function Page({ params: { locale } }) { isOpen={isRefusePopupOpen} message={
-
Veuillez indiquer la raison du refus :
+
+ Veuillez indiquer la raison du refus : +