@rovela-ai/sdk 0.20.0 → 0.22.0

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.
Files changed (140) hide show
  1. package/dist/admin/api/index.d.ts +2 -0
  2. package/dist/admin/api/index.d.ts.map +1 -1
  3. package/dist/admin/api/index.js +2 -0
  4. package/dist/admin/api/index.js.map +1 -1
  5. package/dist/admin/api/integrations.d.ts +60 -0
  6. package/dist/admin/api/integrations.d.ts.map +1 -0
  7. package/dist/admin/api/integrations.js +337 -0
  8. package/dist/admin/api/integrations.js.map +1 -0
  9. package/dist/admin/api/products.d.ts.map +1 -1
  10. package/dist/admin/api/products.js +4 -0
  11. package/dist/admin/api/products.js.map +1 -1
  12. package/dist/admin/api/tax-zones.d.ts.map +1 -1
  13. package/dist/admin/api/tax-zones.js +7 -0
  14. package/dist/admin/api/tax-zones.js.map +1 -1
  15. package/dist/admin/components/AdminNav.d.ts.map +1 -1
  16. package/dist/admin/components/AdminNav.js +3 -1
  17. package/dist/admin/components/AdminNav.js.map +1 -1
  18. package/dist/admin/components/AdminSelect.d.ts.map +1 -1
  19. package/dist/admin/components/AdminSelect.js +2 -0
  20. package/dist/admin/components/AdminSelect.js.map +1 -1
  21. package/dist/admin/components/DiscountsManager.d.ts.map +1 -1
  22. package/dist/admin/components/DiscountsManager.js +2 -2
  23. package/dist/admin/components/DiscountsManager.js.map +1 -1
  24. package/dist/admin/components/IntegrationsManager.d.ts +5 -0
  25. package/dist/admin/components/IntegrationsManager.d.ts.map +1 -0
  26. package/dist/admin/components/IntegrationsManager.js +138 -0
  27. package/dist/admin/components/IntegrationsManager.js.map +1 -0
  28. package/dist/admin/components/OrderDetails.d.ts.map +1 -1
  29. package/dist/admin/components/OrderDetails.js +12 -4
  30. package/dist/admin/components/OrderDetails.js.map +1 -1
  31. package/dist/admin/components/ProductForm.d.ts.map +1 -1
  32. package/dist/admin/components/ProductForm.js +25 -1
  33. package/dist/admin/components/ProductForm.js.map +1 -1
  34. package/dist/admin/components/ShippingSettings.d.ts.map +1 -1
  35. package/dist/admin/components/ShippingSettings.js +21 -21
  36. package/dist/admin/components/ShippingSettings.js.map +1 -1
  37. package/dist/admin/components/TaxSettings.d.ts.map +1 -1
  38. package/dist/admin/components/TaxSettings.js +14 -2
  39. package/dist/admin/components/TaxSettings.js.map +1 -1
  40. package/dist/admin/components/UsersTable.d.ts.map +1 -1
  41. package/dist/admin/components/UsersTable.js +2 -0
  42. package/dist/admin/components/UsersTable.js.map +1 -1
  43. package/dist/admin/components/VariantManager.d.ts.map +1 -1
  44. package/dist/admin/components/VariantManager.js +8 -2
  45. package/dist/admin/components/VariantManager.js.map +1 -1
  46. package/dist/admin/components/index.d.ts +2 -0
  47. package/dist/admin/components/index.d.ts.map +1 -1
  48. package/dist/admin/components/index.js +1 -0
  49. package/dist/admin/components/index.js.map +1 -1
  50. package/dist/admin/index.d.ts +1 -1
  51. package/dist/admin/index.d.ts.map +1 -1
  52. package/dist/admin/index.js +2 -0
  53. package/dist/admin/index.js.map +1 -1
  54. package/dist/admin/integrations/brevo-logo.d.ts +11 -0
  55. package/dist/admin/integrations/brevo-logo.d.ts.map +1 -0
  56. package/dist/admin/integrations/brevo-logo.js +11 -0
  57. package/dist/admin/integrations/brevo-logo.js.map +1 -0
  58. package/dist/admin/integrations/registry.d.ts +116 -0
  59. package/dist/admin/integrations/registry.d.ts.map +1 -0
  60. package/dist/admin/integrations/registry.js +389 -0
  61. package/dist/admin/integrations/registry.js.map +1 -0
  62. package/dist/admin/types.d.ts +15 -0
  63. package/dist/admin/types.d.ts.map +1 -1
  64. package/dist/checkout/api/manual.d.ts.map +1 -1
  65. package/dist/checkout/api/manual.js +7 -0
  66. package/dist/checkout/api/manual.js.map +1 -1
  67. package/dist/checkout/api/shipping.d.ts +0 -18
  68. package/dist/checkout/api/shipping.d.ts.map +1 -1
  69. package/dist/checkout/api/shipping.js +33 -3
  70. package/dist/checkout/api/shipping.js.map +1 -1
  71. package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
  72. package/dist/checkout/components/CheckoutFlow.js +30 -14
  73. package/dist/checkout/components/CheckoutFlow.js.map +1 -1
  74. package/dist/checkout/components/OrderSummary.d.ts +1 -1
  75. package/dist/checkout/components/OrderSummary.d.ts.map +1 -1
  76. package/dist/checkout/components/OrderSummary.js +5 -2
  77. package/dist/checkout/components/OrderSummary.js.map +1 -1
  78. package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
  79. package/dist/checkout/server/create-checkout-session.js +38 -9
  80. package/dist/checkout/server/create-checkout-session.js.map +1 -1
  81. package/dist/checkout/server/handle-webhook.js +6 -0
  82. package/dist/checkout/server/handle-webhook.js.map +1 -1
  83. package/dist/checkout/server/order-service.d.ts.map +1 -1
  84. package/dist/checkout/server/order-service.js +21 -0
  85. package/dist/checkout/server/order-service.js.map +1 -1
  86. package/dist/checkout/server/pricing.d.ts +28 -1
  87. package/dist/checkout/server/pricing.d.ts.map +1 -1
  88. package/dist/checkout/server/pricing.js +84 -6
  89. package/dist/checkout/server/pricing.js.map +1 -1
  90. package/dist/checkout/types.d.ts +32 -0
  91. package/dist/checkout/types.d.ts.map +1 -1
  92. package/dist/core/db/queries.d.ts +83 -2
  93. package/dist/core/db/queries.d.ts.map +1 -1
  94. package/dist/core/db/queries.js +88 -2
  95. package/dist/core/db/queries.js.map +1 -1
  96. package/dist/core/db/schema.d.ts +65 -0
  97. package/dist/core/db/schema.d.ts.map +1 -1
  98. package/dist/core/db/schema.js +26 -0
  99. package/dist/core/db/schema.js.map +1 -1
  100. package/dist/core/i18n/messages/en.d.ts.map +1 -1
  101. package/dist/core/i18n/messages/en.js +123 -0
  102. package/dist/core/i18n/messages/en.js.map +1 -1
  103. package/dist/core/i18n/messages/fr.d.ts.map +1 -1
  104. package/dist/core/i18n/messages/fr.js +123 -0
  105. package/dist/core/i18n/messages/fr.js.map +1 -1
  106. package/dist/emails/send/orders.d.ts +4 -0
  107. package/dist/emails/send/orders.d.ts.map +1 -1
  108. package/dist/emails/send/orders.js +1 -0
  109. package/dist/emails/send/orders.js.map +1 -1
  110. package/dist/emails/templates/order-confirmation.d.ts +9 -0
  111. package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
  112. package/dist/emails/templates/order-confirmation.js +19 -8
  113. package/dist/emails/templates/order-confirmation.js.map +1 -1
  114. package/dist/emails/types.d.ts +5 -0
  115. package/dist/emails/types.d.ts.map +1 -1
  116. package/dist/products/api/products.d.ts +3 -1
  117. package/dist/products/api/products.d.ts.map +1 -1
  118. package/dist/products/api/products.js +44 -3
  119. package/dist/products/api/products.js.map +1 -1
  120. package/dist/products/components/VariantSelector.d.ts.map +1 -1
  121. package/dist/products/components/VariantSelector.js +4 -1
  122. package/dist/products/components/VariantSelector.js.map +1 -1
  123. package/dist/products/hooks/useProducts.d.ts +3 -1
  124. package/dist/products/hooks/useProducts.d.ts.map +1 -1
  125. package/dist/products/hooks/useProducts.js +4 -2
  126. package/dist/products/hooks/useProducts.js.map +1 -1
  127. package/docs/changelog/epoch-08-integrations.md +125 -0
  128. package/docs/changelog/epoch-09-catalog-tax.md +91 -0
  129. package/package.json +1 -1
  130. package/templates/store-template/.claude/skills/build-feature/SKILL.md +19 -0
  131. package/templates/store-template/.claude/skills/manage-products/SKILL.md +1 -1
  132. package/templates/store-template/app/account/orders/[id]/invoice/page.tsx +19 -4
  133. package/templates/store-template/app/admin/(dashboard)/integrations/page.tsx +17 -0
  134. package/templates/store-template/app/api/admin/integrations/route.ts +9 -0
  135. package/templates/store-template/app/faq/page.tsx +42 -56
  136. package/templates/store-template/app/privacy/page.tsx +65 -105
  137. package/templates/store-template/app/products/[slug]/ProductDetailClient.tsx +6 -3
  138. package/templates/store-template/app/products/page.tsx +63 -1
  139. package/templates/store-template/app/terms/page.tsx +70 -198
  140. package/templates/store-template/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"VariantSelector.js","sourceRoot":"","sources":["../../../src/products/components/VariantSelector.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AA0BtC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,GAAG,KAAK,EACrB,iBAAiB,GAAG,IAAI,EACxB,MAAM,GAAG,EAAE,EACX,OAAO,GAAG,SAAS,GACE;IACrB,MAAM,CAAC,GAAG,IAAI,EAAE,CAAA;IAChB,sDAAsD;IACtD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,EAAE;QACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAA;QAE7C,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;oBAC1D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;wBACrB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA;oBAC5B,CAAC;oBACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;gBAC7B,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,0BAA0B;QAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3D,IAAI;YACJ,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE;YACjC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC;SAClD,CAAC,CAAC,CAAA;IACL,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;IAEtB,4BAA4B;IAC5B,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAyB,EAAE,CAAC,CAAA;IAExF,oCAAoC;IACpC,oEAAoE;IACpE,yEAAyE;IACzE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,EAAE,UAAU,EAAE,CAAC;YACzB,2DAA2D;YAC3D,qBAAqB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,4CAA4C;IAC5C,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,KAA6B,EAAyB,EAAE;QACvD,OAAO,CACL,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YACxB,IAAI,CAAC,OAAO,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAA;YACrC,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAChC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,KAAK,CACpD,CAAA;QACH,CAAC,CAAC,IAAI,IAAI,CACX,CAAA;IACH,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,0EAA0E;IAC1E,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,aAAqB,EAAE,KAAa,EAAW,EAAE;QAChD,MAAM,SAAS,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;QACnE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;YACnD,IAAI,CAAC,OAAO,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAA;YACrC,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE;gBACpD,qCAAqC;gBACrC,IAAI,CAAC,GAAG;oBAAE,OAAO,IAAI,CAAA;gBACrB,OAAO,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,GAAG,CAAA;YACxC,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QAC/C,IAAI,CAAC,iBAAiB;YAAE,OAAO,IAAI,CAAA;QAEnC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;IACtD,CAAC,EACD,CAAC,QAAQ,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,CAClD,CAAA;IAED,6BAA6B;IAC7B,MAAM,qBAAqB,GAAG,WAAW,CACvC,CAAC,aAAqB,EAAE,KAAa,EAAE,EAAE;QACvC,MAAM,QAAQ,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;QAClE,qBAAqB,CAAC,QAAQ,CAAC,CAAA;QAE/B,+BAA+B;QAC/B,MAAM,eAAe,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAA;QACrD,QAAQ,CAAC,eAAe,CAAC,CAAA;IAC3B,CAAC,EACD,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,QAAQ,CAAC,CACpD,CAAA;IAED,iDAAiD;IACjD,MAAM,kBAAkB,GAAG,WAAW,CACpC,CAAC,aAAqB,EAAE,KAAa,EAA8B,EAAE;QACnE,MAAM,SAAS,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAA;QACnE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAC/B,IAAI,CAAC,OAAO,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAA;YACrC,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CACpC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,GAAG,CAChD,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAC/B,CAAA;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,YACvC,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC9B,0BACE,iBAAO,SAAS,EAAC,gDAAgD,aAC9D,KAAK,CAAC,KAAK,EACX,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CACjC,eAAM,SAAS,EAAC,wCAAwC,YACrD,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,GAC1B,CACR,IACK,EAEP,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CACvB,cAAK,SAAS,EAAC,sBAAsB,YAClC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;wBAC1B,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAA;wBAC3D,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;wBACvD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;wBACrD,MAAM,YAAY,GAAG,OAAO,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,CAAA;wBAEtD,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,CAAC,WAAW,IAAI,CAAC,iBAAiB,IAAI,YAAY,CAAC,EAC7D,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EACvD,SAAS,EAAE,EAAE,CACX,yFAAyF,EACzF,UAAU;gCACR,CAAC,CAAC,mDAAmD;gCACrD,CAAC,CAAC,kEAAkE,EACtE,CAAC,WAAW,IAAI,+BAA+B,EAC/C,YAAY;gCACV,iBAAiB;gCACjB,4CAA4C,CAC/C,aAEA,KAAK,EACL,aAAa,IAAI,OAAO,IAAI,CAC3B,gBAAM,SAAS,EAAC,oCAAoC,kBAChD,OAAO,CAAC,SAAS,SACd,CACR,KApBI,KAAK,CAqBH,CACV,CAAA;oBACH,CAAC,CAAC,GACE,CACP,CAAC,CAAC,CAAC,CACF,kBACE,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAC3C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAClE,SAAS,EAAC,gJAAgJ,aAE1J,iBAAQ,KAAK,EAAC,EAAE,YAAE,CAAC,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,GAAU,EAC3E,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;4BAC1B,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;4BACvD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;4BACrD,MAAM,YAAY,GAAG,OAAO,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,CAAA;4BAEtD,OAAO,CACL,kBAEE,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,WAAW,IAAI,CAAC,iBAAiB,IAAI,YAAY,CAAC,aAE5D,KAAK,EACL,aAAa,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,EACzD,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAN/C,KAAK,CAOH,CACV,CAAA;wBACH,CAAC,CAAC,IACK,CACV,KAtEO,KAAK,CAAC,IAAI,CAuEd,CACP,CAAC,GACE,CACP,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF;;;GAGG;AACH,SAAS,oBAAoB,CAAC,IAAY;IACxC,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;SAClB,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;SAC1B,IAAI,EAAE;SACN,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SACzE,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
1
+ {"version":3,"file":"VariantSelector.js","sourceRoot":"","sources":["../../../src/products/components/VariantSelector.tsx"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  import type { Product } from '../../core/types';
2
2
  export interface UseProductsOptions {
3
- /** Filter by category ID */
3
+ /** Filter by category ID or slug (the API resolves slugs server-side) */
4
4
  category?: string;
5
+ /** Only products on sale (comparePrice > price) */
6
+ onSale?: boolean;
5
7
  /** Search by product name */
6
8
  search?: string;
7
9
  /** Sort order */
@@ -1 +1 @@
1
- {"version":3,"file":"useProducts.d.ts","sourceRoot":"","sources":["../../../src/products/hooks/useProducts.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAO/C,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,MAAM,CAAA;IACrD,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACrC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAA;IAChB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,4BAA4B;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CA8H/E"}
1
+ {"version":3,"file":"useProducts.d.ts","sourceRoot":"","sources":["../../../src/products/hooks/useProducts.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAO/C,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,MAAM,CAAA;IACrD,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IACrC,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAA;IAClB,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAA;IAChB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,4BAA4B;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CAgI/E"}
@@ -35,7 +35,7 @@ import { useLocale } from '../../core/i18n/context';
35
35
  */
36
36
  export function useProducts(options = {}) {
37
37
  const activeLocale = useLocale();
38
- const { category, search, sort = 'newest', attributes, minPrice, maxPrice, limit = 12, initialPage = 1, endpoint = '/api/products', } = options;
38
+ const { category, onSale, search, sort = 'newest', attributes, minPrice, maxPrice, limit = 12, initialPage = 1, endpoint = '/api/products', } = options;
39
39
  const [products, setProducts] = useState([]);
40
40
  const [total, setTotal] = useState(0);
41
41
  const [page, setPage] = useState(initialPage);
@@ -53,6 +53,8 @@ export function useProducts(options = {}) {
53
53
  params.set('locale', activeLocale);
54
54
  if (category)
55
55
  params.set('category', category);
56
+ if (onSale)
57
+ params.set('onSale', '1');
56
58
  if (search)
57
59
  params.set('search', search);
58
60
  if (minPrice !== undefined)
@@ -63,7 +65,7 @@ export function useProducts(options = {}) {
63
65
  params.set('attributes', JSON.stringify(attributes));
64
66
  }
65
67
  return params.toString();
66
- }, [category, search, sort, attributes, minPrice, maxPrice, limit, activeLocale]);
68
+ }, [category, onSale, search, sort, attributes, minPrice, maxPrice, limit, activeLocale]);
67
69
  // Fetch products
68
70
  const fetchProducts = useCallback(async (pageNum, append = false) => {
69
71
  setIsLoading(true);
@@ -1 +1 @@
1
- {"version":3,"file":"useProducts.js","sourceRoot":"","sources":["../../../src/products/hooks/useProducts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useProducts.js","sourceRoot":"","sources":["../../../src/products/hooks/useProducts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ # E8 Integrations hub — 0.21.0..0.21.0
2
+
3
+ ## What landed
4
+ The admin gained `/admin/integrations` — ONE surface where the merchant
5
+ manages credentials for every external service connected to the store
6
+ (Brevo, PayPal, Turnstile, GA4, Google Ads, Meta, TikTok, Klaviyo, Intercom,
7
+ Trustpilot, plus chat-installed custom integrations). Before this, rotating
8
+ a key meant re-running a Feature Store card (a paid AI turn) or a per-store
9
+ custom settings page; now it is a 20-second admin edit. Installing or
10
+ removing an integration stays a Features Store / chat action — this page
11
+ manages what is installed, it is not a catalog.
12
+
13
+ ## SDK-internal (free via pin bump)
14
+ - `IntegrationsManager` (exported from `@rovela-ai/sdk/admin`) — the page
15
+ component; renders its own `AdminPageHeader` (bare-mount page wrapper).
16
+ - `admin/integrations/registry.ts` — the static registry of known providers.
17
+ Each entry names its storage: dedicated `store_settings` columns for
18
+ secrets (brevo_*, paypal_*, turnstile_*) or a slot in the `analytics`
19
+ JSONB (ga4, google_ads, meta, tiktok, klaviyo, intercom, trustpilot).
20
+ These storage locations are a CONTRACT with the platform's Feature Store
21
+ card prompts — never rename one side alone.
22
+ - Presence semantics: an entry renders only when its storage is detectable
23
+ on the store (column exists / JSONB key present) — a store never sees
24
+ integrations it does not have.
25
+ - Secrets: GET returns `{ hasValue, masked }` only; PUT is write-only
26
+ (blank keeps the stored value). Brevo (`GET /v3/account`) and PayPal
27
+ (OAuth token grant) are validated server-side BEFORE persisting — a dead
28
+ key is never saved.
29
+ - AdminNav Configuration group gained the `integrations` item (after Tax).
30
+
31
+ ## Template contract
32
+ - `app/admin/(dashboard)/integrations/page.tsx` (NEW) — bare mount of
33
+ `IntegrationsManager`.
34
+ - `app/api/admin/integrations/route.ts` (NEW) — re-export
35
+ `getIntegrations as GET, saveIntegration as PUT` from
36
+ `@rovela-ai/sdk/admin/api`. Without it the page shows a permanent load
37
+ error.
38
+
39
+ ## Behavior contracts
40
+ - NEW self-healed column `store_settings.custom_integrations jsonb NOT NULL
41
+ DEFAULT '[]'` — descriptor registry for integrations the SDK does not
42
+ know. Deliberately NOT in the drizzle schema (raw-SQL only, like
43
+ `analytics`), so `findSettings` full-row selects never depend on it; the
44
+ integrations API self-heals it at its own chokepoint. Descriptors carry
45
+ `{key, label, fields:[{id = store_settings column name, label, secret}]}`;
46
+ values ALWAYS live in dedicated store_settings columns (merchant-secret
47
+ rule). Malformed descriptors are skipped, never rendered.
48
+ - Custom-integration writes validate every field id against live
49
+ `information_schema` before a quoted-identifier UPDATE.
50
+ - Store-side Claude Code contract (sandbox CLAUDE.md §7.6 + build-feature
51
+ skill): NEVER build a settings page / credentials form / nav entry for
52
+ integration keys — persist to canonical storage and (for novel
53
+ integrations) register a descriptor so this page renders the form.
54
+
55
+ ## Custom-code hazards (audit greps for CC)
56
+ - Grep `app/admin` for hand-built integration settings pages (e.g. a
57
+ `marketing/page.tsx` managing an API key) — they are superseded by
58
+ `/admin/integrations` when their storage matches a registry entry
59
+ (brevo_api_key/brevo_list_id/brevo_enabled for Brevo). Presentational-only
60
+ duplicates should be REMOVED (page + its API route + its `navItems`
61
+ entry); keep any business logic that is not credential management.
62
+ - Grep `navItems` in `app/admin/(dashboard)/layout.tsx` for entries whose
63
+ page only managed credentials — drop them alongside the page.
64
+
65
+ ## MERCHANT-DATA HAZARD
66
+ None — no existing data changes meaning. The page is a view/editor over
67
+ storage that already exists; runtime readers are untouched.
68
+
69
+ ## Also in 0.21.0 — storefront + admin correctness batch
70
+
71
+ SDK-internal (free via pin bump):
72
+ - Products API `?category=` accepts a SLUG as well as a UUID (store-authored
73
+ mega-menu links carry slugs; pre-0.21 a slug silently matched nothing and
74
+ the link showed the FULL catalog). Unknown slug → honest empty result.
75
+ - Products API + `useProducts` gained `onSale` (comparePrice > price), with
76
+ `countProducts` pagination parity — no more raw-SQL sale pages.
77
+ - `VariantSelector` renders attribute values in FIRST-SEEN order, not
78
+ alphabetical (sizes read S / M / L again, not L / M / S / XL).
79
+ - `VariantManager` sync compares variant combinations as KEY SETS, not
80
+ index-by-index — an order-only mismatch used to fire a normalizing
81
+ onChange right after ProductForm captured its dirty baseline, raising a
82
+ phantom "Unsaved changes" save bar on EVERY variant product open.
83
+ - Discounts page empty state got the full first-run treatment (icon +
84
+ title); `compact` stays for its nested sub-panels only.
85
+ - Admin conventions pass (shipping + integrations + order details):
86
+ Connected states are `admin-badge-success` pills (bare green text + icon
87
+ medallions removed), `admin-radio`/`admin-helper-text`/
88
+ `admin-label-required` adopted, `admin-spinner` replaces the animated
89
+ RefreshCw, sentence-case sweep, 16px icons, responsive form grids,
90
+ aria-labels on icon buttons, native select → AdminSelect and the
91
+ signature checkbox → AdminSwitch on the order ship card.
92
+ - i18n catalogs gained `faqPage.q/a.*`, `terms.*`, `privacy.*`,
93
+ `legal.*`, and `listing.{category,onSale,clearFilter}` keys (en + fr).
94
+
95
+ Template contract (new stores + SDK-update flow):
96
+ - `app/products/page.tsx` now READS `?category=` and `?sale=1` from the URL
97
+ (with the required Suspense boundary around `useSearchParams`) and shows
98
+ an active-filter chip. This is the page half of the category-links fix.
99
+ - `app/products/[slug]/ProductDetailClient.tsx` coerces prices to numbers
100
+ before the strikethrough comparison ('185.00' > '55.50' was
101
+ lexicographically false — the compare-at price never showed).
102
+ - `app/{faq,terms,privacy}/page.tsx` body copy now renders from the i18n
103
+ catalogs (was English literals even on French-default stores); FAQ
104
+ country names/lists localize via Intl.DisplayNames/ListFormat.
105
+
106
+ ## Custom-code hazards (0.21.0 batch — audit greps for CC)
107
+ - Grep custom pages/sections for hand-rolled category or sale filtering
108
+ (raw SQL, client-side filters) — `/api/products?category=<slug>` and
109
+ `?onSale=1` now do it natively.
110
+ - Grep for links to `/products?category=` — they WORK now; stores that
111
+ worked around the bug with custom category pages can keep or migrate them.
112
+
113
+ ## Verify
114
+ - `/admin/integrations` renders under Configuration in the admin nav.
115
+ - A store with Brevo columns shows the Brevo card; entering a bad key
116
+ surfaces Brevo's rejection inline and persists nothing.
117
+ - A saved secret displays as "ends in …xxxx"; saving with the secret blank
118
+ keeps the stored value.
119
+ - `SELECT custom_integrations FROM store_settings` returns `[]` (or the
120
+ registered descriptors) — never an error.
121
+ - `/products?category=<existing slug>` shows only that category;
122
+ `/products?sale=1` shows only discounted products (chip + clear visible).
123
+ - A product with comparePrice > price shows the strikethrough on its PDP.
124
+ - Opening a variant product in the admin does NOT raise the save bar.
125
+ - `/faq`, `/terms`, `/privacy` render in French on a fr-default store.
@@ -0,0 +1,91 @@
1
+ # E9 Catalog & tax — 0.22.0..0.22.0
2
+
3
+ ## What landed
4
+ Two catalog-commerce behaviors every PrestaShop-migrated store needs: the
5
+ public category filter is now TREE-AWARE (a parent-category link includes its
6
+ descendant categories' products — imported catalogs assign products to leaf
7
+ categories), and TAX CLASSES bring per-product VAT rates (French 5.5%/20%
8
+ food split): products carry a `tax_class`, tax zones carry per-class rates,
9
+ and every money surface (quote, Stripe session, orders, emails, invoice,
10
+ admin) computes and renders the per-rate VAT ventilation ("dont TVA par
11
+ taux") French invoices legally require.
12
+
13
+ ## SDK-internal (free)
14
+ - `findProducts`/`countProducts` accept `categoryId: string | string[]`
15
+ (IN-match). New `findCategoryDescendantIds(id)` (recursive CTE) and
16
+ `findTaxClassesByProductIds(ids)`.
17
+ - `resolveTax` accepts optional `lines` — per-line computation grouped by
18
+ rate, order discount allocated pro-rata (largest-remainder, sums exact),
19
+ shipping taxed at the zone's base rate. Returns `taxBreakdown` +
20
+ `taxClassRates`. Without `lines`, or on a zone with no `class_rates`, the
21
+ original lump formula runs — cent-identical to 0.21.x.
22
+ - `buildQuote` carries `taxBreakdown`/`taxClassRates` on the Quote; the
23
+ Stripe session divides each line by ITS OWN rate in tax-inclusive mode and
24
+ stamps `rovelaTaxBreakdown` metadata; both order writers persist
25
+ `orders.tax_breakdown`.
26
+ - Admin: TaxSettings zone editor gains per-class rate rows; ProductForm
27
+ gains a Tax class field (datalist fed from the zones' class names);
28
+ tax-zones API accepts `classRates`; products API accepts `taxClass`.
29
+
30
+ ## Template contract
31
+ - `app/account/orders/[id]/invoice/page.tsx` — the totals block renders one
32
+ `TVA {rate}%` row per `order.taxBreakdown` entry when the order carries a
33
+ multi-rate ventilation, else the single flat tax row (stock shape: gated
34
+ branch on `order.taxBreakdown?.length > 1`). Stores with a customized
35
+ invoice keep their layout and add the same branch.
36
+
37
+ ## Behavior contracts
38
+ - **Public `/api/products?category=` is tree-aware.** A parent category id or
39
+ slug now returns its own products PLUS every descendant category's. Stores
40
+ whose nav deliberately relied on parent links showing ONLY directly-assigned
41
+ products (rare; usually a bug they worked around) will see more products.
42
+ Admin product filters are UNCHANGED (exact match).
43
+ - **`OrderSummary` accepts `taxBreakdown`** and renders per-rate rows when
44
+ more than one rate is present; `CheckoutFlow` computes it from the estimate
45
+ response. Single-rate stores render byte-identically to 0.21.x.
46
+ - The pre-checkout shipping estimate (`/api/checkout/shipping`) accepts an
47
+ optional `productId` per item and returns `tax.breakdown`. Clients that
48
+ omit `productId` get the previous base-rate estimate (totals unchanged in
49
+ tax-inclusive stores).
50
+
51
+ ## Custom-code hazards
52
+ - `grep -rn "resolveTax(" app lib components` — custom callers keep working
53
+ (the `lines` param is optional; omitted = old math). If a custom checkout
54
+ displays tax recomputed from `taxRate` alone, it cannot reproduce a
55
+ multi-rate cart: read `tax.breakdown`/`quote.taxBreakdown` when present
56
+ (see CheckoutFlow's per-group recompute for the reference implementation).
57
+ - `grep -rn "taxRate" app components` — any custom "TVA (20%)" label stays
58
+ correct for single-rate stores; multi-rate stores should render the
59
+ breakdown rows instead.
60
+ - `grep -rn "category=" app components lib` — store-authored nav links to
61
+ PARENT categories now include leaf products (this is almost always the
62
+ desired fix, not a regression).
63
+
64
+ ## DB
65
+ - `products.tax_class varchar(50)` NULL — self-heals via
66
+ `ensureCatalogTranslationsSchema` (every catalog chokepoint).
67
+ - `tax_zones.class_rates jsonb NOT NULL DEFAULT '{}'` — self-heals via
68
+ `ensureVisibilityColumns`.
69
+ - `orders.tax_breakdown jsonb` NULL — self-heals via
70
+ `ensurePaymentMethodsSchema`.
71
+ - All three are additive with behavior-preserving defaults: no class rates
72
+ configured = 0.21.x math to the cent. Pre-applying is optional.
73
+
74
+ ## New surfaces
75
+ - None. (TaxSettings/ProductForm gains are inside existing admin pages; no
76
+ new routes to mount.)
77
+
78
+ ## Verify
79
+ 1. `/products?category=<parent slug>` lists products assigned to child
80
+ categories; the admin Products page filtered to the same parent does NOT.
81
+ 2. Settings → Tax: add a class rate (e.g. `tva-5-5` = 5.5) on the active
82
+ zone; assign the class to one product (Product form → Pricing → Tax
83
+ class).
84
+ 3. Cart with one classed + one unclassed product → checkout review shows two
85
+ `TVA x%` rows summing to the receipt tax; totals unchanged
86
+ (tax-inclusive).
87
+ 4. Place a test order → `orders.tax_breakdown` populated; invoice page and
88
+ order-confirmation email render the ventilation; admin order detail shows
89
+ per-rate rows.
90
+ 5. A store that configures NO class rates: quote totals and every tax line
91
+ render exactly as before the update.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rovela-ai/sdk",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Rovela SDK - Pre-built e-commerce components for AI-powered store generation",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -191,6 +191,25 @@ Active state is auto-detected from the URL — no extra config needed.
191
191
  | Admin API auth check with `getServerSession` | Admin pages are already protected by `AdminGuard` layout |
192
192
  | Forgot admin sidebar item | If feature has admin page, MUST add `navItems` to AdminLayout in layout.tsx |
193
193
 
194
+ ## External-service credentials (integrations)
195
+
196
+ If the feature connects to an external service (API key, secret, tracking ID):
197
+
198
+ - Persist credentials to `store_settings` — dedicated columns for secrets (`ALTER TABLE store_settings ADD COLUMN IF NOT EXISTS …`, read server-side at request time; NEVER `.env.local`, NEVER `NEXT_PUBLIC_`), or the `analytics` JSONB for public tracking IDs.
199
+ - The merchant manages them at `/admin/integrations` (SDK page, already mounted). **Do NOT build a settings page, credentials form, or nav entry for keys.**
200
+ - Known keys are auto-rendered (brevo, paypal, turnstile, ga4, google_ads, meta, tiktok, klaviyo, intercom, trustpilot). A NOVEL integration registers a descriptor (dedup by key, then append):
201
+
202
+ ```sql
203
+ ALTER TABLE store_settings ADD COLUMN IF NOT EXISTS custom_integrations jsonb NOT NULL DEFAULT '[]'::jsonb;
204
+ UPDATE store_settings SET custom_integrations =
205
+ (SELECT COALESCE(jsonb_agg(e), '[]'::jsonb)
206
+ FROM jsonb_array_elements(custom_integrations) e
207
+ WHERE e->>'key' <> '<key>')
208
+ || jsonb_build_array('{"key":"<key>","label":"<Label>","fields":[{"id":"<store_settings_column>","label":"API key","secret":true,"required":true}]}'::jsonb);
209
+ ```
210
+
211
+ Field `id`s = the store_settings column names (ALTERed first); mark secrets `"secret": true`. Tell the merchant credentials live under **Configuration → Integrations**.
212
+
194
213
  ## Checklist
195
214
 
196
215
  - [ ] Tables created and verified with `list_objects`
@@ -27,7 +27,7 @@ Usage: `nextjs_call` with `port="3000"` and `toolName="execute_sql"`
27
27
 
28
28
  | Table | Key Columns |
29
29
  |-------|-------------|
30
- | `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description) |
30
+ | `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description), taxClass (0.22.0 — names a rate in tax_zones.class_rates; NULL = zone base rate) |
31
31
  | `product_variants` | id, productId (CASCADE), sku, name, price, inventory, attributes (JSONB), image, video |
32
32
  | `categories` | id, name, slug, parentId (self-ref), order, translations (JSONB) |
33
33
  | `orders` | id, customerId, email, status, total, currency (ISO snapshot — display orders in THIS currency), refundAmount, returnReason, shippingAddress (JSONB) |
@@ -42,6 +42,8 @@ interface InvoiceOrder {
42
42
  total: number
43
43
  subtotal: number
44
44
  tax: number
45
+ /** Per-rate VAT ventilation (0.22.0) — cents; null/absent = flat tax line. */
46
+ taxBreakdown?: Array<{ rate: number; baseCents: number; taxCents: number }> | null
45
47
  shipping: number
46
48
  discountAmount?: number | string
47
49
  discountCode?: string | null
@@ -245,10 +247,23 @@ function InvoiceContent({ orderId }: { orderId: string }) {
245
247
  <span>{t('common.shipping')}</span>
246
248
  <span>{order.shipping > 0 ? formatPrice(order.shipping, orderCurrency) : t('common.free')}</span>
247
249
  </div>
248
- <div className="flex justify-between text-muted-foreground">
249
- <span>{t('common.tax')}</span>
250
- <span>{formatPrice(order.tax, orderCurrency)}</span>
251
- </div>
250
+ {order.taxBreakdown && order.taxBreakdown.length > 1 ? (
251
+ // Per-rate VAT ventilation (0.22.0) — the legally required French
252
+ // invoice breakdown ("dont TVA par taux").
253
+ order.taxBreakdown.map((entry) => (
254
+ <div key={entry.rate} className="flex justify-between text-muted-foreground">
255
+ <span>
256
+ {t('common.tax')} {entry.rate}%
257
+ </span>
258
+ <span>{formatPrice(entry.taxCents / 100, orderCurrency)}</span>
259
+ </div>
260
+ ))
261
+ ) : (
262
+ <div className="flex justify-between text-muted-foreground">
263
+ <span>{t('common.tax')}</span>
264
+ <span>{formatPrice(order.tax, orderCurrency)}</span>
265
+ </div>
266
+ )}
252
267
  <div className="flex justify-between border-t pt-2 text-base font-semibold text-foreground">
253
268
  <span>{t('common.total')}</span>
254
269
  <span>{formatPrice(order.total, orderCurrency)}</span>
@@ -0,0 +1,17 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * Admin Integrations Page
5
+ *
6
+ * Credentials for the external services connected to this store (Brevo,
7
+ * PayPal, analytics pixels, chat-installed custom integrations…). The
8
+ * IntegrationsManager renders the page header itself — this wrapper stays a
9
+ * bare mount. Installing or removing an integration is a Features Store /
10
+ * chat action on the Rovela platform; this page manages what is installed.
11
+ */
12
+
13
+ import { IntegrationsManager } from '@rovela-ai/sdk/admin'
14
+
15
+ export default function AdminIntegrationsPage() {
16
+ return <IntegrationsManager />
17
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Admin Integrations API Route
3
+ *
4
+ * GET /api/admin/integrations - Installed integrations with masked secrets
5
+ * PUT /api/admin/integrations - Save one integration's credentials/settings
6
+ * (provider-validated before persisting)
7
+ */
8
+
9
+ export { getIntegrations as GET, saveIntegration as PUT } from '@rovela-ai/sdk/admin/api'
@@ -1,6 +1,6 @@
1
- import { localizedAlternates, getRequestLocale } from '@rovela-ai/sdk/core/server'
2
1
  import type { Metadata } from 'next'
3
- import { LocaleLink as Link, getT } from '@rovela-ai/sdk/core'
2
+ import { localizedAlternates, getRequestLocale } from '@rovela-ai/sdk/core/server'
3
+ import { LocaleLink as Link, getT, intlLocaleFor } from '@rovela-ai/sdk/core'
4
4
  import { findSettings } from '@rovela-ai/sdk/core/server'
5
5
  import { buildFaqJsonLd, serializeJsonLd } from '@rovela-ai/sdk/core'
6
6
  import { storeConfig } from '@/lib/store-config'
@@ -19,9 +19,14 @@ import {
19
19
  *
20
20
  * Server Component (no 'use client') so the schema + content are in the initial
21
21
  * HTML — AI crawlers don't execute JavaScript.
22
+ *
23
+ * Every Q&A body comes from the i18n catalogs (they were English literals
24
+ * pre-0.21, which shipped an English FAQ on French-default stores). Country
25
+ * names + list joining use Intl.DisplayNames / Intl.ListFormat so they
26
+ * localize without a hand-maintained map.
22
27
  */
23
28
 
24
- export async function generateMetadata() {
29
+ export async function generateMetadata(): Promise<Metadata> {
25
30
  const { locale } = await getRequestLocale()
26
31
  const t = getT(locale)
27
32
  return {
@@ -31,30 +36,22 @@ export async function generateMetadata() {
31
36
  }
32
37
  }
33
38
 
34
- const COUNTRY_NAMES: Record<string, string> = {
35
- US: 'the United States',
36
- CA: 'Canada',
37
- GB: 'the United Kingdom',
38
- AU: 'Australia',
39
- NZ: 'New Zealand',
40
- IE: 'Ireland',
41
- DE: 'Germany',
42
- FR: 'France',
43
- ES: 'Spain',
44
- IT: 'Italy',
45
- NL: 'the Netherlands',
46
- }
47
-
48
- function formatCountries(codes: string[]): string {
49
- const names = codes.map((c) => COUNTRY_NAMES[c] || c)
50
- if (names.length === 1) return names[0]
51
- if (names.length === 2) return `${names[0]} and ${names[1]}`
52
- return `${names.slice(0, -1).join(', ')}, and ${names[names.length - 1]}`
39
+ function formatCountries(codes: string[], intlLocale: string): string {
40
+ const display = new Intl.DisplayNames([intlLocale], { type: 'region' })
41
+ const names = codes.map((c) => {
42
+ try {
43
+ return display.of(c) || c
44
+ } catch {
45
+ return c
46
+ }
47
+ })
48
+ return new Intl.ListFormat(intlLocale, { style: 'long', type: 'conjunction' }).format(names)
53
49
  }
54
50
 
55
51
  export default async function FaqPage() {
56
52
  const { locale } = await getRequestLocale()
57
53
  const t = getT(locale)
54
+ const intlLocale = intlLocaleFor(locale)
58
55
  const settings = await findSettings().catch(() => null)
59
56
 
60
57
  const countries = shipsToCountries(settings)
@@ -67,49 +64,38 @@ export default async function FaqPage() {
67
64
 
68
65
  const faqs: Array<{ question: string; answer: string }> = [
69
66
  {
70
- question: 'What payment methods do you accept?',
67
+ question: t('faqPage.q.payment'),
68
+ answer: t('faqPage.a.payment'),
69
+ },
70
+ {
71
+ question: t('faqPage.q.countries'),
72
+ answer: t('faqPage.a.countries', { countries: formatCountries(countries, intlLocale) }),
73
+ },
74
+ {
75
+ question: t('faqPage.q.shippingCost'),
71
76
  answer:
72
- 'We accept major credit and debit cards through our secure checkout. Your payment details are encrypted and handled by our payment provider — we never store full card numbers.',
77
+ freeThreshold > 0
78
+ ? t('faqPage.a.shippingCostFree', { threshold: freeThreshold, currency })
79
+ : t('faqPage.a.shippingCost'),
73
80
  },
74
81
  {
75
- question: 'Which countries do you ship to?',
76
- answer: `We currently ship to ${formatCountries(countries)}.`,
82
+ question: t('faqPage.q.delivery'),
83
+ answer: t('faqPage.a.delivery', { processing }),
77
84
  },
78
- freeThreshold > 0
79
- ? {
80
- question: 'How much does shipping cost?',
81
- answer: `Shipping is calculated at checkout based on your address. Orders over ${freeThreshold} ${currency} qualify for free shipping.`,
82
- }
83
- : {
84
- question: 'How much does shipping cost?',
85
- answer:
86
- 'Shipping is calculated at checkout based on your delivery address and the items in your order.',
87
- },
88
85
  {
89
- question: 'How long will my order take to arrive?',
90
- answer: `Orders are typically processed within ${processing} business days and then shipped. Delivery time depends on your location and the carrier.`,
86
+ question: t('faqPage.q.returns'),
87
+ answer:
88
+ returnDays > 0
89
+ ? t('faqPage.a.returns', { days: returnDays })
90
+ : t('faqPage.a.noReturns'),
91
91
  },
92
- returnDays > 0
93
- ? {
94
- question: 'What is your return policy?',
95
- answer: `You can return unused items in their original condition within ${returnDays} days of delivery. Return shipping is the customer's responsibility unless the item arrived damaged or incorrect.`,
96
- }
97
- : {
98
- question: 'What is your return policy?',
99
- answer:
100
- 'All sales are final. If your item arrives damaged or incorrect, contact us right away and we will make it right.',
101
- },
102
92
  {
103
- question: 'Do I need an account to place an order?',
104
- answer: guestCheckout
105
- ? 'No account is required — you can check out as a guest. Creating an account lets you track orders and check out faster next time.'
106
- : 'Please create an account at checkout so you can track your order and manage returns.',
93
+ question: t('faqPage.q.account'),
94
+ answer: guestCheckout ? t('faqPage.a.accountGuest') : t('faqPage.a.accountRequired'),
107
95
  },
108
96
  {
109
- question: 'How can I contact you?',
110
- answer: email
111
- ? `Email us at ${email} and we'll get back to you as soon as we can. You can also use our contact page.`
112
- : `Reach us through our contact page and we'll get back to you as soon as we can.`,
97
+ question: t('faqPage.q.contact'),
98
+ answer: email ? t('faqPage.a.contactEmail', { email }) : t('faqPage.a.contactPage'),
113
99
  },
114
100
  ]
115
101