@pixelated-tech/components 3.13.16 → 3.14.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 (266) hide show
  1. package/dist/components/admin/site-health/google.api.integration.js +5 -4
  2. package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +3 -2
  3. package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +1 -3
  4. package/dist/components/config/crypto.js +17 -1
  5. package/dist/components/general/404.js +1 -1
  6. package/dist/components/general/cache-manager.js +19 -2
  7. package/dist/components/general/callout.js +1 -1
  8. package/dist/components/general/carousel.drag.js +21 -24
  9. package/dist/components/general/carousel.js +3 -3
  10. package/dist/components/general/countup.js +1 -1
  11. package/dist/components/general/intersection-observer.js +4 -0
  12. package/dist/components/general/metadata.functions.js +2 -2
  13. package/dist/components/general/proxy-handler.js +2 -2
  14. package/dist/components/general/semantic.js +3 -6
  15. package/dist/components/general/sitemap.js +2 -1
  16. package/dist/components/general/smartimage.js +2 -4
  17. package/dist/components/general/styleguide.js +1 -1
  18. package/dist/components/general/tiles.js +2 -2
  19. package/dist/components/general/timeline.js +1 -1
  20. package/dist/components/general/utilities.js +68 -0
  21. package/dist/components/integrations/contentful.delivery.js +16 -16
  22. package/dist/components/integrations/contentful.items.components.js +2 -11
  23. package/dist/components/integrations/flickr.js +7 -4
  24. package/dist/components/integrations/google.reviews.components.js +3 -0
  25. package/dist/components/integrations/googleplaces.js +144 -0
  26. package/dist/components/integrations/socialcard.js +5 -2
  27. package/dist/components/integrations/wordpress.components.js +2 -1
  28. package/dist/components/shoppingcart/ebay.components.js +5 -5
  29. package/dist/components/shoppingcart/ebay.functions.js +5 -3
  30. package/dist/components/shoppingcart/paypal.js +1 -1
  31. package/dist/components/shoppingcart/shipping.to.json +3 -4
  32. package/dist/components/shoppingcart/shoppingcart.components.js +7 -5
  33. package/dist/components/shoppingcart/shoppingcart.css +1 -1
  34. package/dist/components/shoppingcart/shoppingcart.functions.js +5 -14
  35. package/dist/components/sitebuilder/config/ConfigEngine.js +2 -2
  36. package/dist/components/sitebuilder/config/google-fonts.js +3 -3
  37. package/dist/components/sitebuilder/form/formcomponents.js +151 -0
  38. package/dist/components/sitebuilder/form/formutils.js +3 -0
  39. package/dist/components/sitebuilder/page/lib/pageStorageContentful.js +2 -2
  40. package/dist/config/pixelated.config.json.enc +1 -1
  41. package/dist/data/form.json +18 -0
  42. package/dist/index.adminserver.js +1 -3
  43. package/dist/index.js +1 -1
  44. package/dist/index.server.js +1 -0
  45. package/dist/scripts/create-pixelated-app.js +187 -79
  46. package/dist/scripts/create-pixelated-app.json +56 -1
  47. package/dist/scripts/pixelated-eslint-plugin.js +142 -0
  48. package/dist/scripts/release.sh +14 -1
  49. package/dist/scripts/update.sh +2 -0
  50. package/dist/types/components/admin/deploy/deployment.integration.d.ts +1 -0
  51. package/dist/types/components/admin/deploy/deployment.integration.d.ts.map +1 -1
  52. package/dist/types/components/admin/site-health/google.api.integration.d.ts.map +1 -1
  53. package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
  54. package/dist/types/components/config/config.types.d.ts +24 -0
  55. package/dist/types/components/config/config.types.d.ts.map +1 -1
  56. package/dist/types/components/config/crypto.d.ts +1 -0
  57. package/dist/types/components/config/crypto.d.ts.map +1 -1
  58. package/dist/types/components/general/404.d.ts.map +1 -1
  59. package/dist/types/components/general/cache-manager.d.ts +16 -2
  60. package/dist/types/components/general/cache-manager.d.ts.map +1 -1
  61. package/dist/types/components/general/callout.d.ts.map +1 -1
  62. package/dist/types/components/general/carousel.drag.d.ts.map +1 -1
  63. package/dist/types/components/general/intersection-observer.d.ts.map +1 -1
  64. package/dist/types/components/general/sitemap.d.ts.map +1 -1
  65. package/dist/types/components/general/smartimage.d.ts.map +1 -1
  66. package/dist/types/components/general/utilities.d.ts +37 -0
  67. package/dist/types/components/general/utilities.d.ts.map +1 -1
  68. package/dist/types/components/integrations/contentful.delivery.d.ts +16 -16
  69. package/dist/types/components/integrations/contentful.items.components.d.ts.map +1 -1
  70. package/dist/types/components/integrations/flickr.d.ts.map +1 -1
  71. package/dist/types/components/integrations/google.reviews.components.d.ts.map +1 -1
  72. package/dist/types/components/integrations/googleplaces.d.ts +61 -0
  73. package/dist/types/components/integrations/googleplaces.d.ts.map +1 -0
  74. package/dist/types/components/integrations/socialcard.d.ts.map +1 -1
  75. package/dist/types/components/integrations/wordpress.components.d.ts.map +1 -1
  76. package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
  77. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
  78. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +2 -2
  79. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
  80. package/dist/types/components/sitebuilder/form/formcomponents.d.ts +22 -0
  81. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
  82. package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -1
  83. package/dist/types/index.adminserver.d.ts +1 -3
  84. package/dist/types/index.d.ts +1 -1
  85. package/dist/types/index.server.d.ts +1 -0
  86. package/dist/types/scripts/create-pixelated-app.d.ts +3 -0
  87. package/dist/types/scripts/create-pixelated-app.d.ts.map +1 -1
  88. package/dist/types/scripts/pixelated-eslint-plugin.d.ts +20 -0
  89. package/dist/types/stories/integrations/contentful.items.stories.d.ts.map +1 -0
  90. package/dist/types/stories/integrations/contentful.stories.d.ts.map +1 -0
  91. package/dist/types/stories/integrations/google.reviews.stories.d.ts.map +1 -0
  92. package/dist/types/stories/integrations/googlesearch.stories.d.ts.map +1 -0
  93. package/dist/types/stories/integrations/gravatar.stories.d.ts.map +1 -0
  94. package/dist/types/stories/integrations/instagram.stories.d.ts.map +1 -0
  95. package/dist/types/stories/integrations/wordpress.stories.d.ts.map +1 -0
  96. package/dist/types/test/test-utils.d.ts +2 -0
  97. package/dist/types/test/test-utils.d.ts.map +1 -1
  98. package/dist/types/tests/404.test.d.ts +2 -0
  99. package/dist/types/tests/404.test.d.ts.map +1 -0
  100. package/dist/types/tests/carousel.drag.test.d.ts +2 -0
  101. package/dist/types/tests/carousel.drag.test.d.ts.map +1 -0
  102. package/dist/types/tests/carouselDrag.test.d.ts +2 -0
  103. package/dist/types/tests/carouselDrag.test.d.ts.map +1 -0
  104. package/dist/types/tests/componentAnalysis.test.d.ts +2 -0
  105. package/dist/types/tests/componentAnalysis.test.d.ts.map +1 -0
  106. package/dist/types/tests/componentDiscovery.test.d.ts +2 -0
  107. package/dist/types/tests/componentDiscovery.test.d.ts.map +1 -0
  108. package/dist/types/tests/componentMap.test.d.ts +2 -0
  109. package/dist/types/tests/componentMap.test.d.ts.map +1 -0
  110. package/dist/types/tests/contentful.items.components.test.d.ts +2 -0
  111. package/dist/types/tests/contentful.items.components.test.d.ts.map +1 -0
  112. package/dist/types/tests/contentful.management.test.d.ts +2 -0
  113. package/dist/types/tests/contentful.management.test.d.ts.map +1 -0
  114. package/dist/types/tests/contentfulManagement.test.d.ts +2 -0
  115. package/dist/types/tests/contentfulManagement.test.d.ts.map +1 -0
  116. package/dist/types/tests/countup.test.d.ts +2 -0
  117. package/dist/types/tests/countup.test.d.ts.map +1 -0
  118. package/dist/types/tests/crypto.test.d.ts +2 -0
  119. package/dist/types/tests/crypto.test.d.ts.map +1 -0
  120. package/dist/types/tests/deployment.integration.test.d.ts +2 -0
  121. package/dist/types/tests/deployment.integration.test.d.ts.map +1 -0
  122. package/dist/types/tests/ebay.components.test.d.ts +2 -0
  123. package/dist/types/tests/ebay.components.test.d.ts.map +1 -0
  124. package/dist/types/tests/ebayComponents.test.d.ts +2 -0
  125. package/dist/types/tests/ebayComponents.test.d.ts.map +1 -0
  126. package/dist/types/tests/flickr.test.d.ts +2 -0
  127. package/dist/types/tests/flickr.test.d.ts.map +1 -0
  128. package/dist/types/tests/formgoogleplacesinput.test.d.ts +2 -0
  129. package/dist/types/tests/formgoogleplacesinput.test.d.ts.map +1 -0
  130. package/dist/types/tests/formutils.test.d.ts +2 -0
  131. package/dist/types/tests/formutils.test.d.ts.map +1 -0
  132. package/dist/types/tests/formvalidator.test.d.ts +2 -0
  133. package/dist/types/tests/formvalidator.test.d.ts.map +1 -0
  134. package/dist/types/tests/gemini-api.client.test.d.ts +2 -0
  135. package/dist/types/tests/gemini-api.client.test.d.ts.map +1 -0
  136. package/dist/types/tests/gemini-api.server.test.d.ts +2 -0
  137. package/dist/types/tests/gemini-api.server.test.d.ts.map +1 -0
  138. package/dist/types/tests/geminiApi.test.d.ts +2 -0
  139. package/dist/types/tests/geminiApi.test.d.ts.map +1 -0
  140. package/dist/types/tests/google.reviews.components.test.d.ts +2 -0
  141. package/dist/types/tests/google.reviews.components.test.d.ts.map +1 -0
  142. package/dist/types/tests/googleanalytics.test.d.ts +2 -0
  143. package/dist/types/tests/googleanalytics.test.d.ts.map +1 -0
  144. package/dist/types/tests/googlemap.test.d.ts +2 -0
  145. package/dist/types/tests/googlemap.test.d.ts.map +1 -0
  146. package/dist/types/tests/gravatar.functions.test.d.ts +2 -0
  147. package/dist/types/tests/gravatar.functions.test.d.ts.map +1 -0
  148. package/dist/types/tests/hubspot.components.test.d.ts +2 -0
  149. package/dist/types/tests/hubspot.components.test.d.ts.map +1 -0
  150. package/dist/types/tests/image-utils.test.d.ts +2 -0
  151. package/dist/types/tests/image-utils.test.d.ts.map +1 -0
  152. package/dist/types/tests/instagram.components.test.d.ts +2 -0
  153. package/dist/types/tests/instagram.components.test.d.ts.map +1 -0
  154. package/dist/types/tests/instagram.functions.test.d.ts +2 -0
  155. package/dist/types/tests/instagram.functions.test.d.ts.map +1 -0
  156. package/dist/types/tests/intersection-observer.test.d.ts +2 -0
  157. package/dist/types/tests/intersection-observer.test.d.ts.map +1 -0
  158. package/dist/types/tests/metadata.functions.test.d.ts +2 -0
  159. package/dist/types/tests/metadata.functions.test.d.ts.map +1 -0
  160. package/dist/types/tests/metadataComponents.test.d.ts +2 -0
  161. package/dist/types/tests/metadataComponents.test.d.ts.map +1 -0
  162. package/dist/types/tests/page-storage.test.d.ts +2 -0
  163. package/dist/types/tests/page-storage.test.d.ts.map +1 -0
  164. package/dist/types/tests/pageStorageContentful.test.d.ts +2 -0
  165. package/dist/types/tests/pageStorageContentful.test.d.ts.map +1 -0
  166. package/dist/types/tests/pageStorageLocal.test.d.ts +2 -0
  167. package/dist/types/tests/pageStorageLocal.test.d.ts.map +1 -0
  168. package/dist/types/tests/pixelated.test.d.ts +2 -0
  169. package/dist/types/tests/pixelated.test.d.ts.map +1 -0
  170. package/dist/types/tests/propTypeIntrospection.test.d.ts +2 -0
  171. package/dist/types/tests/propTypeIntrospection.test.d.ts.map +1 -0
  172. package/dist/types/tests/save-route-example.test.d.ts +2 -0
  173. package/dist/types/tests/save-route-example.test.d.ts.map +1 -0
  174. package/dist/types/tests/saveRouteExample.test.d.ts +2 -0
  175. package/dist/types/tests/saveRouteExample.test.d.ts.map +1 -0
  176. package/dist/types/tests/seoConstants.test.d.ts +2 -0
  177. package/dist/types/tests/seoConstants.test.d.ts.map +1 -0
  178. package/dist/types/tests/site-health-accessibility.test.d.ts +2 -0
  179. package/dist/types/tests/site-health-accessibility.test.d.ts.map +1 -0
  180. package/dist/types/tests/site-health-cloudwatch.integration.test.d.ts +2 -0
  181. package/dist/types/tests/site-health-cloudwatch.integration.test.d.ts.map +1 -0
  182. package/dist/types/tests/site-health-dependency-vulnerabilities.test.d.ts +2 -0
  183. package/dist/types/tests/site-health-dependency-vulnerabilities.test.d.ts.map +1 -0
  184. package/dist/types/tests/site-health-github.test.d.ts +2 -0
  185. package/dist/types/tests/site-health-github.test.d.ts.map +1 -0
  186. package/dist/types/tests/site-health-google-analytics.integration.test.d.ts +2 -0
  187. package/dist/types/tests/site-health-google-analytics.integration.test.d.ts.map +1 -0
  188. package/dist/types/tests/site-health-google-analytics.test.d.ts +2 -0
  189. package/dist/types/tests/site-health-google-analytics.test.d.ts.map +1 -0
  190. package/dist/types/tests/site-health-google-search-console.integration.test.d.ts +2 -0
  191. package/dist/types/tests/site-health-google-search-console.integration.test.d.ts.map +1 -0
  192. package/dist/types/tests/site-health-google-search-console.test.d.ts +2 -0
  193. package/dist/types/tests/site-health-google-search-console.test.d.ts.map +1 -0
  194. package/dist/types/tests/site-health-mock-context.test.d.ts +2 -0
  195. package/dist/types/tests/site-health-mock-context.test.d.ts.map +1 -0
  196. package/dist/types/tests/site-health-on-site-seo.test.d.ts +2 -0
  197. package/dist/types/tests/site-health-on-site-seo.test.d.ts.map +1 -0
  198. package/dist/types/tests/site-health-performance.test.d.ts +2 -0
  199. package/dist/types/tests/site-health-performance.test.d.ts.map +1 -0
  200. package/dist/types/tests/site-health-security.integration.test.d.ts +2 -0
  201. package/dist/types/tests/site-health-security.integration.test.d.ts.map +1 -0
  202. package/dist/types/tests/site-health-security.test.d.ts +2 -0
  203. package/dist/types/tests/site-health-security.test.d.ts.map +1 -0
  204. package/dist/types/tests/site-health-seo.test.d.ts +2 -0
  205. package/dist/types/tests/site-health-seo.test.d.ts.map +1 -0
  206. package/dist/types/tests/site-health-uptime.integration.test.d.ts +2 -0
  207. package/dist/types/tests/site-health-uptime.integration.test.d.ts.map +1 -0
  208. package/dist/types/tests/site-health-uptime.test.d.ts +2 -0
  209. package/dist/types/tests/site-health-uptime.test.d.ts.map +1 -0
  210. package/dist/types/tests/siteHealthGaIntegration.test.d.ts +2 -0
  211. package/dist/types/tests/siteHealthGaIntegration.test.d.ts.map +1 -0
  212. package/dist/types/tests/siteHealthGscIntegration.test.d.ts +2 -0
  213. package/dist/types/tests/siteHealthGscIntegration.test.d.ts.map +1 -0
  214. package/dist/types/tests/spotify.components.test.d.ts +2 -0
  215. package/dist/types/tests/spotify.components.test.d.ts.map +1 -0
  216. package/dist/types/tests/spotify.functions.test.d.ts +2 -0
  217. package/dist/types/tests/spotify.functions.test.d.ts.map +1 -0
  218. package/dist/types/tests/test-utils.d.ts +7 -0
  219. package/dist/types/tests/test-utils.d.ts.map +1 -0
  220. package/dist/types/tests/usePageBuilder.test.d.ts +2 -0
  221. package/dist/types/tests/usePageBuilder.test.d.ts.map +1 -0
  222. package/package.json +34 -30
  223. package/dist/components/admin/site-health/site-health-google-analytics.integration.js +0 -6
  224. package/dist/components/admin/site-health/site-health-google-search-console.integration.js +0 -6
  225. package/dist/components/general/proxy-csp-listener.js +0 -20
  226. package/dist/scripts/create-pixelated-app-template-mapper.js +0 -80
  227. package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts +0 -6
  228. package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts.map +0 -1
  229. package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts +0 -6
  230. package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts.map +0 -1
  231. package/dist/types/components/general/proxy-csp-listener.d.ts +0 -15
  232. package/dist/types/components/general/proxy-csp-listener.d.ts.map +0 -1
  233. package/dist/types/scripts/create-pixelated-app-template-mapper.d.ts +0 -5
  234. package/dist/types/scripts/create-pixelated-app-template-mapper.d.ts.map +0 -1
  235. package/dist/types/stories/general/callout.many.stories.d.ts +0 -7
  236. package/dist/types/stories/general/callout.many.stories.d.ts.map +0 -1
  237. package/dist/types/stories/general/contentful.item.stories.d.ts +0 -12
  238. package/dist/types/stories/general/contentful.item.stories.d.ts.map +0 -1
  239. package/dist/types/stories/general/contentful.items.stories.d.ts.map +0 -1
  240. package/dist/types/stories/general/contentful.stories.d.ts.map +0 -1
  241. package/dist/types/stories/general/global-error.stories.d.ts +0 -26
  242. package/dist/types/stories/general/global-error.stories.d.ts.map +0 -1
  243. package/dist/types/stories/general/google.reviews.stories.d.ts.map +0 -1
  244. package/dist/types/stories/general/googleanalytics.stories.d.ts +0 -14
  245. package/dist/types/stories/general/googleanalytics.stories.d.ts.map +0 -1
  246. package/dist/types/stories/general/googlesearch.stories.d.ts.map +0 -1
  247. package/dist/types/stories/general/gravatar.stories.d.ts.map +0 -1
  248. package/dist/types/stories/general/instagram.stories.d.ts.map +0 -1
  249. package/dist/types/stories/general/loading.stories.d.ts +0 -11
  250. package/dist/types/stories/general/loading.stories.d.ts.map +0 -1
  251. package/dist/types/stories/general/metadata.stories.d.ts +0 -25
  252. package/dist/types/stories/general/metadata.stories.d.ts.map +0 -1
  253. package/dist/types/stories/general/schema.stories.d.ts +0 -62
  254. package/dist/types/stories/general/schema.stories.d.ts.map +0 -1
  255. package/dist/types/stories/general/sitemap.stories.d.ts +0 -8
  256. package/dist/types/stories/general/sitemap.stories.d.ts.map +0 -1
  257. package/dist/types/stories/general/wordpress.stories.d.ts.map +0 -1
  258. package/dist/types/stories/integrations/schema-podcast.stories.d.ts +0 -45
  259. package/dist/types/stories/integrations/schema-podcast.stories.d.ts.map +0 -1
  260. /package/dist/types/stories/{general → integrations}/contentful.items.stories.d.ts +0 -0
  261. /package/dist/types/stories/{general → integrations}/contentful.stories.d.ts +0 -0
  262. /package/dist/types/stories/{general → integrations}/google.reviews.stories.d.ts +0 -0
  263. /package/dist/types/stories/{general → integrations}/googlesearch.stories.d.ts +0 -0
  264. /package/dist/types/stories/{general → integrations}/gravatar.stories.d.ts +0 -0
  265. /package/dist/types/stories/{general → integrations}/instagram.stories.d.ts +0 -0
  266. /package/dist/types/stories/{general → integrations}/wordpress.stories.d.ts +0 -0
