create-snapify-app 0.0.0-stage → 1.1.1

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 (614) hide show
  1. package/LICENSE.md +24 -0
  2. package/README.md +55 -2
  3. package/bin/create-snapify-app.mjs +174 -0
  4. package/lib/args.mjs +59 -0
  5. package/lib/copy.mjs +44 -0
  6. package/lib/env.mjs +84 -0
  7. package/lib/prompt.mjs +63 -0
  8. package/package.json +35 -4
  9. package/template/.env.example +79 -0
  10. package/template/.github/workflows/ci.yml +23 -0
  11. package/template/.github/workflows/deploy.yml +26 -0
  12. package/template/.github/workflows/ping.yml +8 -0
  13. package/template/.github/workflows/release.yml +67 -0
  14. package/template/.snapify-install.json +5 -0
  15. package/template/CHANGELOG.md +28 -0
  16. package/template/LICENSE +14 -0
  17. package/template/README.md +287 -0
  18. package/template/administrator.html +23 -0
  19. package/template/apps/client/src/App.tsx +765 -0
  20. package/template/apps/client/src/auth.css +400 -0
  21. package/template/apps/client/src/lib/api.ts +22 -0
  22. package/template/apps/client/src/main.tsx +20 -0
  23. package/template/apps/community/src/App.tsx +592 -0
  24. package/template/apps/community/src/main.tsx +20 -0
  25. package/template/apps/community/src/styles.css +24 -0
  26. package/template/apps/developers/src/App.tsx +643 -0
  27. package/template/apps/developers/src/main.tsx +17 -0
  28. package/template/apps/developers/src/pages.tsx +1587 -0
  29. package/template/apps/developers/src/styles.css +98 -0
  30. package/template/apps/developers/src/ui.tsx +179 -0
  31. package/template/apps/landing/src/App.tsx +598 -0
  32. package/template/apps/landing/src/LegalPages.tsx +158 -0
  33. package/template/apps/landing/src/OrderPage.tsx +381 -0
  34. package/template/apps/landing/src/SeoPages.tsx +923 -0
  35. package/template/apps/landing/src/copy.ts +195 -0
  36. package/template/apps/landing/src/main.tsx +20 -0
  37. package/template/apps/landing/src/styles.css +803 -0
  38. package/template/apps/landing/src/types.ts +19 -0
  39. package/template/apps/marketplace/src/App.tsx +1229 -0
  40. package/template/apps/marketplace/src/developer/DeveloperApp.tsx +1266 -0
  41. package/template/apps/marketplace/src/main.tsx +20 -0
  42. package/template/apps/marketplace/src/styles.css +1001 -0
  43. package/template/apps/shared/AuthContext.tsx +65 -0
  44. package/template/apps/shared/Logo.tsx +33 -0
  45. package/template/apps/shared/api.ts +47 -0
  46. package/template/apps/shared/ui.tsx +128 -0
  47. package/template/apps/superadmin/src/App.tsx +1264 -0
  48. package/template/apps/superadmin/src/lib/api.ts +20 -0
  49. package/template/apps/superadmin/src/lib/hooks.ts +20 -0
  50. package/template/apps/superadmin/src/main.tsx +16 -0
  51. package/template/apps/superadmin/src/pages/ClientsPage.tsx +185 -0
  52. package/template/apps/superadmin/src/pages/InvoicesPage.tsx +157 -0
  53. package/template/apps/superadmin/src/pages/NewsletterPage.tsx +212 -0
  54. package/template/apps/superadmin/src/pages/OrdersPage.tsx +195 -0
  55. package/template/apps/superadmin/src/pages/PaymentsPage.tsx +150 -0
  56. package/template/apps/superadmin/src/pages/PayoutsPage.tsx +133 -0
  57. package/template/apps/superadmin/src/pages/PublishersPage.tsx +151 -0
  58. package/template/apps/superadmin/src/pages/SeoControlPage.tsx +692 -0
  59. package/template/apps/superadmin/src/pages/SettingsPage.tsx +199 -0
  60. package/template/apps/superadmin/src/pages/SystemPage.tsx +109 -0
  61. package/template/apps/superadmin/src/pages/TicketsPage.tsx +201 -0
  62. package/template/apps/superadmin/src/pages/UsersPage.tsx +167 -0
  63. package/template/client.html +21 -0
  64. package/template/community/hamdiayari/akhbar/README.md +23 -0
  65. package/template/community/hamdiayari/akhbar/screenshot.jpg +0 -0
  66. package/template/community/hamdiayari/akhbar/snapify.theme.json +76 -0
  67. package/template/community/hamdiayari/akhbar/src/Brand.tsx +26 -0
  68. package/template/community/hamdiayari/akhbar/src/Footer.tsx +182 -0
  69. package/template/community/hamdiayari/akhbar/src/Header.tsx +191 -0
  70. package/template/community/hamdiayari/akhbar/src/Layout.tsx +49 -0
  71. package/template/community/hamdiayari/akhbar/src/Social.tsx +33 -0
  72. package/template/community/hamdiayari/akhbar/src/Ticker.tsx +86 -0
  73. package/template/community/hamdiayari/akhbar/src/Views.tsx +285 -0
  74. package/template/community/hamdiayari/akhbar/src/blocks/CollectionBlocks.tsx +672 -0
  75. package/template/community/hamdiayari/akhbar/src/blocks/ContentBlocks.tsx +305 -0
  76. package/template/community/hamdiayari/akhbar/src/blocks/ConversionBlocks.tsx +569 -0
  77. package/template/community/hamdiayari/akhbar/src/blocks/HeaderBlocks.tsx +287 -0
  78. package/template/community/hamdiayari/akhbar/src/index.tsx +51 -0
  79. package/template/community/hamdiayari/akhbar/src/kit.tsx +357 -0
  80. package/template/community/hamdiayari/akhbar/src/site.ts +96 -0
  81. package/template/community/hamdiayari/akhbar/src/styles.css +566 -0
  82. package/template/community/hamdiayari/akhbar-actualites/README.md +28 -0
  83. package/template/community/hamdiayari/akhbar-actualites/screenshot.jpg +0 -0
  84. package/template/community/hamdiayari/akhbar-actualites/snapify.module.json +107 -0
  85. package/template/community/hamdiayari/akhbar-actualites/src/admin/AudiencePage.tsx +185 -0
  86. package/template/community/hamdiayari/akhbar-actualites/src/admin/index.tsx +11 -0
  87. package/template/community/hamdiayari/akhbar-actualites/src/public/Archive.tsx +142 -0
  88. package/template/community/hamdiayari/akhbar-actualites/src/public/cards.tsx +152 -0
  89. package/template/community/hamdiayari/akhbar-actualites/src/public/index.tsx +71 -0
  90. package/template/community/hamdiayari/akhbar-actualites/src/public/posts.ts +103 -0
  91. package/template/community/hamdiayari/akhbar-actualites/src/public/styles.css +568 -0
  92. package/template/community/hamdiayari/akhbar-actualites/src/public/widgets.tsx +226 -0
  93. package/template/community/hamdiayari/akhbar-actualites/src/server.ts +119 -0
  94. package/template/community/hamdiayari/akhbar-actualites/src/types.ts +25 -0
  95. package/template/community/hamdiayari/akhbar-urgent/README.md +36 -0
  96. package/template/community/hamdiayari/akhbar-urgent/screenshot.jpg +0 -0
  97. package/template/community/hamdiayari/akhbar-urgent/snapify.module.json +64 -0
  98. package/template/community/hamdiayari/akhbar-urgent/src/admin/FlashesPage.tsx +229 -0
  99. package/template/community/hamdiayari/akhbar-urgent/src/admin/index.tsx +11 -0
  100. package/template/community/hamdiayari/akhbar-urgent/src/public/Ticker.tsx +81 -0
  101. package/template/community/hamdiayari/akhbar-urgent/src/public/index.tsx +63 -0
  102. package/template/community/hamdiayari/akhbar-urgent/src/public/styles.css +142 -0
  103. package/template/community/hamdiayari/akhbar-urgent/src/server.ts +101 -0
  104. package/template/community/hamdiayari/akhbar-urgent/src/types.ts +35 -0
  105. package/template/community.html +21 -0
  106. package/template/developers.html +24 -0
  107. package/template/docker-compose.db.yml +24 -0
  108. package/template/docs/BACKOFFICE_SNAPIFY.md +130 -0
  109. package/template/docs/CI_CD.md +66 -0
  110. package/template/docs/MODULES.md +346 -0
  111. package/template/docs/PLATFORM_DEPLOY.md +54 -0
  112. package/template/docs/logo.svg +10 -0
  113. package/template/drizzle/0000_init.sql +147 -0
  114. package/template/drizzle/0001_page_project.sql +5 -0
  115. package/template/drizzle/0002_modules.sql +23 -0
  116. package/template/drizzle/0003_themes.sql +4 -0
  117. package/template/drizzle/0004_security.sql +82 -0
  118. package/template/drizzle/0005_module_records.sql +16 -0
  119. package/template/drizzle/0006_avatars.sql +4 -0
  120. package/template/drizzle/0007_platform.sql +264 -0
  121. package/template/drizzle/0008_mp_validation.sql +3 -0
  122. package/template/drizzle/0009_saas_ops.sql +77 -0
  123. package/template/drizzle/0010_cms_chrome.sql +13 -0
  124. package/template/drizzle/0011_client_portal.sql +26 -0
  125. package/template/drizzle/meta/0000_snapshot.json +998 -0
  126. package/template/drizzle/meta/0001_snapshot.json +1004 -0
  127. package/template/drizzle/meta/_journal.json +90 -0
  128. package/template/drizzle.config.ts +16 -0
  129. package/template/ecosystem.snapify.cjs +24 -0
  130. package/template/for.html +1 -0
  131. package/template/index.html +29 -0
  132. package/template/landing.html +37 -0
  133. package/template/marketplace/catalog.json +373 -0
  134. package/template/marketplace/gallery/hamdiayari.preveris/01-home.jpg +0 -0
  135. package/template/marketplace/gallery/hamdiayari.recaptcha/01-reglages.jpg +0 -0
  136. package/template/marketplace/gallery/hamdiayari.recaptcha/02-logo.jpg +0 -0
  137. package/template/marketplace/gallery/novalabs.ai-articles/01-generer.jpg +0 -0
  138. package/template/marketplace/gallery/novalabs.ai-articles/02-fournisseur-ia.jpg +0 -0
  139. package/template/marketplace/gallery/novalabs.calendar/01-agenda-site.jpg +0 -0
  140. package/template/marketplace/gallery/novalabs.calendar/02-evenements-admin.jpg +0 -0
  141. package/template/marketplace/gallery/novalabs.calendar/03-reglages.jpg +0 -0
  142. package/template/marketplace/screenshots/hamdiayari.preveris-1.0.6.jpg +0 -0
  143. package/template/marketplace/screenshots/hamdiayari.recaptcha-1.0.0.jpg +0 -0
  144. package/template/marketplace/screenshots/hamdiayari.wp-seo-migrator-1.1.1.jpg +0 -0
  145. package/template/marketplace/screenshots/novalabs.ai-articles-1.0.1.jpg +0 -0
  146. package/template/marketplace/screenshots/novalabs.ai-chat-1.0.1.jpg +0 -0
  147. package/template/marketplace/screenshots/novalabs.calendar-1.0.1.jpg +0 -0
  148. package/template/marketplace/screenshots/novalabs.cart-1.0.0.jpg +0 -0
  149. package/template/marketplace/screenshots/novalabs.checkout-1.0.0.jpg +0 -0
  150. package/template/marketplace/screenshots/novalabs.customers-1.1.0.jpg +0 -0
  151. package/template/marketplace/screenshots/novalabs.dogga-1.0.0.jpg +0 -0
  152. package/template/marketplace/screenshots/novalabs.mahdia-1.0.0.jpg +0 -0
  153. package/template/marketplace/screenshots/novalabs.shop-1.0.0.jpg +0 -0
  154. package/template/marketplace/screenshots/novalabs.sidibou-1.0.0.jpg +0 -0
  155. package/template/marketplace/screenshots/novalabs.whatsapp-1.0.1.jpg +0 -0
  156. package/template/marketplace.html +21 -0
  157. package/template/metadata.json +7 -0
  158. package/template/modules/ai-articles/screenshot.jpg +0 -0
  159. package/template/modules/ai-articles/snapify.module.json +74 -0
  160. package/template/modules/ai-articles/src/admin/ArticlesPage.tsx +162 -0
  161. package/template/modules/ai-articles/src/admin/GeneratePage.tsx +118 -0
  162. package/template/modules/ai-articles/src/admin/index.tsx +12 -0
  163. package/template/modules/ai-articles/src/public/index.tsx +119 -0
  164. package/template/modules/ai-articles/src/server.ts +287 -0
  165. package/template/modules/ai-articles/src/types.ts +30 -0
  166. package/template/modules/ai-chat/screenshot.jpg +0 -0
  167. package/template/modules/ai-chat/snapify.module.json +217 -0
  168. package/template/modules/ai-chat/src/public.tsx +198 -0
  169. package/template/modules/ai-chat/src/server.ts +142 -0
  170. package/template/modules/ai-theme-studio/README.md +15 -0
  171. package/template/modules/ai-theme-studio/screenshot.jpg +0 -0
  172. package/template/modules/ai-theme-studio/snapify.module.json +175 -0
  173. package/template/modules/ai-theme-studio/src/admin/HistoryPage.tsx +91 -0
  174. package/template/modules/ai-theme-studio/src/admin/StudioPage.tsx +414 -0
  175. package/template/modules/ai-theme-studio/src/admin/index.tsx +11 -0
  176. package/template/modules/ai-theme-studio/src/lib/images.ts +240 -0
  177. package/template/modules/ai-theme-studio/src/lib/llm.ts +123 -0
  178. package/template/modules/ai-theme-studio/src/lib/normalize.ts +714 -0
  179. package/template/modules/ai-theme-studio/src/lib/prompts.ts +198 -0
  180. package/template/modules/ai-theme-studio/src/server.ts +137 -0
  181. package/template/modules/ai-theme-studio/src/types.ts +112 -0
  182. package/template/modules/calendar/screenshot.jpg +0 -0
  183. package/template/modules/calendar/snapify.module.json +45 -0
  184. package/template/modules/calendar/src/admin/EventsPage.tsx +217 -0
  185. package/template/modules/calendar/src/admin/index.tsx +11 -0
  186. package/template/modules/calendar/src/public/index.tsx +231 -0
  187. package/template/modules/calendar/src/server.ts +143 -0
  188. package/template/modules/calendar/src/types.ts +25 -0
  189. package/template/modules/cart/screenshot.jpg +0 -0
  190. package/template/modules/cart/snapify.module.json +90 -0
  191. package/template/modules/cart/src/admin/index.tsx +265 -0
  192. package/template/modules/cart/src/public/CartPage.tsx +198 -0
  193. package/template/modules/cart/src/public/index.tsx +261 -0
  194. package/template/modules/cart/src/public/useQuote.ts +67 -0
  195. package/template/modules/cart/src/server.ts +148 -0
  196. package/template/modules/cart/src/types.ts +31 -0
  197. package/template/modules/checkout/screenshot.jpg +0 -0
  198. package/template/modules/checkout/snapify.module.json +264 -0
  199. package/template/modules/checkout/src/admin/OrderDetailPage.tsx +304 -0
  200. package/template/modules/checkout/src/admin/badges.tsx +28 -0
  201. package/template/modules/checkout/src/admin/index.tsx +236 -0
  202. package/template/modules/checkout/src/public/CheckoutPage.tsx +461 -0
  203. package/template/modules/checkout/src/public/OrderPages.tsx +153 -0
  204. package/template/modules/checkout/src/public/index.tsx +23 -0
  205. package/template/modules/checkout/src/server.ts +383 -0
  206. package/template/modules/checkout/src/types.ts +70 -0
  207. package/template/modules/customers/screenshot.jpg +0 -0
  208. package/template/modules/customers/snapify.module.json +115 -0
  209. package/template/modules/customers/src/admin/CustomerDetailPage.tsx +274 -0
  210. package/template/modules/customers/src/admin/index.tsx +194 -0
  211. package/template/modules/customers/src/public/AccountPages.tsx +470 -0
  212. package/template/modules/customers/src/public/AddressForm.tsx +115 -0
  213. package/template/modules/customers/src/public/AuthPages.tsx +349 -0
  214. package/template/modules/customers/src/public/Avatar.tsx +29 -0
  215. package/template/modules/customers/src/public/ProfileSection.tsx +291 -0
  216. package/template/modules/customers/src/public/index.tsx +137 -0
  217. package/template/modules/customers/src/public/session.ts +51 -0
  218. package/template/modules/customers/src/server.ts +421 -0
  219. package/template/modules/customers/src/types.ts +53 -0
  220. package/template/modules/recaptcha/logo.jpg +0 -0
  221. package/template/modules/recaptcha/screenshot.jpg +0 -0
  222. package/template/modules/recaptcha/snapify.module.json +99 -0
  223. package/template/modules/recaptcha/src/public/index.tsx +94 -0
  224. package/template/modules/recaptcha/src/server.ts +65 -0
  225. package/template/modules/recaptcha/src/types.ts +18 -0
  226. package/template/modules/shop/screenshot.jpg +0 -0
  227. package/template/modules/shop/snapify.module.json +340 -0
  228. package/template/modules/shop/src/admin/CategoriesPage.tsx +224 -0
  229. package/template/modules/shop/src/admin/ProductEditor.tsx +313 -0
  230. package/template/modules/shop/src/admin/ProductsPage.tsx +307 -0
  231. package/template/modules/shop/src/admin/index.tsx +14 -0
  232. package/template/modules/shop/src/public/Catalog.tsx +244 -0
  233. package/template/modules/shop/src/public/NotFound.tsx +22 -0
  234. package/template/modules/shop/src/public/ProductPage.tsx +195 -0
  235. package/template/modules/shop/src/public/index.tsx +134 -0
  236. package/template/modules/shop/src/public/useFetch.ts +26 -0
  237. package/template/modules/shop/src/server.ts +493 -0
  238. package/template/modules/shop/src/shared.ts +41 -0
  239. package/template/modules/shop/src/types.ts +60 -0
  240. package/template/modules/whatsapp/screenshot.jpg +0 -0
  241. package/template/modules/whatsapp/snapify.module.json +121 -0
  242. package/template/modules/whatsapp/src/public.tsx +119 -0
  243. package/template/modules/wp-seo-migrator/ARCHITECTURE.md +113 -0
  244. package/template/modules/wp-seo-migrator/README.md +21 -0
  245. package/template/modules/wp-seo-migrator/fixtures/aioseo-sample.csv +3 -0
  246. package/template/modules/wp-seo-migrator/fixtures/sample-exporter.json +39 -0
  247. package/template/modules/wp-seo-migrator/fixtures/sample-page.html +12 -0
  248. package/template/modules/wp-seo-migrator/fixtures/sample.htaccess +3 -0
  249. package/template/modules/wp-seo-migrator/screenshot.jpg +0 -0
  250. package/template/modules/wp-seo-migrator/snapify.module.json +87 -0
  251. package/template/modules/wp-seo-migrator/src/admin/HistoryPage.tsx +64 -0
  252. package/template/modules/wp-seo-migrator/src/admin/WizardPage.tsx +788 -0
  253. package/template/modules/wp-seo-migrator/src/admin/i18n.ts +156 -0
  254. package/template/modules/wp-seo-migrator/src/admin/index.tsx +11 -0
  255. package/template/modules/wp-seo-migrator/src/connectors/CUSTOM_CONNECTOR.md +31 -0
  256. package/template/modules/wp-seo-migrator/src/connectors/csvSeoFactory.ts +106 -0
  257. package/template/modules/wp-seo-migrator/src/connectors/exporter.ts +96 -0
  258. package/template/modules/wp-seo-migrator/src/connectors/gscCsv.ts +53 -0
  259. package/template/modules/wp-seo-migrator/src/connectors/htaccess.ts +65 -0
  260. package/template/modules/wp-seo-migrator/src/connectors/htmlCrawler.ts +90 -0
  261. package/template/modules/wp-seo-migrator/src/connectors/index.ts +113 -0
  262. package/template/modules/wp-seo-migrator/src/connectors/pluginCsv.ts +77 -0
  263. package/template/modules/wp-seo-migrator/src/connectors/rankMathCsv.ts +77 -0
  264. package/template/modules/wp-seo-migrator/src/connectors/redirection.ts +62 -0
  265. package/template/modules/wp-seo-migrator/src/connectors/sitemap.ts +44 -0
  266. package/template/modules/wp-seo-migrator/src/connectors/utils.ts +111 -0
  267. package/template/modules/wp-seo-migrator/src/connectors/wxr.ts +103 -0
  268. package/template/modules/wp-seo-migrator/src/connectors/yoastCsv.ts +56 -0
  269. package/template/modules/wp-seo-migrator/src/pipeline/analyze.ts +158 -0
  270. package/template/modules/wp-seo-migrator/src/pipeline/htmlParse.ts +58 -0
  271. package/template/modules/wp-seo-migrator/src/pipeline/remoteAuto.ts +328 -0
  272. package/template/modules/wp-seo-migrator/src/server.ts +492 -0
  273. package/template/modules/wp-seo-migrator/src/types.ts +151 -0
  274. package/template/modules/wp-seo-migrator/tests/connectors-extra.test.ts +39 -0
  275. package/template/modules/wp-seo-migrator/tests/merge.test.ts +25 -0
  276. package/template/package-lock.json +6016 -0
  277. package/template/package.json +74 -0
  278. package/template/public/images/photos/caravane-chameaux-desert.webp +0 -0
  279. package/template/public/images/photos/hammamet-medina-plage.jpg +0 -0
  280. package/template/public/images/photos/maison-campagne-collines.webp +0 -0
  281. package/template/public/images/photos/maisons-troglodytes-desert.jpg +0 -0
  282. package/template/public/images/photos/panorama-ville.jpg +0 -0
  283. package/template/public/images/photos/preveris-accessibilite-erp.jpg +0 -0
  284. package/template/public/images/photos/preveris-collectivites.jpg +0 -0
  285. package/template/public/images/photos/preveris-etudes-plans.jpg +0 -0
  286. package/template/public/images/photos/preveris-hero-erp.jpg +0 -0
  287. package/template/public/images/photos/preveris-ssi-incendie.jpg +0 -0
  288. package/template/public/images/photos/preveris-suivi-hotel.jpg +0 -0
  289. package/template/public/images/photos/ruelle-bleue-medina.jpg +0 -0
  290. package/template/public/images/photos/sidi-bou-said-port.webp +0 -0
  291. package/template/public/images/photos/terrasse-blanche-mer-voilier.jpg +0 -0
  292. package/template/public/landing/hero-ai-cms.jpg +0 -0
  293. package/template/public/landing/shot-dogga.jpg +0 -0
  294. package/template/public/landing/shot-mahdia.jpg +0 -0
  295. package/template/public/landing/shot-sidibou.jpg +0 -0
  296. package/template/public/llms.txt +35 -0
  297. package/template/public/logo.svg +10 -0
  298. package/template/scripts/app-pack.ts +155 -0
  299. package/template/scripts/app-publish.ts +123 -0
  300. package/template/scripts/apply-ecommerce-home.ts +196 -0
  301. package/template/scripts/auto-deploy-poll.sh +13 -0
  302. package/template/scripts/db-backup.sh +16 -0
  303. package/template/scripts/db-restore.sh +11 -0
  304. package/template/scripts/deploy.sh +34 -0
  305. package/template/scripts/github-webhook-deploy.sh +7 -0
  306. package/template/scripts/install-new-modules.ts +96 -0
  307. package/template/scripts/refresh-demo-baseline.ts +9 -0
  308. package/template/scripts/reinstall-marketplace-packs.ts +51 -0
  309. package/template/scripts/restore-classic-home.ts +13 -0
  310. package/template/scripts/sdk-pack.ts +289 -0
  311. package/template/scripts/sdk-publish.ts +75 -0
  312. package/template/scripts/seed-demo-products.ts +120 -0
  313. package/template/scripts/seed-theme-content-packs.ts +42 -0
  314. package/template/scripts/snapify-module.ts +207 -0
  315. package/template/scripts/test-theme-switch.ts +24 -0
  316. package/template/sdk/admin.css +18 -0
  317. package/template/sdk/admin.ts +95 -0
  318. package/template/sdk/build.ts +249 -0
  319. package/template/sdk/commerce.ts +512 -0
  320. package/template/sdk/content.ts +76 -0
  321. package/template/sdk/icons.ts +101 -0
  322. package/template/sdk/image.ts +60 -0
  323. package/template/sdk/index.ts +500 -0
  324. package/template/sdk/package.ts +298 -0
  325. package/template/sdk/recaptcha.tsx +122 -0
  326. package/template/sdk/settings.ts +84 -0
  327. package/template/sdk/theme.css +29 -0
  328. package/template/sdk/theme.ts +100 -0
  329. package/template/sdk/ui/commerce.tsx +385 -0
  330. package/template/sdk/ui/orders.tsx +136 -0
  331. package/template/sdk-kit/CHANGELOG.md +17 -0
  332. package/template/sdk-kit/LICENSE.md +47 -0
  333. package/template/sdk-kit/README.md +81 -0
  334. package/template/sdk-kit/cli.ts +339 -0
  335. package/template/sdk-kit/create-snapify/README.md +28 -0
  336. package/template/sdk-kit/create-snapify/create-snapify.mjs +11 -0
  337. package/template/sdk-kit/create-snapify/package.template.json +16 -0
  338. package/template/sdk-kit/package.template.json +95 -0
  339. package/template/sdk-kit/templates/common/README.md.tpl +27 -0
  340. package/template/sdk-kit/templates/common/_gitignore +3 -0
  341. package/template/sdk-kit/templates/common/package.json.tpl +19 -0
  342. package/template/sdk-kit/templates/common/src/snapify-env.d.ts +2 -0
  343. package/template/sdk-kit/templates/common/tsconfig.json +15 -0
  344. package/template/sdk-kit/templates/module/snapify.module.json.tpl +33 -0
  345. package/template/sdk-kit/templates/module/src/admin.tsx +53 -0
  346. package/template/sdk-kit/templates/module/src/public.tsx +49 -0
  347. package/template/sdk-kit/templates/module/src/server.ts +30 -0
  348. package/template/sdk-kit/templates/module/src/types.ts +19 -0
  349. package/template/sdk-kit/templates/theme/snapify.theme.json.tpl +22 -0
  350. package/template/sdk-kit/templates/theme/src/Footer.tsx +40 -0
  351. package/template/sdk-kit/templates/theme/src/Header.tsx +47 -0
  352. package/template/sdk-kit/templates/theme/src/Views.tsx +36 -0
  353. package/template/sdk-kit/templates/theme/src/blocks.tsx +93 -0
  354. package/template/sdk-kit/templates/theme/src/index.tsx +30 -0
  355. package/template/sdk-kit/templates/theme/src/site.tsx +59 -0
  356. package/template/sdk-kit/templates/theme/src/styles.css +71 -0
  357. package/template/server/client/routes.ts +252 -0
  358. package/template/server/cms/analyticsStore.ts +180 -0
  359. package/template/server/cms/auth.ts +155 -0
  360. package/template/server/cms/blockCatalog.ts +342 -0
  361. package/template/server/cms/blocks.ts +521 -0
  362. package/template/server/cms/contentMigration.ts +1119 -0
  363. package/template/server/cms/defaults.ts +303 -0
  364. package/template/server/cms/permissions.ts +154 -0
  365. package/template/server/cms/restoreClassicHome.ts +183 -0
  366. package/template/server/cms/revisions.ts +99 -0
  367. package/template/server/cms/scheduler.ts +78 -0
  368. package/template/server/cms/seed.ts +72 -0
  369. package/template/server/cms/seoAnalyzer.ts +213 -0
  370. package/template/server/cms/store.ts +122 -0
  371. package/template/server/cms/themeContent.ts +1386 -0
  372. package/template/server/cms/themePacks/sidibou-branding.json +1 -0
  373. package/template/server/cms/themePacks/sidibou-home.json +1 -0
  374. package/template/server/cms/themePacks/sidibou-menus.json +1 -0
  375. package/template/server/cms/types.ts +432 -0
  376. package/template/server/community/routes.ts +410 -0
  377. package/template/server/db/client.ts +43 -0
  378. package/template/server/db/repository.ts +389 -0
  379. package/template/server/db/schema.ts +726 -0
  380. package/template/server/demo/cmsReset.ts +196 -0
  381. package/template/server/developers/sdk.ts +85 -0
  382. package/template/server/geoip.ts +15 -0
  383. package/template/server/http.ts +53 -0
  384. package/template/server/mail.ts +216 -0
  385. package/template/server/marketplace/catalog.ts +74 -0
  386. package/template/server/marketplace/packageValidate.ts +475 -0
  387. package/template/server/marketplace/payments.ts +193 -0
  388. package/template/server/marketplace/routes.ts +850 -0
  389. package/template/server/marketplace/signing.ts +116 -0
  390. package/template/server/marketplace/syncOfficial.ts +282 -0
  391. package/template/server/media/images.ts +63 -0
  392. package/template/server/middleware/adminAuth.ts +134 -0
  393. package/template/server/modules/legacy.ts +44 -0
  394. package/template/server/modules/manager.ts +1122 -0
  395. package/template/server/modules/marketplace.ts +178 -0
  396. package/template/server/modules/outbound.ts +178 -0
  397. package/template/server/modules/purchases.ts +149 -0
  398. package/template/server/modules/records.ts +168 -0
  399. package/template/server/modules/themeHtml.ts +32 -0
  400. package/template/server/modules/trust.ts +16 -0
  401. package/template/server/modules/types.ts +147 -0
  402. package/template/server/platform/auth.ts +223 -0
  403. package/template/server/platform/clientWelcome.ts +168 -0
  404. package/template/server/platform/clients.ts +139 -0
  405. package/template/server/platform/dailyImprove.ts +356 -0
  406. package/template/server/platform/flouci.ts +126 -0
  407. package/template/server/platform/host.ts +69 -0
  408. package/template/server/platform/hostingProviders.ts +143 -0
  409. package/template/server/platform/licenseOrders.ts +291 -0
  410. package/template/server/platform/money.ts +42 -0
  411. package/template/server/platform/passwords.ts +41 -0
  412. package/template/server/platform/region.ts +86 -0
  413. package/template/server/platform/routes.ts +225 -0
  414. package/template/server/platform/seed.ts +82 -0
  415. package/template/server/platform/settings.ts +72 -0
  416. package/template/server/routes/adminAccount.ts +403 -0
  417. package/template/server/routes/adminCms.ts +808 -0
  418. package/template/server/routes/adminSystem.ts +243 -0
  419. package/template/server/routes/adminUsers.ts +449 -0
  420. package/template/server/routes/googleOAuth.ts +327 -0
  421. package/template/server/routes/modules.ts +323 -0
  422. package/template/server/routes/publicCms.ts +313 -0
  423. package/template/server/routes/seoPublic.ts +158 -0
  424. package/template/server/security/accounts.ts +121 -0
  425. package/template/server/security/audit.ts +143 -0
  426. package/template/server/security/authTokens.ts +74 -0
  427. package/template/server/security/ip.ts +68 -0
  428. package/template/server/security/rateLimit.ts +85 -0
  429. package/template/server/security/retention.ts +46 -0
  430. package/template/server/security/secrets.ts +44 -0
  431. package/template/server/security/sessions.ts +140 -0
  432. package/template/server/security/totp.ts +101 -0
  433. package/template/server/superadmin/analytics.ts +109 -0
  434. package/template/server/superadmin/auth.ts +92 -0
  435. package/template/server/superadmin/backlinksCatalog.ts +210 -0
  436. package/template/server/superadmin/frSeoContent.ts +165 -0
  437. package/template/server/superadmin/landingSeo.ts +675 -0
  438. package/template/server/superadmin/ops.ts +238 -0
  439. package/template/server/superadmin/routes.ts +1095 -0
  440. package/template/server/superadmin/tnSeoContent.ts +130 -0
  441. package/template/server.ts +522 -0
  442. package/template/src/App.tsx +263 -0
  443. package/template/src/admin/AdminApp.tsx +162 -0
  444. package/template/src/admin/account/AuthLayout.tsx +57 -0
  445. package/template/src/admin/account/SecurityForms.tsx +276 -0
  446. package/template/src/admin/admin.css +127 -0
  447. package/template/src/admin/context/AuthContext.tsx +147 -0
  448. package/template/src/admin/context/SiteContext.tsx +50 -0
  449. package/template/src/admin/editor/BlockLibrary.tsx +173 -0
  450. package/template/src/admin/editor/BlocksPanel.tsx +396 -0
  451. package/template/src/admin/editor/EditorBits.tsx +106 -0
  452. package/template/src/admin/editor/PreviewFrame.tsx +145 -0
  453. package/template/src/admin/editor/RichTextEditor.tsx +276 -0
  454. package/template/src/admin/editor/SeoPanel.tsx +349 -0
  455. package/template/src/admin/editor/StyleEditor.tsx +114 -0
  456. package/template/src/admin/editor/blockSchemas.ts +699 -0
  457. package/template/src/admin/editor/fields.tsx +486 -0
  458. package/template/src/admin/layout/AdminShell.tsx +418 -0
  459. package/template/src/admin/layout/nav.ts +95 -0
  460. package/template/src/admin/lib/api.ts +408 -0
  461. package/template/src/admin/lib/audit.ts +141 -0
  462. package/template/src/admin/lib/format.ts +84 -0
  463. package/template/src/admin/lib/hooks.ts +125 -0
  464. package/template/src/admin/main.tsx +16 -0
  465. package/template/src/admin/modules/InstallDialog.tsx +160 -0
  466. package/template/src/admin/modules/SettingsForm.tsx +145 -0
  467. package/template/src/admin/modules/kit.tsx +127 -0
  468. package/template/src/admin/modules/labels.tsx +226 -0
  469. package/template/src/admin/pages/AccountSetupPage.tsx +62 -0
  470. package/template/src/admin/pages/AnalyticsPage.tsx +206 -0
  471. package/template/src/admin/pages/BrandingPage.tsx +154 -0
  472. package/template/src/admin/pages/DashboardPage.tsx +239 -0
  473. package/template/src/admin/pages/EngagementPage.tsx +168 -0
  474. package/template/src/admin/pages/FormsPage.tsx +435 -0
  475. package/template/src/admin/pages/GeneralPage.tsx +120 -0
  476. package/template/src/admin/pages/LoginPage.tsx +249 -0
  477. package/template/src/admin/pages/MaintenancePage.tsx +125 -0
  478. package/template/src/admin/pages/MarketplacePage.tsx +426 -0
  479. package/template/src/admin/pages/MediaPage.tsx +251 -0
  480. package/template/src/admin/pages/MenusPage.tsx +446 -0
  481. package/template/src/admin/pages/ModuleAdminPage.tsx +113 -0
  482. package/template/src/admin/pages/ModuleDetailPage.tsx +293 -0
  483. package/template/src/admin/pages/ModulesPage.tsx +135 -0
  484. package/template/src/admin/pages/NewsletterPage.tsx +193 -0
  485. package/template/src/admin/pages/PageEditorPage.tsx +322 -0
  486. package/template/src/admin/pages/PagesListPage.tsx +277 -0
  487. package/template/src/admin/pages/PostEditorPage.tsx +292 -0
  488. package/template/src/admin/pages/PostsListPage.tsx +187 -0
  489. package/template/src/admin/pages/ProfilePage.tsx +489 -0
  490. package/template/src/admin/pages/ResetPasswordPage.tsx +110 -0
  491. package/template/src/admin/pages/SeoPage.tsx +670 -0
  492. package/template/src/admin/pages/SettingsPage.tsx +189 -0
  493. package/template/src/admin/pages/ThemeCustomizePage.tsx +170 -0
  494. package/template/src/admin/pages/ThemesPage.tsx +292 -0
  495. package/template/src/admin/pages/UsersPage.tsx +57 -0
  496. package/template/src/admin/pages/WidgetsPage.tsx +200 -0
  497. package/template/src/admin/seo/GoogleSetup.tsx +529 -0
  498. package/template/src/admin/settings/EmailTab.tsx +293 -0
  499. package/template/src/admin/settings/OtherTabs.tsx +270 -0
  500. package/template/src/admin/settings/SecurityTab.tsx +172 -0
  501. package/template/src/admin/settings/controls.tsx +133 -0
  502. package/template/src/admin/ui/Pagination.tsx +170 -0
  503. package/template/src/admin/ui/SaveBar.tsx +77 -0
  504. package/template/src/admin/ui/TagInput.tsx +54 -0
  505. package/template/src/admin/ui/charts.tsx +108 -0
  506. package/template/src/admin/ui/media.tsx +265 -0
  507. package/template/src/admin/ui/overlays.tsx +239 -0
  508. package/template/src/admin/ui/primitives.tsx +544 -0
  509. package/template/src/admin/users/AuditTab.tsx +104 -0
  510. package/template/src/admin/users/RolesTab.tsx +368 -0
  511. package/template/src/admin/users/UsersTab.tsx +723 -0
  512. package/template/src/admin/users/shared.tsx +278 -0
  513. package/template/src/cms/icons.ts +7 -0
  514. package/template/src/components/CookieBanner.tsx +166 -0
  515. package/template/src/components/MaintenanceGate.tsx +66 -0
  516. package/template/src/components/SiteAnalytics.tsx +64 -0
  517. package/template/src/components/SnapifyLogo.tsx +44 -0
  518. package/template/src/components/cms/BlockRenderer.tsx +154 -0
  519. package/template/src/components/cms/WidgetArea.tsx +193 -0
  520. package/template/src/context/SiteConfigContext.tsx +130 -0
  521. package/template/src/demoBase.ts +23 -0
  522. package/template/src/index.css +90 -0
  523. package/template/src/main.tsx +16 -0
  524. package/template/src/modules/ModuleHost.tsx +197 -0
  525. package/template/src/preview.ts +63 -0
  526. package/template/src/runtime.ts +38 -0
  527. package/template/src/themes/ThemeHost.tsx +168 -0
  528. package/template/src/themes/fallback.tsx +71 -0
  529. package/template/src/types.ts +94 -0
  530. package/template/src/views/BlogPostView.tsx +68 -0
  531. package/template/src/views/CmsPageView.tsx +34 -0
  532. package/template/start-pm2.sh +3 -0
  533. package/template/superadmin.html +20 -0
  534. package/template/themes/ai-canvas/screenshot.jpg +0 -0
  535. package/template/themes/ai-canvas/snapify.theme.json +96 -0
  536. package/template/themes/ai-canvas/src/CeeSimulator.tsx +247 -0
  537. package/template/themes/ai-canvas/src/Footer.tsx +190 -0
  538. package/template/themes/ai-canvas/src/Header.tsx +324 -0
  539. package/template/themes/ai-canvas/src/Layout.tsx +56 -0
  540. package/template/themes/ai-canvas/src/NotFound.tsx +58 -0
  541. package/template/themes/ai-canvas/src/Post.tsx +26 -0
  542. package/template/themes/ai-canvas/src/SnapifyLogo.tsx +44 -0
  543. package/template/themes/ai-canvas/src/blocks/CollectionBlocks.tsx +711 -0
  544. package/template/themes/ai-canvas/src/blocks/ContentBlocks.tsx +318 -0
  545. package/template/themes/ai-canvas/src/blocks/ConversionBlocks.tsx +559 -0
  546. package/template/themes/ai-canvas/src/blocks/HeaderBlocks.tsx +341 -0
  547. package/template/themes/ai-canvas/src/index.tsx +54 -0
  548. package/template/themes/ai-canvas/src/kit.tsx +398 -0
  549. package/template/themes/ai-canvas/src/site.ts +29 -0
  550. package/template/themes/ai-canvas/src/styles.css +317 -0
  551. package/template/themes/dogga/screenshot.jpg +0 -0
  552. package/template/themes/dogga/snapify.theme.json +55 -0
  553. package/template/themes/dogga/src/Brand.tsx +41 -0
  554. package/template/themes/dogga/src/Footer.tsx +202 -0
  555. package/template/themes/dogga/src/Header.tsx +239 -0
  556. package/template/themes/dogga/src/Layout.tsx +43 -0
  557. package/template/themes/dogga/src/Views.tsx +71 -0
  558. package/template/themes/dogga/src/blocks/CollectionBlocks.tsx +674 -0
  559. package/template/themes/dogga/src/blocks/ContentBlocks.tsx +307 -0
  560. package/template/themes/dogga/src/blocks/ConversionBlocks.tsx +571 -0
  561. package/template/themes/dogga/src/blocks/HeaderBlocks.tsx +289 -0
  562. package/template/themes/dogga/src/index.tsx +53 -0
  563. package/template/themes/dogga/src/kit.tsx +362 -0
  564. package/template/themes/dogga/src/site.ts +56 -0
  565. package/template/themes/dogga/src/styles.css +396 -0
  566. package/template/themes/mahdia/screenshot.jpg +0 -0
  567. package/template/themes/mahdia/snapify.theme.json +65 -0
  568. package/template/themes/mahdia/src/Brand.tsx +39 -0
  569. package/template/themes/mahdia/src/Footer.tsx +210 -0
  570. package/template/themes/mahdia/src/Header.tsx +291 -0
  571. package/template/themes/mahdia/src/Layout.tsx +44 -0
  572. package/template/themes/mahdia/src/Views.tsx +79 -0
  573. package/template/themes/mahdia/src/blocks/CollectionBlocks.tsx +674 -0
  574. package/template/themes/mahdia/src/blocks/ContentBlocks.tsx +307 -0
  575. package/template/themes/mahdia/src/blocks/ConversionBlocks.tsx +571 -0
  576. package/template/themes/mahdia/src/blocks/HeaderBlocks.tsx +289 -0
  577. package/template/themes/mahdia/src/index.tsx +53 -0
  578. package/template/themes/mahdia/src/kit.tsx +362 -0
  579. package/template/themes/mahdia/src/site.ts +75 -0
  580. package/template/themes/mahdia/src/styles.css +446 -0
  581. package/template/themes/preveris/screenshot.jpg +0 -0
  582. package/template/themes/preveris/snapify.theme.json +126 -0
  583. package/template/themes/preveris/src/Brand.tsx +44 -0
  584. package/template/themes/preveris/src/Footer.tsx +202 -0
  585. package/template/themes/preveris/src/Header.tsx +239 -0
  586. package/template/themes/preveris/src/Layout.tsx +42 -0
  587. package/template/themes/preveris/src/Views.tsx +71 -0
  588. package/template/themes/preveris/src/blocks/CollectionBlocks.tsx +678 -0
  589. package/template/themes/preveris/src/blocks/ContentBlocks.tsx +307 -0
  590. package/template/themes/preveris/src/blocks/ConversionBlocks.tsx +571 -0
  591. package/template/themes/preveris/src/blocks/HeaderBlocks.tsx +299 -0
  592. package/template/themes/preveris/src/index.tsx +53 -0
  593. package/template/themes/preveris/src/kit.tsx +365 -0
  594. package/template/themes/preveris/src/site.ts +79 -0
  595. package/template/themes/preveris/src/styles.css +446 -0
  596. package/template/themes/sidibou/screenshot.jpg +0 -0
  597. package/template/themes/sidibou/snapify.theme.json +21 -0
  598. package/template/themes/sidibou/src/CeeSimulator.tsx +247 -0
  599. package/template/themes/sidibou/src/Footer.tsx +203 -0
  600. package/template/themes/sidibou/src/Header.tsx +324 -0
  601. package/template/themes/sidibou/src/Layout.tsx +53 -0
  602. package/template/themes/sidibou/src/NotFound.tsx +58 -0
  603. package/template/themes/sidibou/src/Post.tsx +26 -0
  604. package/template/themes/sidibou/src/SnapifyLogo.tsx +44 -0
  605. package/template/themes/sidibou/src/blocks/CollectionBlocks.tsx +711 -0
  606. package/template/themes/sidibou/src/blocks/ContentBlocks.tsx +318 -0
  607. package/template/themes/sidibou/src/blocks/ConversionBlocks.tsx +559 -0
  608. package/template/themes/sidibou/src/blocks/HeaderBlocks.tsx +341 -0
  609. package/template/themes/sidibou/src/index.tsx +54 -0
  610. package/template/themes/sidibou/src/kit.tsx +398 -0
  611. package/template/themes/sidibou/src/site.ts +28 -0
  612. package/template/themes/sidibou/src/styles.css +317 -0
  613. package/template/tsconfig.json +33 -0
  614. package/template/vite.config.ts +42 -0
