@interware/content-generator 0.6.0 → 0.7.0

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.
Files changed (58) hide show
  1. package/dist/_chunks/App-Cwr5ra5m.js +1380 -0
  2. package/dist/_chunks/App-h4_txTsI.mjs +1362 -0
  3. package/dist/_chunks/{ImageStudioTabs-BLAH3KYv.mjs → ImageStudioTabs-B-mOwDfY.mjs} +687 -682
  4. package/dist/_chunks/{ImageStudioTabs-DtusqpQO.js → ImageStudioTabs-CG4KTn1S.js} +683 -678
  5. package/dist/_chunks/{Settings-o2GngLaW.mjs → Settings-BT-EqvXs.mjs} +2 -2
  6. package/dist/_chunks/{Settings-BQXxV3LO.js → Settings-D4NGBTk1.js} +4 -4
  7. package/dist/_chunks/{StudioApp-BaySMwrk.js → StudioApp-_ViSAwCm.js} +2 -2
  8. package/dist/_chunks/{StudioApp-C_znlQRo.mjs → StudioApp-xaEy-uIk.mjs} +2 -2
  9. package/dist/_chunks/{index-BKigRXm3.mjs → index-D67xWUPz.mjs} +3 -28
  10. package/dist/_chunks/{index-BKhe-Jyx.js → index-NA9OuMGs.js} +3 -28
  11. package/dist/admin/index.js +1 -1
  12. package/dist/admin/index.mjs +1 -1
  13. package/dist/admin/src/features/articles/ArticlePage.d.ts +5 -0
  14. package/dist/admin/src/features/articles/ArticlesPage.d.ts +7 -0
  15. package/dist/admin/src/features/articles/NewArticlePage.d.ts +6 -0
  16. package/dist/admin/src/features/articles/SharePreview.d.ts +19 -0
  17. package/dist/admin/src/features/articles/articlesApi.d.ts +94 -0
  18. package/dist/admin/src/features/articles/model.d.ts +24 -0
  19. package/dist/admin/src/features/articles/useArticlesApi.d.ts +19 -0
  20. package/dist/admin/src/features/library/LibraryImagePicker.d.ts +6 -1
  21. package/dist/admin/src/lib/postText.d.ts +25 -0
  22. package/dist/server/index.js +515 -321
  23. package/dist/server/index.mjs +515 -321
  24. package/dist/server/src/articles/generation.d.ts +135 -0
  25. package/dist/server/src/articles/schedule.d.ts +12 -0
  26. package/dist/server/src/articles/sources.d.ts +12 -0
  27. package/dist/server/src/bootstrap.d.ts +2 -0
  28. package/dist/server/src/controllers/articles.d.ts +30 -0
  29. package/dist/server/src/controllers/controller.d.ts +0 -4
  30. package/dist/server/src/controllers/index.d.ts +92 -4
  31. package/dist/server/src/index.d.ts +122 -67
  32. package/dist/server/src/services/articles.d.ts +126 -0
  33. package/dist/server/src/services/image-studio.d.ts +0 -10
  34. package/dist/server/src/services/index.d.ts +30 -63
  35. package/dist/server/src/services/service.d.ts +1 -62
  36. package/package.json +1 -1
  37. package/dist/_chunks/App-CJxSC8yt.js +0 -1105
  38. package/dist/_chunks/App-qbgUXlOZ.mjs +0 -1087
  39. package/dist/_chunks/getTranslation-B6Bsu-uq.mjs +0 -5
  40. package/dist/_chunks/getTranslation-BRVMWSf8.js +0 -4
  41. package/dist/admin/src/components/commons/dialog/index.d.ts +0 -12
  42. package/dist/admin/src/components/commons/generate-image-dialog/index.d.ts +0 -5
  43. package/dist/admin/src/components/generate-content/Form.d.ts +0 -15
  44. package/dist/admin/src/components/home/table.d.ts +0 -13
  45. package/dist/admin/src/components/index.d.ts +0 -12
  46. package/dist/admin/src/containers/generate-content/index.d.ts +0 -2
  47. package/dist/admin/src/containers/home/index.d.ts +0 -2
  48. package/dist/admin/src/hooks/useDialog.d.ts +0 -11
  49. package/dist/admin/src/lib/use-cases/articles/index.d.ts +0 -16
  50. package/dist/admin/src/lib/use-cases/categories/index.d.ts +0 -16
  51. package/dist/admin/src/lib/use-cases/facebook/index.d.ts +0 -5
  52. package/dist/admin/src/lib/use-cases/generate-content/index.d.ts +0 -6
  53. package/dist/admin/src/lib/use-cases/linkedin/index.d.ts +0 -5
  54. package/dist/admin/src/lib/use-cases/users/index.d.ts +0 -16
  55. package/dist/admin/src/pages/GenerateContent.d.ts +0 -2
  56. package/dist/admin/src/pages/HomePage.d.ts +0 -2
  57. package/dist/admin/src/reducers/dialog/index.d.ts +0 -6
  58. package/dist/admin/src/types/reducers.d.ts +0 -4
