Skip to content

Commit

Permalink
Mise en place de la pagination pour les admins sur la liste des inven…
Browse files Browse the repository at this point in the history
…taires
  • Loading branch information
NerOcrO committed May 14, 2024
1 parent c38d979 commit f551ac6
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 96 deletions.
24 changes: 20 additions & 4 deletions src/app/(connecte)/(both)/inventaires/page.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import { inventaireModel } from '@prisma/client'
import { Metadata } from 'next'
import { ReactElement } from 'react'

import { getProfilAtih } from '../../../../authentification'
import InventairesLayout from '../../../../components/Inventaires/InventairesLayout'
import { inventairesPresenter } from '../../../../presenters/inventairesPresenter'
import { recupererLesInventairesRepository } from '../../../../repositories/inventairesRepository'
import { recupererLeTotalInventairesRepository, recupererLesInventairesPaginesRepository, recupererLesInventairesRepository } from '../../../../repositories/inventairesRepository'

export const metadata: Metadata = {
title: 'Inventaires',
}

export default async function PageInventaires(): Promise<ReactElement> {
type PageProps = Readonly<{
searchParams?: Readonly<{
page?: string
}>
}>

export default async function PageInventaires({ searchParams }: PageProps): Promise<ReactElement> {
const profil = await getProfilAtih()
const pageCourante = Number(searchParams?.page ?? 0)

const inventairesModel = await recupererLesInventairesRepository(profil.nomEtablissement)
// eslint-disable-next-line @typescript-eslint/init-declarations
let inventairesModel: ReadonlyArray<inventaireModel>
let totalInventaires = 0
if (profil.isAdmin) {
inventairesModel = await recupererLesInventairesPaginesRepository(pageCourante)
totalInventaires = await recupererLeTotalInventairesRepository()
} else {
inventairesModel = await recupererLesInventairesRepository(profil.nomEtablissement)
}

return (
<InventairesLayout
presenter={inventairesPresenter(inventairesModel, profil)}
presenter={inventairesPresenter(inventairesModel, profil, pageCourante, totalInventaires)}
/>
)
}
79 changes: 66 additions & 13 deletions src/components/Inventaires/Inventaires.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('page inventaires', () => {
vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([])

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const titre = screen.getByRole('heading', { level: 1 })
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('page inventaires', () => {
])

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const tableInventaires = screen.getByRole('table')
Expand Down Expand Up @@ -77,6 +77,28 @@ describe('page inventaires', () => {
expect(cellsRow2[4]).toHaveTextContent('Supprimer l’inventaire')
})

it('quand j’affiche la page alors je n’affiche pas la pagination', async () => {
// GIVEN
const nomEtablissement = jeSuisUnUtilisateur()

vi.stubGlobal('Date', FrozenDate)
vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([
inventaireModelFactory({
id: 1,
nomEtablissement,
nomInventaire: 'mon inventaire traité',
statut: 'TRAITE',
}),
])

// WHEN
renderComponent(await PageInventaires({}))

// THEN
const navigation = screen.queryByRole('navigation', { name: 'Pagination' })
expect(navigation).not.toBeInTheDocument()
})

it('quand j’affiche la page alors je ne peux pas télécharger l’export CSV', async () => {
// GIVEN
jeSuisUnUtilisateur()
Expand All @@ -90,7 +112,7 @@ describe('page inventaires', () => {
])

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const lienExporterLesInventaires = screen.queryByRole('link', { name: 'Exporter les inventaires' })
Expand All @@ -107,7 +129,7 @@ describe('page inventaires', () => {
.mockReturnValueOnce(spyNextNavigation.useRouter)
vi.spyOn(repositoryInventaires, 'supprimerUnInventaireRepository').mockResolvedValueOnce(new Date())

renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

const poubelle = screen.getByRole('button', { name: 'Supprimer l’inventaire' })
fireEvent.click(poubelle)
Expand All @@ -121,7 +143,7 @@ describe('page inventaires', () => {
await waitFor(() => {
expect(repositoryInventaires.supprimerUnInventaireRepository).toHaveBeenCalledWith('Hopital de Paris$$00000001K', 'mon super inventaire')
})
expect(spyNextNavigation.useRouter.push).toHaveBeenCalledWith('/')
expect(spyNextNavigation.useRouter.push).toHaveBeenCalledWith('/inventaires')
expect(spyNextNavigation.useRouter.refresh).toHaveBeenCalledWith()
const titreModale = within(modale).queryByRole('heading', { level: 1, name: 'Supprimer l’inventaire' })
expect(titreModale).not.toBeInTheDocument()
Expand All @@ -135,10 +157,10 @@ describe('page inventaires', () => {
// GIVEN
jeSuisUnAdmin()

vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([])
vi.spyOn(repositoryInventaires, 'recupererLesInventairesPaginesRepository').mockResolvedValueOnce([])

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const titre = screen.getByRole('heading', { level: 2 })
Expand All @@ -153,7 +175,7 @@ describe('page inventaires', () => {
// GIVEN
jeSuisUnAdmin()

vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([
vi.spyOn(repositoryInventaires, 'recupererLesInventairesPaginesRepository').mockResolvedValueOnce([
inventaireModelFactory({
id: 1,
nomEtablissement: 'Hopital A$$00000001K',
Expand All @@ -167,7 +189,7 @@ describe('page inventaires', () => {
])

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const listeInventaires = screen.getByRole('table')
Expand All @@ -186,20 +208,50 @@ describe('page inventaires', () => {
expect(cellsRow2[1]).toHaveTextContent('Hopital B')
})

it('quand j’affiche la page alors j’affiche la pagination', async () => {
// GIVEN
jeSuisUnAdmin()

vi.spyOn(repositoryInventaires, 'recupererLesInventairesPaginesRepository').mockResolvedValueOnce([
inventaireModelFactory({
id: 1,
nomEtablissement: 'Hopital A$$00000001K',
nomInventaire: 'mon inventaire A',
}),
])
vi.spyOn(repositoryInventaires, 'recupererLeTotalInventairesRepository').mockResolvedValueOnce(2)

// WHEN
renderComponent(await PageInventaires({}))

// THEN
const navigation = screen.getByRole('navigation', { name: 'Pagination' })
const menu = within(navigation).getByRole('list')
const menuItems = within(menu).getAllByRole('listitem')
expect(menuItems).toHaveLength(3)
const lienPagePrecedente = within(menuItems[0]).getByRole('link', { name: 'Page précédente' })
expect(lienPagePrecedente).toHaveAttribute('href', '/inventaires')
expect(menuItems[1]).toHaveTextContent('Page courante 1')
expect(menuItems[1]).toHaveAttribute('aria-current', 'page')
const lienPageSuivante = within(menuItems[2]).getByRole('link', { name: 'Page suivante' })
expect(lienPageSuivante).toHaveAttribute('href', '/inventaires?page=0')
})

it('quand j’affiche la page alors je n’ai pas accès à la duplication', async () => {
// GIVEN
jeSuisUnAdmin()

vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([
vi.spyOn(repositoryInventaires, 'recupererLesInventairesPaginesRepository').mockResolvedValueOnce([
inventaireModelFactory({
id: 1,
nomEtablissement: 'Hopital A$$00000001K',
nomInventaire: 'mon inventaire A',
}),
])
vi.spyOn(repositoryInventaires, 'recupererLeTotalInventairesRepository').mockResolvedValueOnce(2)

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const listeInventaires = screen.getByRole('table')
Expand All @@ -215,16 +267,17 @@ describe('page inventaires', () => {
// GIVEN
jeSuisUnAdmin()

vi.spyOn(repositoryInventaires, 'recupererLesInventairesRepository').mockResolvedValueOnce([
vi.spyOn(repositoryInventaires, 'recupererLesInventairesPaginesRepository').mockResolvedValueOnce([
inventaireModelFactory({
id: 1,
nomEtablissement: 'Hopital A$$00000001K',
nomInventaire: 'mon inventaire A',
}),
])
vi.spyOn(repositoryInventaires, 'recupererLeTotalInventairesRepository').mockResolvedValueOnce(2)

// WHEN
renderComponent(await PageInventaires())
renderComponent(await PageInventaires({}))

// THEN
const lienExporterLesInventaires = screen.getByRole('link', { name: 'Exporter les inventaires' })
Expand Down
160 changes: 86 additions & 74 deletions src/components/Inventaires/Inventaires.tsx
Original file line number Diff line number Diff line change
@@ -1,90 +1,102 @@
'use client'

import Link from 'next/link'
import React, { ReactElement } from 'react'

import ActionSupprimer from './ActionSupprimer'
import styles from './Inventaires.module.css'
import { InventairePresenter } from '../../presenters/inventairesPresenter'
import { formaterLeNomEtablissement } from '../../presenters/sharedPresenter'
import Pagination from '../sharedComponents/Pagination/Pagination'

type InventairesProps = Readonly<{
inventaires: ReadonlyArray<InventairePresenter>
isAdmin: boolean
pageCourante: number
totalInventaires: number
}>

export default function Inventaires({ inventaires }: InventairesProps): ReactElement {
export default function Inventaires({ inventaires, isAdmin, pageCourante, totalInventaires }: InventairesProps): ReactElement {
return (
<table className="table table-bordered">
<caption className="nav-skip">
Votre inventaire
</caption>
<thead>
<tr>
<th scope="col">
Nom de l’inventaire
</th>
<th scope="col">
Nom de l’organisation
</th>
<th scope="col">
Date de création
</th>
<th scope="col">
État
</th>
<th scope="col">
Action
</th>
</tr>
</thead>
<tbody>
{
inventaires.map((inventaire): ReactElement => {
return (
<tr key={inventaire.id}>
<td>
<Link href={inventaire.lienIndicateursCles}>
{inventaire.nomInventaire}
</Link>
</td>
<td>
{formaterLeNomEtablissement(inventaire.nomEtablissement)}
</td>
<td>
{inventaire.dateInventaire}
</td>
<td>
<span className={`${styles.pastille} ${styles[inventaire.className]} fz-16`}>
{inventaire.statut}
</span>
</td>
<td>
{
inventaire.lienDupliquer !== '/' ? (
<Link
className="text-default mr-2"
href={inventaire.lienDupliquer}
>
<svg
aria-hidden
className="svg-icon"
focusable="false"
<>
<table className="table table-bordered">
<caption className="nav-skip">
Votre inventaire
</caption>
<thead>
<tr>
<th scope="col">
Nom de l’inventaire
</th>
<th scope="col">
Nom de l’organisation
</th>
<th scope="col">
Date de création
</th>
<th scope="col">
État
</th>
<th scope="col">
Action
</th>
</tr>
</thead>
<tbody>
{
inventaires.map((inventaire): ReactElement => {
return (
<tr key={inventaire.id}>
<td>
<Link href={inventaire.lienIndicateursCles}>
{inventaire.nomInventaire}
</Link>
</td>
<td>
{formaterLeNomEtablissement(inventaire.nomEtablissement)}
</td>
<td>
{inventaire.dateInventaire}
</td>
<td>
<span className={`${styles.pastille} ${styles[inventaire.className]} fz-16`}>
{inventaire.statut}
</span>
</td>
<td>
{
inventaire.lienDupliquer !== '/' ? (
<Link
className="text-default mr-2"
href={inventaire.lienDupliquer}
>
<use xlinkHref="/svg-icons/icon-sprite.svg#duplicate" />
</svg>
<span className="sr-only">
Dupliquer l’inventaire
</span>
</Link>
) : null
}
<ActionSupprimer inventaire={inventaire} />
</td>
</tr>
)
})
}
</tbody>
</table>
<svg
aria-hidden
className="svg-icon"
focusable="false"
>
<use xlinkHref="/svg-icons/icon-sprite.svg#duplicate" />
</svg>
<span className="sr-only">
Dupliquer l’inventaire
</span>
</Link>
) : null
}
<ActionSupprimer inventaire={inventaire} />
</td>
</tr>
)
})
}
</tbody>
</table>
{
isAdmin ? (
<Pagination
pageCourante={pageCourante}
totalInventaires={totalInventaires}
/>
) : null
}
</>
)
}
Loading

0 comments on commit f551ac6

Please sign in to comment.