@platform-modules/civil-aviation-authority 2.3.279 → 2.3.280
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.
|
@@ -15,11 +15,10 @@ export declare function workflowTemplate(key: string, params?: Record<string, st
|
|
|
15
15
|
export declare function chatTemplate(key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
16
16
|
export declare function resolveWorkflowStatusAr(status: string | null | undefined): string | null;
|
|
17
17
|
export declare function resolveChatStatusAr(status: string | null | undefined): string | null;
|
|
18
|
-
/** Arabic
|
|
19
|
-
export declare function
|
|
20
|
-
export declare function pickArabicName(arabicName?: string | null, fallback?: string): string;
|
|
18
|
+
/** Arabic column value only — never falls back to English (for content_ar / message_ar). */
|
|
19
|
+
export declare function pickArabicName(arabicName?: string | null): string;
|
|
21
20
|
export declare function pickLocalizedName(englishName?: string | null, arabicName?: string | null, fallback?: string): string;
|
|
22
|
-
/**
|
|
21
|
+
/** EN from English columns; AR from Arabic columns only (no English in ar). */
|
|
23
22
|
export declare function joinDeptSectionBilingualLabels(deptEn?: string | null, deptAr?: string | null, sectEn?: string | null, sectAr?: string | null): {
|
|
24
23
|
en: string;
|
|
25
24
|
ar: string;
|
|
@@ -9,7 +9,6 @@ exports.workflowTemplate = workflowTemplate;
|
|
|
9
9
|
exports.chatTemplate = chatTemplate;
|
|
10
10
|
exports.resolveWorkflowStatusAr = resolveWorkflowStatusAr;
|
|
11
11
|
exports.resolveChatStatusAr = resolveChatStatusAr;
|
|
12
|
-
exports.resolveBilingualName = resolveBilingualName;
|
|
13
12
|
exports.pickArabicName = pickArabicName;
|
|
14
13
|
exports.pickLocalizedName = pickLocalizedName;
|
|
15
14
|
exports.joinDeptSectionBilingualLabels = joinDeptSectionBilingualLabels;
|
|
@@ -60,15 +59,9 @@ function resolveChatStatusAr(status) {
|
|
|
60
59
|
return null;
|
|
61
60
|
return CHAT_STATUS_LABELS[status] ?? status;
|
|
62
61
|
}
|
|
63
|
-
/** Arabic
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
if (ar)
|
|
67
|
-
return ar;
|
|
68
|
-
return englishName?.trim() || '';
|
|
69
|
-
}
|
|
70
|
-
function pickArabicName(arabicName, fallback = '') {
|
|
71
|
-
return arabicName?.trim() || fallback;
|
|
62
|
+
/** Arabic column value only — never falls back to English (for content_ar / message_ar). */
|
|
63
|
+
function pickArabicName(arabicName) {
|
|
64
|
+
return arabicName?.trim() || '';
|
|
72
65
|
}
|
|
73
66
|
function pickLocalizedName(englishName, arabicName, fallback = '') {
|
|
74
67
|
const ar = arabicName?.trim();
|
|
@@ -82,11 +75,12 @@ function pickLocalizedName(englishName, arabicName, fallback = '') {
|
|
|
82
75
|
function joinDeptSectionLabels(dept, section) {
|
|
83
76
|
return [dept, section].map((s) => s?.trim()).filter(Boolean).join(' - ');
|
|
84
77
|
}
|
|
85
|
-
/**
|
|
78
|
+
/** EN from English columns; AR from Arabic columns only (no English in ar). */
|
|
86
79
|
function joinDeptSectionBilingualLabels(deptEn, deptAr, sectEn, sectAr) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
80
|
+
return {
|
|
81
|
+
en: joinDeptSectionLabels(deptEn, sectEn),
|
|
82
|
+
ar: joinDeptSectionLabels(deptAr, sectAr),
|
|
83
|
+
};
|
|
90
84
|
}
|
|
91
85
|
/** @deprecated Use joinDeptSectionBilingualLabels */
|
|
92
86
|
function joinDeptSectionArabicLabels(deptArabic, sectionArabic) {
|
|
@@ -100,48 +94,73 @@ function formatChatCommentSuffix(comment) {
|
|
|
100
94
|
const text = comment?.trim();
|
|
101
95
|
return text ? ` - ${text}` : '';
|
|
102
96
|
}
|
|
103
|
-
function buildWorkflowApprovalByName(templateKey, nameEn, nameAr, comment) {
|
|
97
|
+
function buildWorkflowApprovalByName(templateKey, fallbackKey, nameEn, nameAr, comment) {
|
|
104
98
|
const commentSuffix = formatWorkflowCommentSuffix(comment);
|
|
105
|
-
return
|
|
99
|
+
return {
|
|
100
|
+
en: workflowTemplate(templateKey, { name: nameEn, comment: commentSuffix }).en,
|
|
101
|
+
ar: nameAr
|
|
102
|
+
? workflowTemplate(templateKey, { name: nameAr, comment: '' }).ar
|
|
103
|
+
: workflowTemplate(fallbackKey, { comment: '' }).ar,
|
|
104
|
+
};
|
|
106
105
|
}
|
|
107
106
|
function buildWorkflowApprovalWithoutName(templateKey, comment) {
|
|
108
107
|
const commentSuffix = formatWorkflowCommentSuffix(comment);
|
|
109
|
-
return
|
|
108
|
+
return {
|
|
109
|
+
en: workflowTemplate(templateKey, { comment: commentSuffix }).en,
|
|
110
|
+
ar: workflowTemplate(templateKey, { comment: '' }).ar,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function buildWorkflowFromNamePair(templateWithNameKey, templateWithoutNameKey, nameEn, nameAr) {
|
|
114
|
+
return {
|
|
115
|
+
en: workflowTemplate(templateWithNameKey, { name: nameEn }).en,
|
|
116
|
+
ar: nameAr
|
|
117
|
+
? workflowTemplate(templateWithNameKey, { name: nameAr }).ar
|
|
118
|
+
: workflowTemplate(templateWithoutNameKey).ar,
|
|
119
|
+
};
|
|
110
120
|
}
|
|
111
121
|
function buildApprovalWorkflowContent(params) {
|
|
112
122
|
const nameEn = params.roleName?.trim() || '';
|
|
113
|
-
const nameAr =
|
|
123
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
114
124
|
if (params.status === 'Approved') {
|
|
115
125
|
return nameEn
|
|
116
|
-
? buildWorkflowApprovalByName('request_approved_by', nameEn, nameAr, params.comment)
|
|
126
|
+
? buildWorkflowApprovalByName('request_approved_by', 'request_approved', nameEn, nameAr, params.comment)
|
|
117
127
|
: buildWorkflowApprovalWithoutName('request_approved', params.comment);
|
|
118
128
|
}
|
|
119
129
|
if (params.status === 'Rejected') {
|
|
120
130
|
return nameEn
|
|
121
|
-
? buildWorkflowApprovalByName('request_rejected_by', nameEn, nameAr, params.comment)
|
|
131
|
+
? buildWorkflowApprovalByName('request_rejected_by', 'request_rejected', nameEn, nameAr, params.comment)
|
|
122
132
|
: buildWorkflowApprovalWithoutName('request_rejected', params.comment);
|
|
123
133
|
}
|
|
124
134
|
if (params.status === 'Returned for Modification') {
|
|
125
135
|
return nameEn
|
|
126
|
-
? buildWorkflowApprovalByName('request_returned_for_modification_by', nameEn, nameAr, params.comment)
|
|
136
|
+
? buildWorkflowApprovalByName('request_returned_for_modification_by', 'request_returned_for_modification', nameEn, nameAr, params.comment)
|
|
127
137
|
: buildWorkflowApprovalWithoutName('request_returned_for_modification', params.comment);
|
|
128
138
|
}
|
|
129
139
|
const commentSuffix = formatWorkflowCommentSuffix(params.comment);
|
|
130
140
|
if (nameEn) {
|
|
131
|
-
return
|
|
141
|
+
return {
|
|
142
|
+
en: workflowTemplate('request_approval_pending_from', { name: nameEn, comment: commentSuffix }).en,
|
|
143
|
+
ar: nameAr
|
|
144
|
+
? workflowTemplate('request_approval_pending_from', { name: nameAr, comment: '' }).ar
|
|
145
|
+
: workflowTemplate('request_approval_pending', { comment: '' }).ar,
|
|
146
|
+
};
|
|
132
147
|
}
|
|
133
|
-
return
|
|
148
|
+
return {
|
|
149
|
+
en: workflowTemplate('request_approval_pending', { comment: commentSuffix }).en,
|
|
150
|
+
ar: workflowTemplate('request_approval_pending', { comment: '' }).ar,
|
|
151
|
+
};
|
|
134
152
|
}
|
|
135
153
|
function buildHumanApprovalWorkflowContent(params) {
|
|
136
|
-
const
|
|
154
|
+
const withNameKey = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
155
|
+
const withoutNameKey = params.isFirst ? 'request_approval_in_progress' : 'request_approval_pending';
|
|
137
156
|
if (params.roleName?.trim()) {
|
|
138
157
|
const nameEn = params.roleName.trim();
|
|
139
|
-
const nameAr =
|
|
140
|
-
return
|
|
158
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
159
|
+
return buildWorkflowFromNamePair(withNameKey, withoutNameKey, nameEn, nameAr);
|
|
141
160
|
}
|
|
142
161
|
const { en, ar } = joinDeptSectionBilingualLabels(params.deptName, params.deptArabicName, params.sectionName, params.sectionArabicName);
|
|
143
162
|
if (en) {
|
|
144
|
-
return
|
|
163
|
+
return buildWorkflowFromNamePair(withNameKey, withoutNameKey, en, ar);
|
|
145
164
|
}
|
|
146
165
|
return params.isFirst
|
|
147
166
|
? workflowTemplate('request_approval_in_progress')
|
|
@@ -149,22 +168,32 @@ function buildHumanApprovalWorkflowContent(params) {
|
|
|
149
168
|
}
|
|
150
169
|
function buildApprovalChatMessage(params) {
|
|
151
170
|
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
152
|
-
const roleAr =
|
|
171
|
+
const roleAr = pickArabicName(params.roleArabicName);
|
|
153
172
|
const commentSuffix = formatChatCommentSuffix(params.comment);
|
|
154
|
-
let
|
|
173
|
+
let byRoleKey;
|
|
174
|
+
let withoutRoleKey;
|
|
155
175
|
if (params.status === 'Approved') {
|
|
156
|
-
|
|
176
|
+
byRoleKey = 'request_approved_by_role';
|
|
177
|
+
withoutRoleKey = 'request_approved';
|
|
157
178
|
}
|
|
158
179
|
else if (params.status === 'Rejected') {
|
|
159
|
-
|
|
180
|
+
byRoleKey = 'request_rejected_by_role';
|
|
181
|
+
withoutRoleKey = 'request_rejected';
|
|
160
182
|
}
|
|
161
183
|
else if (params.status === 'Returned for Modification') {
|
|
162
|
-
|
|
184
|
+
byRoleKey = 'request_returned_for_modification_by_role';
|
|
185
|
+
withoutRoleKey = 'request_returned_for_modification';
|
|
163
186
|
}
|
|
164
187
|
else {
|
|
165
|
-
|
|
188
|
+
byRoleKey = 'request_approved_by_role';
|
|
189
|
+
withoutRoleKey = 'request_approved';
|
|
166
190
|
}
|
|
167
|
-
return
|
|
191
|
+
return {
|
|
192
|
+
en: chatTemplate(byRoleKey, { roleName: roleEn, comment: commentSuffix }).en,
|
|
193
|
+
ar: roleAr
|
|
194
|
+
? chatTemplate(byRoleKey, { roleName: roleAr, comment: '' }).ar
|
|
195
|
+
: chatTemplate(withoutRoleKey, { comment: '' }).ar,
|
|
196
|
+
};
|
|
168
197
|
}
|
|
169
198
|
/** Resolve Arabic workflow content from a stored English content string (legacy rows). */
|
|
170
199
|
function resolveWorkflowContentAr(content) {
|
|
@@ -178,8 +207,6 @@ function resolveWorkflowContentAr(content) {
|
|
|
178
207
|
const commentIdx = normalized.indexOf(': ');
|
|
179
208
|
if (commentIdx > 0) {
|
|
180
209
|
const baseEn = normalized.slice(0, commentIdx).trim();
|
|
181
|
-
const commentText = normalized.slice(commentIdx + 2).trim();
|
|
182
|
-
const commentSuffix = formatWorkflowCommentSuffix(commentText);
|
|
183
210
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
184
211
|
if (!tpl.en.includes('{{comment}}'))
|
|
185
212
|
continue;
|
|
@@ -187,15 +214,29 @@ function resolveWorkflowContentAr(content) {
|
|
|
187
214
|
if (withoutComment.includes('{{name}}')) {
|
|
188
215
|
const staticPrefix = withoutComment.replace('{{name}}', '').trim();
|
|
189
216
|
if (baseEn.startsWith(staticPrefix)) {
|
|
190
|
-
const
|
|
191
|
-
|
|
217
|
+
const fallbackKey = Object.entries(WORKFLOW_TEMPLATES).find(([, t]) => t === tpl)?.[0] ?? '';
|
|
218
|
+
if (fallbackKey.includes('_by')) {
|
|
219
|
+
const genericKey = fallbackKey.replace('_by', '');
|
|
220
|
+
if (WORKFLOW_TEMPLATES[genericKey]) {
|
|
221
|
+
return WORKFLOW_TEMPLATES[genericKey].ar;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return tpl.ar.split('{{name}}')[0].trim();
|
|
192
225
|
}
|
|
193
226
|
}
|
|
194
227
|
else if (withoutComment.trim() === baseEn) {
|
|
195
|
-
return interpolate(tpl.ar, { comment:
|
|
228
|
+
return interpolate(tpl.ar, { comment: '' });
|
|
196
229
|
}
|
|
197
230
|
}
|
|
198
231
|
}
|
|
232
|
+
const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
|
|
233
|
+
if (inProgressPrefix && normalized.startsWith(inProgressPrefix)) {
|
|
234
|
+
return WORKFLOW_TEMPLATES.request_approval_in_progress.ar;
|
|
235
|
+
}
|
|
236
|
+
const pendingPrefix = WORKFLOW_TEMPLATES.request_approval_pending_from?.en.split('{{name}}')[0].trim();
|
|
237
|
+
if (pendingPrefix && normalized.startsWith(pendingPrefix)) {
|
|
238
|
+
return WORKFLOW_TEMPLATES.request_approval_pending.ar;
|
|
239
|
+
}
|
|
199
240
|
return null;
|
|
200
241
|
}
|
|
201
242
|
/** Resolve Arabic chat message from a stored English message string (legacy rows). */
|
|
@@ -212,18 +253,26 @@ function resolveChatMessageAr(message) {
|
|
|
212
253
|
function enrichCancellationWorkflowLog(log) {
|
|
213
254
|
const status = log.status != null ? String(log.status) : null;
|
|
214
255
|
const content = log.content != null ? String(log.content) : null;
|
|
256
|
+
const storedAr = log.content_ar != null ? String(log.content_ar).trim() : '';
|
|
257
|
+
const hasEnglishInAr = storedAr && /[A-Za-z]/.test(storedAr);
|
|
215
258
|
return {
|
|
216
259
|
...log,
|
|
217
|
-
content_ar:
|
|
260
|
+
content_ar: hasEnglishInAr
|
|
261
|
+
? (resolveWorkflowContentAr(content) ?? storedAr)
|
|
262
|
+
: (log.content_ar ?? resolveWorkflowContentAr(content)),
|
|
218
263
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
219
264
|
};
|
|
220
265
|
}
|
|
221
266
|
function enrichCancellationChatMessage(chat) {
|
|
222
267
|
const status = chat.status != null ? String(chat.status) : null;
|
|
223
268
|
const message = chat.message != null ? String(chat.message) : null;
|
|
269
|
+
const storedAr = chat.message_ar != null ? String(chat.message_ar).trim() : '';
|
|
270
|
+
const hasEnglishInAr = storedAr && /[A-Za-z]/.test(storedAr);
|
|
224
271
|
return {
|
|
225
272
|
...chat,
|
|
226
|
-
message_ar:
|
|
273
|
+
message_ar: hasEnglishInAr
|
|
274
|
+
? (resolveChatMessageAr(message) ?? storedAr)
|
|
275
|
+
: (chat.message_ar ?? resolveChatMessageAr(message)),
|
|
227
276
|
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
228
277
|
};
|
|
229
278
|
}
|
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
"en": "Cancellation request submitted by {{userName}} ({{employeeId}})",
|
|
59
59
|
"ar": "تم تقديم طلب الإلغاء بواسطة {{userName}} ({{employeeId}})"
|
|
60
60
|
},
|
|
61
|
+
"cancellation_submitted": {
|
|
62
|
+
"en": "Cancellation request submitted",
|
|
63
|
+
"ar": "تم تقديم طلب الإلغاء"
|
|
64
|
+
},
|
|
61
65
|
"request_received": {
|
|
62
66
|
"en": "Request Received",
|
|
63
67
|
"ar": "تم استلام الطلب"
|
|
@@ -73,6 +77,18 @@
|
|
|
73
77
|
"request_returned_for_modification_by_role": {
|
|
74
78
|
"en": "Request Returned for Modification by: {{roleName}}{{comment}}",
|
|
75
79
|
"ar": "تم إرجاع الطلب للتعديل من قبل: {{roleName}}{{comment}}"
|
|
80
|
+
},
|
|
81
|
+
"request_approved": {
|
|
82
|
+
"en": "Request Approved{{comment}}",
|
|
83
|
+
"ar": "تمت الموافقة على الطلب{{comment}}"
|
|
84
|
+
},
|
|
85
|
+
"request_rejected": {
|
|
86
|
+
"en": "Request Rejected{{comment}}",
|
|
87
|
+
"ar": "تم رفض الطلب{{comment}}"
|
|
88
|
+
},
|
|
89
|
+
"request_returned_for_modification": {
|
|
90
|
+
"en": "Request Returned for Modification{{comment}}",
|
|
91
|
+
"ar": "تم إرجاع الطلب للتعديل{{comment}}"
|
|
76
92
|
}
|
|
77
93
|
},
|
|
78
94
|
"workflowStatusLabels": {
|
package/package.json
CHANGED
|
@@ -58,6 +58,10 @@
|
|
|
58
58
|
"en": "Cancellation request submitted by {{userName}} ({{employeeId}})",
|
|
59
59
|
"ar": "تم تقديم طلب الإلغاء بواسطة {{userName}} ({{employeeId}})"
|
|
60
60
|
},
|
|
61
|
+
"cancellation_submitted": {
|
|
62
|
+
"en": "Cancellation request submitted",
|
|
63
|
+
"ar": "تم تقديم طلب الإلغاء"
|
|
64
|
+
},
|
|
61
65
|
"request_received": {
|
|
62
66
|
"en": "Request Received",
|
|
63
67
|
"ar": "تم استلام الطلب"
|
|
@@ -73,6 +77,18 @@
|
|
|
73
77
|
"request_returned_for_modification_by_role": {
|
|
74
78
|
"en": "Request Returned for Modification by: {{roleName}}{{comment}}",
|
|
75
79
|
"ar": "تم إرجاع الطلب للتعديل من قبل: {{roleName}}{{comment}}"
|
|
80
|
+
},
|
|
81
|
+
"request_approved": {
|
|
82
|
+
"en": "Request Approved{{comment}}",
|
|
83
|
+
"ar": "تمت الموافقة على الطلب{{comment}}"
|
|
84
|
+
},
|
|
85
|
+
"request_rejected": {
|
|
86
|
+
"en": "Request Rejected{{comment}}",
|
|
87
|
+
"ar": "تم رفض الطلب{{comment}}"
|
|
88
|
+
},
|
|
89
|
+
"request_returned_for_modification": {
|
|
90
|
+
"en": "Request Returned for Modification{{comment}}",
|
|
91
|
+
"ar": "تم إرجاع الطلب للتعديل{{comment}}"
|
|
76
92
|
}
|
|
77
93
|
},
|
|
78
94
|
"workflowStatusLabels": {
|
|
@@ -66,18 +66,9 @@ export function resolveChatStatusAr(status: string | null | undefined): string |
|
|
|
66
66
|
return CHAT_STATUS_LABELS[status] ?? status;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/** Arabic
|
|
70
|
-
export function
|
|
71
|
-
|
|
72
|
-
arabicName?: string | null,
|
|
73
|
-
): string {
|
|
74
|
-
const ar = arabicName?.trim();
|
|
75
|
-
if (ar) return ar;
|
|
76
|
-
return englishName?.trim() || '';
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function pickArabicName(arabicName?: string | null, fallback = ''): string {
|
|
80
|
-
return arabicName?.trim() || fallback;
|
|
69
|
+
/** Arabic column value only — never falls back to English (for content_ar / message_ar). */
|
|
70
|
+
export function pickArabicName(arabicName?: string | null): string {
|
|
71
|
+
return arabicName?.trim() || '';
|
|
81
72
|
}
|
|
82
73
|
|
|
83
74
|
export function pickLocalizedName(
|
|
@@ -99,19 +90,17 @@ function joinDeptSectionLabels(
|
|
|
99
90
|
return [dept, section].map((s) => s?.trim()).filter(Boolean).join(' - ');
|
|
100
91
|
}
|
|
101
92
|
|
|
102
|
-
/**
|
|
93
|
+
/** EN from English columns; AR from Arabic columns only (no English in ar). */
|
|
103
94
|
export function joinDeptSectionBilingualLabels(
|
|
104
95
|
deptEn?: string | null,
|
|
105
96
|
deptAr?: string | null,
|
|
106
97
|
sectEn?: string | null,
|
|
107
98
|
sectAr?: string | null,
|
|
108
99
|
): { en: string; ar: string } {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
);
|
|
114
|
-
return { en, ar };
|
|
100
|
+
return {
|
|
101
|
+
en: joinDeptSectionLabels(deptEn, sectEn),
|
|
102
|
+
ar: joinDeptSectionLabels(deptAr, sectAr),
|
|
103
|
+
};
|
|
115
104
|
}
|
|
116
105
|
|
|
117
106
|
/** @deprecated Use joinDeptSectionBilingualLabels */
|
|
@@ -132,30 +121,55 @@ function formatChatCommentSuffix(comment?: string | null): string {
|
|
|
132
121
|
return text ? ` - ${text}` : '';
|
|
133
122
|
}
|
|
134
123
|
|
|
124
|
+
type WorkflowByNameKey =
|
|
125
|
+
| 'request_approved_by'
|
|
126
|
+
| 'request_rejected_by'
|
|
127
|
+
| 'request_returned_for_modification_by';
|
|
128
|
+
|
|
129
|
+
type WorkflowWithoutNameKey =
|
|
130
|
+
| 'request_approved'
|
|
131
|
+
| 'request_rejected'
|
|
132
|
+
| 'request_returned_for_modification';
|
|
133
|
+
|
|
135
134
|
function buildWorkflowApprovalByName(
|
|
136
|
-
templateKey:
|
|
135
|
+
templateKey: WorkflowByNameKey,
|
|
136
|
+
fallbackKey: WorkflowWithoutNameKey,
|
|
137
137
|
nameEn: string,
|
|
138
138
|
nameAr: string,
|
|
139
139
|
comment?: string | null,
|
|
140
140
|
): BilingualText {
|
|
141
141
|
const commentSuffix = formatWorkflowCommentSuffix(comment);
|
|
142
|
-
return
|
|
143
|
-
templateKey,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
return {
|
|
143
|
+
en: workflowTemplate(templateKey, { name: nameEn, comment: commentSuffix }).en,
|
|
144
|
+
ar: nameAr
|
|
145
|
+
? workflowTemplate(templateKey, { name: nameAr, comment: '' }).ar
|
|
146
|
+
: workflowTemplate(fallbackKey, { comment: '' }).ar,
|
|
147
|
+
};
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
function buildWorkflowApprovalWithoutName(
|
|
150
|
-
templateKey:
|
|
151
|
+
templateKey: WorkflowWithoutNameKey,
|
|
151
152
|
comment?: string | null,
|
|
152
153
|
): BilingualText {
|
|
153
154
|
const commentSuffix = formatWorkflowCommentSuffix(comment);
|
|
154
|
-
return
|
|
155
|
-
templateKey,
|
|
156
|
-
{ comment:
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
return {
|
|
156
|
+
en: workflowTemplate(templateKey, { comment: commentSuffix }).en,
|
|
157
|
+
ar: workflowTemplate(templateKey, { comment: '' }).ar,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function buildWorkflowFromNamePair(
|
|
162
|
+
templateWithNameKey: 'request_approval_in_progress_from' | 'request_approval_pending_from',
|
|
163
|
+
templateWithoutNameKey: 'request_approval_in_progress' | 'request_approval_pending',
|
|
164
|
+
nameEn: string,
|
|
165
|
+
nameAr: string,
|
|
166
|
+
): BilingualText {
|
|
167
|
+
return {
|
|
168
|
+
en: workflowTemplate(templateWithNameKey, { name: nameEn }).en,
|
|
169
|
+
ar: nameAr
|
|
170
|
+
? workflowTemplate(templateWithNameKey, { name: nameAr }).ar
|
|
171
|
+
: workflowTemplate(templateWithoutNameKey).ar,
|
|
172
|
+
};
|
|
159
173
|
}
|
|
160
174
|
|
|
161
175
|
export function buildApprovalWorkflowContent(params: {
|
|
@@ -165,40 +179,46 @@ export function buildApprovalWorkflowContent(params: {
|
|
|
165
179
|
comment?: string | null;
|
|
166
180
|
}): BilingualText {
|
|
167
181
|
const nameEn = params.roleName?.trim() || '';
|
|
168
|
-
const nameAr =
|
|
182
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
169
183
|
|
|
170
184
|
if (params.status === 'Approved') {
|
|
171
185
|
return nameEn
|
|
172
|
-
? buildWorkflowApprovalByName('request_approved_by', nameEn, nameAr, params.comment)
|
|
186
|
+
? buildWorkflowApprovalByName('request_approved_by', 'request_approved', nameEn, nameAr, params.comment)
|
|
173
187
|
: buildWorkflowApprovalWithoutName('request_approved', params.comment);
|
|
174
188
|
}
|
|
175
189
|
|
|
176
190
|
if (params.status === 'Rejected') {
|
|
177
191
|
return nameEn
|
|
178
|
-
? buildWorkflowApprovalByName('request_rejected_by', nameEn, nameAr, params.comment)
|
|
192
|
+
? buildWorkflowApprovalByName('request_rejected_by', 'request_rejected', nameEn, nameAr, params.comment)
|
|
179
193
|
: buildWorkflowApprovalWithoutName('request_rejected', params.comment);
|
|
180
194
|
}
|
|
181
195
|
|
|
182
196
|
if (params.status === 'Returned for Modification') {
|
|
183
197
|
return nameEn
|
|
184
|
-
? buildWorkflowApprovalByName(
|
|
198
|
+
? buildWorkflowApprovalByName(
|
|
199
|
+
'request_returned_for_modification_by',
|
|
200
|
+
'request_returned_for_modification',
|
|
201
|
+
nameEn,
|
|
202
|
+
nameAr,
|
|
203
|
+
params.comment,
|
|
204
|
+
)
|
|
185
205
|
: buildWorkflowApprovalWithoutName('request_returned_for_modification', params.comment);
|
|
186
206
|
}
|
|
187
207
|
|
|
188
208
|
const commentSuffix = formatWorkflowCommentSuffix(params.comment);
|
|
189
209
|
if (nameEn) {
|
|
190
|
-
return
|
|
191
|
-
'request_approval_pending_from',
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
210
|
+
return {
|
|
211
|
+
en: workflowTemplate('request_approval_pending_from', { name: nameEn, comment: commentSuffix }).en,
|
|
212
|
+
ar: nameAr
|
|
213
|
+
? workflowTemplate('request_approval_pending_from', { name: nameAr, comment: '' }).ar
|
|
214
|
+
: workflowTemplate('request_approval_pending', { comment: '' }).ar,
|
|
215
|
+
};
|
|
195
216
|
}
|
|
196
217
|
|
|
197
|
-
return
|
|
198
|
-
'request_approval_pending',
|
|
199
|
-
{ comment:
|
|
200
|
-
|
|
201
|
-
);
|
|
218
|
+
return {
|
|
219
|
+
en: workflowTemplate('request_approval_pending', { comment: commentSuffix }).en,
|
|
220
|
+
ar: workflowTemplate('request_approval_pending', { comment: '' }).ar,
|
|
221
|
+
};
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
export function buildHumanApprovalWorkflowContent(params: {
|
|
@@ -210,12 +230,13 @@ export function buildHumanApprovalWorkflowContent(params: {
|
|
|
210
230
|
sectionName?: string | null;
|
|
211
231
|
sectionArabicName?: string | null;
|
|
212
232
|
}): BilingualText {
|
|
213
|
-
const
|
|
233
|
+
const withNameKey = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
234
|
+
const withoutNameKey = params.isFirst ? 'request_approval_in_progress' : 'request_approval_pending';
|
|
214
235
|
|
|
215
236
|
if (params.roleName?.trim()) {
|
|
216
237
|
const nameEn = params.roleName.trim();
|
|
217
|
-
const nameAr =
|
|
218
|
-
return
|
|
238
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
239
|
+
return buildWorkflowFromNamePair(withNameKey, withoutNameKey, nameEn, nameAr);
|
|
219
240
|
}
|
|
220
241
|
|
|
221
242
|
const { en, ar } = joinDeptSectionBilingualLabels(
|
|
@@ -225,7 +246,7 @@ export function buildHumanApprovalWorkflowContent(params: {
|
|
|
225
246
|
params.sectionArabicName,
|
|
226
247
|
);
|
|
227
248
|
if (en) {
|
|
228
|
-
return
|
|
249
|
+
return buildWorkflowFromNamePair(withNameKey, withoutNameKey, en, ar);
|
|
229
250
|
}
|
|
230
251
|
|
|
231
252
|
return params.isFirst
|
|
@@ -240,25 +261,31 @@ export function buildApprovalChatMessage(params: {
|
|
|
240
261
|
comment?: string | null;
|
|
241
262
|
}): BilingualText {
|
|
242
263
|
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
243
|
-
const roleAr =
|
|
264
|
+
const roleAr = pickArabicName(params.roleArabicName);
|
|
244
265
|
const commentSuffix = formatChatCommentSuffix(params.comment);
|
|
245
266
|
|
|
246
|
-
let
|
|
267
|
+
let byRoleKey: string;
|
|
268
|
+
let withoutRoleKey: string;
|
|
247
269
|
if (params.status === 'Approved') {
|
|
248
|
-
|
|
270
|
+
byRoleKey = 'request_approved_by_role';
|
|
271
|
+
withoutRoleKey = 'request_approved';
|
|
249
272
|
} else if (params.status === 'Rejected') {
|
|
250
|
-
|
|
273
|
+
byRoleKey = 'request_rejected_by_role';
|
|
274
|
+
withoutRoleKey = 'request_rejected';
|
|
251
275
|
} else if (params.status === 'Returned for Modification') {
|
|
252
|
-
|
|
276
|
+
byRoleKey = 'request_returned_for_modification_by_role';
|
|
277
|
+
withoutRoleKey = 'request_returned_for_modification';
|
|
253
278
|
} else {
|
|
254
|
-
|
|
279
|
+
byRoleKey = 'request_approved_by_role';
|
|
280
|
+
withoutRoleKey = 'request_approved';
|
|
255
281
|
}
|
|
256
282
|
|
|
257
|
-
return
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
283
|
+
return {
|
|
284
|
+
en: chatTemplate(byRoleKey, { roleName: roleEn, comment: commentSuffix }).en,
|
|
285
|
+
ar: roleAr
|
|
286
|
+
? chatTemplate(byRoleKey, { roleName: roleAr, comment: '' }).ar
|
|
287
|
+
: chatTemplate(withoutRoleKey, { comment: '' }).ar,
|
|
288
|
+
};
|
|
262
289
|
}
|
|
263
290
|
|
|
264
291
|
/** Resolve Arabic workflow content from a stored English content string (legacy rows). */
|
|
@@ -273,8 +300,6 @@ export function resolveWorkflowContentAr(content: string | null | undefined): st
|
|
|
273
300
|
const commentIdx = normalized.indexOf(': ');
|
|
274
301
|
if (commentIdx > 0) {
|
|
275
302
|
const baseEn = normalized.slice(0, commentIdx).trim();
|
|
276
|
-
const commentText = normalized.slice(commentIdx + 2).trim();
|
|
277
|
-
const commentSuffix = formatWorkflowCommentSuffix(commentText);
|
|
278
303
|
|
|
279
304
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
280
305
|
if (!tpl.en.includes('{{comment}}')) continue;
|
|
@@ -282,15 +307,30 @@ export function resolveWorkflowContentAr(content: string | null | undefined): st
|
|
|
282
307
|
if (withoutComment.includes('{{name}}')) {
|
|
283
308
|
const staticPrefix = withoutComment.replace('{{name}}', '').trim();
|
|
284
309
|
if (baseEn.startsWith(staticPrefix)) {
|
|
285
|
-
const
|
|
286
|
-
|
|
310
|
+
const fallbackKey = Object.entries(WORKFLOW_TEMPLATES).find(([, t]) => t === tpl)?.[0] ?? '';
|
|
311
|
+
if (fallbackKey.includes('_by')) {
|
|
312
|
+
const genericKey = fallbackKey.replace('_by', '') as WorkflowWithoutNameKey;
|
|
313
|
+
if (WORKFLOW_TEMPLATES[genericKey]) {
|
|
314
|
+
return WORKFLOW_TEMPLATES[genericKey].ar;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return tpl.ar.split('{{name}}')[0].trim();
|
|
287
318
|
}
|
|
288
319
|
} else if (withoutComment.trim() === baseEn) {
|
|
289
|
-
return interpolate(tpl.ar, { comment:
|
|
320
|
+
return interpolate(tpl.ar, { comment: '' });
|
|
290
321
|
}
|
|
291
322
|
}
|
|
292
323
|
}
|
|
293
324
|
|
|
325
|
+
const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
|
|
326
|
+
if (inProgressPrefix && normalized.startsWith(inProgressPrefix)) {
|
|
327
|
+
return WORKFLOW_TEMPLATES.request_approval_in_progress.ar;
|
|
328
|
+
}
|
|
329
|
+
const pendingPrefix = WORKFLOW_TEMPLATES.request_approval_pending_from?.en.split('{{name}}')[0].trim();
|
|
330
|
+
if (pendingPrefix && normalized.startsWith(pendingPrefix)) {
|
|
331
|
+
return WORKFLOW_TEMPLATES.request_approval_pending.ar;
|
|
332
|
+
}
|
|
333
|
+
|
|
294
334
|
return null;
|
|
295
335
|
}
|
|
296
336
|
|
|
@@ -309,9 +349,13 @@ export function resolveChatMessageAr(message: string | null | undefined): string
|
|
|
309
349
|
export function enrichCancellationWorkflowLog(log: Record<string, unknown>): Record<string, unknown> {
|
|
310
350
|
const status = log.status != null ? String(log.status) : null;
|
|
311
351
|
const content = log.content != null ? String(log.content) : null;
|
|
352
|
+
const storedAr = log.content_ar != null ? String(log.content_ar).trim() : '';
|
|
353
|
+
const hasEnglishInAr = storedAr && /[A-Za-z]/.test(storedAr);
|
|
312
354
|
return {
|
|
313
355
|
...log,
|
|
314
|
-
content_ar:
|
|
356
|
+
content_ar: hasEnglishInAr
|
|
357
|
+
? (resolveWorkflowContentAr(content) ?? storedAr)
|
|
358
|
+
: (log.content_ar ?? resolveWorkflowContentAr(content)),
|
|
315
359
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
316
360
|
};
|
|
317
361
|
}
|
|
@@ -319,9 +363,13 @@ export function enrichCancellationWorkflowLog(log: Record<string, unknown>): Rec
|
|
|
319
363
|
export function enrichCancellationChatMessage(chat: Record<string, unknown>): Record<string, unknown> {
|
|
320
364
|
const status = chat.status != null ? String(chat.status) : null;
|
|
321
365
|
const message = chat.message != null ? String(chat.message) : null;
|
|
366
|
+
const storedAr = chat.message_ar != null ? String(chat.message_ar).trim() : '';
|
|
367
|
+
const hasEnglishInAr = storedAr && /[A-Za-z]/.test(storedAr);
|
|
322
368
|
return {
|
|
323
369
|
...chat,
|
|
324
|
-
message_ar:
|
|
370
|
+
message_ar: hasEnglishInAr
|
|
371
|
+
? (resolveChatMessageAr(message) ?? storedAr)
|
|
372
|
+
: (chat.message_ar ?? resolveChatMessageAr(message)),
|
|
325
373
|
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
326
374
|
};
|
|
327
375
|
}
|