@vonaffenfels/contentful-teasermanager 1.2.2 → 1.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vonaffenfels/contentful-teasermanager",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "prepublish": "yarn run build",
@@ -66,6 +66,7 @@
66
66
  "@contentful/forma-36-tokens": "^0.10.1",
67
67
  "@dnd-kit/core": "^6.3.1",
68
68
  "@svgr/webpack": "^5.5.0",
69
+ "@tanstack/react-query": "^4",
69
70
  "babel-loader": "^8.2.2",
70
71
  "classnames": "^2.3.2",
71
72
  "clean-webpack-plugin": "^3.0.0",
@@ -101,7 +102,7 @@
101
102
  "contentful-resolve-response": "^1.9.2",
102
103
  "webpack": "5.88.2"
103
104
  },
104
- "gitHead": "1e99cab528da01b06334b55df31f21305222e6b8",
105
+ "gitHead": "885a22341d4310a5254b3c776fe5c5c32b76c7f2",
105
106
  "publishConfig": {
106
107
  "access": "public"
107
108
  }
@@ -18,7 +18,8 @@ import useDebounce from "../../../hooks/useDebounce";
18
18
  import {getContentfulClient} from "../../../lib/contentfulClient";
19
19
  import {PlusIcon} from "@contentful/f36-icons";
20
20
  import {CSS} from "@dnd-kit/utilities";
