@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.
- package/dist/components/admin/site-health/google.api.integration.js +5 -4
- package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +3 -2
- package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +1 -3
- package/dist/components/config/crypto.js +17 -1
- package/dist/components/general/404.js +1 -1
- package/dist/components/general/cache-manager.js +19 -2
- package/dist/components/general/callout.js +1 -1
- package/dist/components/general/carousel.drag.js +21 -24
- package/dist/components/general/carousel.js +3 -3
- package/dist/components/general/countup.js +1 -1
- package/dist/components/general/intersection-observer.js +4 -0
- package/dist/components/general/metadata.functions.js +2 -2
- package/dist/components/general/proxy-handler.js +2 -2
- package/dist/components/general/semantic.js +3 -6
- package/dist/components/general/sitemap.js +2 -1
- package/dist/components/general/smartimage.js +2 -4
- package/dist/components/general/styleguide.js +1 -1
- package/dist/components/general/tiles.js +2 -2
- package/dist/components/general/timeline.js +1 -1
- package/dist/components/general/utilities.js +68 -0
- package/dist/components/integrations/contentful.delivery.js +16 -16
- package/dist/components/integrations/contentful.items.components.js +2 -11
- package/dist/components/integrations/flickr.js +7 -4
- package/dist/components/integrations/google.reviews.components.js +3 -0
- package/dist/components/integrations/googleplaces.js +144 -0
- package/dist/components/integrations/socialcard.js +5 -2
- package/dist/components/integrations/wordpress.components.js +2 -1
- package/dist/components/shoppingcart/ebay.components.js +5 -5
- package/dist/components/shoppingcart/ebay.functions.js +5 -3
- package/dist/components/shoppingcart/paypal.js +1 -1
- package/dist/components/shoppingcart/shipping.to.json +3 -4
- package/dist/components/shoppingcart/shoppingcart.components.js +7 -5
- package/dist/components/shoppingcart/shoppingcart.css +1 -1
- package/dist/components/shoppingcart/shoppingcart.functions.js +5 -14
- package/dist/components/sitebuilder/config/ConfigEngine.js +2 -2
- package/dist/components/sitebuilder/config/google-fonts.js +3 -3
- package/dist/components/sitebuilder/form/formcomponents.js +151 -0
- package/dist/components/sitebuilder/form/formutils.js +3 -0
- package/dist/components/sitebuilder/page/lib/pageStorageContentful.js +2 -2
- package/dist/config/pixelated.config.json.enc +1 -1
- package/dist/data/form.json +18 -0
- package/dist/index.adminserver.js +1 -3
- package/dist/index.js +1 -1
- package/dist/index.server.js +1 -0
- package/dist/scripts/create-pixelated-app.js +187 -79
- package/dist/scripts/create-pixelated-app.json +56 -1
- package/dist/scripts/pixelated-eslint-plugin.js +142 -0
- package/dist/scripts/release.sh +14 -1
- package/dist/scripts/update.sh +2 -0
- package/dist/types/components/admin/deploy/deployment.integration.d.ts +1 -0
- package/dist/types/components/admin/deploy/deployment.integration.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/google.api.integration.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
- package/dist/types/components/config/config.types.d.ts +24 -0
- package/dist/types/components/config/config.types.d.ts.map +1 -1
- package/dist/types/components/config/crypto.d.ts +1 -0
- package/dist/types/components/config/crypto.d.ts.map +1 -1
- package/dist/types/components/general/404.d.ts.map +1 -1
- package/dist/types/components/general/cache-manager.d.ts +16 -2
- package/dist/types/components/general/cache-manager.d.ts.map +1 -1
- package/dist/types/components/general/callout.d.ts.map +1 -1
- package/dist/types/components/general/carousel.drag.d.ts.map +1 -1
- package/dist/types/components/general/intersection-observer.d.ts.map +1 -1
- package/dist/types/components/general/sitemap.d.ts.map +1 -1
- package/dist/types/components/general/smartimage.d.ts.map +1 -1
- package/dist/types/components/general/utilities.d.ts +37 -0
- package/dist/types/components/general/utilities.d.ts.map +1 -1
- package/dist/types/components/integrations/contentful.delivery.d.ts +16 -16
- package/dist/types/components/integrations/contentful.items.components.d.ts.map +1 -1
- package/dist/types/components/integrations/flickr.d.ts.map +1 -1
- package/dist/types/components/integrations/google.reviews.components.d.ts.map +1 -1
- package/dist/types/components/integrations/googleplaces.d.ts +61 -0
- package/dist/types/components/integrations/googleplaces.d.ts.map +1 -0
- package/dist/types/components/integrations/socialcard.d.ts.map +1 -1
- package/dist/types/components/integrations/wordpress.components.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +2 -2
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formcomponents.d.ts +22 -0
- package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -1
- package/dist/types/index.adminserver.d.ts +1 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.server.d.ts +1 -0
- package/dist/types/scripts/create-pixelated-app.d.ts +3 -0
- package/dist/types/scripts/create-pixelated-app.d.ts.map +1 -1
- package/dist/types/scripts/pixelated-eslint-plugin.d.ts +20 -0
- package/dist/types/stories/integrations/contentful.items.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/contentful.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/google.reviews.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/googlesearch.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/gravatar.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/instagram.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/wordpress.stories.d.ts.map +1 -0
- package/dist/types/test/test-utils.d.ts +2 -0
- package/dist/types/test/test-utils.d.ts.map +1 -1
- package/dist/types/tests/404.test.d.ts +2 -0
- package/dist/types/tests/404.test.d.ts.map +1 -0
- package/dist/types/tests/carousel.drag.test.d.ts +2 -0
- package/dist/types/tests/carousel.drag.test.d.ts.map +1 -0
- package/dist/types/tests/carouselDrag.test.d.ts +2 -0
- package/dist/types/tests/carouselDrag.test.d.ts.map +1 -0
- package/dist/types/tests/componentAnalysis.test.d.ts +2 -0
- package/dist/types/tests/componentAnalysis.test.d.ts.map +1 -0
- package/dist/types/tests/componentDiscovery.test.d.ts +2 -0
- package/dist/types/tests/componentDiscovery.test.d.ts.map +1 -0
- package/dist/types/tests/componentMap.test.d.ts +2 -0
- package/dist/types/tests/componentMap.test.d.ts.map +1 -0
- package/dist/types/tests/contentful.items.components.test.d.ts +2 -0
- package/dist/types/tests/contentful.items.components.test.d.ts.map +1 -0
- package/dist/types/tests/contentful.management.test.d.ts +2 -0
- package/dist/types/tests/contentful.management.test.d.ts.map +1 -0
- package/dist/types/tests/contentfulManagement.test.d.ts +2 -0
- package/dist/types/tests/contentfulManagement.test.d.ts.map +1 -0
- package/dist/types/tests/countup.test.d.ts +2 -0
- package/dist/types/tests/countup.test.d.ts.map +1 -0
- package/dist/types/tests/crypto.test.d.ts +2 -0
- package/dist/types/tests/crypto.test.d.ts.map +1 -0
- package/dist/types/tests/deployment.integration.test.d.ts +2 -0
- package/dist/types/tests/deployment.integration.test.d.ts.map +1 -0
- package/dist/types/tests/ebay.components.test.d.ts +2 -0
- package/dist/types/tests/ebay.components.test.d.ts.map +1 -0
- package/dist/types/tests/ebayComponents.test.d.ts +2 -0
- package/dist/types/tests/ebayComponents.test.d.ts.map +1 -0
- package/dist/types/tests/flickr.test.d.ts +2 -0
- package/dist/types/tests/flickr.test.d.ts.map +1 -0
- package/dist/types/tests/formgoogleplacesinput.test.d.ts +2 -0
- package/dist/types/tests/formgoogleplacesinput.test.d.ts.map +1 -0
- package/dist/types/tests/formutils.test.d.ts +2 -0
- package/dist/types/tests/formutils.test.d.ts.map +1 -0
- package/dist/types/tests/formvalidator.test.d.ts +2 -0
- package/dist/types/tests/formvalidator.test.d.ts.map +1 -0
- package/dist/types/tests/gemini-api.client.test.d.ts +2 -0
- package/dist/types/tests/gemini-api.client.test.d.ts.map +1 -0
- package/dist/types/tests/gemini-api.server.test.d.ts +2 -0
- package/dist/types/tests/gemini-api.server.test.d.ts.map +1 -0
- package/dist/types/tests/geminiApi.test.d.ts +2 -0
- package/dist/types/tests/geminiApi.test.d.ts.map +1 -0
- package/dist/types/tests/google.reviews.components.test.d.ts +2 -0
- package/dist/types/tests/google.reviews.components.test.d.ts.map +1 -0
- package/dist/types/tests/googleanalytics.test.d.ts +2 -0
- package/dist/types/tests/googleanalytics.test.d.ts.map +1 -0
- package/dist/types/tests/googlemap.test.d.ts +2 -0
- package/dist/types/tests/googlemap.test.d.ts.map +1 -0
- package/dist/types/tests/gravatar.functions.test.d.ts +2 -0
- package/dist/types/tests/gravatar.functions.test.d.ts.map +1 -0
- package/dist/types/tests/hubspot.components.test.d.ts +2 -0
- package/dist/types/tests/hubspot.components.test.d.ts.map +1 -0
- package/dist/types/tests/image-utils.test.d.ts +2 -0
- package/dist/types/tests/image-utils.test.d.ts.map +1 -0
- package/dist/types/tests/instagram.components.test.d.ts +2 -0
- package/dist/types/tests/instagram.components.test.d.ts.map +1 -0
- package/dist/types/tests/instagram.functions.test.d.ts +2 -0
- package/dist/types/tests/instagram.functions.test.d.ts.map +1 -0
- package/dist/types/tests/intersection-observer.test.d.ts +2 -0
- package/dist/types/tests/intersection-observer.test.d.ts.map +1 -0
- package/dist/types/tests/metadata.functions.test.d.ts +2 -0
- package/dist/types/tests/metadata.functions.test.d.ts.map +1 -0
- package/dist/types/tests/metadataComponents.test.d.ts +2 -0
- package/dist/types/tests/metadataComponents.test.d.ts.map +1 -0
- package/dist/types/tests/page-storage.test.d.ts +2 -0
- package/dist/types/tests/page-storage.test.d.ts.map +1 -0
- package/dist/types/tests/pageStorageContentful.test.d.ts +2 -0
- package/dist/types/tests/pageStorageContentful.test.d.ts.map +1 -0
- package/dist/types/tests/pageStorageLocal.test.d.ts +2 -0
- package/dist/types/tests/pageStorageLocal.test.d.ts.map +1 -0
- package/dist/types/tests/pixelated.test.d.ts +2 -0
- package/dist/types/tests/pixelated.test.d.ts.map +1 -0
- package/dist/types/tests/propTypeIntrospection.test.d.ts +2 -0
- package/dist/types/tests/propTypeIntrospection.test.d.ts.map +1 -0
- package/dist/types/tests/save-route-example.test.d.ts +2 -0
- package/dist/types/tests/save-route-example.test.d.ts.map +1 -0
- package/dist/types/tests/saveRouteExample.test.d.ts +2 -0
- package/dist/types/tests/saveRouteExample.test.d.ts.map +1 -0
- package/dist/types/tests/seoConstants.test.d.ts +2 -0
- package/dist/types/tests/seoConstants.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-accessibility.test.d.ts +2 -0
- package/dist/types/tests/site-health-accessibility.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-cloudwatch.integration.test.d.ts +2 -0
- package/dist/types/tests/site-health-cloudwatch.integration.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-dependency-vulnerabilities.test.d.ts +2 -0
- package/dist/types/tests/site-health-dependency-vulnerabilities.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-github.test.d.ts +2 -0
- package/dist/types/tests/site-health-github.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-google-analytics.integration.test.d.ts +2 -0
- package/dist/types/tests/site-health-google-analytics.integration.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-google-analytics.test.d.ts +2 -0
- package/dist/types/tests/site-health-google-analytics.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-google-search-console.integration.test.d.ts +2 -0
- package/dist/types/tests/site-health-google-search-console.integration.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-google-search-console.test.d.ts +2 -0
- package/dist/types/tests/site-health-google-search-console.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-mock-context.test.d.ts +2 -0
- package/dist/types/tests/site-health-mock-context.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-on-site-seo.test.d.ts +2 -0
- package/dist/types/tests/site-health-on-site-seo.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-performance.test.d.ts +2 -0
- package/dist/types/tests/site-health-performance.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-security.integration.test.d.ts +2 -0
- package/dist/types/tests/site-health-security.integration.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-security.test.d.ts +2 -0
- package/dist/types/tests/site-health-security.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-seo.test.d.ts +2 -0
- package/dist/types/tests/site-health-seo.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-uptime.integration.test.d.ts +2 -0
- package/dist/types/tests/site-health-uptime.integration.test.d.ts.map +1 -0
- package/dist/types/tests/site-health-uptime.test.d.ts +2 -0
- package/dist/types/tests/site-health-uptime.test.d.ts.map +1 -0
- package/dist/types/tests/siteHealthGaIntegration.test.d.ts +2 -0
- package/dist/types/tests/siteHealthGaIntegration.test.d.ts.map +1 -0
- package/dist/types/tests/siteHealthGscIntegration.test.d.ts +2 -0
- package/dist/types/tests/siteHealthGscIntegration.test.d.ts.map +1 -0
- package/dist/types/tests/spotify.components.test.d.ts +2 -0
- package/dist/types/tests/spotify.components.test.d.ts.map +1 -0
- package/dist/types/tests/spotify.functions.test.d.ts +2 -0
- package/dist/types/tests/spotify.functions.test.d.ts.map +1 -0
- package/dist/types/tests/test-utils.d.ts +7 -0
- package/dist/types/tests/test-utils.d.ts.map +1 -0
- package/dist/types/tests/usePageBuilder.test.d.ts +2 -0
- package/dist/types/tests/usePageBuilder.test.d.ts.map +1 -0
- package/package.json +34 -30
- package/dist/components/admin/site-health/site-health-google-analytics.integration.js +0 -6
- package/dist/components/admin/site-health/site-health-google-search-console.integration.js +0 -6
- package/dist/components/general/proxy-csp-listener.js +0 -20
- package/dist/scripts/create-pixelated-app-template-mapper.js +0 -80
- package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts +0 -6
- package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts.map +0 -1
- package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts +0 -6
- package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts.map +0 -1
- package/dist/types/components/general/proxy-csp-listener.d.ts +0 -15
- package/dist/types/components/general/proxy-csp-listener.d.ts.map +0 -1
- package/dist/types/scripts/create-pixelated-app-template-mapper.d.ts +0 -5
- package/dist/types/scripts/create-pixelated-app-template-mapper.d.ts.map +0 -1
- package/dist/types/stories/general/callout.many.stories.d.ts +0 -7
- package/dist/types/stories/general/callout.many.stories.d.ts.map +0 -1
- package/dist/types/stories/general/contentful.item.stories.d.ts +0 -12
- package/dist/types/stories/general/contentful.item.stories.d.ts.map +0 -1
- package/dist/types/stories/general/contentful.items.stories.d.ts.map +0 -1
- package/dist/types/stories/general/contentful.stories.d.ts.map +0 -1
- package/dist/types/stories/general/global-error.stories.d.ts +0 -26
- package/dist/types/stories/general/global-error.stories.d.ts.map +0 -1
- package/dist/types/stories/general/google.reviews.stories.d.ts.map +0 -1
- package/dist/types/stories/general/googleanalytics.stories.d.ts +0 -14
- package/dist/types/stories/general/googleanalytics.stories.d.ts.map +0 -1
- package/dist/types/stories/general/googlesearch.stories.d.ts.map +0 -1
- package/dist/types/stories/general/gravatar.stories.d.ts.map +0 -1
- package/dist/types/stories/general/instagram.stories.d.ts.map +0 -1
- package/dist/types/stories/general/loading.stories.d.ts +0 -11
- package/dist/types/stories/general/loading.stories.d.ts.map +0 -1
- package/dist/types/stories/general/metadata.stories.d.ts +0 -25
- package/dist/types/stories/general/metadata.stories.d.ts.map +0 -1
- package/dist/types/stories/general/schema.stories.d.ts +0 -62
- package/dist/types/stories/general/schema.stories.d.ts.map +0 -1
- package/dist/types/stories/general/sitemap.stories.d.ts +0 -8
- package/dist/types/stories/general/sitemap.stories.d.ts.map +0 -1
- package/dist/types/stories/general/wordpress.stories.d.ts.map +0 -1
- package/dist/types/stories/integrations/schema-podcast.stories.d.ts +0 -45
- package/dist/types/stories/integrations/schema-podcast.stories.d.ts.map +0 -1
- /package/dist/types/stories/{general → integrations}/contentful.items.stories.d.ts +0 -0
- /package/dist/types/stories/{general → integrations}/contentful.stories.d.ts +0 -0
- /package/dist/types/stories/{general → integrations}/google.reviews.stories.d.ts +0 -0
- /package/dist/types/stories/{general → integrations}/googlesearch.stories.d.ts +0 -0
- /package/dist/types/stories/{general → integrations}/gravatar.stories.d.ts +0 -0
- /package/dist/types/stories/{general → integrations}/instagram.stories.d.ts +0 -0
- /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:
|
|
7
|
+
baseURL: FLICKR_API_BASE_URL,
|
|
6
8
|
urlProps: {
|
|
7
9
|
method: 'flickr.photos.search',
|
|
8
|
-
api_key
|
|
9
|
-
|
|
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:
|
|
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
|
|
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: '
|
|
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,
|
|
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]
|
|
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
|
|
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
|
-
|
|
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
|
|
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" : "
|
|
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" : "
|
|
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
|
-
|
|
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':
|
|
151
|
-
'from':
|
|
152
|
-
'subject':
|
|
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 ==========
|
|
@@ -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
|
|
6
|
-
const cartCache = new CacheManager({ mode: 'local',
|
|
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", {
|
|
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}"
|
|
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' :
|