Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
NerOcrO committed May 10, 2024
1 parent d271e32 commit c7db4f6
Show file tree
Hide file tree
Showing 48 changed files with 1,186 additions and 435 deletions.
2 changes: 1 addition & 1 deletion src/app/(connecte)/creer-un-inventaire/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const metadata: Metadata = {
title,
}

export default async function Page(): Promise<ReactElement> {
export default async function PageCreerUnInventaire(): Promise<ReactElement> {
const profil = await getProfilAtih()

if (profil.isAdmin) {
Expand Down
6 changes: 3 additions & 3 deletions src/app/(connecte)/indicateurs-cles/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export const metadata: Metadata = {
}

type PageProps = Readonly<{
searchParams: Readonly<{
searchParams?: Readonly<{
nomEtablissement?: string
nomInventaire?: string
}>
}>

export default async function Page({ searchParams }: PageProps): Promise<ReactElement> {
if (searchParams.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
export default async function PageIndicateursCles({ searchParams }: PageProps): Promise<ReactElement> {
if (searchParams?.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
notFound()
}

Expand Down
24 changes: 13 additions & 11 deletions src/app/(connecte)/inventaire/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@ export const metadata: Metadata = {
title,
}

export type PageProps = Readonly<{
searchParams: Readonly<{
dureeDeVie?: string
heureUtilisation?: string
nombreEquipement?: string
nomEtablissement?: string
nomInventaire?: string
nouveauNomInventaire?: string
statut?: StatutsInventaire
}>
export type SearchParams = Readonly<{
dureeDeVie?: string
heureUtilisation?: string
nombreEquipement?: string
nomEtablissement?: string
nomInventaire?: string
nouveauNomInventaire?: string
statut?: StatutsInventaire
}>

type PageProps = Readonly<{
searchParams?: SearchParams
}>

export default async function Page({ searchParams }: PageProps): Promise<ReactElement> {
if (searchParams.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
if (searchParams?.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
notFound()
}

Expand Down
6 changes: 3 additions & 3 deletions src/app/(connecte)/liste-equipements/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export const metadata: Metadata = {
}

type PageProps = Readonly<{
searchParams: Readonly<{
searchParams?: Readonly<{
nomEtablissement?: string
nomInventaire?: string
}>
}>

export default async function Page({ searchParams }: PageProps): Promise<ReactElement> {
if (searchParams.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
export default async function PageListeEquipements({ searchParams }: PageProps): Promise<ReactElement> {
if (searchParams?.nomEtablissement === undefined || searchParams.nomInventaire === undefined) {
notFound()
}

Expand Down
5 changes: 3 additions & 2 deletions src/app/(deconnecte)/connexion/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Metadata } from 'next'
import { getProviders } from 'next-auth/react'
import { BuiltInProviderType } from 'next-auth/providers'
import { ClientSafeProvider, LiteralUnion, getProviders } from 'next-auth/react'
import { ReactElement } from 'react'

import { checkIfConnected } from '../../../authentification'
Expand All @@ -12,7 +13,7 @@ export const metadata: Metadata = {
export default async function PageConnexion(): Promise<ReactElement> {
await checkIfConnected()

const providers = await getProviders()
const providers = await getProviders() as Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider>

return (
<Connexion
Expand Down
4 changes: 3 additions & 1 deletion src/authentification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import NextAuth, { NextAuthOptions, Session, getServerSession } from 'next-auth'
import { JWT } from 'next-auth/jwt'
import { OAuthConfig } from 'next-auth/providers'

import { separator } from './configuration'

type Profil = Readonly<{
profile_atih: string
sub: string
Expand Down Expand Up @@ -91,7 +93,7 @@ export async function getProfilAtih(): Promise<ProfilAtih> {
return {
isAdmin: profilsAtih.niveau === niveauAdmin,
isConnected: true,
nomEtablissement: profilsAtih.entite.libelle + '$$' + numeroFiness,
nomEtablissement: profilsAtih.entite.libelle + separator + numeroFiness,
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/Connexion/Connexion.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ describe('page de connexion', () => {
},
})
vi.spyOn(nextAuthReact, 'signIn').mockImplementationOnce(vi.fn())

renderComponent(await PageConnexion())
const boutonSeConnecter = screen.getByRole('button', { name: 'Se connecter avec Plage' })

// WHEN
const boutonSeConnecter = screen.getByRole('button', { name: 'Se connecter avec Plage' })
fireEvent.click(boutonSeConnecter)

// THEN
Expand Down
32 changes: 17 additions & 15 deletions src/components/Connexion/Connexion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,27 @@ import { BuiltInProviderType } from 'next-auth/providers'
import { ClientSafeProvider, LiteralUnion, signIn } from 'next-auth/react'
import { ReactElement } from 'react'

type LoginProps = Readonly<{
providers: Readonly<Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider> | null>
type ConnexionProps = Readonly<{
providers: Readonly<Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider>>
}>

export default function Connexion({ providers }: LoginProps): ReactElement {
export default function Connexion({ providers }: ConnexionProps): ReactElement {
return (
<div className="text-center">
{providers ? Object.values(providers).map((provider): ReactElement => (
<div key={provider.name}>
<button
className="btn btn--plain btn--primary"
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={async () => signIn(provider.id)}
type="button"
>
Se connecter avec Plage
</button>
</div>
)) : null}
{
Object.values(providers).map((provider): ReactElement => (
<div key={provider.name}>
<button
className="btn btn--plain btn--primary"
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={async () => signIn(provider.id)}
type="button"
>
Se connecter avec Plage
</button>
</div>
))
}
</div>
)
}
100 changes: 100 additions & 0 deletions src/components/CreerUnInventaire/CreerUnInventaire.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as navigation from 'next/navigation'

import PageCreerUnInventaire from '../../app/(connecte)/creer-un-inventaire/page'
import * as repositoryInventaires from '../../gateways/inventairesRepository'
import { inventaireModelFactory, jeSuisUnAdmin, jeSuisUnUtilisateur, renderComponent, spyNextNavigation } from '../../testShared'

describe('page modifier le nom de l’inventaire', () => {
describe('en tant qu’utilisateur', () => {
it('quand j’affiche la page alors je ne peux pas valider le formulaire', async () => {
// GIVEN
jeSuisUnUtilisateur()

// WHEN
renderComponent(await PageCreerUnInventaire())

// THEN
const boutonContinuer = screen.getByRole('button', { name: 'Continuer' })
expect(boutonContinuer).toBeDisabled()
})

it('quand j’écris un nom d’inventaire inférieur à 4 caractères alors je ne peux pas créer la simulation', async () => {
// GIVEN
jeSuisUnUtilisateur()

renderComponent(await PageCreerUnInventaire())

// WHEN
const champNomInventaire = screen.getByLabelText('Nom de l’inventaire (minimum 4 caractères)')
fireEvent.change(champNomInventaire, { target: { value: '???' } })

// THEN
const boutonContinuer = screen.getByRole('button', { name: 'Continuer' })
expect(boutonContinuer).toBeDisabled()
})

it('quand je valide le formulaire avec un nom d’inventaire qui existe déjà alors j’ai un message d’erreur', async () => {
// GIVEN
jeSuisUnUtilisateur()

vi.spyOn(repositoryInventaires, 'recupererUnInventaireRepository').mockResolvedValueOnce(inventaireModelFactory())

renderComponent(await PageCreerUnInventaire())

const champNomInventaire = screen.getByLabelText('Nom de l’inventaire (minimum 4 caractères)')
fireEvent.change(champNomInventaire, { target: { value: 'nom inventaire dejà exitant' } })

// WHEN
const boutonContinuer = screen.getByRole('button', { name: 'Continuer' })
fireEvent.click(boutonContinuer)

// THEN
const champNomInventaireMaj = await screen.findByLabelText('Nom de l’inventaire (minimum 4 caractères)')
expect(champNomInventaireMaj).toHaveAttribute('aria-describedby', 'formInputError-error')
expect(champNomInventaireMaj).toHaveAttribute('aria-invalid', 'true')

const textErreur = await screen.findByText('Cet inventaire existe déjà. Modifiez le nom de l’inventaire pour continuer.', { selector: 'p' })
expect(textErreur).toBeInTheDocument()

expect(repositoryInventaires.recupererUnInventaireRepository).toHaveBeenCalledWith('Hopital de Paris$$00000001K', 'nom inventaire dejà exitant')
})

it('quand je valide le formulaire avec un nom d’inventaire qui n’existe pas alors je vais à la suite', async () => {
// GIVEN
jeSuisUnUtilisateur()

vi.spyOn(navigation, 'useRouter')
.mockReturnValueOnce(spyNextNavigation.useRouter)
.mockReturnValueOnce(spyNextNavigation.useRouter)
vi.spyOn(repositoryInventaires, 'recupererUnInventaireRepository').mockResolvedValueOnce(null)

renderComponent(await PageCreerUnInventaire())

const champNomInventaire = screen.getByLabelText('Nom de l’inventaire (minimum 4 caractères)')
fireEvent.change(champNomInventaire, { target: { value: 'nom inventaire correct' } })

// WHEN
const boutonContinuer = screen.getByRole('button', { name: 'Continuer' })
fireEvent.click(boutonContinuer)

// THEN
await waitFor(() => {
expect(spyNextNavigation.useRouter.push).toHaveBeenCalledWith('http://localhost:3000/inventaire?nomEtablissement=Hopital+de+Paris%24%2400000001K&nomInventaire=nom+inventaire+correct')
})
})
})

describe('en tant qu’admin', () => {
it('quand j’affiche la page alors je n’y ai pas accès', async () => {
// GIVEN
jeSuisUnAdmin()

// WHEN
const page = async () => renderComponent(await PageCreerUnInventaire())

// THEN
await expect(page).rejects.toThrow('NEXT_NOT_FOUND')
})
})
})
8 changes: 4 additions & 4 deletions src/components/CreerUnInventaire/CreerUnInventaire.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type CreerUnInventaireProps = Readonly<{
}>

export default function CreerUnInventaire({ nomEtablissement }: CreerUnInventaireProps): ReactElement {
const { creerInventaire, isDisabled, isInvalid, nomInventaire, modifierNomInventaire } = useCreerUnInventaire()
const { creerInventaire, isDisabled, isInvalid, nouveauNomInventaire, modifierNouveauNomInventaire } = useCreerUnInventaire()

return (
<div className="row justify-content-center">
Expand All @@ -35,18 +35,18 @@ export default function CreerUnInventaire({ nomEtablissement }: CreerUnInventair
<div className={`form-group text-left${isInvalid ? ' is-invalid' : ''}`}>
<label htmlFor="nomInventaire">
Nom de l’inventaire (minimum 4 caractères)
<InfoBulle label="Le nom de l’inventaire permet de différencier facilement les différents inventaires au sein d’une organisation et peut être composé de plusieurs éléments (nom de l’entité, référence temporelle)." />
</label>
<InfoBulle label="Le nom de l’inventaire permet de différencier facilement les différents inventaires au sein d’une organisation et peut être composé de plusieurs éléments (nom de l’entité, référence temporelle)." />
<input
aria-describedby={isInvalid ? 'formInputError-error' : ''}
aria-invalid={isInvalid}
className={`form-control${isInvalid ? ' is-invalid' : ''}`}
id="nomInventaire"
name="nomInventaire"
onChange={modifierNomInventaire}
onChange={modifierNouveauNomInventaire}
required
type="text"
value={nomInventaire}
value={nouveauNomInventaire}
/>
{
isInvalid ? (
Expand Down
16 changes: 0 additions & 16 deletions src/components/CreerUnInventaire/action.ts

This file was deleted.

39 changes: 10 additions & 29 deletions src/components/CreerUnInventaire/useCreerUnInventaire.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
import { useRouter } from 'next/navigation'
import { FormEvent, useState } from 'react'
import { FormEvent } from 'react'

import { estCeQueLeNomInventaireExisteAction } from './action'

type State = Readonly<{
isDisabled: boolean
isInvalid: boolean
nomInventaire: string
}>
import { isLeNomInventaireExisteAction } from '../commun/action'
import { useModifierNouveauNomInventaire } from '../commun/useModifierNouveauNomInventaire'

type UseCreerUnInventaire = Readonly<{
creerInventaire: (event: FormEvent<HTMLFormElement>) => Promise<void>
isDisabled: boolean
isInvalid: boolean
modifierNomInventaire: (event: FormEvent<HTMLInputElement>) => void
nomInventaire: string
modifierNouveauNomInventaire: (event: FormEvent<HTMLInputElement>) => void
nouveauNomInventaire: string
}>

export function useCreerUnInventaire(): UseCreerUnInventaire {
const router = useRouter()
const [state, setState] = useState<State>({
isDisabled: true,
isInvalid: false,
nomInventaire: '',
})
const { modifierNouveauNomInventaire, setState, state } = useModifierNouveauNomInventaire('')

const creerInventaire = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault()
Expand All @@ -32,7 +23,7 @@ export function useCreerUnInventaire(): UseCreerUnInventaire {
const nomInventaire = formData.get('nomInventaire') as string
const nomEtablissement = formData.get('nomEtablissement') as string

const nomInventaireExiste = await estCeQueLeNomInventaireExisteAction(nomInventaire)
const nomInventaireExiste = await isLeNomInventaireExisteAction(nomInventaire)

if (!nomInventaireExiste) {
const url = new URL('/inventaire', document.location.href)
Expand All @@ -44,27 +35,17 @@ export function useCreerUnInventaire(): UseCreerUnInventaire {
setState({
isDisabled: true,
isInvalid: true,
nomInventaire: state.nomInventaire,
nouveauNomInventaire: state.nouveauNomInventaire,
})
}
}

const modifierNomInventaire = (event: FormEvent<HTMLInputElement>) => {
const caracteresMinimumPourUnNomInventaire = 4

setState({
isDisabled: event.currentTarget.value.length >= caracteresMinimumPourUnNomInventaire ? false : true,
isInvalid: false,
nomInventaire: event.currentTarget.value,
})
}

return {
creerInventaire,
isDisabled: state.isDisabled,
isInvalid: state.isInvalid,
modifierNomInventaire,
nomInventaire: state.nomInventaire,
modifierNouveauNomInventaire,
nouveauNomInventaire: state.nouveauNomInventaire,
}
}

Expand Down
Loading

0 comments on commit c7db4f6

Please sign in to comment.