@hed-hog/contact 0.0.293 → 0.0.295
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/person/dto/account.dto.d.ts +28 -0
- package/dist/person/dto/account.dto.d.ts.map +1 -0
- package/dist/person/dto/account.dto.js +123 -0
- package/dist/person/dto/account.dto.js.map +1 -0
- package/dist/person/dto/activity.dto.d.ts +15 -0
- package/dist/person/dto/activity.dto.d.ts.map +1 -0
- package/dist/person/dto/activity.dto.js +65 -0
- package/dist/person/dto/activity.dto.js.map +1 -0
- package/dist/person/dto/dashboard-query.dto.d.ts +9 -0
- package/dist/person/dto/dashboard-query.dto.d.ts.map +1 -0
- package/dist/person/dto/dashboard-query.dto.js +40 -0
- package/dist/person/dto/dashboard-query.dto.js.map +1 -0
- package/dist/person/dto/followup-query.dto.d.ts +10 -0
- package/dist/person/dto/followup-query.dto.d.ts.map +1 -0
- package/dist/person/dto/followup-query.dto.js +45 -0
- package/dist/person/dto/followup-query.dto.js.map +1 -0
- package/dist/person/person.controller.d.ts +204 -0
- package/dist/person/person.controller.d.ts.map +1 -1
- package/dist/person/person.controller.js +138 -0
- package/dist/person/person.controller.js.map +1 -1
- package/dist/person/person.service.d.ts +234 -0
- package/dist/person/person.service.d.ts.map +1 -1
- package/dist/person/person.service.js +1367 -0
- package/dist/person/person.service.js.map +1 -1
- package/hedhog/data/menu.yaml +163 -163
- package/hedhog/data/route.yaml +41 -0
- package/hedhog/frontend/app/accounts/_components/account-form-sheet.tsx.ejs +210 -114
- package/hedhog/frontend/app/accounts/_components/account-types.ts.ejs +3 -0
- package/hedhog/frontend/app/accounts/page.tsx.ejs +323 -245
- package/hedhog/frontend/app/activities/_components/activity-detail-sheet.tsx.ejs +240 -0
- package/hedhog/frontend/app/activities/_components/activity-types.ts.ejs +66 -0
- package/hedhog/frontend/app/activities/page.tsx.ejs +165 -517
- package/hedhog/frontend/app/dashboard/_components/dashboard-types.ts.ejs +70 -0
- package/hedhog/frontend/app/dashboard/page.tsx.ejs +504 -356
- package/hedhog/frontend/app/follow-ups/page.tsx.ejs +242 -153
- package/hedhog/frontend/messages/en.json +91 -6
- package/hedhog/frontend/messages/pt.json +91 -6
- package/hedhog/table/crm_activity.yaml +68 -0
- package/hedhog/table/person_company.yaml +22 -0
- package/package.json +5 -5
- package/src/person/dto/account.dto.ts +100 -0
- package/src/person/dto/activity.dto.ts +54 -0
- package/src/person/dto/dashboard-query.dto.ts +25 -0
- package/src/person/dto/followup-query.dto.ts +25 -0
- package/src/person/person.controller.ts +116 -0
- package/src/person/person.service.ts +2139 -77
|
@@ -451,7 +451,7 @@
|
|
|
451
451
|
},
|
|
452
452
|
"CrmDashboard": {
|
|
453
453
|
"title": "CRM Dashboard",
|
|
454
|
-
"subtitle": "Executive and operational CRM panel
|
|
454
|
+
"subtitle": "Executive and operational CRM panel connected to the real data of the current module.",
|
|
455
455
|
"breadcrumbs": {
|
|
456
456
|
"home": "Home",
|
|
457
457
|
"crm": "CRM"
|
|
@@ -462,6 +462,17 @@
|
|
|
462
462
|
"primaryAction": "Open pipeline",
|
|
463
463
|
"secondaryAction": "View leads and contacts",
|
|
464
464
|
"refresh": "Refresh",
|
|
465
|
+
"filters": {
|
|
466
|
+
"ownerPlaceholder": "Owner",
|
|
467
|
+
"ownerAll": "All owners",
|
|
468
|
+
"periodPlaceholder": "Period",
|
|
469
|
+
"period7d": "Last 7 days",
|
|
470
|
+
"period30d": "Last 30 days",
|
|
471
|
+
"period90d": "Last 90 days",
|
|
472
|
+
"periodCustom": "Custom range",
|
|
473
|
+
"dateFrom": "Start date",
|
|
474
|
+
"dateTo": "End date"
|
|
475
|
+
},
|
|
465
476
|
"summary": {
|
|
466
477
|
"pipelineValue": "Pipeline value",
|
|
467
478
|
"conversionRate": "Overall conversion",
|
|
@@ -508,7 +519,7 @@
|
|
|
508
519
|
},
|
|
509
520
|
"source": {
|
|
510
521
|
"title": "Lead source mix",
|
|
511
|
-
"description": "Share of the main sources inside the
|
|
522
|
+
"description": "Share of the main sources inside the filtered CRM base."
|
|
512
523
|
},
|
|
513
524
|
"owner": {
|
|
514
525
|
"title": "Owner performance",
|
|
@@ -554,7 +565,8 @@
|
|
|
554
565
|
"other": "Other"
|
|
555
566
|
},
|
|
556
567
|
"common": {
|
|
557
|
-
"unassigned": "Unassigned"
|
|
568
|
+
"unassigned": "Unassigned",
|
|
569
|
+
"noData": "No data for the current filters."
|
|
558
570
|
}
|
|
559
571
|
},
|
|
560
572
|
"CrmPipeline": {
|
|
@@ -686,6 +698,9 @@
|
|
|
686
698
|
"form": {
|
|
687
699
|
"person": "Person",
|
|
688
700
|
"personPlaceholder": "Select a person",
|
|
701
|
+
"personSearchPlaceholder": "Search person...",
|
|
702
|
+
"personLoading": "Loading people...",
|
|
703
|
+
"personEmpty": "No people found.",
|
|
689
704
|
"date": "Follow-up date",
|
|
690
705
|
"notes": "Notes",
|
|
691
706
|
"notesPlaceholder": "Add context for the next interaction...",
|
|
@@ -766,9 +781,36 @@
|
|
|
766
781
|
"description": "Adjust filters to find activities or clear filters to return to the full queue.",
|
|
767
782
|
"resetFilters": "Clear filters"
|
|
768
783
|
},
|
|
784
|
+
"detail": {
|
|
785
|
+
"title": "Activity details",
|
|
786
|
+
"description": "Review the full operational context before acting on this activity.",
|
|
787
|
+
"person": "Person",
|
|
788
|
+
"personType": "Person type",
|
|
789
|
+
"personTypeValue": {
|
|
790
|
+
"individual": "Individual",
|
|
791
|
+
"company": "Company"
|
|
792
|
+
},
|
|
793
|
+
"tradeName": "Trade name",
|
|
794
|
+
"owner": "Owner",
|
|
795
|
+
"type": "Type",
|
|
796
|
+
"source": "Source",
|
|
797
|
+
"dueAt": "Due at",
|
|
798
|
+
"createdAt": "Created at",
|
|
799
|
+
"completedAt": "Completed at",
|
|
800
|
+
"createdBy": "Created by",
|
|
801
|
+
"completedBy": "Completed by",
|
|
802
|
+
"close": "Close",
|
|
803
|
+
"emptyNotes": "No notes provided.",
|
|
804
|
+
"notCompleted": "Not completed",
|
|
805
|
+
"sourceKind": {
|
|
806
|
+
"manual": "Manual",
|
|
807
|
+
"followup": "Follow-up",
|
|
808
|
+
"interaction": "Interaction"
|
|
809
|
+
}
|
|
810
|
+
},
|
|
769
811
|
"toasts": {
|
|
770
812
|
"markedAsCompleted": "Activity marked as completed.",
|
|
771
|
-
"
|
|
813
|
+
"completeError": "Failed to complete activity."
|
|
772
814
|
}
|
|
773
815
|
},
|
|
774
816
|
"CrmFuturePage": {
|
|
@@ -835,6 +877,49 @@
|
|
|
835
877
|
"email": "Email",
|
|
836
878
|
"phone": "Phone",
|
|
837
879
|
"website": "Website",
|
|
838
|
-
|
|
880
|
+
"industry": "Industry",
|
|
881
|
+
"saveError": "Failed to save account",
|
|
882
|
+
"deleteError": "Failed to delete account",
|
|
883
|
+
"form": {
|
|
884
|
+
"createTitle": "New Account",
|
|
885
|
+
"editTitle": "Edit Account",
|
|
886
|
+
"createDescription": "Create a new account record in the CRM.",
|
|
887
|
+
"editDescription": "Update the account information and relationship details.",
|
|
888
|
+
"companyName": "Company Name",
|
|
889
|
+
"tradeName": "Trade Name",
|
|
890
|
+
"status": "Status",
|
|
891
|
+
"lifecycleStage": "Stage",
|
|
892
|
+
"email": "Email",
|
|
893
|
+
"phone": "Phone",
|
|
894
|
+
"website": "Website",
|
|
895
|
+
"industry": "Industry",
|
|
896
|
+
"annualRevenue": "Annual Revenue",
|
|
897
|
+
"employeeCount": "Employees",
|
|
898
|
+
"city": "City",
|
|
899
|
+
"state": "State",
|
|
900
|
+
"owner": "Owner",
|
|
901
|
+
"createSubmit": "Create Account",
|
|
902
|
+
"updateSubmit": "Save Changes",
|
|
903
|
+
"saving": "Saving...",
|
|
904
|
+
"placeholders": {
|
|
905
|
+
"companyName": "Company name",
|
|
906
|
+
"tradeName": "Trade name or brand",
|
|
907
|
+
"email": "contact@company.com",
|
|
908
|
+
"phone": "(11) 99999-9999",
|
|
909
|
+
"website": "www.company.com",
|
|
910
|
+
"industry": "Technology, Healthcare...",
|
|
911
|
+
"annualRevenue": "0.00",
|
|
912
|
+
"employeeCount": "0",
|
|
913
|
+
"city": "Sao Paulo",
|
|
914
|
+
"state": "SP"
|
|
915
|
+
},
|
|
916
|
+
"validation": {
|
|
917
|
+
"nameMinLength": "Name must be at least 2 characters",
|
|
918
|
+
"invalidEmail": "Enter a valid email address",
|
|
919
|
+
"nonNegativeNumber": "Enter zero or a positive number",
|
|
920
|
+
"integerRequired": "Enter a whole number",
|
|
921
|
+
"stateMaxLength": "State must be at most 2 characters"
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
839
925
|
}
|
|
840
|
-
}
|
|
@@ -450,7 +450,7 @@
|
|
|
450
450
|
},
|
|
451
451
|
"CrmDashboard": {
|
|
452
452
|
"title": "Dashboard CRM",
|
|
453
|
-
"subtitle": "Painel executivo e operacional do funil comercial
|
|
453
|
+
"subtitle": "Painel executivo e operacional do funil comercial conectado aos dados reais do módulo atual.",
|
|
454
454
|
"breadcrumbs": {
|
|
455
455
|
"home": "Home",
|
|
456
456
|
"crm": "CRM"
|
|
@@ -461,6 +461,17 @@
|
|
|
461
461
|
"primaryAction": "Abrir pipeline",
|
|
462
462
|
"secondaryAction": "Ver leads e contatos",
|
|
463
463
|
"refresh": "Atualizar",
|
|
464
|
+
"filters": {
|
|
465
|
+
"ownerPlaceholder": "Responsável",
|
|
466
|
+
"ownerAll": "Todos os responsáveis",
|
|
467
|
+
"periodPlaceholder": "Período",
|
|
468
|
+
"period7d": "Últimos 7 dias",
|
|
469
|
+
"period30d": "Últimos 30 dias",
|
|
470
|
+
"period90d": "Últimos 90 dias",
|
|
471
|
+
"periodCustom": "Intervalo customizado",
|
|
472
|
+
"dateFrom": "Data inicial",
|
|
473
|
+
"dateTo": "Data final"
|
|
474
|
+
},
|
|
464
475
|
"summary": {
|
|
465
476
|
"pipelineValue": "Valor em pipeline",
|
|
466
477
|
"conversionRate": "Conversão geral",
|
|
@@ -507,7 +518,7 @@
|
|
|
507
518
|
},
|
|
508
519
|
"source": {
|
|
509
520
|
"title": "Origem dos leads",
|
|
510
|
-
"description": "Participação das principais origens dentro da base
|
|
521
|
+
"description": "Participação das principais origens dentro da base filtrada do CRM."
|
|
511
522
|
},
|
|
512
523
|
"owner": {
|
|
513
524
|
"title": "Performance por owner",
|
|
@@ -553,7 +564,8 @@
|
|
|
553
564
|
"other": "Outro"
|
|
554
565
|
},
|
|
555
566
|
"common": {
|
|
556
|
-
"unassigned": "Não atribuído"
|
|
567
|
+
"unassigned": "Não atribuído",
|
|
568
|
+
"noData": "Não há dados para os filtros atuais."
|
|
557
569
|
}
|
|
558
570
|
},
|
|
559
571
|
"CrmPipeline": {
|
|
@@ -685,6 +697,9 @@
|
|
|
685
697
|
"form": {
|
|
686
698
|
"person": "Pessoa",
|
|
687
699
|
"personPlaceholder": "Selecione uma pessoa",
|
|
700
|
+
"personSearchPlaceholder": "Buscar pessoa...",
|
|
701
|
+
"personLoading": "Carregando pessoas...",
|
|
702
|
+
"personEmpty": "Nenhuma pessoa encontrada.",
|
|
688
703
|
"date": "Data do follow-up",
|
|
689
704
|
"notes": "Notas",
|
|
690
705
|
"notesPlaceholder": "Adicione contexto para a próxima interação...",
|
|
@@ -765,9 +780,36 @@
|
|
|
765
780
|
"description": "Ajuste os filtros para encontrar atividades ou limpe os filtros para voltar à fila completa.",
|
|
766
781
|
"resetFilters": "Limpar filtros"
|
|
767
782
|
},
|
|
783
|
+
"detail": {
|
|
784
|
+
"title": "Detalhes da atividade",
|
|
785
|
+
"description": "Revise todo o contexto operacional antes de agir sobre esta atividade.",
|
|
786
|
+
"person": "Pessoa",
|
|
787
|
+
"personType": "Tipo de pessoa",
|
|
788
|
+
"personTypeValue": {
|
|
789
|
+
"individual": "Pessoa física",
|
|
790
|
+
"company": "Empresa"
|
|
791
|
+
},
|
|
792
|
+
"tradeName": "Nome fantasia",
|
|
793
|
+
"owner": "Responsável",
|
|
794
|
+
"type": "Tipo",
|
|
795
|
+
"source": "Origem",
|
|
796
|
+
"dueAt": "Prazo",
|
|
797
|
+
"createdAt": "Criada em",
|
|
798
|
+
"completedAt": "Concluída em",
|
|
799
|
+
"createdBy": "Criada por",
|
|
800
|
+
"completedBy": "Concluída por",
|
|
801
|
+
"close": "Fechar",
|
|
802
|
+
"emptyNotes": "Nenhuma nota informada.",
|
|
803
|
+
"notCompleted": "Não concluída",
|
|
804
|
+
"sourceKind": {
|
|
805
|
+
"manual": "Manual",
|
|
806
|
+
"followup": "Follow-up",
|
|
807
|
+
"interaction": "Interação"
|
|
808
|
+
}
|
|
809
|
+
},
|
|
768
810
|
"toasts": {
|
|
769
811
|
"markedAsCompleted": "Atividade marcada como concluída.",
|
|
770
|
-
"
|
|
812
|
+
"completeError": "Falha ao concluir atividade."
|
|
771
813
|
}
|
|
772
814
|
},
|
|
773
815
|
"CrmFuturePage": {
|
|
@@ -834,6 +876,49 @@
|
|
|
834
876
|
"email": "Email",
|
|
835
877
|
"phone": "Telefone",
|
|
836
878
|
"website": "Site",
|
|
837
|
-
|
|
879
|
+
"industry": "Setor",
|
|
880
|
+
"saveError": "Nao foi possivel salvar a conta",
|
|
881
|
+
"deleteError": "Nao foi possivel excluir a conta",
|
|
882
|
+
"form": {
|
|
883
|
+
"createTitle": "Nova Conta",
|
|
884
|
+
"editTitle": "Editar Conta",
|
|
885
|
+
"createDescription": "Crie um novo registro de conta no CRM.",
|
|
886
|
+
"editDescription": "Atualize as informacoes da conta e do relacionamento.",
|
|
887
|
+
"companyName": "Nome da empresa",
|
|
888
|
+
"tradeName": "Nome fantasia",
|
|
889
|
+
"status": "Status",
|
|
890
|
+
"lifecycleStage": "Estagio",
|
|
891
|
+
"email": "Email",
|
|
892
|
+
"phone": "Telefone",
|
|
893
|
+
"website": "Site",
|
|
894
|
+
"industry": "Setor",
|
|
895
|
+
"annualRevenue": "Receita anual",
|
|
896
|
+
"employeeCount": "Colaboradores",
|
|
897
|
+
"city": "Cidade",
|
|
898
|
+
"state": "Estado",
|
|
899
|
+
"owner": "Responsavel",
|
|
900
|
+
"createSubmit": "Criar conta",
|
|
901
|
+
"updateSubmit": "Salvar alteracoes",
|
|
902
|
+
"saving": "Salvando...",
|
|
903
|
+
"placeholders": {
|
|
904
|
+
"companyName": "Nome da empresa",
|
|
905
|
+
"tradeName": "Nome fantasia ou marca",
|
|
906
|
+
"email": "contato@empresa.com",
|
|
907
|
+
"phone": "(11) 99999-9999",
|
|
908
|
+
"website": "www.empresa.com",
|
|
909
|
+
"industry": "Tecnologia, Saude...",
|
|
910
|
+
"annualRevenue": "0,00",
|
|
911
|
+
"employeeCount": "0",
|
|
912
|
+
"city": "Sao Paulo",
|
|
913
|
+
"state": "SP"
|
|
914
|
+
},
|
|
915
|
+
"validation": {
|
|
916
|
+
"nameMinLength": "O nome deve ter pelo menos 2 caracteres",
|
|
917
|
+
"invalidEmail": "Informe um email valido",
|
|
918
|
+
"nonNegativeNumber": "Informe zero ou um numero positivo",
|
|
919
|
+
"integerRequired": "Informe um numero inteiro",
|
|
920
|
+
"stateMaxLength": "O estado deve ter no maximo 2 caracteres"
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
838
924
|
}
|
|
839
|
-
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
table: crm_activity
|
|
2
|
+
columns:
|
|
3
|
+
- type: pk
|
|
4
|
+
- name: person_id
|
|
5
|
+
type: fk
|
|
6
|
+
references:
|
|
7
|
+
table: person
|
|
8
|
+
column: id
|
|
9
|
+
onDelete: CASCADE
|
|
10
|
+
onUpdate: CASCADE
|
|
11
|
+
- name: owner_user_id
|
|
12
|
+
type: fk
|
|
13
|
+
isNullable: true
|
|
14
|
+
references:
|
|
15
|
+
table: user
|
|
16
|
+
column: id
|
|
17
|
+
onDelete: SET NULL
|
|
18
|
+
onUpdate: CASCADE
|
|
19
|
+
- name: created_by_user_id
|
|
20
|
+
type: fk
|
|
21
|
+
isNullable: true
|
|
22
|
+
references:
|
|
23
|
+
table: user
|
|
24
|
+
column: id
|
|
25
|
+
onDelete: SET NULL
|
|
26
|
+
onUpdate: CASCADE
|
|
27
|
+
- name: completed_by_user_id
|
|
28
|
+
type: fk
|
|
29
|
+
isNullable: true
|
|
30
|
+
references:
|
|
31
|
+
table: user
|
|
32
|
+
column: id
|
|
33
|
+
onDelete: SET NULL
|
|
34
|
+
onUpdate: CASCADE
|
|
35
|
+
- name: type
|
|
36
|
+
type: enum
|
|
37
|
+
values: [call, email, meeting, whatsapp, task, note]
|
|
38
|
+
- name: subject
|
|
39
|
+
type: varchar
|
|
40
|
+
length: 255
|
|
41
|
+
- name: notes
|
|
42
|
+
type: text
|
|
43
|
+
isNullable: true
|
|
44
|
+
- name: due_at
|
|
45
|
+
type: datetime
|
|
46
|
+
- name: completed_at
|
|
47
|
+
type: datetime
|
|
48
|
+
isNullable: true
|
|
49
|
+
- name: priority
|
|
50
|
+
type: enum
|
|
51
|
+
values: [high, medium, low]
|
|
52
|
+
default: medium
|
|
53
|
+
- name: source_kind
|
|
54
|
+
type: enum
|
|
55
|
+
values: [manual, followup, interaction]
|
|
56
|
+
default: manual
|
|
57
|
+
- type: created_at
|
|
58
|
+
- type: updated_at
|
|
59
|
+
|
|
60
|
+
indices:
|
|
61
|
+
- columns: [person_id]
|
|
62
|
+
- columns: [owner_user_id]
|
|
63
|
+
- columns: [due_at]
|
|
64
|
+
- columns: [completed_at]
|
|
65
|
+
- columns: [completed_at, due_at]
|
|
66
|
+
- columns: [person_id, source_kind]
|
|
67
|
+
isUnique: true
|
|
68
|
+
where: source_kind = 'followup' AND completed_at IS NULL
|
|
@@ -6,6 +6,28 @@ columns:
|
|
|
6
6
|
column: id
|
|
7
7
|
- name: trade_name
|
|
8
8
|
isNullable: true
|
|
9
|
+
- name: industry
|
|
10
|
+
isNullable: true
|
|
11
|
+
- name: website
|
|
12
|
+
isNullable: true
|
|
13
|
+
- name: annual_revenue
|
|
14
|
+
type: decimal
|
|
15
|
+
precision: 14
|
|
16
|
+
scale: 2
|
|
17
|
+
isNullable: true
|
|
18
|
+
- name: employee_count
|
|
19
|
+
type: int
|
|
20
|
+
isNullable: true
|
|
21
|
+
- name: account_lifecycle_stage
|
|
22
|
+
type: enum
|
|
23
|
+
values: [prospect, customer, churned, inactive]
|
|
24
|
+
isNullable: true
|
|
25
|
+
- name: city
|
|
26
|
+
isNullable: true
|
|
27
|
+
- name: state
|
|
28
|
+
type: varchar
|
|
29
|
+
length: 2
|
|
30
|
+
isNullable: true
|
|
9
31
|
- name: foundation_date
|
|
10
32
|
type: date
|
|
11
33
|
isNullable: true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/contact",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.295",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
-
"@hed-hog/core": "0.0.
|
|
13
|
-
"@hed-hog/api-locale": "0.0.13",
|
|
14
|
-
"@hed-hog/api-prisma": "0.0.5",
|
|
15
|
-
"@hed-hog/address": "0.0.293",
|
|
12
|
+
"@hed-hog/core": "0.0.295",
|
|
16
13
|
"@hed-hog/api-mail": "0.0.8",
|
|
14
|
+
"@hed-hog/api-prisma": "0.0.5",
|
|
15
|
+
"@hed-hog/api-locale": "0.0.13",
|
|
16
|
+
"@hed-hog/address": "0.0.295",
|
|
17
17
|
"@hed-hog/api": "0.0.4",
|
|
18
18
|
"@hed-hog/api-pagination": "0.0.6"
|
|
19
19
|
},
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Type } from 'class-transformer';
|
|
2
|
+
import {
|
|
3
|
+
IsEmail,
|
|
4
|
+
IsIn,
|
|
5
|
+
IsInt,
|
|
6
|
+
IsNumber,
|
|
7
|
+
IsOptional,
|
|
8
|
+
IsString,
|
|
9
|
+
MaxLength,
|
|
10
|
+
} from 'class-validator';
|
|
11
|
+
import { PersonStatus } from './create.dto';
|
|
12
|
+
|
|
13
|
+
export const ACCOUNT_LIFECYCLE_STAGES = [
|
|
14
|
+
'prospect',
|
|
15
|
+
'customer',
|
|
16
|
+
'churned',
|
|
17
|
+
'inactive',
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
export type AccountLifecycleStage = (typeof ACCOUNT_LIFECYCLE_STAGES)[number];
|
|
21
|
+
|
|
22
|
+
export class AccountListQueryDTO {
|
|
23
|
+
@IsOptional()
|
|
24
|
+
@IsString()
|
|
25
|
+
search?: string;
|
|
26
|
+
|
|
27
|
+
@IsOptional()
|
|
28
|
+
@IsIn(['all', PersonStatus.ACTIVE, PersonStatus.INACTIVE])
|
|
29
|
+
status?: 'all' | PersonStatus;
|
|
30
|
+
|
|
31
|
+
@IsOptional()
|
|
32
|
+
@IsIn(['all', ...ACCOUNT_LIFECYCLE_STAGES])
|
|
33
|
+
lifecycle_stage?: 'all' | AccountLifecycleStage;
|
|
34
|
+
|
|
35
|
+
@IsOptional()
|
|
36
|
+
@IsIn(['name', 'created_at'])
|
|
37
|
+
sortField?: 'name' | 'created_at';
|
|
38
|
+
|
|
39
|
+
@IsOptional()
|
|
40
|
+
@IsIn(['asc', 'desc'])
|
|
41
|
+
sortOrder?: 'asc' | 'desc';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class CreateAccountDTO {
|
|
45
|
+
@IsString()
|
|
46
|
+
name: string;
|
|
47
|
+
|
|
48
|
+
@IsOptional()
|
|
49
|
+
@IsString()
|
|
50
|
+
trade_name?: string | null;
|
|
51
|
+
|
|
52
|
+
@IsIn([PersonStatus.ACTIVE, PersonStatus.INACTIVE])
|
|
53
|
+
status: PersonStatus;
|
|
54
|
+
|
|
55
|
+
@IsOptional()
|
|
56
|
+
@IsString()
|
|
57
|
+
industry?: string | null;
|
|
58
|
+
|
|
59
|
+
@IsOptional()
|
|
60
|
+
@IsString()
|
|
61
|
+
website?: string | null;
|
|
62
|
+
|
|
63
|
+
@IsOptional()
|
|
64
|
+
@IsEmail()
|
|
65
|
+
email?: string | null;
|
|
66
|
+
|
|
67
|
+
@IsOptional()
|
|
68
|
+
@IsString()
|
|
69
|
+
phone?: string | null;
|
|
70
|
+
|
|
71
|
+
@IsOptional()
|
|
72
|
+
@Type(() => Number)
|
|
73
|
+
@IsInt()
|
|
74
|
+
owner_user_id?: number | null;
|
|
75
|
+
|
|
76
|
+
@IsOptional()
|
|
77
|
+
@Type(() => Number)
|
|
78
|
+
@IsNumber()
|
|
79
|
+
annual_revenue?: number | null;
|
|
80
|
+
|
|
81
|
+
@IsOptional()
|
|
82
|
+
@Type(() => Number)
|
|
83
|
+
@IsInt()
|
|
84
|
+
employee_count?: number | null;
|
|
85
|
+
|
|
86
|
+
@IsOptional()
|
|
87
|
+
@IsIn(ACCOUNT_LIFECYCLE_STAGES)
|
|
88
|
+
lifecycle_stage?: AccountLifecycleStage | null;
|
|
89
|
+
|
|
90
|
+
@IsOptional()
|
|
91
|
+
@IsString()
|
|
92
|
+
city?: string | null;
|
|
93
|
+
|
|
94
|
+
@IsOptional()
|
|
95
|
+
@IsString()
|
|
96
|
+
@MaxLength(2)
|
|
97
|
+
state?: string | null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class UpdateAccountDTO extends CreateAccountDTO {}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getLocaleText } from '@hed-hog/api-locale';
|
|
2
|
+
import { IsIn, IsOptional, IsString } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
export const CRM_ACTIVITY_TYPES = [
|
|
5
|
+
'call',
|
|
6
|
+
'email',
|
|
7
|
+
'meeting',
|
|
8
|
+
'whatsapp',
|
|
9
|
+
'task',
|
|
10
|
+
'note',
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
export const CRM_ACTIVITY_PRIORITIES = ['high', 'medium', 'low'] as const;
|
|
14
|
+
export const CRM_ACTIVITY_STATUSES = [
|
|
15
|
+
'pending',
|
|
16
|
+
'overdue',
|
|
17
|
+
'completed',
|
|
18
|
+
] as const;
|
|
19
|
+
export const CRM_ACTIVITY_SOURCE_KINDS = [
|
|
20
|
+
'manual',
|
|
21
|
+
'followup',
|
|
22
|
+
'interaction',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
export type CrmActivityType = (typeof CRM_ACTIVITY_TYPES)[number];
|
|
26
|
+
export type CrmActivityPriority = (typeof CRM_ACTIVITY_PRIORITIES)[number];
|
|
27
|
+
export type CrmActivityStatus = (typeof CRM_ACTIVITY_STATUSES)[number];
|
|
28
|
+
export type CrmActivitySourceKind = (typeof CRM_ACTIVITY_SOURCE_KINDS)[number];
|
|
29
|
+
|
|
30
|
+
export class ActivityListQueryDTO {
|
|
31
|
+
@IsOptional()
|
|
32
|
+
@IsString({
|
|
33
|
+
message: (args) => getLocaleText('validation.stringRequired', args.value),
|
|
34
|
+
})
|
|
35
|
+
search?: string;
|
|
36
|
+
|
|
37
|
+
@IsOptional()
|
|
38
|
+
@IsIn(['all', ...CRM_ACTIVITY_STATUSES], {
|
|
39
|
+
message: (args) => getLocaleText('validation.typeMustBeEnum', args.value),
|
|
40
|
+
})
|
|
41
|
+
status?: 'all' | CrmActivityStatus;
|
|
42
|
+
|
|
43
|
+
@IsOptional()
|
|
44
|
+
@IsIn(['all', ...CRM_ACTIVITY_TYPES], {
|
|
45
|
+
message: (args) => getLocaleText('validation.typeMustBeEnum', args.value),
|
|
46
|
+
})
|
|
47
|
+
type?: 'all' | CrmActivityType;
|
|
48
|
+
|
|
49
|
+
@IsOptional()
|
|
50
|
+
@IsIn(['all', ...CRM_ACTIVITY_PRIORITIES], {
|
|
51
|
+
message: (args) => getLocaleText('validation.typeMustBeEnum', args.value),
|
|
52
|
+
})
|
|
53
|
+
priority?: 'all' | CrmActivityPriority;
|
|
54
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Type } from 'class-transformer';
|
|
2
|
+
import { IsDateString, IsIn, IsInt, IsOptional } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
export const CRM_DASHBOARD_PERIODS = ['7d', '30d', '90d', 'custom'] as const;
|
|
5
|
+
|
|
6
|
+
export type CrmDashboardPeriod = (typeof CRM_DASHBOARD_PERIODS)[number];
|
|
7
|
+
|
|
8
|
+
export class DashboardQueryDTO {
|
|
9
|
+
@IsOptional()
|
|
10
|
+
@Type(() => Number)
|
|
11
|
+
@IsInt()
|
|
12
|
+
owner_user_id?: number;
|
|
13
|
+
|
|
14
|
+
@IsOptional()
|
|
15
|
+
@IsIn(CRM_DASHBOARD_PERIODS)
|
|
16
|
+
period?: CrmDashboardPeriod;
|
|
17
|
+
|
|
18
|
+
@IsOptional()
|
|
19
|
+
@IsDateString()
|
|
20
|
+
date_from?: string;
|
|
21
|
+
|
|
22
|
+
@IsOptional()
|
|
23
|
+
@IsDateString()
|
|
24
|
+
date_to?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IsIn, IsOptional, IsString, Matches } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class FollowupListQueryDTO {
|
|
4
|
+
@IsOptional()
|
|
5
|
+
@IsString()
|
|
6
|
+
search?: string;
|
|
7
|
+
|
|
8
|
+
@IsOptional()
|
|
9
|
+
@IsIn(['all', 'today', 'upcoming', 'overdue'])
|
|
10
|
+
status?: 'all' | 'today' | 'upcoming' | 'overdue';
|
|
11
|
+
|
|
12
|
+
@IsOptional()
|
|
13
|
+
@Matches(/^\d{4}-\d{2}-\d{2}$/)
|
|
14
|
+
date_from?: string;
|
|
15
|
+
|
|
16
|
+
@IsOptional()
|
|
17
|
+
@Matches(/^\d{4}-\d{2}-\d{2}$/)
|
|
18
|
+
date_to?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class FollowupStatsQueryDTO {
|
|
22
|
+
@IsOptional()
|
|
23
|
+
@IsString()
|
|
24
|
+
search?: string;
|
|
25
|
+
}
|