@websolutespa/bom-mixer-models 1.5.0 → 1.5.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @websolutespa/bom-mixer-models
2
2
 
3
+ ## 1.5.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Added: StructuredData
8
+ - Updated dependencies
9
+ - @websolutespa/bom-core@0.6.2
10
+
11
+ ## 1.5.1
12
+
13
+ ### Patch Changes
14
+
15
+ - Added: defaultMarket, defaultLocale
16
+ - Updated dependencies [dad63747]
17
+ - @websolutespa/bom-core@0.6.1
18
+
3
19
  ## 1.5.0
4
20
 
5
21
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -301,10 +301,10 @@ declare function getRoutesForTemplates(templates: string[], market?: string, loc
301
301
  [key: string]: string;
302
302
  }>;
303
303
  declare function getStaticPathsForSchema(schema: string): Promise<StaticPath[]>;
304
- declare function getBreadcrumbFromSegments(segments: ICategory[], market?: string, locale?: string): Promise<IRouteLink[]>;
305
- declare function getRouteLinkTree(market?: string, locale?: string): Promise<IRouteLink | undefined>;
306
- declare function newRouteLink(category: ICategory, route?: IRoute, locale?: string): IRouteLink;
307
- declare function categoryToRouteLink(routes: IRoute[], categories: ICategory[], category: ICategory, locale?: string): IRouteLink;
304
+ declare function getBreadcrumbFromSegments(segments: ICategory[], market: string, locale: string): Promise<IRouteLink[]>;
305
+ declare function getRouteLinkTree(market: string, locale: string): Promise<IRouteLink | undefined>;
306
+ declare function newRouteLink(category: ICategory, route: IRoute | undefined, locale: string): IRouteLink;
307
+ declare function categoryToRouteLink(routes: IRoute[], categories: ICategory[], category: ICategory, locale: string): IRouteLink;
308
308
  declare function resolveRoute(route: IRoute & {
309
309
  splat?: string;
310
310
  }): string;
@@ -337,4 +337,70 @@ type IModelStore = {
337
337
  [key: string]: IQuerable<IEntity>;
338
338
  };
339
339
 
