@wisemen/wise-crm-web 0.2.0 → 0.2.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 (97) hide show
  1. package/README.md +1037 -0
  2. package/dist/BusinessDetailSidebarProvider-BQMRbGHQ.js +2083 -0
  3. package/dist/{BusinessDetailView-DvhFfuGg.js → BusinessDetailView-BxGxWOme.js} +5 -5
  4. package/dist/{CrmDetailHeaderCard-e5332OkQ.js → CrmDetailHeaderCard-CCNJpMAK.js} +68 -67
  5. package/dist/{CrmDetailView-C-lsAhtD.js → CrmDetailView-ozCpuaX2.js} +14 -14
  6. package/dist/{DealCommunicationTabView-e7NkRy9r.js → DealCommunicationTabView-Df5EeolN.js} +2 -2
  7. package/dist/{DealDetailView-BDCbOBoo.js → DealDetailView-DdWHqaBr.js} +163 -163
  8. package/dist/{DealExternalAttachment-D1PznE3V.js → DealExternalAttachment-qHdh4yMI.js} +1 -1
  9. package/dist/{DealSendMailDialog-DVE2iYQC.js → DealSendMailDialog-BaYcWZP-.js} +65 -69
  10. package/dist/Error-BArv9rNb.js +12650 -0
  11. package/dist/IndividualDetailSidebarProvider-BXZH951l.js +608 -0
  12. package/dist/{IndividualDetailView-B7dX3hZ8.js → IndividualDetailView-DfYS31-e.js} +5 -5
  13. package/dist/LinkBrokenIcon-CTlqmapl.js +17 -0
  14. package/dist/api/mutations/deal/dealCreate.mutation.d.ts +1 -1
  15. package/dist/api/mutations/deal/dealUpdate.mutation.d.ts +3 -3
  16. package/dist/api/mutations/mail-template/mailTemplateUpdate.mutation.d.ts +1 -1
  17. package/dist/client/apiErrorCode.gen.d.ts +2 -2
  18. package/dist/client/sdk.gen.d.ts +20 -17
  19. package/dist/client/types.gen.d.ts +1057 -1376
  20. package/dist/client/zod.gen.d.ts +15453 -17750
  21. package/dist/{client-BP13IBbl.js → client-pCaNxE3C.js} +748 -1047
  22. package/dist/components/app/dialog/AppConfirmDialog.vue.d.ts +2 -2
  23. package/dist/components/crm-detail/CrmDetailHeaderCard.vue.d.ts +2 -0
  24. package/dist/components/crm-detail/CrmDetailSidebarAccordionContactPersonInfo.vue.d.ts +2 -2
  25. package/dist/components/crm-detail/CrmDetailSidebarAccordionGenericContactPersonInfo.vue.d.ts +2 -2
  26. package/dist/components/notes/NoteList.vue.d.ts +2 -2
  27. package/dist/deal/components/DealSendMailForm.vue.d.ts +2 -2
  28. package/dist/deal/components/DealSendMailFormFooter.vue.d.ts +1 -1
  29. package/dist/deal/components/DealSettingsDialogMailTemplateForm.vue.d.ts +2 -2
  30. package/dist/deal/components/DealSettingsDialogMailTemplateFormFields.vue.d.ts +2 -2
  31. package/dist/dialogs/contact-create/ContactCreateDialog.vue.d.ts +1 -1
  32. package/dist/dialogs/contact-create/components/ContactCreateDialogBusinessContactPersonSearch.vue.d.ts +2 -2
  33. package/dist/dialogs/contact-create/components/ContactCreateDialogBusinessGeneralInfo.vue.d.ts +2 -2
  34. package/dist/dialogs/contact-create/components/ContactCreateDialogFooter.vue.d.ts +2 -2
  35. package/dist/dialogs/contact-create/components/ContactCreateDialogFormSection.vue.d.ts +2 -2
  36. package/dist/dialogs/note/CrmDetailSidebarNotesView.vue.d.ts +2 -2
  37. package/dist/icons/LinkBrokenIcon.vue.d.ts +3 -0
  38. package/dist/icons/icon.d.ts +1 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +448 -453
  41. package/dist/models/brand-colors/brandColor.model.d.ts +14 -0
  42. package/dist/models/brand-colors/brandColor.transformer.d.ts +5 -0
  43. package/dist/models/conent-locale/contentLocaleEnum.model.d.ts +3 -3
  44. package/dist/models/deal/create/dealCreateForm.model.d.ts +2 -2
  45. package/dist/models/deal/detail/dealDetail.model.d.ts +2 -2
  46. package/dist/models/deal/index/dealIndex.model.d.ts +2 -2
  47. package/dist/models/deal/update/dealUpdateForm.model.d.ts +2 -2
  48. package/dist/models/mail-template/detail/mailTemplateDetail.model.d.ts +2 -2
  49. package/dist/models/mail-template/update/mailTemplateUpdateForm.model.d.ts +3 -3
  50. package/dist/models/phone-number/phoneNumberForm.model.d.ts +3 -0
  51. package/dist/models/tenant-config/tenantConfig.model.d.ts +3 -0
  52. package/dist/plugins/i18n.plugin.d.ts +4 -0
  53. package/dist/style.css +1 -1
  54. package/dist/testing/factories/business.factory.d.ts +2 -1
  55. package/dist/testing.js +23 -2
  56. package/package.json +2 -1
  57. package/dist/BusinessDetailSidebarProvider-D11bjWFa.js +0 -2081
  58. package/dist/BusinessDetailSidebarProvider-DYY-Uzvx.js +0 -2081
  59. package/dist/BusinessDetailSidebarProvider-ZYGQoNHh.js +0 -2081
  60. package/dist/BusinessDetailView-BOCy7G-w.js +0 -24
  61. package/dist/BusinessDetailView-WaATSNQS.js +0 -24
  62. package/dist/CrmDetailHeaderCard-C-JNdi7s.js +0 -2515
  63. package/dist/CrmDetailHeaderCard-qkNK-2wR.js +0 -2515
  64. package/dist/CrmDetailView-C6Xm1Lp6.js +0 -65
  65. package/dist/CrmDetailView-DQehs8Fb.js +0 -65
  66. package/dist/DealDetailView-BfkDNvK4.js +0 -1021
  67. package/dist/DealDetailView-Cs5TDhih.js +0 -1021
  68. package/dist/DealSendMailDialog-D5Voyhhc.js +0 -1556
  69. package/dist/DealSendMailDialog-OAn6xjLq.js +0 -1556
  70. package/dist/Error-5vt6UD4m.js +0 -3708
  71. package/dist/Error-B4TwHEhb.js +0 -3706
  72. package/dist/Error-BPxDpKcI.js +0 -3706
  73. package/dist/IndividualDetailSidebarProvider-CvZQdjzp.js +0 -606
  74. package/dist/IndividualDetailSidebarProvider-DBITt-9W.js +0 -606
  75. package/dist/IndividualDetailSidebarProvider-vIu7Hv8O.js +0 -606
  76. package/dist/IndividualDetailView-B1vbJXGc.js +0 -24
  77. package/dist/IndividualDetailView-BKEs0XS5.js +0 -24
  78. /package/dist/{LinkExternalIcon-B9Qg55Oa.js → LinkExternalIcon-LOVtSqBT.js} +0 -0
  79. /package/dist/{LinkIcon-DCW5zjbQ.js → LinkIcon-DqBbVrvs.js} +0 -0
  80. /package/dist/{LocationPinIcon-DBc-wt2e.js → LocationPinIcon-Cp-wRgk2.js} +0 -0
  81. /package/dist/{MailIcon-Do4a7S2W.js → MailIcon-CnTrB1k3.js} +0 -0
  82. /package/dist/{MobilePhoneIcon-DSXyKwjd.js → MobilePhoneIcon-B747hmpS.js} +0 -0
  83. /package/dist/{NumberedListIcon-DUaSJSYu.js → NumberedListIcon-amJxDaaD.js} +0 -0
  84. /package/dist/{PhoneIcon-C8Cv1IiW.js → PhoneIcon-94MYVL85.js} +0 -0
  85. /package/dist/{RefreshIcon-CKZgHIZU.js → RefreshIcon-DRe3coBc.js} +0 -0
  86. /package/dist/{SendIcon-B-sQkQ3W.js → SendIcon-MYItp1xI.js} +0 -0
  87. /package/dist/{SettingsIcon-DzP-IQS5.js → SettingsIcon-C0qTAv0w.js} +0 -0
  88. /package/dist/{StarOutlineIcon-c0VfXRdQ.js → StarOutlineIcon-CiFLgepk.js} +0 -0
  89. /package/dist/{StarYellowIcon-CH0CnlSU.js → StarYellowIcon-C0v_XGwI.js} +0 -0
  90. /package/dist/{ThreeDotsIcon-C6PCFq5J.js → ThreeDotsIcon-lujOTU3G.js} +0 -0
  91. /package/dist/{TimeLineMarkerIcon-6B6SbwTN.js → TimeLineMarkerIcon-C4LfErbc.js} +0 -0
  92. /package/dist/{TrashIcon-BTPSVviz.js → TrashIcon-v4L9SEK_.js} +0 -0
  93. /package/dist/{UploadCloudIcon-1aMW5OJq.js → UploadCloudIcon-j1-1Rvqb.js} +0 -0
  94. /package/dist/{UserCircleIcon-D-19dc-2.js → UserCircleIcon-BjUt_2C4.js} +0 -0
  95. /package/dist/{UserIcon-D1H8TGlg.js → UserIcon-Cb2jFKLr.js} +0 -0
  96. /package/dist/{VerticalDotsIcon-DmPza4Jd.js → VerticalDotsIcon-Y3m6tlQ2.js} +0 -0
  97. /package/dist/{WalletIcon-BlI3D3v-.js → WalletIcon-pPsKbzmh.js} +0 -0
