gatsby-attainlabs-cms 1.0.15 → 1.0.18
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/README.md +1 -0
- package/dist/sliceWrapper.d.ts +3 -1
- package/dist/sliceWrapper.js +38 -2
- package/gatsby-config.js +16 -0
- package/gatsby-node.js +148 -43
- package/package.json +7 -2
- package/src/sliceWrapper.tsx +48 -4
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ module.exports = {
|
|
|
57
57
|
options: {
|
|
58
58
|
brand: "Cash Money", // LendDirect | Cash Money | Heights Finance adding-puck-for-visual-code-editing
|
|
59
59
|
// personalAccessToken: "optional-fallback", // not recommended, but supported
|
|
60
|
+
environment: "production", // production | dev
|
|
60
61
|
},
|
|
61
62
|
},
|
|
62
63
|
],
|
package/dist/sliceWrapper.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ interface SliceWrapperProps {
|
|
|
3
3
|
componentPath: string;
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
};
|
|
6
|
+
data: any;
|
|
6
7
|
}
|
|
7
|
-
export default function SliceWrapper({ sliceContext }: SliceWrapperProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
export default function SliceWrapper({ sliceContext, data, }: SliceWrapperProps): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
+
export declare const TrustPilotQuery: import("gatsby").StaticQueryDocument;
|
|
8
10
|
export {};
|
package/dist/sliceWrapper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { graphql } from "gatsby";
|
|
2
3
|
import { CMS_COMPONENTS } from "./map";
|
|
3
|
-
export default function SliceWrapper({ sliceContext }) {
|
|
4
|
+
export default function SliceWrapper({ sliceContext, data, }) {
|
|
4
5
|
const { componentPath, ...props } = sliceContext;
|
|
5
6
|
const pathFormatted = componentPath
|
|
6
7
|
.replace("src/cms/components//", "")
|
|
@@ -11,5 +12,40 @@ export default function SliceWrapper({ sliceContext }) {
|
|
|
11
12
|
console.warn(`Component "${pathFormatted}" not found in CMS_COMPONENTS`);
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
|
-
return _jsx(Component, { ...props });
|
|
15
|
+
return (_jsx(Component, { ...props, trustPilotData: data.allTrustPilotReviews.edges[0].node }));
|
|
15
16
|
}
|
|
17
|
+
export const TrustPilotQuery = graphql `
|
|
18
|
+
query {
|
|
19
|
+
allTrustPilotReviews {
|
|
20
|
+
edges {
|
|
21
|
+
node {
|
|
22
|
+
recentReviews {
|
|
23
|
+
reviews {
|
|
24
|
+
numberOfLikes
|
|
25
|
+
stars
|
|
26
|
+
text
|
|
27
|
+
title
|
|
28
|
+
createdAt
|
|
29
|
+
isVerified
|
|
30
|
+
reviewVerificationLevel
|
|
31
|
+
consumer {
|
|
32
|
+
displayName
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
businessData {
|
|
37
|
+
score {
|
|
38
|
+
stars
|
|
39
|
+
trustScore
|
|
40
|
+
}
|
|
41
|
+
displayName
|
|
42
|
+
numberOfReviews {
|
|
43
|
+
total
|
|
44
|
+
usedForTrustScoreCalculation
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
`;
|
package/gatsby-config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = ({ brand }) => ({
|
|
2
|
+
plugins: [
|
|
3
|
+
`gatsby-plugin-image`,
|
|
4
|
+
{
|
|
5
|
+
resolve: `gatsby-plugin-sharp`,
|
|
6
|
+
options: {
|
|
7
|
+
defaults: {
|
|
8
|
+
quality: 100,
|
|
9
|
+
placeholder: "none",
|
|
10
|
+
formats: [`webp`, "avif"],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
`gatsby-transformer-sharp`,
|
|
15
|
+
],
|
|
16
|
+
});
|
package/gatsby-node.js
CHANGED
|
@@ -11,18 +11,18 @@ const brands = {
|
|
|
11
11
|
"Attain Finance": "attainfinance",
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
const createPage = async (blocks, pageUrl
|
|
14
|
+
const createPage = async (blocks, pageUrl) => {
|
|
15
15
|
// Validate input parameters
|
|
16
|
-
if (!Array.isArray(blocks) || !pageUrl
|
|
16
|
+
if (!Array.isArray(blocks) || !pageUrl) {
|
|
17
17
|
throw new Error("Invalid parameters passed to createPage.");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// Helper function to generate Slice components
|
|
21
|
-
const generateSlices = (blocks,
|
|
21
|
+
const generateSlices = (blocks, id) => {
|
|
22
22
|
return blocks
|
|
23
23
|
.map(
|
|
24
24
|
(b) =>
|
|
25
|
-
`<Slice alias="
|
|
25
|
+
`<Slice alias="${b.sliceId}" />`
|
|
26
26
|
)
|
|
27
27
|
.join("\n");
|
|
28
28
|
};
|
|
@@ -44,7 +44,7 @@ const createPage = async (blocks, pageUrl, id) => {
|
|
|
44
44
|
const Page = () => {
|
|
45
45
|
return (
|
|
46
46
|
<Layout>
|
|
47
|
-
${generateSlices(blocks, pageUrl
|
|
47
|
+
${generateSlices(blocks, pageUrl)}
|
|
48
48
|
</Layout>
|
|
49
49
|
);
|
|
50
50
|
};
|
|
@@ -59,11 +59,23 @@ const createPage = async (blocks, pageUrl, id) => {
|
|
|
59
59
|
require("dotenv").config();
|
|
60
60
|
// Load PAT from env instead of hardcoding (fallback to old const for now but warn)
|
|
61
61
|
exports.onPreInit = async (_, pluginOptions) => {
|
|
62
|
-
const {
|
|
62
|
+
const {
|
|
63
|
+
brand,
|
|
64
|
+
azureBranch,
|
|
65
|
+
personalAccessToken: patOption,
|
|
66
|
+
environment,
|
|
67
|
+
} = pluginOptions;
|
|
63
68
|
|
|
64
69
|
// Try env first, then plugin option fallback
|
|
65
70
|
const pat = process.env.PERSONAL_ACCESS_TOKEN || patOption;
|
|
66
71
|
|
|
72
|
+
if (environment === "dev") {
|
|
73
|
+
console.log(
|
|
74
|
+
"ℹ️ [gatsby-attainlabs-cms] Running in 'dev' environment mode. Skipping component sync."
|
|
75
|
+
);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
67
79
|
if (!pat) {
|
|
68
80
|
console.warn(
|
|
69
81
|
"⚠️ [gatsby-attainlabs-cms] No PERSONAL_ACCESS_TOKEN found. " +
|
|
@@ -106,13 +118,12 @@ exports.onPreInit = async (_, pluginOptions) => {
|
|
|
106
118
|
// List of folders to download from
|
|
107
119
|
const targets = [
|
|
108
120
|
{
|
|
109
|
-
repoPath: `/apps/cms/src/cms/
|
|
110
|
-
localBasePath: path.resolve("./src/cms/
|
|
121
|
+
repoPath: `/apps/cms/src/cms/editors/visual-block-editor/brands/${brands[brand]}/`,
|
|
122
|
+
localBasePath: path.resolve("./src/cms/"),
|
|
111
123
|
},
|
|
112
124
|
{
|
|
113
|
-
repoPath:
|
|
114
|
-
|
|
115
|
-
localBasePath: path.resolve("./src/cms/components/"),
|
|
125
|
+
repoPath: "/apps/cms/src/cms/editors/visual-block-editor/core/",
|
|
126
|
+
localBasePath: path.resolve("./src/cms/"),
|
|
116
127
|
},
|
|
117
128
|
{
|
|
118
129
|
repoPath: `/apps/cms/src/gatsby-plugin-theme-ui/${brands[brand]}`,
|
|
@@ -165,13 +176,12 @@ exports.onPreInit = async (_, pluginOptions) => {
|
|
|
165
176
|
const result = JSON.parse(data);
|
|
166
177
|
const posix = path.posix;
|
|
167
178
|
|
|
168
|
-
//
|
|
179
|
+
// Exclude files named config.tsx
|
|
169
180
|
const items = (result.value || []).filter(
|
|
170
181
|
(i) =>
|
|
171
182
|
!i.isFolder &&
|
|
172
183
|
i.gitObjectType === "blob" &&
|
|
173
|
-
|
|
174
|
-
posix.extname(i.path) === ".ts")
|
|
184
|
+
posix.basename(i.path) !== "config.tsx"
|
|
175
185
|
);
|
|
176
186
|
|
|
177
187
|
console.log(`Found ${items.length} files in ${repoPath}`);
|
|
@@ -240,8 +250,12 @@ exports.onPreInit = async (_, pluginOptions) => {
|
|
|
240
250
|
res.pipe(fileStream);
|
|
241
251
|
fileStream.on("finish", () => {
|
|
242
252
|
fileStream.close(() => {
|
|
243
|
-
const
|
|
244
|
-
|
|
253
|
+
const ext = path.extname(destFile).toLowerCase();
|
|
254
|
+
let generatedComment = "";
|
|
255
|
+
if (ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx") {
|
|
256
|
+
generatedComment =
|
|
257
|
+
"// GENERATED FILE // This file is automatically generated by the AttainLabs CMS plugin. Do not edit this file directly.\n";
|
|
258
|
+
}
|
|
245
259
|
const fileContent = fs.readFileSync(tmpFile, "utf8");
|
|
246
260
|
fs.writeFileSync(destFile, generatedComment + fileContent);
|
|
247
261
|
|
|
@@ -259,11 +273,96 @@ exports.onPreInit = async (_, pluginOptions) => {
|
|
|
259
273
|
doRequest(fileUrl);
|
|
260
274
|
}
|
|
261
275
|
};
|
|
276
|
+
exports.sourceNodes = async (
|
|
277
|
+
{ actions, createNodeId, createContentDigest },
|
|
278
|
+
pluginOptions
|
|
279
|
+
) => {
|
|
280
|
+
const { createNode } = actions;
|
|
281
|
+
const { trustpilotApiKey, brand } = pluginOptions;
|
|
282
|
+
const apiKey = process.env.TRUSTPILOT_API_KEY || trustpilotApiKey;
|
|
283
|
+
console.log(
|
|
284
|
+
`ℹ️ [gatsby-attainlabs-cms] Fetching Trustpilot data for brand: ${brand}`
|
|
285
|
+
);
|
|
286
|
+
// // Map brand names to Trustpilot business unit IDs
|
|
287
|
+
const businessIds = {
|
|
288
|
+
LendDirect: "599affea0000ff0005a95acd",
|
|
289
|
+
"Cash Money": "599afd420000ff0005a95a9d",
|
|
290
|
+
"Heights Finance": "5e72238d600d1a0001be01eb",
|
|
291
|
+
};
|
|
292
|
+
const businessUnitId = businessIds[brand];
|
|
293
|
+
if (!apiKey) {
|
|
294
|
+
console.warn(
|
|
295
|
+
"⚠️ [gatsby-attainlabs-cms] No TRUSTPILOT_API_KEY found. " +
|
|
296
|
+
"Set it in your project's .env file (recommended) or pass via plugin options.\n" +
|
|
297
|
+
"Example .env:\n" +
|
|
298
|
+
"TRUSTPILOT_API_KEY=xxxxxxx\n"
|
|
299
|
+
);
|
|
300
|
+
return; // stop execution early
|
|
301
|
+
}
|
|
302
|
+
if (!brand || !businessUnitId) {
|
|
303
|
+
console.warn(
|
|
304
|
+
"⚠️ [gatsby-attainlabs-cms] Invalid or missing 'brand' option for Trustpilot integration. " +
|
|
305
|
+
`Current value: '${brand}'. Supported brands: ${Object.keys(businessIds).join(", ")}. ` +
|
|
306
|
+
"Trustpilot data will not be fetched."
|
|
307
|
+
);
|
|
308
|
+
return; // stop execution early
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const fetchTrustpilotData = async (endpoint) => {
|
|
312
|
+
try {
|
|
313
|
+
const response = await fetch(
|
|
314
|
+
`https://api.trustpilot.com/v1/business-units/${businessUnitId}/${endpoint}`,
|
|
315
|
+
{
|
|
316
|
+
headers: { ApiKey: apiKey },
|
|
317
|
+
}
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (!response.ok) {
|
|
321
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
322
|
+
}
|
|
262
323
|
|
|
324
|
+
return await response.json();
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error(
|
|
327
|
+
`Failed to fetch data from Trustpilot (${endpoint}):`,
|
|
328
|
+
error.message
|
|
329
|
+
);
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const businessData = await fetchTrustpilotData("");
|
|
335
|
+
const recentReviewsData = await fetchTrustpilotData(
|
|
336
|
+
"reviews?stars=5&includeReportedReviews=true"
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
if (businessData || recentReviewsData) {
|
|
340
|
+
const combinedData = {
|
|
341
|
+
businessData: businessData || {},
|
|
342
|
+
recentReviews: recentReviewsData || {},
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
return createNode({
|
|
346
|
+
...combinedData,
|
|
347
|
+
id: createNodeId("trustPilotReviews"),
|
|
348
|
+
parent: null,
|
|
349
|
+
internal: {
|
|
350
|
+
type: "TrustPilotReviews",
|
|
351
|
+
contentDigest: createContentDigest(combinedData),
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
};
|
|
263
356
|
exports.createPages = async ({ actions, store }, pluginOptions) => {
|
|
264
|
-
const { brand } = pluginOptions;
|
|
357
|
+
const { brand, environment } = pluginOptions;
|
|
265
358
|
const { createSlice } = actions;
|
|
266
359
|
const siteRoot = store.getState().program.directory;
|
|
360
|
+
if (environment === "dev") {
|
|
361
|
+
console.log(
|
|
362
|
+
"ℹ️ [gatsby-attainlabs-cms] Running in 'dev' environment mode. Skipping component sync."
|
|
363
|
+
);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
267
366
|
// 🚨 Validate brand option
|
|
268
367
|
if (!brand || !brands[brand]) {
|
|
269
368
|
throw new Error(
|
|
@@ -292,34 +391,40 @@ exports.createPages = async ({ actions, store }, pluginOptions) => {
|
|
|
292
391
|
},
|
|
293
392
|
},
|
|
294
393
|
id,
|
|
394
|
+
published,
|
|
295
395
|
} = page;
|
|
296
396
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
397
|
+
if (published) {
|
|
398
|
+
//Generate page's blocks slices
|
|
399
|
+
await Promise.all(
|
|
400
|
+
content.map(async (b) => {
|
|
401
|
+
const name = b.props.component.name;
|
|
402
|
+
const sliceId = `block--${pageUrl}--${name}--${id}--${crypto.randomUUID()}`;
|
|
403
|
+
console.log(`Creating slice: ${sliceId}`);
|
|
404
|
+
// here we could await something per slice if needed later
|
|
405
|
+
createSlice({
|
|
406
|
+
id: sliceId,
|
|
407
|
+
component: path.resolve(
|
|
408
|
+
siteRoot,
|
|
409
|
+
"src/cms/components/sliceWrapper.tsx"
|
|
410
|
+
),
|
|
411
|
+
context: {
|
|
412
|
+
componentPath: `./src/cms/components${b.props.component.path}/index.tsx`,
|
|
413
|
+
...b.props,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
b["sliceId"] = sliceId; // attach sliceId to block for later use
|
|
417
|
+
return b;
|
|
418
|
+
})
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
const pageSource = await createPage(content, pageUrl);
|
|
422
|
+
const outPath = path.join(siteRoot, "src/pages", `${pageUrl}.tsx`);
|
|
423
|
+
// Generate the page itself
|
|
424
|
+
await fse.outputFile(outPath, pageSource);
|
|
425
|
+
console.log(`✅ Wrote page to ${outPath}`);
|
|
426
|
+
}
|
|
323
427
|
}
|
|
324
428
|
}
|
|
325
429
|
};
|
|
430
|
+
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gatsby-attainlabs-cms",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
9
|
"build": "tsc"
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"dotenv": "^17.2.1",
|
|
19
|
+
"gatsby-background-image": "^1.6.0",
|
|
20
|
+
"gatsby-plugin-image": "^3.15.0",
|
|
21
|
+
"gatsby-plugin-sharp": "^5.15.0",
|
|
22
|
+
"gatsby-source-filesystem": "^5.15.0",
|
|
23
|
+
"gatsby-transformer-sharp": "^5.15.0",
|
|
19
24
|
"prettier": "^3.6.2",
|
|
20
25
|
"react-slick": "^0.31.0"
|
|
21
26
|
},
|
package/src/sliceWrapper.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// GENERATED FILE // This file is automatically generated by the AttainLabs CMS plugin. Do not edit this file directly.
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
|
-
import type
|
|
4
|
+
import { graphql, type SliceComponentProps } from "gatsby";
|
|
5
5
|
import { CMS_COMPONENTS } from "./map";
|
|
6
6
|
|
|
7
7
|
interface SliceWrapperProps {
|
|
@@ -9,11 +9,14 @@ interface SliceWrapperProps {
|
|
|
9
9
|
componentPath: string;
|
|
10
10
|
[key: string]: any;
|
|
11
11
|
};
|
|
12
|
+
data: any;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export default function SliceWrapper({
|
|
15
|
+
export default function SliceWrapper({
|
|
16
|
+
sliceContext,
|
|
17
|
+
data,
|
|
18
|
+
}: SliceWrapperProps) {
|
|
15
19
|
const { componentPath, ...props } = sliceContext;
|
|
16
|
-
|
|
17
20
|
const pathFormatted = componentPath
|
|
18
21
|
.replace("src/cms/components//", "")
|
|
19
22
|
.replace(/^.\//, "")
|
|
@@ -24,5 +27,46 @@ export default function SliceWrapper({ sliceContext }: SliceWrapperProps) {
|
|
|
24
27
|
return null;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
return
|
|
30
|
+
return (
|
|
31
|
+
<Component
|
|
32
|
+
{...props}
|
|
33
|
+
trustPilotData={data.allTrustPilotReviews.edges[0].node}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
28
36
|
}
|
|
37
|
+
|
|
38
|
+
export const TrustPilotQuery = graphql`
|
|
39
|
+
query {
|
|
40
|
+
allTrustPilotReviews {
|
|
41
|
+
edges {
|
|
42
|
+
node {
|
|
43
|
+
recentReviews {
|
|
44
|
+
reviews {
|
|
45
|
+
numberOfLikes
|
|
46
|
+
stars
|
|
47
|
+
text
|
|
48
|
+
title
|
|
49
|
+
createdAt
|
|
50
|
+
isVerified
|
|
51
|
+
reviewVerificationLevel
|
|
52
|
+
consumer {
|
|
53
|
+
displayName
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
businessData {
|
|
58
|
+
score {
|
|
59
|
+
stars
|
|
60
|
+
trustScore
|
|
61
|
+
}
|
|
62
|
+
displayName
|
|
63
|
+
numberOfReviews {
|
|
64
|
+
total
|
|
65
|
+
usedForTrustScoreCalculation
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
`;
|