@@ -1,1105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const jsxRuntime = require("react/jsx-runtime");
4
- const admin = require("@strapi/strapi/admin");
5
- const reactRouterDom = require("react-router-dom");
6
- const PluginProviders = require("./PluginProviders-D79TeGSE.js");
7
- const reactIntl = require("react-intl");
8
- const react = require("react");
9
- const designSystem = require("@strapi/design-system");
10
- const reactRedux = require("react-redux");
11
- const index = require("./index-BKhe-Jyx.js");
12
- const icons = require("@strapi/icons");
13
- const getTranslation = require("./getTranslation-BRVMWSf8.js");
14
- const formik = require("formik");
15
- const Yup = require("yup");
16
- const ImageStudioTabs = require("./ImageStudioTabs-DtusqpQO.js");
17
- function _interopNamespace(e) {
18
- if (e && e.__esModule) return e;
19
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
- if (e) {
21
- for (const k in e) {
22
- if (k !== "default") {
23
- const d = Object.getOwnPropertyDescriptor(e, k);
24
- Object.defineProperty(n, k, d.get ? d : {
25
- enumerable: true,
26
- get: () => e[k]
27
- });
28
- }
29
- }
30
- }
31
- n.default = e;
32
- return Object.freeze(n);
33
- }
34
- const Yup__namespace = /* @__PURE__ */ _interopNamespace(Yup);
35
- const useDialog = (id) => {
36
- const dispatch = reactRedux.useDispatch();
37
- const state = reactRedux.useSelector((state2) => state2.content_generator_commonDialog.open[id] ?? false);
38
- return {
39
- open: state,
40
- openDialog: () => dispatch(index.openDialog(id)),
41
- closeDialog: () => dispatch(index.closeDialog(id))
42
- };
43
- };
44
- const useArticles = () => {
45
- const { get } = admin.useFetchClient();
46
- const getArticles = react.useCallback(
47
- async (config) => {
48
- return get("/strapi-content-generator-gemini/posts", config);
49
- },
50
- [get]
51
- );
52
- return {
53
- getArticles
54
- };
55
- };
56
- const REQUEST_TIMEOUT = 12e4;
57
- const useGenerateContent = () => {
58
- const { post } = admin.useFetchClient();
59
- const generateContent = react.useCallback(
60
- async (data, config) => {
61
- const controller = new AbortController();
62
- const timeoutId = setTimeout(() => {
63
- controller.abort();
64
- }, REQUEST_TIMEOUT);
65
- try {
66
- return await post(
67
- "/strapi-content-generator-gemini/generate-article",
68
- data,
69
- {
70
- ...config,
71
- signal: controller.signal
72
- }
73
- );
74
- } finally {
75
- clearTimeout(timeoutId);
76
- }
77
- },
78
- [post]
79
- );
80
- const generateImage = react.useCallback(
81
- async (data, config) => {
82
- const controller = new AbortController();
83
- const timeoutId = setTimeout(() => {
84
- controller.abort();
85
- }, REQUEST_TIMEOUT);
86
- try {
87
- return await post(
88
- "/strapi-content-generator-gemini/generate-image",
89
- data,
90
- {
91
- ...config,
92
- signal: controller.signal
93
- }
94
- );
95
- } finally {
96
- clearTimeout(timeoutId);
97
- }
98
- },
99
- [post]
100
- );
101
- return {
102
- generateContent,
103
- generateImage
104
- };
105
- };
106
- const usePublishLinkedIn = () => {
107
- const { post } = admin.useFetchClient();
108
- const publishToLinkedIn = react.useCallback(
109
- async (data, config) => {
110
- return post("/strapi-content-generator-gemini/publish-linkedin", data, config);
111
- },
112
- [post]
113
- );
114
- return {
115
- publishToLinkedIn
116
- };
117
- };
118
- const usePublishFacebook = () => {
119
- const { post } = admin.useFetchClient();
120
- const publishToFacebook = react.useCallback(
121
- async (data, config) => {
122
- return post("/strapi-content-generator-gemini/publish-facebook", data, config);
123
- },
124
- [post]
125
- );
126
- return {
127
- publishToFacebook
128
- };
129
- };
130
- const PublishingTableComponent = ({
131
- posts,
132
- currentPost,
133
- loadingImage,
134
- loadingPublishLinkedIn,
135
- loadingPublishingToFacebook,
136
- onClickAction
137
- }) => {
138
- const rows = react.useMemo(() => {
139
- const opciones = {
140
- day: "2-digit",
141
- month: "long",
142
- year: "numeric"
143
- };
144
- return posts.map((post) => {
145
- const fecha = post.fecha_publicacion ? new Date(post.fecha_publicacion).toLocaleDateString("es-ES", opciones) : "No definida";
146
- return {
147
- id: post.documentId,
148
- fecha,
149
- titulo: post.titulo && post.titulo.length > 30 ? `${post.titulo.slice(0, 30)}…` : post.titulo,
150
- linkedInURL: post.linkedInPostId ? `https://www.linkedin.com/feed/update/${post.linkedInPostId}` : "",
151
- facebookURL: post.facebookPostId ? `https://www.facebook.com/${post.facebookPostId}` : "",
152
- hasImage: Boolean(post.image)
153
- };
154
- });
155
- }, [posts]);
156
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 7, rowCount: rows.length + 1, children: [
157
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
158
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Fecha de publicación" }) }),
159
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Blog Title" }) }),
160
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, alignItems: "center", justifyContent: "center", children: [
161
- /* @__PURE__ */ jsxRuntime.jsx("i", { className: "fa-brands fa-linkedin" }),
162
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "LinkedIn" })
163
- ] }) }),
164
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, alignItems: "center", justifyContent: "center", children: [
165
- /* @__PURE__ */ jsxRuntime.jsx("i", { className: "fa-brands fa-facebook" }),
166
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Facebook" })
167
- ] }) }),
168
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {}),
169
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {})
170
- ] }) }),
171
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: rows.map((row) => {
172
- const buttonLoadingImage = (loadingImage && currentPost.current) === row.id;
173
- const buttonLoadingPublishingLinkedIn = (loadingPublishLinkedIn && currentPost.current) === row.id;
174
- const buttonLoadingPublishingFacebook = (loadingPublishingToFacebook && currentPost.current) === row.id;
175
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
176
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: row.fecha }) }),
177
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: row.titulo }) }),
178
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: !row.linkedInURL ? /* @__PURE__ */ jsxRuntime.jsx(
179
- designSystem.Button,
180
- {
181
- disabled: row.linkedInURL,
182
- onClick: () => onClickAction(row.id, "publish-to-linked-in-dialog"),
183
- loading: buttonLoadingPublishingLinkedIn,
184
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Play, {}),
185
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: buttonLoadingPublishingLinkedIn ? "publicando" : "publicar" })
186
- }
187
- ) : /* @__PURE__ */ jsxRuntime.jsx(
188
- designSystem.LinkButton,
189
- {
190
- variant: "success-light",
191
- href: row.linkedInURL,
192
- isExternal: true,
193
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExternalLink, {}),
194
- children: "visitar"
195
- }
196
- ) }),
197
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: !row.facebookURL ? /* @__PURE__ */ jsxRuntime.jsx(
198
- designSystem.Button,
199
- {
200
- disabled: row.facebookURL,
201
- onClick: () => onClickAction(row.id, "publish-to-facebook-dialog"),
202
- loading: buttonLoadingPublishingFacebook,
203
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Play, {}),
204
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: buttonLoadingPublishingFacebook ? "publicando" : "publicar" })
205
- }
206
- ) : /* @__PURE__ */ jsxRuntime.jsx(
207
- designSystem.LinkButton,
208
- {
209
- variant: "success-light",
210
- href: row.facebookURL,
211
- isExternal: true,
212
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExternalLink, {}),
213
- children: "visitar"
214
- }
215
- ) }),
216
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
217
- designSystem.Button,
218
- {
219
- disabled: row.hasImage,
220
- onClick: () => onClickAction(row.id, "generate-image-dialog"),
221
- loading: buttonLoadingImage,
222
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Image, {}),
223
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: buttonLoadingImage ? "generando" : "generar" })
224
- }
225
- ) }),
226
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
227
- designSystem.LinkButton,
228
- {
229
- href: `/admin/content-manager/collection-types/api::articulo.articulo/${row.id}`,
230
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "ver" })
231
- }
232
- ) })
233
- ] }, row.id);
234
- }) })
235
- ] }) });
236
- };
237
- const PublishingTable = react.memo(PublishingTableComponent);
238
- const DialogCommon = ({
239
- id,
240
- title = "Confirmación",
241
- children,
242
- cancelText = "Cancelar",
243
- confirmText = "Confirmar",
244
- onCancelAction,
245
- onConfirmAction
246
- }) => {
247
- const { open } = useDialog(id);
248
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
249
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
250
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children }),
251
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
252
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "tertiary", onClick: onCancelAction, children: cancelText }) }),
253
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "danger", onClick: onConfirmAction, children: confirmText }) })
254
- ] })
255
- ] }) });
256
- };
257
- const GenerateImageDialog = ({ onCancelAction, onConfirmAction }) => {
258
- const [imageInstructions, setImageInstructions] = react.useState("");
259
- return /* @__PURE__ */ jsxRuntime.jsx(
260
- DialogCommon,
261
- {
262
- id: "generate-image-dialog",
263
- title: "Generar imágen con Gemini",
264
- cancelText: "Cancelar",
265
- confirmText: "Confirmar",
266
- onCancelAction,
267
- onConfirmAction: () => {
268
- onConfirmAction(imageInstructions);
269
- },
270
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 3, children: [
271
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", width: "100%", children: [
272
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: "¿Deseas generar la imágen para el artículo ahora?" }),
273
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "No te preocupes, también puedes hacerlo más adelante." })
274
- ] }) }),
275
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
276
- designSystem.Field.Root,
277
- {
278
- id: "image-instructions",
279
- width: "100%",
280
- children: [
281
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Instrucciones adicionales" }),
282
- /* @__PURE__ */ jsxRuntime.jsx(
283
- designSystem.Textarea,
284
- {
285
- name: "image-instructions",
286
- value: imageInstructions,
287
- placeholder: "Instrucciones adicionales para generar la imágen",
288
- onChange: (e) => {
289
- const { value } = e.target;
290
- setImageInstructions(value);
291
- },
292
- resizable: false,
293
- rows: 3
294
- }
295
- )
296
- ]
297
- }
298
- ) })
299
- ] })
300
- }
301
- );
302
- };
303
- const HomeContainer = () => {
304
- const [posts, setPosts] = react.useState([]);
305
- const [loadingImage, setIsLoadingImage] = react.useState(false);
306
- const [loadingPublishingToLinkedIn, setIsLoadingPublishingToLinkedIn] = react.useState(false);
307
- const [loadingPublishingToFacebook, setIsLoadingPublishingToFacebook] = react.useState(false);
308
- const currentPostRef = react.useRef("");
309
- const { formatMessage } = reactIntl.useIntl();
310
- const { openDialog: openImageGenerateDialog, closeDialog: closeImageGenerateDialog } = useDialog("generate-image-dialog");
311
- const { openDialog: openPublishToLinkedInDialog, closeDialog: closePublishToLinkedInDialog } = useDialog("publish-to-linked-in-dialog");
312
- const { openDialog: openPublishToFacebookDialog, closeDialog: closePublishToFacebookDialog } = useDialog("publish-to-facebook-dialog");
313
- const { getArticles } = useArticles();
314
- const { generateImage } = useGenerateContent();
315
- const { publishToLinkedIn } = usePublishLinkedIn();
316
- const { publishToFacebook } = usePublishFacebook();
317
- const { toggleNotification } = admin.useNotification();
318
- const fetchPosts = react.useCallback(async () => {
319
- let isMounted = true;
320
- try {
321
- const { data } = await getArticles({
322
- params: {
323
- populate: {
324
- image: { fields: ["url", "caption", "alternativeText"] },
325
- autor: { fields: ["nombre", "apellidos"] }
326
- },
327
- sort: ["createdAt:desc"]
328
- }
329
- });
330
- if (isMounted) {
331
- setPosts(data);
332
- }
333
- } catch (error) {
334
- console.error("Error fetching posts:", error);
335
- }
336
- return () => {
337
- isMounted = false;
338
- };
339
- }, [getArticles]);
340
- react.useEffect(() => {
341
- fetchPosts();
342
- }, [fetchPosts]);
343
- const onConfirmGenerateImage = react.useCallback(
344
- async (imageInstructions) => {
345
- closeImageGenerateDialog();
346
- setIsLoadingImage(true);
347
- try {
348
- await generateImage({
349
- articleId: currentPostRef.current,
350
- imageInstructions
351
- });
352
- fetchPosts();
353
- toggleNotification({
354
- type: "success",
355
- message: formatMessage({
356
- id: `${index.PLUGIN_ID}.config.load.error`,
357
- defaultMessage: "Imagen generada con éxito"
358
- })
359
- });
360
- } catch (err) {
361
- toggleNotification({
362
- type: "danger",
363
- message: formatMessage({
364
- id: `${index.PLUGIN_ID}.config.load.error`,
365
- defaultMessage: "Ocurrió un error al generar la imagen"
366
- })
367
- });
368
- } finally {
369
- setIsLoadingImage(false);
370
- }
371
- },
372
- [generateImage, closeImageGenerateDialog, setIsLoadingImage]
373
- );
374
- const onConfirmPublish = react.useCallback(
375
- async (type) => {
376
- const isLinkedIn = type === "linkedin";
377
- const isFacebook = type === "facebook";
378
- if (isLinkedIn) {
379
- closePublishToLinkedInDialog();
380
- setIsLoadingPublishingToLinkedIn(true);
381
- }
382
- if (isFacebook) {
383
- closePublishToFacebookDialog();
384
- setIsLoadingPublishingToFacebook(true);
385
- }
386
- try {
387
- switch (type) {
388
- case "linkedin":
389
- await publishToLinkedIn({ articleId: currentPostRef.current });
390
- break;
391
- case "facebook":
392
- await publishToFacebook({ articleId: currentPostRef.current });
393
- break;
394
- default:
395
- return;
396
- }
397
- fetchPosts();
398
- toggleNotification({
399
- type: "success",
400
- message: formatMessage({
401
- id: `${index.PLUGIN_ID}.config.publish.success.${type}`,
402
- defaultMessage: type === "linkedin" ? "Artículo publicado en LinkedIn con éxito" : "Artículo publicado en Facebook con éxito"
403
- })
404
- });
405
- } catch (err) {
406
- toggleNotification({
407
- type: "danger",
408
- message: formatMessage({
409
- id: `${index.PLUGIN_ID}.config.publish.error.${type}`,
410
- defaultMessage: type === "linkedin" ? "Ocurrió un error al publicar el artículo en LinkedIn" : "Ocurrió un error al publicar el artículo en Facebook"
411
- })
412
- });
413
- } finally {
414
- if (isLinkedIn) {
415
- setIsLoadingPublishingToLinkedIn(false);
416
- }
417
- if (isFacebook) {
418
- setIsLoadingPublishingToFacebook(false);
419
- }
420
- }
421
- },
422
- [
423
- publishToLinkedIn,
424
- publishToFacebook,
425
- closePublishToLinkedInDialog,
426
- closePublishToFacebookDialog,
427
- setIsLoadingPublishingToLinkedIn,
428
- setIsLoadingPublishingToFacebook,
429
- fetchPosts,
430
- toggleNotification,
431
- formatMessage
432
- ]
433
- );
434
- const onCancel = react.useCallback((dialogId) => {
435
- currentPostRef.current = "";
436
- switch (dialogId) {
437
- case "generate-image-dialog":
438
- closeImageGenerateDialog();
439
- break;
440
- case "publish-to-linked-in-dialog":
441
- closePublishToLinkedInDialog();
442
- break;
443
- case "publish-to-facebook-dialog":
444
- closePublishToFacebookDialog();
445
- break;
446
- default:
447
- return;
448
- }
449
- }, [closeImageGenerateDialog, closePublishToLinkedInDialog, closePublishToFacebookDialog]);
450
- const onClickAction = react.useCallback(
451
- (postId, dialogId) => {
452
- currentPostRef.current = postId;
453
- switch (dialogId) {
454
- case "generate-image-dialog":
455
- openImageGenerateDialog();
456
- break;
457
- case "publish-to-linked-in-dialog":
458
- openPublishToLinkedInDialog();
459
- break;
460
- case "publish-to-facebook-dialog":
461
- openPublishToFacebookDialog();
462
- break;
463
- }
464
- },
465
- [openImageGenerateDialog, openPublishToLinkedInDialog, openPublishToFacebookDialog]
466
- );
467
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
468
- /* @__PURE__ */ jsxRuntime.jsx(
469
- DialogCommon,
470
- {
471
- id: "publish-to-linked-in-dialog",
472
- title: "Publicar en LinkedIn",
473
- confirmText: "Publicar",
474
- onCancelAction: () => onCancel("publish-to-linked-in-dialog"),
475
- onConfirmAction: () => onConfirmPublish("linkedin"),
476
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", children: [
477
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: "¿Seguro que deseas publicar este artículo en LinkedIn?" }),
478
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "¡Esta acción es irreversible desde esta plataforma!" })
479
- ] })
480
- }
481
- ),
482
- /* @__PURE__ */ jsxRuntime.jsx(
483
- DialogCommon,
484
- {
485
- id: "publish-to-facebook-dialog",
486
- title: "Publicar en Facebook",
487
- confirmText: "Publicar",
488
- onCancelAction: () => onCancel("publish-to-facebook-dialog"),
489
- onConfirmAction: () => onConfirmPublish("facebook"),
490
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", children: [
491
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: "¿Seguro que deseas publicar este artículo en Facebook?" }),
492
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "¡Esta acción es irreversible desde esta plataforma!" })
493
- ] })
494
- }
495
- ),
496
- /* @__PURE__ */ jsxRuntime.jsx(GenerateImageDialog, { onConfirmAction: onConfirmGenerateImage, onCancelAction: () => onCancel("generate-image-dialog") }),
497
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
498
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
499
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: formatMessage({ id: getTranslation.getTranslation("plugin.name") }) }),
500
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
501
- ] }) }),
502
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "end", alignItems: "end", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.LinkButton, { href: "/admin/plugins/strapi-content-generator-gemini/generate-content", children: "Generar nuevo artículo" }) }) }),
503
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(
504
- PublishingTable,
505
- {
506
- posts,
507
- loadingImage,
508
- loadingPublishLinkedIn: loadingPublishingToLinkedIn,
509
- loadingPublishingToFacebook,
510
- currentPost: currentPostRef,
511
- onClickAction
512
- }
513
- ) })
514
- ] })
515
- ] });
516
- };
517
- const HomePage = () => {
518
- const { formatMessage } = reactIntl.useIntl();
519
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
520
- /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: formatMessage({ id: getTranslation.getTranslation("plugin.name") }) }),
521
- /* @__PURE__ */ jsxRuntime.jsx(HomeContainer, {})
522
- ] }) });
523
- };
524
- const useCategories = () => {
525
- const { get } = admin.useFetchClient();
526
- const getCategories = react.useCallback(
527
- async (config) => {
528
- return get("/strapi-content-generator-gemini/categories", config);
529
- },
530
- [get]
531
- );
532
- return {
533
- getCategories
534
- };
535
- };
536
- const useUsers = () => {
537
- const { get } = admin.useFetchClient();
538
- const getUsers = react.useCallback(
539
- async (config) => {
540
- return get("/strapi-content-generator-gemini/users", config);
541
- },
542
- [get]
543
- );
544
- return {
545
- getUsers
546
- };
547
- };
548
- const validationSchema$1 = Yup__namespace.object().shape({
549
- titulo: Yup__namespace.string().notRequired(),
550
- autor: Yup__namespace.string().required("Este campo es obligatorio"),
551
- categoria: Yup__namespace.string().required("Este campo es obligatorio"),
552
- temperatura: Yup__namespace.string().notRequired(),
553
- instrucciones: Yup__namespace.string().notRequired()
554
- });
555
- const initialValues$1 = {
556
- titulo: "",
557
- autor: "",
558
- categoria: "",
559
- temperatura: "0.5",
560
- instrucciones: ""
561
- };
562
- const Form$1 = ({ onSubmit, categorias, users }) => {
563
- const formik$1 = formik.useFormik({
564
- initialValues: initialValues$1,
565
- validationSchema: validationSchema$1,
566
- onSubmit
567
- });
568
- const { values, errors, touched, isValid, dirty, isSubmitting, handleChange, setFieldValue, handleSubmit } = formik$1;
569
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", padding: 6, margin: 6, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
570
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
571
- designSystem.Field.Root,
572
- {
573
- id: "titulo",
574
- error: touched.titulo && errors.titulo ? errors.titulo : void 0,
575
- hint: "Ej: Las 10 mejores tendencias en IA para 2026",
576
- width: "100%",
577
- children: [
578
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Título" }),
579
- /* @__PURE__ */ jsxRuntime.jsx(
580
- designSystem.TextInput,
581
- {
582
- name: "titulo",
583
- label: "Título",
584
- placeholder: "Título sugerido para el blog",
585
- onChange: handleChange,
586
- type: "text",
587
- value: values.titulo
588
- }
589
- ),
590
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
591
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
592
- ]
593
- }
594
- ) }),
595
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
596
- designSystem.Field.Root,
597
- {
598
- id: "categoria",
599
- error: touched.categoria && errors.categoria ? errors.categoria : void 0,
600
- hint: "Puedes agregar más desde el Content Type: Categorías",
601
- width: "100%",
602
- required: true,
603
- children: [
604
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Categoría" }),
605
- /* @__PURE__ */ jsxRuntime.jsx(
606
- designSystem.Combobox,
607
- {
608
- name: "categoria",
609
- placeholder: "Selecciona o escribe una categoría",
610
- value: values.categoria,
611
- onChange: (v) => setFieldValue("categoria", v),
612
- onCreateOption: (v) => {
613
- setFieldValue("categoria", v);
614
- },
615
- required: true,
616
- children: categorias.map((c) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: c.documentId, children: c.categoria }, c.documentId))
617
- }
618
- ),
619
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
620
- ]
621
- }
622
- ) }),
623
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
624
- designSystem.Field.Root,
625
- {
626
- id: "autor",
627
- error: touched.autor && errors.autor ? errors.autor : void 0,
628
- width: "100%",
629
- required: true,
630
- children: [
631
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Autor" }),
632
- /* @__PURE__ */ jsxRuntime.jsx(
633
- designSystem.Combobox,
634
- {
635
- name: "autor",
636
- placeholder: "Selecciona o escribe una categoría",
637
- value: values.autor,
638
- onChange: (v) => setFieldValue("autor", v),
639
- onCreateOption: (v) => {
640
- setFieldValue("autor", v);
641
- },
642
- required: true,
643
- children: users.map((c) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: c.documentId, children: c.nombre_completo }, c.documentId))
644
- }
645
- ),
646
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
647
- ]
648
- }
649
- ) }),
650
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
651
- designSystem.Field.Root,
652
- {
653
- id: "temperatura",
654
- error: touched.temperatura && errors.temperatura ? errors.temperatura : void 0,
655
- width: "100%",
656
- children: [
657
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Temperatura" }),
658
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", gap: 4, children: [
659
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
660
- "input",
661
- {
662
- name: "temperatura",
663
- value: values.temperatura,
664
- type: "range",
665
- min: "0",
666
- max: "2",
667
- step: "0.05",
668
- onChange: handleChange,
669
- style: { width: "100%" }
670
- }
671
- ) }),
672
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "100px", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Input, { value: values.temperatura, readOnly: true }) })
673
- ] }),
674
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
675
- ]
676
- }
677
- ) }),
678
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
679
- designSystem.Field.Root,
680
- {
681
- id: "instrucciones",
682
- error: touched.instrucciones && errors.instrucciones ? errors.instrucciones : void 0,
683
- width: "100%",
684
- children: [
685
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Instrucciones adicionales" }),
686
- /* @__PURE__ */ jsxRuntime.jsx(
687
- designSystem.Textarea,
688
- {
689
- name: "instrucciones",
690
- placeholder: "Escribe algunas instrucciones adicionales para el generador de contenido...",
691
- onChange: handleChange,
692
- value: values.instrucciones,
693
- resizable: false,
694
- rows: 10
695
- }
696
- )
697
- ]
698
- }
699
- ) }),
700
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { width: "100%", justifyContent: { initial: "end" }, alignItems: { initial: "end" }, children: /* @__PURE__ */ jsxRuntime.jsx(
701
- designSystem.Button,
702
- {
703
- disabled: !(isValid && dirty) || isSubmitting,
704
- loading: isSubmitting,
705
- type: "submit",
706
- children: "Generar contenido"
707
- }
708
- ) }) })
709
- ] }) }) });
710
- };
711
- const GenerateContentContainer = () => {
712
- const [documentId, setDocumentId] = react.useState("");
713
- const [categorias, setCategorias] = react.useState([]);
714
- const [users, setUsers] = react.useState([]);
715
- const { getCategories } = useCategories();
716
- const { getUsers } = useUsers();
717
- const navigate = reactRouterDom.useNavigate();
718
- const { closeDialog, openDialog } = useDialog("generate-image-dialog");
719
- const { generateContent, generateImage } = useGenerateContent();
720
- const { formatMessage } = reactIntl.useIntl();
721
- const { toggleNotification } = admin.useNotification();
722
- const onSubmit = react.useCallback(
723
- async (values, { setSubmitting }) => {
724
- try {
725
- const { data } = await generateContent(values);
726
- setDocumentId(data.documentId);
727
- openDialog();
728
- toggleNotification({
729
- type: "success",
730
- message: formatMessage({
731
- id: `${index.PLUGIN_ID}.config.load.error`,
732
- defaultMessage: "Artículo generado con éxito"
733
- })
734
- });
735
- } catch (error) {
736
- console.error("Error generating content:", error);
737
- toggleNotification({
738
- type: "danger",
739
- message: formatMessage({
740
- id: `${index.PLUGIN_ID}.config.load.error`,
741
- defaultMessage: "Ocurrió un error al generar el artículo"
742
- })
743
- });
744
- } finally {
745
- setSubmitting(false);
746
- }
747
- },
748
- [generateContent, openDialog]
749
- );
750
- const goToArticle = react.useCallback(() => {
751
- navigate(
752
- `/content-manager/collection-types/api::articulo.articulo/${documentId}`
753
- );
754
- }, [navigate, documentId]);
755
- const onConfirmGenerateImage = react.useCallback(
756
- async (imageInstructions) => {
757
- try {
758
- await generateImage({
759
- articleId: documentId,
760
- imageInstructions
761
- });
762
- goToArticle();
763
- } catch (err) {
764
- console.error("Error generating image:", err);
765
- } finally {
766
- closeDialog();
767
- }
768
- },
769
- [generateImage, documentId, closeDialog, goToArticle]
770
- );
771
- const onCancelGenerateImage = react.useCallback(() => {
772
- closeDialog();
773
- goToArticle();
774
- }, [closeDialog, goToArticle]);
775
- const fetchCategories = react.useCallback(async () => {
776
- let isMounted = true;
777
- try {
778
- const { data } = await getCategories();
779
- if (isMounted) {
780
- setCategorias(data);
781
- }
782
- } catch (error) {
783
- console.error("Error fetching posts:", error);
784
- }
785
- return () => {
786
- isMounted = false;
787
- };
788
- }, [getCategories]);
789
- const fetchUsers = react.useCallback(async () => {
790
- let isMounted = true;
791
- try {
792
- const { data } = await getUsers({
793
- params: {
794
- filters: {
795
- blocked: {
796
- $eq: false
797
- }
798
- }
799
- }
800
- });
801
- if (isMounted) {
802
- setUsers(data);
803
- }
804
- } catch (error) {
805
- console.error("Error fetching posts:", error);
806
- }
807
- return () => {
808
- isMounted = false;
809
- };
810
- }, [getUsers]);
811
- react.useEffect(() => {
812
- fetchCategories();
813
- fetchUsers();
814
- }, [fetchCategories]);
815
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
816
- /* @__PURE__ */ jsxRuntime.jsx(GenerateImageDialog, { onCancelAction: onCancelGenerateImage, onConfirmAction: onConfirmGenerateImage }),
817
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
818
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
819
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar nuevo artículo" }),
820
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
821
- ] }) }),
822
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { alignItems: "end", width: "100%", justifyContent: "end", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.LinkButton, { href: "/admin/plugins/strapi-content-generator-gemini", children: "Regresar" }) }) }),
823
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$1, { categorias, users, onSubmit }) })
824
- ] })
825
- ] });
826
- };
827
- const GenerateContent = () => {
828
- return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
829
- /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Generar nuevo artículo" }),
830
- /* @__PURE__ */ jsxRuntime.jsx(GenerateContentContainer, {})
831
- ] });
832
- };
833
- const sceneSchema = Yup__namespace.object().shape({
834
- prompt: Yup__namespace.string().trim().required("El prompt es obligatorio para esta escena"),
835
- durationSeconds: Yup__namespace.number().min(1, "La duración mínima es 1 segundo").max(90, "La duración máxima es 90 segundos").required("La duración es obligatoria"),
836
- referenceImages: Yup__namespace.array().of(
837
- Yup__namespace.object().shape({
838
- id: Yup__namespace.number().required(),
839
- file: Yup__namespace.mixed().optional(),
840
- previewUrl: Yup__namespace.string().optional()
841
- })
842
- ).max(3, "Se permiten máximo 3 imágenes de referencia por escena").optional()
843
- });
844
- const validationSchema = Yup__namespace.object().shape({
845
- aspectRatio: Yup__namespace.string().oneOf(["16:9", "9:16", "1:1"], "Aspect ratio no válido").required("El aspect ratio es obligatorio"),
846
- scenes: Yup__namespace.array().of(sceneSchema).min(1, "Debe haber al menos una escena").max(20, "No se permiten más de 20 escenas")
847
- });
848
- const initialValues = {
849
- aspectRatio: "16:9",
850
- scenes: [
851
- {
852
- prompt: ``,
853
- durationSeconds: 8,
854
- narrationText: ``,
855
- referenceImages: []
856
- }
857
- ]
858
- };
859
- const Form = ({ onSubmit }) => {
860
- const formik$1 = formik.useFormik({
861
- initialValues,
862
- validationSchema,
863
- validateOnMount: true,
864
- onSubmit
865
- });
866
- console.log("🚀 ~ Form ~ formik:", formik$1.errors);
867
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", padding: 6, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: formik$1.handleSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
868
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: "aspectRatio", width: "100%", required: true, children: [
869
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Relación de aspecto" }),
870
- /* @__PURE__ */ jsxRuntime.jsxs(
871
- designSystem.Combobox,
872
- {
873
- name: "aspectRatio",
874
- onChange: (value) => formik$1.setFieldValue("aspectRatio", value),
875
- onBlur: () => formik$1.setFieldTouched("aspectRatio", true),
876
- value: formik$1.values.aspectRatio,
877
- onClear: () => formik$1.setFieldValue("aspectRatio", ""),
878
- children: [
879
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "16:9", children: "16:9" }),
880
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "9:16", children: "9:16" }),
881
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: "1:1", children: "1:1" })
882
- ]
883
- }
884
- ),
885
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: formik$1.errors.aspectRatio })
886
- ] }) }),
887
- formik$1.values.scenes.map((scene, index2) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral100", padding: 4, hasRadius: true, width: "100%", children: [
888
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: [
889
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
890
- "Escena ",
891
- index2 + 1
892
- ] }),
893
- formik$1.values.scenes.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
894
- designSystem.Button,
895
- {
896
- variant: "danger-light",
897
- onClick: () => {
898
- const updatedScenes = [...formik$1.values.scenes];
899
- updatedScenes.splice(index2, 1);
900
- formik$1.setFieldValue("scenes", updatedScenes);
901
- },
902
- children: "Eliminar Escena"
903
- }
904
- )
905
- ] }),
906
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
907
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.prompt`, width: "100%", required: true, children: [
908
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Prompt de la escena" }),
909
- /* @__PURE__ */ jsxRuntime.jsx(
910
- designSystem.Textarea,
911
- {
912
- name: `scenes.${index2}.prompt`,
913
- placeholder: "Describe visualmente esta escena",
914
- onChange: formik$1.handleChange,
915
- onBlur: formik$1.handleBlur,
916
- value: formik$1.values.scenes[index2].prompt,
917
- rows: 6
918
- }
919
- )
920
- ] }),
921
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.durationSeconds`, width: "100%", required: true, children: [
922
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Duración (segundos)" }),
923
- /* @__PURE__ */ jsxRuntime.jsxs(
924
- designSystem.Combobox,
925
- {
926
- name: `scenes.${index2}.durationSeconds`,
927
- onChange: (value) => formik$1.setFieldValue(`scenes.${index2}.durationSeconds`, value),
928
- onBlur: formik$1.handleBlur,
929
- value: formik$1.values.scenes[index2].durationSeconds,
930
- onClear: () => formik$1.setFieldValue(`scenes.${index2}.durationSeconds`, ""),
931
- children: [
932
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 4, children: "4" }),
933
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 6, children: "6" }),
934
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: 8, children: "8" })
935
- ]
936
- }
937
- )
938
- ] }),
939
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { id: `scenes.${index2}.referenceImages`, width: "100%", children: [
940
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Imagen(es) de referencia" }),
941
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, width: "100%", children: [
942
- scene.referenceImages.map((image, imgIndex) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral200", padding: 2, hasRadius: true, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
943
- image.previewUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: image.previewUrl, alt: "preview", style: { width: 50, height: 50, objectFit: "cover" } }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: 50, height: 50, backgroundColor: "#ccc" } }),
944
- /* @__PURE__ */ jsxRuntime.jsx(
945
- designSystem.IconButton,
946
- {
947
- onClick: () => {
948
- const imageToRemove = scene.referenceImages[imgIndex];
949
- if (imageToRemove.previewUrl) {
950
- URL.revokeObjectURL(imageToRemove.previewUrl);
951
- }
952
- const updatedImages = [...scene.referenceImages];
953
- updatedImages.splice(imgIndex, 1);
954
- formik$1.setFieldValue(`scenes.${index2}.referenceImages`, updatedImages);
955
- },
956
- label: "Eliminar imagen",
957
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
958
- }
959
- )
960
- ] }) }, image.id)),
961
- /* @__PURE__ */ jsxRuntime.jsx(
962
- designSystem.Button,
963
- {
964
- type: "button",
965
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
966
- variant: "secondary",
967
- fullWidth: true,
968
- onClick: () => {
969
- const input = document.createElement("input");
970
- input.type = "file";
971
- input.accept = "image/*";
972
- input.onchange = (e) => {
973
- const selectedFile = e.target.files?.[0];
974
- if (!selectedFile) return;
975
- const newImage = {
976
- id: Date.now(),
977
- file: selectedFile,
978
- previewUrl: URL.createObjectURL(selectedFile)
979
- };
980
- const newImages = [...scene.referenceImages, newImage];
981
- formik$1.setFieldValue(`scenes.${index2}.referenceImages`, newImages.slice(0, 5));
982
- };
983
- input.click();
984
- },
985
- disabled: scene.referenceImages.length >= 5,
986
- children: "Añadir imagen de referencia"
987
- }
988
- )
989
- ] })
990
- ] })
991
- ] })
992
- ] }, index2) }, `scene-${index2}`)),
993
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
994
- designSystem.Button,
995
- {
996
- type: "button",
997
- startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusCircle, {}),
998
- variant: "secondary",
999
- onClick: () => {
1000
- formik$1.setFieldValue("scenes", [
1001
- ...formik$1.values.scenes,
1002
- { prompt: "", durationSeconds: 6, narrationText: "", referenceImages: [] }
1003
- ]);
1004
- },
1005
- fullWidth: true,
1006
- children: "Añadir Escena"
1007
- }
1008
- ) }),
1009
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { width: "100%", justifyContent: "end", alignItems: "end", children: /* @__PURE__ */ jsxRuntime.jsx(
1010
- designSystem.Button,
1011
- {
1012
- type: "submit",
1013
- fullWidth: true,
1014
- disabled: !(formik$1.isValid && formik$1.dirty) || formik$1.isSubmitting,
1015
- loading: formik$1.isSubmitting,
1016
- children: "Generar Video"
1017
- }
1018
- ) }) })
1019
- ] }) }) });
1020
- };
1021
- const useImages = () => {
1022
- const { post } = admin.useFetchClient();
1023
- const generateVideoWithScenes = react.useCallback(
1024
- async (data, config) => {
1025
- return await post("/strapi-content-generator-gemini/generate-video-with-scenes", data, config);
1026
- },
1027
- [post]
1028
- );
1029
- return {
1030
- generateVideoWithScenes
1031
- };
1032
- };
1033
- const GenerateVideoContainer = () => {
1034
- const { toggleNotification } = admin.useNotification();
1035
- const { generateVideoWithScenes } = useImages();
1036
- const { formatMessage } = reactIntl.useIntl();
1037
- const handleSubmit = async (values, { setSubmitting }) => {
1038
- try {
1039
- const formData = new FormData();
1040
- formData.append("aspectRatio", values.aspectRatio);
1041
- values.scenes.forEach((scene, index2) => {
1042
- formData.append(`scenes[${index2}][prompt]`, scene.prompt);
1043
- formData.append(`scenes[${index2}][durationSeconds]`, scene.durationSeconds.toString());
1044
- formData.append(`scenes[${index2}][narrationText]`, scene.narrationText || "");
1045
- scene.referenceImages.forEach((image, imgIndex) => {
1046
- if (image.file) {
1047
- formData.append(`scenes[${index2}][referenceImages][${imgIndex}]`, image.file);
1048
- }
1049
- });
1050
- });
1051
- const response = await generateVideoWithScenes(formData);
1052
- console.log("🚀 ~ handleSubmit ~ response:", response);
1053
- toggleNotification({
1054
- type: "success",
1055
- message: formatMessage({
1056
- id: `${index.PLUGIN_ID}.config.load.success`,
1057
- defaultMessage: "Video generado con éxito"
1058
- })
1059
- });
1060
- } catch (error) {
1061
- toggleNotification({
1062
- type: "danger",
1063
- message: formatMessage({
1064
- id: `${index.PLUGIN_ID}.config.load.error`,
1065
- defaultMessage: "Ocurrió un error al generar el video"
1066
- })
1067
- });
1068
- } finally {
1069
- setSubmitting(false);
1070
- }
1071
- };
1072
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1073
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
1074
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar video con IA" }),
1075
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
1076
- ] }) }) }),
1077
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
1078
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 2 }),
1079
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 8, children: /* @__PURE__ */ jsxRuntime.jsx(Form, { onSubmit: handleSubmit }) })
1080
- ] })
1081
- ] });
1082
- };
1083
- const GenerateVideo = () => {
1084
- return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
1085
- /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Generar video con IA" }),
1086
- /* @__PURE__ */ jsxRuntime.jsx(GenerateVideoContainer, {})
1087
- ] });
1088
- };
1089
- const App = () => {
1090
- const { allowedActions, isLoading } = admin.useRBAC(index.pluginPermissions);
1091
- if (isLoading) {
1092
- return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Loading, {});
1093
- }
1094
- return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Protect, { permissions: [...index.pluginPermissions.access], children: /* @__PURE__ */ jsxRuntime.jsx(PluginProviders.PluginProviders, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
1095
- allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }),
1096
- allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-content", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateContent, {}) }),
1097
- allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1098
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/image-studio", element: /* @__PURE__ */ jsxRuntime.jsx(ImageStudioTabs.StudioRedirect, {}) }),
1099
- ImageStudioTabs.LEGACY_ROUTES.map((r) => /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: r.path, element: ImageStudioTabs.legacyRedirect(r.tab) }, r.path)),
1100
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-video", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateVideo, {}) })
1101
- ] }),
1102
- /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "*", element: /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Error, {}) })
1103
- ] }) }) });
1104
- };
1105
- exports.App = App;