@@ -1,12 +1,15 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import { mergeDeep } from '../general/utilities';
3
+ // Flickr API base URL - non-secret configuration
4
+ const FLICKR_API_BASE_URL = 'https://api.flickr.com/services/rest/?';
3
5
  const defaultFlickr = {
4
6
  flickr: {
5
- baseURL: 'https://api.flickr.com/services/rest/?',
7
+ baseURL: FLICKR_API_BASE_URL,
6
8
  urlProps: {
7
9
  method: 'flickr.photos.search',
8
- api_key: '882cab5548d53c9e6b5fb24d59cc321d',
9
- user_id: '15473210@N04',
10
+ // api_key and user_id must come from props or config provider - do not hardcode
11
+ api_key: '',
12
+ user_id: '',
10
13
  tags: 'pixelatedviewsgallery',
11
14
  extras: 'date_taken,description,owner_name',
12
15
  sort: 'date-taken-desc',
@@ -168,7 +171,7 @@ FlickrWrapper.propTypes = {
168
171
  export function FlickrWrapper(props) {
169
172
  const flickr = {
170
173
  flickr: {
171
- baseURL: 'https://api.flickr.com/services/rest/?',
174
+ baseURL: FLICKR_API_BASE_URL,
172
175
  urlProps: {
173
176
  method: props.method || 'flickr.photos.search',
174
177
  api_key: props.api_key /* || '882cab5548d53c9e6b5fb24d59cc321d' */,
@@ -6,6 +6,9 @@ import { SmartImage } from '../general/smartimage';
6
6
  import { getGoogleReviewsByPlaceId } from './google.reviews.functions';
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
8
  import './google.reviews.css';
9
+ /*
10
+ https://maps.googleapis.com/maps/api/place/textsearch/json?query=Manning+Metalworks+Morris+Plains+NJ&key=AIzaSyBJVi0O9Ir9imRgINLZbojTifatX-Z4aUs
11
+ */
9
12
  /**
10
13
  * GoogleReviewsCard — Fetch and display Google Place reviews for a specific Place ID.
11
14
  *
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Google Places API Integration
3
+ * Handles autocomplete predictions and place details for address validation
4
+ */
5
+ /**
6
+ * GooglePlacesService — Thin service for Google Places API interactions using googleapis
7
+ */
8
+ export class GooglePlacesService {
9
+ apiKey = null;
10
+ sessionToken = null;
11
+ requestCache = new Map();
12
+ cacheTTL = 3600000; // 1 hour default
13
+ constructor(config) {
14
+ if (config) {
15
+ this.apiKey = config.apiKey || null;
16
+ this.cacheTTL = config.cacheTTL || 3600000;
17
+ }
18
+ this.sessionToken = this.generateSessionToken();
19
+ }
20
+ /**
21
+ * Generate or return cached session token for Places requests
22
+ */
23
+ generateSessionToken() {
24
+ return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
25
+ }
26
+ /**
27
+ * Get autocomplete predictions for a search input
28
+ * Uses Google Places Autocomplete API (web service version via googleapis)
29
+ */
30
+ async getPlacePredictions(input, config) {
31
+ if (!input || input.length < 2)
32
+ return [];
33
+ const cacheKey = `predictions_${input}`;
34
+ const cached = this.requestCache.get(cacheKey);
35
+ if (cached)
36
+ return cached;
37
+ try {
38
+ const apiKey = config?.googlePlaces?.apiKey || this.apiKey;
39
+ if (!apiKey) {
40
+ console.error('Google Places API key not configured');
41
+ return [];
42
+ }
43
+ const restrictions = config?.googlePlaces?.countryRestrictions || ['us'];
44
+ const componentFilter = restrictions.length > 0 ? `components=country:${restrictions.join('|country:')}` : '';
45
+ const apiUrl = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${encodeURIComponent(input)}&key=${apiKey}&sessiontoken=${this.sessionToken}&${componentFilter}`;
46
+ // Use global proxy to avoid CORS issues
47
+ const proxyURL = config?.global?.proxyUrl || '';
48
+ const url = proxyURL ? `${proxyURL}${encodeURIComponent(apiUrl)}` : apiUrl;
49
+ const response = await fetch(url);
50
+ const data = await response.json();
51
+ if (!data.predictions) {
52
+ return [];
53
+ }
54
+ const predictions = data.predictions.map((pred) => ({
55
+ placeId: pred.place_id,
56
+ mainText: pred.structured_formatting?.main_text || pred.description,
57
+ secondaryText: pred.structured_formatting?.secondary_text,
58
+ fullText: pred.description,
59
+ }));
60
+ // Cache for TTL
61
+ this.requestCache.set(cacheKey, predictions);
62
+ setTimeout(() => this.requestCache.delete(cacheKey), this.cacheTTL);
63
+ return predictions;
64
+ }
65
+ catch (error) {
66
+ console.error('Error fetching place predictions:', error);
67
+ return [];
68
+ }
69
+ }
70
+ /**
71
+ * Get detailed place information including address components
72
+ */
73
+ async getPlaceDetails(placeId, config) {
74
+ try {
75
+ const apiKey = config?.googlePlaces?.apiKey || this.apiKey;
76
+ if (!apiKey) {
77
+ console.error('Google Places API key not configured');
78
+ return null;
79
+ }
80
+ const apiUrl = `https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&key=${apiKey}&fields=address_component,formatted_address&sessiontoken=${this.sessionToken}`;
81
+ // Use global proxy to avoid CORS issues
82
+ const proxyURL = config?.global?.proxyUrl || '';
83
+ const url = proxyURL ? `${proxyURL}${encodeURIComponent(apiUrl)}` : apiUrl;
84
+ const response = await fetch(url);
85
+ const data = await response.json();
86
+ if (!data.result)
87
+ return null;
88
+ const result = data.result;
89
+ const addressComponents = result.address_components || [];
90
+ // Parse address components
91
+ const parsed = {
92
+ formattedAddress: result.formatted_address || '',
93
+ addressComponents: addressComponents,
94
+ };
95
+ // Extract standard address fields
96
+ for (const component of addressComponents) {
97
+ const types = component.types || [];
98
+ if (types.includes('street_number') || types.includes('route')) {
99
+ parsed.street1 = (parsed.street1 || '') + (component.long_name || '') + ' ';
100
+ }
101
+ else if (types.includes('locality')) {
102
+ parsed.city = component.long_name;
103
+ }
104
+ else if (types.includes('administrative_area_level_1')) {
105
+ parsed.state = component.short_name;
106
+ }
107
+ else if (types.includes('postal_code')) {
108
+ parsed.zip = component.long_name;
109
+ }
110
+ else if (types.includes('country')) {
111
+ parsed.country = component.short_name;
112
+ }
113
+ }
114
+ if (parsed.street1) {
115
+ parsed.street1 = parsed.street1.trim();
116
+ }
117
+ return parsed;
118
+ }
119
+ catch (error) {
120
+ console.error('Error fetching place details:', error);
121
+ return null;
122
+ }
123
+ }
124
+ /**
125
+ * Validate that address is in allowed country
126
+ */
127
+ isValidCountry(placeDetails, allowedCountries = ['US']) {
128
+ if (!placeDetails.country)
129
+ return false;
130
+ return allowedCountries.includes(placeDetails.country.toUpperCase());
131
+ }
132
+ /**
133
+ * Clear cached predictions
134
+ */
135
+ clearCache() {
136
+ this.requestCache.clear();
137
+ }
138
+ }
139
+ /**
140
+ * Factory function to get configured GooglePlacesService instance
141
+ */
142
+ export function getGooglePlacesService(config) {
143
+ return new GooglePlacesService(config);
144
+ }
@@ -42,19 +42,22 @@ SocialCards.propTypes = {
42
42
  };
43
43
  export function SocialCards(props) {
44
44
  const debug = false;
45
+ // Get config values from provider
46
+ const config = usePixelatedConfig();
47
+ const proxyURL = config?.global?.proxyUrl || 'https://proxy.pixelated.tech/prod/proxy';
45
48
  const [state, setState] = useState({
46
49
  loading: true,
47
50
  targetID: '#social',
48
51
  myCardData: [],
49
52
  mySocialCards: [],
50
53
  proxy: {
51
- proxyURL: 'https://proxy.pixelated.tech/prod/proxy',
54
+ proxyURL,
52
55
  proxyURLParam: 'url'
53
56
  },
54
57
  rss2json: {
55
58
  apiURL: 'https://api.rss2json.com/v1/api.json',
56
59
  apiURLParam: 'rss_url',
57
- apiKey: 'c3wsmqh4h1iydxxip3sgkr1jtk3brllbp61jc6yd'
60
+ apiKey: ''
58
61
  },
59
62
  toptal: {
60
63
  apiURL: 'https://www.toptal.com/developers/feed2json/convert',
@@ -8,6 +8,7 @@ import { PageGridItem } from '../general/semantic';
8
8
  import { getWordPressItems, getWordPressLastModified } from './wordpress.functions';
9
9
  import { Loading, ToggleLoading } from '../general/loading';
10
10
  import { CacheManager } from "../general/cache-manager";
11
+ import { getDomain } from '../general/utilities';
11
12
  import "./wordpress.css";
12
13
  import { SchemaBlogPosting } from '../general/schema';
13
14
  import { mapWordPressToBlogPosting } from '../general/schema.functions';
@@ -18,7 +19,7 @@ function decodeString(str) {
18
19
  return textarea.value;
19
20
  }
20
21
  const wpCacheTTL = 1000 * 60 * 60 * 24 * 7; // 1 week
21
- const wpCache = new CacheManager({ mode: 'local', ttl: wpCacheTTL, prefix: 'wp_' });
22
+ const wpCache = new CacheManager({ mode: 'local', ttl: wpCacheTTL, domain: getDomain(), namespace: 'wp' });
22
23
  const wpApiURL = "https://public-api.wordpress.com/rest/v1/sites/";
23
24
  /**
24
25
  * getCachedWordPressItems — Fetch posts from the WordPress REST API with caching. Checks local cache first and returns cached posts if available and not expired; otherwise fetches from the API, stores in cache, and returns the fresh data.
@@ -178,8 +178,8 @@ export function EbayListItem(props) {
178
178
  const itemURL = "./store/" + thisItem.legacyItemId;
179
179
  const itemURLTarget = "_self"; /* "_blank" */
180
180
  const itemImage = (props.cloudinaryProductEnv)
181
- ? getImg({ url: thisItem.thumbnailImages[0].imageUrl, product_env: props.cloudinaryProductEnv })
182
- : thisItem.thumbnailImages[0].imageUrl;
181
+ ? getImg({ url: thisItem.thumbnailImages?.[0]?.imageUrl || thisItem.image?.imageUrl || '', product_env: props.cloudinaryProductEnv })
182
+ : thisItem.thumbnailImages?.[0]?.imageUrl || thisItem.image?.imageUrl || '';
183
183
  const shoppingCartItem = getShoppingCartItem({ thisItem: thisItem, cloudinaryProductEnv: props.cloudinaryProductEnv, apiProps: apiProps });
184
184
  // CHANGE EBAY URL TO LOCAL EBAY ITEM DETAIL URL
185
185
  shoppingCartItem.itemURL = itemURL;
@@ -189,7 +189,7 @@ export function EbayListItem(props) {
189
189
  ? _jsx("a", { href: itemURL, target: itemURLTarget, rel: "noopener noreferrer", children: itemImageComponent })
190
190
  : (itemImageComponent) }), _jsxs("div", { className: "ebay-item-body grid-s5-e13", children: [_jsx("div", { className: "ebay-item-header", children: itemURL
191
191
  ? _jsx(EbayItemHeader, { url: itemURL, target: itemURLTarget, title: thisItem.title })
192
- : _jsx(EbayItemHeader, { title: thisItem.title }) }), _jsxs("div", { className: "ebay-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.legacyItemId] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.categories[0].categoryId == apiProps.itemCategory ? 1 : 10] }), _jsxs("div", { children: [_jsx("b", { children: "Condition: " }), thisItem.condition] }), _jsxs("div", { children: [_jsx("b", { children: "Seller: " }), thisItem.seller.username, " (", thisItem.seller.feedbackScore, ")", _jsx("br", {}), thisItem.seller.feedbackPercentage, "% positive"] }), _jsxs("div", { children: [_jsx("b", { children: "Buying Options: " }), thisItem.buyingOptions[0]] }), _jsxs("div", { children: [_jsx("b", { children: "Location: " }), thisItem.itemLocation.postalCode + ", " + thisItem.itemLocation.country] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.itemCreationDate] })] }), _jsx("div", { className: "ebay-item-price", children: itemURL
192
+ : _jsx(EbayItemHeader, { title: thisItem.title }) }), _jsxs("div", { className: "ebay-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.legacyItemId] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.categories?.[0]?.categoryId == apiProps.itemCategory ? 1 : 10] }), _jsxs("div", { children: [_jsx("b", { children: "Condition: " }), thisItem.condition] }), _jsxs("div", { children: [_jsx("b", { children: "Seller: " }), thisItem.seller?.username, " (", thisItem.seller?.feedbackScore, ")", _jsx("br", {}), thisItem.seller?.feedbackPercentage, "% positive"] }), _jsxs("div", { children: [_jsx("b", { children: "Buying Options: " }), thisItem.buyingOptions?.[0]] }), _jsxs("div", { children: [_jsx("b", { children: "Location: " }), thisItem.itemLocation?.postalCode + ", " + thisItem.itemLocation?.country] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.itemCreationDate] })] }), _jsx("div", { className: "ebay-item-price", children: itemURL
193
193
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.price.value + " " + thisItem.price.currency] })
194
194
  : "$" + thisItem.price.value + " " + thisItem.price.currency }), _jsx("br", {}), _jsxs("div", { className: "ebay-item-add-to-cart", children: [_jsx(ViewItemDetails, { href: "/store", itemID: thisItem.legacyItemId }), _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.legacyItemId })] })] })] }));
195
195
  }
@@ -253,7 +253,7 @@ export function EbayItemDetail(props) {
253
253
  const thisItem = { ...item };
254
254
  if (debug)
255
255
  console.log(thisItem);
256
- const images = thisItem.additionalImages.map((thisImage) => ({ image: (props.cloudinaryProductEnv)
256
+ const images = (thisItem.additionalImages || []).map((thisImage) => ({ image: (props.cloudinaryProductEnv)
257
257
  ? getImg({ url: thisImage.imageUrl, product_env: props.cloudinaryProductEnv })
258
258
  : thisImage.imageUrl }));
259
259
  const itemURL = undefined;
@@ -262,7 +262,7 @@ export function EbayItemDetail(props) {
262
262
  shoppingCartItem.itemURL = itemURL;
263
263
  return (_jsx(_Fragment, { children: _jsxs("div", { className: "ebay-item row-12col", children: [_jsx("div", { className: "ebay-item-header grid-s1-e13", children: itemURL
264
264
  ? _jsx(EbayItemHeader, { url: itemURL, title: thisItem.title })
265
- : _jsx(EbayItemHeader, { title: thisItem.title }) }), _jsx("br", {}), _jsx("div", { className: "ebay-item-photo-carousel grid-s1-e7", children: _jsx(Carousel, { cards: images, draggable: true, imgFit: "contain" }) }), _jsxs("div", { className: "grid-s7-e13", children: [_jsx("div", { className: "ebay-item-details grid12", children: _jsx("div", { dangerouslySetInnerHTML: { __html: thisItem.description.replace(/(<br\s*\/?>\s*){2,}/gi, '') } }) }), _jsx("br", {}), _jsxs("div", { className: "ebay-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.legacyItemId] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.categoryId == apiProps.itemCategory ? 1 : 10] }), _jsxs("div", { children: [_jsx("b", { children: "Category: " }), thisItem.categoryPath] }), _jsxs("div", { children: [_jsx("b", { children: "Condition: " }), thisItem.condition] }), _jsxs("div", { children: [_jsx("b", { children: "Seller: " }), thisItem.seller.username, " (", thisItem.seller.feedbackScore, ")", _jsx("br", {}), thisItem.seller.feedbackPercentage, "% positive"] }), _jsxs("div", { children: [_jsx("b", { children: "Buying Options: " }), thisItem.buyingOptions[0]] }), _jsxs("div", { children: [_jsx("b", { children: "Location: " }), thisItem.itemLocation.city + ", " + thisItem.itemLocation.stateOrProvince] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.itemCreationDate] }), _jsx("br", {})] }), _jsx("div", { className: "ebay-item-price", children: itemURL
265
+ : _jsx(EbayItemHeader, { title: thisItem.title }) }), _jsx("br", {}), _jsx("div", { className: "ebay-item-photo-carousel grid-s1-e7", children: _jsx(Carousel, { cards: images, draggable: true, imgFit: "contain" }) }), _jsxs("div", { className: "grid-s7-e13", children: [_jsx("div", { className: "ebay-item-details grid12", children: _jsx("div", { dangerouslySetInnerHTML: { __html: thisItem.description?.replace(/(<br\s*\/?>\s*){2,}/gi, '') || '' } }) }), _jsx("br", {}), _jsxs("div", { className: "ebay-item-details grid12", children: [_jsxs("div", { children: [_jsx("b", { children: "Item ID: " }), thisItem.legacyItemId] }), _jsxs("div", { children: [_jsx("b", { children: "Quantity: " }), thisItem.categoryId == apiProps.itemCategory ? 1 : 10] }), _jsxs("div", { children: [_jsx("b", { children: "Category: " }), thisItem.categoryPath] }), _jsxs("div", { children: [_jsx("b", { children: "Condition: " }), thisItem.condition] }), _jsxs("div", { children: [_jsx("b", { children: "Seller: " }), thisItem.seller?.username, " (", thisItem.seller?.feedbackScore, ")", _jsx("br", {}), thisItem.seller?.feedbackPercentage, "% positive"] }), _jsxs("div", { children: [_jsx("b", { children: "Buying Options: " }), thisItem.buyingOptions?.[0]] }), _jsxs("div", { children: [_jsx("b", { children: "Location: " }), thisItem.itemLocation?.city + ", " + thisItem.itemLocation?.stateOrProvince] }), _jsxs("div", { children: [_jsx("b", { children: "Listing Date: " }), thisItem.itemCreationDate] }), _jsx("br", {})] }), _jsx("div", { className: "ebay-item-price", children: itemURL
266
266
  ? _jsxs("a", { href: itemURL, target: itemURLTarget, rel: "noreferrer", children: ["$", thisItem.price.value + " " + thisItem.price.currency] })
267
267
  : "$" + thisItem.price.value + " " + thisItem.price.currency }), _jsx("br", {}), _jsx("div", { className: "ebay-item-add-to-cart", children: _jsx(AddToCartButton, { handler: addToShoppingCart, item: shoppingCartItem, itemID: thisItem.legacyItemId }) })] })] }) }));
268
268
  }
@@ -1,11 +1,13 @@
1
1
  import PropTypes from "prop-types";
2
2
  import { getCloudinaryRemoteFetchURL as getImg } from "../integrations/cloudinary";
3
3
  import { CacheManager } from "../general/cache-manager";
4
+ import { getDomain } from "../general/utilities";
4
5
  const debug = false;
5
- // Initialize eBay Cache (Session storage, 1 hour TTL)
6
+ // Initialize eBay Cache (Session storage, 1 hour TTL) — isolated per domain
6
7
  const ebayCache = new CacheManager({
7
8
  mode: 'session',
8
- prefix: 'ebay_',
9
+ domain: getDomain(),
10
+ namespace: 'ebay',
9
11
  ttl: 60 * 60 * 1000
10
12
  });
11
13
  /* ===== EBAY BROWSE API DOCUMENTATION =====
@@ -86,7 +88,7 @@ export function getShoppingCartItem(props) {
86
88
  ? thisItem.thumbnailImages[0].imageUrl
87
89
  : (thisItem.image && props.cloudinaryProductEnv)
88
90
  ? getImg({ url: thisItem.image.imageUrl, product_env: props.cloudinaryProductEnv })
89
- : thisItem.image.imageUrl,
91
+ : thisItem.image?.imageUrl || '',
90
92
  itemID: thisItem.legacyItemId,
91
93
  itemURL: thisItem.itemWebUrl,
92
94
  itemTitle: thisItem.title,
@@ -39,7 +39,7 @@ export function PayPal(props) {
39
39
  if (!isScriptSrc('https://www.paypal.com/sdk/js')) {
40
40
  document.head.appendChild(paypalScript);
41
41
  }
42
- return (_jsxs(_Fragment, { children: [_jsx("link", { rel: "stylesheet", type: "text/css", href: "https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css" }), _jsx("div", { id: "paypal-button-container", className: "paypal-button-container" })] }));
42
+ return (_jsxs(_Fragment, { children: [_jsx("link", { rel: "stylesheet", type: "text/css", fetchPriority: "high", href: "https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css" }), _jsx("div", { id: "paypal-button-container", className: "paypal-button-container" })] }));
43
43
  }
44
44
  export function initPayPalButton(props) {
45
45
  window.paypal.Buttons({
@@ -16,19 +16,18 @@
16
16
  "tooltip" : "Please enter your First and Last Name"
17
17
  }
18
18
  },{
19
- "component" : "FormInput",
19
+ "component" : "FormGooglePlacesInput",
20
20
  "props" : {
21
- "type" : "text",
22
21
  "id" : "street1",
23
22
  "name" : "street1",
24
23
  "defaultValue" : null,
25
- "placeholder": "Street Address",
24
+ "placeholder": "Street Address (start typing)",
26
25
  "autoComplete" : "street-address",
27
26
  "size" : "40",
28
27
  "display" : "horizontal",
29
28
  "required": true,
30
29
  "label" : "Street Address : ",
31
- "tooltip" : "Please enter your Street Address"
30
+ "tooltip" : "Start typing your street address and select from suggestions"
32
31
  }
33
32
  },{
34
33
  "component" : "FormInput",
@@ -79,7 +79,8 @@ export function ShoppingCart(props) {
79
79
  useEffect(() => {
80
80
  // UPDATE DISCOUNT CODES ON EACH PAGE LOAD
81
81
  (async () => {
82
- setDiscountCodes(await getRemoteDiscountCodes());
82
+ const contentfulConfig = config?.contentful;
83
+ setDiscountCodes(await getRemoteDiscountCodes(contentfulConfig));
83
84
  })();
84
85
  // UPDATE SHOPPINGCART AND SHIPPINGDATA STATES IF LOCALSTORAGE CHANGES
85
86
  function handleStorageChange() {
@@ -146,10 +147,11 @@ export function ShoppingCart(props) {
146
147
  }
147
148
  if (progressStep === "ThankYou") {
148
149
  // ========== SENDMAIL ==========
150
+ const cartConfig = config?.shoppingcart;
149
151
  const json = {
150
- 'to': 'brian@pixelvivid.com',
151
- 'from': 'brian@pixelvivid.com',
152
- 'subject': 'PixelVivid Purchase',
152
+ 'to': cartConfig?.orderTo,
153
+ 'from': cartConfig?.orderFrom,
154
+ 'subject': cartConfig?.orderSubject,
153
155
  'orderData': JSON.stringify(orderData, null, 2),
154
156
  };
155
157
  const sendMailResponse = emailJSON(json);
@@ -157,7 +159,7 @@ export function ShoppingCart(props) {
157
159
  console.log("SendMail Response:", sendMailResponse);
158
160
  // ========== THANK YOU ==========
159
161
  const pmt = orderData.purchase_units[0].payments.captures[0];
160
- return (_jsxs("div", { className: "pix-cart", children: [_jsx(CalloutHeader, { title: "Shopping Cart : " }), _jsx("br", {}), _jsx("div", { id: "paypal-button-container", className: "paypal-button-container" }), _jsxs("div", { children: [_jsx("h3", { children: "Thank you for your payment!" }), "Payment ID : ", pmt.id, " ", _jsx("br", {}), "Status : ", pmt.status, " ", _jsx("br", {}), "Amount : $", pmt.amount.value + " " + pmt.amount.currency_code, " ", _jsx("br", {}), "Created : ", pmt.create_time, " ", _jsx("br", {})] })] }));
162
+ return (_jsxs("div", { className: "pix-cart", children: [_jsx(CalloutHeader, { title: "Shopping Cart : " }), _jsx("br", {}), _jsx("div", { id: "paypal-button-container", className: "paypal-button-container" }), _jsxs("div", { children: [_jsx("h3", { children: "Thank you for your payment!" }), "Payment ID : ", pmt.id, " ", _jsx("br", {}), "Status : ", pmt.status, " ", _jsx("br", {}), "Amount : $", pmt.amount.value + " " + (config?.shoppingcart?.currency || pmt.amount.currency_code), " ", _jsx("br", {}), "Created : ", pmt.create_time, " ", _jsx("br", {})] })] }));
161
163
  }
162
164
  else if (progressStep === "Checkout") {
163
165
  // ========== CHECKOUT ==========
@@ -92,7 +92,7 @@
92
92
  .pix-cart-button,
93
93
  .pix-cart .pix-cart-button,
94
94
  #pix-cart-button.pix-cart-button {
95
- font-size: 1.1em;
95
+ /* font-size: 1.1em; */
96
96
  font-family: Verdana, Geneva, sans-serif;
97
97
  color: #000;
98
98
  padding: 5px;
@@ -1,24 +1,15 @@
1
1
  import { getContentfulDiscountCodes } from "../integrations/contentful.delivery";
2
2
  import { CacheManager } from "../general/cache-manager";
3
+ import { getDomain } from "../general/utilities";
3
4
  // Migration-time verbose tracing per user request — remove after verification
4
5
  const debug = false;
5
- // Use CacheManager but preserve existing localStorage keys by using empty prefix
6
- const cartCache = new CacheManager({ mode: 'local', prefix: '' });
6
+ // Use CacheManager with domain + namespace to prevent multi-tenant cache collisions
7
+ const cartCache = new CacheManager({ mode: 'local', domain: getDomain(), namespace: 'checkout' });
7
8
  /* ========== LOCALSTORAGE KEYS ========== */
8
9
  export const shoppingCartKey = "pixelvividCart";
9
10
  export const shippingInfoKey = "pixelvividCartShipping";
10
11
  export const discountCodesKey = "pixelvividDiscountCodes";
11
12
  export const checkoutInfoKey = "pixelvividCartCheckout";
12
- // const sbPayPalApiKey = "AT10GG2ZHoApTtEw7dJoU6XRDYkf3wEvK2k_-eZ9GOvOK-REphG8yKCyZCqFi95OrxKgrdctlfWxayHG";
13
- // const sbPayPalSecret = "EDUrdPonwcNYZwO5j7hNmFSmF-13zptaCndUnO0-Vr_j0GYEW4m-Tfar9IaukHwm0ixL5fUojOOFtZVk";
14
- // const payPalApiKey = "AeWRwYpsrfslATCndF6xjL4GLcqA1UxQZLC5vxQE-FTvPezXfLbCJO_uAFk5zoXUKRFnP-zJ_73yEkBE";
15
- // const payPalSecret = "EBvYvynRXZCI6RbK4rg2NiENNG4N8tbgl8qAmpxB6f9nUkZjXMODxXJZ91JycP439kPrQcnB7uRKp0-F";
16
- const apiProps = {
17
- base_url: "https://cdn.contentful.com",
18
- space_id: "soi9w77t7027",
19
- environment: "master",
20
- delivery_access_token: "muY9LfpCt4qoXosDsnRkkoH3DAVVuUFEuB0WRKRdBUM",
21
- };
22
13
  /* ========== ARRAYS ========== */
23
14
  const shippingOptions = [
24
15
  {
@@ -209,7 +200,7 @@ export function getShippingCost() {
209
200
  return (option && option.price) ? formatAsHundredths(Number(option.price)) : 0;
210
201
  }
211
202
  /* ========== DISCOUNT CODE FUNCTIONS ========== */
212
- export async function validateDiscountCode(field) {
203
+ export async function validateDiscountCode(field, apiProps) {
213
204
  try {
214
205
  const codeList = await getContentfulDiscountCodes({ apiProps: apiProps, contentType: "discountCodes" });
215
206
  if (!codeList) {
@@ -240,7 +231,7 @@ export async function validateDiscountCode(field) {
240
231
  throw error; // Or return false;
241
232
  }
242
233
  }
243
- export async function getRemoteDiscountCodes() {
234
+ export async function getRemoteDiscountCodes(apiProps) {
244
235
  if (debug)
245
236
  console.log("Getting Contentful Discount Codes");
246
237
  try {
@@ -79,7 +79,7 @@ export function VisualDesignStyles({ visualdesign }) {
79
79
  ...fontLines
80
80
  ].join('\n');
81
81
  const googleFontsUsed = hasGoogleFonts();
82
- return (_jsxs(_Fragment, { children: [googleFontsUsed && (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" })] })), _jsx("style", { dangerouslySetInnerHTML: { __html: css } })] }));
82
+ return (_jsxs(_Fragment, { children: [googleFontsUsed && (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", fetchPriority: "high", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", fetchPriority: "high", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" })] })), _jsx("style", { dangerouslySetInnerHTML: { __html: css } })] }));
83
83
  }
84
84
  /**
85
85
  * Component to handle Google Fonts imports - should be used in the document head
@@ -99,5 +99,5 @@ export function GoogleFontsImports({ visualdesign }) {
99
99
  const googleFontsUrl = generateGoogleFontsUrl(fonts);
100
100
  if (!googleFontsUrl)
101
101
  return null;
102
- return (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { href: googleFontsUrl, rel: "stylesheet" })] }));
102
+ return (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", fetchPriority: "high", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", fetchPriority: "high", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { rel: "stylesheet", fetchPriority: "high", href: googleFontsUrl })] }));
103
103
  }
@@ -108,7 +108,7 @@ export function generateGoogleFontsLink(fonts) {
108
108
  const url = generateGoogleFontsUrl(fonts);
109
109
  if (!url)
110
110
  return '';
111
- return `<link rel="preconnect" href="https://fonts.googleapis.com">
112
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
113
- <link href="${url}" rel="stylesheet">`;
111
+ return `<link rel="preconnect" fetchPriority="high" href="https://fonts.googleapis.com">
112
+ <link rel="preconnect" fetchPriority="high" href="https://fonts.gstatic.com" crossorigin>
113
+ <link rel="stylesheet" fetchPriority="high" href="${url}">`;
114
114
  }
@@ -5,6 +5,7 @@ import PropTypes from "prop-types";
5
5
  import { validateField } from "./formvalidator";
6
6
  import { useFormValidation } from "./formvalidator";
7
7
  import * as FVF from "./formfieldvalidations";
8
+ import { usePixelatedConfig } from "../../config/config.client";
8
9
  import "./form.css";
9
10
  /*
10
11
  InferProps to generate Types
@@ -168,6 +169,156 @@ function FormTooltip(props) {
168
169
  let clickHandler = toggleTooltip;
169
170
  return (_jsx(_Fragment, { children: _jsxs("div", { id: mode + "-" + props.id, className: `tooltip-container ${props.className || ''}`, children: [_jsx("span", { className: "tooltip-icon tooltip-icon-" + mode, ...mouseEvents, onClick: clickHandler, onKeyDown: handleKeyDown, "aria-label": "Show more info", "aria-expanded": showTooltip, "aria-describedby": showTooltip ? `${props.id}-tooltip` : undefined, tabIndex: 0, role: "button", children: icon }), showTooltip && _jsx("div", { className: "tooltip-text", role: "tooltip", id: `${props.id}-tooltip`, children: content })] }) }));
170
171
  }
172
+ /**
173
+ * FormGooglePlacesInput — Address input with Google Places autocomplete and address component parsing.
174
+ *
175
+ * @param {string} [props.id] - Input id attribute (required).
176
+ * @param {string} [props.name] - Input name attribute.
177
+ * @param {string} [props.defaultValue] - Default value for uncontrolled inputs.
178
+ * @param {string} [props.placeholder] - Placeholder text.
179
+ * @param {string} [props.autoComplete] - Autocomplete hint.
180
+ * @param {string} [props.size] - Size attribute for text input.
181
+ * @param {string} [props.maxLength] - Maximum characters allowed.
182
+ * @param {string} [props.required] - Required flag.
183
+ * @param {string} [props.display] - Display style (inline/block) for layout purposes.
184
+ * @param {string} [props.label] - Label text associated with the input.
185
+ * @param {string} [props.tooltip] - Tooltip/help text for the input.
186
+ * @param {string} [props.className] - CSS class names applied to the input container.
187
+ * @param {string} [props.validate] - Named validation rule to run for this input.
188
+ * @param {function} [props.onChange] - Change handler invoked when place is selected.
189
+ * @param {function} [props.onAddressParsed] - Callback invoked with parsed address components when place is selected.
190
+ */
191
+ FormGooglePlacesInput.propTypes = {
192
+ id: PropTypes.string.isRequired,
193
+ name: PropTypes.string,
194
+ defaultValue: PropTypes.string,
195
+ placeholder: PropTypes.string,
196
+ autoComplete: PropTypes.string,
197
+ size: PropTypes.string,
198
+ maxLength: PropTypes.string,
199
+ required: PropTypes.string,
200
+ disabled: PropTypes.string,
201
+ display: PropTypes.string,
202
+ label: PropTypes.string,
203
+ tooltip: PropTypes.string,
204
+ className: PropTypes.string,
205
+ validate: PropTypes.string,
206
+ onChange: PropTypes.func,
207
+ onAddressParsed: PropTypes.func,
208
+ };
209
+ export function FormGooglePlacesInput(props) {
210
+ const [inputValue, setInputValue] = React.useState(props.defaultValue || '');
211
+ const [predictions, setPredictions] = React.useState([]);
212
+ const [showPredictions, setShowPredictions] = React.useState(false);
213
+ const [isLoading, setIsLoading] = React.useState(false);
214
+ const { formValidate, inputProps } = useFormComponent(props);
215
+ const config = usePixelatedConfig();
216
+ const debounceTimer = React.useRef(null);
217
+ const inputRef = React.useRef(null);
218
+ // Debounced fetch predictions
219
+ const fetchPredictions = React.useCallback(async (input) => {
220
+ if (!input || input.length < 2) {
221
+ setPredictions([]);
222
+ setShowPredictions(false);
223
+ return;
224
+ }
225
+ setIsLoading(true);
226
+ try {
227
+ const { getGooglePlacesService } = await import('../../integrations/googleplaces');
228
+ const service = getGooglePlacesService(config);
229
+ const results = await service.getPlacePredictions(input, config);
230
+ setPredictions(results);
231
+ setShowPredictions(true);
232
+ }
233
+ catch (error) {
234
+ console.error('Error fetching predictions:', error);
235
+ setPredictions([]);
236
+ }
237
+ finally {
238
+ setIsLoading(false);
239
+ }
240
+ }, [config]);
241
+ // Handle input change with debounce
242
+ const handleInputChange = (e) => {
243
+ const value = e.target.value;
244
+ setInputValue(value);
245
+ // Call parent onChange
246
+ if (props.onChange) {
247
+ props.onChange(value);
248
+ }
249
+ // Clear previous timer
250
+ if (debounceTimer.current) {
251
+ clearTimeout(debounceTimer.current);
252
+ }
253
+ // Set new debounced fetch
254
+ debounceTimer.current = setTimeout(() => fetchPredictions(value), config?.googlePlaces?.debounceDelay || 300);
255
+ };
256
+ // Handle place selection
257
+ const handleSelectPlace = React.useCallback(async (prediction) => {
258
+ setInputValue(prediction.fullText);
259
+ setShowPredictions(false);
260
+ try {
261
+ const { getGooglePlacesService } = await import('../../integrations/googleplaces');
262
+ const service = getGooglePlacesService(config);
263
+ const details = await service.getPlaceDetails(prediction.placeId, config);
264
+ if (details && service.isValidCountry(details, config?.googlePlaces?.countryRestrictions)) {
265
+ // Auto-fill address components
266
+ if (props.onAddressParsed) {
267
+ props.onAddressParsed({
268
+ street1: details.street1,
269
+ city: details.city,
270
+ state: details.state,
271
+ zip: details.zip,
272
+ country: details.country,
273
+ });
274
+ }
275
+ // Update form fields if available
276
+ const form = (inputRef.current?.closest('form') || document.getElementById('address_to'));
277
+ if (form) {
278
+ if (details.city) {
279
+ const cityElement = form.elements.namedItem('city');
280
+ if (cityElement)
281
+ cityElement.value = details.city;
282
+ }
283
+ if (details.state) {
284
+ const stateElement = form.elements.namedItem('state');
285
+ if (stateElement)
286
+ stateElement.value = details.state;
287
+ }
288
+ if (details.zip) {
289
+ const zipElement = form.elements.namedItem('zip');
290
+ if (zipElement)
291
+ zipElement.value = details.zip;
292
+ }
293
+ if (details.country) {
294
+ const countryElement = form.elements.namedItem('country');
295
+ if (countryElement)
296
+ countryElement.value = details.country;
297
+ }
298
+ }
299
+ }
300
+ else {
301
+ console.warn('Selected address is not in allowed countries');
302
+ }
303
+ }
304
+ catch (error) {
305
+ console.error('Error fetching place details:', error);
306
+ }
307
+ }, [config, props]);
308
+ // Close predictions on blur
309
+ const handleBlur = () => {
310
+ setTimeout(() => setShowPredictions(false), 200);
311
+ };
312
+ // Cleanup timer on unmount
313
+ React.useEffect(() => {
314
+ return () => {
315
+ if (debounceTimer.current) {
316
+ clearTimeout(debounceTimer.current);
317
+ }
318
+ };
319
+ }, []);
320
+ return (_jsxs("div", { className: `form-google-places-input ${props.className || ''}`, children: [_jsx(FormLabel, { id: props.id, label: props.label }, "label-" + props.id), props.tooltip ? _jsx(FormTooltip, { id: props.id, text: [props.tooltip] }) : "", props.display === "vertical" ? formValidate : "", _jsxs("div", { className: "google-places-container", children: [_jsx("input", { ref: inputRef, ...inputProps, role: "combobox", type: "text", value: inputValue, onChange: handleInputChange, onBlur: handleBlur, placeholder: props.placeholder || "Start typing an address...", autoComplete: "off", "aria-autocomplete": "list", "aria-controls": `${props.id}-predictions`, "aria-expanded": showPredictions, defaultValue: undefined }), isLoading && _jsx("div", { className: "google-places-loading", children: "Loading..." }), showPredictions && predictions.length > 0 && (_jsx("ul", { id: `${props.id}-predictions`, className: "google-places-predictions", role: "listbox", children: predictions.map((pred, idx) => (_jsx("li", { role: "option", "aria-selected": false, children: _jsxs("button", { type: "button", onClick: () => handleSelectPlace(pred), className: "prediction-item", children: [_jsx("strong", { children: pred.mainText }), pred.secondaryText && _jsx("small", { children: pred.secondaryText })] }) }, idx))) }))] })] }));
321
+ }
171
322
  /**
172
323
  * FormInput — Generic input field used by the FormEngine. Supports standard input attributes and validation hooks.
173
324
  *
@@ -3,6 +3,9 @@ const debug = false;
3
3
  * Maps input type to form component name
4
4
  */
5
5
  export function mapTypeToComponent(myType) {
6
+ if (!myType) {
7
+ throw new Error('Field type is required');
8
+ }
6
9
  if (debug)
7
10
  console.log("Mapping Type Field to Component");
8
11
  let myComponent = (["button"].includes(myType)) ? 'FormButton' :