import { BaseEntity } from "./BaseEntity.js"; import type { PaginatorPage, PaginatorState } from "./BaseEntity.js"; import type { AddOrganizationData, GetMembersAdminData, GetMembersNoAdminData } from "./EndpointApi.types.js"; import type { OpeningHoursEntry } from "./serverDataType/common.js"; import type { OrganizationItemNormalized } from "./serverDataType/Organization.js"; import type { User } from "./User.js"; export declare class Organization extends BaseEntity { static entityType: string; static entityTag: string; /** Bloc de création où injecter les champs costum (CostumScope). */ static COSTUM_ADD_CONSTANT: string; static SCHEMA_CONSTANTS: string[]; static VIRTUAL_SCHEMAS: { VIRTUAL_OPENING_HOURS: { type: string; properties: { openingHours: { type: string; description: string; minItems: number; maxItems: number; items: { oneOf: ({ type: string; const: string; properties?: undefined; required?: undefined; additionalProperties?: undefined; } | { type: string; properties: { dayOfWeek: { type: string; enum: string[]; description: string; }; hours: { type: string; description: string; items: { type: string; properties: { opens: { type: string; pattern: string; description: string; }; closes: { type: string; pattern: string; description: string; }; }; required: string[]; additionalProperties: boolean; }; }; }; required: string[]; additionalProperties: boolean; const?: undefined; })[]; }; }; }; }; /** * Champs de BASE (DATA_BINDING) sans `UPDATE_BLOCK_*` dédié : `telephone`/`video`. Déclarés ici * pour être writable sur le draft, persistés à l'édition via CUSTOM_FIELD_HANDLERS → UPDATE_PATH_VALUE. * (Les champs TIERS-LIEU costum — holderOrganization/manageModel/typePlace/buildingSurfaceArea/ * siteSurfaceArea/openingDate — sont désormais gérés par CostumScope/auto-derive, cf. inc1b/inc2.) */ VIRTUAL_ORG_BASE_FIELDS: { type: string; properties: { telephone: { type: string; }; video: { type: string; items: { type: string; }; }; }; }; }; static CUSTOM_FIELD_HANDLERS: Map<"openingHours" | "video" | "telephone", { readonly updateMethod: "updateOpeningHours"; readonly schemaConstant: "VIRTUAL_OPENING_HOURS"; } | { readonly updateMethod: "updateTelephone"; readonly schemaConstant: "VIRTUAL_ORG_BASE_FIELDS"; } | { readonly updateMethod: "updateVideo"; readonly schemaConstant: "VIRTUAL_ORG_BASE_FIELDS"; }>; static ADD_BLOCKS: Map<"UPDATE_BLOCK_SOCIAL" | "PROFIL_IMAGE" | "ADD_ORGANIZATION", "updateImageProfil" | "updateSocial" | "addOrganization">; static UPDATE_BLOCKS: Map<"UPDATE_BLOCK_DESCRIPTION" | "UPDATE_BLOCK_INFO" | "UPDATE_BLOCK_SOCIAL" | "UPDATE_BLOCK_LOCALITY" | "UPDATE_BLOCK_SLUG" | "PROFIL_IMAGE", "updateImageProfil" | "updateDescription" | "updateSocial" | "updateLocality" | "updateInfo" | "updateSlug">; defaultFields: Record; removeFields: string[]; transforms: Record any>; /** * Transforme les Answer docs imbriqués dans `data.answers` (renvoyé par /costum/navigator/gettl) * en instances d'entité Answer. Le payload backend fait un PHDB::find(Answer::COLLECTION, ...) brut, * donc on injecte `collection: "answers"` avant linkage pour rester cohérent avec les autres entités. * * Structure : `data.answers = { [formId]: AnswerDoc[] }` → `{ [formId]: Answer[] }` * (le formId reste une string ; charger le Form se fait via `api.form({ id: formId })`). * * @protected */ protected _transformServerData(data: OrganizationItemNormalized): OrganizationItemNormalized; _add: (payload: Record) => Promise; _update: (payload: Record) => Promise; /** * Ajoute une organisation. * * @param data - Données de l'organisation à ajouter. * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité n'est pas enregistrée. */ addOrganization(data: AddOrganizationData): Promise; /** * Supprime cette organisation via `DELETE_ELEMENT` (`type=organizations`). * * **Garde** : auteur (`serverData.creator`) OU administrateur direct de l'org * (`userContext.links.memberOf[id].isAdmin`). Pas de hiérarchie parent (une org * est racine). cf. {@link BaseEntity#_deleteViaElement}. * * ⚠️ **Destructif** : supprime l'organisation et potentiellement ses rattachements * (projets/events/membres) côté serveur. À utiliser avec précaution. * * Après succès : données vidées + `_isDeleted = true`. * * @param reason - Raison transmise au backend (audit). Défaut `"delete organization"`. * @throws {ApiError} 400 si l'org n'a pas d'id. * @throws {ApiError} 403 si ni auteur ni admin. */ delete(reason?: string): Promise; getOrganizations(): Promise; /** * {@inheritDoc BaseEntity#getProjects} * * Récupère les projets de l'organisation. */ getProjects(data?: Parameters["getProjects"]>[0]): Promise>; /** * {@inheritDoc BaseEntity#getEvents} * * Récupère les événements de l'organisation. */ getEvents(data?: Parameters["getEvents"]>[0]): Promise>; /** * {@inheritDoc BaseEntity#getPois} * * Récupère les points d'intérêt de l'organisation. */ getPois(data?: Parameters["getPois"]>[0]): Promise>; /** * {@inheritDoc BaseEntity#getBadgesIssuer} * * Récupère les émetteurs de badges de l'organisation. */ getBadgesIssuer(data?: Parameters["getBadgesIssuer"]>[0]): Promise>; /** * {@inheritDoc BaseEntity#getNews} * * Récupère les actualités de l'organisation. */ getNews(data?: Parameters["getNews"]>[0]): Promise; /** * {@inheritDoc BaseEntity#getSubscribers} * * Récupère les abonnés de l'organisation. */ getSubscribers(data?: Parameters["getSubscribers"]>[0]): Promise>; /** * Récupérer les membres de l'organisation. * Constant : GET_MEMBERS_ADMIN / GET_MEMBERS_NO_ADMIN * @param data - Paramètres (partiels) de recherche/pagination. * @param options - Options supplémentaires. * @param options.toBeValidated - Indique si les membres doivent être validés. * @param options.isAdmin - Indique si l'utilisateur est admin. * @param options.isAdminPending - Indique si l'utilisateur est en attente de validation pour être admin. * @param options.isInviting - Indique si l'utilisateur est en attente d'invitation. * @param options.roles - Liste des rôles à filtrer. * @returns - Un objet contenant le nombre de membres et la liste des membres. * @throws {ApiResponseError} - Si une erreur se produit lors de la récupération des contributeurs. * * @example * // Récupérer tous les membres * const members = await organization.getMembers(); * * // Récupérer les membres avec validation en attente * const membersToBeValidated = await organization.getMembers({}, { toBeValidated: true }); * * // Récupérer les membres avec un rôle spécifique * const membersWithRole = await organization.getMembers({}, { roles: ['admin'] }); * * // Récupérer les membres en attente d'invitation * const invitingMembers = await organization.getMembers({}, { isInviting: true }); * * // Récupérer les membres admin * const adminMembers = await organization.getMembers({}, { isAdmin: true }); * * // Récupérer les membres admin et en attente d'invitation * const adminInvitingMembers = await organization.getMembers({}, { isAdmin: true, isInviting: true }); * * // Récupérer les membres avec validation en attente et admin * const adminToBeValidatedMembers = await organization.getMembers({}, { toBeValidated: true, isAdmin: true }); * * // Récupérer les membres en attente de validation pour être admin * const adminPendingMembers = await organization.getMembers({}, { isAdminPending: true }); * * // Restreindre la recherche : uniquement les citoyens * const onlyCitoyens = await organization.getMembers({}, { searchType: "citoyens" }); * * // Restreindre la recherche : uniquement les organisations * const onlyOrgas = await organization.getMembers({}, { searchType: "organizations" }); */ getMembers(data?: Partial, options?: { toBeValidated?: boolean; isAdmin?: boolean; isAdminPending?: boolean; isInviting?: boolean; roles?: any[]; searchType?: "all" | "citoyens" | "organizations"; restoredState?: PaginatorState; }): Promise>; /** * Récupère les organisations dont **cette** organisation est membre * (lien montant : réseau, fédération, collectif… dont l'orga fait partie). * * C'est le miroir de {@link Organization#getMembers} : `getMembers()` liste * *qui* est membre de cette orga, tandis que `getMemberOf()` liste *les orgas * dont cette orga est elle-même membre*. * * Contrairement à {@link BaseEntity#getOrganizations} (désactivée ici car pensée * pour un citoyen via `GET_ORGANIZATIONS_*`), on passe par la recherche réseau * globale `searchCostum` : on cible `searchType: ["organizations"]` et on filtre * sur `links.members.{thisOrgId}`. Seules les adhésions **confirmées** sont * retournées (les liens `toBeValidated` et `isInviting` sont exclus). * * La pagination (`hasNext`/`next()`) et la restauration via `restoredState` * fonctionnent comme pour `searchCostum` : le filtre membership est conservé * d'une page à l'autre. * * @param data - Paramètres de recherche/pagination additionnels (`name`, `indexStep`, * `sortBy`, `locality`, `filters` complémentaires…). Les `filters` fournis sont * fusionnés avec le filtre membership, ce dernier restant prioritaire. * @param options - Options. `restoredState` pour reprendre une pagination sérialisée. * @returns Première page paginée d'organisations. * @throws {ApiError} Si l'organisation n'a pas d'`id`. * * @example * // Toutes les orgas dont cette orga est membre * const page = await org.getMemberOf(); * console.log(page.results, page.count.total); * * @example * // Filtrer par nom + pagination plus large * const page = await org.getMemberOf({ name: "réseau", indexStep: 50 }); * if (page.hasNext) await page.next(); */ getMemberOf(data?: Parameters["searchCostum"]>[0], options?: { restoredState?: PaginatorState; }): Promise>; /** * {@inheritDoc BaseEntity#getGallery} * * Récupère la galerie de l'organisation. */ getGallery(data?: Parameters["getGallery"]>[0]): Promise>; /** * {@inheritDoc BaseEntity#project} * * Crée une instance de projet et récupère son profil si nécessaire. */ project(projectData?: Parameters["project"]>[0]): Promise; /** * {@inheritDoc BaseEntity#poi} * * Crée une instance de POI et la récupère si nécessaire. */ poi(poiData?: Parameters["poi"]>[0]): Promise; /** * {@inheritDoc BaseEntity#event} * * Crée une instance d'événement et la récupère si nécessaire. */ event(eventData?: Parameters["event"]>[0]): Promise; /** * {@inheritDoc BaseEntity#badge} * * Crée une instance de badge et la récupère si nécessaire. */ badge(badgeData?: Parameters["badge"]>[0]): Promise; /** * {@inheritDoc BaseEntity#news} * * Crée une instance de news et la récupère si nécessaire. */ news(newsData?: Parameters["news"]>[0]): Promise; /** * {@inheritDoc BaseEntity#form} * * Crée une instance de Form dans le contexte de cette organisation : le Form aura * `this.parent = Organization`, ce qui permet à `form.getAnswers()` de déléguer * `coformAnswersSearch` avec le bon costumContext. */ form(formData?: Parameters["form"]>[0]): Promise; /** * Met à jour les horaires d'ouverture de l'organisation. * Utilise UPDATE_PATH_VALUE pour modifier le champ openingHours. * * @param hours - Tableau de 7 entrées (une par jour de la semaine) * @returns Résultat de l'appel API * @throws {ApiError} Si l'organisation n'a pas d'ID * * @example * const openingHours = [ * { dayOfWeek: "Mo", hours: [{ opens: "09:00", closes: "18:00" }] }, * { dayOfWeek: "Tu", hours: [{ opens: "09:00", closes: "18:00" }] }, * // ... pour les 7 jours * ]; * await org.updateOpeningHours(openingHours); */ updateOpeningHours(hours: OpeningHoursEntry[]): Promise; /** * ─────────────────────────────── * Champs de BASE sans `UPDATE_BLOCK_*` dédié : `telephone` / `video` (dispatch UPDATE_PATH_VALUE). * Les champs TIERS-LIEU costum (holderOrganization/manageModel/typePlace/buildingSurfaceArea/ * siteSurfaceArea/openingDate) sont gérés par CostumScope (création) + auto-derive de `_costumCtx` * depuis `source.key` (chargement) → dispatch générique `_dispatchCostumFieldUpdates`. cf. inc1b/inc2. * ─────────────────────────────── */ /** Met à jour `telephone` (téléphone de la structure, distinct des champs citoyen fixe/mobile). */ updateTelephone(value: string): Promise; /** Met à jour `video` (liste d'URLs de vidéos de présentation). */ updateVideo(value: string[]): Promise; /** * ─────────────────────────────── * Lien utilisateur ↔ organisation * (rejoindre, valider, quitter, devenir admin) * ─────────────────────────────── */ /** * {@inheritDoc BaseEntity#requestToJoin} * * Envoie une demande pour rejoindre l'organisation en tant que membre. * L'action est soumise à validation par un administrateur de l'organisation. */ requestToJoin(): Promise; /** * {@inheritDoc BaseEntity#requestToJoinAdmin} * * Envoie une demande pour rejoindre l'organisation en tant qu'administrateur. * L'action est soumise à validation par un administrateur existant. */ requestToJoinAdmin(): Promise; /** * {@inheritDoc BaseEntity#acceptInvitation} * * Accepte une invitation à rejoindre l'organisation. * Cette action valide un lien en attente avec l'option `isInviting`. */ acceptInvitation(): Promise; /** * {@inheritDoc BaseEntity#requestPromoteToAdmin} * * Envoie une demande de promotion en tant qu'administrateur de l'organisation. * L'utilisateur doit déjà être membre de l'organisation. */ requestPromoteToAdmin(): Promise; /** * {@inheritDoc BaseEntity#leave} * * Quitte l'organisation, que ce soit en tant que membre ou administrateur. * Cette action supprime le lien entre l'utilisateur et l'organisation. */ leave(): Promise; /** * {@inheritDoc BaseEntity#follow} * * Suivre une organisation. * Cette action permet à l'utilisateur de suivre l'organisation. */ follow(): Promise; /** * {@inheritDoc BaseEntity#unfollow} * * Se désabonne d'une organisation. */ unfollow(): Promise; /** * ─────────────────────────────── * costum * ─────────────────────────────── */ /** * {@inheritDoc BaseEntity#getCostumJson} * * Récupère le JSON personnalisé de l'organisation. */ getCostumJson(): Promise; /** * {@inheritDoc BaseEntity#searchCostum} * * Cette surcharge précise que la recherche est faite dans le contexte de l'organisation. */ searchCostum(data: Parameters["searchCostum"]>[0], options?: Parameters["searchCostum"]>[1]): Promise>; /** * {@inheritDoc BaseEntity#coformAnswersSearch} * * Cette méthode est redéfinie ici pour fournir des types spécifiques à l'entité Answer. */ coformAnswersSearch(data: Parameters["coformAnswersSearch"]>[0]): Promise>; }