-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial SAP Commerce App * Manifest * Fix typings * Fix loaders * Fix typings and descriptions * Remove unused actions and hooks * Remove default values | Add Preview --------- Co-authored-by: decobot <capy@deco.cx>
- Loading branch information
1 parent
771d22a
commit 2f418b1
Showing
14 changed files
with
1,359 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,7 @@ const config = { | |
app("crux"), | ||
app("decohub"), | ||
app("htmx"), | ||
app("sap"), | ||
...compatibilityApps, | ||
], | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<p align="center"> | ||
<strong> | ||
SAP Commerce - Under construction | ||
</strong> | ||
</p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import type { SiteNavigationElement } from "../../../commerce/types.ts"; | ||
import { AppContext } from "../../mod.ts"; | ||
import { CatalogsResponse } from "../../utils/types.ts"; | ||
|
||
export interface Props { | ||
/** | ||
* @description Response configuration. This is the list of fields that should be returned in the response body. Examples: BASIC, DEFAULT, FULL | ||
* @default FULL | ||
*/ | ||
fields?: string; | ||
/** | ||
* @description Filter when it's needed to retrieve only brands, collections or categories. Examples: categories, brands, collections | ||
*/ | ||
categoryType?: "default" | "categories" | "brands" | "collections"; | ||
} | ||
|
||
/** | ||
* @title SAP Integration | ||
* @description WORK IN PROGRESS - Category tree loader | ||
*/ | ||
const loader = async ( | ||
props: Props, | ||
_req: Request, | ||
ctx: AppContext, | ||
): Promise<SiteNavigationElement[] | null> => { | ||
const { api } = ctx; | ||
const { fields } = props; | ||
|
||
const data: CatalogsResponse = await api["GET /catalogs?:fields"]( | ||
{ fields }, | ||
).then( | ||
(res: Response) => res.json(), | ||
); | ||
const _tree = data.catalogs[0].catalogVersions | ||
.find((version) => { | ||
version.id == "Online"; | ||
}); | ||
|
||
return [{ | ||
"@type": "SiteNavigationElement", | ||
additionalType: "", | ||
identifier: "", | ||
name: "", | ||
url: "", | ||
}]; | ||
}; | ||
|
||
export default loader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { Product } from "../../../commerce/types.ts"; | ||
import type { AppContext } from "../../mod.ts"; | ||
import { ProductDetailsResponse } from "../../utils/types.ts"; | ||
import { convertProductData } from "../../utils/transform.ts"; | ||
|
||
export interface Props { | ||
/** | ||
* @title Fields | ||
* @description Response configuration. This is the list of fields that should be returned in the response body. Examples: BASIC, DEFAULT, FULL | ||
* @default "FULL,averageRating,stock(DEFAULT),description,availableForPickup,code,url,price(DEFAULT),manufacturer,categories(FULL),priceRange,multidimensional,configuratorType,configurable,tags,images(FULL),name,purchasable,baseOptions(DEFAULT),baseProduct,variantOptions(DEFAULT),variantType,numberOfReviews,productReferences,likeProductCopy,likeProductGroup,likeProducts(code,likeProductCopy,likeProductGroup,price(DEFAULT),url,primaryFlag,msrpUSD,msrpCAD,msrpCADFormattedValue),classifications" | ||
*/ | ||
fields: string; | ||
/** | ||
* @title Product codes | ||
* @description List of product codes for shelf products. | ||
*/ | ||
productCodes: string[]; | ||
} | ||
|
||
/** | ||
* @title SAP Integration | ||
* @description Product List loader | ||
*/ | ||
const productListLoader = ( | ||
props: Props, | ||
_req: Request, | ||
ctx: AppContext, | ||
): Promise<Product[] | null> => { | ||
const { api } = ctx; | ||
const { productCodes, fields } = props; | ||
|
||
return Promise.all( | ||
productCodes.map(async (productCode) => { | ||
const data: ProductDetailsResponse = await api[ | ||
"GET /products/:productCode" | ||
]({ productCode, fields }).then((res: Response) => res.json()); | ||
|
||
const product = convertProductData(data); | ||
|
||
return product; | ||
}), | ||
); | ||
}; | ||
|
||
export default productListLoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { ProductDetailsPage } from "../../../commerce/types.ts"; | ||
import type { AppContext } from "../../mod.ts"; | ||
import { ProductDetailsResponse } from "../../utils/types.ts"; | ||
import { | ||
convertCategoriesToBreadcrumb, | ||
convertProductData, | ||
} from "../../utils/transform.ts"; | ||
import { RequestURLParam } from "../../../website/functions/requestToParam.ts"; | ||
|
||
export interface Props { | ||
/** | ||
* @title Fields | ||
* @description Response configuration. This is the list of fields that should be returned in the response body. Examples: BASIC, DEFAULT, FULL | ||
* @default "FULL,averageRating,stock(DEFAULT),description,availableForPickup,code,url,price(DEFAULT),manufacturer,categories(FULL),priceRange,multidimensional,configuratorType,configurable,tags,images(FULL),name,purchasable,baseOptions(DEFAULT),baseProduct,variantOptions(DEFAULT),variantType,numberOfReviews,productReferences,likeProductCopy,likeProductGroup,likeProducts(code,likeProductCopy,likeProductGroup,price(DEFAULT),url,primaryFlag,msrpUSD,msrpCAD,msrpCADFormattedValue),classifications" | ||
*/ | ||
fields: string; | ||
/** | ||
* @title Product code | ||
* @description Product identifier. | ||
*/ | ||
productCode: RequestURLParam; | ||
} | ||
|
||
/** | ||
* @title SAP Integration | ||
* @description Product Details loader | ||
*/ | ||
const productDetailsLoader = async ( | ||
props: Props, | ||
_req: Request, | ||
ctx: AppContext, | ||
): Promise<ProductDetailsPage | null> => { | ||
const { api } = ctx; | ||
const { fields, productCode } = props; | ||
|
||
const data: ProductDetailsResponse = await api["GET /products/:productCode"]({ | ||
productCode, | ||
fields, | ||
}).then((res: Response) => { | ||
return res.json(); | ||
}); | ||
|
||
const breadcrumbList = convertCategoriesToBreadcrumb(data.categories); | ||
const product = convertProductData(data); | ||
|
||
return { | ||
"@type": "ProductDetailsPage", | ||
breadcrumbList, | ||
product, | ||
}; | ||
}; | ||
|
||
export default productDetailsLoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { BreadcrumbList, ProductListingPage } from "../../../commerce/types.ts"; | ||
import type { AppContext } from "../../mod.ts"; | ||
import { ProductListResponse } from "../../utils/types.ts"; | ||
import { | ||
convertBreadcrumb, | ||
convertFacetsToFilters, | ||
convertProductData, | ||
getPreviousNextPagination, | ||
} from "../../utils/transform.ts"; | ||
|
||
export interface Props { | ||
/** | ||
* @description Category code of the products of this page. | ||
*/ | ||
categoryCode?: string; | ||
/** | ||
* @description The current result page requested. | ||
* @hide true | ||
* @default 0 | ||
*/ | ||
currentPage?: number; | ||
/** | ||
* @title Fields | ||
* @description Response configuration. This is the list of fields that should be returned in the response body. Examples: BASIC, DEFAULT, FULL | ||
* @default FULL | ||
*/ | ||
fields?: string; | ||
/** | ||
* @title Items per page | ||
* @description The number of results returned per page. | ||
* @default 12 | ||
*/ | ||
pageSize?: number; | ||
} | ||
|
||
/** | ||
* @title SAP Integration | ||
* @description Product List loader | ||
*/ | ||
const PLPLoader = async ( | ||
props: Props, | ||
req: Request, | ||
ctx: AppContext, | ||
): Promise<ProductListingPage | null> => { | ||
const { api } = ctx; | ||
const { url: baseUrl } = req; | ||
const { categoryCode, currentPage, fields, pageSize } = props; | ||
|
||
const url = new URL(baseUrl); | ||
let query = url.searchParams.get("q"); | ||
const sort = query?.split(":")[1] || ""; | ||
|
||
if (!query) { | ||
query = `:relevance:allCategories:${categoryCode}`; | ||
} | ||
|
||
query = decodeURIComponent(query.replace(/\+/g, " ")); | ||
|
||
const data: ProductListResponse = await api[ | ||
"GET /users/anonymous/eluxproducts/search" | ||
]({ | ||
currentPage, | ||
fields: `${fields},facets,products(FULL)`, | ||
pageSize, | ||
query, | ||
sort: "approvalStatusSort", | ||
searchType: "FINISHED_GOODS", | ||
}).then( | ||
( | ||
res: Response, | ||
) => res.json(), | ||
); | ||
|
||
const products = data.products.map(convertProductData); | ||
|
||
let breadcrumb: BreadcrumbList = { | ||
"@type": "BreadcrumbList", | ||
itemListElement: [], | ||
numberOfItems: 0, | ||
}; | ||
if (data.breadcrumbs) { | ||
breadcrumb = convertBreadcrumb(data.breadcrumbs); | ||
} | ||
|
||
const filters = convertFacetsToFilters(data.facets); | ||
const [previousPage, nextPage] = getPreviousNextPagination(data.pagination); | ||
|
||
return { | ||
"@type": "ProductListingPage", | ||
breadcrumb, | ||
filters, | ||
products, | ||
pageInfo: { | ||
currentPage: data.pagination.currentPage, | ||
nextPage, | ||
previousPage, | ||
pageTypes: ["Category", "SubCategory", "Collection"], // TODO: Filter these types. | ||
recordPerPage: data.pagination.totalResults < data.pagination.pageSize | ||
? data.pagination.totalResults | ||
: data.pagination.pageSize, | ||
records: data.pagination.totalResults, | ||
}, | ||
sortOptions: [{ value: sort, label: sort }], | ||
}; | ||
}; | ||
|
||
export default PLPLoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// DO NOT EDIT. This file is generated by deco. | ||
// This file SHOULD be checked into source version control. | ||
// This file is automatically updated during development when running `dev.ts`. | ||
|
||
import * as $$$0 from "./loaders/categories/tree.ts"; | ||
import * as $$$2 from "./loaders/product/productDetailsPage.ts"; | ||
import * as $$$1 from "./loaders/product/ProductList.ts"; | ||
import * as $$$3 from "./loaders/product/productListingPage.ts"; | ||
|
||
const manifest = { | ||
"loaders": { | ||
"sap/loaders/categories/tree.ts": $$$0, | ||
"sap/loaders/product/productDetailsPage.ts": $$$2, | ||
"sap/loaders/product/ProductList.ts": $$$1, | ||
"sap/loaders/product/productListingPage.ts": $$$3, | ||
}, | ||
"name": "sap", | ||
"baseUrl": import.meta.url, | ||
}; | ||
|
||
export type Manifest = typeof manifest; | ||
|
||
export default manifest; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import type { App, FnContext } from "deco/mod.ts"; | ||
import { createHttpClient } from "../utils/http.ts"; | ||
import manifest, { Manifest } from "./manifest.gen.ts"; | ||
import { PreviewContainer } from "../utils/preview.tsx"; | ||
import { Markdown } from "../decohub/components/Markdown.tsx"; | ||
import { API } from "./utils/client/client.ts"; | ||
|
||
export type AppContext = FnContext<State, Manifest>; | ||
|
||
/** @title */ | ||
export interface Props { | ||
/** | ||
* @title Api url | ||
*/ | ||
apiUrl: string; | ||
|
||
/** | ||
* @title Base site ID | ||
*/ | ||
baseSiteId: string; | ||
} | ||
|
||
export interface State extends Props { | ||
api: ReturnType<typeof createHttpClient<API>>; | ||
} | ||
|
||
/** | ||
* @title SAP | ||
* @description Loaders, actions and workflows for adding SAP Commerce to your website. | ||
* @category Ecommmerce | ||
* @logo https://fakestoreapi.com/icons/logo.png | ||
*/ | ||
export default function SAP(props: Props): App<Manifest, State> { | ||
const { apiUrl, baseSiteId } = props; | ||
|
||
const api = createHttpClient<API>({ | ||
base: `${apiUrl}/${baseSiteId}/`, | ||
headers: new Headers({ | ||
"Content-Type": "application/json", | ||
Accept: "application/json", | ||
}), | ||
}); | ||
|
||
return { | ||
state: { ...props, api }, | ||
manifest, | ||
}; | ||
} | ||
export const preview = async () => { | ||
const markdownContent = await Markdown( | ||
new URL("./README.md", import.meta.url).href, | ||
); | ||
return { | ||
Component: PreviewContainer, | ||
props: { | ||
name: "SAP Commerce", | ||
owner: "deco.cx", | ||
description: | ||
"Loaders, actions and workflows for adding SAP Commerce Platform to your website.", | ||
logo: | ||
"https://www.sap.com/dam/application/shared/logos/sap-logo-svg.svg/sap-logo-svg.svg", | ||
images: [], | ||
tabs: [ | ||
{ | ||
title: "About", | ||
content: markdownContent(), | ||
}, | ||
], | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { proxy } from "deco/clients/withManifest.ts"; | ||
import { Manifest } from "./manifest.gen.ts"; | ||
|
||
export const invoke = proxy<Manifest>(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { | ||
CatalogsResponse, | ||
ProductDetailsResponse, | ||
ProductListResponse, | ||
} from "../types.ts"; | ||
|
||
export interface API { | ||
"GET /users/anonymous/eluxproducts/search": { | ||
response: ProductListResponse; | ||
}; | ||
"GET /catalogs?:fields": { | ||
response: CatalogsResponse; | ||
}; | ||
"GET /products/:productCode": { | ||
response: ProductDetailsResponse; | ||
searchParams: { | ||
productCode: string; | ||
fields: string; | ||
}; | ||
}; | ||
} |
Empty file.
Oops, something went wrong.