@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.
|
|
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": "
|
|
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:
|
|
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-
|
|
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)
|
|
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)
|
|
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
|
|
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
|
-
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
+
};
|
package/webpack.config.dev.js
CHANGED
package/webpack.config.js
CHANGED