import { BaseEntity } from "./BaseEntity.js"; import type { Answer } from "./Answer.js"; import type { PaginatorPage, PaginatorState } from "./BaseEntity.js"; import type { CoformAnswersSearchData } from "./EndpointApi.types.js"; import type { CoformCommonTableContributor, FormItemNormalized } from "./serverDataType/Form.js"; /** * Une entrée de catalogue commonTable (une criteria agrégée cross-réponses). * `label`/`usage`/`usageKey`/`coeff`/`count` toujours présents (le backend * les construit avec défauts) ; `names`/`name` seulement si au moins une * réponse `yesOrNo` non vide existe pour la criteria. Les champs echo * (`label`, `usage`…) renvoient la valeur stockée brute, sans coercion. */ export interface CommonTableCatalogEntry { label: unknown; usage: unknown; usageKey: unknown; coeff: number | string | boolean | null; count: number; /** Distribution `{ solutionName → fréquence }` ; absent si aucune réponse. */ names?: Record; /** Mode (plus fréquent) de `names` ; présent ssi `names` présent. */ name?: string; } /** * Catalogue collaboratif des inputs `commonTable` : map * `inputKey → (criteriaId → CommonTableCatalogEntry)`. Les entrées sont * DIRECTEMENT sous l'inputKey (pas de niveau intermédiaire `entries`). * Format aligné sur la réponse backend de `GET_COFORM_CATALOGS` * (`getCatalogs` normalise les `[]` PHP — catalogues vides — en `{}`). */ export type CommonTableCatalogs = Record>; export declare class Form extends BaseEntity { static entityType: string; static entityTag: string; static SCHEMA_CONSTANTS: string[]; static ADD_BLOCKS: Map; static UPDATE_BLOCKS: Map; defaultFields: Record; removeFields: string[]; /** * Transforme les champs imbriqués en instances d'entités si nécessaire. * @param data - Les données brutes du serveur. * @returns Les données transformées. * @protected */ protected _transformServerData(data: FormItemNormalized): FormItemNormalized; /** * Rafraîchit les données du formulaire depuis l'API. * Constant : GET_COFORM_BY_ID */ get(): Promise>; /** * Recherche paginée des Answers liées à CE Form, dans le costumContext de son parent. * * **Délégation au parent** : le Form lui-même n'a pas de costumContext (pas de * `slug` côté serverData). Cette méthode remonte `this.parent` (qui doit être * une `Organization` ou un `Project` ayant un slug) et délègue à * `parent.coformAnswersSearch({ filters: { form: this.id, ... } })`. * * Pattern identique à `Comment._add` qui remonte `this.parent` pour récupérer * le contexte d'ancrage. * * **Important** : pour utiliser cette méthode, le Form doit avoir été créé via * `org.form({id})` ou `project.form({id})` — pas via `api.form({id})` direct * (qui crée un Form avec `parent = ApiClient`, sans costumContext). * * @param data - Paramètres de recherche (`filters`, `fields`, `sortBy`, etc.). * Le champ `filters.form` est automatiquement injecté avec `this.id`. * @param options - Options de pagination (`restoredState` pour reprendre une navigation) * @returns Première page paginée avec `results` (Answer[]), `count`, `hasNext`, etc. * @throws {ApiError} si le Form n'a pas d'id ou si son parent n'a pas de costumContext. * * @example * const org = await api.organization({ slug: "navigatorDesTierslieux" }); * const form = await org.form({ id: "6925e2b05dd63b02ca70d6d9" }); * const page = await form.getAnswers({ sortBy: { created: -1 } }); * page.results; // Answer[] * page.count.total; // nombre total */ getAnswers(data?: Partial, options?: { restoredState?: PaginatorState; }): Promise>; /** * {@inheritDoc BaseEntity#answer} * * Crée une instance d'Answer **rattachée à ce Form**. * * - Si `answerData.id` est fourni → fetch l'Answer existante (via `COFORM_ANSWERS_BY_ID`). * - Sinon → crée un draft d'Answer avec `form: this.id` pré-rempli, prêt à * être complété puis sauvegardé. * * Le parent de l'Answer renvoyée est ce Form — la chaîne `org > form > answer` * est donc préservée, ce qui permet (à terme) à l'Answer de remonter le * costumContext via `this.parent.parent` si besoin. * * @example * // Fetch d'une Answer existante * const form = await org.form({ id: "6925e2b05dd63b02ca70d6d9" }); * const answer = await form.answer({ id: "6925869ad76aaf6c5a2b2f8a" }); * * // Création d'un draft * const draft = await form.answer(); * draft.data.answers = { "field1": "value1" }; * await draft.save(); */ answer(answerData?: Parameters["answer"]>[0]): Promise; /** * Récupère la liste des contributeurs d'une table commune (commonTable) de CE formulaire. * * Pour un input `commonTable` et une ligne du tableau (un ou plusieurs `criteriaIds` * dédupés côté React via `groupKey`), retourne les contributions individuelles * (auteur, solution, satisfaction, note). * * Constant : GET_COFORM_COMMONTABLE_CONTRIBUTORS * (POST /survey/coform/getcommontablecontributors, auth bearer). * * @param params.inputKey - Clé originale de l'input commonTable (sans préfixe yesOrNo). * @param params.criteriaIds - criteriaIds de la ligne agrégée : tableau `string[]` * (sérialisé automatiquement) ou string JSON déjà sérialisée. * @returns La liste des contributions (une entrée par contribution). * @throws {ApiError} si le Form n'a pas d'id. * * @example * const form = await org.form({ id: "6925e2b05dd63b02ca70d6d9" }); * const contributors = await form.getCommonTableContributors({ * inputKey: "usagesEtSolutions", * criteriaIds: ["criteria1778265370227"], * }); */ getCommonTableContributors(params: { inputKey: string; criteriaIds: string | string[]; }): Promise; /** * Récupère en UN appel batch les catalogues collaboratifs des inputs * `commonTable` de CE formulaire. Pour chaque `inputKey`, retourne les * `criterias` agrégées par toutes les réponses + le comptage par * `criteriaId`. * * Constant : `GET_COFORM_CATALOGS` (POST `/survey/coform/getformcatalogs`, * auth: none — accessible aux visiteurs anonymes pour pré-remplir les * suggestions côté input). * * Si `inputKeys` est vide, on lève une erreur — le caller doit gate * l'appel en amont (cf. `useCoFormCatalogs` qui passe `enabled: false`). * * @param params.inputKeys - `fieldKey` de tous les inputs commonTable. * @returns Map `inputKey → (criteriaId → entry)` ; `{}` pour un inputKey sans données. * @throws {ApiError} 400 si Form sans id ou `inputKeys` vide. * * @example * const form = await api.form({ id: formId }); * const catalogs = await form.getCatalogs({ inputKeys: ["usagesEtSolutions"] }); * catalogs["usagesEtSolutions"]; // {criteriaId: {label, count, name?, names?, ...}} */ getCatalogs(params: { inputKeys: string[]; }): Promise; }