@@ -0,0 +1,121 @@
1
+ {
2
+ "id": "novalabs.whatsapp",
3
+ "name": "WhatsApp",
4
+ "version": "1.0.1",
5
+ "description": "Bouton flottant qui ouvre une conversation WhatsApp avec un message pré-rempli. Position, pages et appareils configurables.",
6
+ "author": {
7
+ "name": "NOVALABS WEB DESIGN",
8
+ "email": "contact@novalabs.tn",
9
+ "url": "https://novalabs.tn"
10
+ },
11
+ "pricing": "free",
12
+ "category": "Contact",
13
+ "icon": "message-circle",
14
+ "engines": {
15
+ "snapify": "^1.0.0"
16
+ },
17
+ "permissions": [],
18
+ "slots": [
19
+ "floating"
20
+ ],
21
+ "entries": {
22
+ "public": "src/public.tsx"
23
+ },
24
+ "settings": [
25
+ {
26
+ "key": "number",
27
+ "type": "phone",
28
+ "group": "Conversation",
29
+ "label": "Numéro WhatsApp",
30
+ "help": "Format international, ex. +216 24 734 647. Vide : le téléphone des informations générales du site.",
31
+ "default": "",
32
+ "public": true,
33
+ "maxLength": 30,
34
+ "placeholder": "+216 24 734 647"
35
+ },
36
+ {
37
+ "key": "defaultMessage",
38
+ "type": "textarea",
39
+ "group": "Conversation",
40
+ "label": "Message pré-rempli",
41
+ "help": "Texte proposé au visiteur à l’ouverture de WhatsApp.",
42
+ "default": "Bonjour, je souhaite avoir plus d’informations.",
43
+ "public": true,
44
+ "maxLength": 500,
45
+ "rows": 2
46
+ },
47
+ {
48
+ "key": "title",
49
+ "type": "text",
50
+ "group": "Fenêtre",
51
+ "label": "Titre",
52
+ "default": "Discutons sur WhatsApp",
53
+ "public": true,
54
+ "maxLength": 60
55
+ },
56
+ {
57
+ "key": "greeting",
58
+ "type": "textarea",
59
+ "group": "Fenêtre",
60
+ "label": "Message d’accueil",
61
+ "default": "👋 Bonjour ! Une question ? Écrivez-nous, nous vous répondons rapidement.",
62
+ "public": true,
63
+ "maxLength": 300,
64
+ "rows": 2
65
+ },
66
+ {
67
+ "key": "tooltip",
68
+ "type": "text",
69
+ "group": "Fenêtre",
70
+ "label": "Info-bulle (ordinateur)",
71
+ "help": "Vide : pas d’info-bulle.",
72
+ "default": "Besoin d’aide ?",
73
+ "public": true,
74
+ "maxLength": 40
75
+ },
76
+ {
77
+ "key": "position",
78
+ "type": "select",
79
+ "group": "Affichage",
80
+ "label": "Position",
81
+ "default": "bottom-right",
82
+ "public": true,
83
+ "options": [
84
+ {
85
+ "value": "bottom-right",
86
+ "label": "En bas à droite"
87
+ },
88
+ {
89
+ "value": "bottom-left",
90
+ "label": "En bas à gauche"
91
+ }
92
+ ]
93
+ },
94
+ {
95
+ "key": "showOnDesktop",
96
+ "type": "boolean",
97
+ "group": "Affichage",
98
+ "label": "Afficher sur ordinateur",
99
+ "default": true,
100
+ "public": true
101
+ },
102
+ {
103
+ "key": "showOnMobile",
104
+ "type": "boolean",
105
+ "group": "Affichage",
106
+ "label": "Afficher sur mobile",
107
+ "default": true,
108
+ "public": true
109
+ },
110
+ {
111
+ "key": "showOnPages",
112
+ "type": "paths",
113
+ "group": "Affichage",
114
+ "label": "Pages concernées",
115
+ "help": "Vide : toutes les pages. Une adresse terminée par * inclut ses sous-pages (ex. /blog/*).",
116
+ "default": [],
117
+ "public": true
118
+ }
119
+ ],
120
+ "screenshot": "screenshot.jpg"
121
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Snapify — module WhatsApp
3
+ * © 2026 NOVALABS WEB DESIGN — Tunisie
4
+ * Contact : contact@novalabs.tn · +216 24 734 647
5
+ * Tous droits réservés. Toute reproduction, modification ou diffusion sans autorisation écrite est interdite.
6
+ */
7
+ import { useState } from 'react';
8
+ import { MessageCircle, Send, X } from 'lucide-react';
9
+ import { definePublicModule, matchesPaths, type PublicModuleProps } from '@snapify/sdk';
10
+
11
+ interface Settings {
12
+ number: string;
13
+ defaultMessage: string;
14
+ title: string;
15
+ greeting: string;
16
+ tooltip: string;
17
+ position: 'bottom-right' | 'bottom-left';
18
+ showOnDesktop: boolean;
19
+ showOnMobile: boolean;
20
+ showOnPages: string[];
21
+ }
22
+
23
+ function WhatsAppWidget({ settings, site, path }: PublicModuleProps<Settings>) {
24
+ const [open, setOpen] = useState(false);
25
+ const [message, setMessage] = useState(settings.defaultMessage);
26
+
27
+ if (!matchesPaths(settings.showOnPages, path)) return null;
28
+ if (!settings.showOnMobile && !settings.showOnDesktop) return null;
29
+ const phone = (settings.number || site.phoneClean).replace(/\D/g, '');
30
+ if (phone.length < 8) return null;
31
+
32
+ const side = settings.position === 'bottom-left' ? 'left-5' : 'right-5';
33
+ const visibility = !settings.showOnMobile ? 'hidden lg:flex' : !settings.showOnDesktop ? 'flex lg:hidden' : 'flex';
34
+
35
+ const send = () => {
36
+ window.open(`https://wa.me/${phone}?text=${encodeURIComponent(message)}`, '_blank', 'noopener,noreferrer');
37
+ setOpen(false);
38
+ };
39
+
40
+ return (
41
+ <>
42
+ <div className={`fixed bottom-20 lg:bottom-6 ${side} z-40 ${visibility} items-center gap-2`}>
43
+ {settings.tooltip ? (
44
+ <div className="pointer-events-none hidden rounded-full border border-slate-200 bg-white/95 px-3 py-1.5 text-xs font-semibold text-px-navy shadow-lg xl:block">
45
+ {settings.tooltip}
46
+ </div>
47
+ ) : null}
48
+ <button
49
+ type="button"
50
+ onClick={() => setOpen(!open)}
51
+ aria-label={`Contacter ${site.name} sur WhatsApp`}
52
+ className="relative flex h-14 w-14 items-center justify-center rounded-full bg-[#25D366] text-white shadow-xl transition-all duration-200 hover:scale-105 hover:bg-[#20bd5a] active:scale-95"
53
+ >
54
+ <span className="pointer-events-none absolute -inset-1 animate-ping rounded-full bg-[#25D366] opacity-30" />
55
+ <svg viewBox="0 0 24 24" className="h-7 w-7 fill-current" aria-hidden="true">
56
+ <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.885-9.885 9.885m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z" />
57
+ </svg>
58
+ </button>
59
+ </div>
60
+
61
+ {open ? (
62
+ <div className={`fixed bottom-24 ${side} z-50 w-[90vw] max-w-sm overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-2xl`}>
63
+ <div className="flex items-center justify-between border-b border-slate-800 bg-px-navy p-4 text-white">
64
+ <div className="flex items-center gap-3">
65
+ <div className="flex h-10 w-10 items-center justify-center rounded-full bg-[#25D366] text-white">
66
+ <MessageCircle className="h-5 w-5" />
67
+ </div>
68
+ <div>
69
+ <div className="text-sm font-semibold text-white">{settings.title}</div>
70
+ {site.slaHours ? (
71
+ <div className="flex items-center gap-1.5 text-[11px] text-px-primary-light">
72
+ <span className="h-2 w-2 animate-pulse rounded-full bg-px-primary-light" />
73
+ <span>{site.slaHours}</span>
74
+ </div>
75
+ ) : null}
76
+ </div>
77
+ </div>
78
+ <button type="button" onClick={() => setOpen(false)} aria-label="Fermer" className="rounded-full p-1 text-slate-400 hover:text-white">
79
+ <X className="h-5 w-5" />
80
+ </button>
81
+ </div>
82
+
83
+ <div className="space-y-3 bg-px-surface p-4">
84
+ {settings.greeting ? (
85
+ <div className="rounded-2xl rounded-tl-xs border border-slate-200 bg-white p-3 text-xs leading-relaxed text-slate-700 shadow-xs">{settings.greeting}</div>
86
+ ) : null}
87
+ <div className="space-y-1">
88
+ <label htmlFor="snapify-wa-message" className="block text-[11px] font-semibold uppercase tracking-wider text-slate-500">
89
+ Votre message
90
+ </label>
91
+ <textarea
92
+ id="snapify-wa-message"
93
+ rows={3}
94
+ value={message}
95
+ onChange={(e) => setMessage(e.target.value)}
96
+ className="w-full resize-none rounded-xl border border-slate-300 bg-white p-3 text-xs text-slate-800 focus:border-[#25D366] focus:outline-hidden"
97
+ />
98
+ </div>
99
+ <button
100
+ type="button"
101
+ onClick={send}
102
+ className="flex w-full items-center justify-center gap-2 rounded-full bg-[#25D366] px-4 py-2.5 text-xs font-semibold text-white shadow-sm transition-colors hover:bg-[#20bd5a]"
103
+ >
104
+ <span>Ouvrir dans WhatsApp</span>
105
+ <Send className="h-3.5 w-3.5" />
106
+ </button>
107
+ {site.phone ? (
108
+ <div className="text-center text-[10px] text-slate-400">
109
+ Ligne directe : <span className="font-mono text-slate-600">{site.phone}</span>
110
+ </div>
111
+ ) : null}
112
+ </div>
113
+ </div>
114
+ ) : null}
115
+ </>
116
+ );
117
+ }
118
+
119
+ export default definePublicModule<Settings>({ slots: { floating: WhatsAppWidget } });
@@ -0,0 +1,113 @@
1
+ # WP SEO Migrator — Plan d’architecture (étape 1)
2
+
3
+ **Module** : `hamdiayari.wp-seo-migrator`
4
+ **Auteur marketplace** : Hamdi Ayari
5
+ **API Snapify cible** : `^1.3.0`
6
+ **Doc lue** : https://developers.snapify.fr/ (+ `docs/MODULES.md`, `@snapify/sdk`, modules de référence `ai-articles`, `calendar`, `ai-chat`)
7
+
8
+ ---
9
+
10
+ ## 1. Objectif produit
11
+
12
+ Assistant « migration SEO WordPress → Snapify » en 4 écrans, public non technique, dry-run, reprise, rapport, surveillance 30 j.
13
+
14
+ ## 2. Points de la doc Snapify utilisés
15
+
16
+ | Besoin | Doc / API | Réf. |
17
+ | --- | --- | --- |
18
+ | Manifeste, permissions, `adminPages`, `entries.admin` | Guide modules / manifeste | `docs/MODULES.md` §2 ; developers `/docs/modules/manifeste` |
19
+ | `defineServerModule`, `ctx.admin.*`, `ctx.db`, `ctx.storage`, `ctx.lock`, `ctx.files`, `ctx.mail`, `ctx.fetch`+`net:hôte` | Contexte serveur | developers `/docs/modules/serveur` ; `sdk/index.ts` `ServerContext` |
20
+ | `defineAdminModule` + kit UI | Admin modules | `@snapify/sdk/admin` ; ex. `modules/ai-articles` |
21
+ | Collections JSON (256 Ko/doc) | Base de données modules | `/docs/modules/base-de-donnees` |
22
+ | Background « jobs » | **Pas d’API jobs** — pattern `setInterval` + cleanup au deactivate | Exemple doc serveur (`setInterval` / `clearInterval`) |
23
+ | SEO natif Snapify | `SeoMeta` pages/posts + `redirects` | `server/cms/types.ts` ; admin `PUT /api/admin/pages/:id`, `PUT /api/admin/redirects` |
24
+ | Paquet `.snapmod`, signature, marketplace | Paquets / publier | `/docs/paquets`, `/docs/publier` |
25
+
26
+ ## 3. Architecture module
27
+
28
+ ```
29
+ modules/wp-seo-migrator/
30
+ ├── snapify.module.json
31
+ ├── ARCHITECTURE.md ← ce plan
32
+ ├── README.md
33
+ ├── wp-plugin/ ← Snapify Exporter (PHP) téléchargeable
34
+ ├── fixtures/ ← Yoast, Rank Math, WXR, redirections
35
+ ├── src/
36
+ │ ├── types.ts ← SeoRecord normalisé + SeoConnector
37
+ │ ├── i18n/ ← fr / en / ar (RTL)
38
+ │ ├── connectors/ ← interface + Yoast, RankMath, WXR, Redirection, Exporter, CSV
39
+ │ ├── pipeline/ ← merge, score, redirects, apply-plan, report
40
+ │ ├── server.ts ← admin routes + worker setInterval
41
+ │ └── admin/ ← 4 écrans (wizard)
42
+ └── tests/
43
+ ```
44
+
45
+ ### Flux MVP
46
+
47
+ 1. **Connexion** — URL affichée pour contexte + upload (Exporter / WXR / CSV). Options avancées repliées.
48
+ 2. **Analyse** — connecteurs détectés, compteurs lisibles, score de couverture.
49
+ 3. **Aperçu** — problèmes en langage simple, avant/après 5 pages, tout pré-coché, mode Expert masqué.
50
+ 4. **Migration** — job en base (`migrations` + `migration_items`), worker `setInterval`, progression, annulation, rapport CSV.
51
+
52
+ ### Fusion multi-connecteurs
53
+
54
+ `SeoConnector` déclare `fields[]` + `detect()` + `extract()`.
55
+ Merge par champ : source la plus riche d’abord ; chaque valeur garde `sources[field]=connectorId`.
56
+
57
+ ### Application dans Snapify (repli documenté)
58
+
59
+ Le SDK **n’expose pas** d’API pour écrire pages/SEO/redirections CMS.
60
+ **Repli MVP** : le serveur produit un *apply plan* ; l’UI admin (session déjà authentifiée, mêmes cookies) appelle les routes host documentées :
61
+
62
+ - `GET/PUT /api/admin/pages` / `PUT /api/admin/pages/:id` (seo)
63
+ - `GET` pages+posts puis `PUT /api/admin/redirects`
64
+
65
+ Nécessite les droits `seo.edit` (et `pages.edit` si création de pages — hors MVP : on ne crée pas de contenu, on mappe le SEO sur les chemins existants + redirections 301).
66
+
67
+ ## 4. Lacunes doc / SDK (explicites) + replis
68
+
69
+ | Lacune | Impact | Repli choisi |
70
+ | --- | --- | --- |
71
+ | ~~Pas de `net:*` dynamique~~ | ~~Impossible d’appeler un WP arbitraire~~ | **Résolu (1.2)** : permissions core `net:outbound` (HTTP(S) anti-SSRF) + `net:ftp` (`ctx.ftp`). Analyse auto URL-first ; fichiers = expert uniquement. |
72
+ | Pas d’API jobs / queue | Migrations longues | `setInterval` + `ctx.lock` + collections `migrations` / `items` ; reprise au redémarrage |
73
+ | Pas de `ctx.cms` / écriture SEO | Appliquer title/meta/canonical/redirects | Apply plan + appels `/api/admin/*` depuis l’UI admin (session) |
74
+ | Pas de GSC/GA OAuth module | Priorisation trafic | Option CSV GSC upload (MVP partiel) ; OAuth v2 |
75
+ | Schema JSON-LD riche limité dans `SeoMeta` | Snapify : `schemaType` enum simple | Stocker JSON-LD brut dans meta module + mapper `schemaType` au plus proche ; rapport « schema avancé à revérifier » |
76
+ | Surveillance 404 / trafic 30 j | Pas d’API analytics module complète | Collection `watch_hits` + lecture basique via routes admin ; alertes mail `mail:send` si SMTP configuré |
77
+ | PDF rapport | Pas de PDF dans SDK | CSV + HTML téléchargeable (PDF v2) |
78
+ | i18n admin RTL | Kit admin non i18né | Dictionnaires fr/en/ar dans le module + `dir=rtl` pour ar |
79
+
80
+ ## 5. Permissions manifeste (minimales)
81
+
82
+ `admin:routes`, `database`, `storage`, `files`, `mail:send`, `site:read`
83
+ Pas de `net:` en MVP (fichier-first).
84
+ Pas de `http:routes` public (tout passe par admin).
85
+
86
+ ## 6. Sécurité
87
+
88
+ - Identifiants WP (si saisis en expert) : chiffrés via secret dérivé `storage` + purge après job (`credentialsClearedAt`).
89
+ - Uploads : types MIME/extensions allowlist, taille max, parse sandbox.
90
+ - Sanitize XSS dans title/meta/JSON-LD avant écriture.
91
+ - Apply non destructif : dry-run par défaut ; confirmation avant écriture ; bouton Annuler.
92
+
93
+ ## 7. Livré / reste
94
+
95
+ **MVP 1.0.0** (publié marketplace, éditeur Hamdi Ayari) : WXR + Yoast CSV + Rank Math CSV + Redirection + Exporter JSON + 4 écrans + worker + apply SEO/redirects + rapport + tests.
96
+
97
+ **1.1.0** : AIOSEO / SEOPress / TSF / Slim SEO CSV ; Screaming Frog / Semrush / Ahrefs CSV ; `.htaccess` / nginx ; sitemap XML ; GSC CSV (priorisation) ; HTML rendu (secours) ; gabarit `CUSTOM_CONNECTOR.md` + `createCsvSeoConnector`.
98
+
99
+ **Reste (roadmap v2)** : Squirrly / SmartCrawl / Platinum / builders Divi·Elementor meta natives ; Safe Redirect Manager REST ; WPML / Polylang / Weglot hreflang riches ; WooCommerce marques/GTIN ; ACF/Schema Pro ; crawl live + REST Application Password (`net:outbound` core) ; GSC OAuth ; PDF ; MySQL lecture seule.
100
+
101
+ ### Correctif build SDK (publication)
102
+
103
+ Rolldown embarquait React (+ `process.env`) dans `server.mjs` via le re-export `recaptcha` de `@snapify/sdk`. Correctifs : type `ComponentType` local dans `sdk/index.ts`, reCAPTCHA via `@snapify/sdk/recaptcha`, garde-fou build serveur.
104
+
105
+ ## 8. Questions ouvertes (produit)
106
+
107
+ 1. Pages absentes dans Snapify : brouillons SEO vs 301 uniquement ?
108
+ 2. Tarification marketplace : rester `free` ?
109
+ 3. Priorité v2 : live WP (`net:outbound`) ou connecteurs multilingue / Woo ?
110
+
111
+ ---
112
+
113
+ *Statut : 1.1.0 — connecteurs A/B/F étendus ; C/D/E riches et live net en v2.*
@@ -0,0 +1,21 @@
1
+ # WP SEO Migrator (`hamdiayari.wp-seo-migrator`)
2
+
3
+ Assistant **1 clic** : collez l’adresse WordPress → analyse SEO automatique (pas de WXR à importer).
4
+
5
+ ## Pour l’utilisateur
6
+
7
+ 1. **Adresse du site** + **Analyser**
8
+ 2. L’assistant lit : page d’accueil, REST WordPress, sitemaps, crawl des URLs, éventuellement FTP
9
+ 3. Aperçu → **Migrer mon SEO**
10
+
11
+ ### Options avancées (si besoin)
12
+
13
+ - Mot de passe d’application WordPress (REST plus riche)
14
+ - FTP / FTPS (`.htaccess`, exports sur disque)
15
+ - Mode expert : fichier d’export (dernier recours)
16
+
17
+ ## Technique
18
+
19
+ Permissions : `net:outbound` (HTTP(S) anti-SSRF) + `net:ftp` (`ctx.ftp` côté hôte).
20
+
21
+ Voir [ARCHITECTURE.md](./ARCHITECTURE.md).
@@ -0,0 +1,3 @@
1
+ URL,Title,Description,Keyphrases,Canonical
2
+ https://exemple.fr/a-propos/,À propos | Exemple,Notre histoire et notre équipe,à propos,https://exemple.fr/a-propos/
3
+ https://exemple.fr/contact/,Contact,Écrivez-nous,contact,https://exemple.fr/contact/
@@ -0,0 +1,39 @@
1
+ {
2
+ "format": "snapify-wp-seo/1",
3
+ "site": { "url": "https://demo-wp.example/" },
4
+ "plugins": [
5
+ { "id": "wordpress-seo", "name": "Yoast SEO", "active": true },
6
+ { "id": "seo-by-rank-math", "name": "Rank Math", "active": false }
7
+ ],
8
+ "records": [
9
+ {
10
+ "id": "1",
11
+ "kind": "page",
12
+ "url": "https://demo-wp.example/",
13
+ "path": "/",
14
+ "slug": "home",
15
+ "status": "publish",
16
+ "title": "Accueil",
17
+ "seoTitle": "Boutique démo — Accueil",
18
+ "metaDescription": "Bienvenue sur notre boutique démo WordPress migrée vers Snapify.",
19
+ "focusKeyphrase": "boutique démo",
20
+ "canonicalUrl": "https://demo-wp.example/",
21
+ "sources": { "seoTitle": "yoast", "metaDescription": "yoast" }
22
+ },
23
+ {
24
+ "id": "2",
25
+ "kind": "post",
26
+ "url": "https://demo-wp.example/blog/bonjour/",
27
+ "path": "/blog/bonjour",
28
+ "slug": "bonjour",
29
+ "status": "publish",
30
+ "title": "Bonjour",
31
+ "seoTitle": "Bonjour le monde",
32
+ "metaDescription": "Premier article de blog.",
33
+ "sources": { "seoTitle": "yoast" }
34
+ }
35
+ ],
36
+ "redirects": [
37
+ { "from": "/ancienne-page/", "to": "/", "permanent": true }
38
+ ]
39
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <title>Accueil — Exemple</title>
5
+ <meta name="description" content="Bienvenue sur le site exemple." />
6
+ <link rel="canonical" href="https://exemple.fr/" />
7
+ <meta property="og:title" content="Accueil OG" />
8
+ <meta property="og:description" content="Desc OG" />
9
+ <script type="application/ld+json">{"@type":"Organization","name":"Exemple"}</script>
10
+ </head>
11
+ <body><h1>Accueil</h1><img src="/logo.png" alt="Logo Exemple" /></body>
12
+ </html>
@@ -0,0 +1,3 @@
1
+ RewriteEngine On
2
+ Redirect 301 /ancien-blog/ /blog/
3
+ RewriteRule ^promo-ete$ /offres/ [R=301,L]
@@ -0,0 +1,87 @@
1
+ {
2
+ "id": "hamdiayari.wp-seo-migrator",
3
+ "name": "WP SEO Migrator",
4
+ "version": "1.2.4",
5
+ "description": "Migrez le référencement WordPress vers Snapify en 1 clic : saisissez l’adresse du site, l’assistant lit titres, meta et redirections automatiquement (REST, sitemap, crawl). Option FTP. Sans jargon.",
6
+ "author": {
7
+ "name": "Hamdi Ayari",
8
+ "email": "hamdi.ayari@novalabs.tn",
9
+ "url": "https://novalabs.tn"
10
+ },
11
+ "pricing": "free",
12
+ "category": "SEO",
13
+ "icon": "search",
14
+ "engines": {
15
+ "snapify": "^1.3.0"
16
+ },
17
+ "permissions": [
18
+ "admin:routes",
19
+ "database",
20
+ "storage",
21
+ "files",
22
+ "mail:send",
23
+ "site:read",
24
+ "net:outbound",
25
+ "net:ftp"
26
+ ],
27
+ "slots": [],
28
+ "entries": {
29
+ "server": "src/server.ts",
30
+ "admin": "src/admin/index.tsx"
31
+ },
32
+ "adminPages": [
33
+ {
34
+ "id": "wizard",
35
+ "label": "Migrer le SEO",
36
+ "icon": "search"
37
+ },
38
+ {
39
+ "id": "history",
40
+ "label": "Historique",
41
+ "icon": "chart-bar"
42
+ }
43
+ ],
44
+ "settings": [
45
+ {
46
+ "key": "uiLang",
47
+ "type": "select",
48
+ "group": "Interface",
49
+ "label": "Langue de l’assistant",
50
+ "default": "fr",
51
+ "options": [
52
+ {
53
+ "value": "fr",
54
+ "label": "Français"
55
+ },
56
+ {
57
+ "value": "en",
58
+ "label": "English"
59
+ },
60
+ {
61
+ "value": "ar",
62
+ "label": "العربية"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "key": "watchDays",
68
+ "type": "number",
69
+ "group": "Après migration",
70
+ "label": "Jours de surveillance des 404",
71
+ "help": "Alertes simples si d’anciennes URL renvoient une erreur.",
72
+ "default": 30,
73
+ "min": 0,
74
+ "max": 90
75
+ },
76
+ {
77
+ "key": "notifyEmail",
78
+ "type": "text",
79
+ "group": "Après migration",
80
+ "label": "E-mail de notification",
81
+ "help": "Vide = e-mail du site. Utilisé à la fin de la migration.",
82
+ "default": "",
83
+ "maxLength": 200
84
+ }
85
+ ],
86
+ "screenshot": "screenshot.jpg"
87
+ }
@@ -0,0 +1,64 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { Button, Card, EmptyState, PageHeader, PageSkeleton, errorMessage, toast, type AdminPageProps } from '@snapify/sdk/admin';
3
+ import type { MigrationJob, Settings } from '../types';
4
+
5
+ export function HistoryPage({ api, navigate }: AdminPageProps<Settings>) {
6
+ const [items, setItems] = useState<MigrationJob[] | null>(null);
7
+
8
+ useEffect(() => {
9
+ void api
10
+ .get<{ items: MigrationJob[] }>('/jobs')
11
+ .then((r) => setItems(r.items))
12
+ .catch((e) => toast.error(errorMessage(e)));
13
+ }, [api]);
14
+
15
+ if (!items) return <PageSkeleton />;
16
+
17
+ return (
18
+ <div className="space-y-6">
19
+ <PageHeader
20
+ title="Historique des migrations"
21
+ description="Reprenez une migration ou téléchargez un rapport."
22
+ actions={
23
+ <Button onClick={() => navigate('/m/hamdiayari.wp-seo-migrator/wizard', { absolute: true })}>
24
+ Nouvelle migration
25
+ </Button>
26
+ }
27
+ />
28
+ {!items.length ? (
29
+ <EmptyState title="Aucune migration" description="Lancez l’assistant pour analyser un export WordPress." />
30
+ ) : (
31
+ <div className="space-y-3">
32
+ {items.map((j) => (
33
+ <Card key={j.id} className="flex flex-wrap items-center justify-between gap-3 p-4">
34
+ <div>
35
+ <div className="font-semibold">{j.siteUrl}</div>
36
+ <div className="text-sm text-slate-500">
37
+ {j.status} · {j.stats.coveragePct} % · {new Date(j.createdAt).toLocaleString('fr-TN')}
38
+ </div>
39
+ </div>
40
+ <Button
41
+ size="sm"
42
+ variant="secondary"
43
+ onClick={async () => {
44
+ try {
45
+ const r = await api.get<{ filename: string; csv: string }>(`/jobs/${j.id}/report`);
46
+ const blob = new Blob([r.csv], { type: 'text/csv' });
47
+ const a = document.createElement('a');
48
+ a.href = URL.createObjectURL(blob);
49
+ a.download = r.filename;
50
+ a.click();
51
+ } catch (e) {
52
+ toast.error(errorMessage(e));
53
+ }
54
+ }}
55
+ >
56
+ Rapport CSV
57
+ </Button>
58
+ </Card>
59
+ ))}
60
+ </div>
61
+ )}
62
+ </div>
63
+ );
64
+ }