diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategories-returns-data.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategories-returns-data.json new file mode 100644 index 0000000000..79291dcf25 --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategories-returns-data.json @@ -0,0 +1,67 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories?ids=womens-clothing%2Cmens-clothing&levels=2&siteId=RefArchGlobal", + "body": "", + "status": 200, + "response": [ + "1f8b0800000000000003ec944d6fdb300c86effd15840fdb258efbb10c6b8e4b2fc556f490023b0c43c148b4a34d1603916e9a0efbef83dc74ab53a75fdba1875e8248a425f2a5dee7e70e40e65ded341bc3fe20ad2c2a6663f8ba0300f0b3fd05c80c2a551c1dc99fd8ed789be36c36866cc93505c9b9d1d2a964834e468d15a5a4b9ea42c645717515cb7c77776f2818ec8c2f878dec1e0cede5d0705d5334643c377628e8494a8e8652a0e05058aa31d825461a8aa23a53e4c5d429492eca91cac84173838a9eabbcce03879cd25725365e0bbbfc604687fbb3f765d196248578d6429ad9f90c43a0288541cdafffe7dd8e86df1755b7ab8075dbd4695fcb0bace888c444b750c721e5f1b6bc33a79eeec9881474723d88d5f16db18d679dbb50ddf7c15924eacc6e737e7766d839add3e997eb7827fc6bf0f893fb0bee5c31b9c978fe257d2af60eac7bc5add5b78e9ee69c02ce3c4db84ed2666328d10b6de4c89c97c7e18442938d4163433b3dc56ff7cd8d32b9f2e2c5ba67ef60442324fb04f7a476b65be7ec4eb33dbe99ce7901edd37b2b309dbba83284e99ca302060b9e4305e2892e6800a79725473b00a931ea000c4a83be4d331e459c01d19527819223346146a869b460b82ed38165e41a56dc44b0243f4019744e504542056ed43247015498", + "ac9586492bf5dd1e3ed16ac9d1cadf1183a4d207b05ed948b2b9b7e40b0a1b7b5c96ced0c6e6baaf76f31e9edc88966406178c6fac0bd55abb37f03929375d2b37698f1cc064add31b38e148af28fa27146d77f55d1b3c9b4609360fc16833eeae6832c7a8c7470fced09c279b7f6c5d7dfc6250b46bcbd1e1e8803a28f218d2032ffad46f21f44c26b75ea5178b654bef3e1cec213d01cbeb8eb693f9a8afe587e0bc3eb5852b7a0f6c0c8ae3701b3e25c73a71862e28a475cbe66b9cb9000817181de90ab804c3be17b78f20ded14625a73795bc02edff00adcf12bd0fa88dff060000ffff", + "ec98c16edb300c86ef7b0a9eda8b13b4c65620d8a92b3060dd6143d617602c2676625b0545c7cbdb0fb4652371eca409ba211872952c4ab4f47ff8c94b3359332b62b38b157418de4d66e1fdc71304ed331a16f497be948f09fa856de188dd187e324692449572d16d46624725213776aa8c89694dacdee99609624243660c4f31452b754ef09264336225f4ad833966b670c0c5624126a82cdc2845270a04f17b06b024cc9d9a385e5878c55c5c458bcc329debc1aa28ad8d5ac5b84a3a635bbb056a0b67285b47f2033bd3ae6bcb7603fa2c1adb477992d5636fc098bf34f8d6e2f3bb1ed9a95de38575417b43013c6bccab6d7b57caf571a257557f9772a7b9b73399b8c4684597dbb90923a2fbaee13bcc449fd130139feb0fe0069e2cca896cf48b837a2ddcc08f4288158ae3b688f225e348c80919582067a4182b138941184da2a1b592934daaf2362498a40e2456cab05d27a62d4e03487257a4a84b2a10123a529f94d93569dc00ca18a5c2b056ad25a1c4c4e7a272d9e4d7c0cd6ea32ef5c1bb5f9528c4af6ced7c6fca9f9eccdecc9a5c370430b9c409e602bd0fb31797ed0d6c0173fb8ed39422b9bac0f7e363dfd51c54d87fc0c939914a75c4642e9595f34fe1643e79c01358c9648639f9b54e19a664dec6486da035a29c92815f7aecb16fde05e0144d956959e549f53a6a4f975635a01ee530a1584de39034bb5c70d0bc7878ac37e849e30a80f300302486c1e7f3afcac10f9da8477ed20589f76e3e9985480f2788b7496747c1fbf7ddce1cb336cd8a314c29c5dfaa3649324ab563edfbe84e2b3d8850e59a6ec0e69febde795ddf8885c8b229d86eaa9aed0f000000ffff", + "ec9a4d6ec2301085f73d450ed048905242ba44add42ed22ee8058c312815b5911dab82d35763e71f3b3841a05075074ab063e2797ef3cd14110f574486f05fe586781cd10dd1b087a6e47bc738e27b457e24d73f2598f908fe4e40f2c9868aa78cc7eb6c4b1df776446473372cb70a85ed0048587c691aff765d29ddc64739eca71a2fcfe01a79598be4d8ee395219eb596516f1a6b2743af5cc431e2bc971dc9d88e4b663dc1d540f1452231c91301c3f1a21358471f6d9870b7acb1943faaef2be7a94e6eb922de480ebf3e3092651300d5dc44f2d4badc6ee5c163271cdeb62257d6a3c858d97522414148f716fb7254848b0302ff48bedb5d4d558f52a59af09846b4ec414d796a95bb5b05096187465513cc33c7f06184d57e84e3b978bf89676d712f7f42c57702ca736bf61bb5c374919a06e4d8360860282bae856231a1d8f999b4250cb083fe05910398bd3650054fcb7f1531d3e55d193193c59b1930d3a5591534fe0547b0546d834dfa2c38170f12fd7e7c8f54df1a59beba1c0eb49309a8e669d65beaa6bbd845e558f7d9d080ed68a4641b8c22176b7a23aaf6d6fa9c8185817a5af748a096b8f04e4d8da7896ad1622e5c90e92f7a54c5346bd15fba1f71e2c34e18c16d4ad437b455c3657640ba9b695e5d3cdf574cf6aba7746fdb75f000000ffff", + "ec9ad10e822014865fa527708892f0106e6d6ede8bc665b57affad71bc9012944356ac7800060738df76f67fe3767ec964e26140dfb83fda47b5b20821c779c74b515568c8c15d1b3d1d04ba9b562de315c728a7392b150271e745c435967257e6edcb1550050b35dd7afd04a76cd7da666bad6d0700ab1937b19f2e11083540cfefd0f603fe7e84cea55244a8237e849e5a2c8838201fc50a9ca2a232e764f0060e54e3e6cd615eec326e3614da1e19f415a9cd54dae6425bb8ce6691d94c950d21b28db70ecff406892d811ac3014be7a47119012f36889e33b247237d82d86a3e1d7d3a5d0c8c482a3a6f826f954dd73f924c67ee68fa39983662698f50ba7644d2906984c4d1af86d1c6fa3b000000ffff", + "c25b8892d0baa1eb343417cc24b0294a25f9258939a0edd25cb500000000ffff", + "0300772c72733f3d0000" + ], + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:41 GMT", + "content-type", + "application/json;charset=UTF-8", + "transfer-encoding", + "chunked", + "connection", + "close", + "cf-ray", + "73f62f1d6d13a70f-PHX", + "allow", + "GET, HEAD, OPTIONS", + "cache-control", + "public, must-revalidate, max-age=900", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "vary", + "accept-encoding", + "cf-cache-status", + "DYNAMIC", + "_sfdc_personalization_group_id", + "e2f546e3a8fd618560d80ce9ea16b40223dc2b67fe53352238d5396843eac93c", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "jweb", + "y", + "x-content-type-options", + "nosniff, nosniff", + "x-correlation-id", + "73f62f1d6d13a70f", + "x-envoy-upstream-service-time", + "34", + "x-frame-options", + "SAMEORIGIN", + "x-ratelimit-limit", + "11700", + "x-ratelimit-remaining", + "11700", + "x-xss-protection", + "1; mode=block", + "server", + "cloudflare", + "content-encoding", + "gzip", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories?ids=womens-clothing%2Cmens-clothing&levels=2&siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-data.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-data.json new file mode 100644 index 0000000000..542f72fefa --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-data.json @@ -0,0 +1,63 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories/newarrivals?siteId=RefArchGlobal", + "body": "", + "status": 200, + "response": [ + "1f8b0800000000000003000000ffff", + "e4954d6f1b470c86effa15c41e92cb7e284e1ddb425d207151c005940470d01caac2a066b9da716687c2909b8d12e4bf173bfab6e4c0e929482fd200e472c899f77de6cb002031a834e360499211fc3d0000f8127f01125b2623483c751882fd884eb28e1bf292a49b8c0667d427d5aa731915c5e7cfa1ca86c367b9a02fa7fc296f65f83c2f3fe5869b868221e3b82d734147527130d4070af645490dfab2c340b928aa354556dc5825c944395015d86b6650d1f12c6b32cf3ea3feab0a5ba745d90dab8be909d28b22b6248538d642dae9ed14bda7208541cd96ebd5149971acb5f5b3fc6e3edb8ee4b18913bdbf37ea1c67f43b890976ae967d9ff29a3a78b93a1ab01e9675a142a92d7b9c3a02f425882e9c951a6e6a2649e10ecd0752892140e780b5a600eb6ea0e200ad9f126aac60b8a9382894b800ebd3f8cfade6f036a0516bd0c54abb9bf61b92405753a08f14406b023606c5b2cff7277a67d5d1b159e2f84f05fe60d68e30a4f0a6550acbe5d5bad727f0d21812590a68a77220af574b692daeefcbe8a1c4778168a3c25d251e57e3a6ccdebded0e926c12bea68f2c7a5fe2c734b1adba5afdb319c8dc52bc832b6efad9921154e88476e2527377edc7e4db64041adabd98637d15357afdc3180bcd059d9d3d3bdd3396435f5a3f8ba65aadb33e3065556e8e1a6cb0730ddf20cc8fca97e7e5e9707a72818fe1cb23e832fe5eb6f41fc01e3bfe3b3052209445a69cf5763ec0c582dba781a0262ca97c2c2fc691166b30a470d35a959f910f0fd361fcbf63c3f9399eff727176f63d6c88e6280389486d83ca0e1c06abd37ae02a8f5f618c1c31d04dcdf3f8bc7aea00b74a35aeed5b5a3ed6d148f1d1361be5de51472e2c52c0ad745390959e1b0e04a870b53ada5ef26db9ed626390f79bfad1baf7fdb275ca9febfd76ac024f60cc81d6650fdd1298f55874cf220f63f6104887b6d85ec737849b98dbc889d08b7629cfbedaafb699013abd9cec83224a779280047339f969deb649029d2db5be9c242727a793048adf9283c379132cf9bec9a53cffa21059bc4e3cb0fee0ebbf000000ffff", + "03008b50d7bca00b0000" + ], + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:41 GMT", + "content-type", + "application/json;charset=UTF-8", + "transfer-encoding", + "chunked", + "connection", + "close", + "cf-ray", + "73f62f214f76a71a-PHX", + "allow", + "GET, HEAD, OPTIONS", + "cache-control", + "public, must-revalidate, max-age=900", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "vary", + "accept-encoding", + "cf-cache-status", + "DYNAMIC", + "_sfdc_personalization_group_id", + "e2f546e3a8fd618560d80ce9ea16b40223dc2b67fe53352238d5396843eac93c", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "jweb", + "y", + "x-content-type-options", + "nosniff, nosniff", + "x-correlation-id", + "73f62f214f76a71a", + "x-envoy-upstream-service-time", + "14", + "x-frame-options", + "SAMEORIGIN", + "x-ratelimit-limit", + "11700", + "x-ratelimit-remaining", + "11699", + "x-xss-protection", + "1; mode=block", + "server", + "cloudflare", + "content-encoding", + "gzip", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories/newarrivals?siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-error.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-error.json new file mode 100644 index 0000000000..a1766a7c55 --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/usecategory-returns-error.json @@ -0,0 +1,105 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories/abc?siteId=RefArchGlobal", + "body": "", + "status": 404, + "response": { + "title": "Category Not Found", + "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/category-not-found", + "detail": "No category with ID 'abc' for site 'RefArchGlobal' could be found.", + "categoryId": "abc", + "siteId": "RefArchGlobal" + }, + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:42 GMT", + "content-type", + "application/problem+json; charset=UTF-8", + "content-length", + "272", + "connection", + "close", + "host", + "lb001-mprd-use1.cloudhub.commercecloud.salesforce.com", + "cf-ew-via", + "15", + "cdn-loop", + "cloudflare; subreqs=1", + "x-real-ip", + "162.158.142.225", + "x-forwarded-proto", + "https", + "cf-ray", + "73f62f244e2b1afb-PHX", + "accept-encoding", + "gzip", + "accept", + "*/*", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "user-agent", + "Amazon CloudFront", + "cf-cache-status", + "DYNAMIC", + "_is_allowed", + "true", + "_sfdc_badge", + "1fd0c2e5-f426-40d3-bf3b-e6a9ba2c22b6", + "_sfdc_c2c_jti", + "C2C4856201860-189067890319256445710512518", + "_sfdc_client_id", + "c9c45bfd-0ed3-4aa2-9971-40f88962b836", + "_sfdc_customer_id", + "c89ed2ba-78ef-4b54-ae2b-388d193b7ab6", + "_sfdc_customer_idp", + "slas", + "_sfdc_customer_login", + "guest", + "_sfdc_customer_type", + "guest", + "_sfdc_customer_visit_id", + "c89ed2ba-78ef-4b54-ae2b-388d193b7ab6", + "_sfdc_org_id", + "f_ecom_zzrf_001", + "_sfdc_shopperjwt_type", + "slas", + "cf-connecting-ip", + "13.110.54.14", + "cf-visitor", + "{\"scheme\":\"https\"}", + "cf-worker", + "commerce-api-eu.api.commercecloud.salesforce.com", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "true-client-ip", + "13.110.54.14", + "x-correlation-id", + "73f62f244e2b1afb", + "x-forwarded-for", + "13.110.54.14, 162.158.142.225", + "x-forwarded-host", + "kv7kzm78.api.commercecloud.salesforce.com", + "x-forwarded-proto-real", + "https", + "x-mobify", + "true", + "x-ssl-client-dn", + "/C=US/ST=California/L=San Francisco/O=salesforce.com, inc./CN=cloudflare.api.commercecloud.salesforce.com", + "x-ssl-client-serial", + "6283AC6B34ED9D02", + "x-ssl-client-verify", + "SUCCESS", + "x-ssl-issuer", + "/C=US/ST=California/L=San Francisco/O=salesforce.com, inc./CN=salesforce.com Internal CA PHX 2", + "Vary", + "Accept-Encoding", + "server", + "cloudflare", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/categories/abc?siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproduct-returns-data.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproduct-returns-data.json new file mode 100644 index 0000000000..846b01ef6f --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproduct-returns-data.json @@ -0,0 +1,64 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products/25502228M?siteId=RefArchGlobal", + "body": "", + "status": 200, + "response": [ + "1f8b0800000000000003000000ffff", + "dc544d6f133110bde757587bceda5e27db34390644a4aaa0882221055568e299dd1abc1fb2bd4d3fc47f47d924a5e540402961cbc5b26734e337f39ede7d8fb14837ce51a96fa3098b66d379d45f070dae9f2a4da552eaf4ed3658404e335735b58f26ec538f31c6eedb7397fc117f9c6bf360c3bae5946c2064afc0a1c9a1641f4db86217a141df677d66c1e5d47ef65087c64fc1d3b929bfaeebaf42a8fd4408c29c381aef43ce755514e434695b35c83d58f259e534ad130257a28526ae95582cdebff92c6522aa52201550e20a1c711f20182d62716102f918ea1a1cd9b8883504b0552e9032686c10b84ab41ac86136def4f4a2052ce6339e4895a4c968cccfcee4bbf3d792cf17fc4b9d3f9dc5fe34c4dd9dcb622913eea1c46575c31b2f071c6f7e3dd13f021f4cb0b48fc2e8a1e25bff7fd6811ae825924ef7af72da3d1d1c06fe4f75b0bd5dee9a44d786561f6eebb6c786e8de23c13cafa11484a629baaca454255a8ee16447c606f14bb19403d11fd353ba2f8565321c110dd3df5866075de540f4cf6a2b5baeff9eaff802acedb29620253c1911edd86801bf1457390cfc314da5f33a504bc84ed34ced5fe5312ce53b000000ffff", + "d458db6a1b31107dcf570893d775b44edc5ca094c421216063b74e4a2894a2dd1daf45b49291669dba907f2f92f6e2cbba0ea909e4d15a8dced1ccd191c6ef4a7eaf8ee20b7d504efce91b223907894adbdec96ba7c5d05acbf129f5abb422163f299d806691233361c240f1cd3759d522bfcacba9b51c803a2fe7cf346c5bcaa08a9ffa3007e1d10f0a5db78492e9359858f31972252de030d7240283c480105ca6242e13c30d91ea99e4b384d9843ddb3c319200b2786a4149040209930931367b6d32625c138ee5cc5ea102d2b3322063541a889982102e88a3454835302413a589e4120254c184cfc14d8860a164d2f6dd66c60c82ae33eb7fdf3534a6ffca188fedd0a7b07d725ce524e37268e77fcd99448eb67aa1fb2059b643309eda8ca5f031936a99dfef3e17c5e4e5ecd52323d00f92e3fa878ce9458f21a44a2f7c959e5506d204b15038e5320d50cdaa955592c738d22a5336830dff27c44c0895e3c0a48e6abe204a02e92b99921e48044dc6c032327ee2da672f05241d526114f52f003ca1de54f11886932b257333d22a81188391e7e20e4fa07301d6bd93e6b7c32aa9c32e2537fc3724a458c390cb4ce512c965a4e640424ab75239ec52175a46fa401767c35e81ee365122bbd23b5117144cc1a1d3ddcea14a431ee3d01f89e1a42072a5e66063d71c4f83737a99b02d655b9d50b8677dafdadb7126d8e23b13b9d360c9ff1a907141462c0512909e56c69031acdcadad7911141eacdddc352a247708d9924984e79dc1fa26cc5469fc98e7d7883c7dd0e2ffef6473f40d26973a9ede0a15317114392f08ca5d07967ce0367454996d7b8a99f822984c3f177774410a61b6e1a5b85cfadaccad3957463c678227375a65f5c472615b3f1ad2200c83f0ec9e762f28bda0b44d29fdd15a8ad79c496c9061f37dd0e469e5c1b02af4ba39a5e1a793ced9d9f959e778501f1e0766e5e2b46b56651d2ba1ecf65ac5836459b686ff71523fefdf96af8d97c6f3bd1fd227a77b253d1ebc07e963ba57d283ebf720dd3dd92be9c7fe1ae9cab0aab52f11358f7284a63fe01d3b8f54b12a5f34bdd5e179c9714b0f5c86f559ae61adbfd996bb158bae36baf9bc6e6eca1d79978a0deee395d1d7521fbf85f592dab7378625c2e04d08b5347723f4df8450dbcc6e84c7b741d452dd28ac15edc1cb5f000000ffff", + "03006a25a7345a1a0000" + ], + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:40 GMT", + "content-type", + "application/json;charset=UTF-8", + "transfer-encoding", + "chunked", + "connection", + "close", + "cf-ray", + "73f62f1a387d1b05-PHX", + "allow", + "GET, HEAD, OPTIONS", + "cache-control", + "public, must-revalidate, max-age=60", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "vary", + "accept-encoding", + "cf-cache-status", + "DYNAMIC", + "_sfdc_personalization_group_id", + "e2f546e3a8fd618560d80ce9ea16b40223dc2b67fe53352238d5396843eac93c", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "jweb", + "y", + "x-content-type-options", + "nosniff, nosniff", + "x-correlation-id", + "73f62f1a387d1b05", + "x-envoy-upstream-service-time", + "71", + "x-frame-options", + "SAMEORIGIN", + "x-ratelimit-limit", + "28000", + "x-ratelimit-remaining", + "28000", + "x-xss-protection", + "1; mode=block", + "server", + "cloudflare", + "content-encoding", + "gzip", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products/25502228M?siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-data.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-data.json new file mode 100644 index 0000000000..56dd55f977 --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-data.json @@ -0,0 +1,65 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products?ids=25502228M%2C25503045M&siteId=RefArchGlobal", + "body": "", + "status": 200, + "response": [ + "1f8b0800000000000003000000ffff", + "d496db6adb4010865f65996b59274771a24b273410d2d63485424a09a3dd91bccd6a57ec8eec1cc8bb17d971692934890945bd935673f8673e7e490f6074ab19ca3c02858c507e7d00d97b4f56de410967f30544a015949017459ae7f9d1fbe1a0c586cebcebbbb0c9d8dc6f2fd130943027c3a4c4097aa51bb4e28be6a5b8e45e854844c2a06f0822503acc31d085b63750c292b90b6592906a28563a046e62e9da96bc24695cafe2808642edbca4e141a2d6c9a671b2ca93abab4fefaed3344b9c4d14b568d51a3dc58191b54c26c9a5660a13ec3af46426ed4422a3714da2a8c6de70a2d699cca7e9417dbcad19928dc864711667699e15d9ec383e3f4f3f5c9ca6f1e22afede351081f95df8fdbdaf27699ac501adaadc6ddc87741aabdbbf4ff12f05b36643cfe081c7e83fa6984f65a54816cf2f653e0e8a7b087e19c56f11ac34ad3fdf7543ec16d680f6955e6d49e9be1d1be622cf647a8c87bbad6d558ed9adfb287e53bb8e1364951dcc880e8a17ac652486dd47f13e8e7de2b58765438bc68c0d3416a40e6744bbb56d448ed9b07b087e53bf8e92625e617d54d4f9f34b19cbe7f5f582f731eb16d670a8ed8a2c3b7f07e503200728a7b334820ae58df38a3c5643f11a4da0a71feb9f19d7c3dbf99720f63d45d079fa3331b0933717b422b3a9ff188171b639a520bdee583b0b257cecbda828b008648cb68d90bb497410d6ad45df291c265c0f83a150c42897431b519161815689308c1b8b056a2f34ef224f9e5089938195b864e749842519b349d23c74683c218bda7961b5a509bb49ad573f000000ffff", + "d4586d6fda3010fe2b96d58f843a6f6d409a264ad56a1d0836da0a6dea072731219a63578ec3c62afefb64e785764028f025fd86c9dd3de7bbf373f6112de0932567611bb660825349840a55feebcbff2f8d2de1880302bb1766dbb1572d98c46ca444be6598c9582e61d76c418693fa04c2167cc611f978f1525edfefad4ff8364cc56a4cc403536fbdf59f0916cb3e9624e262a943ff9b2784a54640b99cc72c32247fceadf1300be458f084ab68e5bd28c094f24c0ed34879932d0167040c388b409f30490498109c80c9af58e4c189880416589bcc6d69dcfe9cc70119cdae38cbd2b1e02109a431ce5175991b22a344f160a809f40df4998bc04dfc8784a0d048412fe11993a0e7f3050126421b80672ed22aa546aea0e595f8068676acb4afb3a4cbae004a0b24cbdd44aab69405729417eb6856c05df105513a8a38d23917f2e355644ab3e841d093193e3dff4e663d11cc6f29f7313df775751be58e0de5b8a137735ef1437b2e13fa9962167d2a185f3924c9f31b36909aa25f2aae513cb26ac105a671782378a2be95ea5d68211319a66998de3d72bb0875116a23847e40ad2262cc645efdb5cc541d195d0297c8bc702ccfeb7896ad484ddb51397ec4345317bb171870ca05ecc2a21ba97dc47fd529ef0c6ee14a95e35178cee5c17893e10978363a186f787d029eeb1c8c371dc095eedea5524f4a11fb992c6ed8ba27e7ea5527e917cb4561ffe74bf965803341e8b646a5655f79b07ad25779655dbb52199fe4ab4ddb933ab33a4fad4a76582bab62bc961dd4caaa7a5bcb4eeb8555309ff29ded9e1adac871df3535bce6128cb19444b0aaad3576d284023b084cc7da3ab8f14cc76ddfddd95f1fa7d3a63c688e70b8bc0a6f4fccaba7cc87ca5ce87766c8b6fcfd8168c823e60887f765eeddd3c15d996de638c90b3cd3b74373fb70a689a7f2188f4f3e96cd4c9e332333dc71dd7784a22107f3188f0f3b997553c05dd96de4e4c8f330ea78ff000000ffff", + "ecd8410b82301407f0af323c579a92635dbb77e9d031d6341c450bf72a3af4dd436d26a59399c288ae63f27f6ff8c4fd70580b31560ea679c15fcfa59d728bb78c32c2da0fc292a9ec50b0d9506ab58fe061b58fe05aed5bc70884d82348b844ec40a5e4ece505d99d5d618152809b38a768472f22e510a348003a159d6b614efdcc375ed7fc89875b60aeee946b49aee7a6aa7ad65443a58b0f372b17ff6e66b59bf5fcda0c455c9180f133a6742eb79c313b714b8dc01bc6045e10126fd68a31f967d704b7747953df38af159b747941689c976353d73c9f18e7e578d7336eb96891f0a3d01b5751c82f1bd7c8611b2e97f11562096a53b6b4a2eaa16c1308a00767eedf1f000000ffff", + "0300f0dbc1f45b270000" + ], + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:39 GMT", + "content-type", + "application/json;charset=UTF-8", + "transfer-encoding", + "chunked", + "connection", + "close", + "cf-ray", + "73f62f100bb5df08-PHX", + "allow", + "GET, HEAD, OPTIONS", + "cache-control", + "public, must-revalidate, max-age=60", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "vary", + "accept-encoding", + "cf-cache-status", + "DYNAMIC", + "_sfdc_personalization_group_id", + "e2f546e3a8fd618560d80ce9ea16b40223dc2b67fe53352238d5396843eac93c", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "jweb", + "y", + "x-content-type-options", + "nosniff, nosniff", + "x-correlation-id", + "73f62f100bb5df08", + "x-envoy-upstream-service-time", + "124", + "x-frame-options", + "SAMEORIGIN", + "x-ratelimit-limit", + "28000", + "x-ratelimit-remaining", + "28000", + "x-xss-protection", + "1; mode=block", + "server", + "cloudflare", + "content-encoding", + "gzip", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products?ids=25502228M%2C25503045M&siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-error.json b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-error.json new file mode 100644 index 0000000000..76fbb0b4bb --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/mock-responses/useproducts-returns-error.json @@ -0,0 +1,103 @@ +[ + { + "scope": "http://localhost:3000", + "method": "GET", + "path": "/mobify/proxy/api/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products?ids=22%2C9%2C12%2C2%2C24%2C25%2C9%2C9%2C1%2C9%2C21%2C20%2C24%2C0%2C1%2C8%2C15%2C24%2C7%2C22%2C5%2C22%2C18%2C13%2C8%2C16&siteId=RefArchGlobal", + "body": "", + "status": 400, + "response": { + "title": "Bad Request", + "type": "https://api.commercecloud.salesforce.com/documentation/error/v1/errors/validation", + "detail": "Maximum number of products you can request in one call is 25." + }, + "rawHeaders": [ + "date", + "Tue, 23 Aug 2022 19:16:40 GMT", + "content-type", + "application/problem+json; charset=UTF-8", + "content-length", + "200", + "connection", + "close", + "host", + "lb001-mprd-use1.cloudhub.commercecloud.salesforce.com", + "cf-ew-via", + "15", + "cdn-loop", + "cloudflare; subreqs=1", + "x-real-ip", + "162.158.142.173", + "x-forwarded-proto", + "https", + "cf-ray", + "73f62f150b38a6f7-PHX", + "accept-encoding", + "gzip", + "accept", + "*/*", + "strict-transport-security", + "max-age=31536000; includeSubdomains;", + "user-agent", + "Amazon CloudFront", + "cf-cache-status", + "DYNAMIC", + "_is_allowed", + "true", + "_sfdc_badge", + "1fd0c2e5-f426-40d3-bf3b-e6a9ba2c22b6", + "_sfdc_c2c_jti", + "C2C4856201860-189067890319256445710512518", + "_sfdc_client_id", + "c9c45bfd-0ed3-4aa2-9971-40f88962b836", + "_sfdc_customer_id", + "c89ed2ba-78ef-4b54-ae2b-388d193b7ab6", + "_sfdc_customer_idp", + "slas", + "_sfdc_customer_login", + "guest", + "_sfdc_customer_type", + "guest", + "_sfdc_customer_visit_id", + "c89ed2ba-78ef-4b54-ae2b-388d193b7ab6", + "_sfdc_org_id", + "f_ecom_zzrf_001", + "_sfdc_shopperjwt_type", + "slas", + "cf-connecting-ip", + "13.110.54.14", + "cf-visitor", + "{\"scheme\":\"https\"}", + "cf-worker", + "commerce-api-eu.api.commercecloud.salesforce.com", + "expect-ct", + "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", + "true-client-ip", + "13.110.54.14", + "x-correlation-id", + "73f62f150b38a6f7", + "x-forwarded-for", + "13.110.54.14, 162.158.142.173", + "x-forwarded-host", + "kv7kzm78.api.commercecloud.salesforce.com", + "x-forwarded-proto-real", + "https", + "x-mobify", + "true", + "x-ssl-client-dn", + "/C=US/ST=California/L=San Francisco/O=salesforce.com, inc./CN=cloudflare.api.commercecloud.salesforce.com", + "x-ssl-client-serial", + "6283AC6B34ED9D02", + "x-ssl-client-verify", + "SUCCESS", + "x-ssl-issuer", + "/C=US/ST=California/L=San Francisco/O=salesforce.com, inc./CN=salesforce.com Internal CA PHX 2", + "Vary", + "Accept-Encoding", + "server", + "cloudflare", + "x-proxy-request-url", + "https://kv7kzm78.api.commercecloud.salesforce.com/product/shopper-products/v1/organizations/f_ecom_zzrf_001/products?ids=22%2C9%2C12%2C2%2C24%2C25%2C9%2C9%2C1%2C9%2C21%2C20%2C24%2C0%2C1%2C8%2C15%2C24%2C7%2C22%2C5%2C22%2C18%2C13%2C8%2C16&siteId=RefArchGlobal" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.test.tsx b/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.test.tsx new file mode 100644 index 0000000000..3908411c98 --- /dev/null +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.test.tsx @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import React, {ReactElement} from 'react' +import '@testing-library/jest-dom' +import {mockHttpResponses, renderWithProviders} from '../../test-utils' +import {useCategories, useCategory, useProduct, useProducts} from './query' +import {screen, waitFor} from '@testing-library/react' + +const {withMocks} = mockHttpResponses({directory: `${__dirname}/mock-responses`}) +const ProductsComponent = ({ids}: {ids: string}): ReactElement => { + const {data, isLoading, error} = useProducts({ + ids + }) + return ( +
+ {isLoading && Loading...} + {data && ( +
+
Total: {data.total}
+
+ )} + {data && ( +
+ {data.data?.map(({name}) => ( +
{name}
+ ))} +
+ )} + {error && error} +
+ ) +} + +const ProductComponent = ({id}: {id: string}): ReactElement => { + const {data, isLoading, error} = useProduct({ + id + }) + return ( +
+ {isLoading && Loading...} + {data &&
{data.name}
} + {error && error} +
+ ) +} + +const CategoriesComponent = ({ids}: {ids: string}): ReactElement => { + const {data, isLoading, error} = useCategories({ + ids, + levels: 2 + }) + return ( +
+ {isLoading && Loading...} + {data &&
Total: {data.total}
} + {data && ( +
+ {data.data?.map(({id}: {id: string}) => ( +
{id}
+ ))} +
+ )} + {error && error} +
+ ) +} + +const CategoryComponent = ({id}: {id: string}): ReactElement => { + const {data, isLoading, error} = useCategory({ + id + }) + return ( +
+ {isLoading && Loading...} + {data &&
{data.name}
} + {error && error} +
+ ) +} +const tests = [ + { + hook: 'useProducts', + cases: [ + { + name: 'returns data', + assertions: withMocks(async () => { + const ids = '25502228M,25503045M' + renderWithProviders() + const productNames = ['Dot Pattern Cardigan', 'Belted Cardigan With Studs'] + + expect(screen.queryByText(productNames[0])).toBeNull() + expect(screen.queryByText(productNames[1])).toBeNull() + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText(productNames[0])) + expect(screen.getByText(productNames[0])).toBeInTheDocument() + expect(screen.getByText(productNames[1])).toBeInTheDocument() + expect(screen.getByText(`Total: ${productNames.length}`)).toBeInTheDocument() + }) + }, + { + name: 'returns error', + assertions: withMocks(async () => { + // limit of id is 25, generating 26 random ids here to get an 400 error from server + const fakeIds = [...new Array(26)] + .map((i) => Math.floor(Math.random() * 26)) + .join(',') + renderWithProviders() + + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText('error')) + expect(screen.getByText('error')).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + } + ] + }, + { + hook: 'useProduct', + cases: [ + { + name: 'returns data', + assertions: withMocks(async () => { + const id = '25502228M' + renderWithProviders() + const productName = 'Belted Cardigan With Studs' + + expect(screen.queryByText(productName)).toBeNull() + expect(screen.getByText('Loading...')).toBeInTheDocument() + + await waitFor(() => screen.getByText(productName)) + + expect(screen.getByText(productName)).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + }, + { + name: 'returns error', + assertions: withMocks(async () => { + renderWithProviders() + + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText('error')) + expect(screen.getByText('error')).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + } + ] + }, + { + hook: 'useCategories', + cases: [ + { + name: 'returns data', + assertions: withMocks(async () => { + const catIds = ['womens-clothing', 'mens-clothing'] + renderWithProviders() + + expect(screen.queryByText(catIds[0])).toBeNull() + expect(screen.queryByText(catIds[1])).toBeNull() + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText(`Total: 2`)) + expect(screen.getByText(catIds[0])).toBeInTheDocument() + expect(screen.getByText(catIds[1])).toBeInTheDocument() + expect(screen.getByText(`Total: ${catIds.length}`)).toBeInTheDocument() + }) + }, + { + name: 'returns error', + assertions: withMocks(async () => { + // limit of id is 50, generating 51 random ids here to get an 400 error from server + const fakeIds = [...new Array(51)] + .map((i) => Math.floor(Math.random() * 26)) + .join(',') + renderWithProviders() + + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText('error')) + expect(screen.getByText('error')).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + } + ] + }, + { + hook: 'useCategory', + cases: [ + { + name: 'returns data', + assertions: withMocks(async () => { + const id = 'newarrivals' + renderWithProviders() + const categoryName = 'New Arrivals' + + expect(screen.queryByText(categoryName)).toBeNull() + expect(screen.getByText('Loading...')).toBeInTheDocument() + + await waitFor(() => screen.getByText(categoryName)) + + expect(screen.getByText(categoryName)).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + }, + { + name: 'returns error', + assertions: withMocks(async () => { + renderWithProviders() + + expect(screen.getByText('Loading...')).toBeInTheDocument() + await waitFor(() => screen.getByText('error')) + expect(screen.getByText('error')).toBeInTheDocument() + expect(screen.queryByText('Loading...')).toBeNull() + }) + } + ] + } +] + +tests.forEach(({hook, cases}) => { + describe(hook, () => { + cases.forEach(({name, assertions}) => { + test(name, assertions) + }) + }) +}) diff --git a/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.ts b/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.ts index 84e9f52f4e..e413110630 100644 --- a/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.ts +++ b/packages/commerce-sdk-react/src/hooks/ShopperProducts/query.ts @@ -7,10 +7,13 @@ import {ApiClients, Argument, DataType} from '../types' import {useAsync} from '../useAsync' import useCommerceApi from '../useCommerceApi' -import {UseQueryResult} from '@tanstack/react-query' +import {UseQueryOptions, UseQueryResult} from '@tanstack/react-query' type Client = ApiClients['shopperProducts'] +type UseProductsParameters = NonNullable>['parameters'] +type UseProductsHeaders = NonNullable>['headers'] +type UseProductsArg = {headers?: UseProductsHeaders; rawResponse?: boolean} & UseProductsParameters /** * A hook for `ShopperProducts#getProducts`. * Allows access to multiple products by a single request. Only products that are online and assigned to a site catalog are returned. The maximum number of productIDs that can be requested are 24. Along with product details, the availability, images, price, promotions, and variations for the valid products will be included, as appropriate. @@ -18,12 +21,33 @@ type Client = ApiClients['shopperProducts'] * @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperproducts.shopperproducts-1.html#getproducts} for more information on the parameters and returned data type. * @returns An object describing the state of the request. */ -export const useProducts = ( - arg: Argument -): UseQueryResult, Error> => { +function useProducts( + arg: Omit & {rawResponse?: false}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult, Error> +function useProducts( + arg: Omit & {rawResponse: true}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult +function useProducts( + arg: UseProductsArg, + options?: UseQueryOptions | Response, Error> +) { + if (!arg.ids) { + throw new Error('ids is required for useProducts') + } const {shopperProducts: client} = useCommerceApi() - return useAsync(['products', arg], () => client.getProducts(arg)) + const {headers, rawResponse, ...parameters} = arg + return useAsync( + ['products', arg], + () => client.getProducts({parameters, headers}, rawResponse), + options + ) } + +type UseProductParameters = NonNullable>['parameters'] +type UseProductHeaders = NonNullable>['headers'] +type UseProductArg = {headers?: UseProductHeaders; rawResponse?: boolean} & UseProductParameters /** * A hook for `ShopperProducts#getProduct`. * Allows access to product details for a single product ID. Only products that are online and assigned to a site catalog are returned. Along with product details, the availability, images, price, bundled_products, set_products, recommedations, product options, variations, and promotions for the products will be included, as appropriate. @@ -31,12 +55,36 @@ export const useProducts = ( * @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperproducts.shopperproducts-1.html#getproduct} for more information on the parameters and returned data type. * @returns An object describing the state of the request. */ -export const useProduct = ( - arg: Argument -): UseQueryResult, Error> => { +function useProduct( + arg: Omit & {rawResponse?: false}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult, Error> +function useProduct( + arg: Omit & {rawResponse: true}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult +function useProduct( + arg: UseProductArg, + options?: UseQueryOptions | Response, Error> +): UseQueryResult | Response, Error> { + if (!arg.id) { + throw new Error('id is required for useProduct.') + } + const {headers, rawResponse, ...parameters} = arg const {shopperProducts: client} = useCommerceApi() - return useAsync(['product', arg], () => client.getProduct(arg)) + return useAsync( + ['product', arg], + () => client.getProduct({parameters, headers}, rawResponse), + options + ) } + +type UseCategoriesParameters = NonNullable>['parameters'] +type UseCategoriesHeaders = NonNullable>['headers'] +type UseCategoriesArg = { + headers?: UseCategoriesHeaders + rawResponse?: boolean +} & UseCategoriesParameters /** * A hook for `ShopperProducts#getCategories`. * When you use the URL template, the server returns multiple categories (a result object of category documents). You can use this template as a convenient way of obtaining multiple categories in a single request, instead of issuing separate requests for each category. You can specify up to 50 multiple IDs. You must enclose the list of IDs in parentheses. If a category identifier contains parenthesis or the separator sign, you must URL encode the character. The server only returns online categories. @@ -44,24 +92,66 @@ export const useProduct = ( * @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperproducts.shopperproducts-1.html#getcategories} for more information on the parameters and returned data type. * @returns An object describing the state of the request. */ -export const useCategories = ( - arg: Argument -): UseQueryResult, Error> => { +function useCategories( + arg: Omit & {rawResponse?: false}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult, Error> +function useCategories( + arg: Omit & {rawResponse: true}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult +function useCategories( + arg: UseCategoriesArg, + options?: UseQueryOptions | Response, Error> +): UseQueryResult | Response, Error> { + if (!arg.ids) { + throw new Error('ids is required for useCategories') + } + const {headers, rawResponse, ...parameters} = arg + const {shopperProducts: client} = useCommerceApi() - return useAsync(['categories'], () => client.getCategories(arg)) + return useAsync( + ['categories', arg], + () => client.getCategories({parameters, headers}, rawResponse), + options + ) } + +type UseCategoryParameters = NonNullable>['parameters'] +type UseCategoryHeaders = NonNullable>['headers'] +type UseCategoryArg = { + headers?: UseCategoryHeaders + rawResponse?: boolean +} & UseCategoryParameters /** * A hook for `ShopperProducts#getCategory`. * When you use the URL template below, the server returns a category identified by its ID; by default, the server -also returns the first level of subcategories, but you can specify another level by setting the levels -parameter. The server only returns online categories. + also returns the first level of subcategories, but you can specify another level by setting the levels + parameter. The server only returns online categories. * @see {@link https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-products?meta=getCategory} for more information about the API endpoint. * @see {@link https://salesforcecommercecloud.github.io/commerce-sdk-isomorphic/classes/shopperproducts.shopperproducts-1.html#getcategory} for more information on the parameters and returned data type. * @returns An object describing the state of the request. */ -export const useCategory = ( - arg: Argument -): UseQueryResult, Error> => { +function useCategory( + arg: Omit & {rawResponse?: false}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult, Error> +function useCategory( + arg: Omit & {rawResponse: true}, + options?: UseQueryOptions | Response, Error> +): UseQueryResult +function useCategory( + arg: UseCategoryArg, + options?: UseQueryOptions | Response, Error> +): UseQueryResult | Response, Error> { + const {headers, rawResponse, ...parameters} = arg + const {shopperProducts: client} = useCommerceApi() - return useAsync(['category'], () => client.getCategory(arg)) + return useAsync( + ['category', arg], + () => client.getCategory({parameters, headers}, rawResponse), + options + ) } + +export {useProducts, useProduct, useCategories, useCategory} diff --git a/packages/commerce-sdk-react/tsconfig.json b/packages/commerce-sdk-react/tsconfig.json index f0c5a6b9d4..767fe15366 100644 --- a/packages/commerce-sdk-react/tsconfig.json +++ b/packages/commerce-sdk-react/tsconfig.json @@ -47,7 +47,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ "sourceMap": true /* Create source map files for emitted JavaScript files. */, // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "../commerce-sdk-react/dist" + "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ diff --git a/packages/template-typescript-minimal/tsconfig.json b/packages/template-typescript-minimal/tsconfig.json index f0c5a6b9d4..767fe15366 100644 --- a/packages/template-typescript-minimal/tsconfig.json +++ b/packages/template-typescript-minimal/tsconfig.json @@ -47,7 +47,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ "sourceMap": true /* Create source map files for emitted JavaScript files. */, // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "../commerce-sdk-react/dist" + "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ diff --git a/packages/test-commerce-sdk-react/app/components/Json.tsx b/packages/test-commerce-sdk-react/app/components/Json.tsx index 60e465b914..b0fbdfda11 100644 --- a/packages/test-commerce-sdk-react/app/components/Json.tsx +++ b/packages/test-commerce-sdk-react/app/components/Json.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, salesforce.com, inc. + * Copyright (c) 2022, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause diff --git a/packages/test-commerce-sdk-react/app/components/_app-config/index.tsx b/packages/test-commerce-sdk-react/app/components/_app-config/index.tsx index eedb437d82..a82f6920c9 100644 --- a/packages/test-commerce-sdk-react/app/components/_app-config/index.tsx +++ b/packages/test-commerce-sdk-react/app/components/_app-config/index.tsx @@ -1,10 +1,11 @@ /* - * Copyright (c) 2021, salesforce.com, inc. + * Copyright (c) 2022, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import React, {ReactElement} from 'react' +// @ts-ignore import {CommerceApiProvider} from 'commerce-sdk-react' interface AppConfigProps { @@ -18,7 +19,7 @@ const AppConfig = (props: AppConfigProps): ReactElement => { shortCode="8o7m175y" clientId="c9c45bfd-0ed3-4aa2-9971-40f88962b836" organizationId="f_ecom_zzrf_001" - proxy="/mobify/proxy/api" + proxy="http://localhost:3000/mobify/proxy/api" locale="en-US" currency="USD" > diff --git a/packages/test-commerce-sdk-react/app/components/_app/index.tsx b/packages/test-commerce-sdk-react/app/components/_app/index.tsx new file mode 100644 index 0000000000..664ff38e5d --- /dev/null +++ b/packages/test-commerce-sdk-react/app/components/_app/index.tsx @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import React, {ReactElement} from 'react' +import {Link} from 'react-router-dom' +interface AppProps { + children: React.ReactNode +} +function App(props: AppProps): ReactElement { + return ( +
+
+ Home +
+ {props.children} +
+ ) +} + +export default App diff --git a/packages/test-commerce-sdk-react/app/main.tsx b/packages/test-commerce-sdk-react/app/main.tsx index 94bc1f1e3a..19b850b5cb 100644 --- a/packages/test-commerce-sdk-react/app/main.tsx +++ b/packages/test-commerce-sdk-react/app/main.tsx @@ -1,9 +1,10 @@ /* - * Copyright (c) 2021, salesforce.com, inc. + * Copyright (c) 2022, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ +// @ts-ignore import {start} from 'pwa-kit-react-sdk/ssr/browser/main' start() diff --git a/packages/test-commerce-sdk-react/app/pages/home.tsx b/packages/test-commerce-sdk-react/app/pages/home.tsx index 84dfac3ae2..8c3696ce16 100644 --- a/packages/test-commerce-sdk-react/app/pages/home.tsx +++ b/packages/test-commerce-sdk-react/app/pages/home.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, salesforce.com, inc. + * Copyright (c) 2022, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause @@ -19,7 +19,9 @@ const Home = () => {

Happy coding.

Hooks

- useShopperProducts + useShopperProducts +
+ useCategories ) } diff --git a/packages/test-commerce-sdk-react/app/pages/use-shopper-categories.tsx b/packages/test-commerce-sdk-react/app/pages/use-shopper-categories.tsx new file mode 100644 index 0000000000..5a695e83aa --- /dev/null +++ b/packages/test-commerce-sdk-react/app/pages/use-shopper-categories.tsx @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +// @ts-ignore +import {useCategories} from 'commerce-sdk-react' + +import React from 'react' +import Json from '../components/Json' +import {Link} from 'react-router-dom' +import {flatten} from '../utils/utils' + +function UseShopperCategories() { + // how to get the categories type + const {isLoading, error, data: result} = useCategories({ + ids: 'root', + levels: 2 + }) + if (isLoading) { + return ( +
+

useShopperCategories page

+

Loading...

+
+ ) + } + if (error) { + return

Something is wrong

+ } + return ( +
+

useShopperCategories page

+ {result && + Object.keys(flatten(result.data[0], 'categories')).map((key) => ( +
+ Category {key} +
+ ))} + +
+
+
Returning data
+ +
+
+ ) +} + +UseShopperCategories.getTemplateName = () => 'UserShopperCategories' +export default UseShopperCategories diff --git a/packages/test-commerce-sdk-react/app/pages/use-shopper-category.tsx b/packages/test-commerce-sdk-react/app/pages/use-shopper-category.tsx new file mode 100644 index 0000000000..e8d423a772 --- /dev/null +++ b/packages/test-commerce-sdk-react/app/pages/use-shopper-category.tsx @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import React from 'react' +// @ts-ignore +import {useCategory} from 'commerce-sdk-react' +import {Link, useParams} from 'react-router-dom' +import Json from '../components/Json' +import {flatten} from '../utils/utils' + +function UseShopperCategory() { + const {categoryId}: {categoryId: string} = useParams() + const {isLoading, error, data} = useCategory({ + id: categoryId + }) + if (isLoading) { + return ( +
+

useCategory Page

+

Loading...

+
+ ) + } + if (error) { + return

Something is wrong

+ } + return ( +
+

useCategory Page

+

Categories {data?.name}

+ {data && data.categories && ( + <> +

Sub categories

+ {Object.keys(flatten(data, 'categories')) + .filter((key) => key !== categoryId) + .map((key) => ( +
+ Category {key} +
+ ))} + + )} + +
+
Returned data
+ +
+ ) +} + +UseShopperCategory.getTemplateName = () => 'UseShopperCategory' + +export default UseShopperCategory diff --git a/packages/test-commerce-sdk-react/app/pages/use-shopper-product.tsx b/packages/test-commerce-sdk-react/app/pages/use-shopper-product.tsx new file mode 100644 index 0000000000..e89bfb0284 --- /dev/null +++ b/packages/test-commerce-sdk-react/app/pages/use-shopper-product.tsx @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import React from 'react' +// @ts-ignore +import {useProduct} from 'commerce-sdk-react' +import Json from '../components/Json' +import {Link, useParams} from 'react-router-dom' + +function UseShopperProduct() { + const {productId}: {productId: string} = useParams() + const {data, isLoading, error} = useProduct({id: productId}) + if (isLoading) { + return ( +
+

useProducts page

+

Loading...

+
+ ) + } + if (error) { + return

Something is wrong

+ } + return ( + <> +

useProducts page

+

{data?.name}

+ + {productId !== '25604455M' && ( +
+ See No-Iron Textured Dress Shirt +
+ )} +
+

Returning data

+ + + ) +} + +UseShopperProduct.getTemplateName = () => 'UseShopperProduct' + +export default UseShopperProduct diff --git a/packages/test-commerce-sdk-react/app/pages/use-shopper-products.tsx b/packages/test-commerce-sdk-react/app/pages/use-shopper-products.tsx new file mode 100644 index 0000000000..825e07eb21 --- /dev/null +++ b/packages/test-commerce-sdk-react/app/pages/use-shopper-products.tsx @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import React from 'react' +// @ts-ignore +import {useProducts} from 'commerce-sdk-react' +import Json from '../components/Json' +import {Link} from 'react-router-dom' +const ids = '25502228M,25503045M' + +const UseShopperProducts = () => { + const {isLoading, error, data: result} = useProducts({ + ids + }) + if (isLoading) { + return ( +
+

Products

+

Loading...

+
+ ) + } + + if (error) { + return

Something is wrong

+ } + return ( + <> +

Products

+
Click on the link to go to a product page
+ {result?.data.map(({id, name}) => { + return ( +
+ {name} +
+ ) + })} +
+
+
Returning data
+ +
+ + ) +} + +UseShopperProducts.getTemplateName = () => 'UseShopperProducts' + +export default UseShopperProducts diff --git a/packages/test-commerce-sdk-react/app/pages/useShopperProducts.tsx b/packages/test-commerce-sdk-react/app/pages/useShopperProducts.tsx deleted file mode 100644 index db13ecda9d..0000000000 --- a/packages/test-commerce-sdk-react/app/pages/useShopperProducts.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2021, salesforce.com, inc. - * All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ -import React from 'react' -import {useShopperProducts} from 'commerce-sdk-react' -import Json from '../components/Json' - -const UseShopperProducts = () => { - const result = useShopperProducts({}, []) - return ( - <> -

useProducts

- - - ) -} - -UseShopperProducts.getTemplateName = () => 'UseShopperProducts' - -export default UseShopperProducts diff --git a/packages/test-commerce-sdk-react/app/routes.tsx b/packages/test-commerce-sdk-react/app/routes.tsx index ff0a1612d2..931f9b0146 100644 --- a/packages/test-commerce-sdk-react/app/routes.tsx +++ b/packages/test-commerce-sdk-react/app/routes.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, salesforce.com, inc. + * Copyright (c) 2022, salesforce.com, inc. * All rights reserved. * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause @@ -7,7 +7,10 @@ import loadable from '@loadable/component' const Home = loadable(() => import('./pages/home')) -const UseProducts = loadable(() => import('./pages/useShopperProducts')) +const UseProducts = loadable(() => import('./pages/use-shopper-products')) +const UseProduct = loadable(() => import('./pages/use-shopper-product')) +const UseCategories = loadable(() => import('./pages/use-shopper-categories')) +const UseCategory = loadable(() => import('./pages/use-shopper-category')) const routes = [ { @@ -16,8 +19,20 @@ const routes = [ component: Home }, { - path: '/useShopperProducts', + path: '/products/:productId', + component: UseProduct + }, + { + path: '/products', component: UseProducts + }, + { + path: '/categories/:categoryId', + component: UseCategory + }, + { + path: '/categories', + component: UseCategories } ] diff --git a/packages/test-commerce-sdk-react/app/utils/utils.ts b/packages/test-commerce-sdk-react/app/utils/utils.ts new file mode 100644 index 0000000000..a59d66fc5e --- /dev/null +++ b/packages/test-commerce-sdk-react/app/utils/utils.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +type RecursiveList> = {id: string} & Partial< + Record +> +/** + * Flattens a tree data structure + * @param {*} node + * @param key + * @returns + */ +export const flatten = >( + node: T, + key: K +): Record => { + const base = {[node.id]: node} + const children = node[key] + if (!Array.isArray(children) || children.length === 0) return base + return children.reduce( + (result, child) => ({ + ...result, + ...flatten(child, key) + }), + base + ) +} diff --git a/packages/test-commerce-sdk-react/package-lock.json b/packages/test-commerce-sdk-react/package-lock.json index 8553bbea75..44a95c4730 100644 --- a/packages/test-commerce-sdk-react/package-lock.json +++ b/packages/test-commerce-sdk-react/package-lock.json @@ -41,6 +41,21 @@ "use-sync-external-store": "^1.2.0" } }, + "@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, + "@types/loadable__component": { + "version": "5.13.4", + "resolved": "https://registry.npmjs.org/@types/loadable__component/-/loadable__component-5.13.4.tgz", + "integrity": "sha512-YhoCCxyuvP2XeZNbHbi8Wb9EMaUJuA2VGHxJffcQYrJKIKSkymJrhbzsf9y4zpTmr5pExAAEh5hbF628PAZ8Dg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -67,6 +82,27 @@ "@types/react": "*" } }, + "@types/react-router": { + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz", + "integrity": "sha512-YYknwy0D0iOwKQgz9v8nOzt2J6l4gouBmDnWqUUznltOTaon+r8US8ky8HvN0tXvc38U9m6z/t2RsVsnd1zM0g==", + "dev": true, + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "requires": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", diff --git a/packages/test-commerce-sdk-react/package.json b/packages/test-commerce-sdk-react/package.json index ef44aafe8d..d04e856ef1 100644 --- a/packages/test-commerce-sdk-react/package.json +++ b/packages/test-commerce-sdk-react/package.json @@ -9,7 +9,9 @@ "devDependencies": { "@loadable/component": "^5.15.0", "@tanstack/react-query": "^4.0.10", + "@types/loadable__component": "^5.13.4", "@types/react": "^17.0.2", + "@types/react-router-dom": "^5.1.2", "@types/react-dom": "^17.0.2", "commerce-sdk-react": "^2.3.0-dev", "pwa-kit-dev": "^2.3.0-dev", diff --git a/packages/test-commerce-sdk-react/tsconfig.json b/packages/test-commerce-sdk-react/tsconfig.json index f0c5a6b9d4..767fe15366 100644 --- a/packages/test-commerce-sdk-react/tsconfig.json +++ b/packages/test-commerce-sdk-react/tsconfig.json @@ -47,7 +47,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ "sourceMap": true /* Create source map files for emitted JavaScript files. */, // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "../commerce-sdk-react/dist" + "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */