Skip to content

Commit

Permalink
Merge pull request #907 from betagouv/main
Browse files Browse the repository at this point in the history
MEP
  • Loading branch information
charlescd authored Sep 18, 2024
2 parents 3c77e03 + 44c40fd commit 2435e3e
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 63 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ node_modules
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# typescript
*.tsbuildinfo

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
title: Démarchage téléphonique
desc: 'J’ai été contacté par téléphone et par SMS à plusieurs reprises et ai reçu une invitation personnelle à mon domicile m’incitant de façon insistante à me rendre rapidement en magasin pour retirer des cadeaux'
tags:
- DemarchageTelephonique
companyKind: PHONE
detailInputs:
- label: Date du premier appel ou du SMS reçu
type: DATE
defaultValue: SYSDATE
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Etes-vous inscrit sur Bloctel ?
type: RADIO
options:
- Non
- Oui (à préciser votre numéro de téléphone)
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'J’ai eu l’impression de ne pas pouvoir sortir du magasin avant d’avoir fait un achat'
desc: 'La négociation commerciale a duré plusieurs heures et les vendeurs ont été très insistants'
detailInputs:
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'J’ai bénéficié de remises conséquentes sur le prix des produits'
desc: 'Les vendeurs m’ont accordé plusieurs remises successives d’un montant important et un bon d’achat valables uniquement le jour même.'
detailInputs:
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'J’ai procédé au paiement le jour de la vente'
desc: 'J’ai remis un ou plusieurs chèques aux vendeurs le jour de la vente.'
detailInputs:
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'Le vendeur ne m’a pas fourni tous les documents et informations obligatoires au moment de la vente'
desc: 'J’ai souscrit un crédit pour financer mon achat mais aucun document ne m’a été remis par les vendeurs, ni aucune explication sur ses caractéristiques.'
detailInputs:
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'Les vendeurs refusent d’annuler la vente'
desc: 'Je n’arrive pas à exercer mon droit de rétractation alors que le délai légal de 14 jours n’est pas expiré.'
detailInputs:
- label: Date de l'achat ou de la visite dans le magasin
type: DATE
defaultValue: SYSDATE
- label: Adresse précise du magasin (numéro, nom de rue, code postal et nom de la ville)
type: TEXT
placeholder: Nom ou type de produit
- label: Description
type: TEXTAREA
fileLabel: Invitation personnelle / le bon de commande / fiche technique du produit / un devis manuscrit / facture / crédit associé
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
title: J’ai été invité par démarchage téléphonique à venir retirer des cadeaux dans un magasin éphémère et lors de ma venue sur place, j’ai été l’objet de pratiques commerciales déloyales ou agressives.
desc: 'Retirer des cadeaux comme un bon voyages, bouteilles de vins, couteaux, bijoux'
tags:
- BauxPrecaire
companyKind: SIRET
6 changes: 5 additions & 1 deletion website/src/clients/BaseApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, {AxiosInstance, AxiosResponse, ResponseType, isAxiosError} from 'axios'
import axios, {AxiosInstance, AxiosResponse, ResponseType, isAxiosError, AxiosProgressEvent, GenericAbortSignal} from 'axios'
import * as qs from 'qs'