340
- export { IAddress, IAddressOptions, IAppProps, IApplication, IApplicationProps, ICartAddItem, ICartItem, ICheckout, ICheckoutDelivery, ICheckoutDiscount, ICheckoutInfo, ICheckoutItem, ICheckoutPartial, ICheckoutPayment, ICheckoutPaymentRedirect, ICheckoutStore, ICompanyAddress, IFeatureType, IKeyedList, ILazyComponent, ILazyComponentFunc, ILazyComponentProps, ILazyFuncProps, ILazyModules, ILazyProps, ILazyStaticProps, ILazyStaticPropsFunc, ILazyableProps, ILazyedProps, ILink, IList, IModelStore, IOrder, IOrderDetail, IOrderStatus, IOrderStatusValue, ISiteMap, IUser, IUserAddress, IUserChangePassword, IUserForgot, IUserLogin, IUserRegister, LAZY_PROPS, PartialPageProps, StaticPath, categoryToRouteLink, findManyPages, findOnePage, getBreadcrumbFromSegments, getCategories, getCategory, getCountries, getCountry, getDecoratedComponents, getDeliveries, getErrorPageLayout, getFeatureType, getFeatureTypes, getInfo, getItems, getLabel, getLabels, getLayout, getListByKeys, getLists, getLocale, getLocaleFromProps, getLocales, getMarket, getMarkets, getMenu, getMenus, getOrder, getOrders, getPage, getPageCategory, getPageProps, getPageRoutes, getPayment, getPayments, getProvince, getProvinces, getRegion, getRegions, getRoute, getRouteLinkTree, getRoutes, getRoutesForSchemas, getRoutesForTemplates, getSegments, getSiteMapIndex, getSiteMapIndexProps, getSiteMapXML, getSiteMapXMLProps, getSiteMapXSL, getSiteMapXSLProps, getStaticPathsForSchema, getStores, newRouteLink, resolveLabel, resolveRoute, routeInterceptor, routeRevalidateHandler, setDiscountCode, updateCheckout, withLazyProps };
340
+ type StructuredDataPerson = {
341
+ '@type': 'Person';
342
+ name: string;
343
+ url: string;
344
+ };
345
+ type StructuredDataPerformingGroup = {
346
+ '@type': 'PerformingGroup';
347
+ name: string;
348
+ };
349
+ type StructuredDataOffer = {
350
+ '@type': 'Offer';
351
+ url: string;
352
+ price: number;
353
+ priceCurrency: string;
354
+ validFrom?: Date | string;
355
+ };
356
+ type StructuredDataAddress = {
357
+ '@type': 'PostalAddress';
358
+ addressCountry?: string;
359
+ addressLocality: string;
360
+ addressRegion?: string;
361
+ postalCode: string;
362
+ streetAddress: string;
363
+ };
364
+ type StructuredDataPlace = {
365
+ '@type': 'Place';
366
+ name: string;
367
+ address: StructuredDataAddress;
368
+ };
369
+ type StructuredDataOrganization = {
370
+ '@type': 'Organization';
371
+ address?: StructuredDataAddress;
372
+ alumni?: StructuredDataPerson[];
373
+ email?: string;
374
+ faxNumber?: string;
375
+ member?: StructuredDataOrganization[];
376
+ name: string;
377
+ telephone?: string;
378
+ url?: string;
379
+ };
380
+ type StructuredDataArticle = {
381
+ '@context': 'https://schema.org';
382
+ '@type': 'Article' | 'BlogPosting' | 'NewsArticle';
383
+ author: (StructuredDataPerson | StructuredDataOrganization)[];
384
+ dateModified: Date | string;
385
+ datePublished: Date | string;
386
+ headline: string;
387
+ image: string[];
388
+ };
389
+ type StructuredDataEvent = {
390
+ '@context': 'https://schema.org';
391
+ '@type': 'Event';
392
+ name: string;
393
+ description: string;
394
+ startDate: Date | string;
395
+ endDate: Date | string;
396
+ location?: StructuredDataPlace;
397
+ image?: string[];
398
+ offers?: StructuredDataOffer;
399
+ performer?: StructuredDataPerformingGroup;
400
+ organizer?: StructuredDataOrganization;
401
+ };
402
+ type StructuredDataKeys = 'article';
403
+ type StructuredDataCollections = Record<StructuredDataKeys, string[]>;
404
+ declare function resolveStructuredData(page: IPage, types?: StructuredDataCollections): string | undefined;
405
+
406
+ export { IAddress, IAddressOptions, IAppProps, IApplication, IApplicationProps, ICartAddItem, ICartItem, ICheckout, ICheckoutDelivery, ICheckoutDiscount, ICheckoutInfo, ICheckoutItem, ICheckoutPartial, ICheckoutPayment, ICheckoutPaymentRedirect, ICheckoutStore, ICompanyAddress, IFeatureType, IKeyedList, ILazyComponent, ILazyComponentFunc, ILazyComponentProps, ILazyFuncProps, ILazyModules, ILazyProps, ILazyStaticProps, ILazyStaticPropsFunc, ILazyableProps, ILazyedProps, ILink, IList, IModelStore, IOrder, IOrderDetail, IOrderStatus, IOrderStatusValue, ISiteMap, IUser, IUserAddress, IUserChangePassword, IUserForgot, IUserLogin, IUserRegister, LAZY_PROPS, PartialPageProps, StaticPath, StructuredDataAddress, StructuredDataArticle, StructuredDataCollections, StructuredDataEvent, StructuredDataKeys, StructuredDataOffer, StructuredDataOrganization, StructuredDataPerformingGroup, StructuredDataPerson, StructuredDataPlace, categoryToRouteLink, findManyPages, findOnePage, getBreadcrumbFromSegments, getCategories, getCategory, getCountries, getCountry, getDecoratedComponents, getDeliveries, getErrorPageLayout, getFeatureType, getFeatureTypes, getInfo, getItems, getLabel, getLabels, getLayout, getListByKeys, getLists, getLocale, getLocaleFromProps, getLocales, getMarket, getMarkets, getMenu, getMenus, getOrder, getOrders, getPage, getPageCategory, getPageProps, getPageRoutes, getPayment, getPayments, getProvince, getProvinces, getRegion, getRegions, getRoute, getRouteLinkTree, getRoutes, getRoutesForSchemas, getRoutesForTemplates, getSegments, getSiteMapIndex, getSiteMapIndexProps, getSiteMapXML, getSiteMapXMLProps, getSiteMapXSL, getSiteMapXSLProps, getStaticPathsForSchema, getStores, newRouteLink, resolveLabel, resolveRoute, resolveStructuredData, routeInterceptor, routeRevalidateHandler, setDiscountCode, updateCheckout, withLazyProps };
package/dist/index.js CHANGED
@@ -78,6 +78,7 @@ __export(src_exports, {
78
78
  newRouteLink: () => newRouteLink,
79
79
  resolveLabel: () => resolveLabel,
80
80
  resolveRoute: () => resolveRoute,
81
+ resolveStructuredData: () => resolveStructuredData,
81
82
  routeInterceptor: () => routeInterceptor,
82
83
  routeRevalidateHandler: () => routeRevalidateHandler,
83
84
  setDiscountCode: () => setDiscountCode,
@@ -215,7 +216,7 @@ async function getStaticPathsForSchema(schema) {
215
216
  });
216
217
  return routes.map((x) => ({ params: { id: x.page.toString(), market: x.market, locale: x.locale } }));
217
218
  }
