@communecter/cocolight-api-client 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/api/News.js CHANGED
@@ -1,142 +1,44 @@
1
1
  import { ApiError } from "../error.js";
2
- import { DraftStateMixin } from "../mixin/DraftStateMixin.js";
3
- import { UtilMixin } from "../mixin/UtilMixin.js";
4
-
5
- // News.js
6
- export class News {
7
- #draftData = {};
8
- #initialDraftData = {};
9
- #serverData = null;
2
+ import BaseEntity from "./BaseEntity.js";
10
3
 
4
+ export class News extends BaseEntity {
11
5
  static entityType = "news";
12
6
 
13
7
  static SCHEMA_CONSTANTS = [
14
8
  "ADD_NEWS"
15
9
  ];
16
10
 
17
- /**
18
- * Crée une instance de News.
19
- * @param {(Organization|Project|User)} parent - L'instance de l'element parent (ex: Organization, Project, User).
20
- * @param {Object} data - Objet contenant { id }
21
- * @param {Object} deps - Dépendances injectées (ex: User).
22
- * @param {EndpointApi} deps.EndpointApi - Classe EndpointApi pour éviter les dépendances circulaires.
23
- * @param {User} deps.User - Classe User pour éviter les dépendances circulaires.
24
- */
25
-
26
- constructor(parent, data = {}, deps = {}) {
27
- this.__entityTag = "News";
28
-
29
- if (!deps.EndpointApi) throw new ApiError("EndpointApi class must be injected to avoid circular dependency.");
30
- if (!deps.User) throw new ApiError("User class must be injected.");
31
-
32
- if (!parent) throw new ApiError("Parent is required.");
33
- this.deps = deps;
34
- this.EndpointApiClass = deps.EndpointApi;
35
-
36
- if (parent?.__entityTag === "User" || parent?.__entityTag === "Organization" || parent?.__entityTag === "Project") {
37
- this.apiClient = parent.apiClient;
38
- this.parent = parent;
39
- } else {
40
- throw new ApiError("Invalid parent for News.");
41
- }
42
-
43
- this.endpointApi = typeof deps.EndpointApi === "function"
44
- ? new deps.EndpointApi(this.apiClient)
45
- : (typeof deps.EndpointApi === "object"
46
- ? deps.EndpointApi
47
- : (() => { throw new ApiError("deps.EndpointApi must be a class or instance."); })());
48
-
49
-
50
- this.#serverData = null;
11
+ static ADD_BLOCKS = new Map([
12
+ ["ADD_NEWS", "addNews"]
13
+ ]);
51
14
 
52
- const { draft, proxy } = this._buildDraftAndProxy({
53
- data: { ...data, ...this.defaultFields },
54
- serverData: this.#serverData,
55
- constant: News.SCHEMA_CONSTANTS,
56
- apiClient: this.apiClient,
57
- transforms: this.transforms,
58
- removeFields: this.removeFields
59
- });
60
-
61
- this.#initialDraftData = JSON.parse(JSON.stringify(draft)); // snapshot propre
62
- this.#draftData = draft;
63
- this.data = proxy;
15
+ static UPDATE_BLOCKS = new Map([
16
+ ["ADD_NEWS", "updateNews"]
17
+ ]);
64
18
 
65
- }
66
-
67
-
68
- // Getters en lecture seule pour chaque propriété
69
- get id() {
70
- return this.#draftData.id || null;
71
- }
72
-
73
- get isConnected() {
74
- return this.apiClient.isConnected;
75
- }
76
-
77
- get draftData() {
78
- return this.#draftData;
79
- }
80
-
81
- get initialDraftData() {
82
- return this.#initialDraftData;
83
- }
84
-
85
- get serverData() {
86
- return this.#serverData;
87
- }
88
-
89
- get userId() {
90
- return this.apiClient.userId;
91
- }
92
-
93
- get isMe() {
94
- return this.isConnected && this.userId === this.parent.id;
95
- }
96
-
97
- _setData(newData) {
98
- this.#serverData = { ...newData };
19
+ defaultFields = {
99
20
 
100
- const { draft, proxy } = this._buildDraftAndProxy({
101
- data: { ...newData, ...this.defaultFields },
102
- serverData: this.#serverData,
103
- constant: News.SCHEMA_CONSTANTS,
104
- apiClient: this.apiClient,
105
- transforms: this.transforms,
106
- removeFields: this.removeFields
107
- });
108
- this.#initialDraftData = JSON.parse(JSON.stringify(draft));
109
- this.#draftData = draft;
110
- this.data = proxy;
111
- }
21
+ };
112
22
 
113
- getEntityType() {
114
- return News.entityType;
115
- }
23
+ removeFields = [
116
24
 
117
- static fromServerData(data, parent, deps) {
118
- const instance = new News(parent, {}, deps);
119
- instance.#serverData = { ...data };
120
-
121
- const { draft, proxy } = instance._buildDraftAndProxy({
122
- data: { ...data, ...instance.defaultFields },
123
- serverData: instance.#serverData,
124
- constant: News.SCHEMA_CONSTANTS,
125
- apiClient: instance.apiClient,
126
- transforms: instance.transforms,
127
- removeFields: instance.removeFields
128
- });
129
-
130
- instance.#draftData = draft;
131
- instance.data = proxy;
132
-
133
- return instance;
134
- }
25
+ ];
135
26
 
136
- async refresh() {
137
- if (!this.id) throw new ApiError("Impossible de rafraîchir sans ID.");
138
- return this.get();
139
- }
27
+ transforms = {
28
+ scope: val => val?.type,
29
+ mentions: val =>
30
+ Array.isArray(val)
31
+ ? val.map(m => ({ ...m, count: parseInt(m.count) }))
32
+ : [],
33
+ mediaImg: val => {
34
+ const images = val?.images?.map(img => img.id).filter(Boolean) || [];
35
+ return images.length > 0 ? { countImages: images.length, images } : undefined;
36
+ },
37
+ mediaFile: val => {
38
+ const files = val?.files?.map(f => f.id).filter(Boolean) || [];
39
+ return files.length > 0 ? { countFiles: files.length, files } : undefined;
40
+ }
41
+ };
140
42
 
141
43
  /**
142
44
  * Récupérer des actualités par IDs : Récupère des actualités à partir d’une liste d’identifiants.
@@ -144,93 +46,140 @@ export class News {
144
46
  */
145
47
  async get() {
146
48
  if (!this.id) throw new ApiError("Impossible de rafraîchir sans ID.");
147
-
49
+
148
50
  const newsArray = await this.callIsConnected(() =>
149
51
  this.endpointApi.getNewsById({ ids: [this.id] })
150
52
  );
151
-
53
+
152
54
  if (newsArray && Array.isArray(newsArray) && newsArray.length === 1) {
153
55
  const data = newsArray[0];
154
- this.#serverData = { ...data };
155
-
156
56
  this._setData(data);
157
-
158
- return this.#serverData;
57
+ return this.serverData;
159
58
  }
160
59
  throw new ApiError(`Aucune actualité trouvée pour l'ID ${this.id}`);
161
60
  }
162
61
 
163
-
164
- /**
165
- * Ajouter une actualité : Ajoute une nouvelle actualité.
166
- * Constant : ADD_NEWS | UPDATE_NEWS
167
- */
168
- async save() {
169
-
170
- if(!this.isConnected){
171
- throw new ApiError("Impossible de sauvegarder sans être connecté.");
62
+
63
+ async _add(payload) {
64
+ if (!this._calledFromSave) {
65
+ throw new Error("utilisation invalide de _add, utilisez save");
172
66
  }
173
67
 
174
68
  // si le texte est vide, on met un espace pour que le champ soit pris en compte car sur le serveur
175
69
  // il y a une vérification de la taille du texte je pense
176
- if(this.#draftData?.text === ""){
177
- this.#draftData.text = " ";
70
+ if(payload.text === ""){
71
+ payload.text = " ";
178
72
  }
179
-
180
- const payload = { ...this.#draftData };
181
73
  payload.parentId = this.parent.id;
182
74
  payload.parentType = this.parent.getEntityType();
183
-
184
- if (!this.id) {
185
- const reponseData = await this.callIsConnected(() => this.endpointApi.addNews(payload));
186
- this.#draftData.id = reponseData.object.id;
187
- // TODO : voir si j'ai ce qui faut dans reponseData de ADD_NEWS pour mettre à jour #serverData
188
- // c'est dans reponseData.object
189
- if(reponseData?.object){
190
- this.#serverData = { ...reponseData.object };
191
- }
192
- // await this.refresh();
193
- return reponseData;
194
- } else {
195
- if(payload.id){
196
- delete payload.id;
197
- }
198
- const reponseData = await this.callIsConnected(() => this.endpointApi.updateNews({ ...payload, idNews: this.id }));
199
- // TODO : voir si j'ai ce qui faut dans reponseData de UPDATE_NEWS pour mettre à jour #serverData
200
- // c'est dans reponseData.object
201
- if(reponseData?.object){
202
- this.#serverData = { ...reponseData.object };
75
+
76
+ // const data = await this.callIsConnected(() => this.endpointApi.addNews(payload));
77
+ // this._draftData.id = data.object.id;
78
+ // // TODO : voir si j'ai ce qui faut dans reponseData de ADD_NEWS pour mettre à jour #serverData
79
+ // // c'est dans reponseData.object
80
+ // // if(data?.object){
81
+ // // this._serverData = { ...data.object };
82
+ // // }
83
+
84
+ for (const [constant, methodName] of News.ADD_BLOCKS) {
85
+ const blockData = this._extractChangedFieldsFromSchema(
86
+ this.apiClient,
87
+ constant,
88
+ { ...payload, ...this.defaultFields },
89
+ () => {}
90
+ );
91
+ if (blockData && Object.keys(blockData).length > 0) {
92
+ const data = await this[methodName](blockData);
93
+ if (!this.id && data?.object?.id) {
94
+ this._draftData.id = data.object.id;
95
+ // this._serverData = { ...data.object };
96
+ }
203
97
  }
204
- // await this.refresh();
205
- return reponseData;
206
98
  }
207
99
  }
208
100
 
101
+ async _update(payload) {
102
+ if (!this._calledFromSave) {
103
+ throw new Error("utilisation invalide de _update, utilisez save");
104
+ }
105
+
106
+ if (payload.id) delete payload.id;
107
+
108
+ // si le texte est vide, on met un espace pour que le champ soit pris en compte car sur le serveur
109
+ // il y a une vérification de la taille du texte je pense
110
+ if(payload?.text === ""){
111
+ payload.text = " ";
112
+ }
113
+
114
+ payload.parentId = this.parent.id;
115
+ payload.parentType = this.parent.getEntityType();
116
+ payload.idNews = this.id;
117
+
118
+ let hasChanged = false;
119
+ const data = await this.callIsConnected(() => this.endpointApi.updateNews(payload));
120
+ // TODO : voir si j'ai ce qui faut dans data de UPDATE_NEWS pour mettre à jour #serverData
121
+ // c'est dans data.object
122
+ if(data?.object){
123
+ this._serverData = { ...data.object };
124
+ }
125
+ hasChanged = true;
126
+ return hasChanged;
127
+
128
+ // if (payload.id) delete payload.id;
129
+ // let hasChanged = false;
130
+
131
+ // for (const [constant, methodName] of News.UPDATE_BLOCKS) {
132
+ // const blockData = this._extractChangedFieldsFromSchema(
133
+ // this.apiClient,
134
+ // constant,
135
+ // { ...payload, ...this.defaultFields },
136
+ // () => this.initialDraftData,
137
+ // this.removeFields
138
+ // );
139
+ // if (blockData && Object.keys(blockData).length > 0) {
140
+ // await this[methodName](blockData);
141
+ // hasChanged = true;
142
+ // }
143
+ // }
144
+
145
+ // return hasChanged;
146
+ }
147
+
148
+ async addNews(data = {}) {
149
+ return this.callIsConnected(() => this.endpointApi.addNews(data));
150
+ }
151
+
152
+ async updateNews(data = {}) {
153
+ return this.callIsConnected(() => this.endpointApi.updateNews(data));
154
+ }
209
155
 
210
156
  async addMention({ slug, id }) {
211
157
  try {
212
158
  if (!slug && !id) {
213
159
  throw new ApiError("Vous devez fournir un slug ou un id pour ajouter une mention.");
214
160
  }
215
- const userInstance = new this.deps.User(this.apiClient, { id, slug }, { EndpointApi: this.endpointApi });
161
+
162
+ const userInstance = await this.entity("citoyens", { id, slug });
163
+ // const userInstance = new this.deps.User(this.apiClient, { id, slug }, { EndpointApi: this.endpointApi });
216
164
  const user = userInstance.serverData;
217
- if (!this.#draftData.mentions) {
218
- this.#draftData.mentions = [];
165
+
166
+ if (!this._draftData.mentions) {
167
+ this._draftData.mentions = [];
219
168
  }
220
169
  // Vérification si la mention existe déjà
221
- if (this.#draftData.mentions.find((mention) => mention.id === user.id)) {
170
+ if (this._draftData.mentions.find((mention) => mention.id === user.id)) {
222
171
  // Si la mention existe déjà, on incrémente le compteur
223
- this.#draftData.mentions = this.#draftData.mentions.map((mention) => {
172
+ this._draftData.mentions = this._draftData.mentions.map((mention) => {
224
173
  if (mention.id === user.id) {
225
174
  mention.count += 1;
226
175
  }
227
176
  return mention;
228
177
  });
229
- return this.#draftData.mentions;
178
+ return this._draftData.mentions;
230
179
  }
231
180
  const mention = { id: user.id, slug: user.slug, type: userInstance.getEntityType(), name: user.name, value: user.name, count: 1 };
232
- this.#draftData.mentions.push(mention);
233
- return this.#draftData.mentions;
181
+ this._draftData.mentions.push(mention);
182
+ return this._draftData.mentions;
234
183
  } catch (error) {
235
184
  this.apiClient._logger.error("Erreur lors de l'ajout de la mention :", error);
236
185
  throw error;
@@ -247,11 +196,11 @@ export class News {
247
196
  image = await this._validateImage(image);
248
197
  const data = { pathParams: { folder: this.parent.getEntityType(), ownerId: this.parent.id }, newsImage: image };
249
198
  const dataImage = await this.callIsConnected(() => this.endpointApi.addImageNews(data));
250
- if (this.#draftData.mediaImg) {
251
- this.#draftData.mediaImg.countImages = this.#draftData.mediaImg.countImages + 1;
252
- this.#draftData.mediaImg.images.push(dataImage.id);
199
+ if (this._draftData.mediaImg) {
200
+ this._draftData.mediaImg.countImages = this._draftData.mediaImg.countImages + 1;
201
+ this._draftData.mediaImg.images.push(dataImage.id);
253
202
  } else {
254
- this.#draftData.mediaImg = { countImages: 1, images: [dataImage.id] };
203
+ this._draftData.mediaImg = { countImages: 1, images: [dataImage.id] };
255
204
  }
256
205
  return dataImage;
257
206
  }
@@ -264,11 +213,11 @@ export class News {
264
213
  file = await this._validateFile(file);
265
214
  const data = { pathParams: { folder: this.parent.getEntityType(), ownerId: this.parent.id }, newsFile: file };
266
215
  const dataFile = await this.callIsConnected(() =>this.endpointApi.addFileNews(data));
267
- if (this.#draftData.mediaFile) {
268
- this.#draftData.mediaFile.countFiles = this.#draftData.mediaFile.countFiles + 1;
269
- this.#draftData.mediaFile.files.push(dataFile);
216
+ if (this._draftData.mediaFile) {
217
+ this._draftData.mediaFile.countFiles = this._draftData.mediaFile.countFiles + 1;
218
+ this._draftData.mediaFile.files.push(dataFile);
270
219
  } else {
271
- this.#draftData.mediaFile = { countFiles: 1, files: [dataFile] };
220
+ this._draftData.mediaFile = { countFiles: 1, files: [dataFile] };
272
221
  }
273
222
  return dataFile;
274
223
  }
@@ -283,45 +232,11 @@ export class News {
283
232
  }
284
233
  const data = { pathParams: { id: this.id } };
285
234
  await this.callIsConnected(() => this.endpointApi.deleteNews(data));
286
- this.#draftData = {};
287
- this.#serverData = null;
288
- this.#draftData.id = null;
235
+ this._draftData = {};
236
+ this._serverData = null;
237
+ this._draftData.id = null;
289
238
  this._isDeleted = true;
290
239
  }
291
240
 
292
- _updateInitialDraftSnapshot() {
293
- this.#initialDraftData = JSON.parse(JSON.stringify(this.#draftData));
294
- }
295
-
296
- hasChanges() {
297
- return JSON.stringify(this.#draftData) !== JSON.stringify(this.#initialDraftData);
298
- }
299
-
300
- defaultFields = {
301
-
302
- };
303
-
304
- removeFields = [
305
-
306
- ];
307
-
308
- transforms = {
309
- scope: val => val?.type,
310
- mentions: val =>
311
- Array.isArray(val)
312
- ? val.map(m => ({ ...m, count: parseInt(m.count) }))
313
- : [],
314
- mediaImg: val => {
315
- const images = val?.images?.map(img => img.id).filter(Boolean) || [];
316
- return images.length > 0 ? { countImages: images.length, images } : undefined;
317
- },
318
- mediaFile: val => {
319
- const files = val?.files?.map(f => f.id).filter(Boolean) || [];
320
- return files.length > 0 ? { countFiles: files.length, files } : undefined;
321
- }
322
- };
323
241
 
324
242
  }
325
-
326
- // Incorporation du mixin dans Organization
327
- Object.assign(News.prototype, UtilMixin, DraftStateMixin);