@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.
Files changed (128) hide show
  1. package/README.md +7 -0
  2. package/dist/components/admin/site-health/site-health-utils.js +22 -0
  3. package/dist/components/config/config.example.js +5 -6
  4. package/dist/components/config/config.js +7 -29
  5. package/dist/components/config/config.types.js +33 -1
  6. package/dist/components/config/config.utils.js +52 -0
  7. package/dist/components/general/cache-manager.js +124 -0
  8. package/dist/components/general/contentful.delivery.js +3 -0
  9. package/dist/components/general/google.reviews.components.js +7 -3
  10. package/dist/components/general/googlemap.js +5 -2
  11. package/dist/components/general/instagram.components.js +7 -3
  12. package/dist/components/general/sitemap.js +3 -1
  13. package/dist/components/general/smartimage.js +1 -1
  14. package/dist/components/shoppingcart/ebay.components.js +13 -9
  15. package/dist/components/shoppingcart/ebay.functions.js +94 -9
  16. package/dist/components/shoppingcart/shoppingcart.components.js +4 -2
  17. package/dist/config/pixelated.config.json +72 -0
  18. package/dist/index.js +2 -0
  19. package/dist/index.server.js +1 -0
  20. package/dist/scripts/release.sh +2 -2
  21. package/dist/test/config.mock.js +13 -0
  22. package/dist/test/setup.js +46 -0
  23. package/dist/test/test-utils.js +23 -0
  24. package/dist/types/components/admin/site-health/site-health-utils.d.ts +1 -1
  25. package/dist/types/components/admin/site-health/site-health-utils.d.ts.map +1 -1
  26. package/dist/types/components/config/config.d.ts +1 -1
  27. package/dist/types/components/config/config.d.ts.map +1 -1
  28. package/dist/types/components/config/config.example.d.ts.map +1 -1
  29. package/dist/types/components/config/config.types.d.ts +29 -5
  30. package/dist/types/components/config/config.types.d.ts.map +1 -1
  31. package/dist/types/components/config/config.utils.d.ts +6 -0
  32. package/dist/types/components/config/config.utils.d.ts.map +1 -0
  33. package/dist/types/components/general/cache-manager.d.ts +45 -0
  34. package/dist/types/components/general/cache-manager.d.ts.map +1 -0
  35. package/dist/types/components/general/contentful.delivery.d.ts.map +1 -1
  36. package/dist/types/components/general/google.reviews.components.d.ts.map +1 -1
  37. package/dist/types/components/general/googlemap.d.ts +1 -1
  38. package/dist/types/components/general/googlemap.d.ts.map +1 -1
  39. package/dist/types/components/general/instagram.components.d.ts.map +1 -1
  40. package/dist/types/components/general/sitemap.d.ts.map +1 -1
  41. package/dist/types/components/shoppingcart/ebay.components.d.ts +1 -1
  42. package/dist/types/components/shoppingcart/ebay.components.d.ts.map +1 -1
  43. package/dist/types/components/shoppingcart/ebay.functions.d.ts +15 -0
  44. package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
  45. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +1 -1
  46. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
  47. package/dist/types/index.d.ts +2 -0
  48. package/dist/types/index.server.d.ts +1 -0
  49. package/dist/types/stories/callout/callout.many.stories.d.ts +0 -1
  50. package/dist/types/stories/callout/callout.many.stories.d.ts.map +1 -1
  51. package/dist/types/stories/callout/callout.stories.d.ts +0 -1
  52. package/dist/types/stories/callout/callout.stories.d.ts.map +1 -1
  53. package/dist/types/stories/carousel/carousel-hero.stories.d.ts +1 -9
  54. package/dist/types/stories/carousel/carousel-hero.stories.d.ts.map +1 -1
  55. package/dist/types/stories/carousel/carousel-reviews.stories.d.ts +0 -1
  56. package/dist/types/stories/carousel/carousel-reviews.stories.d.ts.map +1 -1
  57. package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts +1 -9
  58. package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts.map +1 -1
  59. package/dist/types/stories/carousel/carousel.stories.d.ts +1 -9
  60. package/dist/types/stories/carousel/carousel.stories.d.ts.map +1 -1
  61. package/dist/types/stories/carousel/tiles.stories.d.ts +0 -1
  62. package/dist/types/stories/carousel/tiles.stories.d.ts.map +1 -1
  63. package/dist/types/stories/cms/contentful.item.stories.d.ts +0 -9
  64. package/dist/types/stories/cms/contentful.item.stories.d.ts.map +1 -1
  65. package/dist/types/stories/cms/contentful.items.stories.d.ts +1 -11
  66. package/dist/types/stories/cms/contentful.items.stories.d.ts.map +1 -1
  67. package/dist/types/stories/cms/contentful.stories.d.ts +0 -1
  68. package/dist/types/stories/cms/contentful.stories.d.ts.map +1 -1
  69. package/dist/types/stories/cms/google.reviews.stories.d.ts +24 -12
  70. package/dist/types/stories/cms/google.reviews.stories.d.ts.map +1 -1
  71. package/dist/types/stories/cms/gravatar.stories.d.ts +0 -1
  72. package/dist/types/stories/cms/gravatar.stories.d.ts.map +1 -1
  73. package/dist/types/stories/cms/instagram.stories.d.ts +40 -9
  74. package/dist/types/stories/cms/instagram.stories.d.ts.map +1 -1
  75. package/dist/types/stories/cms/wordpress.stories.d.ts +38 -13
  76. package/dist/types/stories/cms/wordpress.stories.d.ts.map +1 -1
  77. package/dist/types/stories/general/accordion.stories.d.ts +3 -2
  78. package/dist/types/stories/general/accordion.stories.d.ts.map +1 -1
  79. package/dist/types/stories/general/headers.stories.d.ts.map +1 -1
  80. package/dist/types/stories/general/microinteractions.stories.d.ts +0 -1
  81. package/dist/types/stories/general/microinteractions.stories.d.ts.map +1 -1
  82. package/dist/types/stories/general/modal.stories.d.ts +0 -1
  83. package/dist/types/stories/general/modal.stories.d.ts.map +1 -1
  84. package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
  85. package/dist/types/stories/general/splitscroll.stories.d.ts.map +1 -1
  86. package/dist/types/stories/seo/seo.404.stories.d.ts +0 -1
  87. package/dist/types/stories/seo/seo.404.stories.d.ts.map +1 -1
  88. package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts +1 -6
  89. package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts.map +1 -1
  90. package/dist/types/stories/seo/seo.schema.stories.d.ts +0 -1
  91. package/dist/types/stories/seo/seo.schema.stories.d.ts.map +1 -1
  92. package/dist/types/stories/shoppingcart/shoppingcart.ebay.item.stories.d.ts +1 -12
  93. package/dist/types/stories/shoppingcart/shoppingcart.ebay.item.stories.d.ts.map +1 -1
  94. package/dist/types/stories/shoppingcart/shoppingcart.ebay.items.stories.d.ts +1 -12
  95. package/dist/types/stories/shoppingcart/shoppingcart.ebay.items.stories.d.ts.map +1 -1
  96. package/dist/types/stories/shoppingcart/shoppingcart.stories.d.ts.map +1 -1
  97. package/dist/types/stories/sitebuilder/compoundfontselector.stories.d.ts +12 -34
  98. package/dist/types/stories/sitebuilder/compoundfontselector.stories.d.ts.map +1 -1
  99. package/dist/types/stories/sitebuilder/form-engine.stories.d.ts +0 -1
  100. package/dist/types/stories/sitebuilder/form-engine.stories.d.ts.map +1 -1
  101. package/dist/types/stories/sitebuilder/pageengine.stories.d.ts +0 -1
  102. package/dist/types/stories/sitebuilder/pageengine.stories.d.ts.map +1 -1
  103. package/dist/types/stories/structured/markdown.stories.d.ts +0 -1
  104. package/dist/types/stories/structured/markdown.stories.d.ts.map +1 -1
  105. package/dist/types/stories/structured/recipe.stories.d.ts +0 -1
  106. package/dist/types/stories/structured/recipe.stories.d.ts.map +1 -1
  107. package/dist/types/stories/structured/resume.stories.d.ts +0 -1
  108. package/dist/types/stories/structured/resume.stories.d.ts.map +1 -1
  109. package/dist/types/stories/structured/socialcard.stories.d.ts +0 -1
  110. package/dist/types/stories/structured/socialcard.stories.d.ts.map +1 -1
  111. package/dist/types/stories/structured/timeline.stories.d.ts +0 -1
  112. package/dist/types/stories/structured/timeline.stories.d.ts.map +1 -1
  113. package/dist/types/test/config.mock.d.ts +11 -0
  114. package/dist/types/test/config.mock.d.ts.map +1 -0
  115. package/dist/types/test/setup.d.ts.map +1 -0
  116. package/dist/types/test/test-utils.d.ts +84 -0
  117. package/dist/types/test/test-utils.d.ts.map +1 -0
  118. package/dist/types/tests/cache-manager.test.d.ts +2 -0
  119. package/dist/types/tests/cache-manager.test.d.ts.map +1 -0
  120. package/dist/types/tests/config-core.test.d.ts +2 -0
  121. package/dist/types/tests/config-core.test.d.ts.map +1 -0
  122. package/dist/types/tests/ebay-functions.test.d.ts +2 -0
  123. package/dist/types/tests/ebay-functions.test.d.ts.map +1 -0
  124. package/dist/types/tests/site-health-utils.test.d.ts +2 -0
  125. package/dist/types/tests/site-health-utils.test.d.ts.map +1 -0
  126. package/package.json +4 -4
  127. package/dist/types/tests/setup.d.ts.map +0 -1
  128. /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(), 'app/config', filename),
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('PIXELATED_CONFIG not found. Ensure src/app/config/pixelated.config.json is available.');
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 ?? getFullPixelatedConfig();
71
- function isSecretKey(key) {
72
- // Explicitly allow common public-facing keys
73
- if (/api_key|apikey|public_key/i.test(key))
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
- export {};
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 = 'AIzaSyBtknq7LHzN0xb0lIN3K0CXXf0swVp6ReA';
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: props.proxyBase ?? undefined,
29
- apiKey: props.apiKey || GOOGLE_MAPS_API_KEY,
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.isRequired,
12
+ api_key: PropTypes.string,
12
13
  parameters: PropTypes.string,
13
14
  };
14
15
  export function GoogleMaps(props) {
15
- 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=${props.api_key}&${props.parameters}`, allowFullScreen: true }) }));
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: props.accessToken ?? undefined,
25
- userId: props.userId ?? undefined,
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
- }, [props.accessToken, props.userId, props.limit, props.useThumbnails, props.includeVideos, props.includeCaptions]);
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
- sbxAppCertId: '',
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 { Loading, ToggleLoading } from "../general/loading";
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 Get Items Data", response);
59
- setItems(response.itemSummaries);
60
- setAspects(response.refinement.aspectDistributions);
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(Loading, {}), _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
+ 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", children: _jsx(Loading, {}) }) }));
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 (let key in props.aspects) {
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);