-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TRA-15092] ETQ utilisateur je peux créer, révoquer et consulter mes …
…demandes de délégation RNDTS (#3588) * feat: implemented create endpoint * feat: added endpoint rndtsDeclarationDelegation * refacto: improved condition check on overlap + tests * refacto * feat: checking that delegator & delegate are different * feat: small opti on queries * refacto: making endpoints session only * feat: removed isDeleted, using isRevoked instead + added status sub-resolver * feat: cleaned up dates to midnight * feat: huge refactoring, nesting companies within delegation + started revoke endpoint * test: added test for revocation * fix: fixed tests * feat: added endpoints delegationS * fix: fixes & refacto * fix: fixed test * fix: moved delegate & delegator to subResolvers + dates fixing to zod only * fix: changing where.id to where.orgId * feat: started implemeting front * fix: submitting create form * fix: using .nullish() instead of .optional() * feat: added prisma migration script * feat: started implementing lists * feat: starting table pagination. need backend fix first * feat: changed pagination args * feat: polishes the table * feat: added revoke * feat: trying to fix test * fix: trying to fix tests * fix: fixing typing issues due to sub-resolvers * fix: let's chill on the capslock * fix: trying to fix subresolvers (isDormant error) * feat: adding created delegation to table * feat: added givenName to CompanyPublic * feat: displaying givenName * feat: sending email on creation. Needing content though * fix: displaying error message on required for delegatorId (companySelector) * feat: added email content. Still some details missing * fix: lint * feat: added feature flag on companies * feat: not showing action buttons to non-admins * fix: fixes after reviews with the bowss * fix: fixed email with links * fix: fixed permissions using can() * fix: renamed rndtsDeclarationDelegation -> registryDelegation * feat: re-generated migration script with new name registryDelegation * feat: added events in repository methods * lint: format * feat: renamed rndtsDeclarationDelegation -> registryDelegation * fix: PR review fixes * feat: added endDate in mail
- Loading branch information
1 parent
6a809b1
commit 4921b88
Showing
10 changed files
with
757 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
front/src/Apps/Companies/CompanyRegistryDelegation/CompanyRegistryDelegation.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from "react"; | ||
import "./companyRegistryDelegation.scss"; | ||
import { CompanyPrivate } from "@td/codegen-ui"; | ||
import { CompanyRegistryDelegationAsDelegator } from "./CompanyRegistryDelegationAsDelegator"; | ||
import { CompanyRegistryDelegationAsDelegate } from "./CompanyRegistryDelegationAsDelegate"; | ||
|
||
interface Props { | ||
company: CompanyPrivate; | ||
} | ||
|
||
export const CompanyRegistryDelegation = ({ company }: Props) => { | ||
return ( | ||
<> | ||
<CompanyRegistryDelegationAsDelegator company={company} /> | ||
<CompanyRegistryDelegationAsDelegate company={company} /> | ||
</> | ||
); | ||
}; |
23 changes: 23 additions & 0 deletions
23
front/src/Apps/Companies/CompanyRegistryDelegation/CompanyRegistryDelegationAsDelegate.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from "react"; | ||
import "./companyRegistryDelegation.scss"; | ||
import { CompanyPrivate } from "@td/codegen-ui"; | ||
import { RegistryDelegationsTable } from "./RegistryDelegationsTable"; | ||
|
||
interface Props { | ||
company: CompanyPrivate; | ||
} | ||
|
||
export const CompanyRegistryDelegationAsDelegate = ({ company }: Props) => { | ||
return ( | ||
<> | ||
<h4>Délégataires</h4> | ||
<div> | ||
Les entreprises ci-dessous m'autorisent à faire leurs déclarations au | ||
Registre National des Déchets, Terres Excavées et Sédiments (RNDTS) | ||
</div> | ||
<div> | ||
<RegistryDelegationsTable as="delegate" company={company} /> | ||
</div> | ||
</> | ||
); | ||
}; |
54 changes: 54 additions & 0 deletions
54
front/src/Apps/Companies/CompanyRegistryDelegation/CompanyRegistryDelegationAsDelegator.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import React, { useState } from "react"; | ||
import "./companyRegistryDelegation.scss"; | ||
import { CompanyPrivate, UserRole } from "@td/codegen-ui"; | ||
import Button from "@codegouvfr/react-dsfr/Button"; | ||
import { CreateRegistryDelegationModal } from "./CreateRegistryDelegationModal"; | ||
import { RegistryDelegationsTable } from "./RegistryDelegationsTable"; | ||
|
||
interface Props { | ||
company: CompanyPrivate; | ||
} | ||
|
||
export const CompanyRegistryDelegationAsDelegator = ({ company }: Props) => { | ||
const isAdmin = company.userRole === UserRole.Admin; | ||
|
||
const [isModalOpen, setIsModalOpen] = useState(false); | ||
|
||
return ( | ||
<> | ||
<h4>Délégations</h4> | ||
<div> | ||
J'autorise les entreprises ci-dessous à faire mes déclarations au | ||
Registre National des Déchets, Terres Excavées et Sédiments (RNDTS) | ||
</div> | ||
|
||
{isAdmin && ( | ||
<div> | ||
<Button | ||
priority="primary" | ||
size="small" | ||
className="fr-my-4v" | ||
nativeButtonProps={{ | ||
type: "button", | ||
"data-testid": "company-add-registryDelegation" | ||
}} | ||
disabled={isModalOpen} | ||
onClick={() => setIsModalOpen(true)} | ||
> | ||
Créer une délégation | ||
</Button> | ||
</div> | ||
)} | ||
|
||
<div> | ||
<RegistryDelegationsTable as="delegator" company={company} /> | ||
</div> | ||
|
||
<CreateRegistryDelegationModal | ||
company={company} | ||
isOpen={isModalOpen} | ||
onClose={() => setIsModalOpen(false)} | ||
/> | ||
</> | ||
); | ||
}; |
231 changes: 231 additions & 0 deletions
231
front/src/Apps/Companies/CompanyRegistryDelegation/CreateRegistryDelegationModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
import React from "react"; | ||
import { | ||
CompanyPrivate, | ||
Mutation, | ||
MutationCreateRegistryDelegationArgs | ||
} from "@td/codegen-ui"; | ||
import { FieldError, useForm } from "react-hook-form"; | ||
import { Modal } from "../../../common/components"; | ||
import CompanySelectorWrapper from "../../common/Components/CompanySelectorWrapper/CompanySelectorWrapper"; | ||
import Input from "@codegouvfr/react-dsfr/Input"; | ||
import Button from "@codegouvfr/react-dsfr/Button"; | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { z } from "zod"; | ||
import { isSiret } from "@td/constants"; | ||
import { datetimeToYYYYMMDD } from "../../Dashboard/Validation/BSPaoh/paohUtils"; | ||
import { startOfDay } from "date-fns"; | ||
import { useMutation } from "@apollo/client"; | ||
import { | ||
CREATE_REGISTRY_DELEGATION, | ||
REGISTRY_DELEGATIONS | ||
} from "../../common/queries/registryDelegation/queries"; | ||
import toast from "react-hot-toast"; | ||
|
||
const displayError = (error: FieldError | undefined) => { | ||
return error ? <>{error.message}</> : null; | ||
}; | ||
|
||
const getSchema = () => | ||
z | ||
.object({ | ||
delegateOrgId: z | ||
.string({ required_error: "Ce champ est requis" }) | ||
.refine(isSiret, "Siret non valide"), | ||
startDate: z.coerce | ||
.date({ | ||
required_error: "La date de début est requise", | ||
invalid_type_error: "La date de début est invalide" | ||
}) | ||
.min(startOfDay(new Date()), { | ||
message: "La date de début ne peut pas être dans le passé" | ||
}) | ||
.transform(val => val.toISOString()) | ||
.nullish(), | ||
// Date & "" hack: https://github.com/colinhacks/zod/issues/1721 | ||
endDate: z.preprocess( | ||
arg => (arg === "" ? null : arg), | ||
z.coerce | ||
.date({ | ||
invalid_type_error: "La date de fin est invalide" | ||
}) | ||
.min(new Date(), { | ||
message: "La date de fin ne peut pas être dans le passé" | ||
}) | ||
.transform(val => { | ||
if (val) return val.toISOString(); | ||
return val; | ||
}) | ||
.nullish() | ||
), | ||
comment: z.string().max(500).optional() | ||
}) | ||
.refine( | ||
data => { | ||
const { startDate, endDate } = data; | ||
|
||
if (startDate && endDate) { | ||
return new Date(startDate) < new Date(endDate); | ||
} | ||
|
||
return true; | ||
}, | ||
{ | ||
path: ["startDate"], | ||
message: "La date de début doit être avant la date de fin." | ||
} | ||
); | ||
|
||
interface Props { | ||
company: CompanyPrivate; | ||
isOpen: boolean; | ||
onClose: () => void; | ||
} | ||
|
||
export const CreateRegistryDelegationModal = ({ | ||
company, | ||
onClose, | ||
isOpen | ||
}: Props) => { | ||
const [createRegistryDelegation, { loading }] = useMutation< | ||
Pick<Mutation, "createRegistryDelegation">, | ||
MutationCreateRegistryDelegationArgs | ||
>(CREATE_REGISTRY_DELEGATION, { | ||
refetchQueries: [REGISTRY_DELEGATIONS] | ||
}); | ||
|
||
const validationSchema = getSchema(); | ||
const { | ||
register, | ||
handleSubmit, | ||
setValue, | ||
watch, | ||
reset, | ||
formState: { errors, isSubmitting } | ||
} = useForm<z.infer<typeof validationSchema>>({ | ||
defaultValues: { | ||
startDate: datetimeToYYYYMMDD(new Date()) | ||
}, | ||
resolver: zodResolver(validationSchema) | ||
}); | ||
|
||
const closeModal = () => { | ||
reset(); | ||
onClose(); | ||
}; | ||
|
||
const onSubmit = async input => { | ||
await createRegistryDelegation({ | ||
variables: { | ||
input: { | ||
...input, | ||
delegatorOrgId: company.orgId | ||
} | ||
}, | ||
onCompleted: () => toast.success("Délégation créée!"), | ||
onError: err => toast.error(err.message) | ||
}); | ||
|
||
closeModal(); | ||
}; | ||
|
||
const delegateOrgId = watch("delegateOrgId") ?? {}; | ||
|
||
const isLoading = loading || isSubmitting; | ||
|
||
return ( | ||
<Modal | ||
onClose={closeModal} | ||
ariaLabel="Créer une délégation" | ||
isOpen={isOpen} | ||
size="L" | ||
> | ||
<div> | ||
<form onSubmit={handleSubmit(onSubmit)}> | ||
<h4>Créer une délégation</h4> | ||
|
||
<CompanySelectorWrapper | ||
orgId={company.orgId} | ||
disabled={isLoading} | ||
selectedCompanyOrgId={delegateOrgId} | ||
selectedCompanyError={selectedCompany => { | ||
if (selectedCompany?.orgId === company.orgId) { | ||
return "Le délégant et le délégataire doivent être différents"; | ||
} | ||
if (!selectedCompany?.siret) { | ||
return "L'entreprise doit avoir un n° de SIRET"; | ||
} | ||
return null; | ||
}} | ||
onCompanySelected={company => { | ||
if (company) { | ||
setValue("delegateOrgId", company.orgId); | ||
} | ||
}} | ||
/> | ||
{errors.delegateOrgId && ( | ||
<span className="fr-error-text"> | ||
{errors.delegateOrgId.message} | ||
</span> | ||
)} | ||
|
||
<div className="fr-container--fluid fr-mb-8v"> | ||
<div className="fr-grid-row fr-grid-row--gutters fr-grid-row--bottom"> | ||
<div className="fr-col-6"> | ||
<Input | ||
label="Date de début" | ||
state={errors?.startDate && "error"} | ||
stateRelatedMessage={displayError(errors?.startDate)} | ||
disabled={isLoading} | ||
nativeInputProps={{ | ||
type: "date", | ||
min: datetimeToYYYYMMDD(new Date()), | ||
max: datetimeToYYYYMMDD(new Date("2050-12-31")), | ||
...register("startDate") | ||
}} | ||
/> | ||
</div> | ||
<div className="fr-col-6"> | ||
<Input | ||
label="Date de fin (optionnelle)" | ||
hintText="Illimité s'il n'y a pas de date renseignée" | ||
state={errors?.endDate && "error"} | ||
stateRelatedMessage={displayError(errors?.endDate)} | ||
disabled={isLoading} | ||
nativeInputProps={{ | ||
type: "date", | ||
max: datetimeToYYYYMMDD(new Date("2050-12-31")), | ||
...register("endDate") | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<Input | ||
label="Objet" | ||
state={errors?.comment && "error"} | ||
stateRelatedMessage={displayError(errors?.comment)} | ||
disabled={isLoading} | ||
nativeInputProps={{ | ||
...register("comment") | ||
}} | ||
/> | ||
|
||
<div className="dsfr-modal-actions fr-mt-3w"> | ||
<Button | ||
disabled={isLoading} | ||
priority="secondary" | ||
onClick={onClose} | ||
type="button" | ||
> | ||
Annuler | ||
</Button> | ||
<Button type="submit" disabled={isLoading}> | ||
Créer | ||
</Button> | ||
</div> | ||
</form> | ||
</div> | ||
</Modal> | ||
); | ||
}; |
Oops, something went wrong.