diff --git a/apps/backend/src/controller/establishment/establishmentController.ts b/apps/backend/src/controller/establishment/establishmentController.ts index a8521e82a..232f81523 100644 --- a/apps/backend/src/controller/establishment/establishmentController.ts +++ b/apps/backend/src/controller/establishment/establishmentController.ts @@ -1,4 +1,4 @@ -import { Controller, Route, SuccessResponse, TsoaResponse, Res, Example, Get, Path } from 'tsoa' +import { Controller, Route, SuccessResponse, TsoaResponse, Res, Example, Get, Path, Query } from 'tsoa' import { ErrorJSON, Establishment, EstablishmentNotFoundError, EstablishmentService, ValidateErrorJSON, Monitor } from '@tee/backend-ddd' import { EstablishmentSearch } from '@tee/common' @@ -38,7 +38,7 @@ export class SireneController extends Controller { /** * Retrieve establishments informations used in front end * for a single establishment using the SIRENE API if search by SIRET - * or for up to 3 establishments using the Recherche-entreprise API otherwise. + * or for up to 9 establishments using the Recherche-entreprise API otherwise. * Also return the number of matches found * * @summary Search for establishments from a query @@ -50,11 +50,12 @@ export class SireneController extends Controller { @Get('{query}') public async getEstablishmentBySiret( @Path() query: string, + @Query() resultCount = 3, @Res() requestFailedResponse: TsoaResponse<500, ErrorJSON>, @Res() _validationFailedResponse: TsoaResponse<422, ValidateErrorJSON>, @Res() notFoundResponse: TsoaResponse<404, EstablishmentNotFoundErrorJSON> ): Promise { - const establishmentResult = await new EstablishmentService().search(query) + const establishmentResult = await new EstablishmentService().search(query, resultCount) if (establishmentResult.isErr) { const err = establishmentResult.error diff --git a/apps/web/public/css/custom.css b/apps/web/public/css/custom.css index e420c7de0..f0563ed10 100644 --- a/apps/web/public/css/custom.css +++ b/apps/web/public/css/custom.css @@ -186,12 +186,6 @@ button.fr-link:hover, .tee-router-link:hover { line-height: 1.2em; } -/* TRACK INPUT */ -.tee-resp-info-block { - text-indent: -3.5rem; - padding-left: 3.5rem; -} - /* CUSTOM BUTTON INPUT */ .tee-btn-next { justify-content: end; @@ -199,30 +193,9 @@ button.fr-link:hover, .tee-router-link:hover { .tee-form-input-large { display: flex; } -.tee-input-large { - font-size: 1.1rem; - height: 4rem !important; - max-height: 4rem !important; - border-radius: .25rem 0 0 0; -} -.tee-input-large::placeholder { - font-size: 1rem; -} -.tee-btn-input-large { - max-height: 4rem !important; - max-width: 4rem !important; -} .tee-btn-input-large::before { width: 3rem !important; } - -.tee-input-large:focus { - outline-offset: unset; - outline-width: unset; - outline-color: unset; - outline-style: none; -} - .tee-input-hint { color: #000091; } diff --git a/apps/web/public/images/TEE-modal-bottom-mobile.svg b/apps/web/public/images/TEE-modal-bottom-mobile.svg new file mode 100644 index 000000000..685109905 --- /dev/null +++ b/apps/web/public/images/TEE-modal-bottom-mobile.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/web/public/images/TEE-modal-bottom.svg b/apps/web/public/images/TEE-modal-bottom.svg new file mode 100644 index 000000000..078922c5e --- /dev/null +++ b/apps/web/public/images/TEE-modal-bottom.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/web/src/WebApp.vue b/apps/web/src/WebApp.vue index 4d3bc8104..d03e52a0a 100644 --- a/apps/web/src/WebApp.vue +++ b/apps/web/src/WebApp.vue @@ -3,6 +3,7 @@
+ diff --git a/apps/web/src/components/identification/TeeRegisterModal.vue b/apps/web/src/components/identification/TeeRegisterModal.vue new file mode 100644 index 000000000..c41af5925 --- /dev/null +++ b/apps/web/src/components/identification/TeeRegisterModal.vue @@ -0,0 +1,145 @@ + + + diff --git a/apps/web/src/components/identification/TeeRegisterSiret.vue b/apps/web/src/components/identification/TeeRegisterSiret.vue new file mode 100644 index 000000000..410406552 --- /dev/null +++ b/apps/web/src/components/identification/TeeRegisterSiret.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/apps/web/src/components/identification/TeeRegisterSiretBar.vue b/apps/web/src/components/identification/TeeRegisterSiretBar.vue new file mode 100644 index 000000000..5f56be008 --- /dev/null +++ b/apps/web/src/components/identification/TeeRegisterSiretBar.vue @@ -0,0 +1,73 @@ + + + diff --git a/apps/web/src/components/identification/details/TeeProfileActivity.vue b/apps/web/src/components/identification/details/TeeProfileActivity.vue new file mode 100644 index 000000000..4ae488efa --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileActivity.vue @@ -0,0 +1,65 @@ + + diff --git a/apps/web/src/components/identification/details/TeeProfileDetails.vue b/apps/web/src/components/identification/details/TeeProfileDetails.vue new file mode 100644 index 000000000..0455d3760 --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileDetails.vue @@ -0,0 +1,109 @@ + + diff --git a/apps/web/src/components/identification/details/TeeProfileElement.vue b/apps/web/src/components/identification/details/TeeProfileElement.vue new file mode 100644 index 000000000..aaa5eafac --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileElement.vue @@ -0,0 +1,59 @@ + + diff --git a/apps/web/src/components/identification/details/TeeProfileLocalisation.vue b/apps/web/src/components/identification/details/TeeProfileLocalisation.vue new file mode 100644 index 000000000..04aee42a1 --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileLocalisation.vue @@ -0,0 +1,97 @@ + + + diff --git a/apps/web/src/components/identification/details/TeeProfileSiret.vue b/apps/web/src/components/identification/details/TeeProfileSiret.vue new file mode 100644 index 000000000..4879e88d3 --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileSiret.vue @@ -0,0 +1,42 @@ + + + diff --git a/apps/web/src/components/identification/details/TeeProfileSize.vue b/apps/web/src/components/identification/details/TeeProfileSize.vue new file mode 100644 index 000000000..580237a6d --- /dev/null +++ b/apps/web/src/components/identification/details/TeeProfileSize.vue @@ -0,0 +1,67 @@ + + diff --git a/apps/web/src/service/api/establishmentApi.ts b/apps/web/src/service/api/establishmentApi.ts index 4e79fd616..dfef21fa3 100644 --- a/apps/web/src/service/api/establishmentApi.ts +++ b/apps/web/src/service/api/establishmentApi.ts @@ -5,8 +5,8 @@ import { EstablishmentSearch } from '@/types' export default class EstablishmentApi extends RequestApi { protected readonly url = '/api/establishments/' - async getByQuery(query: string): Promise> { - const url: string = this.url + query + async getByQuery(query: string, resultCount?: number): Promise> { + const url: string = this.url + query + (resultCount ? `?resultCount=${resultCount}` : '') try { const response = await fetch(url) if (!response.ok) { diff --git a/apps/web/src/stores/navigation.ts b/apps/web/src/stores/navigation.ts index 692495be8..dcab4c262 100644 --- a/apps/web/src/stores/navigation.ts +++ b/apps/web/src/stores/navigation.ts @@ -25,6 +25,7 @@ export const useNavigationStore = defineStore('navigation', () => { const stringOfSearchParams = ref('') const tabSelectedOnList = ref(0) const hasSpinner = ref(false) + const hasRegisterModal = ref(false) const query = computed>(() => { const query: LocationQuery = {} for (const key of new URLSearchParams(stringOfSearchParams.value).keys()) { @@ -217,6 +218,7 @@ export const useNavigationStore = defineStore('navigation', () => { searchParams, tabSelectedOnList, hasSpinner, + hasRegisterModal, isCatalog, isCatalogAboutPrograms, isCatalogAboutProjects, diff --git a/apps/web/src/translations/fr.ts b/apps/web/src/translations/fr.ts index 97329ae7a..a81f48ab3 100644 --- a/apps/web/src/translations/fr.ts +++ b/apps/web/src/translations/fr.ts @@ -1,5 +1,6 @@ import programFrDict from '@/translations/fr/program' import projectFrDict from '@/translations/fr/project' +import registerFrDict from '@/translations/fr/register' export const frDict = { next: 'Suivant', @@ -7,7 +8,7 @@ export const frDict = { close: 'Fermer', send: 'Envoyer', modify: 'modifier', - or: 'Ou', + or: 'ou', footer: { thisApplicationAndIts: 'Cette application et son', sourceCode: 'code source', @@ -124,5 +125,6 @@ export const frDict = { } }, ...programFrDict, - ...projectFrDict + ...projectFrDict, + ...registerFrDict } diff --git a/apps/web/src/translations/fr/register.ts b/apps/web/src/translations/fr/register.ts new file mode 100644 index 000000000..37feb08f7 --- /dev/null +++ b/apps/web/src/translations/fr/register.ts @@ -0,0 +1,8 @@ +const registerFrDict = { + register: { + mainTitle: 'Vous êtes...?', + description: 'Renseignez votre profil entreprise pour visualiser les aides éligibles et les actions pertinentes pour votre secteur.' + } +} + +export default registerFrDict diff --git a/apps/web/src/types/companyDataType.ts b/apps/web/src/types/companyDataType.ts index 278b9b998..e6928c2da 100644 --- a/apps/web/src/types/companyDataType.ts +++ b/apps/web/src/types/companyDataType.ts @@ -1,11 +1,54 @@ import { EstablishmentFront, StructureSize } from '@tee/common' +import { Region, Sector } from '@/types' export enum CompanyDataStorageKey { - Siret = 'siret', + Company = 'company', Size = 'structure_size' } +export type ManualCompanyData = { + region: Region + secteur: Sector + denomination: string +} + export type CompanyDataType = { - [CompanyDataStorageKey.Siret]: EstablishmentFront | null + [CompanyDataStorageKey.Company]: EstablishmentFront | null | ManualCompanyData [CompanyDataStorageKey.Size]: StructureSize | null } + +export enum RegisterDetailType { + Siret = 'siret', + Localisation = 'localisation', + Activity = 'activity', + Size = 'size' +} + +export type RegisterDetails = { + [key: string]: RegisterDetailUnion + siret: RegisterDetail + activity: RegisterDetailActivity + size: RegisterDetailSize + localisation: RegisterDetail +} +export type RegisterDetail = { + icon: string + title: string + value: string | undefined + description?: string + if?: boolean + type: RegisterDetailType + tagLabel?: string +} + +export type RegisterDetailSize = Omit & { + value: StructureSize | undefined | null +} +export type RegisterDetailActivity = Omit & { value: Sector | undefined } +export type RegisterDetailUnion = RegisterDetail | RegisterDetailSize | RegisterDetailActivity +export type RegisterProfile = { + establishment?: EstablishmentFront | undefined + size: StructureSize | undefined + localisation: string | undefined + activity: Sector | string | undefined +} diff --git a/apps/web/src/types/genericTypes.ts b/apps/web/src/types/genericTypes.ts index 458fb0995..262464335 100644 --- a/apps/web/src/types/genericTypes.ts +++ b/apps/web/src/types/genericTypes.ts @@ -13,6 +13,7 @@ export enum FieldType { Number = 'number', Select = 'select', Radio = 'radio', + Tag = 'tag', Checkbox = 'checkbox', Textarea = 'textarea', Email = 'email', diff --git a/apps/web/src/types/index.ts b/apps/web/src/types/index.ts index efcefb440..acc27dfbc 100644 --- a/apps/web/src/types/index.ts +++ b/apps/web/src/types/index.ts @@ -1,5 +1,6 @@ export * from './color' export * from './conditionOperators' +export * from './companyDataType' export * from './elementsPropsTypes' export * from './formTypes' export * from './genericTypes' diff --git a/apps/web/src/utils/navigation.ts b/apps/web/src/utils/navigation.ts index e09c5ccb5..fb52877a4 100644 --- a/apps/web/src/utils/navigation.ts +++ b/apps/web/src/utils/navigation.ts @@ -1,7 +1,24 @@ // CONSOLE LOG TEMPLATE // console.log(`utils.navigation > FUNCTION_NAME > MSG_OR_VALUE :`) +import { useNavigationStore } from '@/stores/navigation' export default class Navigation { static hashByRouteName = (routeName: string) => { return `#${routeName}` } + static toggleRegisterModal = (forceStatus?: boolean) => { + const navigationStore = useNavigationStore() + navigationStore.hasRegisterModal = forceStatus || !navigationStore.hasRegisterModal + document.body.style.overflow = navigationStore.hasRegisterModal ? 'hidden' : '' + const header = document.getElementById('tee-header') + if (header) { + const headerHeight = header.offsetHeight + 'px' + document.documentElement.style.setProperty('--header-height', headerHeight) + } + if (navigationStore.hasRegisterModal) { + window.scrollTo({ + top: 0, + behavior: 'smooth' + }) + } + } } diff --git a/apps/web/src/utils/storage/companyDataStorage.ts b/apps/web/src/utils/storage/companyDataStorage.ts index 2843b1b5d..97f2d02f3 100644 --- a/apps/web/src/utils/storage/companyDataStorage.ts +++ b/apps/web/src/utils/storage/companyDataStorage.ts @@ -1,40 +1,40 @@ -import { CompanyDataStorageKey, CompanyDataType } from '@/types/companyDataType' +import { CompanyDataStorageKey, CompanyDataType } from '@/types' import { LocalStorageHandler } from '@/utils/storage/localStorageHandler' -import { EstablishmentFront, StructureSize } from '@tee/common' +import { StructureSize } from '@tee/common' import { ref, Ref } from 'vue' export default class CompanyDataStorage { private static readonly _storageHandler = new LocalStorageHandler() - private static readonly _data: Ref = ref({ [CompanyDataStorageKey.Siret]: null, [CompanyDataStorageKey.Size]: null }) + private static readonly _data: Ref = ref({ [CompanyDataStorageKey.Company]: null, [CompanyDataStorageKey.Size]: null }) static getData(): Ref { return this._data } static hasData() { - return this._data.value[CompanyDataStorageKey.Siret] !== null || this._data.value[CompanyDataStorageKey.Size] !== null + return this._data.value[CompanyDataStorageKey.Company] !== null || this._data.value[CompanyDataStorageKey.Size] !== null } - static setSiret(value: EstablishmentFront) { - this.setItem(CompanyDataStorageKey.Siret, value) + static setCompany(value: CompanyDataType[CompanyDataStorageKey.Company]) { + this.setItem(CompanyDataStorageKey.Company, value) } static setSize(value: StructureSize) { this.setItem(CompanyDataStorageKey.Size, value) } - static setItem(key: CompanyDataStorageKey, value: string | EstablishmentFront | StructureSize): void { + static setItem(key: CompanyDataStorageKey, value: CompanyDataType[CompanyDataStorageKey.Company] | StructureSize): void { this._storageHandler.setItem(key, value) - this._updateData() + this.updateData() } static getItem(key: CompanyDataStorageKey): unknown { return this._storageHandler.getItem(key) } - static getSiret(): EstablishmentFront | null { - return (this.getItem(CompanyDataStorageKey.Siret) as EstablishmentFront) || null + static getCompanyData(): CompanyDataType[CompanyDataStorageKey.Company] | null { + return (this.getItem(CompanyDataStorageKey.Company) as CompanyDataType[CompanyDataStorageKey.Company]) || null } static getSize(): StructureSize | null { @@ -43,10 +43,11 @@ export default class CompanyDataStorage { static removeItem(key: CompanyDataStorageKey): void { this._storageHandler.removeItem(key) + this.updateData() } - private static _updateData(): void { - this._data.value[CompanyDataStorageKey.Siret] = this.getSiret() + static updateData(): void { + this._data.value[CompanyDataStorageKey.Company] = this.getCompanyData() this._data.value[CompanyDataStorageKey.Size] = this.getSize() } } diff --git a/apps/web/src/utils/track/TrackSiret.ts b/apps/web/src/utils/track/TrackSiret.ts index 3762cebda..3088e8636 100644 --- a/apps/web/src/utils/track/TrackSiret.ts +++ b/apps/web/src/utils/track/TrackSiret.ts @@ -5,8 +5,8 @@ import { SiretValidator } from '@tee/common' import CompanyDataStorage from '@/utils/storage/companyDataStorage' export default class TrackSiret { - static async search(query: string) { - return await new EstablishmentApi().getByQuery(query) + static async search(query: string, resultCount?: number) { + return await new EstablishmentApi().getByQuery(query, resultCount) } static createData( @@ -34,7 +34,7 @@ export default class TrackSiret { static saveData(option: TrackOptionsUnion, questionnaireData?: EstablishmentFront) { const data = questionnaireData || option.questionnaireData - CompanyDataStorage.setSiret(data as EstablishmentFront) + CompanyDataStorage.setCompany(data as EstablishmentFront) } static async getOptionBySiret(track: Track, siret: string): Promise { diff --git a/libs/backend-ddd/src/establishment/application/establishmentService.ts b/libs/backend-ddd/src/establishment/application/establishmentService.ts index f19dc5377..746bc787d 100644 --- a/libs/backend-ddd/src/establishment/application/establishmentService.ts +++ b/libs/backend-ddd/src/establishment/application/establishmentService.ts @@ -19,8 +19,8 @@ export default class EstablishmentService { ) } - public search(query: string): Promise> { - return this._establishmentFeatures.search(query) + public search(query: string, resultCount: number): Promise> { + return this._establishmentFeatures.search(query, resultCount) } public getBySiret(siret: Siret): Promise> { diff --git a/libs/backend-ddd/src/establishment/domain/establishmentFeatures.ts b/libs/backend-ddd/src/establishment/domain/establishmentFeatures.ts index 5bcba55af..919995ccd 100644 --- a/libs/backend-ddd/src/establishment/domain/establishmentFeatures.ts +++ b/libs/backend-ddd/src/establishment/domain/establishmentFeatures.ts @@ -14,7 +14,7 @@ export default class EstablishmentFeatures { this._nafMapping = nafMapping } - public async search(query: string): Promise> { + public async search(query: string, resultCount: number): Promise> { if (SiretValidator.validate(query)) { const bySiretResult = await this._searchBySiret(query) if (bySiretResult.isOk) { @@ -22,7 +22,7 @@ export default class EstablishmentFeatures { } } - return await this._searchByQuery(query) + return await this._searchByQuery(query, resultCount) } public async getBySiret(siret: Siret): Promise> { @@ -48,8 +48,8 @@ export default class EstablishmentFeatures { return Result.ok(establishmentSearch) } - private async _searchByQuery(query: string): Promise> { - const results = await this._establishmentRepository.search(query) + private async _searchByQuery(query: string, resultCount: number): Promise> { + const results = await this._establishmentRepository.search(query, resultCount) if (results.isOk) { const establishmentsSearch = this._enrichAndConvertToEstablishmentSearch(results.value) return Result.ok(establishmentsSearch) diff --git a/libs/backend-ddd/src/establishment/domain/spi.ts b/libs/backend-ddd/src/establishment/domain/spi.ts index bd9886ca9..01721d722 100644 --- a/libs/backend-ddd/src/establishment/domain/spi.ts +++ b/libs/backend-ddd/src/establishment/domain/spi.ts @@ -3,7 +3,7 @@ import { EstablishmentDetails, SearchResult } from './types' export type EstablishmentRepository = { get: (siret: string) => Promise> - search: (query: string) => Promise> + search: (query: string, resultCount: number) => Promise> } export type CityToRegionMappingType = { diff --git a/libs/backend-ddd/src/establishment/infrastructure/api/recherche-entreprise/recherche-entreprise.ts b/libs/backend-ddd/src/establishment/infrastructure/api/recherche-entreprise/recherche-entreprise.ts index ad201f3f2..207e67a12 100644 --- a/libs/backend-ddd/src/establishment/infrastructure/api/recherche-entreprise/recherche-entreprise.ts +++ b/libs/backend-ddd/src/establishment/infrastructure/api/recherche-entreprise/recherche-entreprise.ts @@ -7,8 +7,8 @@ import { RechercheEntrepriseEstablishment, RechercheEntrepriseSearch } from './t import Monitor from '../../../../common/domain/monitoring/monitor' export class RechercheEntreprise { - public searchEstablishment: EstablishmentRepository['search'] = async (query) => { - const api_url = `https://recherche-entreprises.api.gouv.fr/search?q=${query}&per_page=3&etat_administratif=A` + public searchEstablishment: EstablishmentRepository['search'] = async (query: string, resultCount: number) => { + const api_url = `https://recherche-entreprises.api.gouv.fr/search?q=${query}&per_page=${resultCount}&etat_administratif=A` try { const response: AxiosResponse = await axios.get(api_url)