@nexxtmove/ui 0.1.24 → 0.1.26
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/index.d.ts +75 -1
- package/dist/index.js +1500 -1066
- package/dist/nuxt.js +20 -17
- package/package.json +1 -1
- package/src/components/AnimatedNumber/AnimatedNumber.vue +4 -0
- package/src/components/TimelineEvent/TimelineEvent.stories.ts +291 -0
- package/src/components/TimelineEvent/TimelineEvent.test.ts +166 -0
- package/src/components/TimelineEvent/TimelineEvent.vue +115 -0
- package/src/components/TimelineEvent/TimelineTypes.ts +236 -0
- package/src/components/TimelinePhaseblock/TimelinePhaseblock.stories.ts +198 -0
- package/src/components/TimelinePhaseblock/TimelinePhaseblock.test.ts +283 -0
- package/src/components/TimelinePhaseblock/TimelinePhaseblock.vue +158 -0
- package/src/components/Tooltip/Tooltip.stories.ts +146 -0
- package/src/components/Tooltip/Tooltip.test.ts +122 -0
- package/src/components/Tooltip/Tooltip.vue +49 -0
- package/src/components.json +4 -1
- package/src/index.ts +3 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
export interface TimelineEvent {
|
|
2
|
+
id: number
|
|
3
|
+
type: string
|
|
4
|
+
happened_at: string
|
|
5
|
+
medium_type: string | null
|
|
6
|
+
url: string | null
|
|
7
|
+
page_title: string | null
|
|
8
|
+
request_reason: string | null
|
|
9
|
+
agenda_item_type: string | null
|
|
10
|
+
source: string
|
|
11
|
+
direction: string
|
|
12
|
+
description: string | null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TimelinePhase {
|
|
16
|
+
phase: {
|
|
17
|
+
value: number
|
|
18
|
+
}
|
|
19
|
+
entered_at: string | null
|
|
20
|
+
exited_at: string | null
|
|
21
|
+
events: TimelineEvent[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TimelineResponse {
|
|
25
|
+
data: {
|
|
26
|
+
current_phase: {
|
|
27
|
+
value: number
|
|
28
|
+
entered_at?: string
|
|
29
|
+
}
|
|
30
|
+
phases: TimelinePhase[]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PhaseConfig {
|
|
35
|
+
label: string
|
|
36
|
+
color: string
|
|
37
|
+
bgColor: string
|
|
38
|
+
fromColor: string
|
|
39
|
+
toColor: string
|
|
40
|
+
textColor: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const EVENT_CONFIG_MAP: Record<string, { label: string; icon: string; color: string }> = {
|
|
44
|
+
// FieldResearch / Awareness
|
|
45
|
+
contact_created: { label: 'Contact aangemaakt', icon: 'user-plus', color: 'bg-pink-500' },
|
|
46
|
+
page_viewed: { label: 'Pagina bekeken', icon: 'eye', color: 'bg-blue-500' },
|
|
47
|
+
house_viewing_requested: {
|
|
48
|
+
label: 'Bezichtiging aangevraagd',
|
|
49
|
+
icon: 'house-chimney',
|
|
50
|
+
color: 'bg-orange-500',
|
|
51
|
+
},
|
|
52
|
+
automation_phase_opened: {
|
|
53
|
+
label: 'Automation e-mail geopend',
|
|
54
|
+
icon: 'envelope-open-text',
|
|
55
|
+
color: 'bg-indigo-500',
|
|
56
|
+
},
|
|
57
|
+
automation_whatsapp_button_clicked: {
|
|
58
|
+
label: 'WhatsApp knop geklikt',
|
|
59
|
+
icon: 'whatsapp',
|
|
60
|
+
color: 'bg-[#25D366]',
|
|
61
|
+
},
|
|
62
|
+
automation_button_mail_answered: {
|
|
63
|
+
label: 'Automation mail beantwoord',
|
|
64
|
+
icon: 'reply',
|
|
65
|
+
color: 'bg-indigo-600',
|
|
66
|
+
},
|
|
67
|
+
waiting_list_signup: {
|
|
68
|
+
label: 'Aangemeld voor wachtlijst',
|
|
69
|
+
icon: 'list-check',
|
|
70
|
+
color: 'bg-yellow-500',
|
|
71
|
+
},
|
|
72
|
+
viewing_created: {
|
|
73
|
+
label: 'Bezichtiging aangemaakt',
|
|
74
|
+
icon: 'house',
|
|
75
|
+
color: 'bg-orange-400',
|
|
76
|
+
},
|
|
77
|
+
viewing_agenda_item_scheduled: {
|
|
78
|
+
label: 'Bezichtiging gepland',
|
|
79
|
+
icon: 'calendar-check',
|
|
80
|
+
color: 'bg-orange-400',
|
|
81
|
+
},
|
|
82
|
+
general_agenda_item_scheduled: {
|
|
83
|
+
label: 'Afspraak gepland',
|
|
84
|
+
icon: 'calendar',
|
|
85
|
+
color: 'bg-gray-400',
|
|
86
|
+
},
|
|
87
|
+
sales_agenda_item_scheduled: {
|
|
88
|
+
label: 'Verkoopgesprek gepland',
|
|
89
|
+
icon: 'handshake',
|
|
90
|
+
color: 'bg-blue-500',
|
|
91
|
+
},
|
|
92
|
+
agenda_item_scheduled: {
|
|
93
|
+
label: 'Agenda-item gepland',
|
|
94
|
+
icon: 'calendar-plus',
|
|
95
|
+
color: 'bg-gray-500',
|
|
96
|
+
},
|
|
97
|
+
whatsapp_message_sent: {
|
|
98
|
+
label: 'WhatsApp-bericht verzonden',
|
|
99
|
+
icon: 'paper-plane',
|
|
100
|
+
color: 'bg-[#25D366]',
|
|
101
|
+
},
|
|
102
|
+
whatsapp_message_received: {
|
|
103
|
+
label: 'WhatsApp-bericht ontvangen',
|
|
104
|
+
icon: 'whatsapp',
|
|
105
|
+
color: 'bg-[#25D366]',
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// Transaction
|
|
109
|
+
appraisal_agenda_item_scheduled: {
|
|
110
|
+
label: 'Taxatie gepland',
|
|
111
|
+
icon: 'file-invoice-dollar',
|
|
112
|
+
color: 'bg-teal-500',
|
|
113
|
+
},
|
|
114
|
+
purchase_agenda_item_scheduled: {
|
|
115
|
+
label: 'Aankoopgesprek gepland',
|
|
116
|
+
icon: 'cart-shopping',
|
|
117
|
+
color: 'bg-emerald-600',
|
|
118
|
+
},
|
|
119
|
+
structural_inspection_agenda_item_scheduled: {
|
|
120
|
+
label: 'Bouwkundige keuring gepland',
|
|
121
|
+
icon: 'hard-hat',
|
|
122
|
+
color: 'bg-amber-600',
|
|
123
|
+
},
|
|
124
|
+
valuation_agenda_item_scheduled: {
|
|
125
|
+
label: 'Waardebepaling gepland',
|
|
126
|
+
icon: 'calculator',
|
|
127
|
+
color: 'bg-teal-600',
|
|
128
|
+
},
|
|
129
|
+
mortgage_agenda_item_scheduled: {
|
|
130
|
+
label: 'Hypotheekgesprek gepland',
|
|
131
|
+
icon: 'money-check-dollar-pen',
|
|
132
|
+
color: 'bg-blue-600',
|
|
133
|
+
},
|
|
134
|
+
purchase_deed_signing_agenda_item_scheduled: {
|
|
135
|
+
label: 'Koopovereenkomst tekenen',
|
|
136
|
+
icon: 'pen-fancy',
|
|
137
|
+
color: 'bg-emerald-500',
|
|
138
|
+
},
|
|
139
|
+
proposal_sent: { label: 'Voorstel verzonden', icon: 'paper-plane-top', color: 'bg-blue-400' },
|
|
140
|
+
proposal_opened: { label: 'Voorstel geopend', icon: 'envelope-open', color: 'bg-blue-300' },
|
|
141
|
+
proposal_accepted: { label: 'Voorstel geaccepteerd', icon: 'check', color: 'bg-emerald-500' },
|
|
142
|
+
|
|
143
|
+
// Aftercare
|
|
144
|
+
final_inspection_agenda_item_scheduled: {
|
|
145
|
+
label: 'Eindinspectie gepland',
|
|
146
|
+
icon: 'clipboard-check',
|
|
147
|
+
color: 'bg-green-400',
|
|
148
|
+
},
|
|
149
|
+
key_handover_agenda_item_scheduled: {
|
|
150
|
+
label: 'Sleuteloverdracht gepland',
|
|
151
|
+
icon: 'key',
|
|
152
|
+
color: 'bg-green-500',
|
|
153
|
+
},
|
|
154
|
+
transport_agenda_item_scheduled: {
|
|
155
|
+
label: 'Transport bij notaris',
|
|
156
|
+
icon: 'file-signature',
|
|
157
|
+
color: 'bg-green-600',
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Other / Awareness
|
|
161
|
+
newsletter_opened: {
|
|
162
|
+
label: 'Nieuwsbrief geopend',
|
|
163
|
+
icon: 'envelope-open',
|
|
164
|
+
color: 'bg-indigo-400',
|
|
165
|
+
},
|
|
166
|
+
contact_requested: { label: 'Contactaanvraag', icon: 'user', color: 'bg-indigo-500' },
|
|
167
|
+
house_valuation_requested: {
|
|
168
|
+
label: 'Waardebepaling aangevraagd',
|
|
169
|
+
icon: 'search',
|
|
170
|
+
color: 'bg-teal-500',
|
|
171
|
+
},
|
|
172
|
+
unsubscribed: {
|
|
173
|
+
label: 'Afgemeld',
|
|
174
|
+
icon: 'user-slash',
|
|
175
|
+
color: 'bg-red-500',
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export const PHASE_MAP: Record<number, PhaseConfig> = {
|
|
180
|
+
0: {
|
|
181
|
+
label: 'Inactief',
|
|
182
|
+
color: 'border-slate-300',
|
|
183
|
+
bgColor: 'bg-slate-300',
|
|
184
|
+
fromColor: 'from-slate-300',
|
|
185
|
+
toColor: 'to-slate-300',
|
|
186
|
+
textColor: 'text-gray-700',
|
|
187
|
+
},
|
|
188
|
+
1: {
|
|
189
|
+
label: 'Latente woonfase',
|
|
190
|
+
color: 'border-amber-500',
|
|
191
|
+
bgColor: 'bg-amber-500',
|
|
192
|
+
fromColor: 'from-amber-500',
|
|
193
|
+
toColor: 'to-amber-500',
|
|
194
|
+
textColor: 'text-white',
|
|
195
|
+
},
|
|
196
|
+
2: {
|
|
197
|
+
label: 'Oriëntatie',
|
|
198
|
+
color: 'border-purple-500',
|
|
199
|
+
bgColor: 'bg-purple-500',
|
|
200
|
+
fromColor: 'from-purple-500',
|
|
201
|
+
toColor: 'to-purple-500',
|
|
202
|
+
textColor: 'text-white',
|
|
203
|
+
},
|
|
204
|
+
3: {
|
|
205
|
+
label: 'Actieve zoektocht',
|
|
206
|
+
color: 'border-yellow-500',
|
|
207
|
+
bgColor: 'bg-yellow-500',
|
|
208
|
+
fromColor: 'from-yellow-500',
|
|
209
|
+
toColor: 'to-yellow-500',
|
|
210
|
+
textColor: 'text-white',
|
|
211
|
+
},
|
|
212
|
+
4: {
|
|
213
|
+
label: 'Selectie',
|
|
214
|
+
color: 'border-blue-500',
|
|
215
|
+
bgColor: 'bg-blue-500',
|
|
216
|
+
fromColor: 'from-blue-500',
|
|
217
|
+
toColor: 'to-blue-500',
|
|
218
|
+
textColor: 'text-white',
|
|
219
|
+
},
|
|
220
|
+
5: {
|
|
221
|
+
label: 'Transactie',
|
|
222
|
+
color: 'border-emerald-500',
|
|
223
|
+
bgColor: 'bg-emerald-500',
|
|
224
|
+
fromColor: 'from-emerald-500',
|
|
225
|
+
toColor: 'to-emerald-500',
|
|
226
|
+
textColor: 'text-white',
|
|
227
|
+
},
|
|
228
|
+
6: {
|
|
229
|
+
label: 'Wonen',
|
|
230
|
+
color: 'border-green-500',
|
|
231
|
+
bgColor: 'bg-green-500',
|
|
232
|
+
fromColor: 'from-green-500',
|
|
233
|
+
toColor: 'to-green-500',
|
|
234
|
+
textColor: 'text-white',
|
|
235
|
+
},
|
|
236
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import TimelinePhaseblock from './TimelinePhaseblock.vue'
|
|
3
|
+
import type { TimelinePhase } from '../TimelineEvent/TimelineTypes'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Molecules/Timeline Phaseblock',
|
|
7
|
+
component: TimelinePhaseblock,
|
|
8
|
+
} satisfies Meta<typeof TimelinePhaseblock>
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj<typeof TimelinePhaseblock>
|
|
11
|
+
|
|
12
|
+
const makePhase = (
|
|
13
|
+
value: number,
|
|
14
|
+
entered_at: string | null = '2024-06-01T09:00:00.000Z',
|
|
15
|
+
exited_at: string | null = '2024-07-01T09:00:00.000Z',
|
|
16
|
+
events: TimelinePhase['events'] = [],
|
|
17
|
+
): TimelinePhase => ({
|
|
18
|
+
phase: { value },
|
|
19
|
+
entered_at,
|
|
20
|
+
exited_at,
|
|
21
|
+
events,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const sampleEvent = {
|
|
25
|
+
id: 1,
|
|
26
|
+
type: 'contact_created',
|
|
27
|
+
happened_at: '2024-06-10T10:30:00.000Z',
|
|
28
|
+
medium_type: null,
|
|
29
|
+
url: null,
|
|
30
|
+
page_title: null,
|
|
31
|
+
request_reason: null,
|
|
32
|
+
agenda_item_type: null,
|
|
33
|
+
source: 'system',
|
|
34
|
+
direction: 'outbound',
|
|
35
|
+
description: null,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Single phase at the end of the timeline (no separator shown)
|
|
39
|
+
export const SinglePhase: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
phase: makePhase(1),
|
|
42
|
+
index: 0,
|
|
43
|
+
phases: [makePhase(1)],
|
|
44
|
+
isSplitView: true,
|
|
45
|
+
isLast: true,
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// First phase (index 0) in split view — shows the Outbound/Inbound header
|
|
50
|
+
export const FirstPhaseWithHeader: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
phase: makePhase(4),
|
|
53
|
+
index: 0,
|
|
54
|
+
phases: [makePhase(4), makePhase(2)],
|
|
55
|
+
isSplitView: true,
|
|
56
|
+
isLast: false,
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Phase separator visible — phase progressed upward (arrow up)
|
|
61
|
+
export const PhaseProgressedUp: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
phase: makePhase(4),
|
|
64
|
+
index: 0,
|
|
65
|
+
phases: [makePhase(4), makePhase(2)],
|
|
66
|
+
isSplitView: true,
|
|
67
|
+
isLast: false,
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Phase separator visible — phase regressed downward (arrow down)
|
|
72
|
+
export const PhaseRegressedDown: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
phase: makePhase(2),
|
|
75
|
+
index: 0,
|
|
76
|
+
phases: [makePhase(2), makePhase(4)],
|
|
77
|
+
isSplitView: true,
|
|
78
|
+
isLast: false,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Last item in a multi-phase list — no separator shown
|
|
83
|
+
export const LastInList: Story = {
|
|
84
|
+
args: {
|
|
85
|
+
phase: makePhase(1),
|
|
86
|
+
index: 1,
|
|
87
|
+
phases: [makePhase(4), makePhase(1)],
|
|
88
|
+
isSplitView: true,
|
|
89
|
+
isLast: true,
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Non-split view — with phase separator
|
|
94
|
+
export const NonSplitView: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
phase: makePhase(3),
|
|
97
|
+
index: 0,
|
|
98
|
+
phases: [makePhase(3), makePhase(1)],
|
|
99
|
+
isSplitView: false,
|
|
100
|
+
isLast: false,
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Non-split view — single/last phase (no separator)
|
|
105
|
+
export const NonSplitViewLast: Story = {
|
|
106
|
+
args: {
|
|
107
|
+
phase: makePhase(3),
|
|
108
|
+
index: 0,
|
|
109
|
+
phases: [makePhase(3)],
|
|
110
|
+
isSplitView: false,
|
|
111
|
+
isLast: true,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Non-split view — with events
|
|
116
|
+
export const NonSplitViewWithEvents: Story = {
|
|
117
|
+
args: {
|
|
118
|
+
phase: makePhase(4, '2024-06-01T09:00:00.000Z', '2024-07-01T09:00:00.000Z', [
|
|
119
|
+
sampleEvent,
|
|
120
|
+
{ ...sampleEvent, id: 2, type: 'page_viewed', happened_at: '2024-06-12T14:00:00.000Z' },
|
|
121
|
+
]),
|
|
122
|
+
index: 0,
|
|
123
|
+
phases: [makePhase(4), makePhase(2)],
|
|
124
|
+
isSplitView: false,
|
|
125
|
+
isLast: false,
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Phase with events
|
|
130
|
+
export const WithEvents: Story = {
|
|
131
|
+
args: {
|
|
132
|
+
phase: makePhase(4, '2024-06-01T09:00:00.000Z', '2024-07-01T09:00:00.000Z', [
|
|
133
|
+
sampleEvent,
|
|
134
|
+
{ ...sampleEvent, id: 2, type: 'page_viewed', happened_at: '2024-06-12T14:00:00.000Z' },
|
|
135
|
+
{
|
|
136
|
+
...sampleEvent,
|
|
137
|
+
id: 3,
|
|
138
|
+
type: 'whatsapp_message_received',
|
|
139
|
+
direction: 'inbound',
|
|
140
|
+
happened_at: '2024-06-15T11:00:00.000Z',
|
|
141
|
+
},
|
|
142
|
+
]),
|
|
143
|
+
index: 0,
|
|
144
|
+
phases: [makePhase(4), makePhase(2)],
|
|
145
|
+
isSplitView: true,
|
|
146
|
+
isLast: false,
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// All phases shown together (newest first)
|
|
151
|
+
export const FullTimeline: Story = {
|
|
152
|
+
args: {
|
|
153
|
+
phase: makePhase(5, '2024-08-01T09:00:00.000Z', null, [
|
|
154
|
+
{ ...sampleEvent, id: 4, type: 'proposal_accepted', happened_at: '2024-08-05T10:00:00.000Z' },
|
|
155
|
+
]),
|
|
156
|
+
index: 0,
|
|
157
|
+
phases: [
|
|
158
|
+
makePhase(5, '2024-08-01T09:00:00.000Z', null),
|
|
159
|
+
makePhase(4, '2024-06-01T09:00:00.000Z', '2024-08-01T09:00:00.000Z'),
|
|
160
|
+
makePhase(1, '2024-01-01T09:00:00.000Z', '2024-06-01T09:00:00.000Z'),
|
|
161
|
+
],
|
|
162
|
+
isSplitView: true,
|
|
163
|
+
isLast: false,
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Phase with no entered_at or exited_at dates
|
|
168
|
+
export const NoDates: Story = {
|
|
169
|
+
args: {
|
|
170
|
+
phase: makePhase(2, null, null),
|
|
171
|
+
index: 0,
|
|
172
|
+
phases: [makePhase(2, null, null), makePhase(1, null, null)],
|
|
173
|
+
isSplitView: true,
|
|
174
|
+
isLast: false,
|
|
175
|
+
},
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Inactive phase (value 0)
|
|
179
|
+
export const InactivePhase: Story = {
|
|
180
|
+
args: {
|
|
181
|
+
phase: makePhase(0),
|
|
182
|
+
index: 0,
|
|
183
|
+
phases: [makePhase(0)],
|
|
184
|
+
isSplitView: true,
|
|
185
|
+
isLast: true,
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Wonen phase (value 6 — highest)
|
|
190
|
+
export const WonenPhase: Story = {
|
|
191
|
+
args: {
|
|
192
|
+
phase: makePhase(6),
|
|
193
|
+
index: 0,
|
|
194
|
+
phases: [makePhase(6), makePhase(5)],
|
|
195
|
+
isSplitView: true,
|
|
196
|
+
isLast: false,
|
|
197
|
+
},
|
|
198
|
+
}
|