realtimex-crm 0.1.2

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 (468) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +104 -0
  3. package/dist/assets/DealList-DqDrFeDV.js +59 -0
  4. package/dist/assets/DealList-DqDrFeDV.js.map +1 -0
  5. package/dist/assets/index-BiQoGq1P.css +1 -0
  6. package/dist/assets/index-CDIy4x-0.js +152 -0
  7. package/dist/assets/index-CDIy4x-0.js.map +1 -0
  8. package/dist/auth-callback.html +140 -0
  9. package/dist/favicon.ico +0 -0
  10. package/dist/img/adding-users.png +0 -0
  11. package/dist/img/empty.svg +42 -0
  12. package/dist/index.html +1 -0
  13. package/dist/logo192.png +0 -0
  14. package/dist/logo512.png +0 -0
  15. package/dist/logos/0.png +0 -0
  16. package/dist/logos/1.png +0 -0
  17. package/dist/logos/10.png +0 -0
  18. package/dist/logos/11.png +0 -0
  19. package/dist/logos/12.png +0 -0
  20. package/dist/logos/13.png +0 -0
  21. package/dist/logos/14.png +0 -0
  22. package/dist/logos/15.png +0 -0
  23. package/dist/logos/16.png +0 -0
  24. package/dist/logos/17.png +0 -0
  25. package/dist/logos/18.png +0 -0
  26. package/dist/logos/19.png +0 -0
  27. package/dist/logos/2.png +0 -0
  28. package/dist/logos/20.png +0 -0
  29. package/dist/logos/21.png +0 -0
  30. package/dist/logos/22.png +0 -0
  31. package/dist/logos/23.png +0 -0
  32. package/dist/logos/24.png +0 -0
  33. package/dist/logos/25.png +0 -0
  34. package/dist/logos/26.png +0 -0
  35. package/dist/logos/27.png +0 -0
  36. package/dist/logos/28.png +0 -0
  37. package/dist/logos/29.png +0 -0
  38. package/dist/logos/3.png +0 -0
  39. package/dist/logos/30.png +0 -0
  40. package/dist/logos/31.png +0 -0
  41. package/dist/logos/32.png +0 -0
  42. package/dist/logos/33.png +0 -0
  43. package/dist/logos/34.png +0 -0
  44. package/dist/logos/35.png +0 -0
  45. package/dist/logos/36.png +0 -0
  46. package/dist/logos/37.png +0 -0
  47. package/dist/logos/38.png +0 -0
  48. package/dist/logos/39.png +0 -0
  49. package/dist/logos/4.png +0 -0
  50. package/dist/logos/40.png +0 -0
  51. package/dist/logos/41.png +0 -0
  52. package/dist/logos/42.png +0 -0
  53. package/dist/logos/43.png +0 -0
  54. package/dist/logos/44.png +0 -0
  55. package/dist/logos/45.png +0 -0
  56. package/dist/logos/46.png +0 -0
  57. package/dist/logos/47.png +0 -0
  58. package/dist/logos/48.png +0 -0
  59. package/dist/logos/49.png +0 -0
  60. package/dist/logos/5.png +0 -0
  61. package/dist/logos/50.png +0 -0
  62. package/dist/logos/51.png +0 -0
  63. package/dist/logos/52.png +0 -0
  64. package/dist/logos/53.png +0 -0
  65. package/dist/logos/54.png +0 -0
  66. package/dist/logos/55.png +0 -0
  67. package/dist/logos/6.png +0 -0
  68. package/dist/logos/7.png +0 -0
  69. package/dist/logos/8.png +0 -0
  70. package/dist/logos/9.png +0 -0
  71. package/dist/logos/Readme.md +1 -0
  72. package/dist/logos/logo_atomic_crm.svg +14 -0
  73. package/dist/logos/logo_atomic_crm_dark.svg +14 -0
  74. package/dist/logos/logo_atomic_crm_light.svg +14 -0
  75. package/dist/manifest.json +25 -0
  76. package/dist/robots.txt +3 -0
  77. package/dist/stats.html +4949 -0
  78. package/package.json +152 -0
  79. package/public/auth-callback.html +140 -0
  80. package/public/favicon.ico +0 -0
  81. package/public/img/adding-users.png +0 -0
  82. package/public/img/empty.svg +42 -0
  83. package/public/logo192.png +0 -0
  84. package/public/logo512.png +0 -0
  85. package/public/logos/0.png +0 -0
  86. package/public/logos/1.png +0 -0
  87. package/public/logos/10.png +0 -0
  88. package/public/logos/11.png +0 -0
  89. package/public/logos/12.png +0 -0
  90. package/public/logos/13.png +0 -0
  91. package/public/logos/14.png +0 -0
  92. package/public/logos/15.png +0 -0
  93. package/public/logos/16.png +0 -0
  94. package/public/logos/17.png +0 -0
  95. package/public/logos/18.png +0 -0
  96. package/public/logos/19.png +0 -0
  97. package/public/logos/2.png +0 -0
  98. package/public/logos/20.png +0 -0
  99. package/public/logos/21.png +0 -0
  100. package/public/logos/22.png +0 -0
  101. package/public/logos/23.png +0 -0
  102. package/public/logos/24.png +0 -0
  103. package/public/logos/25.png +0 -0
  104. package/public/logos/26.png +0 -0
  105. package/public/logos/27.png +0 -0
  106. package/public/logos/28.png +0 -0
  107. package/public/logos/29.png +0 -0
  108. package/public/logos/3.png +0 -0
  109. package/public/logos/30.png +0 -0
  110. package/public/logos/31.png +0 -0
  111. package/public/logos/32.png +0 -0
  112. package/public/logos/33.png +0 -0
  113. package/public/logos/34.png +0 -0
  114. package/public/logos/35.png +0 -0
  115. package/public/logos/36.png +0 -0
  116. package/public/logos/37.png +0 -0
  117. package/public/logos/38.png +0 -0
  118. package/public/logos/39.png +0 -0
  119. package/public/logos/4.png +0 -0
  120. package/public/logos/40.png +0 -0
  121. package/public/logos/41.png +0 -0
  122. package/public/logos/42.png +0 -0
  123. package/public/logos/43.png +0 -0
  124. package/public/logos/44.png +0 -0
  125. package/public/logos/45.png +0 -0
  126. package/public/logos/46.png +0 -0
  127. package/public/logos/47.png +0 -0
  128. package/public/logos/48.png +0 -0
  129. package/public/logos/49.png +0 -0
  130. package/public/logos/5.png +0 -0
  131. package/public/logos/50.png +0 -0
  132. package/public/logos/51.png +0 -0
  133. package/public/logos/52.png +0 -0
  134. package/public/logos/53.png +0 -0
  135. package/public/logos/54.png +0 -0
  136. package/public/logos/55.png +0 -0
  137. package/public/logos/6.png +0 -0
  138. package/public/logos/7.png +0 -0
  139. package/public/logos/8.png +0 -0
  140. package/public/logos/9.png +0 -0
  141. package/public/logos/Readme.md +1 -0
  142. package/public/logos/logo_atomic_crm.svg +14 -0
  143. package/public/logos/logo_atomic_crm_dark.svg +14 -0
  144. package/public/logos/logo_atomic_crm_light.svg +14 -0
  145. package/public/manifest.json +25 -0
  146. package/public/robots.txt +3 -0
  147. package/src/App.css +42 -0
  148. package/src/App.tsx +58 -0
  149. package/src/assets/react.svg +1 -0
  150. package/src/components/admin/Readme.md +40 -0
  151. package/src/components/admin/admin.tsx +132 -0
  152. package/src/components/admin/app-sidebar.tsx +166 -0
  153. package/src/components/admin/array-field.tsx +59 -0
  154. package/src/components/admin/array-input.tsx +201 -0
  155. package/src/components/admin/authentication.tsx +86 -0
  156. package/src/components/admin/autocomplete-array-input.tsx +254 -0
  157. package/src/components/admin/autocomplete-input.tsx +296 -0
  158. package/src/components/admin/badge-field.tsx +65 -0
  159. package/src/components/admin/boolean-input.tsx +116 -0
  160. package/src/components/admin/breadcrumb.tsx +135 -0
  161. package/src/components/admin/bulk-actions-toolbar.tsx +83 -0
  162. package/src/components/admin/bulk-delete-button.tsx +70 -0
  163. package/src/components/admin/bulk-export-button.tsx +76 -0
  164. package/src/components/admin/cancel-button.tsx +46 -0
  165. package/src/components/admin/columns-button.tsx +345 -0
  166. package/src/components/admin/confirm.tsx +166 -0
  167. package/src/components/admin/count.tsx +94 -0
  168. package/src/components/admin/create-button.tsx +58 -0
  169. package/src/components/admin/create.tsx +132 -0
  170. package/src/components/admin/data-table.tsx +520 -0
  171. package/src/components/admin/date-field.tsx +136 -0
  172. package/src/components/admin/date-input.tsx +317 -0
  173. package/src/components/admin/date-time-input.tsx +331 -0
  174. package/src/components/admin/delete-button.tsx +113 -0
  175. package/src/components/admin/edit-button.tsx +64 -0
  176. package/src/components/admin/edit-guesser.tsx +157 -0
  177. package/src/components/admin/edit.tsx +152 -0
  178. package/src/components/admin/email-field.tsx +74 -0
  179. package/src/components/admin/error.tsx +111 -0
  180. package/src/components/admin/export-button.tsx +126 -0
  181. package/src/components/admin/field-toggle.tsx +164 -0
  182. package/src/components/admin/file-field.tsx +123 -0
  183. package/src/components/admin/file-input.tsx +361 -0
  184. package/src/components/admin/filter-form.tsx +510 -0
  185. package/src/components/admin/form.tsx +312 -0
  186. package/src/components/admin/icon-button-with-tooltip.tsx +85 -0
  187. package/src/components/admin/index.ts +73 -0
  188. package/src/components/admin/input-helper-text.tsx +29 -0
  189. package/src/components/admin/layout.tsx +69 -0
  190. package/src/components/admin/list-guesser.tsx +239 -0
  191. package/src/components/admin/list-pagination.tsx +247 -0
  192. package/src/components/admin/list.tsx +178 -0
  193. package/src/components/admin/loading.tsx +40 -0
  194. package/src/components/admin/locales-menu-button.tsx +60 -0
  195. package/src/components/admin/login-page.tsx +104 -0
  196. package/src/components/admin/notification.tsx +114 -0
  197. package/src/components/admin/number-field.tsx +84 -0
  198. package/src/components/admin/number-input.tsx +124 -0
  199. package/src/components/admin/radio-button-group-input.tsx +184 -0
  200. package/src/components/admin/ready.tsx +55 -0
  201. package/src/components/admin/record-field.tsx +132 -0
  202. package/src/components/admin/reference-array-field.tsx +152 -0
  203. package/src/components/admin/reference-array-input.tsx +68 -0
  204. package/src/components/admin/reference-field.tsx +153 -0
  205. package/src/components/admin/reference-input.tsx +46 -0
  206. package/src/components/admin/reference-many-count.tsx +92 -0
  207. package/src/components/admin/reference-many-field.tsx +132 -0
  208. package/src/components/admin/refresh-button.tsx +31 -0
  209. package/src/components/admin/saved-queries.tsx +174 -0
  210. package/src/components/admin/search-input.tsx +57 -0
  211. package/src/components/admin/select-field.tsx +111 -0
  212. package/src/components/admin/select-input.tsx +323 -0
  213. package/src/components/admin/show-button.tsx +57 -0
  214. package/src/components/admin/show-guesser.tsx +215 -0
  215. package/src/components/admin/show.tsx +184 -0
  216. package/src/components/admin/simple-form-iterator.tsx +582 -0
  217. package/src/components/admin/simple-form.tsx +95 -0
  218. package/src/components/admin/simple-show-layout.tsx +8 -0
  219. package/src/components/admin/single-field-list.tsx +67 -0
  220. package/src/components/admin/sort-button.tsx +152 -0
  221. package/src/components/admin/spinner.tsx +46 -0
  222. package/src/components/admin/text-field.tsx +60 -0
  223. package/src/components/admin/text-input.tsx +77 -0
  224. package/src/components/admin/theme-mode-toggle.tsx +48 -0
  225. package/src/components/admin/theme-provider.tsx +74 -0
  226. package/src/components/admin/toggle-filter-button.tsx +77 -0
  227. package/src/components/admin/url-field.tsx +83 -0
  228. package/src/components/admin/user-menu.tsx +84 -0
  229. package/src/components/atomic-crm/activity/ActivityLog.tsx +54 -0
  230. package/src/components/atomic-crm/activity/ActivityLogCompanyCreated.tsx +50 -0
  231. package/src/components/atomic-crm/activity/ActivityLogContactCreated.tsx +42 -0
  232. package/src/components/atomic-crm/activity/ActivityLogContactNoteCreated.tsx +71 -0
  233. package/src/components/atomic-crm/activity/ActivityLogContext.tsx +11 -0
  234. package/src/components/atomic-crm/activity/ActivityLogDealCreated.tsx +41 -0
  235. package/src/components/atomic-crm/activity/ActivityLogDealNoteCreated.tsx +84 -0
  236. package/src/components/atomic-crm/activity/ActivityLogIterator.tsx +80 -0
  237. package/src/components/atomic-crm/activity/ActivityLogNote.tsx +36 -0
  238. package/src/components/atomic-crm/companies/AutocompleteCompanyInput.tsx +43 -0
  239. package/src/components/atomic-crm/companies/CompanyAside.tsx +207 -0
  240. package/src/components/atomic-crm/companies/CompanyAvatar.tsx +29 -0
  241. package/src/components/atomic-crm/companies/CompanyCard.tsx +88 -0
  242. package/src/components/atomic-crm/companies/CompanyCreate.tsx +41 -0
  243. package/src/components/atomic-crm/companies/CompanyEdit.tsx +33 -0
  244. package/src/components/atomic-crm/companies/CompanyEmpty.tsx +26 -0
  245. package/src/components/atomic-crm/companies/CompanyInputs.tsx +160 -0
  246. package/src/components/atomic-crm/companies/CompanyList.tsx +54 -0
  247. package/src/components/atomic-crm/companies/CompanyListFilter.tsx +55 -0
  248. package/src/components/atomic-crm/companies/CompanyShow.tsx +241 -0
  249. package/src/components/atomic-crm/companies/GridList.tsx +46 -0
  250. package/src/components/atomic-crm/companies/index.ts +11 -0
  251. package/src/components/atomic-crm/companies/sizes.ts +7 -0
  252. package/src/components/atomic-crm/consts.ts +5 -0
  253. package/src/components/atomic-crm/contacts/Avatar.tsx +40 -0
  254. package/src/components/atomic-crm/contacts/ContactAside.tsx +187 -0
  255. package/src/components/atomic-crm/contacts/ContactCreate.tsx +34 -0
  256. package/src/components/atomic-crm/contacts/ContactEdit.tsx +32 -0
  257. package/src/components/atomic-crm/contacts/ContactEmpty.tsx +28 -0
  258. package/src/components/atomic-crm/contacts/ContactImportButton.tsx +213 -0
  259. package/src/components/atomic-crm/contacts/ContactInputs.tsx +209 -0
  260. package/src/components/atomic-crm/contacts/ContactList.tsx +116 -0
  261. package/src/components/atomic-crm/contacts/ContactListContent.tsx +107 -0
  262. package/src/components/atomic-crm/contacts/ContactListFilter.tsx +126 -0
  263. package/src/components/atomic-crm/contacts/ContactMergeButton.tsx +263 -0
  264. package/src/components/atomic-crm/contacts/ContactShow.tsx +76 -0
  265. package/src/components/atomic-crm/contacts/ExportVCardButton.tsx +79 -0
  266. package/src/components/atomic-crm/contacts/TagsList.tsx +33 -0
  267. package/src/components/atomic-crm/contacts/TagsListEdit.tsx +155 -0
  268. package/src/components/atomic-crm/contacts/contacts_export.csv +3 -0
  269. package/src/components/atomic-crm/contacts/exportToVCard.ts +104 -0
  270. package/src/components/atomic-crm/contacts/index.tsx +14 -0
  271. package/src/components/atomic-crm/contacts/useContactImport.tsx +206 -0
  272. package/src/components/atomic-crm/dashboard/Dashboard.tsx +66 -0
  273. package/src/components/atomic-crm/dashboard/DashboardActivityLog.tsx +22 -0
  274. package/src/components/atomic-crm/dashboard/DashboardStepper.tsx +72 -0
  275. package/src/components/atomic-crm/dashboard/DealsChart.tsx +202 -0
  276. package/src/components/atomic-crm/dashboard/DealsPipeline.tsx +90 -0
  277. package/src/components/atomic-crm/dashboard/HotContacts.tsx +92 -0
  278. package/src/components/atomic-crm/dashboard/LatestNotes.tsx +116 -0
  279. package/src/components/atomic-crm/dashboard/TasksList.tsx +69 -0
  280. package/src/components/atomic-crm/dashboard/TasksListEmpty.tsx +22 -0
  281. package/src/components/atomic-crm/dashboard/TasksListFilter.tsx +72 -0
  282. package/src/components/atomic-crm/dashboard/Welcome.tsx +41 -0
  283. package/src/components/atomic-crm/deals/ContactList.tsx +31 -0
  284. package/src/components/atomic-crm/deals/DealArchivedList.tsx +105 -0
  285. package/src/components/atomic-crm/deals/DealCard.tsx +78 -0
  286. package/src/components/atomic-crm/deals/DealColumn.tsx +52 -0
  287. package/src/components/atomic-crm/deals/DealCreate.tsx +95 -0
  288. package/src/components/atomic-crm/deals/DealEdit.tsx +81 -0
  289. package/src/components/atomic-crm/deals/DealEmpty.tsx +63 -0
  290. package/src/components/atomic-crm/deals/DealInputs.tsx +103 -0
  291. package/src/components/atomic-crm/deals/DealList.tsx +95 -0
  292. package/src/components/atomic-crm/deals/DealListContent.tsx +245 -0
  293. package/src/components/atomic-crm/deals/DealShow.tsx +260 -0
  294. package/src/components/atomic-crm/deals/OnlyMineInput.tsx +30 -0
  295. package/src/components/atomic-crm/deals/deal.ts +5 -0
  296. package/src/components/atomic-crm/deals/dealUtils.ts +26 -0
  297. package/src/components/atomic-crm/deals/index.ts +6 -0
  298. package/src/components/atomic-crm/deals/stages.ts +28 -0
  299. package/src/components/atomic-crm/filters/FilterCategory.tsx +20 -0
  300. package/src/components/atomic-crm/layout/FormToolbar.tsx +12 -0
  301. package/src/components/atomic-crm/layout/Header.tsx +134 -0
  302. package/src/components/atomic-crm/layout/Layout.tsx +21 -0
  303. package/src/components/atomic-crm/layout/TopToolbar.tsx +24 -0
  304. package/src/components/atomic-crm/login/LoginSkeleton.tsx +18 -0
  305. package/src/components/atomic-crm/login/SignupPage.tsx +150 -0
  306. package/src/components/atomic-crm/login/StartPage.tsx +27 -0
  307. package/src/components/atomic-crm/misc/AsideSection.tsx +21 -0
  308. package/src/components/atomic-crm/misc/ContactOption.tsx +26 -0
  309. package/src/components/atomic-crm/misc/ImageEditorField.tsx +206 -0
  310. package/src/components/atomic-crm/misc/RelativeDate.tsx +5 -0
  311. package/src/components/atomic-crm/misc/Status.tsx +28 -0
  312. package/src/components/atomic-crm/misc/fetchWithTimeout.ts +19 -0
  313. package/src/components/atomic-crm/misc/isLinkedInUrl.ts +15 -0
  314. package/src/components/atomic-crm/misc/unsupportedDomains.const.ts +105 -0
  315. package/src/components/atomic-crm/misc/useAppBarHeight.ts +9 -0
  316. package/src/components/atomic-crm/misc/usePapaParse.tsx +144 -0
  317. package/src/components/atomic-crm/notes/Note.tsx +187 -0
  318. package/src/components/atomic-crm/notes/NoteAttachments.tsx +56 -0
  319. package/src/components/atomic-crm/notes/NoteCreate.tsx +112 -0
  320. package/src/components/atomic-crm/notes/NoteInputs.tsx +92 -0
  321. package/src/components/atomic-crm/notes/NotesIterator.tsx +37 -0
  322. package/src/components/atomic-crm/notes/StatusSelector.tsx +39 -0
  323. package/src/components/atomic-crm/notes/index.ts +3 -0
  324. package/src/components/atomic-crm/notes/utils.ts +13 -0
  325. package/src/components/atomic-crm/providers/commons/activity.ts +174 -0
  326. package/src/components/atomic-crm/providers/commons/canAccess.ts +26 -0
  327. package/src/components/atomic-crm/providers/commons/getCompanyAvatar.spec.ts +20 -0
  328. package/src/components/atomic-crm/providers/commons/getCompanyAvatar.ts +21 -0
  329. package/src/components/atomic-crm/providers/commons/getContactAvatar.spec.ts +80 -0
  330. package/src/components/atomic-crm/providers/commons/getContactAvatar.ts +70 -0
  331. package/src/components/atomic-crm/providers/commons/mergeContacts.ts +185 -0
  332. package/src/components/atomic-crm/providers/fakerest/authProvider.ts +74 -0
  333. package/src/components/atomic-crm/providers/fakerest/dataGenerator/companies.ts +53 -0
  334. package/src/components/atomic-crm/providers/fakerest/dataGenerator/contactNotes.ts +25 -0
  335. package/src/components/atomic-crm/providers/fakerest/dataGenerator/contacts.ts +103 -0
  336. package/src/components/atomic-crm/providers/fakerest/dataGenerator/dealNotes.ts +19 -0
  337. package/src/components/atomic-crm/providers/fakerest/dataGenerator/deals.ts +53 -0
  338. package/src/components/atomic-crm/providers/fakerest/dataGenerator/finalize.ts +10 -0
  339. package/src/components/atomic-crm/providers/fakerest/dataGenerator/index.ts +25 -0
  340. package/src/components/atomic-crm/providers/fakerest/dataGenerator/sales.ts +37 -0
  341. package/src/components/atomic-crm/providers/fakerest/dataGenerator/tags.ts +14 -0
  342. package/src/components/atomic-crm/providers/fakerest/dataGenerator/tasks.ts +55 -0
  343. package/src/components/atomic-crm/providers/fakerest/dataGenerator/types.ts +21 -0
  344. package/src/components/atomic-crm/providers/fakerest/dataGenerator/utils.ts +28 -0
  345. package/src/components/atomic-crm/providers/fakerest/dataProvider.ts +518 -0
  346. package/src/components/atomic-crm/providers/fakerest/index.ts +2 -0
  347. package/src/components/atomic-crm/providers/fakerest/internal/listParser.ts +48 -0
  348. package/src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.spec.ts +721 -0
  349. package/src/components/atomic-crm/providers/fakerest/internal/supabaseAdapter.ts +49 -0
  350. package/src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.spec.ts +35 -0
  351. package/src/components/atomic-crm/providers/fakerest/internal/transformContainsFilter.ts +17 -0
  352. package/src/components/atomic-crm/providers/fakerest/internal/transformFilter.ts +57 -0
  353. package/src/components/atomic-crm/providers/fakerest/internal/transformInFilter.spec.ts +32 -0
  354. package/src/components/atomic-crm/providers/fakerest/internal/transformInFilter.ts +17 -0
  355. package/src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.spec.ts +23 -0
  356. package/src/components/atomic-crm/providers/fakerest/internal/transformOrFilter.ts +17 -0
  357. package/src/components/atomic-crm/providers/supabase/authProvider.ts +121 -0
  358. package/src/components/atomic-crm/providers/supabase/dataProvider.ts +407 -0
  359. package/src/components/atomic-crm/providers/supabase/index.ts +2 -0
  360. package/src/components/atomic-crm/providers/supabase/supabase.ts +34 -0
  361. package/src/components/atomic-crm/providers/types.ts +1 -0
  362. package/src/components/atomic-crm/root/CRM.tsx +167 -0
  363. package/src/components/atomic-crm/root/ConfigurationContext.tsx +80 -0
  364. package/src/components/atomic-crm/root/defaultConfiguration.ts +64 -0
  365. package/src/components/atomic-crm/root/i18nProvider.tsx +25 -0
  366. package/src/components/atomic-crm/sales/SaleName.tsx +13 -0
  367. package/src/components/atomic-crm/sales/SalesCreate.tsx +51 -0
  368. package/src/components/atomic-crm/sales/SalesEdit.tsx +82 -0
  369. package/src/components/atomic-crm/sales/SalesInputs.tsx +31 -0
  370. package/src/components/atomic-crm/sales/SalesList.tsx +62 -0
  371. package/src/components/atomic-crm/sales/index.ts +12 -0
  372. package/src/components/atomic-crm/settings/DatabaseSettings.tsx +169 -0
  373. package/src/components/atomic-crm/settings/SettingsPage.tsx +259 -0
  374. package/src/components/atomic-crm/setup/SupabaseSetupWizard.tsx +215 -0
  375. package/src/components/atomic-crm/simple-list/ListNoResults.tsx +53 -0
  376. package/src/components/atomic-crm/simple-list/ListPlaceholder.tsx +9 -0
  377. package/src/components/atomic-crm/simple-list/SimpleList.tsx +245 -0
  378. package/src/components/atomic-crm/simple-list/SimpleListItem.tsx +138 -0
  379. package/src/components/atomic-crm/simple-list/SimpleListLoading.tsx +60 -0
  380. package/src/components/atomic-crm/tags/RoundButton.tsx +10 -0
  381. package/src/components/atomic-crm/tags/TagChip.tsx +45 -0
  382. package/src/components/atomic-crm/tags/TagCreateModal.tsx +39 -0
  383. package/src/components/atomic-crm/tags/TagDialog.tsx +118 -0
  384. package/src/components/atomic-crm/tags/TagEditModal.tsx +42 -0
  385. package/src/components/atomic-crm/tags/colors.ts +12 -0
  386. package/src/components/atomic-crm/tasks/AddTask.tsx +191 -0
  387. package/src/components/atomic-crm/tasks/Task.tsx +184 -0
  388. package/src/components/atomic-crm/tasks/TaskEdit.tsx +96 -0
  389. package/src/components/atomic-crm/tasks/TasksIterator.tsx +30 -0
  390. package/src/components/atomic-crm/types.ts +226 -0
  391. package/src/components/supabase/forgot-password-page.tsx +86 -0
  392. package/src/components/supabase/layout.tsx +27 -0
  393. package/src/components/supabase/set-password-page.tsx +119 -0
  394. package/src/components/ui/README.md +34 -0
  395. package/src/components/ui/accordion.tsx +64 -0
  396. package/src/components/ui/alert.tsx +66 -0
  397. package/src/components/ui/avatar.tsx +99 -0
  398. package/src/components/ui/badge.tsx +46 -0
  399. package/src/components/ui/breadcrumb.tsx +109 -0
  400. package/src/components/ui/button.tsx +59 -0
  401. package/src/components/ui/card.tsx +92 -0
  402. package/src/components/ui/checkbox.tsx +30 -0
  403. package/src/components/ui/command.tsx +175 -0
  404. package/src/components/ui/dialog.tsx +133 -0
  405. package/src/components/ui/drawer.tsx +133 -0
  406. package/src/components/ui/dropdown-menu.tsx +255 -0
  407. package/src/components/ui/input.tsx +21 -0
  408. package/src/components/ui/label.tsx +24 -0
  409. package/src/components/ui/navigation-menu.tsx +168 -0
  410. package/src/components/ui/pagination.tsx +127 -0
  411. package/src/components/ui/popover.tsx +46 -0
  412. package/src/components/ui/progress.tsx +29 -0
  413. package/src/components/ui/radio-group.tsx +43 -0
  414. package/src/components/ui/select.tsx +183 -0
  415. package/src/components/ui/separator.tsx +26 -0
  416. package/src/components/ui/sheet.tsx +137 -0
  417. package/src/components/ui/sidebar.tsx +724 -0
  418. package/src/components/ui/skeleton.tsx +13 -0
  419. package/src/components/ui/sonner.tsx +38 -0
  420. package/src/components/ui/spinner.tsx +51 -0
  421. package/src/components/ui/switch.tsx +29 -0
  422. package/src/components/ui/table.tsx +114 -0
  423. package/src/components/ui/tabs.tsx +64 -0
  424. package/src/components/ui/textarea.tsx +18 -0
  425. package/src/components/ui/tooltip.tsx +61 -0
  426. package/src/hooks/saved-queries.tsx +67 -0
  427. package/src/hooks/simple-form-iterator-context.tsx +70 -0
  428. package/src/hooks/use-mobile.ts +21 -0
  429. package/src/hooks/useBulkExport.tsx +61 -0
  430. package/src/hooks/useSupportCreateSuggestion.tsx +188 -0
  431. package/src/hooks/user-menu-context.tsx +24 -0
  432. package/src/index.css +170 -0
  433. package/src/lib/field.type.ts +22 -0
  434. package/src/lib/genericMemo.ts +18 -0
  435. package/src/lib/i18nProvider.ts +9 -0
  436. package/src/lib/sanitizeInputRestProps.ts +46 -0
  437. package/src/lib/supabase-config.ts +123 -0
  438. package/src/lib/utils.ts +6 -0
  439. package/src/main.tsx +10 -0
  440. package/src/setupTests.js +5 -0
  441. package/src/vite-env.d.ts +1 -0
  442. package/supabase/config.toml +157 -0
  443. package/supabase/functions/.env.development +7 -0
  444. package/supabase/functions/_shared/db.ts +187 -0
  445. package/supabase/functions/_shared/supabaseAdmin.ts +13 -0
  446. package/supabase/functions/_shared/utils.ts +13 -0
  447. package/supabase/functions/mergeContacts/index.ts +215 -0
  448. package/supabase/functions/postmark/addNoteToContact.ts +129 -0
  449. package/supabase/functions/postmark/extractMailContactData.ts +41 -0
  450. package/supabase/functions/postmark/getExpectedAuthorization.ts +4 -0
  451. package/supabase/functions/postmark/getNoteContent.ts +6 -0
  452. package/supabase/functions/postmark/index.ts +210 -0
  453. package/supabase/functions/updatePassword/index.ts +50 -0
  454. package/supabase/functions/users/index.ts +206 -0
  455. package/supabase/migrations/20240730075029_init_db.sql +600 -0
  456. package/supabase/migrations/20240730075425_init_triggers.sql +57 -0
  457. package/supabase/migrations/20240806124555_task_sales_id.sql +1 -0
  458. package/supabase/migrations/20240807082449_remove-aquisition.sql +20 -0
  459. package/supabase/migrations/20240808141826_init_state_configure.sql +9 -0
  460. package/supabase/migrations/20240813084010_tags_policy.sql +18 -0
  461. package/supabase/migrations/20241104153231_sales_policies.sql +7 -0
  462. package/supabase/migrations/20250109152531_email_jsonb.sql +43 -0
  463. package/supabase/migrations/20250113132531_phone_jsonb.sql +67 -0
  464. package/supabase/migrations/20251204172855_merge_contacts_function.sql +153 -0
  465. package/supabase/migrations/20251204201317_drop_merge_contacts_function.sql +2 -0
  466. package/supabase/seed.sql +0 -0
  467. package/supabase/templates/invite.html +70 -0
  468. package/supabase/templates/recovery.html +75 -0