package/README.md ADDED
@@ -0,0 +1,1037 @@
1
+ # @wisemen/wise-crm-web
2
+
3
+ A comprehensive CRM component library for Vue 3 applications, providing ready-to-use components, composables, and utilities for building CRM features.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Configuration](#configuration)
10
+ - [Components](#components)
11
+ - [Composables](#composables)
12
+ - [Routing](#routing)
13
+ - [Internationalization](#internationalization)
14
+ - [Icons](#icons)
15
+ - [Testing Utilities](#testing-utilities)
16
+ - [Type System](#type-system)
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ # In a monorepo with pnpm workspaces
24
+ pnpm add @wisemen/wise-crm-web@workspace:*
25
+ ```
26
+
27
+ Or for external projects:
28
+
29
+ ```bash
30
+ npm install @wisemen/wise-crm-web
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Quick Start
36
+
37
+ ### 1. Initialize the CRM
38
+
39
+ Initialize the CRM configuration in your root layout or app entry point:
40
+
41
+ ```vue
42
+ <script setup lang="ts">
43
+ import { useWiseCrmConfig } from '@wisemen/wise-crm-web'
44
+ import { BoardColumnTransitionTriggerType } from '@wisemen/wise-crm-web/client'
45
+
46
+ const wiseCrm = useWiseCrmConfig()
47
+
48
+ wiseCrm.init({
49
+ apiCrmBaseUrl: 'https://api.your-crm.com',
50
+ getAccessToken: () => oAuthClient.getAccessToken(),
51
+ googleMapsApiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
52
+ locale: 'en-US',
53
+ options: {
54
+ deals: {
55
+ allowedTransitionTriggerTypes: [
56
+ BoardColumnTransitionTriggerType.EMAIL,
57
+ BoardColumnTransitionTriggerType.MANUAL,
58
+ ],
59
+ },
60
+ widgets: {
61
+ entityStatistics: {
62
+ viewAllBusinessRouteName: 'crm-businesses',
63
+ viewAllIndividualRouteName: 'crm-individuals',
64
+ },
65
+ recentlyCreatedEntities: true,
66
+ },
67
+ },
68
+ })
69
+ </script>
70
+ ```
71
+
72
+ ### 2. Set Up Routes
73
+
74
+ Configure CRM routes in your router:
75
+
76
+ ```typescript
77
+ import { useWiseCrmRoutes } from '@wisemen/wise-crm-web'
78
+
79
+ const routes = [
80
+ // ... your other routes
81
+ useWiseCrmRoutes({
82
+ businessTabRoutes: [
83
+ {
84
+ label: computed(() => 'Information'),
85
+ route: {
86
+ name: 'crm-business-information',
87
+ component: BusinessInformationTabView,
88
+ },
89
+ },
90
+ ],
91
+ individualTabRoutes: [
92
+ {
93
+ label: computed(() => 'Information'),
94
+ route: {
95
+ name: 'crm-individual-information',
96
+ component: IndividualInformationTabView,
97
+ },
98
+ },
99
+ ],
100
+ dealTabRoutes: [
101
+ {
102
+ label: computed(() => 'Information'),
103
+ route: {
104
+ name: 'crm-deal-information',
105
+ component: DealInformationTabView,
106
+ },
107
+ },
108
+ ],
109
+ excludedReturnRoutes: [], // Optional: routes to exclude from return navigation
110
+ }),
111
+ ]
112
+ ```
113
+
114
+ ### 3. Integrate i18n and Icons
115
+
116
+ ```typescript
117
+ // i18n setup
118
+ import { wiseCrmLocales } from '@wisemen/wise-crm-web'
119
+
120
+ const messages = {
121
+ 'en-US': {
122
+ ...yourEnLocale,
123
+ ...wiseCrmLocales['en-US'],
124
+ },
125
+ 'nl-BE': {
126
+ ...yourNlLocale,
127
+ ...wiseCrmLocales['nl-BE'],
128
+ },
129
+ }
130
+
131
+ // Icons setup
132
+ import { wiseCrmIcons } from '@wisemen/wise-crm-web'
133
+
134
+ export const icons = {
135
+ ...wiseCrmIcons,
136
+ ...yourCustomIcons,
137
+ }
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Configuration
143
+
144
+ ### `useWiseCrmConfig().init(options)`
145
+
146
+ Initialize the CRM with the following configuration options:
147
+
148
+ #### Required Parameters
149
+
150
+ | Parameter | Type | Description |
151
+ |-----------|------|-------------|
152
+ | `apiCrmBaseUrl` | `string` | Base URL for the CRM API |
153
+ | `getAccessToken` | `() => Promise<string>` | Function that returns the current authentication token |
154
+ | `googleMapsApiKey` | `string` | Google Maps API key for address autocomplete |
155
+ | `locale` | `Locale` | Initial locale ('en-US' or 'nl-BE') |
156
+
157
+ #### Options
158
+
159
+ ##### `options.deals`
160
+
161
+ Configure deal/pipeline behavior:
162
+
163
+ ```typescript
164
+ {
165
+ deals: {
166
+ // Types of transitions allowed in the deal board
167
+ allowedTransitionTriggerTypes: BoardColumnTransitionTriggerType[]
168
+ } | null
169
+ }
170
+ ```
171
+
172
+ Available transition types:
173
+ - `BoardColumnTransitionTriggerType.MANUAL` - Manual drag & drop
174
+ - `BoardColumnTransitionTriggerType.EMAIL` - Email-triggered transitions
175
+
176
+ ##### `options.widgets`
177
+
178
+ Configure widget behaviors:
179
+
180
+ ```typescript
181
+ {
182
+ widgets: {
183
+ entityStatistics?: {
184
+ // Route names for "View All" buttons in statistics widgets
185
+ viewAllBusinessRouteName: string
186
+ viewAllIndividualRouteName: string
187
+ }
188
+ // Enable recently created entities widget
189
+ recentlyCreatedEntities?: true
190
+ }
191
+ }
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Components
197
+
198
+ ### Overview Components
199
+
200
+ #### `WiseCrmOverviewContent`
201
+
202
+ Main CRM dashboard with statistics widgets and recent activity.
203
+
204
+ ```vue
205
+ <template>
206
+ <WiseCrmOverviewContent />
207
+ </template>
208
+ ```
209
+ ### Deal Components
210
+
211
+ #### `WiseCrmCrmDealOverview`
212
+
213
+ Kanban-style deal pipeline board with drag-and-drop.
214
+
215
+ ```vue
216
+ <template>
217
+ <WiseCrmCrmDealOverview />
218
+ </template>
219
+ ```
220
+
221
+ ### Dialog Components
222
+
223
+ #### `WiseCrmContactCreateDialog`
224
+
225
+ Dialog for adding contact persons to a business.
226
+
227
+ ```vue
228
+ <script setup lang="ts">
229
+ import { useWiseCrmContactCreateDialog, WiseCrmContactCreateDialog } from '@wisemen/wise-crm-web'
230
+
231
+ const contactDialog = useWiseCrmContactCreateDialog()
232
+
233
+ // Open from anywhere in your app
234
+ function addContact(): void {
235
+ contactDialog.open(businessUuid)
236
+ }
237
+ </script>
238
+
239
+ <template>
240
+ <WiseCrmContactCreateDialog />
241
+ </template>
242
+ ```
243
+
244
+ ### Card Components
245
+
246
+ #### `WiseCrmBusinessUpdateCard`
247
+
248
+ Form card for updating business information.
249
+
250
+ ```vue
251
+ <script setup lang="ts">
252
+ import { useRouteParams } from '@vueuse/router'
253
+ import type { WiseCrmBusinessUuid } from '@wisemen/wise-crm-web'
254
+ import { WiseCrmBusinessUpdateCard } from '@wisemen/wise-crm-web'
255
+
256
+ const businessUuid = useRouteParams<WiseCrmBusinessUuid>('businessUuid', null)
257
+ </script>
258
+
259
+ <template>
260
+ <WiseCrmBusinessUpdateCard
261
+ v-if="businessUuid !== null"
262
+ :business-uuid="businessUuid"
263
+ />
264
+ </template>
265
+ ```
266
+
267
+ **Props:**
268
+ - `businessUuid`: `WiseCrmBusinessUuid` - The business to update
269
+
270
+ #### `WiseCrmBusinessBillingInformationCard`
271
+
272
+ Form card for managing business billing information.
273
+
274
+ ```vue
275
+ <template>
276
+ <WiseCrmBusinessBillingInformationCard :business-uuid="businessUuid" />
277
+ </template>
278
+ ```
279
+
280
+ **Props:**
281
+ - `businessUuid`: `WiseCrmBusinessUuid` - The business UUID
282
+
283
+ #### `WiseCrmIndividualUpdateCard`
284
+
285
+ Form card for updating individual information.
286
+
287
+ ```vue
288
+ <template>
289
+ <WiseCrmIndividualUpdateCard :individual-uuid="individualUuid" />
290
+ </template>
291
+ ```
292
+
293
+ **Props:**
294
+ - `individualUuid`: `WiseCrmIndividualUuid` - The individual UUID
295
+
296
+ #### `WiseCrmIndividualBillingInformationCard`
297
+
298
+ Form card for managing individual billing information.
299
+
300
+ ```vue
301
+ <template>
302
+ <WiseCrmIndividualBillingInformationCard :individual-uuid="individualUuid" />
303
+ </template>
304
+ ```
305
+
306
+ **Props:**
307
+ - `individualUuid`: `WiseCrmIndividualUuid` - The individual UUID
308
+
309
+ ### Widget Components
310
+
311
+ #### `WiseCrmBusinessWidget`
312
+
313
+ Statistics widget showing business metrics.
314
+
315
+ ```vue
316
+ <template>
317
+ <WiseCrmBusinessWidget />
318
+ </template>
319
+ ```
320
+
321
+ #### `WiseCrmIndividualWidget`
322
+
323
+ Statistics widget showing individual metrics.
324
+
325
+ ```vue
326
+ <template>
327
+ <WiseCrmIndividualWidget />
328
+ </template>
329
+ ```
330
+
331
+ #### `WiseCrmRecentlyCreatedWidget`
332
+
333
+ Widget displaying recently created entities.
334
+
335
+ ```vue
336
+ <template>
337
+ <WiseCrmRecentlyCreatedWidget />
338
+ </template>
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Composables
344
+
345
+ ### `useWiseCrm()`
346
+
347
+ Main composable for CRM operations and navigation.
348
+
349
+ ```typescript
350
+ import { useWiseCrm } from '@wisemen/wise-crm-web'
351
+
352
+ const crm = useWiseCrm()
353
+ ```
354
+
355
+ #### Methods
356
+
357
+ ##### `openBusinessDetail(businessUuid: WiseCrmBusinessUuid): void`
358
+
359
+ Navigate to business detail page.
360
+
361
+ ```typescript
362
+ crm.openBusinessDetail(businessUuid)
363
+ ```
364
+
365
+ ##### `openIndividualDetail(individualUuid: WiseCrmIndividualUuid): void`
366
+
367
+ Navigate to individual detail page.
368
+
369
+ ```typescript
370
+ crm.openIndividualDetail(individualUuid)
371
+ ```
372
+
373
+ ##### `getEntityConfig(type: EntityType): EntityConfig | null`
374
+
375
+ Get configuration for a specific entity type.
376
+
377
+ ```typescript
378
+ const businessConfig = crm.getEntityConfig(EntityType.BUSINESS)
379
+ console.log(businessConfig?.name) // Localized name like "Business" or "Bedrijf"
380
+ ```
381
+
382
+ ##### `goToReturnRoute(): void`
383
+
384
+ Navigate back to the stored return route (useful for "back" buttons).
385
+
386
+ ```typescript
387
+ crm.goToReturnRoute()
388
+ ```
389
+
390
+ ##### `storeReturnRoute(route: RouteLocationNormalized, excludedRoutes?: (string | RegExp)[]): void`
391
+
392
+ Manually store a return route (usually handled automatically by `useWiseCrmRoutes`).
393
+
394
+ ```typescript
395
+ crm.storeReturnRoute(router.currentRoute.value, ['crm-detail'])
396
+ ```
397
+
398
+ ### `useWiseCrmConfig()`
399
+
400
+ CRM initialization and configuration composable.
401
+
402
+ ```typescript
403
+ import { useWiseCrmConfig } from '@wisemen/wise-crm-web'
404
+
405
+ const wiseCrm = useWiseCrmConfig()
406
+ ```
407
+
408
+ #### Properties
409
+
410
+ ##### `isInitialized: Ref<boolean>`
411
+
412
+ Reactive flag indicating if CRM has been initialized.
413
+
414
+ ```typescript
415
+ watch(wiseCrm.isInitialized, (initialized) => {
416
+ if (initialized) {
417
+ console.log('CRM is ready!')
418
+ }
419
+ })
420
+ ```
421
+
422
+ #### Methods
423
+
424
+ ##### `init(props: InitProps): Promise<void>`
425
+
426
+ Initialize the CRM (see [Configuration](#configuration) section).
427
+
428
+ ##### `getConfig(): TenantConfig`
429
+
430
+ Get the current tenant configuration.
431
+
432
+ ```typescript
433
+ const config = wiseCrm.getConfig()
434
+ console.log(config.entities) // Entity configurations
435
+ ```
436
+
437
+ ##### `getOptions(): InitProps['options']`
438
+
439
+ Get the initialization options.
440
+
441
+ ```typescript
442
+ const options = wiseCrm.getOptions()
443
+ console.log(options.deals?.allowedTransitionTriggerTypes)
444
+ ```
445
+
446
+ ##### `getCustomFieldDefinitionForEntity(entityType: EntityType): CustomFieldDefinitionIndex[]`
447
+
448
+ Get custom field definitions for an entity type.
449
+
450
+ ```typescript
451
+ const customFields = wiseCrm.getCustomFieldDefinitionForEntity(EntityType.BUSINESS)
452
+ ```
453
+
454
+ ### `useWiseCrmContactCreateDialog()`
455
+
456
+ Composable for controlling the contact creation dialog.
457
+
458
+ ```typescript
459
+ import { useWiseCrmContactCreateDialog } from '@wisemen/wise-crm-web'
460
+
461
+ const contactDialog = useWiseCrmContactCreateDialog()
462
+ ```
463
+
464
+ #### Methods
465
+
466
+ ##### `open(businessUuid: WiseCrmBusinessUuid): void`
467
+
468
+ Open the contact creation dialog for a specific business.
469
+
470
+ ```typescript
471
+ contactDialog.open(businessUuid)
472
+ ```
473
+
474
+ ---
475
+
476
+ ## Routing
477
+
478
+ ### `useWiseCrmRoutes(options)`
479
+
480
+ Generate CRM routes with tab-based detail views.
481
+
482
+ ```typescript
483
+ import type { ComputedRef } from 'vue'
484
+ import { useWiseCrmRoutes } from '@wisemen/wise-crm-web'
485
+
486
+ interface CrmRouteOptions {
487
+ label: ComputedRef<string>
488
+ route: RouteRecordRaw
489
+ }
490
+
491
+ const crmRoutes = useWiseCrmRoutes({
492
+ businessTabRoutes: CrmRouteOptions[],
493
+ individualTabRoutes: CrmRouteOptions[],
494
+ dealTabRoutes: CrmRouteOptions[],
495
+ excludedReturnRoutes?: (string | RegExp)[], // Optional
496
+ })
497
+ ```
498
+
499
+ #### Parameters
500
+
501
+ - `businessTabRoutes`: Array of tab routes for business detail pages
502
+ - `individualTabRoutes`: Array of tab routes for individual detail pages
503
+ - `dealTabRoutes`: Array of tab routes for deal detail pages
504
+ - `excludedReturnRoutes`: Routes to exclude from return navigation tracking
505
+
506
+ #### Example
507
+
508
+ ```typescript
509
+ const crmRoutes = useWiseCrmRoutes({
510
+ businessTabRoutes: [
511
+ {
512
+ label: computed(() => i18n.t('information')),
513
+ route: {
514
+ name: 'crm-business-information',
515
+ path: 'information',
516
+ component: BusinessInformationView,
517
+ },
518
+ },
519
+ {
520
+ label: computed(() => i18n.t('contacts')),
521
+ route: {
522
+ name: 'crm-business-contacts',
523
+ path: 'contacts',
524
+ component: BusinessContactsView,
525
+ },
526
+ },
527
+ ],
528
+ individualTabRoutes: [
529
+ {
530
+ label: computed(() => i18n.t('information')),
531
+ route: {
532
+ name: 'crm-individual-information',
533
+ path: 'information',
534
+ component: IndividualInformationView,
535
+ },
536
+ },
537
+ ],
538
+ dealTabRoutes: [],
539
+ excludedReturnRoutes: [
540
+ 'crm-business-detail',
541
+ 'crm-individual-detail',
542
+ /^crm-.*-edit$/,
543
+ ],
544
+ })
545
+ ```
546
+
547
+ ### Generated Routes
548
+
549
+ The composable automatically generates these route patterns:
550
+
551
+ - `/individual/:individualUuid` - Individual detail page with tabs
552
+ - `/business/:businessUuid` - Business detail page with tabs
553
+ - `/deal/:dealUuid` - Deal detail page with tabs
554
+
555
+ ---
556
+
557
+ ## Internationalization
558
+
559
+ ### Available Locales
560
+
561
+ - `en-US` - English (United States)
562
+ - `nl-BE` - Dutch (Belgium)
563
+
564
+ ### Integration
565
+
566
+ ```typescript
567
+ import { wiseCrmLocales } from '@wisemen/wise-crm-web'
568
+
569
+ const i18n = createI18n({
570
+ messages: {
571
+ 'en-US': {
572
+ ...yourMessages,
573
+ ...wiseCrmLocales['en-US'],
574
+ },
575
+ 'nl-BE': {
576
+ ...yourMessages,
577
+ ...wiseCrmLocales['nl-BE'],
578
+ },
579
+ },
580
+ })
581
+ ```
582
+
583
+ ### Updating Locale
584
+
585
+ The CRM automatically watches for locale changes if you're using vue-i18n. To manually update:
586
+
587
+ ```typescript
588
+ import { useI18n } from 'vue-i18n'
589
+
590
+ const i18n = useI18n()
591
+ i18n.locale.value = 'nl-BE' // CRM will automatically update
592
+ ```
593
+
594
+ ---
595
+
596
+ ## Icons
597
+
598
+ ### Integration
599
+
600
+ ```typescript
601
+ import { wiseCrmIcons } from '@wisemen/wise-crm-web'
602
+
603
+ export const icons = {
604
+ ...wiseCrmIcons,
605
+ // Your custom icons
606
+ customIcon: () => import('./CustomIcon.vue'),
607
+ }
608
+ ```
609
+
610
+ ### Available Icons
611
+
612
+ The CRM includes icons for:
613
+ - Entity types (business, individual, deal)
614
+ - Actions (add, edit, delete, search)
615
+ - Navigation (back, forward, close)
616
+ - Status indicators
617
+ - And more...
618
+
619
+ ---
620
+
621
+ ## Testing Utilities
622
+
623
+ ### Factory Classes
624
+
625
+ The library includes factory classes for generating mock data in tests.
626
+
627
+ #### Import Path
628
+
629
+ ```typescript
630
+ import {
631
+ BusinessFactory,
632
+ IndividualFactory,
633
+ DealFactory,
634
+ NoteFactory,
635
+ } from '@wisemen/wise-crm-web/testing'
636
+ ```
637
+
638
+ ### `BusinessFactory`
639
+
640
+ #### Methods
641
+
642
+ ##### `createDetail(overrides?): ViewBusinessDetailResponse`
643
+
644
+ Create a mock business detail object.
645
+
646
+ ```typescript
647
+ const business = BusinessFactory.createDetail({
648
+ name: 'Custom Corp',
649
+ email: 'custom@example.com',
650
+ })
651
+ ```
652
+
653
+ ##### `createIndex(overrides?): ViewBusinessIndexResponseItem`
654
+
655
+ Create a mock business list item.
656
+
657
+ ```typescript
658
+ const businessItem = BusinessFactory.createIndex({
659
+ name: 'List Item Corp',
660
+ })
661
+ ```
662
+
663
+ ##### `createIndexList(count, overrides?): ViewBusinessIndexResponseItem[]`
664
+
665
+ Create an array of mock business list items.
666
+
667
+ ```typescript
668
+ const businesses = BusinessFactory.createIndexList(10)
669
+ ```
670
+
671
+ ##### `createBillingInformation(overrides?): ViewBusinessBillingInformationDetailResponse`
672
+
673
+ Create mock billing information.
674
+
675
+ ```typescript
676
+ const billing = BusinessFactory.createBillingInformation({
677
+ invoiceEmail: 'billing@example.com',
678
+ })
679
+ ```
680
+
681
+ ##### `createContactPerson(overrides?): BusinessContactPersonResponse`
682
+
683
+ Create a mock contact person.
684
+
685
+ ```typescript
686
+ const contact = BusinessFactory.createContactPerson({
687
+ firstName: 'John',
688
+ lastName: 'Doe',
689
+ })
690
+ ```
691
+
692
+ ##### `createStatistics(overrides?): ViewBusinessStatisticsResponse`
693
+
694
+ Create mock business statistics.
695
+
696
+ ```typescript
697
+ const stats = BusinessFactory.createStatistics({
698
+ total: 100,
699
+ monthlyAdded: 10,
700
+ })
701
+ ```
702
+
703
+ ### `IndividualFactory`
704
+
705
+ Similar methods to `BusinessFactory` for individual entities:
706
+
707
+ - `createDetail(overrides?)`
708
+ - `createIndex(overrides?)`
709
+ - `createIndexList(count, overrides?)`
710
+ - `createBillingInformation(overrides?)`
711
+ - `createStatistics(overrides?)`
712
+
713
+ ### `DealFactory`
714
+
715
+ - `createDetail(overrides?)`
716
+ - `createIndex(overrides?)`
717
+ - `createIndexList(count, overrides?)`
718
+
719
+ ### `NoteFactory`
720
+
721
+ - `create(overrides?)`
722
+ - `createList(count, overrides?)`
723
+
724
+ ### Testing Example
725
+
726
+ ```typescript
727
+ import { expect, test } from '@playwright/test'
728
+ import { BusinessFactory } from '@wisemen/wise-crm-web/testing'
729
+ import { HttpResponse } from 'msw'
730
+
731
+ test('Create business', async ({ page, http, worker }) => {
732
+ const mockBusiness = BusinessFactory.createDetail({
733
+ name: 'Test Business',
734
+ })
735
+
736
+ await worker.use(
737
+ http.post('*/api/v1/businesses', () => {
738
+ return HttpResponse.json(
739
+ { uuid: mockBusiness.uuid },
740
+ { status: 201 }
741
+ )
742
+ }),
743
+ http.get(`*/api/v1/businesses/${mockBusiness.uuid}`, () => {
744
+ return HttpResponse.json(mockBusiness)
745
+ }),
746
+ )
747
+
748
+ await page.goto('/crm/businesses')
749
+ // ... rest of test
750
+ })
751
+ ```
752
+
753
+ ---
754
+
755
+ ## Type System
756
+
757
+ ### Entity UUID Types
758
+
759
+ The library exports branded UUID types for type safety:
760
+
761
+ ```typescript
762
+ import type {
763
+ WiseCrmBusinessUuid,
764
+ WiseCrmIndividualUuid,
765
+ } from '@wisemen/wise-crm-web'
766
+
767
+ // These are branded types that prevent mixing UUIDs
768
+ function updateBusiness(uuid: WiseCrmBusinessUuid): void {
769
+ // TypeScript ensures you can't pass WiseCrmIndividualUuid here
770
+ }
771
+ ```
772
+
773
+ ### Validation Schemas
774
+
775
+ UUID schemas for runtime validation:
776
+
777
+ ```typescript
778
+ import {
779
+ businessUuidSchema,
780
+ individualUuidSchema,
781
+ } from '@wisemen/wise-crm-web'
782
+
783
+ // Use with zod or similar validators
784
+ const result = businessUuidSchema.safeParse(value)
785
+ ```
786
+
787
+ ### Dialog Content Tabs
788
+
789
+ ```typescript
790
+ import type { WiseCrmDialogContentTab } from '@wisemen/wise-crm-web'
791
+
792
+ // Type for custom dialog tab content
793
+ const tabs: WiseCrmDialogContentTab[] = [
794
+ { label: 'General', component: GeneralTab },
795
+ { label: 'Advanced', component: AdvancedTab },
796
+ ]
797
+ ```
798
+
799
+ ---
800
+
801
+ ## Environment Variables
802
+
803
+ ### Required
804
+
805
+ ```env
806
+ # CRM API Base URL
807
+ API_CRM_BASE_URL=https://api.your-crm.com
808
+
809
+ # Google Maps API Key (for address autocomplete)
810
+ GOOGLE_MAPS_API_KEY=your_google_maps_api_key
811
+ ```
812
+
813
+ ### Example `.env`
814
+
815
+ ```env
816
+ API_CRM_BASE_URL=https://wise-crm.development.appwi.se
817
+ GOOGLE_MAPS_API_KEY=AIzaSyD0DOeAK9X_gXAtwPEyKPl4CaJc1dhKC9Q
818
+ ```
819
+
820
+ ---
821
+
822
+ ## Advanced Usage
823
+
824
+ ### Custom Field Definitions
825
+
826
+ Access custom field definitions for dynamic form generation:
827
+
828
+ ```typescript
829
+ import { EntityType } from '@wisemen/wise-crm-web/client'
830
+ import { useWiseCrmConfig } from '@wisemen/wise-crm-web'
831
+
832
+ const crmConfig = useWiseCrmConfig()
833
+
834
+ const customFields = crmConfig.getCustomFieldDefinitionForEntity(
835
+ EntityType.BUSINESS
836
+ )
837
+
838
+ // Use customFields to render dynamic form fields
839
+ ```
840
+
841
+ ### Entity Configuration
842
+
843
+ Get localized entity names and colors:
844
+
845
+ ```typescript
846
+ import { EntityType } from '@wisemen/wise-crm-web/client'
847
+ import { useWiseCrm } from '@wisemen/wise-crm-web'
848
+
849
+ const crm = useWiseCrm()
850
+ const businessConfig = crm.getEntityConfig(EntityType.BUSINESS)
851
+
852
+ console.log(businessConfig?.name) // "Business" or "Bedrijf"
853
+ console.log(businessConfig?.color) // "blue", "green", etc.
854
+ ```
855
+
856
+ ### CSS Custom Properties
857
+
858
+ The CRM automatically sets CSS custom properties for entity colors:
859
+
860
+ ```css
861
+ /* Available CSS variables */
862
+ --wise-crm-business-50
863
+ --wise-crm-business-100
864
+ --wise-crm-business-200
865
+ /* ... etc for all color shades */
866
+
867
+ --wise-crm-individual-50
868
+ --wise-crm-individual-100
869
+ /* ... etc */
870
+ ```
871
+
872
+ Use these in your custom components for consistent theming:
873
+
874
+ ```vue
875
+ <style scoped>
876
+ .business-badge {
877
+ background-color: var(--wise-crm-business-100);
878
+ color: var(--wise-crm-business-700);
879
+ }
880
+ </style>
881
+ ```
882
+
883
+ ---
884
+
885
+ ## Troubleshooting
886
+
887
+ ### "CRM Tenant Config not initialized" Error
888
+
889
+ **Cause:** Attempting to use CRM components before initialization.
890
+
891
+ **Solution:** Ensure `useWiseCrmConfig().init()` is called before rendering any CRM components. Use `isInitialized` to conditionally render:
892
+
893
+ ```vue
894
+ <script setup lang="ts">
895
+ import { useWiseCrmConfig } from '@wisemen/wise-crm-web'
896
+
897
+ const crmConfig = useWiseCrmConfig()
898
+
899
+ // Initialize in onMounted or similar
900
+ onMounted(async () => {
901
+ await crmConfig.init({ /* ... */ })
902
+ })
903
+ </script>
904
+
905
+ <template>
906
+ <div v-if="crmConfig.isInitialized.value">
907
+ <WiseCrmOverviewContent />
908
+ </div>
909
+ <div v-else>
910
+ Loading CRM...
911
+ </div>
912
+ </template>
913
+ ```
914
+
915
+ ### TypeScript Errors with Factory Methods
916
+
917
+ **Cause:** Stale TypeScript cache or build artifacts.
918
+
919
+ **Solution:**
920
+ 1. Restart TypeScript server: `Cmd+Shift+P` → "TypeScript: Restart TS Server"
921
+ 2. Rebuild packages: `pnpm build`
922
+ 3. Clear build cache: `rm -rf dist node_modules/.cache`
923
+
924
+ ### Address Autocomplete Not Working
925
+
926
+ **Cause:** Invalid or missing Google Maps API key.
927
+
928
+ **Solution:** Ensure your `GOOGLE_MAPS_API_KEY` environment variable is set and the key has the Places API enabled in Google Cloud Console.
929
+
930
+ ---
931
+
932
+ ## Examples
933
+
934
+ ### Complete Integration Example
935
+
936
+ ```vue
937
+ <!-- App.vue -->
938
+ <script setup lang="ts">
939
+ import { useWiseCrmConfig } from '@wisemen/wise-crm-web'
940
+ import { BoardColumnTransitionTriggerType } from '@wisemen/wise-crm-web/client'
941
+ import { onMounted } from 'vue'
942
+
943
+ const crmConfig = useWiseCrmConfig()
944
+
945
+ onMounted(async () => {
946
+ await crmConfig.init({
947
+ apiCrmBaseUrl: import.meta.env.API_CRM_BASE_URL,
948
+ getAccessToken: () => authClient.getToken(),
949
+ googleMapsApiKey: import.meta.env.GOOGLE_MAPS_API_KEY,
950
+ locale: 'en-US',
951
+ options: {
952
+ deals: {
953
+ allowedTransitionTriggerTypes: [
954
+ BoardColumnTransitionTriggerType.MANUAL,
955
+ ],
956
+ },
957
+ widgets: {
958
+ entityStatistics: {
959
+ viewAllBusinessRouteName: 'businesses',
960
+ viewAllIndividualRouteName: 'individuals',
961
+ },
962
+ recentlyCreatedEntities: true,
963
+ },
964
+ },
965
+ })
966
+ })
967
+ </script>
968
+
969
+ <template>
970
+ <RouterView v-if="crmConfig.isInitialized.value" />
971
+ </template>
972
+ ```
973
+
974
+ ```typescript
975
+ // router.ts
976
+ import { createRouter } from 'vue-router'
977
+ import { useWiseCrmRoutes } from '@wisemen/wise-crm-web'
978
+ import { computed } from 'vue'
979
+
980
+ const router = createRouter({
981
+ routes: [
982
+ {
983
+ path: '/crm',
984
+ children: [
985
+ {
986
+ name: 'crm-overview',
987
+ path: '',
988
+ component: () => import('./views/CrmOverview.vue'),
989
+ },
990
+ {
991
+ name: 'crm-businesses',
992
+ path: 'businesses',
993
+ component: () => import('./views/BusinessList.vue'),
994
+ },
995
+ {
996
+ name: 'crm-individuals',
997
+ path: 'individuals',
998
+ component: () => import('./views/IndividualList.vue'),
999
+ },
1000
+ ],
1001
+ },
1002
+ useWiseCrmRoutes({
1003
+ businessTabRoutes: [
1004
+ {
1005
+ label: computed(() => 'Information'),
1006
+ route: {
1007
+ name: 'business-info',
1008
+ path: 'information',
1009
+ component: () => import('./views/BusinessInfo.vue'),
1010
+ },
1011
+ },
1012
+ ],
1013
+ individualTabRoutes: [
1014
+ {
1015
+ label: computed(() => 'Information'),
1016
+ route: {
1017
+ name: 'individual-info',
1018
+ path: 'information',
1019
+ component: () => import('./views/IndividualInfo.vue'),
1020
+ },
1021
+ },
1022
+ ],
1023
+ dealTabRoutes: [],
1024
+ }),
1025
+ ],
1026
+ })
1027
+ ```
1028
+
1029
+ ---
1030
+
1031
+ ## License
1032
+
1033
+ MIT
1034
+
1035
+ ## Support
1036
+
1037
+ For issues and questions, please contact the WiseMen Digital team.