feat: enhance user seeding with UUIDs and improve code formatting in various files

This commit is contained in:
2025-10-18 19:37:32 +02:00
parent 94ed954dc1
commit 35600023b7
10 changed files with 2213 additions and 764 deletions

View File

@@ -2,22 +2,23 @@ name: CI
on:
pull_request:
branches: [ main ]
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- uses: pnpm/action-setup@v4
with:
version: 8
- run: pnpm install
- run: npx prisma generate
- run: npx prisma db push
- run: node scripts/seed-test.js
- run: pnpm ci
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- uses: pnpm/action-setup@v4
with:
version: 8
- run: pnpm install
- run: npx prisma generate
- run: npx prisma db push
- run: node scripts/seed-test.js
- run: pnpm ci
- run: pnpm run build

View File

@@ -246,7 +246,8 @@ export default function AdminPage() {
const userMap = users.reduce(
(acc, user) => {
const name = `${user.firstName || ''} ${user.lastName || ''}`.trim() || user.email;
const name =
`${user.firstName || ''} ${user.lastName || ''}`.trim() || user.email;
acc[user.id] = { name, email: user.email, role: user.role };
return acc;
},
@@ -256,7 +257,7 @@ export default function AdminPage() {
const userTotals = users.reduce(
(acc, user) => {
acc[user.id] = hours
.filter(h => h.userId === user.id && h.status === 'VALIDATED')
.filter((h) => h.userId === user.id && h.status === 'VALIDATED')
.reduce((sum, h) => sum + h.duration, 0);
return acc;
},
@@ -444,13 +445,14 @@ export default function AdminPage() {
<TableCell>{hour.reason}</TableCell>
<TableCell>
{hour.status === 'VALIDATED' && hour.validatedBy
? `Validé par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() || hour.validatedBy.email
? `Validé par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() ||
hour.validatedBy.email
: hour.status === 'REJECTED' && hour.validatedBy
? `Rejeté par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() || hour.validatedBy.email
: hour.status === 'PENDING'
? 'En attente'
: hour.status
}
? `Rejeté par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() ||
hour.validatedBy.email
: hour.status === 'PENDING'
? 'En attente'
: hour.status}
</TableCell>
<TableCell>{userMap[hour.userId]?.name}</TableCell>
<TableCell>
@@ -729,7 +731,10 @@ export default function AdminPage() {
</Dialog>
)}
{selectedUserForReset && (
<Dialog open={resetPasswordDialog} onOpenChange={setResetPasswordDialog}>
<Dialog
open={resetPasswordDialog}
onOpenChange={setResetPasswordDialog}
>
<DialogContent>
<DialogHeader>
<DialogTitle>Réinitialiser le mot de passe</DialogTitle>
@@ -750,23 +755,31 @@ export default function AdminPage() {
</div>
</div>
<DialogFooter>
<Button onClick={() => setResetPasswordDialog(false)}>Annuler</Button>
<Button onClick={() => setResetPasswordDialog(false)}>
Annuler
</Button>
<Button onClick={handleResetPassword}>Réinitialiser</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
{selectedUserForReset && confirmResetPassword && (
<Dialog open={confirmResetPassword} onOpenChange={setConfirmResetPassword}>
<Dialog
open={confirmResetPassword}
onOpenChange={setConfirmResetPassword}
>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirmation de réinitialisation</DialogTitle>
</DialogHeader>
<DialogDescription>
Êtes-vous sûr de vouloir réinitialiser le mot de passe de {selectedUserForReset.name} ?
Êtes-vous sûr de vouloir réinitialiser le mot de passe de{' '}
{selectedUserForReset.name} ?
</DialogDescription>
<DialogFooter>
<Button onClick={() => setConfirmResetPassword(false)}>Annuler</Button>
<Button onClick={() => setConfirmResetPassword(false)}>
Annuler
</Button>
<Button onClick={handleConfirmResetPassword}>Confirmer</Button>
</DialogFooter>
</DialogContent>

View File

@@ -243,14 +243,17 @@ export default function DashboardPage() {
</TableCell>
<TableCell>{hour.duration} min</TableCell>
<TableCell>{hour.reason}</TableCell>
<TableCell>{hour.status === 'VALIDATED' && hour.validatedBy
? `Validé par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() || hour.validatedBy.email
<TableCell>
{hour.status === 'VALIDATED' && hour.validatedBy
? `Validé par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() ||
hour.validatedBy.email
: hour.status === 'REJECTED' && hour.validatedBy
? `Rejeté par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() || hour.validatedBy.email
: hour.status === 'PENDING'
? 'En attente'
: hour.status
}</TableCell>
? `Rejeté par ${hour.validatedBy.firstName || ''} ${hour.validatedBy.lastName || ''}`.trim() ||
hour.validatedBy.email
: hour.status === 'PENDING'
? 'En attente'
: hour.status}
</TableCell>
{isAdmin && <TableCell>{hour.user.email}</TableCell>}
{isAdmin && (
<TableCell>

View File

@@ -22,12 +22,15 @@ export default function Header() {
{session && (
<div className="flex items-center space-x-4">
<span className="text-gray-900 dark:text-white">
{session.user.email} ({
session.user.role === 'MEMBER' ? 'Membre' :
session.user.role === 'ADMIN' ? 'Bureau' :
session.user.role === 'SUPER_ADMIN' ? 'Gestionnaire' :
session.user.role
})
{session.user.email} (
{session.user.role === 'MEMBER'
? 'Membre'
: session.user.role === 'ADMIN'
? 'Bureau'
: session.user.role === 'SUPER_ADMIN'
? 'Gestionnaire'
: session.user.role}
)
</span>
<Button onClick={() => signOut()} variant="destructive">
Déconnexion

View File

@@ -8,9 +8,7 @@ export function Providers({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<SettingsProvider>
{children}
</SettingsProvider>
<SettingsProvider>{children}</SettingsProvider>
</ThemeProvider>
</SessionProvider>
);

View File

@@ -1,6 +1,12 @@
'use client';
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import {
createContext,
useContext,
useState,
useEffect,
ReactNode,
} from 'react';
interface Settings {
name: string;
@@ -12,7 +18,9 @@ interface SettingsContextType {
refetchSettings: () => void;
}
const SettingsContext = createContext<SettingsContextType | undefined>(undefined);
const SettingsContext = createContext<SettingsContextType | undefined>(
undefined,
);
export function useSettings() {
const context = useContext(SettingsContext);
@@ -38,7 +46,9 @@ export function SettingsProvider({ children }: { children: ReactNode }) {
}, []);
return (
<SettingsContext.Provider value={{ settings, refetchSettings: fetchSettings }}>
<SettingsContext.Provider
value={{ settings, refetchSettings: fetchSettings }}
>
{children}
</SettingsContext.Provider>
);

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'cypress'
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
@@ -7,4 +7,4 @@ export default defineConfig({
// implement node event listeners here
},
},
})
});

View File

@@ -1,10 +1,9 @@
describe('Login', () => {
it('should login successfully', () => {
cy.visit('/login')
cy.get('input[name="email"]').type('test@example.com')
cy.get('input[name="password"]').type('password')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
})
})
cy.visit('/login');
cy.get('input[name="email"]').type('test@example.com');
cy.get('input[name="password"]').type('password');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
});

2838
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
const { PrismaClient } = require('@prisma/client');
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');
const prisma = new PrismaClient();
@@ -15,6 +16,7 @@ async function main() {
role: 'MEMBER',
firstName: 'Test',
lastName: 'User',
id: uuidv4(),
},
});