21
-
21
+ import {queryFromLogic} from "../../../queryFromLogic";
22
+ import {useQuery} from "@tanstack/react-query";
22
23
  export const LogicEditor = (props) => {
23
24
  const [selectedTags, setSelectedTags] = useState([]);
24
25
 
@@ -65,6 +66,43 @@ const LogicEditorInner = ({
65
66
  const [addTimepoint, setAddTimepoint] = useState(7);
66
67
  const debouncedSearch = useDebounce(searchQuery, 500);
67
68
  const [selectedTimepoints, setSelectedTimepoints] = useState([]);
69
+ const {
70
+ portal,
71
+ locale = "de",
72
+ } = sdk.parameters.invocation;
73
+
74
+ const {data: articles} = useQuery({
75
+ enabled: !!selectedTags.length && !!portal && !!contentfulClient,
76
+ queryKey: ["articles", selectedTags, portal],
77
+ queryFn: async () => {
78
+ const query = queryFromLogic({
79
+ tags: selectedTags,
80
+ portal,
81
+ });
82
+
83
+ try {
84
+ const result = await contentfulClient.getEntries({
85
+ content_type: "article",
86
+ locale: "de",
87
+ order: "-fields.date",
88
+ limit: 10,
89
+ ...query,
90
+ select: [
91
+ "fields.title",
92
+ "fields.slug",
93
+ "fields.date",
94
+ "sys.id",
95
+ ].join(","),
96
+ });
97
+
98
+ return result;
99
+ } catch (e) {
100
+ console.error(e);
101
+ return {items: []};
102
+ }
103
+ },
104
+ });
105
+
68
106
  useEffect(() => {
69
107
  if (logicData?.timepoints) {
70
108
  setSelectedTimepoints(logicData?.timepoints);
@@ -83,11 +121,6 @@ const LogicEditorInner = ({
83
121
  node: andNode,
84
122
  } = useDroppable({id: "and"});
85
123
 
86
- const {
87
- portal,
88
- locale = "de",
89
- } = sdk.parameters.invocation;
90
-
91
124
  useEffect(() => {
92
125
  setLoading(true);
93
126
  const params = {
@@ -125,7 +158,7 @@ const LogicEditorInner = ({
125
158
  return [];
126
159
  }
127
160
 
128
- const references = await sdk.cma.entry.references({entryId: response.items[0].sys.id}, {include: 7});
161
+ const references = await sdk.cma.entry.references({entryId: response.items[0].sys.id}, {include: 10});
129
162
  const resolved = contentfulResolveResponse(references);
130
163
  const allCategories = {};
131
164
 
@@ -141,7 +174,7 @@ const LogicEditorInner = ({
141
174
  }
142
175
  }
143
176
 
144
- return Object.values(allCategories);
177
+ return Object.values(allCategories).filter((c) => c.tags.length > 0);
145
178
  }),
146
179
  ]).then(([tags, categories]) => {
147
180
  setLoading(false);
@@ -196,8 +229,8 @@ const LogicEditorInner = ({
196
229
  </div>
197
230
  <div className="flex w-full flex-row items-center gap-2" style={{minHeight: 36}}>
198
231
  <SectionHeading style={{marginBottom: 0}}>Gewählte Kategorien & Tags:</SectionHeading>
199
- <div className="grid grid-cols-2 gap-4">
200
- <div className="flex flex-col gap-2">
232
+ <div className="grid w-full grid-cols-4 gap-4">
233
+ <div className="flex w-full flex-col gap-2">
201
234
  <div>
202
235
  <SectionHeading style={{marginBottom: 0}}>Oder</SectionHeading>
203
236
  </div>
@@ -222,7 +255,7 @@ const LogicEditorInner = ({
222
255
  })}
223
256
  </div>
224
257
  </div>
225
- <div className="flex flex-col gap-2">
258
+ <div className="flex w-full flex-col gap-2">
226
259
  <SectionHeading style={{marginBottom: 0}}>Und</SectionHeading>
227
260
  <div
228
261
  ref={setAndNodeRef}
@@ -246,6 +279,39 @@ const LogicEditorInner = ({
246
279
  })}
247
280
  </div>
248
281
  </div>
282
+ <div className="col-span-2 flex w-full flex-col gap-4">
283
+ <div>
284
+ <SectionHeading style={{marginBottom: 0}}>Artikel</SectionHeading>
285
+ </div>
286
+ <div className="flex flex-col gap-4">
287
+ <table className="w-full max-w-full table-auto gap-4 text-left">
288
+ <thead>
289
+ <tr>
290
+ <th>Datum</th>
291
+ <th className="pl-4">Titel</th>
292
+ </tr>
293
+ </thead>
294
+ <tbody>
295
+ {articles?.items?.map((article) => {
296
+ return <tr key={article.sys.id}>
297
+ <td className="whitespace-nowrap">
298
+ {new Date(article.fields.date.de).toLocaleString("de-DE", {
299
+ hour: "2-digit",
300
+ minute: "2-digit",
301
+ day: "2-digit",
302
+ month: "2-digit",
303
+ year: "numeric",
304
+ })}
305
+ </td>
306
+ <td className="truncate whitespace-nowrap pl-4">
307
+ {article.fields.title.de}
308
+ </td>
309
+ </tr>;
310
+ })}
311
+ </tbody>
312
+ </table>
313
+ </div>
314
+ </div>
249
315
  </div>
250
316
  </div>
251
317
  <div className="flex w-full flex-row gap-2">
@@ -266,16 +332,11 @@ const LogicEditorInner = ({
266
332
  return (
267
333
  <Checkbox
268
334
  key={category.id}
269
- isChecked={selectedTags.some((t) => category.tags.some((c) => c.id === t.id) || t.id === category.id)}
335
+ isChecked={selectedTags.some((t) => category.tags.some((c) => c.id === t.id))}
270
336
  onChange={(e) => {
271
337
  let newTags = [...selectedTags];
272
338
 
273
339
  if (e.target.checked) {
274
- newTags.push({
275
- label: category.title,
276
- id: category.id,
277
- type: "or",
278
- });
279
340
  for (const tag of category.tags) {
280
341
  if (!selectedTags.find((t) => t.id === tag.id)) {
281
342
  newTags.push({
@@ -286,8 +347,6 @@ const LogicEditorInner = ({
286
347
  }
287
348
  }
288
349
  } else {
289
- newTags = newTags.filter((t) => t.id !== category.id);
290
-
291
350
  for (const tag of category.tags) {
292
351
  newTags = newTags.filter((t) => t.id !== tag.id);
293
352
  }
@@ -297,7 +356,7 @@ const LogicEditorInner = ({
297
356
  }}
298
357
  >
299
358
  {category.title} ({selectedTags.filter((t) =>
300
- category.tags.some((c) => c.id === t.id) || t.id === category.id).length}/{category.tags.length + 1})
359
+ category.tags.some((c) => c.id === t.id)).length}/{category.tags.length})
301
360
  </Checkbox>
302
361
  );
303
362
  })}
@@ -351,15 +410,16 @@ const LogicEditorInner = ({
351
410
  </div>;
352
411
  };
353
412
 
354
- function getAllTagsFromCategory(categoryNode, allCategories = {}) {
413
+ function getAllTagsFromCategory(categoryNode, allCategories = {}, parentCategoryTitle = null) {
355
414
  if (!categoryNode || !categoryNode.fields?.children) {
356
415
  return allCategories;
357
416
  }
358
417
 
359
418
  const children = categoryNode.fields.children.de || [];
419
+ const title = parentCategoryTitle ? `${parentCategoryTitle} > ${categoryNode.fields.title.de}` : categoryNode.fields.title.de;
360
420
 
361
421
  allCategories[categoryNode.sys.id] = {
362
- title: categoryNode.fields.title.de,
422
+ title,
363
423
  tags: [],
364
424
  id: categoryNode.sys.id,
365
425
  };
@@ -399,7 +459,7 @@ function getAllTagsFromCategory(categoryNode, allCategories = {}) {
399
459
  }
400
460
  }
401
461
 
402
- getAllTagsFromCategory(child, allCategories);
462
+ getAllTagsFromCategory(child, allCategories, title);
403
463
  }
404
464
 
405
465
  allCategories[categoryNode.sys.id].tags = [...new Set(allCategories[categoryNode.sys.id].tags)];
@@ -2,8 +2,12 @@ import React, {
2
2
  useEffect, useState,
3
3
  } from 'react';
4
4
  import {NewestArticles} from "./Dialog/NewestArticles";
5
- import {NoAccess} from "../NoAccess";
6
5
  import {LogicEditor} from './Dialog/LogicEditor';
6
+ import {
7
+ QueryClient, QueryClientProvider,
8
+ } from "@tanstack/react-query";
9
+
10
+ const queryClient = new QueryClient();
7
11
 
8
12
  const Dialog = ({
9
13
  sdk,
@@ -60,21 +64,23 @@ const Dialog = ({
60
64
  backgroundColor: "#FFFFFF",
61
65
  minHeight: "100vh",
62
66
  }}>
63
- {sdk.parameters.invocation.isLogicEditor ?
64
- <LogicEditor
65
- sdk={sdk}
66
- onSave={onSave}
67
- logicData={logicData}
68
- portals={portals}
69
- /> :
70
- <NewestArticles
71
- sdk={sdk}
72
- onEntryClick={selectEntry}
73
- slotState={slotState}
74
- getArticleThumbnailUrl={getArticleThumbnailUrl}
75
- portals={portals}
76
- />
77
- }
67
+ <QueryClientProvider client={queryClient}>
68
+ {sdk.parameters.invocation.isLogicEditor ?
69
+ <LogicEditor
70
+ sdk={sdk}
71
+ onSave={onSave}
72
+ logicData={logicData}
73
+ portals={portals}
74
+ /> :
75
+ <NewestArticles
76
+ sdk={sdk}
77
+ onEntryClick={selectEntry}
78
+ slotState={slotState}
79
+ getArticleThumbnailUrl={getArticleThumbnailUrl}
80
+ portals={portals}
81
+ />
82
+ }
83
+ </QueryClientProvider>
78
84
  </div>;
79
85
  };
80
86
 
@@ -0,0 +1,29 @@
1
+ export const queryFromLogic = (logic) => {
2
+ const orTags = logic.tags.filter(v => v.type === "or").map(v => v.id);
3
+ const andTags = logic.tags.filter(v => v.type === "and").map(v => v.id);
4
+ const timeZoneOffsetInHours = new Date().getTimezoneOffset() / 60;
5
+ const differenceToGermanTime = timeZoneOffsetInHours + 2;
6
+ const hours = [...(logic.timepoints || [])].map(v => parseInt(v)).sort((a, b) => a - b);
7
+ let nearestPassedTime = hours.find(v => v <= new Date().getUTCHours() + differenceToGermanTime);
8
+ const logicQuery = {"fields.portal": logic.portal};
9
+
10
+ if (!nearestPassedTime) {
11
+ nearestPassedTime = hours.at(0) || 0;
12
+ }
13
+
14
+ if (orTags.length) {
15
+ logicQuery["fields.tags.sys.id[in]"] = orTags.join(",");
16
+ }
17
+
18
+ if (andTags.length) {
19
+ logicQuery["fields.tags.sys.id[all]"] = andTags.join(",");
20
+ }
21
+
22
+ if (nearestPassedTime && hours.length) {
23
+ logicQuery["fields.date[lte]"] = new Date(new Date().setHours(
24
+ nearestPassedTime + differenceToGermanTime, 0, 0, 0,
25
+ ));
26
+ }
27
+
28
+ return logicQuery;
29
+ };
@@ -5,7 +5,7 @@ let config = require("./webpack.config")({
5
5
  });
6
6
 
7
7
 
8
- config.entry = {index: './src/dev.js'};
8
+ config.entry.index = './src/dev.js';
9
9
 
10
10
  config.mode = "development";
11
11
  config.watch = true;
package/webpack.config.js CHANGED
@@ -21,7 +21,10 @@ module.exports = ({
21
21
  }) => {
22
22
  return {
23
23
  mode: 'production',
24
- entry: {index: './src/index.js'},
24
+ entry: {
25
+ index: './src/index.js',
26
+ queryFromLogic: './src/queryFromLogic.js',
27
+ },
25
28
  module: {
26
29
  rules: [
27
30
  {