@@ -0,0 +1,407 @@
1
+ import { supabaseDataProvider } from "ra-supabase-core";
2
+ import {
3
+ withLifecycleCallbacks,
4
+ type CreateParams,
5
+ type DataProvider,
6
+ type GetListParams,
7
+ type Identifier,
8
+ type UpdateParams,
9
+ } from "ra-core";
10
+
11
+ import type {
12
+ Contact,
13
+ ContactNote,
14
+ Deal,
15
+ DealNote,
16
+ RAFile,
17
+ Sale,
18
+ SalesFormData,
19
+ SignUpData,
20
+ } from "../../types";
21
+ import { getActivityLog } from "../commons/activity";
22
+ import { getCompanyAvatar } from "../commons/getCompanyAvatar";
23
+ import { getContactAvatar } from "../commons/getContactAvatar";
24
+ import { getIsInitialized } from "./authProvider";
25
+ import { supabase } from "./supabase";
26
+ import { getSupabaseConfig } from "@/lib/supabase-config";
27
+
28
+ // Get config dynamically (from localStorage or env vars)
29
+ // If no config, create a dummy provider that will never be used
30
+ // (App.tsx will show setup wizard before CRM loads)
31
+ const config = getSupabaseConfig() || {
32
+ url: "https://placeholder.supabase.co",
33
+ anonKey: "placeholder-key",
34
+ };
35
+
36
+ const baseDataProvider = supabaseDataProvider({
37
+ instanceUrl: config.url,
38
+ apiKey: config.anonKey,
39
+ supabaseClient: supabase,
40
+ sortOrder: "asc,desc.nullslast" as any,
41
+ });
42
+
43
+ const processCompanyLogo = async (params: any) => {
44
+ let logo = params.data.logo;
45
+
46
+ if (typeof logo !== "object" || logo === null || !logo.src) {
47
+ logo = await getCompanyAvatar(params.data);
48
+ } else if (logo.rawFile instanceof File) {
49
+ await uploadToBucket(logo);
50
+ }
51
+
52
+ return {
53
+ ...params,
54
+ data: {
55
+ ...params.data,
56
+ logo,
57
+ },
58
+ };
59
+ };
60
+
61
+ async function processContactAvatar(
62
+ params: UpdateParams<Contact>,
63
+ ): Promise<UpdateParams<Contact>>;
64
+
65
+ async function processContactAvatar(
66
+ params: CreateParams<Contact>,
67
+ ): Promise<CreateParams<Contact>>;
68
+
69
+ async function processContactAvatar(
70
+ params: CreateParams<Contact> | UpdateParams<Contact>,
71
+ ): Promise<CreateParams<Contact> | UpdateParams<Contact>> {
72
+ const { data } = params;
73
+ if (data.avatar?.src || !data.email_jsonb || !data.email_jsonb.length) {
74
+ return params;
75
+ }
76
+ const avatarUrl = await getContactAvatar(data);
77
+
78
+ // Clone the data and modify the clone
79
+ const newData = { ...data, avatar: { src: avatarUrl || undefined } };
80
+
81
+ return { ...params, data: newData };
82
+ }
83
+
84
+ const dataProviderWithCustomMethods = {
85
+ ...baseDataProvider,
86
+ async getList(resource: string, params: GetListParams) {
87
+ if (resource === "companies") {
88
+ return baseDataProvider.getList("companies_summary", params);
89
+ }
90
+ if (resource === "contacts") {
91
+ return baseDataProvider.getList("contacts_summary", params);
92
+ }
93
+
94
+ return baseDataProvider.getList(resource, params);
95
+ },
96
+ async getOne(resource: string, params: any) {
97
+ if (resource === "companies") {
98
+ return baseDataProvider.getOne("companies_summary", params);
99
+ }
100
+ if (resource === "contacts") {
101
+ return baseDataProvider.getOne("contacts_summary", params);
102
+ }
103
+
104
+ return baseDataProvider.getOne(resource, params);
105
+ },
106
+
107
+ async signUp({ email, password, first_name, last_name }: SignUpData) {
108
+ const response = await supabase.auth.signUp({
109
+ email,
110
+ password,
111
+ options: {
112
+ data: {
113
+ first_name,
114
+ last_name,
115
+ },
116
+ },
117
+ });
118
+
119
+ if (!response.data?.user || response.error) {
120
+ console.error("signUp.error", response.error);
121
+ throw new Error("Failed to create account");
122
+ }
123
+
124
+ // Update the is initialized cache
125
+ getIsInitialized._is_initialized_cache = true;
126
+
127
+ return {
128
+ id: response.data.user.id,
129
+ email,
130
+ password,
131
+ };
132
+ },
133
+ async salesCreate(body: SalesFormData) {
134
+ const { data, error } = await supabase.functions.invoke<Sale>("users", {
135
+ method: "POST",
136
+ body,
137
+ });
138
+
139
+ if (!data || error) {
140
+ console.error("salesCreate.error", error);
141
+ throw new Error("Failed to create account manager");
142
+ }
143
+
144
+ return data;
145
+ },
146
+ async salesUpdate(
147
+ id: Identifier,
148
+ data: Partial<Omit<SalesFormData, "password">>,
149
+ ) {
150
+ const { email, first_name, last_name, administrator, avatar, disabled } =
151
+ data;
152
+
153
+ const { data: sale, error } = await supabase.functions.invoke<Sale>(
154
+ "users",
155
+ {
156
+ method: "PATCH",
157
+ body: {
158
+ sales_id: id,
159
+ email,
160
+ first_name,
161
+ last_name,
162
+ administrator,
163
+ disabled,
164
+ avatar,
165
+ },
166
+ },
167
+ );
168
+
169
+ if (!sale || error) {
170
+ console.error("salesCreate.error", error);
171
+ throw new Error("Failed to update account manager");
172
+ }
173
+
174
+ return data;
175
+ },
176
+ async updatePassword(id: Identifier) {
177
+ const { data: passwordUpdated, error } =
178
+ await supabase.functions.invoke<boolean>("updatePassword", {
179
+ method: "PATCH",
180
+ body: {
181
+ sales_id: id,
182
+ },
183
+ });
184
+
185
+ if (!passwordUpdated || error) {
186
+ console.error("passwordUpdate.error", error);
187
+ throw new Error("Failed to update password");
188
+ }
189
+
190
+ return passwordUpdated;
191
+ },
192
+ async unarchiveDeal(deal: Deal) {
193
+ // get all deals where stage is the same as the deal to unarchive
194
+ const { data: deals } = await baseDataProvider.getList<Deal>("deals", {
195
+ filter: { stage: deal.stage },
196
+ pagination: { page: 1, perPage: 1000 },
197
+ sort: { field: "index", order: "ASC" },
198
+ });
199
+
200
+ // set index for each deal starting from 1, if the deal to unarchive is found, set its index to the last one
201
+ const updatedDeals = deals.map((d, index) => ({
202
+ ...d,
203
+ index: d.id === deal.id ? 0 : index + 1,
204
+ archived_at: d.id === deal.id ? null : d.archived_at,
205
+ }));
206
+
207
+ return await Promise.all(
208
+ updatedDeals.map((updatedDeal) =>
209
+ baseDataProvider.update("deals", {
210
+ id: updatedDeal.id,
211
+ data: updatedDeal,
212
+ previousData: deals.find((d) => d.id === updatedDeal.id),
213
+ }),
214
+ ),
215
+ );
216
+ },
217
+ async getActivityLog(companyId?: Identifier) {
218
+ return getActivityLog(baseDataProvider, companyId);
219
+ },
220
+ async isInitialized() {
221
+ return getIsInitialized();
222
+ },
223
+ async mergeContacts(sourceId: Identifier, targetId: Identifier) {
224
+ const { data, error } = await supabase.functions.invoke("mergeContacts", {
225
+ method: "POST",
226
+ body: { loserId: sourceId, winnerId: targetId },
227
+ });
228
+
229
+ if (error) {
230
+ console.error("mergeContacts.error", error);
231
+ throw new Error("Failed to merge contacts");
232
+ }
233
+
234
+ return data;
235
+ },
236
+ } satisfies DataProvider;
237
+
238
+ export type CrmDataProvider = typeof dataProviderWithCustomMethods;
239
+
240
+ export const dataProvider = withLifecycleCallbacks(
241
+ dataProviderWithCustomMethods,
242
+ [
243
+ {
244
+ resource: "contactNotes",
245
+ beforeSave: async (data: ContactNote, _, __) => {
246
+ if (data.attachments) {
247
+ for (const fi of data.attachments) {
248
+ await uploadToBucket(fi);
249
+ }
250
+ }
251
+ return data;
252
+ },
253
+ },
254
+ {
255
+ resource: "dealNotes",
256
+ beforeSave: async (data: DealNote, _, __) => {
257
+ if (data.attachments) {
258
+ for (const fi of data.attachments) {
259
+ await uploadToBucket(fi);
260
+ }
261
+ }
262
+ return data;
263
+ },
264
+ },
265
+ {
266
+ resource: "sales",
267
+ beforeSave: async (data: Sale, _, __) => {
268
+ if (data.avatar) {
269
+ await uploadToBucket(data.avatar);
270
+ }
271
+ return data;
272
+ },
273
+ },
274
+ {
275
+ resource: "contacts",
276
+ beforeCreate: async (params) => {
277
+ return processContactAvatar(params);
278
+ },
279
+ beforeUpdate: async (params) => {
280
+ return processContactAvatar(params);
281
+ },
282
+ beforeGetList: async (params) => {
283
+ return applyFullTextSearch([
284
+ "first_name",
285
+ "last_name",
286
+ "company_name",
287
+ "title",
288
+ "email",
289
+ "phone",
290
+ "background",
291
+ ])(params);
292
+ },
293
+ },
294
+ {
295
+ resource: "companies",
296
+ beforeGetList: async (params) => {
297
+ return applyFullTextSearch([
298
+ "name",
299
+ "phone_number",
300
+ "website",
301
+ "zipcode",
302
+ "city",
303
+ "stateAbbr",
304
+ ])(params);
305
+ },
306
+ beforeCreate: async (params) => {
307
+ const createParams = await processCompanyLogo(params);
308
+
309
+ return {
310
+ ...createParams,
311
+ data: {
312
+ ...createParams.data,
313
+ created_at: new Date().toISOString(),
314
+ },
315
+ };
316
+ },
317
+ beforeUpdate: async (params) => {
318
+ return await processCompanyLogo(params);
319
+ },
320
+ },
321
+ {
322
+ resource: "contacts_summary",
323
+ beforeGetList: async (params) => {
324
+ return applyFullTextSearch(["first_name", "last_name"])(params);
325
+ },
326
+ },
327
+ {
328
+ resource: "deals",
329
+ beforeGetList: async (params) => {
330
+ return applyFullTextSearch(["name", "type", "description"])(params);
331
+ },
332
+ },
333
+ ],
334
+ );
335
+
336
+ const applyFullTextSearch = (columns: string[]) => (params: GetListParams) => {
337
+ if (!params.filter?.q) {
338
+ return params;
339
+ }
340
+ const { q, ...filter } = params.filter;
341
+ return {
342
+ ...params,
343
+ filter: {
344
+ ...filter,
345
+ "@or": columns.reduce((acc, column) => {
346
+ if (column === "email")
347
+ return {
348
+ ...acc,
349
+ [`email_fts@ilike`]: q,
350
+ };
351
+ if (column === "phone")
352
+ return {
353
+ ...acc,
354
+ [`phone_fts@ilike`]: q,
355
+ };
356
+ else
357
+ return {
358
+ ...acc,
359
+ [`${column}@ilike`]: q,
360
+ };
361
+ }, {}),
362
+ },
363
+ };
364
+ };
365
+
366
+ const uploadToBucket = async (fi: RAFile) => {
367
+ if (!fi.src.startsWith("blob:") && !fi.src.startsWith("data:")) {
368
+ // Sign URL check if path exists in the bucket
369
+ if (fi.path) {
370
+ const { error } = await supabase.storage
371
+ .from("attachments")
372
+ .createSignedUrl(fi.path, 60);
373
+
374
+ if (!error) {
375
+ return;
376
+ }
377
+ }
378
+ }
379
+
380
+ const dataContent = fi.src
381
+ ? await fetch(fi.src).then((res) => res.blob())
382
+ : fi.rawFile;
383
+
384
+ const file = fi.rawFile;
385
+ const fileExt = file.name.split(".").pop();
386
+ const fileName = `${Math.random()}.${fileExt}`;
387
+ const filePath = `${fileName}`;
388
+ const { error: uploadError } = await supabase.storage
389
+ .from("attachments")
390
+ .upload(filePath, dataContent);
391
+
392
+ if (uploadError) {
393
+ console.error("uploadError", uploadError);
394
+ throw new Error("Failed to upload attachment");
395
+ }
396
+
397
+ const { data } = supabase.storage.from("attachments").getPublicUrl(filePath);
398
+
399
+ fi.path = filePath;
400
+ fi.src = data.publicUrl;
401
+
402
+ // save MIME type
403
+ const mimeType = file.type;
404
+ fi.type = mimeType;
405
+
406
+ return fi;
407
+ };
@@ -0,0 +1,2 @@
1
+ export { authProvider } from "./authProvider";
2
+ export { dataProvider } from "./dataProvider";
@@ -0,0 +1,34 @@
1
+ import { createClient, type SupabaseClient } from "@supabase/supabase-js";
2
+ import { getSupabaseConfig } from "@/lib/supabase-config";
3
+
4
+ // Lazy initialization - create client on first access
5
+ let supabaseInstance: SupabaseClient | null = null;
6
+
7
+ function getSupabaseClient(): SupabaseClient {
8
+ if (!supabaseInstance) {
9
+ const config = getSupabaseConfig();
10
+
11
+ if (!config) {
12
+ // Return a placeholder client that will never be used
13
+ // (App.tsx will show setup wizard before this is accessed)
14
+ console.warn("[Supabase] No configuration found, using placeholder");
15
+ supabaseInstance = createClient(
16
+ "https://placeholder.supabase.co",
17
+ "placeholder-key",
18
+ );
19
+ } else {
20
+ supabaseInstance = createClient(config.url, config.anonKey);
21
+ }
22
+ }
23
+
24
+ return supabaseInstance;
25
+ }
26
+
27
+ // Export as a getter proxy to support lazy initialization
28
+ export const supabase = new Proxy({} as SupabaseClient, {
29
+ get(_target, prop) {
30
+ const client = getSupabaseClient();
31
+ const value = client[prop as keyof SupabaseClient];
32
+ return typeof value === "function" ? value.bind(client) : value;
33
+ },
34
+ });
@@ -0,0 +1 @@
1
+ export type { CrmDataProvider } from "./supabase/dataProvider";
@@ -0,0 +1,167 @@
1
+ import {
2
+ CustomRoutes,
3
+ localStorageStore,
4
+ Resource,
5
+ type AuthProvider,
6
+ type DataProvider,
7
+ } from "ra-core";
8
+ import { useEffect } from "react";
9
+ import { Route } from "react-router";
10
+ import { Admin } from "@/components/admin/admin";
11
+ import { ForgotPasswordPage } from "@/components/supabase/forgot-password-page";
12
+ import { SetPasswordPage } from "@/components/supabase/set-password-page";
13
+
14
+ import companies from "../companies";
15
+ import contacts from "../contacts";
16
+ import { Dashboard } from "../dashboard/Dashboard";
17
+ import deals from "../deals";
18
+ import { Layout } from "../layout/Layout";
19
+ import { SignupPage } from "../login/SignupPage";
20
+ import {
21
+ authProvider as defaultAuthProvider,
22
+ dataProvider as defaultDataProvider,
23
+ } from "../providers/supabase";
24
+ import sales from "../sales";
25
+ import { SettingsPage } from "../settings/SettingsPage";
26
+ import type { ConfigurationContextValue } from "./ConfigurationContext";
27
+ import { ConfigurationProvider } from "./ConfigurationContext";
28
+ import {
29
+ defaultCompanySectors,
30
+ defaultContactGender,
31
+ defaultDarkModeLogo,
32
+ defaultDealCategories,
33
+ defaultDealPipelineStatuses,
34
+ defaultDealStages,
35
+ defaultLightModeLogo,
36
+ defaultNoteStatuses,
37
+ defaultTaskTypes,
38
+ defaultTitle,
39
+ } from "./defaultConfiguration";
40
+ import { i18nProvider } from "./i18nProvider";
41
+ import { StartPage } from "../login/StartPage.tsx";
42
+
43
+ export type CRMProps = {
44
+ dataProvider?: DataProvider;
45
+ authProvider?: AuthProvider;
46
+ disableTelemetry?: boolean;
47
+ } & Partial<ConfigurationContextValue>;
48
+
49
+ /**
50
+ * CRM Component
51
+ *
52
+ * This component sets up and renders the main CRM application using `ra-core`. It provides
53
+ * default configurations and themes but allows for customization through props. The component
54
+ * wraps the application with a `ConfigurationProvider` to provide configuration values via context.
55
+ *
56
+ * @param {Array<ContactGender>} contactGender - The gender options for contacts used in the application.
57
+ * @param {string[]} companySectors - The list of company sectors used in the application.
58
+ * @param {RaThemeOptions} darkTheme - The theme to use when the application is in dark mode.
59
+ * @param {string[]} dealCategories - The categories of deals used in the application.
60
+ * @param {string[]} dealPipelineStatuses - The statuses of deals in the pipeline used in the application.
61
+ * @param {DealStage[]} dealStages - The stages of deals used in the application.
62
+ * @param {RaThemeOptions} lightTheme - The theme to use when the application is in light mode.
63
+ * @param {string} logo - The logo used in the CRM application.
64
+ * @param {NoteStatus[]} noteStatuses - The statuses of notes used in the application.
65
+ * @param {string[]} taskTypes - The types of tasks used in the application.
66
+ * @param {string} title - The title of the CRM application.
67
+ *
68
+ * @returns {JSX.Element} The rendered CRM application.
69
+ *
70
+ * @example
71
+ * // Basic usage of the CRM component
72
+ * import { CRM } from '@/components/atomic-crm/dashboard/CRM';
73
+ *
74
+ * const App = () => (
75
+ * <CRM
76
+ * logo="/path/to/logo.png"
77
+ * title="My Custom CRM"
78
+ * lightTheme={{
79
+ * ...defaultTheme,
80
+ * palette: {
81
+ * primary: { main: '#0000ff' },
82
+ * },
83
+ * }}
84
+ * />
85
+ * );
86
+ *
87
+ * export default App;
88
+ */
89
+ export const CRM = ({
90
+ contactGender = defaultContactGender,
91
+ companySectors = defaultCompanySectors,
92
+ dealCategories = defaultDealCategories,
93
+ dealPipelineStatuses = defaultDealPipelineStatuses,
94
+ dealStages = defaultDealStages,
95
+ darkModeLogo = defaultDarkModeLogo,
96
+ lightModeLogo = defaultLightModeLogo,
97
+ noteStatuses = defaultNoteStatuses,
98
+ taskTypes = defaultTaskTypes,
99
+ title = defaultTitle,
100
+ dataProvider = defaultDataProvider,
101
+ authProvider = defaultAuthProvider,
102
+ disableTelemetry,
103
+ ...rest
104
+ }: CRMProps) => {
105
+ useEffect(() => {
106
+ if (
107
+ disableTelemetry ||
108
+ process.env.NODE_ENV !== "production" ||
109
+ typeof window === "undefined" ||
110
+ typeof window.location === "undefined" ||
111
+ typeof Image === "undefined"
112
+ ) {
113
+ return;
114
+ }
115
+ const img = new Image();
116
+ img.src = `https://atomic-crm-telemetry.marmelab.com/atomic-crm-telemetry?domain=${window.location.hostname}`;
117
+ }, [disableTelemetry]);
118
+
119
+ return (
120
+ <ConfigurationProvider
121
+ contactGender={contactGender}
122
+ companySectors={companySectors}
123
+ dealCategories={dealCategories}
124
+ dealPipelineStatuses={dealPipelineStatuses}
125
+ dealStages={dealStages}
126
+ darkModeLogo={darkModeLogo}
127
+ lightModeLogo={lightModeLogo}
128
+ noteStatuses={noteStatuses}
129
+ taskTypes={taskTypes}
130
+ title={title}
131
+ >
132
+ <Admin
133
+ dataProvider={dataProvider}
134
+ authProvider={authProvider}
135
+ store={localStorageStore(undefined, "CRM")}
136
+ layout={Layout}
137
+ loginPage={StartPage}
138
+ i18nProvider={i18nProvider}
139
+ dashboard={Dashboard}
140
+ requireAuth
141
+ disableTelemetry
142
+ {...rest}
143
+ >
144
+ <CustomRoutes noLayout>
145
+ <Route path={SignupPage.path} element={<SignupPage />} />
146
+ <Route path={SetPasswordPage.path} element={<SetPasswordPage />} />
147
+ <Route
148
+ path={ForgotPasswordPage.path}
149
+ element={<ForgotPasswordPage />}
150
+ />
151
+ </CustomRoutes>
152
+
153
+ <CustomRoutes>
154
+ <Route path={SettingsPage.path} element={<SettingsPage />} />
155
+ </CustomRoutes>
156
+ <Resource name="deals" {...deals} />
157
+ <Resource name="contacts" {...contacts} />
158
+ <Resource name="companies" {...companies} />
159
+ <Resource name="contactNotes" />
160
+ <Resource name="dealNotes" />
161
+ <Resource name="tasks" />
162
+ <Resource name="sales" {...sales} />
163
+ <Resource name="tags" />
164
+ </Admin>
165
+ </ConfigurationProvider>
166
+ );
167
+ };
@@ -0,0 +1,80 @@
1
+ import { createContext, useContext, type ReactNode } from "react";
2
+
3
+ import type { ContactGender, DealStage, NoteStatus } from "../types";
4
+ import {
5
+ defaultCompanySectors,
6
+ defaultContactGender,
7
+ defaultDarkModeLogo,
8
+ defaultDealCategories,
9
+ defaultDealPipelineStatuses,
10
+ defaultDealStages,
11
+ defaultLightModeLogo,
12
+ defaultNoteStatuses,
13
+ defaultTaskTypes,
14
+ defaultTitle,
15
+ } from "./defaultConfiguration";
16
+
17
+ // Define types for the context value
18
+ export interface ConfigurationContextValue {
19
+ companySectors: string[];
20
+ dealCategories: string[];
21
+ dealPipelineStatuses: string[];
22
+ dealStages: DealStage[];
23
+ noteStatuses: NoteStatus[];
24
+ taskTypes: string[];
25
+ title: string;
26
+ darkModeLogo: string;
27
+ lightModeLogo: string;
28
+ contactGender: ContactGender[];
29
+ }
30
+
31
+ export interface ConfigurationProviderProps extends ConfigurationContextValue {
32
+ children: ReactNode;
33
+ }
34
+
35
+ // Create context with default value
36
+ export const ConfigurationContext = createContext<ConfigurationContextValue>({
37
+ companySectors: defaultCompanySectors,
38
+ dealCategories: defaultDealCategories,
39
+ dealPipelineStatuses: defaultDealPipelineStatuses,
40
+ dealStages: defaultDealStages,
41
+ noteStatuses: defaultNoteStatuses,
42
+ taskTypes: defaultTaskTypes,
43
+ title: defaultTitle,
44
+ darkModeLogo: defaultDarkModeLogo,
45
+ lightModeLogo: defaultLightModeLogo,
46
+ contactGender: defaultContactGender,
47
+ });
48
+
49
+ export const ConfigurationProvider = ({
50
+ children,
51
+ companySectors,
52
+ dealCategories,
53
+ dealPipelineStatuses,
54
+ dealStages,
55
+ darkModeLogo,
56
+ lightModeLogo,
57
+ noteStatuses,
58
+ taskTypes,
59
+ title,
60
+ contactGender,
61
+ }: ConfigurationProviderProps) => (
62
+ <ConfigurationContext.Provider
63
+ value={{
64
+ companySectors,
65
+ dealCategories,
66
+ dealPipelineStatuses,
67
+ dealStages,
68
+ darkModeLogo,
69
+ lightModeLogo,
70
+ noteStatuses,
71
+ title,
72
+ taskTypes,
73
+ contactGender,
74
+ }}
75
+ >
76
+ {children}
77
+ </ConfigurationContext.Provider>
78
+ );
79
+
80
+ export const useConfigurationContext = () => useContext(ConfigurationContext);