218
- async function getBreadcrumbFromSegments(segments, market = "ww", locale = "en") {
219
+ async function getBreadcrumbFromSegments(segments, market, locale) {
219
220
  const routes = await getRoutes({
220
221
  where: {
221
222
  market: {
@@ -242,7 +243,7 @@ async function getBreadcrumbFromSegments(segments, market = "ww", locale = "en")
242
243
  });
243
244
  return tree;
244
245
  }
245
- async function getRouteLinkTree(market = "ww", locale = "en") {
246
+ async function getRouteLinkTree(market, locale) {
246
247
  const store = await (0, import_bom_mixer_store5.getStore)();
247
248
  const routes = await store.route.findMany({
248
249
  where: {
@@ -264,7 +265,7 @@ async function getRouteLinkTree(market = "ww", locale = "en") {
264
265
  }
265
266
  return void 0;
266
267
  }
267
- function newRouteLink(category, route, locale = "en") {
268
+ function newRouteLink(category, route, locale) {
268
269
  const href = route && route.id ? route.id.toString() : "/";
269
270
  const id = route?.page || category.id;
270
271
  const media = category.media || route?.media;
@@ -281,7 +282,7 @@ function newRouteLink(category, route, locale = "en") {
281
282
  };
282
283
  return routeLink;
283
284
  }
284
- function categoryToRouteLink(routes, categories, category, locale = "en") {
285
+ function categoryToRouteLink(routes, categories, category, locale) {
285
286
  const route = routes.find(
286
287
  (r) => r.category === category.id
287
288
  );
@@ -1112,7 +1113,7 @@ async function getPage(schema, id, market, locale) {
1112
1113
  const currentRoute = routes.find((x) => x.market === market && x.locale === locale);
1113
1114
  const alternates = routes.filter((x) => x.market !== market || x.locale !== locale);
1114
1115
  const segments = await getSegments(page);
1115
- const breadcrumb = await getBreadcrumbFromSegments(segments, market, locale);
1116
+ const breadcrumb = currentRoute ? await getBreadcrumbFromSegments(segments, currentRoute.market, currentRoute.locale) : [];
1116
1117
  const parentRoute = breadcrumb.length > 1 ? breadcrumb[breadcrumb.length - 2] : void 0;
1117
1118
  return {
1118
1119
  ...page,
@@ -1188,9 +1189,7 @@ async function getPageCategory(schema, page, market, locale) {
1188
1189
  }
1189
1190
  }
1190
1191
  async function getErrorPageLayout() {
1191
- const defaultMarket = "ww";
1192
- const defaultLocale = "en";
1193
- const layout = await getLayout(defaultMarket, defaultLocale);
1192
+ const layout = await getLayout(import_bom_core3.defaultMarket, import_bom_core3.defaultLocale);
1194
1193
  const title = resolveLabel(layout.labels, "notfound.title");
1195
1194
  const abstract = resolveLabel(layout.labels, "notfound.abstract");
1196
1195
  const page = {
@@ -1342,14 +1341,14 @@ async function getSiteMapXML(origin, marketId, localeId) {
1342
1341
  let locales = await getLocales();
1343
1342
  markets = markets.filter((x) => x.isActive !== false);
1344
1343
  locales = locales.filter((x) => x.isActive !== false);
1345
- const defaultMarket = markets.find((x) => marketId ? x.id === marketId : x.isDefault) || markets[0];
1346
- const defaultLocale = locales.find((x) => localeId ? x.id === localeId : x.isDefault) || locales[0];
1347
- const defaultMarketLocale = defaultMarket && defaultMarket.defaultLanguage ? defaultMarket.defaultLanguage : defaultLocale.id;
1344
+ const defaultMarket2 = markets.find((x) => marketId ? x.id === marketId : x.isDefault) || markets[0];
1345
+ const defaultLocale2 = locales.find((x) => localeId ? x.id === localeId : x.isDefault) || locales[0];
1346
+ const defaultMarketLocale = defaultMarket2 && defaultMarket2.defaultLanguage ? defaultMarket2.defaultLanguage : defaultLocale2.id;
1348
1347
  const routes = await getRoutes();
1349
1348
  const isCanonicalRoute = marketId && localeId ? (route) => {
1350
- return route.market === defaultMarket.id && route.locale === defaultLocale.id;
1349
+ return route.market === defaultMarket2.id && route.locale === defaultLocale2.id;
1351
1350
  } : (route) => {
1352
- return route.market === defaultMarket.id && route.locale === defaultMarketLocale;
1351
+ return route.market === defaultMarket2.id && route.locale === defaultMarketLocale;
1353
1352
  };
1354
1353
  const getCanonicalAlternates = marketId && localeId ? (canonical) => {
1355
1354
  return [];
@@ -1585,6 +1584,36 @@ var getSiteMapXSLProps = async (context) => {
1585
1584
  props: {}
1586
1585
  };
1587
1586
  };
1587
+
1588
+ // src/structured_data/structured_data.ts
1589
+ var DefaultStructuredDataCollections = {
1590
+ article: ["news_detail"]
1591
+ };
1592
+ function resolveStructuredData(page, types = DefaultStructuredDataCollections) {
1593
+ let schema = null;
1594
+ const json = null;
1595
+ const pageType = page.template || page.schema || "";
1596
+ if (types.article.includes(pageType)) {
1597
+ schema = {
1598
+ "@context": "https://schema.org",
1599
+ "@type": "NewsArticle",
1600
+ headline: page.title,
1601
+ image: page.media ? [page.media.src] : [],
1602
+ datePublished: page.createdAt,
1603
+ dateModified: page.updatedAt,
1604
+ author: [{
1605
+ "@type": "Organization",
1606
+ name: "WebsiteName"
1607
+ // 'Autorità del bacino distrettuale dell\'Appennino Centrale',
1608
+ // url: 'https://twitter.com/autoritadac',
1609
+ }]
1610
+ };
1611
+ }
1612
+ if (json) {
1613
+ return JSON.stringify(json);
1614
+ }
1615
+ return void 0;
1616
+ }
1588
1617
  // Annotate the CommonJS export names for ESM import in node:
1589
1618
  0 && (module.exports = {
1590
1619
  IOrderStatus,
@@ -1645,6 +1674,7 @@ var getSiteMapXSLProps = async (context) => {
1645
1674
  newRouteLink,
1646
1675
  resolveLabel,
1647
1676
  resolveRoute,
1677
+ resolveStructuredData,
1648
1678
  routeInterceptor,
1649
1679
  routeRevalidateHandler,
1650
1680
  setDiscountCode,
package/dist/index.mjs CHANGED
@@ -127,7 +127,7 @@ async function getStaticPathsForSchema(schema) {
127
127
  });
128
128
  return routes.map((x) => ({ params: { id: x.page.toString(), market: x.market, locale: x.locale } }));
129
129
  }
130
- async function getBreadcrumbFromSegments(segments, market = "ww", locale = "en") {
130
+ async function getBreadcrumbFromSegments(segments, market, locale) {
131
131
  const routes = await getRoutes({
132
132
  where: {
133
133
  market: {
@@ -154,7 +154,7 @@ async function getBreadcrumbFromSegments(segments, market = "ww", locale = "en")
154
154
  });
155
155
  return tree;
156
156
  }
157
- async function getRouteLinkTree(market = "ww", locale = "en") {
157
+ async function getRouteLinkTree(market, locale) {
158
158
  const store = await getStore5();
159
159
  const routes = await store.route.findMany({
160
160
  where: {
@@ -176,7 +176,7 @@ async function getRouteLinkTree(market = "ww", locale = "en") {
176
176
  }
177
177
  return void 0;
178
178
  }
179
- function newRouteLink(category, route, locale = "en") {
179
+ function newRouteLink(category, route, locale) {
180
180
  const href = route && route.id ? route.id.toString() : "/";
181
181
  const id = route?.page || category.id;
182
182
  const media = category.media || route?.media;
@@ -193,7 +193,7 @@ function newRouteLink(category, route, locale = "en") {
193
193
  };
194
194
  return routeLink;
195
195
  }
196
- function categoryToRouteLink(routes, categories, category, locale = "en") {
196
+ function categoryToRouteLink(routes, categories, category, locale) {
197
197
  const route = routes.find(
198
198
  (r) => r.category === category.id
199
199
  );
@@ -992,7 +992,7 @@ async function getOrder(id, market, locale) {
992
992
  }
993
993
 
994
994
  // src/page/page.service.ts
995
- import { asServerProps } from "@websolutespa/bom-core";
995
+ import { asServerProps, defaultLocale, defaultMarket } from "@websolutespa/bom-core";
996
996
  import { getStore as getStore12 } from "@websolutespa/bom-mixer-store";
997
997
  async function findOnePage(schema, id, params) {
998
998
  const store = await getStore12();
@@ -1024,7 +1024,7 @@ async function getPage(schema, id, market, locale) {
1024
1024
  const currentRoute = routes.find((x) => x.market === market && x.locale === locale);
1025
1025
  const alternates = routes.filter((x) => x.market !== market || x.locale !== locale);
1026
1026
  const segments = await getSegments(page);
1027
- const breadcrumb = await getBreadcrumbFromSegments(segments, market, locale);
1027
+ const breadcrumb = currentRoute ? await getBreadcrumbFromSegments(segments, currentRoute.market, currentRoute.locale) : [];
1028
1028
  const parentRoute = breadcrumb.length > 1 ? breadcrumb[breadcrumb.length - 2] : void 0;
1029
1029
  return {
1030
1030
  ...page,
@@ -1100,8 +1100,6 @@ async function getPageCategory(schema, page, market, locale) {
1100
1100
  }
1101
1101
  }
1102
1102
  async function getErrorPageLayout() {
1103
- const defaultMarket = "ww";
1104
- const defaultLocale = "en";
1105
1103
  const layout = await getLayout(defaultMarket, defaultLocale);
1106
1104
  const title = resolveLabel(layout.labels, "notfound.title");
1107
1105
  const abstract = resolveLabel(layout.labels, "notfound.abstract");
@@ -1254,14 +1252,14 @@ async function getSiteMapXML(origin, marketId, localeId) {
1254
1252
  let locales = await getLocales();
1255
1253
  markets = markets.filter((x) => x.isActive !== false);
1256
1254
  locales = locales.filter((x) => x.isActive !== false);
1257
- const defaultMarket = markets.find((x) => marketId ? x.id === marketId : x.isDefault) || markets[0];
1258
- const defaultLocale = locales.find((x) => localeId ? x.id === localeId : x.isDefault) || locales[0];
1259
- const defaultMarketLocale = defaultMarket && defaultMarket.defaultLanguage ? defaultMarket.defaultLanguage : defaultLocale.id;
1255
+ const defaultMarket2 = markets.find((x) => marketId ? x.id === marketId : x.isDefault) || markets[0];
1256
+ const defaultLocale2 = locales.find((x) => localeId ? x.id === localeId : x.isDefault) || locales[0];
1257
+ const defaultMarketLocale = defaultMarket2 && defaultMarket2.defaultLanguage ? defaultMarket2.defaultLanguage : defaultLocale2.id;
1260
1258
  const routes = await getRoutes();
1261
1259
  const isCanonicalRoute = marketId && localeId ? (route) => {
1262
- return route.market === defaultMarket.id && route.locale === defaultLocale.id;
1260
+ return route.market === defaultMarket2.id && route.locale === defaultLocale2.id;
1263
1261
  } : (route) => {
1264
- return route.market === defaultMarket.id && route.locale === defaultMarketLocale;
1262
+ return route.market === defaultMarket2.id && route.locale === defaultMarketLocale;
1265
1263
  };
1266
1264
  const getCanonicalAlternates = marketId && localeId ? (canonical) => {
1267
1265
  return [];
@@ -1497,6 +1495,36 @@ var getSiteMapXSLProps = async (context) => {
1497
1495
  props: {}
1498
1496
  };
1499
1497
  };
1498
+
1499
+ // src/structured_data/structured_data.ts
1500
+ var DefaultStructuredDataCollections = {
1501
+ article: ["news_detail"]
1502
+ };
1503
+ function resolveStructuredData(page, types = DefaultStructuredDataCollections) {
1504
+ let schema = null;
1505
+ const json = null;
1506
+ const pageType = page.template || page.schema || "";
1507
+ if (types.article.includes(pageType)) {
1508
+ schema = {
1509
+ "@context": "https://schema.org",
1510
+ "@type": "NewsArticle",
1511
+ headline: page.title,
1512
+ image: page.media ? [page.media.src] : [],
1513
+ datePublished: page.createdAt,
1514
+ dateModified: page.updatedAt,
1515
+ author: [{
1516
+ "@type": "Organization",
1517
+ name: "WebsiteName"
1518
+ // 'Autorità del bacino distrettuale dell\'Appennino Centrale',
1519
+ // url: 'https://twitter.com/autoritadac',
1520
+ }]
1521
+ };
1522
+ }
1523
+ if (json) {
1524
+ return JSON.stringify(json);
1525
+ }
1526
+ return void 0;
1527
+ }
1500
1528
  export {
1501
1529
  IOrderStatus,
1502
1530
  LAZY_PROPS,
@@ -1556,6 +1584,7 @@ export {
1556
1584
  newRouteLink,
1557
1585
  resolveLabel,
1558
1586
  resolveRoute,
1587
+ resolveStructuredData,
1559
1588
  routeInterceptor,
1560
1589
  routeRevalidateHandler,
1561
1590
  setDiscountCode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-mixer-models",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Mixer Models module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -30,22 +30,22 @@ export async function getDeliveries(checkout: ICheckoutPartial, market: string,
30
30
  'name': 'In-store pick up',
31
31
  'abstract': 'Conveniently collect from your nearest shop at no extra charge',
32
32
  'price': 0,
33
- 'fullPrice': 0
33
+ 'fullPrice': 0,
34
34
  },
35
35
  {
36
36
  'id': 2,
37
37
  'name': 'Courier delivery',
38
38
  'abstract': 'Packaged goods are delivered by our trusted forwarder.',
39
39
  'price': 81,
40
- 'fullPrice': 81
40
+ 'fullPrice': 81,
41
41
  },
42
42
  {
43
43
  'id': 3,
44
44
  'name': 'In-home courier delivery',
45
45
  'abstract': 'Packaged goods are delivered inside at front door. <br>White glove delivery, unpacking, assembly, or removal of debris is optional on request.',
46
46
  'price': 156,
47
- 'fullPrice': 156
48
- }
47
+ 'fullPrice': 156,
48
+ },
49
49
  ];
50
50
  }
51
51
 
@@ -65,10 +65,10 @@ export async function getStores(checkout: ICheckoutPartial, market: string, loca
65
65
  'timetable': [],
66
66
  'position': {
67
67
  'latitude': 0.0,
68
- 'longitude': 0.0
68
+ 'longitude': 0.0,
69
69
  },
70
70
  'distance': 151.84174300013095,
71
- 'rank': 1
71
+ 'rank': 1,
72
72
  }, {
73
73
  'id': 7430,
74
74
  'category': { 'id': 'store_category_distributor', 'name': 'Mixer Distributor' },
@@ -82,10 +82,10 @@ export async function getStores(checkout: ICheckoutPartial, market: string, loca
82
82
  'timetable': [],
83
83
  'position': {
84
84
  'latitude': 0.0,
85
- 'longitude': 0.0
85
+ 'longitude': 0.0,
86
86
  },
87
87
  'distance': 170.6551472799284,
88
- 'rank': 2
88
+ 'rank': 2,
89
89
  }, {
90
90
  'id': 325,
91
91
  'category': { 'id': 'store_category_distributor', 'name': 'Mixer Distributor' },
@@ -100,10 +100,10 @@ export async function getStores(checkout: ICheckoutPartial, market: string, loca
100
100
  'timetable': [],
101
101
  'position': {
102
102
  'latitude': 0.0,
103
- 'longitude': 0.0
103
+ 'longitude': 0.0,
104
104
  },
105
105
  'distance': 196.0600048738732,
106
- 'rank': 3
106
+ 'rank': 3,
107
107
  }];
108
108
  }
109
109
 
@@ -115,72 +115,72 @@ export async function getPayments(checkout: ICheckoutPartial, market: string, lo
115
115
  'name': 'Alipay',
116
116
  'media': {
117
117
  'type': 'image',
118
- 'src': '/assets/payment/alipay.svg'
119
- }
118
+ 'src': '/assets/payment/alipay.svg',
119
+ },
120
120
  },
121
121
  {
122
122
  'id': 'amex',
123
123
  'name': 'American Express',
124
124
  'media': {
125
125
  'type': 'image',
126
- 'src': '/assets/payment/american-express.svg'
127
- }
126
+ 'src': '/assets/payment/american-express.svg',
127
+ },
128
128
  },
129
129
  {
130
130
  'id': 'apple-pay',
131
131
  'name': 'Apple Pay',
132
132
  'media': {
133
133
  'type': 'image',
134
- 'src': '/assets/payment/apple-pay.svg'
135
- }
134
+ 'src': '/assets/payment/apple-pay.svg',
135
+ },
136
136
  },
137
137
  {
138
138
  'id': 'bank-transfer',
139
139
  'name': 'Bank Transfer',
140
140
  'media': {
141
141
  'type': 'image',
142
- 'src': '/assets/payment/bank-transfer.svg'
143
- }
142
+ 'src': '/assets/payment/bank-transfer.svg',
143
+ },
144
144
  },
145
145
  {
146
146
  'id': 'cbc',
147
147
  'name': 'CBC',
148
148
  'media': {
149
149
  'type': 'image',
150
- 'src': '/assets/payment/cbc.svg'
151
- }
150
+ 'src': '/assets/payment/cbc.svg',
151
+ },
152
152
  },
153
153
  {
154
154
  'id': 'direct-debit',
155
155
  'name': 'Direct Debit',
156
156
  'media': {
157
157
  'type': 'image',
158
- 'src': '/assets/payment/direct-debit.svg'
159
- }
158
+ 'src': '/assets/payment/direct-debit.svg',
159
+ },
160
160
  },
161
161
  {
162
162
  'id': 'googlepay',
163
163
  'name': 'Google Pay',
164
164
  'media': {
165
165
  'type': 'image',
166
- 'src': '/assets/payment/googlepay.svg'
167
- }
166
+ 'src': '/assets/payment/googlepay.svg',
167
+ },
168
168
  },
169
169
  {
170
170
  'id': 'ideal',
171
171
  'name': 'iDEAL',
172
172
  'media': {
173
173
  'type': 'image',
174
- 'src': '/assets/payment/ideal.svg'
175
- }
174
+ 'src': '/assets/payment/ideal.svg',
175
+ },
176
176
  },
177
177
  {
178
178
  'id': 'maestro',
179
179
  'name': 'Maestro',
180
180
  'media': {
181
181
  'type': 'image',
182
- 'src': '/assets/payment/maestro.svg'
183
- }
182
+ 'src': '/assets/payment/maestro.svg',
183
+ },
184
184
  },
185
185
  {
186
186
  'id': 'mastercard',
@@ -188,32 +188,32 @@ export async function getPayments(checkout: ICheckoutPartial, market: string, lo
188
188
  'abstract': '<p>You can use your Mastercard credit card. The 3DS authentication procedure will be used when the order is concluded, and you will be redirected to the bank\'s web page. To complete the order, follow the required steps.</p>',
189
189
  'media': {
190
190
  'type': 'image',
191
- 'src': '/assets/payment/mastercard.svg'
192
- }
191
+ 'src': '/assets/payment/mastercard.svg',
192
+ },
193
193
  },
194
194
  {
195
195
  'id': 'mybank',
196
196
  'name': 'MyBank',
197
197
  'media': {
198
198
  'type': 'image',
199
- 'src': '/assets/payment/mybank.svg'
200
- }
199
+ 'src': '/assets/payment/mybank.svg',
200
+ },
201
201
  },
202
202
  {
203
203
  'id': 'paypal',
204
204
  'name': 'PayPal',
205
205
  'media': {
206
206
  'type': 'image',
207
- 'src': '/assets/payment/paypal.svg'
208
- }
207
+ 'src': '/assets/payment/paypal.svg',
208
+ },
209
209
  },
210
210
  {
211
211
  'id': 'trustly',
212
212
  'name': 'Trustly',
213
213
  'media': {
214
214
  'type': 'image',
215
- 'src': '/assets/payment/trustly.svg'
216
- }
215
+ 'src': '/assets/payment/trustly.svg',
216
+ },
217
217
  },
218
218
  {
219
219
  'id': 'visa',
@@ -221,16 +221,16 @@ export async function getPayments(checkout: ICheckoutPartial, market: string, lo
221
221
  'abstract': '<p>You can use your Visa credit card. The 3DS authentication procedure will be used when the order is concluded, and you will be redirected to the bank\'s web page. To complete the order, follow the required steps.</p>',
222
222
  'media': {
223
223
  'type': 'image',
224
- 'src': '/assets/payment/visa.svg'
225
- }
224
+ 'src': '/assets/payment/visa.svg',
225
+ },
226
226
  },
227
227
  {
228
228
  'id': 'wechatpay',
229
229
  'name': 'WeChat Pay',
230
230
  'media': {
231
231
  'type': 'image',
232
- 'src': '/assets/payment/wechatpay.svg'
233
- }
232
+ 'src': '/assets/payment/wechatpay.svg',
233
+ },
234
234
  },
235
235
  {
236
236
  'id': 'wire-transfer',
@@ -238,9 +238,9 @@ export async function getPayments(checkout: ICheckoutPartial, market: string, lo
238
238
  'abstract': '<p>The order confirmation will contain a summary of the total amount to be paid and the details of the bank to which the payment is to be made..</p><p> Once the payment has been made, the order will be activated and the delivery terms indicated for the various items ordered will apply. The successful completion of the payment will be communicated by email to the email address indicated during registration.</p>',
239
239
  'media': {
240
240
  'type': 'image',
241
- 'src': '/assets/payment/wire-transfer.svg'
242
- }
243
- }
241
+ 'src': '/assets/payment/wire-transfer.svg',
242
+ },
243
+ },
244
244
  ];
245
245
  }
246
246
 
package/src/index.ts CHANGED
@@ -26,5 +26,6 @@ export * from './route/route.service';
26
26
  export * from './sitemap/sitemap.handler';
27
27
  export * from './sitemap/sitemap.service';
28
28
  export * from './store/store';
29
+ export * from './structured_data/structured_data';
29
30
  export * from './user/user';
30
31
 
@@ -20,7 +20,7 @@ export function resolveLabel(labels: ILabel[], id: string): string {
20
20
  }
21
21
 
22
22
  /*
23
- export function localizedLabel(labels: Label[], id: string, locale: string = 'en', defaultLocale: string = 'en'): Promise<Label> {
23
+ export function localizedLabel(labels: Label[], id: string, locale: string, defaultLocale: string): Promise<Label> {
24
24
  const label = labels.find(x => x.id === id);
25
25
  if (label) {
26
26
  return store.localizeValue(label, locale, defaultLocale);
@@ -1,4 +1,4 @@
1
- import { ICategorized, ICategory, IEquatable, ILayout, IPage, IPageResult, IRoute, IRouteLink, PageProps, QueryParams, SchemaType, asServerProps } from '@websolutespa/bom-core';
1
+ import { ICategorized, ICategory, IEquatable, ILayout, IPage, IPageResult, IRoute, IRouteLink, PageProps, QueryParams, SchemaType, asServerProps, defaultLocale, defaultMarket } from '@websolutespa/bom-core';
2
2
  import { getStore } from '@websolutespa/bom-mixer-store';
3
3
  import { getSegments } from '../category/category.service';
4
4
  import { resolveLabel } from '../label/label.service';
@@ -41,7 +41,9 @@ export async function getPage<T extends ICategorized = ICategorized>(schema: str
41
41
  const currentRoute = routes.find((x: IRoute) => x.market === market && x.locale === locale);
42
42
  const alternates = routes.filter((x: IRoute) => x.market !== market || x.locale !== locale);
43
43
  const segments: ICategory[] = await getSegments(page);
44
- const breadcrumb: IRouteLink[] = await getBreadcrumbFromSegments(segments, market, locale);
44
+ const breadcrumb: IRouteLink[] = currentRoute ?
45
+ await getBreadcrumbFromSegments(segments, currentRoute.market, currentRoute.locale) :
46
+ [];
45
47
  const parentRoute: IRouteLink | undefined = breadcrumb.length > 1 ? breadcrumb[breadcrumb.length - 2] : undefined;
46
48
  return {
47
49
  ...page,
@@ -116,8 +118,6 @@ export async function getPageCategory<T extends IPage>(schema: string, page?: IP
116
118
  }
117
119
 
118
120
  export async function getErrorPageLayout(): Promise<{ layout: ILayout, page: IPage }> {
119
- const defaultMarket = 'ww';
120
- const defaultLocale = 'en';
121
121
  const layout = await getLayout(defaultMarket, defaultLocale);
122
122
  // console.log('getErrorPageLayout', layout);
123
123
  const title = resolveLabel(layout.labels, 'notfound.title');
@@ -79,7 +79,7 @@ export async function getStaticPathsForSchema(schema: string): Promise<StaticPat
79
79
  return routes.map((x: any) => ({ params: { id: x.page.toString(), market: x.market, locale: x.locale } }));
80
80
  }
81
81
 
82
- export async function getBreadcrumbFromSegments(segments: ICategory[], market: string = 'ww', locale: string = 'en'): Promise<IRouteLink[]> {
82
+ export async function getBreadcrumbFromSegments(segments: ICategory[], market: string, locale: string): Promise<IRouteLink[]> {
83
83
  const routes: IRoute[] = await getRoutes({
84
84
  where: {
85
85
  market: {
@@ -107,7 +107,7 @@ export async function getBreadcrumbFromSegments(segments: ICategory[], market: s
107
107
  return tree;
108
108
  }
109
109
 
110
- export async function getRouteLinkTree(market: string = 'ww', locale: string = 'en'): Promise<IRouteLink | undefined> {
110
+ export async function getRouteLinkTree(market: string, locale: string): Promise<IRouteLink | undefined> {
111
111
  const store = await getStore<IModelStore>();
112
112
  // console.log('getRouteLinkTree.store');
113
113
  const routes = await store.route.findMany({
@@ -133,7 +133,7 @@ export async function getRouteLinkTree(market: string = 'ww', locale: string = '
133
133
  return undefined;
134
134
  }
135
135
 
136
- export function newRouteLink(category: ICategory, route?: IRoute, locale: string = 'en'): IRouteLink {
136
+ export function newRouteLink(category: ICategory, route: IRoute | undefined, locale: string): IRouteLink {
137
137
  const href = (route && route.id) ? route.id.toString() : '/';
138
138
  const id = route?.page || category.id;
139
139
  const media = category.media || route?.media;
@@ -151,7 +151,7 @@ export function newRouteLink(category: ICategory, route?: IRoute, locale: string
151
151
  return routeLink;
152
152
  }
153
153
 
154
- export function categoryToRouteLink(routes: IRoute[], categories: ICategory[], category: ICategory, locale: string = 'en'): IRouteLink {
154
+ export function categoryToRouteLink(routes: IRoute[], categories: ICategory[], category: ICategory, locale: string): IRouteLink {
155
155
  const route = routes.find(r =>
156
156
  r.category === category.id
157
157
  );
@@ -0,0 +1,108 @@
1
+ import { IPage } from '@websolutespa/bom-core';
2
+
3
+ export type StructuredDataPerson = {
4
+ '@type': 'Person';
5
+ name: string;
6
+ url: string;
7
+ };
8
+
9
+ export type StructuredDataPerformingGroup = {
10
+ '@type': 'PerformingGroup';
11
+ name: string;
12
+ };
13
+
14
+ export type StructuredDataOffer = {
15
+ '@type': 'Offer';
16
+ url: string;
17
+ price: number;
18
+ priceCurrency: string;
19
+ // availability: 'https://schema.org/InStock',
20
+ validFrom?: Date | string;
21
+ };
22
+
23
+ export type StructuredDataAddress = {
24
+ '@type': 'PostalAddress';
25
+ addressCountry?: string;
26
+ addressLocality: string;
27
+ addressRegion?: string;
28
+ postalCode: string;
29
+ streetAddress: string;
30
+ };
31
+
32
+ export type StructuredDataPlace = {
33
+ '@type': 'Place';
34
+ name: string;
35
+ address: StructuredDataAddress;
36
+ };
37
+
38
+ export type StructuredDataOrganization = {
39
+ '@type': 'Organization';
40
+ address?: StructuredDataAddress;
41
+ alumni?: StructuredDataPerson[];
42
+ email?: string;
43
+ faxNumber?: string;
44
+ member?: StructuredDataOrganization[];
45
+ name: string;
46
+ telephone?: string;
47
+ url?: string;
48
+ };
49
+
50
+ export type StructuredDataArticle = {
51
+ '@context': 'https://schema.org';
52
+ '@type': 'Article' | 'BlogPosting' | 'NewsArticle';
53
+ author: (StructuredDataPerson | StructuredDataOrganization)[];
54
+ dateModified: Date | string;
55
+ datePublished: Date | string;
56
+ headline: string;
57
+ image: string[];
58
+ };
59
+
60
+ export type StructuredDataEvent = {
61
+ '@context': 'https://schema.org';
62
+ '@type': 'Event';
63
+ name: string;
64
+ description: string;
65
+ startDate: Date | string;
66
+ endDate: Date | string;
67
+ /*
68
+ eventAttendanceMode: 'https://schema.org/OfflineEventAttendanceMode',
69
+ eventStatus: 'https://schema.org/EventScheduled',
70
+ */
71
+ location?: StructuredDataPlace,
72
+ image?: string[],
73
+ offers?: StructuredDataOffer,
74
+ performer?: StructuredDataPerformingGroup,
75
+ organizer?: StructuredDataOrganization;
76
+ };
77
+
78
+ export type StructuredDataKeys = 'article';
79
+ export type StructuredDataCollections = Record<StructuredDataKeys, string[]>;
80
+
81
+ const DefaultStructuredDataCollections: StructuredDataCollections = {
82
+ article: ['news_detail'],
83
+ };
84
+
85
+ export function resolveStructuredData(page: IPage, types: StructuredDataCollections = DefaultStructuredDataCollections): string | undefined {
86
+ let schema = null;
87
+ const json: {} | null = null;
88
+ const pageType = page.template || page.schema || '';
89
+ if (types.article.includes(pageType)) {
90
+ schema = {
91
+ '@context': 'https://schema.org',
92
+ '@type': 'NewsArticle',
93
+ headline: page.title,
94
+ image: page.media ? [page.media.src] : [],
95
+ datePublished: page.createdAt,
96
+ dateModified: page.updatedAt,
97
+ author: [{
98
+ '@type': 'Organization',
99
+ name: 'WebsiteName', // 'Autorità del bacino distrettuale dell\'Appennino Centrale',
100
+ // url: 'https://twitter.com/autoritadac',
101
+ }],
102
+ } as StructuredDataArticle;
103
+ }
104
+ if (json) {
105
+ return JSON.stringify(json);
106
+ }
107
+ return undefined;
108
+ }