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