@pixelated-tech/components 3.7.13 → 3.8.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.
- package/README.md +7 -0
- package/dist/components/admin/site-health/site-health-utils.js +22 -0
- package/dist/components/config/config.example.js +5 -6
- package/dist/components/config/config.js +7 -29
- package/dist/components/config/config.types.js +33 -1
- package/dist/components/config/config.utils.js +52 -0
- package/dist/components/general/cache-manager.js +124 -0
- package/dist/components/general/contentful.delivery.js +3 -0
- package/dist/components/general/google.reviews.components.js +7 -3
- package/dist/components/general/googlemap.js +5 -2
- package/dist/components/general/instagram.components.js +7 -3
- package/dist/components/general/sitemap.js +3 -1
- package/dist/components/general/smartimage.js +1 -1
- package/dist/components/shoppingcart/ebay.components.js +13 -9
- package/dist/components/shoppingcart/ebay.functions.js +94 -9
- package/dist/components/shoppingcart/shoppingcart.components.js +4 -2
- package/dist/config/pixelated.config.json +72 -0
- package/dist/index.js +2 -0
- package/dist/index.server.js +1 -0
- package/dist/scripts/release.sh +2 -2
- package/dist/test/config.mock.js +13 -0
- package/dist/test/setup.js +46 -0
- package/dist/test/test-utils.js +23 -0
- package/dist/types/components/admin/site-health/site-health-utils.d.ts +1 -1
- package/dist/types/components/admin/site-health/site-health-utils.d.ts.map +1 -1
- package/dist/types/components/config/config.d.ts +1 -1
- package/dist/types/components/config/config.d.ts.map +1 -1
- package/dist/types/components/config/config.example.d.ts.map +1 -1
- package/dist/types/components/config/config.types.d.ts +29 -5
- package/dist/types/components/config/config.types.d.ts.map +1 -1
- package/dist/types/components/config/config.utils.d.ts +6 -0
- package/dist/types/components/config/config.utils.d.ts.map +1 -0
- package/dist/types/components/general/cache-manager.d.ts +45 -0
- package/dist/types/components/general/cache-manager.d.ts.map +1 -0
- package/dist/types/components/general/contentful.delivery.d.ts.map +1 -1
- package/dist/types/components/general/google.reviews.components.d.ts.map +1 -1
- package/dist/types/components/general/googlemap.d.ts +1 -1
- package/dist/types/components/general/googlemap.d.ts.map +1 -1
- package/dist/types/components/general/instagram.components.d.ts.map +1 -1
- package/dist/types/components/general/sitemap.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/ebay.components.d.ts +1 -1
- package/dist/types/components/shoppingcart/ebay.components.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/ebay.functions.d.ts +15 -0
- package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.server.d.ts +1 -0
- package/dist/types/stories/callout/callout.many.stories.d.ts +0 -1
- package/dist/types/stories/callout/callout.many.stories.d.ts.map +1 -1
- package/dist/types/stories/callout/callout.stories.d.ts +0 -1
- package/dist/types/stories/callout/callout.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel-hero.stories.d.ts +1 -9
- package/dist/types/stories/carousel/carousel-hero.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel-reviews.stories.d.ts +0 -1
- package/dist/types/stories/carousel/carousel-reviews.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts +1 -9
- package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel.stories.d.ts +1 -9
- package/dist/types/stories/carousel/carousel.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/tiles.stories.d.ts +0 -1
- package/dist/types/stories/carousel/tiles.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.item.stories.d.ts +0 -9
- package/dist/types/stories/cms/contentful.item.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.items.stories.d.ts +1 -11
- package/dist/types/stories/cms/contentful.items.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.stories.d.ts +0 -1
- package/dist/types/stories/cms/contentful.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/google.reviews.stories.d.ts +24 -12
- package/dist/types/stories/cms/google.reviews.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/gravatar.stories.d.ts +0 -1
- package/dist/types/stories/cms/gravatar.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/instagram.stories.d.ts +40 -9
- package/dist/types/stories/cms/instagram.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/wordpress.stories.d.ts +38 -13
- package/dist/types/stories/cms/wordpress.stories.d.ts.map +1 -1
- package/dist/types/stories/general/accordion.stories.d.ts +3 -2
- package/dist/types/stories/general/accordion.stories.d.ts.map +1 -1
- package/dist/types/stories/general/headers.stories.d.ts.map +1 -1
- package/dist/types/stories/general/microinteractions.stories.d.ts +0 -1
- package/dist/types/stories/general/microinteractions.stories.d.ts.map +1 -1
- package/dist/types/stories/general/modal.stories.d.ts +0 -1
- package/dist/types/stories/general/modal.stories.d.ts.map +1 -1
- package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
- package/dist/types/stories/general/splitscroll.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.404.stories.d.ts +0 -1
- package/dist/types/stories/seo/seo.404.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts +1 -6
- package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.schema.stories.d.ts +0 -1
- package/dist/types/stories/seo/seo.schema.stories.d.ts.map +1 -1
- package/dist/types/stories/shoppingcart/shoppingcart.ebay.item.stories.d.ts +1 -12
- package/dist/types/stories/shoppingcart/shoppingcart.ebay.item.stories.d.ts.map +1 -1
- package/dist/types/stories/shoppingcart/shoppingcart.ebay.items.stories.d.ts +1 -12
- package/dist/types/stories/shoppingcart/shoppingcart.ebay.items.stories.d.ts.map +1 -1
- package/dist/types/stories/shoppingcart/shoppingcart.stories.d.ts.map +1 -1
- package/dist/types/stories/sitebuilder/compoundfontselector.stories.d.ts +12 -34
- package/dist/types/stories/sitebuilder/compoundfontselector.stories.d.ts.map +1 -1
- package/dist/types/stories/sitebuilder/form-engine.stories.d.ts +0 -1
- package/dist/types/stories/sitebuilder/form-engine.stories.d.ts.map +1 -1
- package/dist/types/stories/sitebuilder/pageengine.stories.d.ts +0 -1
- package/dist/types/stories/sitebuilder/pageengine.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/markdown.stories.d.ts +0 -1
- package/dist/types/stories/structured/markdown.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/recipe.stories.d.ts +0 -1
- package/dist/types/stories/structured/recipe.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/resume.stories.d.ts +0 -1
- package/dist/types/stories/structured/resume.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/socialcard.stories.d.ts +0 -1
- package/dist/types/stories/structured/socialcard.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/timeline.stories.d.ts +0 -1
- package/dist/types/stories/structured/timeline.stories.d.ts.map +1 -1
- package/dist/types/test/config.mock.d.ts +11 -0
- package/dist/types/test/config.mock.d.ts.map +1 -0
- package/dist/types/test/setup.d.ts.map +1 -0
- package/dist/types/test/test-utils.d.ts +84 -0
- package/dist/types/test/test-utils.d.ts.map +1 -0
- package/dist/types/tests/cache-manager.test.d.ts +2 -0
- package/dist/types/tests/cache-manager.test.d.ts.map +1 -0
- package/dist/types/tests/config-core.test.d.ts +2 -0
- package/dist/types/tests/config-core.test.d.ts.map +1 -0
- package/dist/types/tests/ebay-functions.test.d.ts +2 -0
- package/dist/types/tests/ebay-functions.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-utils.test.d.ts +2 -0
- package/dist/types/tests/site-health-utils.test.d.ts.map +1 -0
- package/package.json +4 -4
- package/dist/types/tests/setup.d.ts.map +0 -1
- /package/dist/types/{tests → test}/setup.d.ts +0 -0
package/README.md
CHANGED
|
@@ -242,6 +242,13 @@ External service integrations:
|
|
|
242
242
|
- **Yelp** - Business reviews and ratings
|
|
243
243
|
|
|
244
244
|
|
|
245
|
+
### Utilities
|
|
246
|
+
Shared technical utilities and helpers:
|
|
247
|
+
- **CacheManager** - Unified caching layer with Memory, Session, and LocalStorage support with TTL and SSR fallbacks.
|
|
248
|
+
- **Cloudinary** - Image processing and URL generation helpers.
|
|
249
|
+
- **Date/Time** - Formatting and manipulation utilities.
|
|
250
|
+
|
|
251
|
+
|
|
245
252
|
### Site Health & Monitoring
|
|
246
253
|
Comprehensive site health monitoring and analytics:
|
|
247
254
|
- **SiteHealthOverview** - Dashboard overview of site health metrics
|
|
@@ -25,6 +25,28 @@ export function formatScore(score) {
|
|
|
25
25
|
* Formats audit item details for display
|
|
26
26
|
*/
|
|
27
27
|
export function formatAuditItem(item, auditTitle) {
|
|
28
|
+
// Handle raw timing data that might be passed directly
|
|
29
|
+
if (typeof item === 'number') {
|
|
30
|
+
let context = '';
|
|
31
|
+
if (auditTitle) {
|
|
32
|
+
if (auditTitle.toLowerCase().includes('server') || auditTitle.toLowerCase().includes('backend')) {
|
|
33
|
+
context = ' server response';
|
|
34
|
+
}
|
|
35
|
+
else if (auditTitle.toLowerCase().includes('network') || auditTitle.toLowerCase().includes('request')) {
|
|
36
|
+
context = ' network request';
|
|
37
|
+
}
|
|
38
|
+
else if (auditTitle.toLowerCase().includes('render') || auditTitle.toLowerCase().includes('blocking')) {
|
|
39
|
+
context = ' render blocking';
|
|
40
|
+
}
|
|
41
|
+
else if (auditTitle.toLowerCase().includes('javascript') || auditTitle.toLowerCase().includes('js')) {
|
|
42
|
+
context = ' JavaScript';
|
|
43
|
+
}
|
|
44
|
+
else if (auditTitle.toLowerCase().includes('image') || auditTitle.toLowerCase().includes('media')) {
|
|
45
|
+
context = ' media resource';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return `${item.toFixed(2)}ms${context}`;
|
|
49
|
+
}
|
|
28
50
|
// Handle URLs
|
|
29
51
|
if (item.url && typeof item.url === 'string') {
|
|
30
52
|
return item.url;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Example pixelated.config.ts for consumer apps.
|
|
2
2
|
// Place this file in your app (for example: `src/pixelated.config.ts`) and import it where you mount the provider.
|
|
3
3
|
const pixelatedConfig = {
|
|
4
|
+
global: {
|
|
5
|
+
proxyUrl: 'https://proxy.pixelated.tech/prod/proxy?url=',
|
|
6
|
+
},
|
|
4
7
|
cloudinary: {
|
|
5
8
|
product_env: 'your-cloud-name',
|
|
6
9
|
baseUrl: 'https://res.cloudinary.com',
|
|
@@ -18,8 +21,10 @@ const pixelatedConfig = {
|
|
|
18
21
|
ebay: {
|
|
19
22
|
proxyURL: 'https://proxy.provier.com/proxy?url=',
|
|
20
23
|
appId: 'your-ebay-client-id',
|
|
24
|
+
appDevId: 'your-ebay-client-dev-id',
|
|
21
25
|
appCertId: 'your-ebay-client-secret',
|
|
22
26
|
sbxAppId: 'your-ebay-sandbox-client-id',
|
|
27
|
+
sbxAppDevId: 'your-ebay-sandbox-client-dev-id',
|
|
23
28
|
sbxAppCertId: 'your-ebay-sandbox-client-secret',
|
|
24
29
|
globalId: 'EBAY_US',
|
|
25
30
|
environment: 'production',
|
|
@@ -30,9 +35,6 @@ const pixelatedConfig = {
|
|
|
30
35
|
baseItemURL: 'https://api.ebay.com/buy/browse/v1/item',
|
|
31
36
|
qsItemURL: '/v1|295959752403|0?fieldgroups=PRODUCT,ADDITIONAL_SELLER_DETAILS',
|
|
32
37
|
},
|
|
33
|
-
featureFlags: {
|
|
34
|
-
enableNewGrid: true,
|
|
35
|
-
},
|
|
36
38
|
flickr: {
|
|
37
39
|
baseURL: 'https://api.flickr.com/services/rest/?',
|
|
38
40
|
urlProps: {
|
|
@@ -67,9 +69,6 @@ const pixelatedConfig = {
|
|
|
67
69
|
payPalApiKey: "your-paypal-client-id",
|
|
68
70
|
payPalSecret: "your-paypal-client-secret"
|
|
69
71
|
},
|
|
70
|
-
proxy: {
|
|
71
|
-
proxyURL: 'https://proxy.pixelated.tech/prod/proxy?url='
|
|
72
|
-
},
|
|
73
72
|
wordpress: {
|
|
74
73
|
baseURL: 'https://public-api.wordpress.com/rest/v1/sites/',
|
|
75
74
|
site: 'your-blog.wordpress.com'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decrypt, isEncrypted } from './crypto';
|
|
2
|
+
import { getClientOnlyPixelatedConfig as stripSecrets } from './config.utils';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
const debug = false;
|
|
@@ -14,7 +15,7 @@ export function getFullPixelatedConfig() {
|
|
|
14
15
|
const filename = 'pixelated.config.json';
|
|
15
16
|
const paths = [
|
|
16
17
|
path.join(process.cwd(), 'src/app/config', filename),
|
|
17
|
-
path.join(process.cwd(), '
|
|
18
|
+
path.join(process.cwd(), 'src/config', filename),
|
|
18
19
|
path.join(process.cwd(), filename),
|
|
19
20
|
path.join(process.cwd(), '.next/server', filename), // Sometimes moved here in build
|
|
20
21
|
];
|
|
@@ -31,7 +32,7 @@ export function getFullPixelatedConfig() {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
if (!raw) {
|
|
34
|
-
console.error('
|
|
35
|
+
console.error('pixelated.config.json not found. Searched in src/app/config/, src/config/, and root.');
|
|
35
36
|
return {};
|
|
36
37
|
}
|
|
37
38
|
// Handle decryption if the content is encrypted
|
|
@@ -67,31 +68,8 @@ export function getFullPixelatedConfig() {
|
|
|
67
68
|
* This will walk the object and drop any fields that match a secret pattern.
|
|
68
69
|
*/
|
|
69
70
|
export function getClientOnlyPixelatedConfig(full) {
|
|
70
|
-
const src = full
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return false;
|
|
75
|
-
return /token|secret|key|password|management|access/i.test(key);
|
|
76
|
-
}
|
|
77
|
-
function strip(obj) {
|
|
78
|
-
if (!obj || typeof obj !== 'object')
|
|
79
|
-
return obj;
|
|
80
|
-
if (Array.isArray(obj))
|
|
81
|
-
return obj.map(strip);
|
|
82
|
-
const out = {};
|
|
83
|
-
for (const k of Object.keys(obj)) {
|
|
84
|
-
if (isSecretKey(k))
|
|
85
|
-
continue;
|
|
86
|
-
out[k] = strip(obj[k]);
|
|
87
|
-
}
|
|
88
|
-
return out;
|
|
89
|
-
}
|
|
90
|
-
try {
|
|
91
|
-
return strip(src);
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
console.error('Failed to strip secrets from config', err);
|
|
95
|
-
return {};
|
|
96
|
-
}
|
|
71
|
+
const src = (full === undefined) ? getFullPixelatedConfig() : full;
|
|
72
|
+
if (src === null || typeof src !== 'object')
|
|
73
|
+
return (src || {});
|
|
74
|
+
return stripSecrets(src);
|
|
97
75
|
}
|
|
@@ -1,2 +1,34 @@
|
|
|
1
1
|
// Types for Pixelated integration configuration
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Metadata defining which configuration keys are secrets and must be stripped
|
|
4
|
+
* before being sent to the client (browser).
|
|
5
|
+
*/
|
|
6
|
+
export const SECRET_CONFIG_KEYS = {
|
|
7
|
+
// Keys found at the root of the configuration object
|
|
8
|
+
global: [
|
|
9
|
+
'PIXELATED_CONFIG_KEY'
|
|
10
|
+
],
|
|
11
|
+
// Keys found within specific service configuration blocks
|
|
12
|
+
services: {
|
|
13
|
+
cloudinary: [
|
|
14
|
+
'api_key',
|
|
15
|
+
'api_secret'
|
|
16
|
+
],
|
|
17
|
+
contentful: [
|
|
18
|
+
'management_access_token',
|
|
19
|
+
'preview_access_token'
|
|
20
|
+
],
|
|
21
|
+
ebay: [
|
|
22
|
+
'sbxAppId'
|
|
23
|
+
],
|
|
24
|
+
paypal: [
|
|
25
|
+
'sandboxPayPalApiKey',
|
|
26
|
+
'sandboxPayPalSecret',
|
|
27
|
+
'payPalApiKey',
|
|
28
|
+
'payPalSecret'
|
|
29
|
+
],
|
|
30
|
+
instagram: [
|
|
31
|
+
'accessToken'
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SECRET_CONFIG_KEYS } from './config.types';
|
|
2
|
+
/**
|
|
3
|
+
* Produce a client-safe copy of a config by removing secret-like keys.
|
|
4
|
+
*/
|
|
5
|
+
export function getClientOnlyPixelatedConfig(src) {
|
|
6
|
+
const visited = new WeakSet();
|
|
7
|
+
function isSecretKey(key, serviceName) {
|
|
8
|
+
// 1. Check Global Secret List
|
|
9
|
+
if (SECRET_CONFIG_KEYS.global.includes(key))
|
|
10
|
+
return true;
|
|
11
|
+
// 2. Check Service-Specific Secret List
|
|
12
|
+
if (serviceName && SECRET_CONFIG_KEYS.services[serviceName]) {
|
|
13
|
+
const serviceSecrets = SECRET_CONFIG_KEYS.services[serviceName];
|
|
14
|
+
if (serviceSecrets.includes(key)) {
|
|
15
|
+
// console.log(`Config Stripper: Removing secret key "${key}" from service "${serviceName}"`);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function strip(obj, serviceName) {
|
|
22
|
+
// Base case for non-objects
|
|
23
|
+
if (obj === null || typeof obj !== 'object')
|
|
24
|
+
return obj;
|
|
25
|
+
// Avoid circular references
|
|
26
|
+
if (visited.has(obj))
|
|
27
|
+
return '[Circular]';
|
|
28
|
+
visited.add(obj);
|
|
29
|
+
// Handle Arrays
|
|
30
|
+
if (Array.isArray(obj)) {
|
|
31
|
+
return obj.map((item) => strip(item, serviceName));
|
|
32
|
+
}
|
|
33
|
+
const out = {};
|
|
34
|
+
for (const k of Object.keys(obj)) {
|
|
35
|
+
// At the top level (serviceName is undefined), k is the service name
|
|
36
|
+
const currentService = serviceName || k;
|
|
37
|
+
// Check if this key should be stripped
|
|
38
|
+
if (isSecretKey(k, serviceName)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
out[k] = strip(obj[k], currentService);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return strip(src);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error('Failed to strip secrets from config', err);
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CacheManager
|
|
3
|
+
*
|
|
4
|
+
* A unified caching utility that supports Memory, LocalStorage, and SessionStorage.
|
|
5
|
+
* Includes TTL (Time-To-Live) support and automatic SSR fallback.
|
|
6
|
+
*/
|
|
7
|
+
export class CacheManager {
|
|
8
|
+
memoryCache = new Map();
|
|
9
|
+
defaultTTL = 60 * 60 * 1000; // 1 hour
|
|
10
|
+
mode;
|
|
11
|
+
prefix;
|
|
12
|
+
ttl;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.mode = options.mode || 'memory';
|
|
15
|
+
this.prefix = options.prefix || 'pix_';
|
|
16
|
+
this.ttl = options.ttl || this.defaultTTL;
|
|
17
|
+
// Fallback to memory if browser storage is requested but unavailable (SSR/Node environment)
|
|
18
|
+
if (typeof window === 'undefined' && (this.mode === 'local' || this.mode === 'session')) {
|
|
19
|
+
this.mode = 'memory';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the storage engine based on the mode
|
|
24
|
+
*/
|
|
25
|
+
getStorage() {
|
|
26
|
+
if (typeof window === 'undefined')
|
|
27
|
+
return null;
|
|
28
|
+
if (this.mode === 'local')
|
|
29
|
+
return window.localStorage;
|
|
30
|
+
if (this.mode === 'session')
|
|
31
|
+
return window.sessionStorage;
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generates a prefixed key to avoid collisions
|
|
36
|
+
*/
|
|
37
|
+
getFullKey(key) {
|
|
38
|
+
return `${this.prefix}${key}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves data from the cache
|
|
42
|
+
*/
|
|
43
|
+
get(key) {
|
|
44
|
+
if (this.mode === 'none')
|
|
45
|
+
return null;
|
|
46
|
+
const fullKey = this.getFullKey(key);
|
|
47
|
+
let wrapper = null;
|
|
48
|
+
// 1. Check Memory cache first (fastest)
|
|
49
|
+
const memMatch = this.memoryCache.get(fullKey);
|
|
50
|
+
if (memMatch) {
|
|
51
|
+
wrapper = memMatch;
|
|
52
|
+
}
|
|
53
|
+
// 2. Check Browser storage if memory failed or was bypassed
|
|
54
|
+
if (!wrapper) {
|
|
55
|
+
const storage = this.getStorage();
|
|
56
|
+
if (storage) {
|
|
57
|
+
const raw = storage.getItem(fullKey);
|
|
58
|
+
if (raw) {
|
|
59
|
+
try {
|
|
60
|
+
wrapper = JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 3. Validate Expiry
|
|
69
|
+
if (wrapper) {
|
|
70
|
+
if (Date.now() < wrapper.expiry) {
|
|
71
|
+
// Resync memory cache if we pulled from storage
|
|
72
|
+
if (!memMatch) {
|
|
73
|
+
this.memoryCache.set(fullKey, wrapper);
|
|
74
|
+
}
|
|
75
|
+
return wrapper.data;
|
|
76
|
+
}
|
|
77
|
+
// Clean up expired items
|
|
78
|
+
this.remove(key);
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Stores data in the cache with a specified TTL
|
|
84
|
+
*/
|
|
85
|
+
set(key, data, customTTL) {
|
|
86
|
+
if (this.mode === 'none')
|
|
87
|
+
return;
|
|
88
|
+
const fullKey = this.getFullKey(key);
|
|
89
|
+
const expiry = Date.now() + (customTTL || this.ttl);
|
|
90
|
+
const wrapper = { data, expiry };
|
|
91
|
+
// Always update memory
|
|
92
|
+
this.memoryCache.set(fullKey, wrapper);
|
|
93
|
+
// Update browser storage if applicable
|
|
94
|
+
const storage = this.getStorage();
|
|
95
|
+
if (storage) {
|
|
96
|
+
storage.setItem(fullKey, JSON.stringify(wrapper));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Removes a specific item from all storage engines
|
|
101
|
+
*/
|
|
102
|
+
remove(key) {
|
|
103
|
+
const fullKey = this.getFullKey(key);
|
|
104
|
+
this.memoryCache.delete(fullKey);
|
|
105
|
+
const storage = this.getStorage();
|
|
106
|
+
if (storage) {
|
|
107
|
+
storage.removeItem(fullKey);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clears only the items belonging to this manager (by prefix)
|
|
112
|
+
*/
|
|
113
|
+
clear() {
|
|
114
|
+
this.memoryCache.clear();
|
|
115
|
+
const storage = this.getStorage();
|
|
116
|
+
if (storage) {
|
|
117
|
+
Object.keys(storage).forEach(k => {
|
|
118
|
+
if (k.startsWith(this.prefix)) {
|
|
119
|
+
storage.removeItem(k);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -61,6 +61,9 @@ getContentfulEntriesByType.propTypes = {
|
|
|
61
61
|
};
|
|
62
62
|
export async function getContentfulEntriesByType(props) {
|
|
63
63
|
const allEntries = await getContentfulEntries({ apiProps: props.apiProps });
|
|
64
|
+
if (!allEntries || !allEntries.items) {
|
|
65
|
+
return { items: [] };
|
|
66
|
+
}
|
|
64
67
|
const typeEntries = [];
|
|
65
68
|
for (const item of allEntries.items) {
|
|
66
69
|
if (item.sys.contentType.sys.id == props.contentType) {
|
|
@@ -4,8 +4,9 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import { SmartImage } from './smartimage';
|
|
6
6
|
import { getGoogleReviewsByPlaceId } from './google.reviews.functions';
|
|
7
|
+
import { usePixelatedConfig } from '../config/config.client';
|
|
7
8
|
import './google.reviews.css';
|
|
8
|
-
const GOOGLE_MAPS_API_KEY = '
|
|
9
|
+
const GOOGLE_MAPS_API_KEY = 'AIzaSyBJVi0O9Ir9imRgINLZbojTifatX-Z4aUs';
|
|
9
10
|
GoogleReviewsCard.propTypes = {
|
|
10
11
|
placeId: PropTypes.string.isRequired,
|
|
11
12
|
language: PropTypes.string,
|
|
@@ -14,10 +15,13 @@ GoogleReviewsCard.propTypes = {
|
|
|
14
15
|
apiKey: PropTypes.string,
|
|
15
16
|
};
|
|
16
17
|
export function GoogleReviewsCard(props) {
|
|
18
|
+
const config = usePixelatedConfig();
|
|
17
19
|
const [place, setPlace] = useState();
|
|
18
20
|
const [reviews, setReviews] = useState([]);
|
|
19
21
|
const [loading, setLoading] = useState(true);
|
|
20
22
|
const [error, setError] = useState(null);
|
|
23
|
+
const apiKey = props.apiKey || config?.googleMaps?.apiKey || GOOGLE_MAPS_API_KEY;
|
|
24
|
+
const proxyBase = props.proxyBase || config?.global?.proxyUrl || undefined;
|
|
21
25
|
useEffect(() => {
|
|
22
26
|
(async () => {
|
|
23
27
|
try {
|
|
@@ -25,8 +29,8 @@ export function GoogleReviewsCard(props) {
|
|
|
25
29
|
placeId: props.placeId,
|
|
26
30
|
language: props.language ?? undefined,
|
|
27
31
|
maxReviews: props.maxReviews ?? undefined,
|
|
28
|
-
proxyBase:
|
|
29
|
-
apiKey:
|
|
32
|
+
proxyBase: proxyBase,
|
|
33
|
+
apiKey: apiKey,
|
|
30
34
|
});
|
|
31
35
|
setPlace(result.place);
|
|
32
36
|
setReviews(result.reviews);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
+
import { usePixelatedConfig } from "../config/config.client";
|
|
3
4
|
// https://developers.google.com/maps/documentation/embed/embedding-map
|
|
4
5
|
GoogleMaps.propTypes = {
|
|
5
6
|
title: PropTypes.string,
|
|
@@ -8,9 +9,11 @@ GoogleMaps.propTypes = {
|
|
|
8
9
|
frameBorder: PropTypes.string,
|
|
9
10
|
style: PropTypes.object,
|
|
10
11
|
map_mode: PropTypes.string.isRequired,
|
|
11
|
-
api_key: PropTypes.string
|
|
12
|
+
api_key: PropTypes.string,
|
|
12
13
|
parameters: PropTypes.string,
|
|
13
14
|
};
|
|
14
15
|
export function GoogleMaps(props) {
|
|
15
|
-
|
|
16
|
+
const config = usePixelatedConfig();
|
|
17
|
+
const apiKey = props.api_key || config?.googleMaps?.apiKey;
|
|
18
|
+
return (_jsx("div", { className: "gmap", suppressHydrationWarning: true, children: _jsx("iframe", { title: props.title || "Google Map", width: props.width || "600", height: props.height || "400", frameBorder: props.frameBorder || "0", style: props.style || { border: 0 }, referrerPolicy: "no-referrer-when-downgrade", src: `https://www.google.com/maps/embed/v1/${props.map_mode}?key=${apiKey}&${props.parameters}`, allowFullScreen: true }) }));
|
|
16
19
|
}
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import { getInstagramTiles } from '../general/instagram.functions';
|
|
6
|
+
import { usePixelatedConfig } from "../config/config.client";
|
|
6
7
|
import { Tiles } from './tiles';
|
|
7
8
|
InstagramTiles.propTypes = {
|
|
8
9
|
accessToken: PropTypes.string,
|
|
@@ -14,15 +15,18 @@ InstagramTiles.propTypes = {
|
|
|
14
15
|
includeCaptions: PropTypes.bool,
|
|
15
16
|
};
|
|
16
17
|
export function InstagramTiles(props) {
|
|
18
|
+
const config = usePixelatedConfig();
|
|
17
19
|
const [tiles, setTiles] = useState([]);
|
|
18
20
|
const [loading, setLoading] = useState(true);
|
|
19
21
|
const [error, setError] = useState(null);
|
|
22
|
+
const accessToken = props.accessToken ?? config?.instagram?.accessToken;
|
|
23
|
+
const userId = props.userId ?? config?.instagram?.userId;
|
|
20
24
|
useEffect(() => {
|
|
21
25
|
(async () => {
|
|
22
26
|
try {
|
|
23
27
|
const result = await getInstagramTiles({
|
|
24
|
-
accessToken:
|
|
25
|
-
userId:
|
|
28
|
+
accessToken: accessToken ?? undefined,
|
|
29
|
+
userId: userId ?? undefined,
|
|
26
30
|
limit: props.limit ?? 12,
|
|
27
31
|
useThumbnails: props.useThumbnails ?? undefined,
|
|
28
32
|
includeVideos: props.includeVideos ?? undefined,
|
|
@@ -36,7 +40,7 @@ export function InstagramTiles(props) {
|
|
|
36
40
|
setLoading(false);
|
|
37
41
|
}
|
|
38
42
|
})();
|
|
39
|
-
}, [
|
|
43
|
+
}, [accessToken, userId, props.limit, props.useThumbnails, props.includeVideos, props.includeCaptions]);
|
|
40
44
|
if (loading) {
|
|
41
45
|
return (_jsx("div", { style: { padding: 16 }, children: _jsx("p", { children: "Loading Instagram posts..." }) }));
|
|
42
46
|
}
|
|
@@ -305,9 +305,11 @@ const defaultEbayProps = {
|
|
|
305
305
|
baseItemURL: 'https://api.ebay.com/buy/browse/v1/item',
|
|
306
306
|
qsItemURL: '/v1|295959752403|0?fieldgroups=PRODUCT,ADDITIONAL_SELLER_DETAILS',
|
|
307
307
|
appId: 'BrianWha-Pixelate-PRD-1fb4458de-1a8431fe', // clientId
|
|
308
|
+
appDevId: 'fa7b86b5-3a10-43ae-bf6f-497aa4e55ddd',
|
|
308
309
|
appCertId: 'PRD-fb4458deef01-0d54-496a-b572-a04b', // clientSecret
|
|
309
310
|
sbxAppId: 'BrianWha-Pixelate-SBX-ad482b6ae-8cb8fead', // Sandbox
|
|
310
|
-
|
|
311
|
+
sbxAppDevId: 'fa7b86b5-3a10-43ae-bf6f-497aa4e55ddd',
|
|
312
|
+
sbxAppCertId: 'SBX-d482b6ae0d62-f57c-4d3c-88b7-22ec',
|
|
311
313
|
globalId: 'EBAY-US',
|
|
312
314
|
};
|
|
313
315
|
export async function createEbayItemURLs(origin) {
|
|
@@ -103,7 +103,7 @@ export function SmartImage(props) {
|
|
|
103
103
|
newProps.width = parseNumber(props.width ?? 500);
|
|
104
104
|
newProps.height = parseNumber(props.height ?? 500);
|
|
105
105
|
newProps.quality = parseNumber(props.quality ?? 75);
|
|
106
|
-
const filename = (newProps.src).split('/').pop()?.split('?')[0] || '';
|
|
106
|
+
const filename = (String(newProps.src || '')).split('/').pop()?.split('?')[0] || '';
|
|
107
107
|
const imageName = filename.replace(/\.[^.]+$/, '');
|
|
108
108
|
newProps.id = newProps.id || newProps.name || sanitizeString(newProps.title) || sanitizeString(newProps.alt) || sanitizeString(imageName);
|
|
109
109
|
newProps.name = newProps.name || newProps.id || sanitizeString(newProps.title) || sanitizeString(newProps.alt) || sanitizeString(imageName);
|
|
@@ -8,7 +8,7 @@ import { defaultEbayProps, ebaySunglassCategory, getEbayItems, getEbayItem, getS
|
|
|
8
8
|
import { addToShoppingCart } from "./shoppingcart.functions";
|
|
9
9
|
import { AddToCartButton, /* GoToCartButton */ ViewItemDetails } from "./shoppingcart.components";
|
|
10
10
|
import { getCloudinaryRemoteFetchURL as getImg } from "../general/cloudinary";
|
|
11
|
-
import {
|
|
11
|
+
import { ToggleLoading } from "../general/loading";
|
|
12
12
|
import { usePixelatedConfig } from "../config/config.client";
|
|
13
13
|
import "../../css/pixelated.grid.scss";
|
|
14
14
|
import "./ebay.css";
|
|
@@ -44,6 +44,8 @@ export function EbayItems(props) {
|
|
|
44
44
|
};
|
|
45
45
|
async function fetchItems(props) {
|
|
46
46
|
try {
|
|
47
|
+
if (debug)
|
|
48
|
+
console.log("Fetching ebay API Items Data");
|
|
47
49
|
const myApiProps = { ...apiProps };
|
|
48
50
|
if (props) {
|
|
49
51
|
const params = new URLSearchParams(myApiProps.qsSearchURL);
|
|
@@ -55,9 +57,9 @@ export function EbayItems(props) {
|
|
|
55
57
|
}
|
|
56
58
|
const response = await getEbayItems({ apiProps: myApiProps });
|
|
57
59
|
if (debug)
|
|
58
|
-
console.log("eBay API
|
|
59
|
-
setItems(response
|
|
60
|
-
setAspects(response
|
|
60
|
+
console.log("eBay API Search Items Data:", response);
|
|
61
|
+
setItems(response?.itemSummaries);
|
|
62
|
+
setAspects(response?.refinement?.aspectDistributions);
|
|
61
63
|
}
|
|
62
64
|
catch (error) {
|
|
63
65
|
console.error("Error fetching eBay items:", error);
|
|
@@ -70,11 +72,11 @@ export function EbayItems(props) {
|
|
|
70
72
|
fetchItems();
|
|
71
73
|
ToggleLoading(false);
|
|
72
74
|
}, []);
|
|
73
|
-
if (items.length > 0) {
|
|
74
|
-
return (_jsxs(_Fragment, { children: [_jsx(
|
|
75
|
+
if (items && items.length > 0) {
|
|
76
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "ebayItemsHeader", children: _jsx(EbayItemHeader, { title: `${items.length} Store Items` }) }), _jsx("div", { className: "ebayItemsHeader", children: _jsx(EbayListFilter, { aspects: aspects, callback: fetchItems }) }), _jsx("div", { id: "ebayItems", className: "ebayItems", children: paintItems({ items: items, cloudinaryProductEnv: props.cloudinaryProductEnv }) })] }));
|
|
75
77
|
}
|
|
76
78
|
else {
|
|
77
|
-
return (_jsx("div", { className: "section-container", children: _jsx("div", { id: "ebayItems", className: "ebayItems"
|
|
79
|
+
return (_jsx("div", { className: "section-container", children: _jsx("div", { id: "ebayItems", className: "ebayItems" }) }));
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
82
|
EbayListFilter.propTypes = {
|
|
@@ -82,10 +84,12 @@ EbayListFilter.propTypes = {
|
|
|
82
84
|
callback: PropTypes.func.isRequired,
|
|
83
85
|
};
|
|
84
86
|
export function EbayListFilter(props) {
|
|
87
|
+
if (!props.aspects || !Array.isArray(props.aspects)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
85
90
|
const aspectNames = props.aspects.map((aspect) => (aspect.localizedAspectName)).sort();
|
|
86
91
|
let aspectNamesValues = {};
|
|
87
|
-
for (
|
|
88
|
-
const aspect = props.aspects[key];
|
|
92
|
+
for (const aspect of props.aspects) {
|
|
89
93
|
const thisAspectName = aspect.localizedAspectName;
|
|
90
94
|
const aspectNameValues = aspect.aspectValueDistributions.map((aspectValue) => {
|
|
91
95
|
return (aspectValue.localizedAspectValue);
|