@salla.sa/twilight-theme-engine 1.0.145 → 1.0.147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AddToCartForm-NZNFVGDV.js → AddToCartForm-GF22RRTM.js} +3 -3
- package/dist/{AddToCartForm-NZNFVGDV.js.map → AddToCartForm-GF22RRTM.js.map} +1 -1
- package/dist/{BlogAuthorPage-BXRIYXVN.js → BlogAuthorPage-RL6AMYDY.js} +17 -17
- package/dist/{BlogAuthorPage-BXRIYXVN.js.map → BlogAuthorPage-RL6AMYDY.js.map} +1 -1
- package/dist/{BlogCategoryPage-GHWC2WVM.js → BlogCategoryPage-B4DIJZCK.js} +17 -17
- package/dist/{BlogCategoryPage-GHWC2WVM.js.map → BlogCategoryPage-B4DIJZCK.js.map} +1 -1
- package/dist/{BlogPage-ZCGNKBLI.js → BlogPage-UQKCNSB7.js} +15 -15
- package/dist/{BlogPage-ZCGNKBLI.js.map → BlogPage-UQKCNSB7.js.map} +1 -1
- package/dist/{BlogSinglePage-TH7Z3MKB.js → BlogSinglePage-MG7A3FK4.js} +15 -15
- package/dist/{BlogSinglePage-TH7Z3MKB.js.map → BlogSinglePage-MG7A3FK4.js.map} +1 -1
- package/dist/{BlogTagPage-GM422SOW.js → BlogTagPage-G7GLKQIE.js} +17 -17
- package/dist/{BlogTagPage-GM422SOW.js.map → BlogTagPage-G7GLKQIE.js.map} +1 -1
- package/dist/{BrandsPage-LNNPU4NX.js → BrandsPage-EINNM2YV.js} +16 -16
- package/dist/{BrandsPage-LNNPU4NX.js.map → BrandsPage-EINNM2YV.js.map} +1 -1
- package/dist/{Breadcrumb-TSG2CW3S.js → Breadcrumb-VLIGUJV2.js} +15 -15
- package/dist/{Breadcrumb-TSG2CW3S.js.map → Breadcrumb-VLIGUJV2.js.map} +1 -1
- package/dist/{CartItem-UVSLCSEP.js → CartItem-QCNLWMWV.js} +15 -15
- package/dist/{CartItem-UVSLCSEP.js.map → CartItem-QCNLWMWV.js.map} +1 -1
- package/dist/{CartSummary-ZCXTED4G.js → CartSummary-ZWBB3R3X.js} +15 -15
- package/dist/{CartSummary-ZCXTED4G.js.map → CartSummary-ZWBB3R3X.js.map} +1 -1
- package/dist/{Copyright-B25RLEVV.js → Copyright-SG3C7STC.js} +3 -3
- package/dist/{Copyright-B25RLEVV.js.map → Copyright-SG3C7STC.js.map} +1 -1
- package/dist/{CustomerLayout-WGEUJEDP.js → CustomerLayout-OZCEEEL5.js} +15 -15
- package/dist/{CustomerLayout-WGEUJEDP.js.map → CustomerLayout-OZCEEEL5.js.map} +1 -1
- package/dist/{Footer-QMNESEEI.js → Footer-F6H52J6C.js} +4 -4
- package/dist/{Footer-QMNESEEI.js.map → Footer-F6H52J6C.js.map} +1 -1
- package/dist/{Header-ZPDXQ7U6.js → Header-IZ22UIE4.js} +8 -8
- package/dist/{Header-ZPDXQ7U6.js.map → Header-IZ22UIE4.js.map} +1 -1
- package/dist/{LatestProducts-UEUM47MI.js → LatestProducts-EUROHOV5.js} +17 -17
- package/dist/{LatestProducts-UEUM47MI.js.map → LatestProducts-EUROHOV5.js.map} +1 -1
- package/dist/{LoyaltyPage-ZM3FDTV3.js → LoyaltyPage-V6UL2JG3.js} +15 -15
- package/dist/{LoyaltyPage-ZM3FDTV3.js.map → LoyaltyPage-V6UL2JG3.js.map} +1 -1
- package/dist/{LoyaltyPointsPage-QQIKIBTH.js → LoyaltyPointsPage-DSUGI2WQ.js} +6 -6
- package/dist/{LoyaltyPointsPage-QQIKIBTH.js.map → LoyaltyPointsPage-DSUGI2WQ.js.map} +1 -1
- package/dist/{MainMenu-3Z7HRQGU.js → MainMenu-L6SYV24F.js} +5 -5
- package/dist/{MainMenu-3Z7HRQGU.js.map → MainMenu-L6SYV24F.js.map} +1 -1
- package/dist/{MasterLayout-ZRTWOZGC.js → MasterLayout-35PAQI5L.js} +15 -15
- package/dist/{MasterLayout-ZRTWOZGC.js.map → MasterLayout-35PAQI5L.js.map} +1 -1
- package/dist/{MobileMenu-SC7HJ6BT.js → MobileMenu-AMKXMQPQ.js} +16 -16
- package/dist/{MobileMenu-SC7HJ6BT.js.map → MobileMenu-AMKXMQPQ.js.map} +1 -1
- package/dist/{NotificationsPage-JMAZ2N2A.js → NotificationsPage-POSF3L7Z.js} +15 -15
- package/dist/{NotificationsPage-JMAZ2N2A.js.map → NotificationsPage-POSF3L7Z.js.map} +1 -1
- package/dist/{OrderSinglePage-6MAFH4Q6.js → OrderSinglePage-Y47JLCKF.js} +16 -16
- package/dist/{OrderSinglePage-6MAFH4Q6.js.map → OrderSinglePage-Y47JLCKF.js.map} +1 -1
- package/dist/{OrdersPage-NMINSG67.js → OrdersPage-BLEBRK7S.js} +15 -15
- package/dist/{OrdersPage-NMINSG67.js.map → OrdersPage-BLEBRK7S.js.map} +1 -1
- package/dist/{PageSingle-WLIXOODC.js → PageSingle-UN5NXZ6G.js} +3 -3
- package/dist/{PageSingle-WLIXOODC.js.map → PageSingle-UN5NXZ6G.js.map} +1 -1
- package/dist/{ProductDetails-NFZLUKLN.js → ProductDetails-MSJAUDZT.js} +5 -5
- package/dist/{ProductDetails-NFZLUKLN.js.map → ProductDetails-MSJAUDZT.js.map} +1 -1
- package/dist/{ProfilePage-5PBU637J.js → ProfilePage-ITTU6TKE.js} +15 -15
- package/dist/{ProfilePage-5PBU637J.js.map → ProfilePage-ITTU6TKE.js.map} +1 -1
- package/dist/{ReviewsPage-RWNFVHWR.js → ReviewsPage-F6LUX4JH.js} +3 -3
- package/dist/{ReviewsPage-RWNFVHWR.js.map → ReviewsPage-F6LUX4JH.js.map} +1 -1
- package/dist/{SeoCartWidget-HPBQ6673.js → SeoCartWidget-ZPKKBEX6.js} +15 -15
- package/dist/{SeoCartWidget-HPBQ6673.js.map → SeoCartWidget-ZPKKBEX6.js.map} +1 -1
- package/dist/{SettingsPage-Y5X5BNHD.js → SettingsPage-DUT42ZM7.js} +15 -15
- package/dist/{SettingsPage-Y5X5BNHD.js.map → SettingsPage-DUT42ZM7.js.map} +1 -1
- package/dist/{StoreClosedNotification-5DOQFF2O.js → StoreClosedNotification-BIVXHO3M.js} +16 -16
- package/dist/{StoreClosedNotification-5DOQFF2O.js.map → StoreClosedNotification-BIVXHO3M.js.map} +1 -1
- package/dist/{TestimonialsPage-ZDALOH2L.js → TestimonialsPage-BVJKGYKY.js} +3 -3
- package/dist/{TestimonialsPage-ZDALOH2L.js.map → TestimonialsPage-BVJKGYKY.js.map} +1 -1
- package/dist/ThankYouPage-4AF4JSSN.js +187 -0
- package/dist/ThankYouPage-4AF4JSSN.js.map +1 -0
- package/dist/{WalletPage-DPWZBROY.js → WalletPage-JCGVSMQ2.js} +16 -16
- package/dist/{WalletPage-DPWZBROY.js.map → WalletPage-JCGVSMQ2.js.map} +1 -1
- package/dist/{WebMcpTools-3TBLKZL5.js → WebMcpTools-7AWIQEVW.js} +5 -5
- package/dist/{WebMcpTools-3TBLKZL5.js.map → WebMcpTools-7AWIQEVW.js.map} +1 -1
- package/dist/{WishlistPage-BM3XSMQF.js → WishlistPage-PJGN3E6X.js} +17 -17
- package/dist/{WishlistPage-BM3XSMQF.js.map → WishlistPage-PJGN3E6X.js.map} +1 -1
- package/dist/ambient/salla-components.d.ts +42 -0
- package/dist/api/advertisement.js +2 -2
- package/dist/api/apps.js +2 -2
- package/dist/api/blog.js +3 -3
- package/dist/api/brands.js +3 -3
- package/dist/api/cart.js +3 -3
- package/dist/api/category.js +3 -3
- package/dist/api/client.js +1 -1
- package/dist/api/home.js +2 -2
- package/dist/api/loyalty.js +3 -3
- package/dist/api/menu.js +2 -2
- package/dist/api/notification.js +2 -2
- package/dist/api/order.js +3 -3
- package/dist/api/page.js +3 -3
- package/dist/api/product.js +3 -3
- package/dist/api/profile.js +1 -1
- package/dist/api/store.js +2 -2
- package/dist/api/translations.js +2 -2
- package/dist/api/user.js +2 -2
- package/dist/api/wallet.js +2 -2
- package/dist/api/wishlist.js +4 -4
- package/dist/{chunk-OLL5OGQ5.js → chunk-25LQB2XQ.js} +4 -4
- package/dist/{chunk-OLL5OGQ5.js.map → chunk-25LQB2XQ.js.map} +1 -1
- package/dist/{chunk-HJGN3XVG.js → chunk-3D4UXOBU.js} +7 -7
- package/dist/{chunk-HJGN3XVG.js.map → chunk-3D4UXOBU.js.map} +1 -1
- package/dist/{chunk-YYVZFOUI.js → chunk-3XRZEYOO.js} +3 -3
- package/dist/{chunk-YYVZFOUI.js.map → chunk-3XRZEYOO.js.map} +1 -1
- package/dist/{chunk-7NTPNCIK.js → chunk-4FUBEE6Q.js} +3 -3
- package/dist/{chunk-7NTPNCIK.js.map → chunk-4FUBEE6Q.js.map} +1 -1
- package/dist/{chunk-PCB5DCS4.js → chunk-5C4ENAQA.js} +3 -3
- package/dist/{chunk-PCB5DCS4.js.map → chunk-5C4ENAQA.js.map} +1 -1
- package/dist/{chunk-WIDH6AK6.js → chunk-6JTIZQEJ.js} +4 -4
- package/dist/{chunk-WIDH6AK6.js.map → chunk-6JTIZQEJ.js.map} +1 -1
- package/dist/{chunk-MVT5AF2A.js → chunk-6T55LXJL.js} +3 -2
- package/dist/chunk-6T55LXJL.js.map +1 -0
- package/dist/{chunk-TF46NIZF.js → chunk-72I5YXU4.js} +4 -4
- package/dist/{chunk-TF46NIZF.js.map → chunk-72I5YXU4.js.map} +1 -1
- package/dist/{chunk-TWYTA2SX.js → chunk-7QXWREJU.js} +7 -7
- package/dist/{chunk-TWYTA2SX.js.map → chunk-7QXWREJU.js.map} +1 -1
- package/dist/{chunk-BMCECPSU.js → chunk-BETGKZUQ.js} +3 -3
- package/dist/{chunk-BMCECPSU.js.map → chunk-BETGKZUQ.js.map} +1 -1
- package/dist/{chunk-R64ITZ7U.js → chunk-BOB2Z4G7.js} +3 -3
- package/dist/{chunk-R64ITZ7U.js.map → chunk-BOB2Z4G7.js.map} +1 -1
- package/dist/{chunk-YQOCPSOI.js → chunk-CITCHC3B.js} +4 -4
- package/dist/{chunk-YQOCPSOI.js.map → chunk-CITCHC3B.js.map} +1 -1
- package/dist/{chunk-VCMGBB5Y.js → chunk-DOV2LE3E.js} +3 -3
- package/dist/{chunk-VCMGBB5Y.js.map → chunk-DOV2LE3E.js.map} +1 -1
- package/dist/{chunk-2ZESCQRM.js → chunk-DQG7IMT3.js} +3 -3
- package/dist/{chunk-2ZESCQRM.js.map → chunk-DQG7IMT3.js.map} +1 -1
- package/dist/{chunk-ETC7OJT5.js → chunk-E6SVWI3B.js} +3 -3
- package/dist/{chunk-ETC7OJT5.js.map → chunk-E6SVWI3B.js.map} +1 -1
- package/dist/{chunk-DHWMC6VU.js → chunk-ELI3F3IS.js} +4 -4
- package/dist/{chunk-DHWMC6VU.js.map → chunk-ELI3F3IS.js.map} +1 -1
- package/dist/{chunk-FPGR63AQ.js → chunk-EXWAEAB2.js} +3 -3
- package/dist/{chunk-FPGR63AQ.js.map → chunk-EXWAEAB2.js.map} +1 -1
- package/dist/{chunk-VZRZQV4Q.js → chunk-FR6K5DBJ.js} +3 -3
- package/dist/{chunk-VZRZQV4Q.js.map → chunk-FR6K5DBJ.js.map} +1 -1
- package/dist/{chunk-NGWHUW34.js → chunk-GEJDHAP5.js} +3 -3
- package/dist/{chunk-NGWHUW34.js.map → chunk-GEJDHAP5.js.map} +1 -1
- package/dist/{chunk-U2UNWN4G.js → chunk-GIKY54MI.js} +3 -3
- package/dist/{chunk-U2UNWN4G.js.map → chunk-GIKY54MI.js.map} +1 -1
- package/dist/{chunk-MIAVMNPM.js → chunk-GKXRKR66.js} +5 -5
- package/dist/{chunk-MIAVMNPM.js.map → chunk-GKXRKR66.js.map} +1 -1
- package/dist/{chunk-NLKLS3GZ.js → chunk-H3JEKVHZ.js} +4 -4
- package/dist/{chunk-NLKLS3GZ.js.map → chunk-H3JEKVHZ.js.map} +1 -1
- package/dist/{chunk-U5TWRPMK.js → chunk-HAGJ2W6O.js} +7 -7
- package/dist/{chunk-U5TWRPMK.js.map → chunk-HAGJ2W6O.js.map} +1 -1
- package/dist/{chunk-NR5YIBTS.js → chunk-HMMV7QYC.js} +4 -4
- package/dist/{chunk-NR5YIBTS.js.map → chunk-HMMV7QYC.js.map} +1 -1
- package/dist/{chunk-ITNUDQVP.js → chunk-JCP3VCNO.js} +10 -10
- package/dist/{chunk-ITNUDQVP.js.map → chunk-JCP3VCNO.js.map} +1 -1
- package/dist/{chunk-RJKMW36K.js → chunk-JLLDFGGH.js} +7 -7
- package/dist/{chunk-RJKMW36K.js.map → chunk-JLLDFGGH.js.map} +1 -1
- package/dist/{chunk-XV3HPKLI.js → chunk-JZTNZ6C7.js} +3 -3
- package/dist/{chunk-XV3HPKLI.js.map → chunk-JZTNZ6C7.js.map} +1 -1
- package/dist/{chunk-LSMKTPIE.js → chunk-LAVMQ7HM.js} +4 -4
- package/dist/{chunk-LSMKTPIE.js.map → chunk-LAVMQ7HM.js.map} +1 -1
- package/dist/{chunk-5JZSBFA5.js → chunk-LZ6RMZPJ.js} +3 -3
- package/dist/{chunk-5JZSBFA5.js.map → chunk-LZ6RMZPJ.js.map} +1 -1
- package/dist/{chunk-X4ITNSMT.js → chunk-MDVGYQE6.js} +5 -5
- package/dist/{chunk-X4ITNSMT.js.map → chunk-MDVGYQE6.js.map} +1 -1
- package/dist/{chunk-N44U2AA7.js → chunk-MS2MOOPH.js} +4 -4
- package/dist/{chunk-N44U2AA7.js.map → chunk-MS2MOOPH.js.map} +1 -1
- package/dist/{chunk-HRW4YFHR.js → chunk-N7E6KO5Q.js} +3 -3
- package/dist/{chunk-HRW4YFHR.js.map → chunk-N7E6KO5Q.js.map} +1 -1
- package/dist/{chunk-KKTVDCVO.js → chunk-NFJE6MYZ.js} +3 -3
- package/dist/{chunk-KKTVDCVO.js.map → chunk-NFJE6MYZ.js.map} +1 -1
- package/dist/{chunk-GBMMP344.js → chunk-NMYYHEPN.js} +15 -15
- package/dist/{chunk-GBMMP344.js.map → chunk-NMYYHEPN.js.map} +1 -1
- package/dist/{chunk-QIHSKEWU.js → chunk-RDVZCO5A.js} +4 -4
- package/dist/{chunk-QIHSKEWU.js.map → chunk-RDVZCO5A.js.map} +1 -1
- package/dist/{chunk-KGSB2Y7O.js → chunk-RMV5X6GY.js} +3 -3
- package/dist/{chunk-KGSB2Y7O.js.map → chunk-RMV5X6GY.js.map} +1 -1
- package/dist/{chunk-GFRJHCRX.js → chunk-SCKSX4IS.js} +4 -4
- package/dist/{chunk-GFRJHCRX.js.map → chunk-SCKSX4IS.js.map} +1 -1
- package/dist/{chunk-AJM7KUA3.js → chunk-XCSGB37K.js} +4 -4
- package/dist/{chunk-AJM7KUA3.js.map → chunk-XCSGB37K.js.map} +1 -1
- package/dist/{chunk-DMR3ICV5.js → chunk-Y3G6GQKW.js} +3 -3
- package/dist/{chunk-DMR3ICV5.js.map → chunk-Y3G6GQKW.js.map} +1 -1
- package/dist/{chunk-52QZKUDU.js → chunk-ZONZSJ5G.js} +5 -5
- package/dist/{chunk-52QZKUDU.js.map → chunk-ZONZSJ5G.js.map} +1 -1
- package/dist/{chunk-2N6XZZ4W.js → chunk-ZY5XF5ML.js} +3 -3
- package/dist/{chunk-2N6XZZ4W.js.map → chunk-ZY5XF5ML.js.map} +1 -1
- package/dist/components/cart/index.js +1 -1
- package/dist/components/common/index.js +1 -1
- package/dist/components/drawer/index.js +13 -13
- package/dist/components/home/index.js +18 -18
- package/dist/components/layout/index.js +4 -4
- package/dist/components/product/index.js +15 -15
- package/dist/components/store/index.js +14 -14
- package/dist/dev/editor/index.js +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/{document-class-VHDNGZQK.js → document-class-2BDL463P.js} +11 -11
- package/dist/{document-class-VHDNGZQK.js.map → document-class-2BDL463P.js.map} +1 -1
- package/dist/hooks/index.js +13 -13
- package/dist/hooks/useGtm.js +13 -13
- package/dist/hooks/useMoney.js +13 -13
- package/dist/hooks/useStore.js +13 -13
- package/dist/hooks/useUser.js +3 -3
- package/dist/index.js +13 -13
- package/dist/{navigation-VW5P7XQM.js → navigation-4DEWYAFD.js} +4 -4
- package/dist/{navigation-VW5P7XQM.js.map → navigation-4DEWYAFD.js.map} +1 -1
- package/dist/{navigation-C5K5SOU2.js → navigation-TXFKCXSH.js} +5 -5
- package/dist/{navigation-C5K5SOU2.js.map → navigation-TXFKCXSH.js.map} +1 -1
- package/dist/{not-found-U2LJEYDT.js → not-found-QCVLRYNM.js} +16 -16
- package/dist/{not-found-U2LJEYDT.js.map → not-found-QCVLRYNM.js.map} +1 -1
- package/dist/providers/index.js +13 -13
- package/dist/routes/account/orders.js +4 -4
- package/dist/routes/account.js +13 -13
- package/dist/routes/blog/loader.d.ts.map +1 -1
- package/dist/routes/blog.js +23 -15
- package/dist/routes/blog.js.map +1 -1
- package/dist/routes/brands.js +4 -4
- package/dist/routes/cart.js +22 -22
- package/dist/routes/home.js +19 -19
- package/dist/routes/index.js +3 -3
- package/dist/routes/loyalty.js +5 -5
- package/dist/routes/page.js +4 -4
- package/dist/routes/product-listing.js +20 -20
- package/dist/routes/product.js +18 -18
- package/dist/routes/seo-redirects.js +3 -3
- package/dist/routes/testimonials.js +2 -2
- package/dist/routes/thank-you/ThankYouPage.d.ts +2 -1
- package/dist/routes/thank-you/ThankYouPage.d.ts.map +1 -1
- package/dist/routes/thank-you/loader.d.ts +5 -1
- package/dist/routes/thank-you/loader.d.ts.map +1 -1
- package/dist/routes/thank-you/types.d.ts +23 -1
- package/dist/routes/thank-you/types.d.ts.map +1 -1
- package/dist/routes/thank-you.js +79 -15
- package/dist/routes/thank-you.js.map +1 -1
- package/dist/skeleton.js +19 -19
- package/dist/{store-lookup-YL4EUIS2.js → store-lookup-6GMQGPVL.js} +8 -8
- package/dist/{store-lookup-YL4EUIS2.js.map → store-lookup-6GMQGPVL.js.map} +1 -1
- package/dist/tanstack.js +11 -11
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/index.js +2 -2
- package/dist/vite/index.js +1 -0
- package/dist/vite/index.js.map +1 -1
- package/dist/vite/plugins/best-practices/hooks-registry.d.ts.map +1 -1
- package/package.json +1 -1
- package/tailwind/routes/blog/loader.ts.txt +26 -8
- package/tailwind/routes/thank-you/ThankYouPage.tsx.txt +124 -209
- package/tailwind/routes/thank-you/index.tsx.txt +1 -1
- package/tailwind/routes/thank-you/loader.ts.txt +112 -14
- package/tailwind/routes/thank-you/types.ts.txt +24 -1
- package/dist/ThankYouPage-SYMPRWCS.js +0 -267
- package/dist/ThankYouPage-SYMPRWCS.js.map +0 -1
- package/dist/chunk-MVT5AF2A.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-registry.d.ts","sourceRoot":"","sources":["../../../../src/vite/plugins/best-practices/hooks-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"hooks-registry.d.ts","sourceRoot":"","sources":["../../../../src/vite/plugins/best-practices/hooks-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,EAiN1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI,CAOxE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { blog } from '../../api/blog';
|
|
2
2
|
import { getTwilightContext } from '../../twilight/context';
|
|
3
3
|
import { RouteId } from '../../router/route-ids';
|
|
4
|
-
import { notFound, orThrow } from '../../providers/NavigationProvider';
|
|
4
|
+
import { notFound, orThrow, responseStatusOf } from '../../providers/NavigationProvider';
|
|
5
5
|
import type { Breadcrumb } from '../../types';
|
|
6
6
|
import type {
|
|
7
7
|
BlogPageProps,
|
|
@@ -12,6 +12,24 @@ import type {
|
|
|
12
12
|
} from './types';
|
|
13
13
|
import type { IdParams, SlugIdParams } from '../types';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* {@link orThrow} for the blog, which also answers 404 when the store's plan lacks the blog.
|
|
17
|
+
*
|
|
18
|
+
* Every blog endpoint sits behind `feature:store-blog`, which answers 403 ("الميزة غير متاحة في
|
|
19
|
+
* الوقت الحالي") on such a store, so an article a crawler still links to was a 500. There is no
|
|
20
|
+
* page to show, so the route answers the router's not-found like a missing article. Twig answers
|
|
21
|
+
* the same store's `/blog` with its 403 page and an article with a 302 home. Kept to the blog:
|
|
22
|
+
* elsewhere a 403 can mean the shopper must sign in.
|
|
23
|
+
*/
|
|
24
|
+
async function blogOrNotFound<T>(promise: Promise<T>): Promise<T> {
|
|
25
|
+
try {
|
|
26
|
+
return await orThrow(promise);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (responseStatusOf(error) === 403) return notFound();
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
15
33
|
export async function blogLoader(): Promise<BlogPageProps> {
|
|
16
34
|
const i18n = getTwilightContext().i18n;
|
|
17
35
|
|
|
@@ -56,7 +74,7 @@ export async function blogSingleLoader({
|
|
|
56
74
|
|
|
57
75
|
// The API answers a non-numeric id with 417, which `orThrow` would pass through as an error.
|
|
58
76
|
if (!/^\d+$/.test(id)) throw notFound();
|
|
59
|
-
const article = await blog.articles.
|
|
77
|
+
const article = await blogOrNotFound(blog.articles.find(id));
|
|
60
78
|
|
|
61
79
|
const breadcrumbs: Breadcrumb[] = [
|
|
62
80
|
{ name: i18n.t('common.titles.home'), url: '/' },
|
|
@@ -85,8 +103,8 @@ export async function blogAuthorLoader({
|
|
|
85
103
|
const i18n = getTwilightContext().i18n;
|
|
86
104
|
|
|
87
105
|
const [response, overview] = await Promise.all([
|
|
88
|
-
|
|
89
|
-
blog.get(),
|
|
106
|
+
blogOrNotFound(blog.articles.list({ author: id })),
|
|
107
|
+
blogOrNotFound(blog.get()),
|
|
90
108
|
]);
|
|
91
109
|
const author = response.author;
|
|
92
110
|
// The API answers an unknown id without the author object: 404 instead of a TypeError (500).
|
|
@@ -121,8 +139,8 @@ export async function blogCategoryLoader({
|
|
|
121
139
|
const i18n = getTwilightContext().i18n;
|
|
122
140
|
|
|
123
141
|
const [response, overview] = await Promise.all([
|
|
124
|
-
|
|
125
|
-
blog.get(),
|
|
142
|
+
blogOrNotFound(blog.articles.list({ category: id })),
|
|
143
|
+
blogOrNotFound(blog.get()),
|
|
126
144
|
]);
|
|
127
145
|
const category = response.category;
|
|
128
146
|
if (!category) throw notFound();
|
|
@@ -151,8 +169,8 @@ export async function blogTagLoader({
|
|
|
151
169
|
const i18n = getTwilightContext().i18n;
|
|
152
170
|
|
|
153
171
|
const [response, overview] = await Promise.all([
|
|
154
|
-
|
|
155
|
-
blog.get(),
|
|
172
|
+
blogOrNotFound(blog.articles.list({ tag: id })),
|
|
173
|
+
blogOrNotFound(blog.get()),
|
|
156
174
|
]);
|
|
157
175
|
const tag = response.tag;
|
|
158
176
|
if (!tag) throw notFound();
|
|
@@ -1,240 +1,155 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { SallaButton } from '@salla.sa/twilight-components-react/button';
|
|
4
|
-
import { SallaNextOrderCoupon } from '@salla.sa/twilight-components-react/next-order-coupon';
|
|
5
|
-
import { SallaOrderBranch } from '@salla.sa/twilight-components-react/order-branch';
|
|
6
|
-
import { Link } from '../../components/common';
|
|
7
|
-
import { HookSlot, usePageConfig } from '../../hooks';
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { HookSlot, useIsClient, usePageConfig } from '../../hooks';
|
|
8
3
|
import type { ThankYouPageProps } from './types';
|
|
9
4
|
import { useTwilight } from '../../providers/twilight-context';
|
|
10
5
|
import { useTranslation } from '../../providers/I18nProvider';
|
|
11
|
-
import
|
|
12
|
-
import { onSallaEvent } from '../../utils/sdk-helpers';
|
|
6
|
+
import { stripUnsafeHtml } from '../../utils/sanitize';
|
|
13
7
|
|
|
14
8
|
const EMPTY_MESSAGES: NonNullable<ThankYouPageProps['messages']> = [];
|
|
9
|
+
const ICON_FONT_URL = 'https://cdn.salla.network/fonts/hugeicons-font.css';
|
|
15
10
|
|
|
11
|
+
/** The order confirmation page, built like Twig Raed's from the Twilight thank-you components. */
|
|
16
12
|
export function ThankYouPage({
|
|
17
13
|
page,
|
|
18
14
|
order,
|
|
19
15
|
thank_you_title,
|
|
20
16
|
messages = EMPTY_MESSAGES,
|
|
17
|
+
instructions,
|
|
18
|
+
items,
|
|
19
|
+
is_pickable,
|
|
20
|
+
created_at,
|
|
21
|
+
loyalty_points = 0,
|
|
22
|
+
loyalty_url,
|
|
23
|
+
cashback,
|
|
24
|
+
wallet_url,
|
|
21
25
|
}: ThankYouPageProps) {
|
|
22
26
|
const { store } = useTwilight();
|
|
23
27
|
const { t } = useTranslation();
|
|
24
|
-
//
|
|
28
|
+
// The order components read the order id from `salla.config.page.id`.
|
|
25
29
|
usePageConfig(page);
|
|
26
|
-
|
|
30
|
+
// The components rewrite their light DOM once the SDK loads, which can come before hydration.
|
|
31
|
+
const isClient = useIsClient();
|
|
32
|
+
const heading =
|
|
27
33
|
thank_you_title ?? t('pages.thank_you.hero_title', 'Thank you for shopping with us! 😊');
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
setInvoiceSent(true);
|
|
39
|
-
};
|
|
40
|
-
const listener = handleInvoiceSent as (...args: unknown[]) => void;
|
|
41
|
-
|
|
42
|
-
return onSallaEvent('order::invoice.sent', listener);
|
|
43
|
-
}, [t]);
|
|
34
|
+
const currency = order?.currency;
|
|
35
|
+
const itemsJson = useMemo(() => JSON.stringify(items ?? []), [items]);
|
|
36
|
+
const discountsJson = useMemo(() => {
|
|
37
|
+
const discounts = order?.amounts.discounts ?? [];
|
|
38
|
+
return discounts.length
|
|
39
|
+
? JSON.stringify(discounts.map(({ title, discount }) => ({ name: title, discount })))
|
|
40
|
+
: undefined;
|
|
41
|
+
}, [order]);
|
|
42
|
+
const amounts = order?.amounts;
|
|
43
|
+
const showRewards = loyalty_points > 0 || !!cashback;
|
|
44
44
|
|
|
45
45
|
return (
|
|
46
46
|
<>
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
<div className="h-52 -mb-52 w-full bg-primary rtl:right-0 ltr:left-0 relative -z-1">
|
|
50
|
-
<svg
|
|
51
|
-
className="text-primary absolute top-full"
|
|
52
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
-
viewBox="0 0 1440 320"
|
|
54
|
-
>
|
|
55
|
-
<path
|
|
56
|
-
className="fill-current"
|
|
57
|
-
fillOpacity="1"
|
|
58
|
-
d="M0,96L120,112C240,128,480,160,720,165.3C960,171,1200,149,1320,138.7L1440,128L1440,0L1320,0C1200,0,960,0,720,0C480,0,240,0,120,0L0,0Z"
|
|
59
|
-
></path>
|
|
60
|
-
</svg>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<div className="container mb-20">
|
|
64
|
-
<nav className="w-full py-5">
|
|
65
|
-
<ol className="list-reset flex items-center text-sm text-primary-reverse">
|
|
66
|
-
<li>
|
|
67
|
-
<Link to="/" className="fix-align text-primary-reverse">
|
|
68
|
-
{t('common.titles.home', 'Home')}
|
|
69
|
-
</Link>
|
|
70
|
-
</li>
|
|
71
|
-
<li>
|
|
72
|
-
<i className="sicon-keyboard_arrow_left mx-2"></i>
|
|
73
|
-
</li>
|
|
74
|
-
<li>
|
|
75
|
-
<span className="fix-align">{title}</span>
|
|
76
|
-
</li>
|
|
77
|
-
</ol>
|
|
78
|
-
</nav>
|
|
79
|
-
|
|
80
|
-
<div className="bg-white p-4 md:p-8 rounded-md mb-6 md:mb-8">
|
|
81
|
-
<div className="flex flex-col items-center pt-16 pb-10">
|
|
82
|
-
<img src={confettiImage} alt={title} className="size-[140px] mb-8" />
|
|
83
|
-
<h1 className="font-bold text-lg mb-2.5">{title}</h1>
|
|
84
|
-
<p className="text-gray-500 max-w-xs text-center text-sm leading-6 mb-2.5">
|
|
85
|
-
{t(
|
|
86
|
-
'pages.thank_you.description',
|
|
87
|
-
'Your order has been received and will be reviewed and confirmed shortly.'
|
|
88
|
-
)}
|
|
89
|
-
</p>
|
|
90
|
-
{order && (
|
|
91
|
-
<>
|
|
92
|
-
<p className="text-gray-500 max-w-xs text-center text-sm leading-6 mb-6">
|
|
93
|
-
{t('pages.thank_you.order_id_label', 'Order ID')}{' '}
|
|
94
|
-
<SallaButton
|
|
95
|
-
className="relative"
|
|
96
|
-
onClick={() => copyToClipboard(String(order.reference_id))}
|
|
97
|
-
color="dark"
|
|
98
|
-
shape="link"
|
|
99
|
-
>
|
|
100
|
-
<span>#{order.reference_id}</span>
|
|
101
|
-
<i className="copy-icon sicon-swap-stroke pointer-events-none rtl:mr-1 ltr:ml-1"></i>
|
|
102
|
-
</SallaButton>
|
|
103
|
-
</p>
|
|
104
|
-
<Link
|
|
105
|
-
to={`/account/orders/${order.id}`}
|
|
106
|
-
className="bg-primary text-white text-sm font-bold h-10 px-4 rounded-md flex items-center justify-center gap-1.5"
|
|
107
|
-
>
|
|
108
|
-
<i className="sicon-newspaper rtl:ml-1 ltr:mr-1"></i>
|
|
109
|
-
{t('pages.thank_you.view_order_details', 'View Order Details')}
|
|
110
|
-
</Link>
|
|
111
|
-
</>
|
|
112
|
-
)}
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
{(order as { instructions?: string } | undefined)?.instructions && (
|
|
116
|
-
<article
|
|
117
|
-
className="article article--main article--small text-center"
|
|
118
|
-
dangerouslySetInnerHTML={{
|
|
119
|
-
__html: (order as { instructions?: string }).instructions ?? '',
|
|
120
|
-
}}
|
|
121
|
-
/>
|
|
122
|
-
)}
|
|
47
|
+
<link rel="stylesheet" href={ICON_FONT_URL} />
|
|
123
48
|
|
|
124
|
-
|
|
125
|
-
<div
|
|
126
|
-
key={message}
|
|
127
|
-
className="flex flex-col items-center pt-1 pb-10 justify-start rtl:space-x-reverse space-x-2"
|
|
128
|
-
>
|
|
129
|
-
<span className="font-bold">{message}</span>
|
|
130
|
-
</div>
|
|
131
|
-
))}
|
|
132
|
-
|
|
133
|
-
<HookSlot name="thank-you:items.start" />
|
|
134
|
-
<HookSlot name="thank-you:items.end" />
|
|
135
|
-
</div>
|
|
136
|
-
|
|
137
|
-
{/* Next-order coupon and pickup branch — each renders nothing when it doesn't apply */}
|
|
138
|
-
<SallaNextOrderCoupon />
|
|
139
|
-
<SallaOrderBranch />
|
|
49
|
+
<HookSlot name="thank-you:start" />
|
|
140
50
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
51
|
+
<div className="container">
|
|
52
|
+
{isClient && (
|
|
53
|
+
<salla-thank-you-page className="thank-you-content">
|
|
54
|
+
<div slot="main">
|
|
55
|
+
<salla-thank-you-header
|
|
56
|
+
heading={heading}
|
|
57
|
+
subtitle={t('pages.thank_you.order_received', 'Your order has been received')}
|
|
58
|
+
store-logo={store.logo || ''}
|
|
59
|
+
store-name={store.name}
|
|
60
|
+
reference-id={order ? String(order.reference_id) : undefined}
|
|
61
|
+
created-at={created_at}
|
|
62
|
+
>
|
|
63
|
+
{instructions && (
|
|
64
|
+
<article className="article article--main article--small text-center">
|
|
65
|
+
<p
|
|
66
|
+
// nosemgrep: the store's own order message, with unsafe markup stripped
|
|
67
|
+
dangerouslySetInnerHTML={{ __html: stripUnsafeHtml(instructions) }}
|
|
68
|
+
/>
|
|
69
|
+
</article>
|
|
70
|
+
)}
|
|
71
|
+
{messages.map((message) => (
|
|
72
|
+
<span key={message} className="font-bold">
|
|
73
|
+
{message}
|
|
74
|
+
</span>
|
|
75
|
+
))}
|
|
76
|
+
</salla-thank-you-header>
|
|
77
|
+
|
|
78
|
+
<HookSlot name="thank-you:items.start" />
|
|
79
|
+
{order &&
|
|
80
|
+
(is_pickable ? (
|
|
81
|
+
<salla-order-branch
|
|
82
|
+
data-testid="store-thankyou-branch"
|
|
83
|
+
items={itemsJson}
|
|
84
|
+
currency={currency}
|
|
85
|
+
sticky-cta
|
|
86
|
+
/>
|
|
87
|
+
) : (
|
|
88
|
+
<salla-order-shipments
|
|
89
|
+
data-testid="store-thankyou-shipments"
|
|
90
|
+
order-id={String(order.id)}
|
|
91
|
+
items={itemsJson}
|
|
92
|
+
currency={currency}
|
|
93
|
+
sticky-cta
|
|
94
|
+
/>
|
|
95
|
+
))}
|
|
96
|
+
<HookSlot name="thank-you:items.end" />
|
|
97
|
+
|
|
98
|
+
{order && amounts && (
|
|
99
|
+
<salla-order-payment
|
|
100
|
+
data-testid="store-thankyou-payment"
|
|
101
|
+
payment-method={order.payment?.method}
|
|
102
|
+
currency={currency}
|
|
103
|
+
payment-logo={
|
|
104
|
+
order.payment?.method
|
|
105
|
+
? `https://cdn.salla.network/images/payment/${order.payment.method}_mini.png`
|
|
106
|
+
: undefined
|
|
107
|
+
}
|
|
108
|
+
sub-total={amounts.sub_total.amount}
|
|
109
|
+
total={amounts.total.amount}
|
|
110
|
+
tax-amount={amounts.tax?.amount.amount}
|
|
111
|
+
shipping-cost={amounts.shipping_cost?.amount}
|
|
112
|
+
cod-cost={amounts.cash_on_delivery?.amount}
|
|
113
|
+
discounts={discountsJson}
|
|
114
|
+
invoice-url={order.urls.print}
|
|
115
|
+
/>
|
|
197
116
|
)}
|
|
198
117
|
</div>
|
|
199
|
-
)}
|
|
200
118
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
119
|
+
<HookSlot name="thank-you:payment.end" />
|
|
120
|
+
|
|
121
|
+
{showRewards && (
|
|
122
|
+
<salla-order-rewards
|
|
123
|
+
data-testid="store-thankyou-rewards"
|
|
124
|
+
{...(loyalty_points > 0
|
|
125
|
+
? { 'loyalty-points': loyalty_points, 'loyalty-url': loyalty_url }
|
|
126
|
+
: {})}
|
|
127
|
+
{...(cashback
|
|
128
|
+
? {
|
|
129
|
+
'cashback-amount': cashback.amount,
|
|
130
|
+
currency: cashback.currency,
|
|
131
|
+
'cashback-url': wallet_url,
|
|
132
|
+
}
|
|
133
|
+
: {})}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
206
136
|
|
|
207
|
-
<
|
|
208
|
-
{store.contacts.mobile && (
|
|
209
|
-
<div className="text-sm unicode flex items-center">
|
|
210
|
-
<i className="sicon-phone"></i>
|
|
211
|
-
<a
|
|
212
|
-
href={`tel:${store.contacts.mobile}`}
|
|
213
|
-
className="hover:text-primary transition"
|
|
214
|
-
>
|
|
215
|
-
<b className="unicode mx-1.5">{store.contacts.mobile}</b>
|
|
216
|
-
</a>
|
|
217
|
-
</div>
|
|
218
|
-
)}
|
|
137
|
+
<salla-next-order-coupon data-testid="store-thankyou-coupon" />
|
|
219
138
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
className="hover:text-primary transition"
|
|
226
|
-
target="_blank"
|
|
227
|
-
rel="noopener noreferrer"
|
|
228
|
-
>
|
|
229
|
-
<b className="unicode mx-1.5">{store.contacts.whatsapp}</b>
|
|
230
|
-
</a>
|
|
231
|
-
</div>
|
|
139
|
+
<salla-contacts
|
|
140
|
+
data-testid="store-thankyou-contacts"
|
|
141
|
+
introduction={t(
|
|
142
|
+
'pages.thank_you.contact_us',
|
|
143
|
+
'Got a question? We are happy to hear from you'
|
|
232
144
|
)}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
145
|
+
hide-title
|
|
146
|
+
horizontal
|
|
147
|
+
icons-only
|
|
148
|
+
/>
|
|
236
149
|
|
|
237
|
-
|
|
150
|
+
<HookSlot name="thank-you:end" />
|
|
151
|
+
</salla-thank-you-page>
|
|
152
|
+
)}
|
|
238
153
|
</div>
|
|
239
154
|
</>
|
|
240
155
|
);
|
|
@@ -23,7 +23,7 @@ async function loader(
|
|
|
23
23
|
ctx: { params: ThankYouLoaderParams }
|
|
24
24
|
) => Promise<Record<string, unknown>> | Record<string, unknown>
|
|
25
25
|
): Promise<ThankYouPageProps> {
|
|
26
|
-
const data = await thankYouLoader({ params: ctx.params });
|
|
26
|
+
const data = await thankYouLoader({ params: ctx.params, locale: ctx.locale });
|
|
27
27
|
|
|
28
28
|
if (extend) {
|
|
29
29
|
const extra = await extend(data, ctx);
|
|
@@ -1,30 +1,119 @@
|
|
|
1
|
-
import type { ThankYouPageProps, ThankYouLoaderParams } from './types';
|
|
1
|
+
import type { ThankYouPageProps, ThankYouLoaderParams, ThankYouLineItem } from './types';
|
|
2
2
|
import type { Order } from '../account/types';
|
|
3
|
-
import {
|
|
3
|
+
import type { PointBalanceResponse } from '../loyalty/types';
|
|
4
|
+
import type { TransactionItem } from '../../api/wallet';
|
|
5
|
+
import type { StoreOrderInstruction } from '../../types';
|
|
6
|
+
import { api, getAuthToken } from '../../api/client';
|
|
7
|
+
import { order, type TwilightOrder } from '../../api/order';
|
|
4
8
|
import { getTwilightContext } from '../../twilight/context';
|
|
9
|
+
import { storePageUrl } from '../../utils/baseHead';
|
|
5
10
|
import { RouteId } from '../../router/route-ids';
|
|
6
11
|
|
|
12
|
+
const INSTRUCTION_BY_STATUS: Record<string, keyof StoreOrderInstruction> = {
|
|
13
|
+
payment_pending: 'order_instructions_payment_waiting',
|
|
14
|
+
under_review: 'order_instructions_under_review',
|
|
15
|
+
completed: 'order_instructions_completed',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
async function orderLoyaltyPoints(): Promise<PointBalanceResponse['data']> {
|
|
19
|
+
const response = await api.get('balance/points').json<PointBalanceResponse>();
|
|
20
|
+
return response.data ?? [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// A plain array today; `wallet.list` expects the paginated object, so accept both.
|
|
24
|
+
async function walletTransactions(): Promise<TransactionItem[]> {
|
|
25
|
+
const response = await api
|
|
26
|
+
.get('balance/wallet?page=1&per_page=20')
|
|
27
|
+
.json<{ data?: { transactions?: TransactionItem[] | { data?: TransactionItem[] } } }>();
|
|
28
|
+
const transactions = response.data?.transactions;
|
|
29
|
+
return Array.isArray(transactions) ? transactions : (transactions?.data ?? []);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function offsetMinutes(timeZone: string, at: number): number {
|
|
33
|
+
const name = new Intl.DateTimeFormat('en-US', { timeZone, timeZoneName: 'longOffset' })
|
|
34
|
+
.formatToParts(at)
|
|
35
|
+
.find((part) => part.type === 'timeZoneName')?.value;
|
|
36
|
+
const [, sign, hours, minutes] = name?.match(/([+-])(\d{2}):(\d{2})/) ?? [];
|
|
37
|
+
return sign ? (sign === '-' ? -1 : 1) * (Number(hours) * 60 + Number(minutes)) : 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** `2026-11-03 14:00:42.000000` in `Asia/Riyadh` -> `2026-11-03T14:00:42+03:00`. */
|
|
41
|
+
export function orderCreatedAtIso(createdAt?: Order['created_at']): string | undefined {
|
|
42
|
+
if (!createdAt?.date) return undefined;
|
|
43
|
+
const [day, time = '00:00:00'] = createdAt.date.split(' ');
|
|
44
|
+
const local = `${day}T${time.slice(0, 8)}`;
|
|
45
|
+
try {
|
|
46
|
+
const asUtc = Date.parse(`${local}Z`);
|
|
47
|
+
// The local clock read as UTC can fall on the other side of a DST change; look again.
|
|
48
|
+
const offset = offsetMinutes(
|
|
49
|
+
createdAt.timezone,
|
|
50
|
+
asUtc - offsetMinutes(createdAt.timezone, asUtc) * 60_000
|
|
51
|
+
);
|
|
52
|
+
const abs = Math.abs(offset);
|
|
53
|
+
const hhmm = `${String(Math.floor(abs / 60)).padStart(2, '0')}:${String(abs % 60).padStart(2, '0')}`;
|
|
54
|
+
return `${local}${offset < 0 ? '-' : '+'}${hhmm}`;
|
|
55
|
+
} catch {
|
|
56
|
+
return local;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
7
60
|
export async function thankYouLoader({
|
|
8
61
|
params,
|
|
62
|
+
locale,
|
|
9
63
|
}: {
|
|
10
64
|
params: ThankYouLoaderParams;
|
|
65
|
+
locale?: string;
|
|
11
66
|
}): Promise<ThankYouPageProps> {
|
|
12
67
|
const orderId = params.orderId;
|
|
68
|
+
const { i18n, settings } = getTwilightContext();
|
|
69
|
+
const store = settings?.store;
|
|
70
|
+
const signedIn = !!getAuthToken();
|
|
71
|
+
const loyaltyEnabled = signedIn && !!store?.features?.includes('loyalty-system');
|
|
13
72
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
// ponytail: guest order detail needs checkout/thank-you to return the order; source it
|
|
17
|
-
// here once that payload is confirmed on a correctly store-bound worker.
|
|
18
|
-
const [orderResult, thankYouResult] = await Promise.allSettled([
|
|
73
|
+
// Guests have no token for orders/{id}; render whatever resolves.
|
|
74
|
+
const [orderResult, componentsResult, pointsResult, walletResult] = await Promise.allSettled([
|
|
19
75
|
order.find(orderId),
|
|
20
|
-
order.
|
|
76
|
+
order.findForComponents(orderId),
|
|
77
|
+
loyaltyEnabled ? orderLoyaltyPoints() : Promise.resolve([]),
|
|
78
|
+
signedIn ? walletTransactions() : Promise.resolve([]),
|
|
21
79
|
]);
|
|
22
80
|
|
|
23
81
|
const orderData: Order | undefined =
|
|
24
82
|
orderResult.status === 'fulfilled' ? orderResult.value.order : undefined;
|
|
25
|
-
const
|
|
83
|
+
const componentsOrder: TwilightOrder | undefined =
|
|
84
|
+
componentsResult.status === 'fulfilled' ? componentsResult.value : undefined;
|
|
85
|
+
// Points and wallet entries name the order by its reference number, not its id.
|
|
86
|
+
const isThisOrder = (id: number | string | null | undefined) =>
|
|
87
|
+
!!orderData && Number(id) === Number(orderData.reference_id);
|
|
88
|
+
|
|
89
|
+
const loyaltyPoints =
|
|
90
|
+
pointsResult.status === 'fulfilled'
|
|
91
|
+
? (pointsResult.value.find(
|
|
92
|
+
(entry) => entry.key === 'BUY_FROM_STORE' && isThisOrder(entry.order_id)
|
|
93
|
+
)?.amount ?? 0)
|
|
94
|
+
: 0;
|
|
95
|
+
const cashbackAmount =
|
|
96
|
+
walletResult.status === 'fulfilled'
|
|
97
|
+
? walletResult.value
|
|
98
|
+
.filter((entry) => entry.action_type === 'cashback' && isThisOrder(entry.order_id))
|
|
99
|
+
.reduce((sum, entry) => sum + Number(entry.amount), 0)
|
|
100
|
+
: 0;
|
|
101
|
+
|
|
102
|
+
const items: ThankYouLineItem[] | undefined = orderData?.items.map((item, index) => ({
|
|
103
|
+
id: item.id,
|
|
104
|
+
name: item.name,
|
|
105
|
+
image: item.thumbnail ?? item.product_thumbnail ?? item.image,
|
|
106
|
+
quantity: item.quantity,
|
|
107
|
+
price: item.amounts.amount,
|
|
108
|
+
url: componentsOrder?.items[index]?.product?.url,
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
const instructionKey = orderData
|
|
112
|
+
? INSTRUCTION_BY_STATUS[orderData.status?.slug ?? '']
|
|
113
|
+
: undefined;
|
|
114
|
+
const instruction = instructionKey ? store?.order_instruction?.[instructionKey] : undefined;
|
|
115
|
+
const storeUrl = (path: string) => storePageUrl(settings, locale ? `/${locale}${path}` : path);
|
|
26
116
|
|
|
27
|
-
const i18n = getTwilightContext().i18n;
|
|
28
117
|
return {
|
|
29
118
|
page: {
|
|
30
119
|
slug: RouteId.THANK_YOU,
|
|
@@ -32,9 +121,18 @@ export async function thankYouLoader({
|
|
|
32
121
|
title: i18n.t('common.titles.thank_you') || 'Thank You',
|
|
33
122
|
},
|
|
34
123
|
order: orderData,
|
|
35
|
-
thank_you_title:
|
|
36
|
-
messages:
|
|
37
|
-
|
|
38
|
-
|
|
124
|
+
thank_you_title: store?.order_instruction?.thank_title || undefined,
|
|
125
|
+
messages: [],
|
|
126
|
+
instructions: instruction || undefined,
|
|
127
|
+
items,
|
|
128
|
+
is_pickable: !!(componentsOrder as { is_pickable?: boolean } | undefined)?.is_pickable,
|
|
129
|
+
created_at: orderCreatedAtIso(orderData?.created_at),
|
|
130
|
+
loyalty_points: loyaltyPoints,
|
|
131
|
+
loyalty_url: storeUrl('/loyalty'),
|
|
132
|
+
cashback:
|
|
133
|
+
cashbackAmount > 0 && orderData
|
|
134
|
+
? { amount: cashbackAmount, currency: orderData.currency }
|
|
135
|
+
: undefined,
|
|
136
|
+
wallet_url: storeUrl('/wallet'),
|
|
39
137
|
};
|
|
40
138
|
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import type { Page } from '../../types';
|
|
1
|
+
import type { Money, Page } from '../../types';
|
|
2
2
|
import type { Order } from '../account/types';
|
|
3
3
|
|
|
4
4
|
export interface ThankYouLoaderParams {
|
|
5
5
|
orderId: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
/** An order line in the shape the thank-you web components read. */
|
|
9
|
+
export interface ThankYouLineItem {
|
|
10
|
+
id?: number;
|
|
11
|
+
name: string;
|
|
12
|
+
image?: string;
|
|
13
|
+
quantity: number;
|
|
14
|
+
price?: Money;
|
|
15
|
+
url?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
export interface ThankYouPageProps {
|
|
9
19
|
page: Page;
|
|
10
20
|
/** Absent when the authenticated `orders/{id}` fetch fails (e.g. guest checkout / no token). */
|
|
@@ -13,4 +23,17 @@ export interface ThankYouPageProps {
|
|
|
13
23
|
share_message?: string;
|
|
14
24
|
short_share_message?: string;
|
|
15
25
|
messages?: string[];
|
|
26
|
+
/** The merchant's message for the order's status (HTML). */
|
|
27
|
+
instructions?: string;
|
|
28
|
+
items?: ThankYouLineItem[];
|
|
29
|
+
/** Pickup orders show the branch card instead of the shipments card. */
|
|
30
|
+
is_pickable?: boolean;
|
|
31
|
+
/** Order time as ISO 8601 with the store's offset. */
|
|
32
|
+
created_at?: string;
|
|
33
|
+
/** Loyalty points this order earns; 0 when the store has no loyalty program. */
|
|
34
|
+
loyalty_points?: number;
|
|
35
|
+
loyalty_url?: string;
|
|
36
|
+
/** Cashback already credited to the customer's wallet for this order. */
|
|
37
|
+
cashback?: Money;
|
|
38
|
+
wallet_url?: string;
|
|
16
39
|
}
|