@interware/content-generator 0.1.1

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/_chunks/App-6ntGE8c-.js +702 -0
  4. package/dist/_chunks/App-CUBxywy1.mjs +684 -0
  5. package/dist/_chunks/Settings-CwPVYHgw.js +218 -0
  6. package/dist/_chunks/Settings-DTPXHARn.mjs +200 -0
  7. package/dist/_chunks/en-B4KWt_jN.js +4 -0
  8. package/dist/_chunks/en-Byx4XI2L.mjs +4 -0
  9. package/dist/_chunks/es-Cb6O-nM6.js +4 -0
  10. package/dist/_chunks/es-DlGQb34u.mjs +4 -0
  11. package/dist/_chunks/getTranslation-AfxwBFKN.js +4 -0
  12. package/dist/_chunks/getTranslation-Di36t3DD.mjs +5 -0
  13. package/dist/_chunks/index-CkkBgYlg.mjs +126 -0
  14. package/dist/_chunks/index-Dcpjhvs5.js +125 -0
  15. package/dist/admin/index.js +3 -0
  16. package/dist/admin/index.mjs +4 -0
  17. package/dist/admin/src/components/Initializer.d.ts +5 -0
  18. package/dist/admin/src/components/PluginIcon.d.ts +2 -0
  19. package/dist/admin/src/components/commons/dialog/index.d.ts +12 -0
  20. package/dist/admin/src/components/commons/generate-image-dialog/index.d.ts +5 -0
  21. package/dist/admin/src/components/generate-content/Form.d.ts +15 -0
  22. package/dist/admin/src/components/home/table.d.ts +12 -0
  23. package/dist/admin/src/components/index.d.ts +12 -0
  24. package/dist/admin/src/components/settings/Form.d.ts +8 -0
  25. package/dist/admin/src/containers/generate-content/index.d.ts +2 -0
  26. package/dist/admin/src/containers/home/index.d.ts +2 -0
  27. package/dist/admin/src/containers/settings/index.d.ts +7 -0
  28. package/dist/admin/src/hooks/useDialog.d.ts +11 -0
  29. package/dist/admin/src/index.d.ts +10 -0
  30. package/dist/admin/src/lib/use-cases/articles/index.d.ts +5 -0
  31. package/dist/admin/src/lib/use-cases/categories/index.d.ts +5 -0
  32. package/dist/admin/src/lib/use-cases/generate-content/index.d.ts +6 -0
  33. package/dist/admin/src/lib/use-cases/linkedin/index.d.ts +5 -0
  34. package/dist/admin/src/lib/use-cases/settings/index.d.ts +6 -0
  35. package/dist/admin/src/lib/use-cases/users/index.d.ts +5 -0
  36. package/dist/admin/src/pages/App.d.ts +2 -0
  37. package/dist/admin/src/pages/GenerateContent.d.ts +2 -0
  38. package/dist/admin/src/pages/HomePage.d.ts +2 -0
  39. package/dist/admin/src/pages/Settings.d.ts +2 -0
  40. package/dist/admin/src/permissions.d.ts +7 -0
  41. package/dist/admin/src/pluginId.d.ts +1 -0
  42. package/dist/admin/src/reducers/dialog/index.d.ts +6 -0
  43. package/dist/admin/src/types/reducers.d.ts +4 -0
  44. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  45. package/dist/server/index.js +3149 -0
  46. package/dist/server/index.mjs +3130 -0
  47. package/dist/server/src/bootstrap.d.ts +5 -0
  48. package/dist/server/src/config/index.d.ts +5 -0
  49. package/dist/server/src/content-types/index.d.ts +2 -0
  50. package/dist/server/src/controllers/config.d.ts +8 -0
  51. package/dist/server/src/controllers/controller.d.ts +15 -0
  52. package/dist/server/src/controllers/index.d.ts +22 -0
  53. package/dist/server/src/destroy.d.ts +5 -0
  54. package/dist/server/src/index.d.ts +148 -0
  55. package/dist/server/src/middlewares/index.d.ts +2 -0
  56. package/dist/server/src/policies/index.d.ts +2 -0
  57. package/dist/server/src/register.d.ts +5 -0
  58. package/dist/server/src/routes/admin.d.ts +10 -0
  59. package/dist/server/src/routes/content-api.d.ts +10 -0
  60. package/dist/server/src/routes/index.d.ts +27 -0
  61. package/dist/server/src/services/index.d.ts +83 -0
  62. package/dist/server/src/services/service.d.ts +86 -0
  63. package/package.json +98 -0
@@ -0,0 +1,702 @@
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 designSystem = require("@strapi/design-system");
6
+ const reactRouterDom = require("react-router-dom");
7
+ const reactIntl = require("react-intl");
8
+ const react = require("react");
9
+ const reactRedux = require("react-redux");
10
+ const index = require("./index-Dcpjhvs5.js");
11
+ const icons = require("@strapi/icons");
12
+ const getTranslation = require("./getTranslation-AfxwBFKN.js");
13
+ const formik = require("formik");
14
+ const Yup = require("yup");
15
+ function _interopNamespace(e) {
16
+ if (e && e.__esModule) return e;
17
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
18
+ if (e) {
19
+ for (const k in e) {
20
+ if (k !== "default") {
21
+ const d = Object.getOwnPropertyDescriptor(e, k);
22
+ Object.defineProperty(n, k, d.get ? d : {
23
+ enumerable: true,
24
+ get: () => e[k]
25
+ });
26
+ }
27
+ }
28
+ }
29
+ n.default = e;
30
+ return Object.freeze(n);
31
+ }
32
+ const Yup__namespace = /* @__PURE__ */ _interopNamespace(Yup);
33
+ const useDialog = (id) => {
34
+ const dispatch = reactRedux.useDispatch();
35
+ const state = reactRedux.useSelector((state2) => state2.content_generator_commonDialog.open[id] ?? false);
36
+ return {
37
+ open: state,
38
+ openDialog: () => dispatch(index.openDialog(id)),
39
+ closeDialog: () => dispatch(index.closeDialog(id))
40
+ };
41
+ };
42
+ const useArticles = () => {
43
+ const { get } = admin.useFetchClient();
44
+ const getArticles = react.useCallback(
45
+ async (config) => {
46
+ return get("/strapi-content-generator-gemini/posts", config);
47
+ },
48
+ [get]
49
+ );
50
+ return {
51
+ getArticles
52
+ };
53
+ };
54
+ const useGenerateContent = () => {
55
+ const { post } = admin.useFetchClient();
56
+ const generateContent = react.useCallback(
57
+ async (data, config) => {
58
+ return post("/strapi-content-generator-gemini/generate-article", data, config);
59
+ },
60
+ [post]
61
+ );
62
+ const generateImage = react.useCallback(
63
+ async (data, config) => {
64
+ return post("/strapi-content-generator-gemini/generate-image", data, config);
65
+ },
66
+ [post]
67
+ );
68
+ return {
69
+ generateContent,
70
+ generateImage
71
+ };
72
+ };
73
+ const usePublishLinkedIn = () => {
74
+ const { post } = admin.useFetchClient();
75
+ const publishToLinkedIn = react.useCallback(
76
+ async (data, config) => {
77
+ return post("/strapi-content-generator-gemini/publish-linkedin", data, config);
78
+ },
79
+ [post]
80
+ );
81
+ return {
82
+ publishToLinkedIn
83
+ };
84
+ };
85
+ const PublishingTableComponent = ({
86
+ posts,
87
+ currentPost,
88
+ loadingImage,
89
+ loadingPublishLinkedIn,
90
+ onClickAction
91
+ }) => {
92
+ const rows = react.useMemo(() => {
93
+ const opciones = {
94
+ day: "2-digit",
95
+ month: "long",
96
+ year: "numeric"
97
+ };
98
+ return posts.map((post) => {
99
+ const fecha = post.fecha_publicacion ? new Date(post.fecha_publicacion).toLocaleDateString("es-ES", opciones) : "No definida";
100
+ return {
101
+ id: post.documentId,
102
+ fecha,
103
+ titulo: post.titulo && post.titulo.length > 30 ? `${post.titulo.slice(0, 30)}…` : post.titulo,
104
+ autor: `${post.autor?.nombre ?? ""} ${post.autor?.apellidos ?? ""}`,
105
+ linkedInURL: post.linkedInPostId,
106
+ hasImage: Boolean(post.image)
107
+ };
108
+ });
109
+ }, [posts]);
110
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 7, rowCount: rows.length + 1, children: [
111
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
112
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Fecha de publicación" }) }),
113
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Blog Title" }) }),
114
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "Autor" }) }),
115
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, alignItems: "center", justifyContent: "center", children: [
116
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "fa-brands fa-linkedin" }),
117
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: "LinkedIn" })
118
+ ] }) }),
119
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {}),
120
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {})
121
+ ] }) }),
122
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: rows.map((row) => {
123
+ const buttonLoadingImage = loadingImage && currentPost.current === row.id;
124
+ const buttonLoadingPublishingLinkediN = loadingPublishLinkedIn && currentPost.current === row.id;
125
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
126
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: row.fecha }) }),
127
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: row.titulo }) }),
128
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: row.autor }) }),
129
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
130
+ designSystem.Button,
131
+ {
132
+ disabled: row.linkedInURL,
133
+ onClick: () => onClickAction(row.id, "publish-to-linked-in-dialog"),
134
+ loading: buttonLoadingPublishingLinkediN,
135
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Play, {}),
136
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: buttonLoadingImage ? "publicando" : "publicar" })
137
+ }
138
+ ) }),
139
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
140
+ designSystem.Button,
141
+ {
142
+ disabled: row.hasImage,
143
+ onClick: () => onClickAction(row.id, "generate-image-dialog"),
144
+ loading: buttonLoadingImage,
145
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Image, {}),
146
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: buttonLoadingImage ? "generando" : "generar" })
147
+ }
148
+ ) }),
149
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
150
+ designSystem.LinkButton,
151
+ {
152
+ href: `/admin/content-manager/collection-types/api::articulo.articulo/${row.id}`,
153
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "ver" })
154
+ }
155
+ ) })
156
+ ] }, row.id);
157
+ }) })
158
+ ] }) });
159
+ };
160
+ const PublishingTable = react.memo(PublishingTableComponent);
161
+ const DialogCommon = ({
162
+ id,
163
+ title = "Confirmación",
164
+ children,
165
+ cancelText = "Cancelar",
166
+ confirmText = "Confirmar",
167
+ onCancelAction,
168
+ onConfirmAction
169
+ }) => {
170
+ const { open } = useDialog(id);
171
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
173
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children }),
174
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
175
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "tertiary", onClick: onCancelAction, children: cancelText }) }),
176
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "danger", onClick: onConfirmAction, children: confirmText }) })
177
+ ] })
178
+ ] }) });
179
+ };
180
+ const GenerateImageDialog = ({ onCancelAction, onConfirmAction }) => {
181
+ const [imageInstructions, setImageInstructions] = react.useState("");
182
+ return /* @__PURE__ */ jsxRuntime.jsx(
183
+ DialogCommon,
184
+ {
185
+ id: "generate-image-dialog",
186
+ title: "Generar imágen con Gemini",
187
+ cancelText: "Cancelar",
188
+ confirmText: "Confirmar",
189
+ onCancelAction,
190
+ onConfirmAction: () => {
191
+ onConfirmAction(imageInstructions);
192
+ },
193
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 3, children: [
194
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", justifyContent: "center", width: "100%", children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: "¿Deseas generar la imágen para el artículo ahora?" }),
196
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "No te preocupes, también puedes hacerlo más adelante." })
197
+ ] }) }),
198
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { m: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
199
+ designSystem.Field.Root,
200
+ {
201
+ id: "image-instructions",
202
+ width: "100%",
203
+ children: [
204
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Instrucciones adicionales" }),
205
+ /* @__PURE__ */ jsxRuntime.jsx(
206
+ designSystem.Textarea,
207
+ {
208
+ name: "image-instructions",
209
+ value: imageInstructions,
210
+ placeholder: "Instrucciones adicionales para generar la imágen",
211
+ onChange: (e) => {
212
+ const { value } = e.target;
213
+ setImageInstructions(value);
214
+ },
215
+ resizable: false,
216
+ rows: 3
217
+ }
218
+ )
219
+ ]
220
+ }
221
+ ) })
222
+ ] })
223
+ }
224
+ );
225
+ };
226
+ const HomeContainer = () => {
227
+ const [posts, setPosts] = react.useState([]);
228
+ const [loadingImage, setIsLoadingImage] = react.useState(false);
229
+ const [loadingPublishingToLinkedIn, setIsLoadingPublishingToLinkedIn] = react.useState(false);
230
+ const currentPostRef = react.useRef("");
231
+ const { formatMessage } = reactIntl.useIntl();
232
+ const { openDialog: openImageGenerateDialog, closeDialog: closeImageGenerateDialog } = useDialog("generate-image-dialog");
233
+ const { openDialog: openPublishToLinkedInDialog, closeDialog: closePublishToLinkedInDialog } = useDialog("publish-to-linked-in-dialog");
234
+ const { getArticles } = useArticles();
235
+ const { generateImage } = useGenerateContent();
236
+ const { publishToLinkedIn } = usePublishLinkedIn();
237
+ const { toggleNotification } = admin.useNotification();
238
+ const fetchPosts = react.useCallback(async () => {
239
+ let isMounted = true;
240
+ try {
241
+ const { data } = await getArticles({
242
+ params: {
243
+ populate: {
244
+ image: { fields: ["url", "caption", "alternativeText"] },
245
+ autor: { fields: ["nombre", "apellidos"] }
246
+ },
247
+ sort: ["createdAt:desc"]
248
+ }
249
+ });
250
+ if (isMounted) {
251
+ setPosts(data);
252
+ }
253
+ } catch (error) {
254
+ console.error("Error fetching posts:", error);
255
+ }
256
+ return () => {
257
+ isMounted = false;
258
+ };
259
+ }, [getArticles]);
260
+ react.useEffect(() => {
261
+ fetchPosts();
262
+ }, [fetchPosts]);
263
+ const onConfirmGenerateImage = react.useCallback(
264
+ async (imageInstructions) => {
265
+ closeImageGenerateDialog();
266
+ setIsLoadingImage(true);
267
+ try {
268
+ await generateImage({
269
+ articleId: currentPostRef.current,
270
+ imageInstructions
271
+ });
272
+ fetchPosts();
273
+ toggleNotification({
274
+ type: "success",
275
+ message: formatMessage({
276
+ id: `${index.PLUGIN_ID}.config.load.error`,
277
+ defaultMessage: "Imagen generada con éxito"
278
+ })
279
+ });
280
+ } catch (err) {
281
+ toggleNotification({
282
+ type: "danger",
283
+ message: formatMessage({
284
+ id: `${index.PLUGIN_ID}.config.load.error`,
285
+ defaultMessage: "Ocurrió un error al generar la imagen"
286
+ })
287
+ });
288
+ } finally {
289
+ setIsLoadingImage(false);
290
+ }
291
+ },
292
+ [generateImage, closeImageGenerateDialog, setIsLoadingImage]
293
+ );
294
+ const onConfirmPublishToLinedIn = react.useCallback(
295
+ async () => {
296
+ closePublishToLinkedInDialog();
297
+ setIsLoadingPublishingToLinkedIn(true);
298
+ try {
299
+ await publishToLinkedIn({ articleId: currentPostRef.current });
300
+ fetchPosts();
301
+ toggleNotification({
302
+ type: "success",
303
+ message: formatMessage({
304
+ id: `${index.PLUGIN_ID}.config.load.error`,
305
+ defaultMessage: "Artículo publicado en LinkedIn con éxito"
306
+ })
307
+ });
308
+ } catch (err) {
309
+ toggleNotification({
310
+ type: "danger",
311
+ message: formatMessage({
312
+ id: `${index.PLUGIN_ID}.config.load.error`,
313
+ defaultMessage: "Ocurrió un error al publicar el artículo en LinkedIn"
314
+ })
315
+ });
316
+ } finally {
317
+ setIsLoadingPublishingToLinkedIn(false);
318
+ }
319
+ },
320
+ [publishToLinkedIn, closeImageGenerateDialog, setIsLoadingPublishingToLinkedIn]
321
+ );
322
+ const onCancel = react.useCallback((dialogId) => {
323
+ currentPostRef.current = "";
324
+ switch (dialogId) {
325
+ case "generate-image-dialog":
326
+ closeImageGenerateDialog();
327
+ case "publish-to-linked-in-dialog":
328
+ closePublishToLinkedInDialog();
329
+ default:
330
+ return;
331
+ }
332
+ }, [closeImageGenerateDialog, closePublishToLinkedInDialog]);
333
+ const onClickAction = react.useCallback(
334
+ (postId, dialogId) => {
335
+ currentPostRef.current = postId;
336
+ switch (dialogId) {
337
+ case "generate-image-dialog":
338
+ openImageGenerateDialog();
339
+ case "publish-to-linked-in-dialog":
340
+ openPublishToLinkedInDialog();
341
+ }
342
+ },
343
+ [openImageGenerateDialog, openPublishToLinkedInDialog]
344
+ );
345
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
346
+ /* @__PURE__ */ jsxRuntime.jsx(
347
+ DialogCommon,
348
+ {
349
+ id: "publish-to-linked-in-dialog",
350
+ title: "Publicar en LinkedIn",
351
+ confirmText: "Publicar",
352
+ onCancelAction: () => onCancel("publish-to-linked-in-dialog"),
353
+ onConfirmAction: onConfirmPublishToLinedIn,
354
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", children: [
355
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: "¿Seguro que deseas publicar este artículo en LinkedIn?" }),
356
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "¡Esta acción es irreversible desde esta plataforma!" })
357
+ ] })
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsxRuntime.jsx(GenerateImageDialog, { onConfirmAction: onConfirmGenerateImage, onCancelAction: () => onCancel("generate-image-dialog") }),
361
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
362
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
363
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: formatMessage({ id: getTranslation.getTranslation("plugin.name") }) }),
364
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
365
+ ] }) }),
366
+ /* @__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" }) }) }),
367
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(
368
+ PublishingTable,
369
+ {
370
+ posts,
371
+ loadingImage,
372
+ loadingPublishLinkedIn: loadingPublishingToLinkedIn,
373
+ currentPost: currentPostRef,
374
+ onClickAction
375
+ }
376
+ ) })
377
+ ] })
378
+ ] });
379
+ };
380
+ const HomePage = () => {
381
+ const { formatMessage } = reactIntl.useIntl();
382
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
383
+ /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: formatMessage({ id: getTranslation.getTranslation("plugin.name") }) }),
384
+ /* @__PURE__ */ jsxRuntime.jsx(HomeContainer, {})
385
+ ] }) });
386
+ };
387
+ const useCategories = () => {
388
+ const { get } = admin.useFetchClient();
389
+ const getCategories = react.useCallback(
390
+ async (config) => {
391
+ return get("/strapi-content-generator-gemini/categories", config);
392
+ },
393
+ [get]
394
+ );
395
+ return {
396
+ getCategories
397
+ };
398
+ };
399
+ const useUsers = () => {
400
+ const { get } = admin.useFetchClient();
401
+ const getUsers = react.useCallback(
402
+ async (config) => {
403
+ return get("/strapi-content-generator-gemini/users", config);
404
+ },
405
+ [get]
406
+ );
407
+ return {
408
+ getUsers
409
+ };
410
+ };
411
+ const validationSchema = Yup__namespace.object().shape({
412
+ titulo: Yup__namespace.string().notRequired(),
413
+ autor: Yup__namespace.string().required("Este campo es obligatorio"),
414
+ categoria: Yup__namespace.string().required("Este campo es obligatorio"),
415
+ keywords: Yup__namespace.string().notRequired(),
416
+ instrucciones: Yup__namespace.string().notRequired()
417
+ });
418
+ const initialValues = {
419
+ titulo: "",
420
+ autor: "",
421
+ categoria: "",
422
+ keywords: "",
423
+ instrucciones: ""
424
+ };
425
+ const Form = ({ onSubmit, categorias, users }) => {
426
+ const formik$1 = formik.useFormik({
427
+ initialValues,
428
+ validationSchema,
429
+ onSubmit
430
+ });
431
+ const { values, errors, touched, isValid, dirty, isSubmitting, handleChange, setFieldValue, handleSubmit } = formik$1;
432
+ 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: [
433
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
434
+ designSystem.Field.Root,
435
+ {
436
+ id: "titulo",
437
+ error: touched.titulo && errors.titulo ? errors.titulo : void 0,
438
+ hint: "Ej: Las 10 mejores tendencias en IA para 2026",
439
+ width: "100%",
440
+ children: [
441
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Título" }),
442
+ /* @__PURE__ */ jsxRuntime.jsx(
443
+ designSystem.TextInput,
444
+ {
445
+ name: "titulo",
446
+ label: "Título",
447
+ placeholder: "Título sugerido para el blog",
448
+ onChange: handleChange,
449
+ type: "text",
450
+ value: values.titulo
451
+ }
452
+ ),
453
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}),
454
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
455
+ ]
456
+ }
457
+ ) }),
458
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
459
+ designSystem.Field.Root,
460
+ {
461
+ id: "categoria",
462
+ error: touched.categoria && errors.categoria ? errors.categoria : void 0,
463
+ hint: "Puedes agregar más desde el Content Type: Categorías",
464
+ width: "100%",
465
+ required: true,
466
+ children: [
467
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Categoría" }),
468
+ /* @__PURE__ */ jsxRuntime.jsx(
469
+ designSystem.Combobox,
470
+ {
471
+ name: "categoria",
472
+ placeholder: "Selecciona o escribe una categoría",
473
+ value: values.categoria,
474
+ onChange: (v) => setFieldValue("categoria", v),
475
+ onCreateOption: (v) => {
476
+ setFieldValue("categoria", v);
477
+ },
478
+ required: true,
479
+ children: categorias.map((c) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: c.documentId, children: c.categoria }, c.documentId))
480
+ }
481
+ ),
482
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
483
+ ]
484
+ }
485
+ ) }),
486
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { xs: 12, s: 12, m: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
487
+ designSystem.Field.Root,
488
+ {
489
+ id: "autor",
490
+ error: touched.autor && errors.autor ? errors.autor : void 0,
491
+ width: "100%",
492
+ required: true,
493
+ children: [
494
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Autor" }),
495
+ /* @__PURE__ */ jsxRuntime.jsx(
496
+ designSystem.Combobox,
497
+ {
498
+ name: "autor",
499
+ placeholder: "Selecciona o escribe una categoría",
500
+ value: values.autor,
501
+ onChange: (v) => setFieldValue("autor", v),
502
+ onCreateOption: (v) => {
503
+ setFieldValue("autor", v);
504
+ },
505
+ required: true,
506
+ children: users.map((c) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.ComboboxOption, { value: c.documentId, children: c.nombre_completo }, c.documentId))
507
+ }
508
+ ),
509
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
510
+ ]
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
514
+ designSystem.Field.Root,
515
+ {
516
+ id: "keywords",
517
+ error: touched.keywords && errors.keywords ? errors.keywords : void 0,
518
+ width: "100%",
519
+ hint: "Ej: Innovación, Desarrollo, AI",
520
+ children: [
521
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Palabras clave" }),
522
+ /* @__PURE__ */ jsxRuntime.jsx(
523
+ designSystem.TextInput,
524
+ {
525
+ name: "keywords",
526
+ id: "keywords",
527
+ placeholder: "Palabras clave separadas por comas",
528
+ onChange: handleChange,
529
+ value: values.keywords
530
+ }
531
+ ),
532
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
533
+ ]
534
+ }
535
+ ) }),
536
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
537
+ designSystem.Field.Root,
538
+ {
539
+ id: "instrucciones",
540
+ error: touched.instrucciones && errors.instrucciones ? errors.instrucciones : void 0,
541
+ width: "100%",
542
+ children: [
543
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Instrucciones adicionales" }),
544
+ /* @__PURE__ */ jsxRuntime.jsx(
545
+ designSystem.Textarea,
546
+ {
547
+ name: "instrucciones",
548
+ placeholder: "Escribe algunas instrucciones adicionales para el generador de contenido...",
549
+ onChange: handleChange,
550
+ value: values.instrucciones,
551
+ rows: 8
552
+ }
553
+ )
554
+ ]
555
+ }
556
+ ) }),
557
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { width: "100%", justifyContent: { initial: "end" }, alignItems: { initial: "end" }, children: /* @__PURE__ */ jsxRuntime.jsx(
558
+ designSystem.Button,
559
+ {
560
+ disabled: !(isValid && dirty) || isSubmitting,
561
+ loading: isSubmitting,
562
+ type: "submit",
563
+ children: "Generar contenido"
564
+ }
565
+ ) }) })
566
+ ] }) }) });
567
+ };
568
+ const GenerateContentContainer = () => {
569
+ const [documentId, setDocumentId] = react.useState("");
570
+ const [categorias, setCategorias] = react.useState([]);
571
+ const [users, setUsers] = react.useState([]);
572
+ const { getCategories } = useCategories();
573
+ const { getUsers } = useUsers();
574
+ const navigate = reactRouterDom.useNavigate();
575
+ const { closeDialog, openDialog } = useDialog("generate-image-dialog");
576
+ const { generateContent, generateImage } = useGenerateContent();
577
+ const { formatMessage } = reactIntl.useIntl();
578
+ const { toggleNotification } = admin.useNotification();
579
+ const onSubmit = react.useCallback(
580
+ async (values, { setSubmitting }) => {
581
+ try {
582
+ const { data } = await generateContent(values);
583
+ setDocumentId(data.documentId);
584
+ openDialog();
585
+ toggleNotification({
586
+ type: "success",
587
+ message: formatMessage({
588
+ id: `${index.PLUGIN_ID}.config.load.error`,
589
+ defaultMessage: "Artículo generado con éxito"
590
+ })
591
+ });
592
+ } catch (error) {
593
+ console.error("Error generating content:", error);
594
+ toggleNotification({
595
+ type: "danger",
596
+ message: formatMessage({
597
+ id: `${index.PLUGIN_ID}.config.load.error`,
598
+ defaultMessage: "Ocurrió un error al generar el artículo"
599
+ })
600
+ });
601
+ } finally {
602
+ setSubmitting(false);
603
+ }
604
+ },
605
+ [generateContent, openDialog]
606
+ );
607
+ const goToArticle = react.useCallback(() => {
608
+ navigate(
609
+ `/content-manager/collection-types/api::articulo.articulo/${documentId}`
610
+ );
611
+ }, [navigate, documentId]);
612
+ const onConfirmGenerateImage = react.useCallback(
613
+ async (imageInstructions) => {
614
+ try {
615
+ await generateImage({
616
+ articleId: documentId,
617
+ imageInstructions
618
+ });
619
+ goToArticle();
620
+ } catch (err) {
621
+ console.error("Error generating image:", err);
622
+ } finally {
623
+ closeDialog();
624
+ }
625
+ },
626
+ [generateImage, documentId, closeDialog, goToArticle]
627
+ );
628
+ const onCancelGenerateImage = react.useCallback(() => {
629
+ closeDialog();
630
+ goToArticle();
631
+ }, [closeDialog, goToArticle]);
632
+ const fetchCategories = react.useCallback(async () => {
633
+ let isMounted = true;
634
+ try {
635
+ const { data } = await getCategories();
636
+ if (isMounted) {
637
+ setCategorias(data);
638
+ }
639
+ } catch (error) {
640
+ console.error("Error fetching posts:", error);
641
+ }
642
+ return () => {
643
+ isMounted = false;
644
+ };
645
+ }, [getCategories]);
646
+ const fetchUsers = react.useCallback(async () => {
647
+ let isMounted = true;
648
+ try {
649
+ const { data } = await getUsers({
650
+ params: {
651
+ filters: {
652
+ blocked: {
653
+ $eq: false
654
+ }
655
+ }
656
+ }
657
+ });
658
+ console.log("🚀 ~ GenerateContentContainer ~ data:", data.length);
659
+ if (isMounted) {
660
+ setUsers(data);
661
+ }
662
+ } catch (error) {
663
+ console.error("Error fetching posts:", error);
664
+ }
665
+ return () => {
666
+ isMounted = false;
667
+ };
668
+ }, [getUsers]);
669
+ react.useEffect(() => {
670
+ fetchCategories();
671
+ fetchUsers();
672
+ }, [fetchCategories]);
673
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
674
+ /* @__PURE__ */ jsxRuntime.jsx(GenerateImageDialog, { onCancelAction: onCancelGenerateImage, onConfirmAction: onConfirmGenerateImage }),
675
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { padding: 6, children: [
676
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "start", children: [
677
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", children: "Generar nuevo artículo" }),
678
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: "Para uso exclusivo de InterWare de México" })
679
+ ] }) }),
680
+ /* @__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" }) }) }),
681
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form, { categorias, users, onSubmit }) })
682
+ ] })
683
+ ] });
684
+ };
685
+ const GenerateContent = () => {
686
+ return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
687
+ /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Generar nuevo artículo" }),
688
+ /* @__PURE__ */ jsxRuntime.jsx(GenerateContentContainer, {})
689
+ ] });
690
+ };
691
+ const App = () => {
692
+ const { allowedActions, isLoading } = admin.useRBAC(index.pluginPermissions);
693
+ if (isLoading) {
694
+ return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Loading, {});
695
+ }
696
+ return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Protect, { permissions: [...index.pluginPermissions.access], children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.DesignSystemProvider, { locale: "es-MX", children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
697
+ allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }),
698
+ allowedActions.canAccess && /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/generate-content", element: /* @__PURE__ */ jsxRuntime.jsx(GenerateContent, {}) }),
699
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "*", element: /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Error, {}) })
700
+ ] }) }) });
701
+ };
702
+ exports.App = App;