@paro.io/expert-shared-components 1.14.4 → 1.14.6
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/lib/components/ProjectIntelligence/EngagementHeader/index.d.ts +4 -1
- package/lib/components/ProjectIntelligence/EngagementHeader/index.js +18 -15
- package/lib/components/ProjectIntelligence/FocusAreas/index.js +35 -5
- package/lib/components/ProjectIntelligence/MissingInformation/index.js +37 -38
- package/lib/components/ProjectIntelligence/ProgressTracker/index.d.ts +0 -1
- package/lib/components/ProjectIntelligence/ProgressTracker/index.js +3 -3
- package/lib/components/ProjectIntelligence/index.js +163 -18
- package/package.json +1 -1
|
@@ -9,10 +9,13 @@ interface EngagementHeaderProps {
|
|
|
9
9
|
expertName: string;
|
|
10
10
|
expertTitle: string;
|
|
11
11
|
startDate: string;
|
|
12
|
-
status: '
|
|
12
|
+
status: 'PreKickoff' | 'Kickoff' | 'Setup' | 'Active' | 'Renewal';
|
|
13
13
|
clientTabs: ClientTab[];
|
|
14
14
|
selectedClientId: string | null;
|
|
15
15
|
onClientChange: (opportunityId: string) => void;
|
|
16
|
+
allFocusAreasCompleted?: boolean;
|
|
17
|
+
onMoveToNextStage?: () => void;
|
|
18
|
+
isLoading?: boolean;
|
|
16
19
|
}
|
|
17
20
|
export declare const EngagementHeader: React.FC<EngagementHeaderProps>;
|
|
18
21
|
export {};
|
|
@@ -7,22 +7,20 @@ exports.EngagementHeader = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const date_fns_1 = require("date-fns");
|
|
9
9
|
const STATUS_COLORS = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Cancelled: 'bg-red-100 text-red-800 border-red-200',
|
|
10
|
+
'PreKickoff': 'bg-orange-100 text-orange-800 border-orange-200',
|
|
11
|
+
Kickoff: 'bg-green-100 text-green-800 border-green-200',
|
|
12
|
+
Setup: 'bg-green-100 text-green-800 border-green-200',
|
|
13
|
+
Active: 'bg-green-100 text-green-800 border-green-200',
|
|
14
|
+
Renewal: 'bg-green-100 text-green-800 border-green-200',
|
|
16
15
|
};
|
|
17
16
|
const STATUS_LABELS = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Cancelled: 'CANCELLED',
|
|
17
|
+
'PreKickoff': 'PRE KICKOFF',
|
|
18
|
+
Kickoff: 'KICKOFF',
|
|
19
|
+
Setup: 'SETUP',
|
|
20
|
+
Active: 'ACTIVE',
|
|
21
|
+
Renewal: 'RENEWAL',
|
|
24
22
|
};
|
|
25
|
-
const EngagementHeader = ({ clientName, expertName, expertTitle, startDate, status, clientTabs, selectedClientId, onClientChange }) => {
|
|
23
|
+
const EngagementHeader = ({ clientName, expertName, expertTitle, startDate, status, clientTabs, selectedClientId, onClientChange, allFocusAreasCompleted = false, onMoveToNextStage, isLoading = false }) => {
|
|
26
24
|
const formattedDate = startDate ? (0, date_fns_1.format)(new Date(startDate), 'MMMM dd, yyyy') : (0, date_fns_1.format)(new Date(), 'MMMM dd, yyyy');
|
|
27
25
|
return (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200" },
|
|
28
26
|
react_1.default.createElement("div", { className: "px-6 pt-4" },
|
|
@@ -42,9 +40,14 @@ const EngagementHeader = ({ clientName, expertName, expertTitle, startDate, stat
|
|
|
42
40
|
expertTitle,
|
|
43
41
|
" \u2022 Started ",
|
|
44
42
|
formattedDate)),
|
|
45
|
-
react_1.default.createElement("div", { className: "flex items-center" },
|
|
43
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-3" },
|
|
46
44
|
react_1.default.createElement("span", { className: `inline-flex items-center px-3 py-1 rounded-full text-sm font-medium ${STATUS_COLORS[status]}` },
|
|
47
45
|
react_1.default.createElement("div", { className: "w-2 h-2 bg-current rounded-full mr-1.5" }),
|
|
48
|
-
STATUS_LABELS[status])
|
|
46
|
+
STATUS_LABELS[status]),
|
|
47
|
+
allFocusAreasCompleted && status !== 'Active' && onMoveToNextStage && (react_1.default.createElement("button", { onClick: onMoveToNextStage, disabled: isLoading, className: `inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors ${isLoading ? 'opacity-50 cursor-not-allowed' : ''}` }, isLoading ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
48
|
+
react_1.default.createElement("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" },
|
|
49
|
+
react_1.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
50
|
+
react_1.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })),
|
|
51
|
+
"Processing...")) : ('Move to Next Stage'))))))));
|
|
49
52
|
};
|
|
50
53
|
exports.EngagementHeader = EngagementHeader;
|
|
@@ -28,9 +28,9 @@ const react_1 = __importStar(require("react"));
|
|
|
28
28
|
const date_fns_1 = require("date-fns");
|
|
29
29
|
const utils_1 = require("../../shared/utils");
|
|
30
30
|
const STATUS_COLORS = {
|
|
31
|
-
CONFIRMED: 'bg-
|
|
31
|
+
CONFIRMED: 'bg-blue-100 text-blue-800 border-blue-200',
|
|
32
32
|
IN_PROGRESS: 'bg-blue-100 text-blue-800 border-blue-200',
|
|
33
|
-
COMPLETED: 'bg-
|
|
33
|
+
COMPLETED: 'bg-green-100 text-green-800 border-green-200',
|
|
34
34
|
AT_RISK: 'bg-red-100 text-red-800 border-red-200',
|
|
35
35
|
};
|
|
36
36
|
const STATUS_ICONS = {
|
|
@@ -125,6 +125,32 @@ const FocusAreas = ({ focusAreas, updateOpportunityFocusArea, GetOpportunityInsi
|
|
|
125
125
|
// Here you would typically call an API to update the focus area
|
|
126
126
|
console.log('Saving focus area:', id, newTitle, newDescription);
|
|
127
127
|
};
|
|
128
|
+
const handleStatusUpdate = (focusArea, newStatus) => {
|
|
129
|
+
try {
|
|
130
|
+
// Update in the backend
|
|
131
|
+
updateOpportunityFocusArea({
|
|
132
|
+
variables: {
|
|
133
|
+
opportunityId: selectedOpportunityId,
|
|
134
|
+
input: {
|
|
135
|
+
id: focusArea.id,
|
|
136
|
+
status: newStatus
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
refetchQueries: [
|
|
140
|
+
{ query: GetOpportunityInsightsDocument, variables: { opportunityId: selectedOpportunityId } }
|
|
141
|
+
]
|
|
142
|
+
});
|
|
143
|
+
// Update local state
|
|
144
|
+
setLocalFocusAreas(prev => prev.map(area => area.id === focusArea.id
|
|
145
|
+
? Object.assign(Object.assign({}, area), { status: newStatus }) : area));
|
|
146
|
+
(0, utils_1.showToast)('success', `Focus area marked as ${newStatus.toLowerCase()}`);
|
|
147
|
+
onSaveFocusArea && onSaveFocusArea();
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.error('Error updating focus area status:', error);
|
|
151
|
+
(0, utils_1.showToast)('warning', 'Error updating focus area status. Please try again.');
|
|
152
|
+
}
|
|
153
|
+
};
|
|
128
154
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
129
155
|
react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200" },
|
|
130
156
|
react_1.default.createElement("div", { className: "px-6 py-4 border-b border-gray-200" },
|
|
@@ -145,9 +171,13 @@ const FocusAreas = ({ focusAreas, updateOpportunityFocusArea, GetOpportunityInsi
|
|
|
145
171
|
STATUS_ICONS[area.status],
|
|
146
172
|
" ",
|
|
147
173
|
area.status.replace('_', ' '))),
|
|
148
|
-
react_1.default.createElement("
|
|
149
|
-
react_1.default.createElement("
|
|
150
|
-
|
|
174
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-2" },
|
|
175
|
+
area.status !== 'COMPLETED' && (react_1.default.createElement("button", { onClick: () => handleStatusUpdate(area, 'COMPLETED'), className: "flex items-center space-x-1 px-2 py-1 text-xs font-medium text-green-600 bg-green-50 hover:text-green-800 hover:bg-green-100 rounded transition-colors" },
|
|
176
|
+
react_1.default.createElement("span", null, "\u2713"),
|
|
177
|
+
react_1.default.createElement("span", null, "Mark as Complete"))),
|
|
178
|
+
react_1.default.createElement("button", { onClick: () => handleEditClick(area), className: "flex items-center space-x-1 px-2 py-1 text-xs font-medium text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded transition-colors" },
|
|
179
|
+
react_1.default.createElement("span", null, "\u270F\uFE0F"),
|
|
180
|
+
react_1.default.createElement("span", null, "Edit Focus Area")))),
|
|
151
181
|
react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-2" }, area.description),
|
|
152
182
|
react_1.default.createElement("div", { className: "flex items-center space-x-4 text-xs text-gray-500" },
|
|
153
183
|
react_1.default.createElement("span", null, (0, date_fns_1.format)(new Date(area.dueDate), 'MMM dd, yyyy')),
|
|
@@ -77,48 +77,51 @@ const getPriorityLevel = (priority) => {
|
|
|
77
77
|
return PRIORITY_LEVELS[0];
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
+
// Convert priority level string to priority value
|
|
81
|
+
const getPriorityNumber = (priorityLevel) => {
|
|
82
|
+
switch (priorityLevel) {
|
|
83
|
+
case 'Urgent - Blocks current work': return 'HIGH';
|
|
84
|
+
case 'High - Needed this week': return 'MEDIUM';
|
|
85
|
+
case 'Medium - Needed next week':
|
|
86
|
+
case 'Low - Needed eventually':
|
|
87
|
+
default: return 'LOW';
|
|
88
|
+
}
|
|
89
|
+
};
|
|
80
90
|
// Request Information Modal Component
|
|
81
91
|
const RequestInfoModal = ({ isOpen, missingInfoItem, onClose, onSubmit, documentCenterController, isInternal, handleRouteToDocuments, isParoIntelligenceRolePresent, }) => {
|
|
82
92
|
const [submitting, setSubmitting] = (0, react_1.useState)(false);
|
|
83
|
-
const [
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
specificInformation: '',
|
|
87
|
-
});
|
|
93
|
+
const [informationCategory, setInformationCategory] = (0, react_1.useState)(INFORMATION_CATEGORIES[0]);
|
|
94
|
+
const [priorityLevel, setPriorityLevel] = (0, react_1.useState)(PRIORITY_LEVELS[0]);
|
|
95
|
+
const [specificInformation, setSpecificInformation] = (0, react_1.useState)('');
|
|
88
96
|
react_1.default.useEffect(() => {
|
|
89
97
|
if (missingInfoItem) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
specificInformation: missingInfoItem.description || '',
|
|
94
|
-
});
|
|
98
|
+
setInformationCategory(missingInfoItem.category || INFORMATION_CATEGORIES[0]);
|
|
99
|
+
setPriorityLevel(getPriorityLevel(missingInfoItem.priority));
|
|
100
|
+
setSpecificInformation(missingInfoItem.description || '');
|
|
95
101
|
}
|
|
96
102
|
}, [missingInfoItem]);
|
|
103
|
+
const handleCancel = () => {
|
|
104
|
+
setInformationCategory(INFORMATION_CATEGORIES[0]);
|
|
105
|
+
setPriorityLevel(PRIORITY_LEVELS[0]);
|
|
106
|
+
setSpecificInformation('');
|
|
107
|
+
setSubmitting(false);
|
|
108
|
+
onClose();
|
|
109
|
+
};
|
|
97
110
|
const handleSubmit = () => {
|
|
98
111
|
setSubmitting(true);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
const data = {
|
|
113
|
+
informationCategory: informationCategory,
|
|
114
|
+
priority: getPriorityNumber(priorityLevel),
|
|
115
|
+
specificInformation: specificInformation,
|
|
116
|
+
};
|
|
117
|
+
if (onSubmit) {
|
|
118
|
+
onSubmit(data);
|
|
119
|
+
setInformationCategory(INFORMATION_CATEGORIES[0]);
|
|
120
|
+
setPriorityLevel(PRIORITY_LEVELS[0]);
|
|
121
|
+
setSpecificInformation('');
|
|
106
122
|
setSubmitting(false);
|
|
123
|
+
onClose();
|
|
107
124
|
}
|
|
108
|
-
onClose();
|
|
109
|
-
};
|
|
110
|
-
const handleCancel = () => {
|
|
111
|
-
// Reset form data when canceling
|
|
112
|
-
if (missingInfoItem) {
|
|
113
|
-
setFormData({
|
|
114
|
-
informationCategory: missingInfoItem.category || '',
|
|
115
|
-
priorityLevel: missingInfoItem.priority === 'HIGH' ? 'Urgent - Blocks current work' :
|
|
116
|
-
missingInfoItem.priority === 'MEDIUM' ? 'High - Needed this week' :
|
|
117
|
-
'Medium - Needed next week',
|
|
118
|
-
specificInformation: missingInfoItem.description || '',
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
onClose();
|
|
122
125
|
};
|
|
123
126
|
const handleOpenDocumentCenter = () => {
|
|
124
127
|
if (isInternal && handleRouteToDocuments) {
|
|
@@ -155,17 +158,13 @@ const RequestInfoModal = ({ isOpen, missingInfoItem, onClose, onSubmit, document
|
|
|
155
158
|
"View Documents in Document Center"))))),
|
|
156
159
|
react_1.default.createElement("div", null,
|
|
157
160
|
react_1.default.createElement("label", { htmlFor: "informationCategory", className: "block text-sm font-medium text-gray-700 mb-1" }, "Information Category"),
|
|
158
|
-
react_1.default.createElement("select", { id: "informationCategory", disabled: isInternal && !isParoIntelligenceRolePresent, value:
|
|
161
|
+
react_1.default.createElement("select", { id: "informationCategory", disabled: isInternal && !isParoIntelligenceRolePresent, value: informationCategory, onChange: (e) => { var _a; return setInformationCategory((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value); }, className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" }, INFORMATION_CATEGORIES.map((category) => (react_1.default.createElement("option", { key: category, value: category }, category))))),
|
|
159
162
|
react_1.default.createElement("div", null,
|
|
160
163
|
react_1.default.createElement("label", { htmlFor: "priorityLevel", className: "block text-sm font-medium text-gray-700 mb-1" }, "Priority Level"),
|
|
161
|
-
react_1.default.createElement("select", { id: "priorityLevel", disabled: isInternal && !isParoIntelligenceRolePresent, value:
|
|
164
|
+
react_1.default.createElement("select", { id: "priorityLevel", disabled: isInternal && !isParoIntelligenceRolePresent, value: priorityLevel, onChange: (e) => { var _a; return setPriorityLevel((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value); }, className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm" }, PRIORITY_LEVELS.map((level) => (react_1.default.createElement("option", { key: level, value: level }, level))))),
|
|
162
165
|
react_1.default.createElement("div", null,
|
|
163
166
|
react_1.default.createElement("label", { htmlFor: "specificInformation", className: "block text-sm font-medium text-gray-700 mb-1" }, "Specific Information Needed"),
|
|
164
|
-
react_1.default.createElement("textarea", { id: "specificInformation", disabled: isInternal && !isParoIntelligenceRolePresent, value:
|
|
165
|
-
debugger;
|
|
166
|
-
setFormData(prev => { var _a; return (Object.assign(Object.assign({}, prev), { specificInformation: (_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value })); });
|
|
167
|
-
console.log('formData', formData);
|
|
168
|
-
}, rows: 4, className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm", placeholder: "Need NetSuite configuration details:\n \n 1. US vs Colombian entity setup\n 2. Consolidation process and requirements" }))),
|
|
167
|
+
react_1.default.createElement("textarea", { id: "specificInformation", disabled: isInternal && !isParoIntelligenceRolePresent, value: specificInformation, onChange: (e) => { var _a; return setSpecificInformation((_a = e === null || e === void 0 ? void 0 : e.target) === null || _a === void 0 ? void 0 : _a.value); }, rows: 4, className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm", placeholder: "Need NetSuite configuration details:\n \n 1. US vs Colombian entity setup\n 2. Consolidation process and requirements" }))),
|
|
169
168
|
react_1.default.createElement("div", { className: "px-6 py-4 border-t border-gray-200 flex justify-end space-x-3" },
|
|
170
169
|
react_1.default.createElement("button", { onClick: handleCancel, className: "px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-gray-500 transition-colors" }, "Cancel"),
|
|
171
170
|
react_1.default.createElement("button", { onClick: handleSubmit, disabled: isInternal && !isParoIntelligenceRolePresent, className: `px-4 py-2 text-sm font-medium text-white bg-blue bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors cursor-${isInternal && !isParoIntelligenceRolePresent ? "not-allowed" : "pointer"}` }, buttonText)))));
|
|
@@ -6,16 +6,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.ProgressTracker = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const PHASE_TABS = [
|
|
9
|
-
{ id: '
|
|
9
|
+
{ id: 'prekickoff', label: 'Pre-Kickoff', active: true },
|
|
10
10
|
{ id: 'kickoff', label: 'Kickoff', active: false },
|
|
11
11
|
{ id: 'setup', label: 'Setup', active: false },
|
|
12
12
|
{ id: 'active', label: 'Active', active: false },
|
|
13
13
|
{ id: 'renewal', label: 'Renewal', active: false },
|
|
14
14
|
];
|
|
15
|
-
const ProgressTracker = ({ percentage, currentPhase,
|
|
15
|
+
const ProgressTracker = ({ percentage, currentPhase, }) => {
|
|
16
16
|
return (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 mt-6" },
|
|
17
17
|
react_1.default.createElement("div", { className: "px-6 py-4 border-b border-gray-200" },
|
|
18
|
-
react_1.default.createElement("div", { className: "flex space-x-2" }, PHASE_TABS.map((phase) => (react_1.default.createElement("button", { key: phase.id, disabled:
|
|
18
|
+
react_1.default.createElement("div", { className: "flex space-x-2" }, PHASE_TABS.map((phase) => (react_1.default.createElement("button", { key: phase.id, disabled: phase.id.toLowerCase() !== currentPhase.toLowerCase(), className: `px-4 py-2 text-sm font-medium rounded-md transition-colors ${phase.id.toLowerCase() === currentPhase.toLowerCase()
|
|
19
19
|
? 'bg-green-100 text-green-800 border border-green-200 hover:bg-green-200 cursor-pointer'
|
|
20
20
|
: 'text-gray-400 bg-gray-50 border border-gray-200 cursor-not-allowed opacity-60'}` }, phase.label)))))));
|
|
21
21
|
};
|
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
4
24
|
};
|
|
5
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
26
|
exports.ProjectIntelligence = void 0;
|
|
7
|
-
const react_1 =
|
|
27
|
+
const react_1 = __importStar(require("react"));
|
|
8
28
|
const EngagementHeader_1 = require("./EngagementHeader");
|
|
9
29
|
const ProgressTracker_1 = require("./ProgressTracker");
|
|
10
30
|
const FocusAreas_1 = require("./FocusAreas");
|
|
@@ -14,7 +34,13 @@ const KeyMetrics_1 = require("./KeyMetrics");
|
|
|
14
34
|
const MissingInformation_1 = require("./MissingInformation");
|
|
15
35
|
const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityInsightsData, selectedOpportunityId, setSelectedOpportunityId, GetOpportunityInsightsDocument, updateOpportunityMissingInformation, documentCenterController = null, updateOpportunityFocusArea, isInternal = false, handleRouteToDocuments, onSaveFocusArea, onSaveMissingInformation, isParoIntelligenceRolePresent = false, }) => {
|
|
16
36
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
|
|
37
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
38
|
+
const [currentPhase, setCurrentPhase] = (0, react_1.useState)('Setup');
|
|
39
|
+
const [nextStageData, setNextStageData] = (0, react_1.useState)(null);
|
|
17
40
|
const opportunityInsights = opportunityInsightsData === null || opportunityInsightsData === void 0 ? void 0 : opportunityInsightsData.getOpportunityInsights;
|
|
41
|
+
(0, react_1.useEffect)(() => {
|
|
42
|
+
setCurrentPhase((opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.phase) || 'In_Progress');
|
|
43
|
+
}, [opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.phase]);
|
|
18
44
|
// Create client tabs from checkIfOpportunityInsightsExistData
|
|
19
45
|
const clientTabs = ((_a = checkIfOpportunityInsightsExistData === null || checkIfOpportunityInsightsExistData === void 0 ? void 0 : checkIfOpportunityInsightsExistData.checkIfOpportunityInsightsExist) === null || _a === void 0 ? void 0 : _a.map((insight) => ({
|
|
20
46
|
id: insight.opportunityId,
|
|
@@ -77,8 +103,12 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
77
103
|
};
|
|
78
104
|
// Convert API focus areas to component format
|
|
79
105
|
const convertFocusAreas = () => {
|
|
80
|
-
if (!(opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.focusAreas))
|
|
106
|
+
if (!(opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.focusAreas) && !nextStageData)
|
|
81
107
|
return [];
|
|
108
|
+
// If we're showing the next stage data, return that instead
|
|
109
|
+
if (nextStageData && currentPhase === 'Active') {
|
|
110
|
+
return nextStageData.focusAreas;
|
|
111
|
+
}
|
|
82
112
|
return opportunityInsights.focusAreas.map((area, index) => ({
|
|
83
113
|
id: (area === null || area === void 0 ? void 0 : area.id) || `focus-${index}`,
|
|
84
114
|
title: (area === null || area === void 0 ? void 0 : area.title) || 'N/A',
|
|
@@ -88,6 +118,87 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
88
118
|
priority: mapPriority(area === null || area === void 0 ? void 0 : area.priority)
|
|
89
119
|
}));
|
|
90
120
|
};
|
|
121
|
+
// Check if all focus areas are completed
|
|
122
|
+
const areAllFocusAreasCompleted = () => {
|
|
123
|
+
if (!(opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.focusAreas) || opportunityInsights.focusAreas.length === 0) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
return opportunityInsights.focusAreas.every((area) => mapFocusAreaStatus(area === null || area === void 0 ? void 0 : area.status) === 'COMPLETED');
|
|
127
|
+
};
|
|
128
|
+
// Handle moving to the next stage
|
|
129
|
+
const handleMoveToNextStage = () => {
|
|
130
|
+
setIsLoading(true);
|
|
131
|
+
// Create next stage data with financial focus areas and carry over missing information
|
|
132
|
+
const nextStageFocusAreas = [
|
|
133
|
+
{
|
|
134
|
+
id: 'next-focus-1',
|
|
135
|
+
title: 'Clean up prior accounting periods',
|
|
136
|
+
description: 'Review and bring the company\'s books up-to-date for all prior accounting periods before the project start date. This includes entering invoices, applying payments, entering bills, categorizing transactions, and reconciling accounts test',
|
|
137
|
+
status: 'CONFIRMED',
|
|
138
|
+
dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days from now
|
|
139
|
+
priority: 'HIGH'
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'next-focus-2',
|
|
143
|
+
title: 'Ongoing bookkeeping and accounting',
|
|
144
|
+
description: 'Provide monthly bookkeeping and accounting support including invoice entry, payment processing, bill entry, transaction categorization, account reconciliations, and reporting package delivery.',
|
|
145
|
+
status: 'CONFIRMED',
|
|
146
|
+
dueDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString(), // 14 days from now
|
|
147
|
+
priority: 'MEDIUM'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'next-focus-3',
|
|
151
|
+
title: 'Transition to new accounting system',
|
|
152
|
+
description: 'Assist in preparing the books and migrating data to the company\'s new front-end accounting system once implemented.',
|
|
153
|
+
status: 'CONFIRMED',
|
|
154
|
+
dueDate: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000).toISOString(), // 10 days from now
|
|
155
|
+
priority: 'HIGH'
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
// Carry over missing information that doesn't have CLIENT_RESPONDED status
|
|
159
|
+
const carriedOverMissingInfo = (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.missingInformation)
|
|
160
|
+
? opportunityInsights.missingInformation
|
|
161
|
+
.filter((item) => (item === null || item === void 0 ? void 0 : item.status) !== 'CLIENT_RESPONDED')
|
|
162
|
+
.map((item, index) => (Object.assign(Object.assign({}, item), { id: `carried-${item.id || index}` })))
|
|
163
|
+
: [];
|
|
164
|
+
// Add new missing information items
|
|
165
|
+
const newMissingInfo = [
|
|
166
|
+
{
|
|
167
|
+
id: 'new-missing-1',
|
|
168
|
+
title: 'Financial Transaction History',
|
|
169
|
+
description: 'Need access to the last 6 months of financial transaction history for the project',
|
|
170
|
+
priority: 'HIGH',
|
|
171
|
+
category: 'Financial',
|
|
172
|
+
status: 'PENDING'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: 'new-missing-2',
|
|
176
|
+
title: 'Budget Approval Documentation',
|
|
177
|
+
description: 'Require documentation showing approval of the current budget allocation',
|
|
178
|
+
priority: 'MEDIUM',
|
|
179
|
+
category: 'Documentation',
|
|
180
|
+
status: 'PENDING'
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: 'new-missing-3',
|
|
184
|
+
title: 'Financial Stakeholder Contact Information',
|
|
185
|
+
description: 'Need contact details for all financial stakeholders involved in the project',
|
|
186
|
+
priority: 'LOW',
|
|
187
|
+
category: 'Contact',
|
|
188
|
+
status: 'PENDING'
|
|
189
|
+
}
|
|
190
|
+
];
|
|
191
|
+
// Set the next stage data
|
|
192
|
+
setNextStageData({
|
|
193
|
+
focusAreas: nextStageFocusAreas,
|
|
194
|
+
missingInformation: [...carriedOverMissingInfo, ...newMissingInfo]
|
|
195
|
+
});
|
|
196
|
+
// Simulate loading and then update the UI
|
|
197
|
+
setTimeout(() => {
|
|
198
|
+
setCurrentPhase('Active');
|
|
199
|
+
setIsLoading(false);
|
|
200
|
+
}, 3000);
|
|
201
|
+
};
|
|
91
202
|
const hasNoProjectIntelligence = !(checkIfOpportunityInsightsExistData === null || checkIfOpportunityInsightsExistData === void 0 ? void 0 : checkIfOpportunityInsightsExistData.checkIfOpportunityInsightsExist) ||
|
|
92
203
|
checkIfOpportunityInsightsExistData.checkIfOpportunityInsightsExist.length === 0;
|
|
93
204
|
// If there's no data, show a message
|
|
@@ -99,11 +210,54 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
99
210
|
react_1.default.createElement("div", { className: "text-2xl font-bold text-gray-700 mb-2" }, "No project intelligence found"),
|
|
100
211
|
react_1.default.createElement("p", { className: "text-gray-500 max-w-md" }, "No project intelligence found for your won projects. Please check back after you win your next Opportunity!")))));
|
|
101
212
|
}
|
|
213
|
+
// Get missing information items based on current phase
|
|
214
|
+
const getMissingInformationItems = () => {
|
|
215
|
+
if (nextStageData && currentPhase === 'Active') {
|
|
216
|
+
return nextStageData.missingInformation.map((item, index) => ({
|
|
217
|
+
id: (item === null || item === void 0 ? void 0 : item.id) || `missing-${index}`,
|
|
218
|
+
title: (item === null || item === void 0 ? void 0 : item.title) || 'N/A',
|
|
219
|
+
description: (item === null || item === void 0 ? void 0 : item.description) || 'N/A',
|
|
220
|
+
priority: mapPriority(item === null || item === void 0 ? void 0 : item.priority),
|
|
221
|
+
category: (item === null || item === void 0 ? void 0 : item.category) || 'N/A',
|
|
222
|
+
status: (item === null || item === void 0 ? void 0 : item.status) || undefined,
|
|
223
|
+
clientResponse: (item === null || item === void 0 ? void 0 : item.clientResponse) || undefined
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
return (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.missingInformation) ?
|
|
227
|
+
opportunityInsights.missingInformation.map((item, index) => ({
|
|
228
|
+
id: (item === null || item === void 0 ? void 0 : item.id) || `missing-${index}`,
|
|
229
|
+
title: (item === null || item === void 0 ? void 0 : item.title) || 'N/A',
|
|
230
|
+
description: (item === null || item === void 0 ? void 0 : item.description) || 'N/A',
|
|
231
|
+
priority: mapPriority(item === null || item === void 0 ? void 0 : item.priority),
|
|
232
|
+
category: (item === null || item === void 0 ? void 0 : item.category) || 'N/A',
|
|
233
|
+
status: (item === null || item === void 0 ? void 0 : item.status) || undefined,
|
|
234
|
+
clientResponse: (item === null || item === void 0 ? void 0 : item.clientResponse) || undefined
|
|
235
|
+
})) : [];
|
|
236
|
+
};
|
|
237
|
+
// Get the current phase and next steps text based on the current phase
|
|
238
|
+
const getPhaseInfo = () => {
|
|
239
|
+
if (currentPhase === 'Kickoff') {
|
|
240
|
+
return {
|
|
241
|
+
phaseDisplay: 'Kickoff Phase (Day 1 of 3)',
|
|
242
|
+
nextSteps: 'System access & team introductions'
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
return {
|
|
247
|
+
phaseDisplay: 'Preparation Phase',
|
|
248
|
+
nextSteps: 'Complete initial focus areas'
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const phaseInfo = getPhaseInfo();
|
|
102
253
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
103
254
|
react_1.default.createElement("div", { className: "mx-auto px-4 py-8" },
|
|
104
|
-
react_1.default.createElement(EngagementHeader_1.EngagementHeader, { clientName: (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.opportunityName) || '', expertName: ((_b = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.expertInfo) === null || _b === void 0 ? void 0 : _b.name) || '', expertTitle: ((_c = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.expertInfo) === null || _c === void 0 ? void 0 : _c.role) || '', startDate: (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.startDate) || '', status: (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.phase) || 'In_Progress', clientTabs: clientTabs, selectedClientId: selectedOpportunityId, onClientChange: handleClientChange }),
|
|
105
|
-
react_1.default.createElement(ProgressTracker_1.ProgressTracker, { percentage: 0, currentPhase:
|
|
106
|
-
react_1.default.createElement("div", { className: "flex
|
|
255
|
+
react_1.default.createElement(EngagementHeader_1.EngagementHeader, { clientName: (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.opportunityName) || '', expertName: ((_b = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.expertInfo) === null || _b === void 0 ? void 0 : _b.name) || '', expertTitle: ((_c = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.expertInfo) === null || _c === void 0 ? void 0 : _c.role) || '', startDate: (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.startDate) || '', status: currentPhase || (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.phase) || 'In_Progress', clientTabs: clientTabs, selectedClientId: selectedOpportunityId, onClientChange: handleClientChange, allFocusAreasCompleted: areAllFocusAreasCompleted(), onMoveToNextStage: handleMoveToNextStage, isLoading: isLoading }),
|
|
256
|
+
react_1.default.createElement(ProgressTracker_1.ProgressTracker, { percentage: 0, currentPhase: currentPhase }),
|
|
257
|
+
isLoading ? (react_1.default.createElement("div", { className: "flex items-center justify-center h-64" },
|
|
258
|
+
react_1.default.createElement("div", { className: "text-center" },
|
|
259
|
+
react_1.default.createElement("div", { className: "animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto mb-4" }),
|
|
260
|
+
react_1.default.createElement("p", { className: "text-lg font-medium text-gray-700" }, "Calculating Intelligence for your next Stage")))) : (react_1.default.createElement("div", { className: "flex flex-row space-x-4 mt-8" },
|
|
107
261
|
react_1.default.createElement("div", { className: "w-2/3 space-7-4" },
|
|
108
262
|
react_1.default.createElement(FocusAreas_1.FocusAreas, { focusAreas: convertFocusAreas(), onEditFocusAreas: () => { }, updateOpportunityFocusArea: updateOpportunityFocusArea, GetOpportunityInsightsDocument: GetOpportunityInsightsDocument, selectedOpportunityId: selectedOpportunityId, onSaveFocusArea: onSaveFocusArea }),
|
|
109
263
|
react_1.default.createElement(ProjectHealth_1.ProjectHealth, { healthData: {
|
|
@@ -124,16 +278,7 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
124
278
|
description: ((_u = (_t = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.opportunityHealth) === null || _t === void 0 ? void 0 : _t.riskManagement) === null || _u === void 0 ? void 0 : _u.description) || 'N/A'
|
|
125
279
|
}
|
|
126
280
|
}, className: "mt-8" }),
|
|
127
|
-
react_1.default.createElement(MissingInformation_1.MissingInformation, { items: (
|
|
128
|
-
opportunityInsights.missingInformation.map((item, index) => ({
|
|
129
|
-
id: (item === null || item === void 0 ? void 0 : item.id) || `missing-${index}`,
|
|
130
|
-
title: (item === null || item === void 0 ? void 0 : item.title) || 'N/A',
|
|
131
|
-
description: (item === null || item === void 0 ? void 0 : item.description) || 'N/A',
|
|
132
|
-
priority: mapPriority(item === null || item === void 0 ? void 0 : item.priority),
|
|
133
|
-
category: (item === null || item === void 0 ? void 0 : item.category) || 'N/A',
|
|
134
|
-
status: (item === null || item === void 0 ? void 0 : item.status) || undefined,
|
|
135
|
-
clientResponse: (item === null || item === void 0 ? void 0 : item.clientResponse) || undefined
|
|
136
|
-
})) : [], className: "mt-8", opportunityId: selectedOpportunityId, GetOpportunityInsightsDocument: GetOpportunityInsightsDocument, updateOpportunityMissingInformation: updateOpportunityMissingInformation, documentCenterController: documentCenterController, isInternal: isInternal, handleRouteToDocuments: handleRouteToDocuments, onSaveMissingInformation: onSaveMissingInformation, isParoIntelligenceRolePresent: isParoIntelligenceRolePresent })),
|
|
281
|
+
react_1.default.createElement(MissingInformation_1.MissingInformation, { items: getMissingInformationItems(), className: "mt-8", opportunityId: selectedOpportunityId, GetOpportunityInsightsDocument: GetOpportunityInsightsDocument, updateOpportunityMissingInformation: updateOpportunityMissingInformation, documentCenterController: documentCenterController, isInternal: isInternal, handleRouteToDocuments: handleRouteToDocuments, onSaveMissingInformation: onSaveMissingInformation, isParoIntelligenceRolePresent: isParoIntelligenceRolePresent })),
|
|
137
282
|
react_1.default.createElement("div", { className: "w-1/3 space-y-4" },
|
|
138
283
|
react_1.default.createElement(TeamSection_1.TeamSection, { clientTeam: opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.clientTeam, expert: {
|
|
139
284
|
id: 'expert-1',
|
|
@@ -159,6 +304,6 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
159
304
|
challenge: ((_8 = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.businessContext) === null || _8 === void 0 ? void 0 : _8.challenge) || 'N/A',
|
|
160
305
|
opportunity: ((_9 = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.businessContext) === null || _9 === void 0 ? void 0 : _9.opportunity) || 'N/A',
|
|
161
306
|
tags: ((_10 = opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.businessContext) === null || _10 === void 0 ? void 0 : _10.tags) || []
|
|
162
|
-
}, GetOpportunityInsightsDocument: GetOpportunityInsightsDocument, selectedOpportunityId: selectedOpportunityId }))))));
|
|
307
|
+
}, GetOpportunityInsightsDocument: GetOpportunityInsightsDocument, selectedOpportunityId: selectedOpportunityId })))))));
|
|
163
308
|
};
|
|
164
309
|
exports.ProjectIntelligence = ProjectIntelligence;
|