@granto-umbrella/umbrella-components 3.0.56 → 3.0.57

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/package.json CHANGED
@@ -1,141 +1,141 @@
1
- {
2
- "name": "@granto-umbrella/umbrella-components",
3
- "version": "3.0.56",
4
- "description": "Umbrella Components for React",
5
- "type": "module",
6
- "main": "src/index.js",
7
- "module": "src/index.js",
8
- "repository": {
9
- "type": "git",
10
- "url": "https://github.com/grantoseguros/granto-umbrella-components.git"
11
- },
12
- "scripts": {
13
- "dev": "vite",
14
- "build": "tsc -b && vite build",
15
- "commit": "cz",
16
- "pr": "node scripts/open-pr.cjs",
17
- "typecheck": "npm run typecheck:app && npm run typecheck:test",
18
- "typecheck:app": "tsc -p tsconfig.app.json --noEmit",
19
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
20
- "test": "jest --config=jest.config.mjs",
21
- "test:ci": "jest --config=jest.config.mjs --coverage",
22
- "test:related": "jest --config=jest.config.mjs -o",
23
- "test:coverage": "jest --config jest.config.mjs --coverage --coverageReporters",
24
- "lint": "eslint .",
25
- "lint:staged": "eslint --max-warnings=0 --ignore-pattern 'storybook-static/**' --ignore-pattern 'coverage/**' --ignore-pattern 'dist/**'",
26
- "format": "prettier -c .",
27
- "format:check": "prettier --check .",
28
- "format:write": "prettier -w .",
29
- "prepare": "lefthook install",
30
- "preview": "vite preview",
31
- "storybook": "storybook dev -p 6006",
32
- "build-storybook": "storybook build",
33
- "build:storybook": "storybook build -o storybook-static",
34
- "predeploy": "npm run build-storybook",
35
- "deploy": "gh-pages -d storybook-static",
36
- "version": "npm run build && git add .",
37
- "release:patch": "npm version patch && git push && git push --tags",
38
- "release:minor": "npm version minor && git push && git push --tags",
39
- "release:major": "npm version major && git push && git push --tags",
40
- "bump:patch": "npm version patch",
41
- "bump:minor": "npm version minor",
42
- "bump:major": "npm version major"
43
- },
44
- "config": {
45
- "commitizen": {
46
- "path": "cz-git"
47
- }
48
- },
49
- "dependencies": {
50
- "@hello-pangea/dnd": "^18.0.1",
51
- "@phosphor-icons/react": "^2.1.10",
52
- "@radix-ui/react-dialog": "^1.1.15",
53
- "@radix-ui/react-label": "^2.1.3",
54
- "@radix-ui/react-popover": "^1.1.11",
55
- "@radix-ui/react-radio-group": "^1.2.4",
56
- "cpf-cnpj-validator": "^1.0.3",
57
- "date-fns": "^4.1.0",
58
- "lucide-react": "^0.488.0",
59
- "make-mask": "^1.0.3",
60
- "phosphor-react": "^1.4.1",
61
- "radix": "^0.0.0",
62
- "react": "^18.3.1",
63
- "react-datepicker": "^8.3.0",
64
- "react-day-picker": "^9.6.7",
65
- "react-dom": "^18.3.1",
66
- "react-hook-form": "^7.63.0",
67
- "react-router": "^6.30.1",
68
- "react-router-dom": "^6.30.1",
69
- "react-select": "^5.10.0",
70
- "recharts": "^3.2.1",
71
- "tailwind-merge": "^3.2.0"
72
- },
73
- "devDependencies": {
74
- "@chromatic-com/storybook": "4.1.3",
75
- "@commitlint/cli": "^20.1.0",
76
- "@commitlint/config-conventional": "^20.0.0",
77
- "@eslint/js": "^9.17.0",
78
- "@storybook/addon-actions": "^9.0.8",
79
- "@storybook/addon-docs": "10.1.6",
80
- "@storybook/addon-essentials": "^8.6.14",
81
- "@storybook/addon-onboarding": "10.1.6",
82
- "@storybook/react-vite": "^10.1.6",
83
- "@storybook/test": "^8.6.14",
84
- "@testing-library/dom": "^10.4.1",
85
- "@testing-library/jest-dom": "^6.9.1",
86
- "@testing-library/react": "^16.3.0",
87
- "@testing-library/user-event": "^14.6.1",
88
- "@types/jest": "^30.0.0",
89
- "@types/mocha": "^10.0.10",
90
- "@types/node": "^24.9.2",
91
- "@types/react": "^18.3.17",
92
- "@types/react-dom": "^18.3.5",
93
- "@types/styled-components": "^5.1.34",
94
- "@vitejs/plugin-react": "^4.7.0",
95
- "babel-plugin-styled-components": "^2.1.4",
96
- "commitizen": "^4.3.1",
97
- "commitlint": "^20.1.0",
98
- "cz-git": "^1.12.0",
99
- "eslint": "^9.17.0",
100
- "eslint-plugin-react-hooks": "^5.0.0",
101
- "eslint-plugin-react-refresh": "^0.4.16",
102
- "eslint-plugin-storybook": "10.1.6",
103
- "gh-pages": "^6.3.0",
104
- "globals": "^15.13.0",
105
- "identity-obj-proxy": "^3.0.0",
106
- "jest": "^29.7.0",
107
- "jest-environment-jsdom": "^29.7.0",
108
- "jest-styled-components": "^7.2.0",
109
- "lefthook": "^2.0.1",
110
- "prettier": "^3.6.2",
111
- "react-icons": "^5.4.0",
112
- "storybook": "^10.1.10",
113
- "styled-components": "^6.1.19",
114
- "ts-jest": "^29.4.5",
115
- "ts-node": "^10.9.2",
116
- "typescript": "~5.6.2",
117
- "typescript-eslint": "^8.18.1",
118
- "vite": "^6.0.3",
119
- "vite-plugin-dts": "^4.5.4"
120
- },
121
- "keywords": [
122
- "cli",
123
- "vite",
124
- "components"
125
- ],
126
- "eslintConfig": {
127
- "extends": [
128
- "plugin:storybook/recommended"
129
- ]
130
- },
131
- "engines": {
132
- "node": "20.17.0",
133
- "yarn": ">=1.22.18"
134
- },
135
- "files": [
136
- "dist",
137
- "src/**/*",
138
- "!src/**/*.test.*",
139
- "!src/**/*.stories.*"
140
- ]
141
- }
1
+ {
2
+ "name": "@granto-umbrella/umbrella-components",
3
+ "version": "3.0.57",
4
+ "description": "Umbrella Components for React",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "module": "src/index.js",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/grantoseguros/granto-umbrella-components.git"
11
+ },
12
+ "scripts": {
13
+ "dev": "vite",
14
+ "build": "tsc -b && vite build",
15
+ "commit": "cz",
16
+ "pr": "node scripts/open-pr.cjs",
17
+ "typecheck": "npm run typecheck:app && npm run typecheck:test",
18
+ "typecheck:app": "tsc -p tsconfig.app.json --noEmit",
19
+ "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
20
+ "test": "jest --config=jest.config.mjs",
21
+ "test:ci": "jest --config=jest.config.mjs --coverage",
22
+ "test:related": "jest --config=jest.config.mjs -o",
23
+ "test:coverage": "jest --config jest.config.mjs --coverage --coverageReporters",
24
+ "lint": "eslint .",
25
+ "lint:staged": "eslint --max-warnings=0 --ignore-pattern 'storybook-static/**' --ignore-pattern 'coverage/**' --ignore-pattern 'dist/**'",
26
+ "format": "prettier -c .",
27
+ "format:check": "prettier --check .",
28
+ "format:write": "prettier -w .",
29
+ "prepare": "lefthook install",
30
+ "preview": "vite preview",
31
+ "storybook": "storybook dev -p 6006",
32
+ "build-storybook": "storybook build",
33
+ "build:storybook": "storybook build -o storybook-static",
34
+ "predeploy": "npm run build-storybook",
35
+ "deploy": "gh-pages -d storybook-static",
36
+ "version": "npm run build && git add .",
37
+ "release:patch": "npm version patch && git push && git push --tags",
38
+ "release:minor": "npm version minor && git push && git push --tags",
39
+ "release:major": "npm version major && git push && git push --tags",
40
+ "bump:patch": "npm version patch",
41
+ "bump:minor": "npm version minor",
42
+ "bump:major": "npm version major"
43
+ },
44
+ "config": {
45
+ "commitizen": {
46
+ "path": "cz-git"
47
+ }
48
+ },
49
+ "dependencies": {
50
+ "@hello-pangea/dnd": "^18.0.1",
51
+ "@phosphor-icons/react": "^2.1.10",
52
+ "@radix-ui/react-dialog": "^1.1.15",
53
+ "@radix-ui/react-label": "^2.1.3",
54
+ "@radix-ui/react-popover": "^1.1.11",
55
+ "@radix-ui/react-radio-group": "^1.2.4",
56
+ "cpf-cnpj-validator": "^1.0.3",
57
+ "date-fns": "^4.1.0",
58
+ "lucide-react": "^0.488.0",
59
+ "make-mask": "^1.0.3",
60
+ "phosphor-react": "^1.4.1",
61
+ "radix": "^0.0.0",
62
+ "react": "^18.3.1",
63
+ "react-datepicker": "^8.3.0",
64
+ "react-day-picker": "^9.6.7",
65
+ "react-dom": "^18.3.1",
66
+ "react-hook-form": "^7.63.0",
67
+ "react-router": "^6.30.1",
68
+ "react-router-dom": "^6.30.1",
69
+ "react-select": "^5.10.0",
70
+ "recharts": "^3.2.1",
71
+ "tailwind-merge": "^3.2.0"
72
+ },
73
+ "devDependencies": {
74
+ "@chromatic-com/storybook": "4.1.3",
75
+ "@commitlint/cli": "^20.1.0",
76
+ "@commitlint/config-conventional": "^20.0.0",
77
+ "@eslint/js": "^9.17.0",
78
+ "@storybook/addon-actions": "^9.0.8",
79
+ "@storybook/addon-docs": "10.1.6",
80
+ "@storybook/addon-essentials": "^8.6.14",
81
+ "@storybook/addon-onboarding": "10.1.6",
82
+ "@storybook/react-vite": "^10.1.6",
83
+ "@storybook/test": "^8.6.14",
84
+ "@testing-library/dom": "^10.4.1",
85
+ "@testing-library/jest-dom": "^6.9.1",
86
+ "@testing-library/react": "^16.3.0",
87
+ "@testing-library/user-event": "^14.6.1",
88
+ "@types/jest": "^30.0.0",
89
+ "@types/mocha": "^10.0.10",
90
+ "@types/node": "^24.9.2",
91
+ "@types/react": "^18.3.17",
92
+ "@types/react-dom": "^18.3.5",
93
+ "@types/styled-components": "^5.1.34",
94
+ "@vitejs/plugin-react": "^4.7.0",
95
+ "babel-plugin-styled-components": "^2.1.4",
96
+ "commitizen": "^4.3.1",
97
+ "commitlint": "^20.1.0",
98
+ "cz-git": "^1.12.0",
99
+ "eslint": "^9.17.0",
100
+ "eslint-plugin-react-hooks": "^5.0.0",
101
+ "eslint-plugin-react-refresh": "^0.4.16",
102
+ "eslint-plugin-storybook": "10.1.6",
103
+ "gh-pages": "^6.3.0",
104
+ "globals": "^15.13.0",
105
+ "identity-obj-proxy": "^3.0.0",
106
+ "jest": "^29.7.0",
107
+ "jest-environment-jsdom": "^29.7.0",
108
+ "jest-styled-components": "^7.2.0",
109
+ "lefthook": "^2.0.1",
110
+ "prettier": "^3.6.2",
111
+ "react-icons": "^5.4.0",
112
+ "storybook": "^10.1.10",
113
+ "styled-components": "^6.1.19",
114
+ "ts-jest": "^29.4.5",
115
+ "ts-node": "^10.9.2",
116
+ "typescript": "~5.6.2",
117
+ "typescript-eslint": "^8.18.1",
118
+ "vite": "^6.0.3",
119
+ "vite-plugin-dts": "^4.5.4"
120
+ },
121
+ "keywords": [
122
+ "cli",
123
+ "vite",
124
+ "components"
125
+ ],
126
+ "eslintConfig": {
127
+ "extends": [
128
+ "plugin:storybook/recommended"
129
+ ]
130
+ },
131
+ "engines": {
132
+ "node": "20.17.0",
133
+ "yarn": ">=1.22.18"
134
+ },
135
+ "files": [
136
+ "dist",
137
+ "src/**/*",
138
+ "!src/**/*.test.*",
139
+ "!src/**/*.stories.*"
140
+ ]
141
+ }
@@ -0,0 +1,50 @@
1
+ import styled from 'styled-components';
2
+ import {
3
+ primitiveSizes,
4
+ semanticBorders,
5
+ semanticColors,
6
+ semanticRadius,
7
+ semanticShadows,
8
+ typographyTokens,
9
+ } from '../../../styles/tokens';
10
+ import CreatableSelect from 'react-select/creatable';
11
+
12
+ export const Container = styled.div`
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: ${primitiveSizes.size.x1};
16
+ width: 100%;
17
+ `;
18
+
19
+ export const Label = styled.label`
20
+ font-size: ${typographyTokens.fontSizes.labelS};
21
+ font-weight: ${typographyTokens.fontWeights.medium};
22
+ color: ${semanticColors.global.text.subtitle.enabled};
23
+ `;
24
+
25
+ export const SupportingText = styled.span<{ $error?: boolean }>`
26
+ font-size: ${typographyTokens.fontSizes.captionM};
27
+ color: ${({ $error }) =>
28
+ $error
29
+ ? semanticColors.global.text.feedback.strong.error
30
+ : semanticColors.global.text.subtitle.enabled};
31
+ `;
32
+
33
+ export const CustomSelect = styled(CreatableSelect)<{
34
+ $error?: boolean;
35
+ $size?: 'sm' | 'md' | 'lg';
36
+ }>`
37
+ .react-select__control {
38
+ min-height: ${primitiveSizes.size.x12};
39
+ border-radius: ${semanticRadius.global.radius.md};
40
+ border: ${semanticBorders.global.sm} solid
41
+ ${({ $error }) =>
42
+ $error
43
+ ? semanticColors.global.border.danger.enabled
44
+ : semanticColors.global.border.medium};
45
+
46
+ &:focus-within {
47
+ box-shadow: ${semanticShadows.shadow.md};
48
+ }
49
+ }
50
+ `;
@@ -0,0 +1,136 @@
1
+ 'use client';
2
+
3
+ import { useMemo, useState } from 'react';
4
+ import type { InputActionMeta } from 'react-select';
5
+ import {
6
+ Container,
7
+ Label,
8
+ SupportingText,
9
+ CustomSelect,
10
+ } from './EditableDurationSelect.styles';
11
+ import {
12
+ DurationOption,
13
+ EditableDurationSelectProps,
14
+ } from './EditableDurationSelect.types';
15
+
16
+ const DAYS_IN_YEAR = 365;
17
+ const BASE_LIMIT = 5;
18
+
19
+ function parseDuration(input: string): DurationOption | null {
20
+ if (!input) return null;
21
+
22
+ const normalized = input.trim().toLowerCase();
23
+
24
+ if (/^\d+$/.test(normalized)) {
25
+ const amount = Number(normalized);
26
+ if (amount <= 0) return null;
27
+
28
+ const isYear = amount <= BASE_LIMIT;
29
+
30
+ return {
31
+ label: isYear
32
+ ? `${amount} ${amount > 1 ? 'anos' : 'ano'}`
33
+ : `${amount} ${amount > 1 ? 'dias' : 'dia'}`,
34
+ value: normalized,
35
+ days: isYear ? amount * DAYS_IN_YEAR : amount,
36
+ };
37
+ }
38
+
39
+ const match = normalized.match(/^(\d+)\s*(dia|dias|ano|anos)$/);
40
+ if (!match) return null;
41
+
42
+ const amount = Number(match[1]);
43
+ const unit = match[2];
44
+
45
+ if (amount <= 0) return null;
46
+
47
+ const isYear = unit.startsWith('ano');
48
+
49
+ return {
50
+ label: `${amount} ${isYear ? (amount > 1 ? 'anos' : 'ano') : amount > 1 ? 'dias' : 'dia'}`,
51
+ value: normalized,
52
+ days: isYear ? amount * DAYS_IN_YEAR : amount,
53
+ };
54
+ }
55
+
56
+ export default function EditableDurationSelect({
57
+ label,
58
+ supportingText,
59
+ value,
60
+ onChange,
61
+ options = [],
62
+ disabled,
63
+ error,
64
+ size = 'md',
65
+ testId,
66
+ baseLimit = BASE_LIMIT,
67
+ }: EditableDurationSelectProps) {
68
+ const [inputValue, setInputValue] = useState('');
69
+
70
+ const parsedInput = useMemo(() => parseDuration(inputValue), [inputValue]);
71
+
72
+ const dynamicOption = useMemo(() => {
73
+ if (!parsedInput) return [];
74
+ return [
75
+ {
76
+ label: parsedInput.label,
77
+ value: parsedInput.value,
78
+ days: parsedInput.days,
79
+ },
80
+ ];
81
+ }, [parsedInput]);
82
+
83
+ const mergedOptions = useMemo(() => {
84
+ return [
85
+ ...dynamicOption.filter((d) => !options.some((o) => o.days === d.days)),
86
+ ...options,
87
+ ];
88
+ }, [dynamicOption, options]);
89
+
90
+ const helperText = useMemo(() => {
91
+ if (!inputValue) return supportingText;
92
+
93
+ if (!parsedInput) return 'Valor inválido';
94
+
95
+ return parsedInput.days > baseLimit * DAYS_IN_YEAR
96
+ ? `Valores acima de ${baseLimit} são considerados dias`
97
+ : `Valores até ${baseLimit} são considerados anos`;
98
+ }, [baseLimit, inputValue, parsedInput, supportingText]);
99
+
100
+ function handleInputChange(value: string, meta: InputActionMeta) {
101
+ if (meta.action === 'input-change') {
102
+ setInputValue(value);
103
+ }
104
+ }
105
+
106
+ function handleChange(option: DurationOption | null) {
107
+ if (!option) return;
108
+ onChange?.(option);
109
+ setInputValue('');
110
+ }
111
+
112
+ return (
113
+ <Container data-testid={testId}>
114
+ {label && <Label>{label}</Label>}
115
+
116
+ <CustomSelect
117
+ isSearchable
118
+ isDisabled={disabled}
119
+ $size={size}
120
+ $error={error}
121
+ options={mergedOptions}
122
+ value={value}
123
+ placeholder="Digite ou selecione"
124
+ onInputChange={handleInputChange}
125
+ onChange={(opt) => handleChange(opt as DurationOption | null)}
126
+ formatCreateLabel={() => null}
127
+ />
128
+
129
+ {helperText && (
130
+ <SupportingText $error={error || helperText === 'Valor inválido'}>
131
+ {helperText}
132
+ </SupportingText>
133
+ )}
134
+ </Container>
135
+ );
136
+ }
@@ -0,0 +1,18 @@
1
+ export type DurationOption = {
2
+ label: string;
3
+ value: string;
4
+ days: number;
5
+ };
6
+
7
+ export interface EditableDurationSelectProps {
8
+ label?: string;
9
+ supportingText?: string;
10
+ value?: DurationOption | null;
11
+ onChange?: (value: DurationOption | null) => void;
12
+ options?: DurationOption[];
13
+ disabled?: boolean;
14
+ error?: boolean;
15
+ size?: 'sm' | 'md' | 'lg';
16
+ testId?: string;
17
+ baseLimit?: number;
18
+ }
@@ -0,0 +1 @@
1
+ export { default } from './EditableDurationSelect';
@@ -1,86 +1,86 @@
1
- // TimeLine.mapper.ts
2
- import {
3
- TimelineItem,
4
- RemoteEvent,
5
- EventIdKey,
6
- TimelineVariant,
7
- } from './TimeLine.types';
8
- import { resolveTimelineConfig } from './TimeLine.registry';
9
-
10
- function toEventIdKey(eventId: number | string): EventIdKey {
11
- const raw = String(eventId).trim();
12
- return raw as EventIdKey;
13
- }
14
-
15
- function toVariant(eventIdKey: EventIdKey): TimelineVariant {
16
- return resolveTimelineConfig(eventIdKey)?.variant || 'continued';
17
- }
18
-
19
- function buildTitle(eventIdKey: EventIdKey): string {
20
- const base =
21
- resolveTimelineConfig(eventIdKey)?.labelPtBr || `Evento ${eventIdKey}`;
22
-
23
- return base;
24
- }
25
-
26
- function actorFrom(ev: RemoteEvent) {
27
- if (!ev.user) {
28
- return { id: '', displayName: 'Sistema', type: 'app' as const };
29
- }
30
-
31
- return {
32
- id: String(ev.user.id),
33
- displayName: ev.user.name || 'Usuário',
34
- type: 'user' as const,
35
- };
36
- }
37
-
38
- function safeOrigin(ev: RemoteEvent): string {
39
- const origin = ev.parentType || ev.eventType;
40
- return origin ? String(origin) : 'unknown';
41
- }
42
-
43
- function safeData(ev: RemoteEvent): Record<string, unknown> {
44
- return ev.data && typeof ev.data === 'object' ? ev.data : {};
45
- }
46
-
47
- export function mapRemoteToTimeline(items: RemoteEvent[]): TimelineItem[] {
48
- return items.map((ev, idx) => {
49
- const id = ev.id || String(idx);
50
- const eventIdKey = toEventIdKey(ev.eventId);
51
- const data = safeData(ev) as Record<string, any>;
52
-
53
- return {
54
- id,
55
- timestamp: ev.startDate,
56
- type: toVariant(eventIdKey),
57
- title: buildTitle(eventIdKey),
58
- description: undefined,
59
- actor: actorFrom(ev),
60
- origin: safeOrigin(ev),
61
- correlationId: ev.id,
62
- metadata: {
63
- eventIdKey,
64
- eventIdRaw: ev.eventId,
65
- eventType: ev.eventType,
66
- isPublic: ev.isPublic,
67
- startDate: ev.startDate,
68
- endDate: ev.endDate,
69
- duration: ev.duration,
70
- parentId: ev.parentId,
71
- parentType: ev.parentType,
72
-
73
- proposalId: data?.id,
74
- orderId: data?.umOrder,
75
- insuranceId: data?.umInsurance,
76
- insuredName: data?.insuredName,
77
- insuredDocument: data?.insuredDocument,
78
- status: data?.status,
79
- stage: data?.stage,
80
- modality: data?.modality,
81
-
82
- data,
83
- },
84
- };
85
- });
86
- }
1
+ // TimeLine.mapper.ts
2
+ import {
3
+ TimelineItem,
4
+ RemoteEvent,
5
+ EventIdKey,
6
+ TimelineVariant,
7
+ } from './TimeLine.types';
8
+ import { resolveTimelineConfig } from './TimeLine.registry';
9
+
10
+ function toEventIdKey(eventId: number | string): EventIdKey {
11
+ const raw = String(eventId).trim();
12
+ return raw as EventIdKey;
13
+ }
14
+
15
+ function toVariant(eventIdKey: EventIdKey): TimelineVariant {
16
+ return resolveTimelineConfig(eventIdKey)?.variant || 'continued';
17
+ }
18
+
19
+ function buildTitle(eventIdKey: EventIdKey): string {
20
+ const base =
21
+ resolveTimelineConfig(eventIdKey)?.labelPtBr || `Evento ${eventIdKey}`;
22
+
23
+ return base;
24
+ }
25
+
26
+ function actorFrom(ev: RemoteEvent) {
27
+ if (!ev.user) {
28
+ return { id: '', displayName: 'Sistema', type: 'app' as const };
29
+ }
30
+
31
+ return {
32
+ id: String(ev.user.id),
33
+ displayName: ev.user.name || 'Usuário',
34
+ type: 'user' as const,
35
+ };
36
+ }
37
+
38
+ function safeOrigin(ev: RemoteEvent): string {
39
+ const origin = ev.parentType || ev.eventType;
40
+ return origin ? String(origin) : 'unknown';
41
+ }
42
+
43
+ function safeData(ev: RemoteEvent): Record<string, unknown> {
44
+ return ev.data && typeof ev.data === 'object' ? ev.data : {};
45
+ }
46
+
47
+ export function mapRemoteToTimeline(items: RemoteEvent[]): TimelineItem[] {
48
+ return items.map((ev, idx) => {
49
+ const id = ev.id || String(idx);
50
+ const eventIdKey = toEventIdKey(ev.eventId);
51
+ const data = safeData(ev) as Record<string, any>;
52
+
53
+ return {
54
+ id,
55
+ timestamp: ev.startDate,
56
+ type: toVariant(eventIdKey),
57
+ title: buildTitle(eventIdKey),
58
+ description: undefined,
59
+ actor: actorFrom(ev),
60
+ origin: safeOrigin(ev),
61
+ correlationId: ev.id,
62
+ metadata: {
63
+ eventIdKey,
64
+ eventIdRaw: ev.eventId,
65
+ eventType: ev.eventType,
66
+ isPublic: ev.isPublic,
67
+ startDate: ev.startDate,
68
+ endDate: ev.endDate,
69
+ duration: ev.duration,
70
+ parentId: ev.parentId,
71
+ parentType: ev.parentType,
72
+
73
+ proposalId: data?.id,
74
+ orderId: data?.umOrder,
75
+ insuranceId: data?.umInsurance,
76
+ insuredName: data?.insuredName,
77
+ insuredDocument: data?.insuredDocument,
78
+ status: data?.status,
79
+ stage: data?.stage,
80
+ modality: data?.modality,
81
+
82
+ data,
83
+ },
84
+ };
85
+ });
86
+ }