interface RequestOptions {
Expand All @@ -8,6 +8,8 @@ interface RequestOptions {
readonly body?: any
readonly timeout?: number
readonly responseType?: ResponseType
readonly onUploadProgress?: (progressEvent: AxiosProgressEvent) => void
readonly signal?: GenericAbortSignal
}

interface ApiErrorDetails {
Expand Down Expand Up @@ -72,6 +74,8 @@ export class BaseApiClient {
params: options?.qs,
data: options?.body,
paramsSerializer: params => qs.stringify(params, {arrayFormat: 'repeat'}),
onUploadProgress: builtOptions.onUploadProgress,
signal: builtOptions.signal,
})
.then((_: AxiosResponse) => _.data)
.catch((_: any) => {
Expand Down
21 changes: 19 additions & 2 deletions website/src/clients/SignalConsoApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {Country} from '../model/Country'
import {CreatedReport} from '../model/CreatedReport'
import {FileOrigin, UploadedFile} from '../model/UploadedFile'
import {ApiError, BaseApiClient} from './BaseApiClient'
import {GenericAbortSignal} from 'axios'

type PublicStat =
| 'PromesseAction'
Expand Down Expand Up @@ -103,13 +104,29 @@ export class SignalConsoApiClient {

getDocumentLink = (file: UploadedFile) => `${this.client.baseUrl}/reports/files/${file.id}/${encodeURI(file.filename)}`

uploadDocument = (file: File, origin: FileOrigin) => {
uploadDocument = (
file: File,
origin: FileOrigin,
id: string,
uploadProgress?: (percent: number) => void,
signal?: GenericAbortSignal,
) => {
const fileFormData: FormData = new FormData()
fileFormData.append('reportFile', file, file.name)
fileFormData.append('reportFileOrigin', origin)
// We need to put manually the header since axios 1.x https://github.com/axios/axios/issues/5556
// There are other ways but this is the quickest
return this.client.post<UploadedFile>(`reports/files`, {body: fileFormData, headers: {'Content-Type': 'multipart/form-data'}})
return this.client.post<UploadedFile>(`reports/files?reportFileId=${id}`, {
body: fileFormData,
headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: uploadProgress
? progressEvent => {
const percentCompleted = progressEvent.total ? Math.round((progressEvent.loaded * 100) / progressEvent.total) : 0.0
uploadProgress(percentCompleted)
}
: undefined,
signal: signal,
})
}

rateSubcategory = (category: string, subcategories: Subcategory[], positive: boolean): Promise<void> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const PlaygroundConsumer = () => {
},
},
}}
saveChange={(_, goToNextStep) => alert(JSON.stringify(_))}
saveChange={(_, goToNextStep) => goToNextStep && alert(JSON.stringify(_))}
stepNavigation={dummyStepNavigation}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {ButtonWithLoader} from '@/components_simple/buttons/Buttons'
import {GeoArea, ScAutocompleteGeoArea} from '@/components_simple/formInputs/ScAutocompleteGeoArea'
import {ScCheckbox} from '@/components_simple/formInputs/ScCheckbox'
import {ScTextInput} from '@/components_simple/formInputs/ScTextInput'
import {appConfig} from '@/core/appConfig'
import {useI18n} from '@/i18n/I18n'
import {forwardRef, Ref} from 'react'
import {Controller, useForm} from 'react-hook-form'
Expand All @@ -15,8 +14,7 @@ type RawForm = {
}
export type CompanySearchInputs = {input: string; geoArea?: GeoArea}

// it's not functional yet on the backend
const enableSearchByDepartment = appConfig.useDepartementSearch
const enableSearchByDepartment = true

type Props = {
onSubmit: (_: CompanySearchInputs) => void
Expand Down Expand Up @@ -54,23 +52,19 @@ export const CompanySmartSearchForm = forwardRef((props: Props, ref: Ref<HTMLFor
placeholder={m.identifyBy_nameOrIdentity_ex}
/>
<div className={`${restrictToGeoArea ? 'p-4 pb-1 mb-4 bg-sclightpurple rounded-lg' : ''}`}>
<ScCheckbox
{...register('restrictToGeoArea')}
label={enableSearchByDepartment ? m.restrictToPostalCodeOrDpt : m.restrictToPostalCode}
required
/>
<ScCheckbox {...register('restrictToGeoArea')} label={m.restrictToPostalCodeOrDpt} required />
{restrictToGeoArea && (
<div className="max-w-lg">
<Controller
control={control}
name="geoArea"
render={({field: {onChange, onBlur, name, value}, fieldState: {error}}) => (
<ScAutocompleteGeoArea
label={enableSearchByDepartment ? 'Département ou code postal' : m.postalCode}
noDepartements={!enableSearchByDepartment}
label={m.postalCodeOrDpt}
{...{onChange, onBlur, name, value}}
error={!!error}
helperText={error?.message}
showRequiredAsterisk={false}
/>
)}
/>
Expand Down
4 changes: 1 addition & 3 deletions website/src/components_simple/reportFile/ReportFile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {useApiClients} from '@/context/ApiClientsContext'
import {useI18n} from '@/i18n/I18n'
import {UploadedFile} from '../../model/UploadedFile'
import {ReportFileDeleteButton} from './ReportFileDeleteButton'
import {FileType, extensionToType} from './reportFileConfig'
Expand All @@ -13,7 +12,6 @@ export interface ReportFileProps {
export const ReportFile = ({file, onRemove}: ReportFileProps) => {
const fileType = extensionToType(file.filename)
const {signalConsoApiClient} = useApiClients()
const {m} = useI18n()

const fileUrl = signalConsoApiClient.getDocumentLink(file)

Expand Down Expand Up @@ -64,7 +62,7 @@ export const ReportFile = ({file, onRemove}: ReportFileProps) => {
<ReportFileDeleteButton
filename={file.filename}
onConfirm={() => {
remove()
return remove()
}}
/>
</div>
Expand Down
23 changes: 4 additions & 19 deletions website/src/components_simple/reportFile/ReportFileAdd.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import {Button} from '@codegouvfr/react-dsfr/Button'
import {useApiClients} from '@/context/ApiClientsContext'
import {useToastError} from '@/hooks/useToastError'
import {useI18n} from '@/i18n/I18n'
import {useRef, useState} from 'react'
import {useRef} from 'react'
import {appConfig} from '../../core/appConfig'
import {FileOrigin, UploadedFile} from '../../model/UploadedFile'
import {compressFile} from '../../utils/compressFile'
import {extractFileExt} from './reportFileConfig'
import {DragDropContext, Droppable} from '@hello-pangea/dnd'
import {FileOrigin} from '../../model/UploadedFile'

interface Props {
fileOrigin: FileOrigin
isUploading: boolean
uploadFile: (files: FileList | null) => Promise<void>
}

export const ADD_FILE_HELP_ID = 'aide-piece-jointe'

export const ReportFileAdd = ({isUploading, fileOrigin, uploadFile}: Props) => {
const [uploading, setUploading] = useState(isUploading)
export const ReportFileAdd = ({fileOrigin, uploadFile}: Props) => {
const fileInputEl = useRef<HTMLInputElement>(null)
const {m} = useI18n()
const openFileSelection = () => {
Expand All @@ -28,20 +21,12 @@ export const ReportFileAdd = ({isUploading, fileOrigin, uploadFile}: Props) => {
return (
<>
<Button
{...(uploading
? {
style: {
paddingLeft: '14px',
},
}
: {iconId: 'ri-download-2-line'})}
iconId="ri-download-2-line"
priority="secondary"
disabled={uploading}
onClick={openFileSelection}
className=""
nativeButtonProps={{'aria-describedby': ADD_FILE_HELP_ID}}
>
{uploading && <div className="sc-loader w-4 h-4 mr-2"></div>}
{m.addAttachmentFile}
</Button>
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import {PortalToBody} from '@/utils/PortalToBody'
import Button from '@codegouvfr/react-dsfr/Button'
import {createModal} from '@codegouvfr/react-dsfr/Modal'

const modal = createModal({
id: 'file-delete-modal',
isOpenedByDefault: false,
})

export function ReportFileDeleteButton({filename, onConfirm}: {filename: string; onConfirm: () => void}) {
const {m} = useI18n()
const modal = createModal({
id: `file-delete-modal-${filename}`,
isOpenedByDefault: false,
})
return (
<>
<Button
Expand Down
Loading

0 comments on commit 2435e3e

Please sign in to comment.