@platform-modules/civil-aviation-authority 2.3.277 → 2.3.278
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/.env +1 -1
- package/dist/helpers/cancellation-bilingual-persist.helper.d.ts +37 -0
- package/dist/helpers/cancellation-bilingual-persist.helper.js +77 -0
- package/dist/i18n/workflow-chat-i18n.d.ts +12 -3
- package/dist/i18n/workflow-chat-i18n.js +72 -22
- package/package.json +1 -1
- package/src/i18n/workflow-chat-i18n.ts +84 -22
package/.env
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { EntityManager } from 'typeorm';
|
|
2
|
+
import { CancellationMessageType } from '../models/CancellationChatModel';
|
|
3
|
+
import { CancellationWorkFlowStatus } from '../models/CancellationWorkflowModel';
|
|
4
|
+
export type CancellationWorkflowRowInput = {
|
|
5
|
+
request_id: number;
|
|
6
|
+
service_id?: number | null;
|
|
7
|
+
sub_service_id?: number | null;
|
|
8
|
+
content: string;
|
|
9
|
+
content_ar?: string | null;
|
|
10
|
+
status: CancellationWorkFlowStatus;
|
|
11
|
+
status_ar?: string | null;
|
|
12
|
+
user_id?: number | null;
|
|
13
|
+
role_id?: number | null;
|
|
14
|
+
department_id?: number | null;
|
|
15
|
+
section_id?: number | null;
|
|
16
|
+
step_order?: number | null;
|
|
17
|
+
created_by?: number | null;
|
|
18
|
+
};
|
|
19
|
+
export type CancellationChatRowInput = {
|
|
20
|
+
request_id: number;
|
|
21
|
+
service_id?: number | null;
|
|
22
|
+
sub_service_id?: number | null;
|
|
23
|
+
user_id: number;
|
|
24
|
+
role_id?: number | null;
|
|
25
|
+
message: string;
|
|
26
|
+
message_ar?: string | null;
|
|
27
|
+
messageType?: CancellationMessageType;
|
|
28
|
+
status?: string | null;
|
|
29
|
+
status_ar?: string | null;
|
|
30
|
+
created_by?: number | string | null;
|
|
31
|
+
};
|
|
32
|
+
/** Force-persist Arabic workflow columns (guards against stale TypeORM entity metadata). */
|
|
33
|
+
export declare function patchCancellationWorkflowArabic(manager: EntityManager, workflowId: number, contentAr: string | null, statusAr: string | null): Promise<void>;
|
|
34
|
+
/** Force-persist Arabic chat columns (guards against stale TypeORM entity metadata). */
|
|
35
|
+
export declare function patchCancellationChatArabic(manager: EntityManager, chatId: number, messageAr: string | null, statusAr: string | null): Promise<void>;
|
|
36
|
+
export declare function insertCancellationWorkflowRow(manager: EntityManager, input: CancellationWorkflowRowInput): Promise<number>;
|
|
37
|
+
export declare function insertCancellationChatRow(manager: EntityManager, input: CancellationChatRowInput): Promise<number>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.patchCancellationWorkflowArabic = patchCancellationWorkflowArabic;
|
|
4
|
+
exports.patchCancellationChatArabic = patchCancellationChatArabic;
|
|
5
|
+
exports.insertCancellationWorkflowRow = insertCancellationWorkflowRow;
|
|
6
|
+
exports.insertCancellationChatRow = insertCancellationChatRow;
|
|
7
|
+
const CancellationChatModel_1 = require("../models/CancellationChatModel");
|
|
8
|
+
const CancellationWorkflowModel_1 = require("../models/CancellationWorkflowModel");
|
|
9
|
+
const workflow_chat_i18n_1 = require("../i18n/workflow-chat-i18n");
|
|
10
|
+
function resolveWorkflowRowId(insertResult) {
|
|
11
|
+
const id = insertResult.raw?.[0]?.id ?? insertResult.identifiers?.[0]?.id;
|
|
12
|
+
if (!id) {
|
|
13
|
+
throw new Error('Failed to insert cancellation workflow row');
|
|
14
|
+
}
|
|
15
|
+
return id;
|
|
16
|
+
}
|
|
17
|
+
function resolveChatRowId(insertResult) {
|
|
18
|
+
const id = insertResult.raw?.[0]?.id ?? insertResult.identifiers?.[0]?.id;
|
|
19
|
+
if (!id) {
|
|
20
|
+
throw new Error('Failed to insert cancellation chat row');
|
|
21
|
+
}
|
|
22
|
+
return id;
|
|
23
|
+
}
|
|
24
|
+
/** Force-persist Arabic workflow columns (guards against stale TypeORM entity metadata). */
|
|
25
|
+
async function patchCancellationWorkflowArabic(manager, workflowId, contentAr, statusAr) {
|
|
26
|
+
await manager.query(`UPDATE cancellation_workflows
|
|
27
|
+
SET content_ar = $1,
|
|
28
|
+
status_ar = $2,
|
|
29
|
+
updated_at = CURRENT_TIMESTAMP
|
|
30
|
+
WHERE id = $3`, [contentAr, statusAr, workflowId]);
|
|
31
|
+
}
|
|
32
|
+
/** Force-persist Arabic chat columns (guards against stale TypeORM entity metadata). */
|
|
33
|
+
async function patchCancellationChatArabic(manager, chatId, messageAr, statusAr) {
|
|
34
|
+
await manager.query(`UPDATE cancellation_chats
|
|
35
|
+
SET message_ar = $1,
|
|
36
|
+
status_ar = $2,
|
|
37
|
+
updated_at = CURRENT_TIMESTAMP
|
|
38
|
+
WHERE id = $3`, [messageAr, statusAr, chatId]);
|
|
39
|
+
}
|
|
40
|
+
async function insertCancellationWorkflowRow(manager, input) {
|
|
41
|
+
const contentAr = input.content_ar ?? null;
|
|
42
|
+
const statusAr = input.status_ar ?? (0, workflow_chat_i18n_1.resolveWorkflowStatusAr)(input.status);
|
|
43
|
+
const insertResult = await manager
|
|
44
|
+
.createQueryBuilder()
|
|
45
|
+
.insert()
|
|
46
|
+
.into(CancellationWorkflowModel_1.CancellationWorkFlow)
|
|
47
|
+
.values({
|
|
48
|
+
...input,
|
|
49
|
+
content_ar: contentAr,
|
|
50
|
+
status_ar: statusAr,
|
|
51
|
+
})
|
|
52
|
+
.returning('id')
|
|
53
|
+
.execute();
|
|
54
|
+
const id = resolveWorkflowRowId(insertResult);
|
|
55
|
+
await patchCancellationWorkflowArabic(manager, id, contentAr, statusAr);
|
|
56
|
+
return id;
|
|
57
|
+
}
|
|
58
|
+
async function insertCancellationChatRow(manager, input) {
|
|
59
|
+
const messageAr = input.message_ar ?? null;
|
|
60
|
+
const statusAr = input.status_ar ?? (0, workflow_chat_i18n_1.resolveChatStatusAr)(input.status ?? null);
|
|
61
|
+
const messageType = input.messageType ?? CancellationChatModel_1.CancellationMessageType.TEXT;
|
|
62
|
+
const insertResult = await manager
|
|
63
|
+
.createQueryBuilder()
|
|
64
|
+
.insert()
|
|
65
|
+
.into(CancellationChatModel_1.CancellationRequestChat)
|
|
66
|
+
.values({
|
|
67
|
+
...input,
|
|
68
|
+
message_ar: messageAr,
|
|
69
|
+
status_ar: statusAr,
|
|
70
|
+
messageType,
|
|
71
|
+
})
|
|
72
|
+
.returning('id')
|
|
73
|
+
.execute();
|
|
74
|
+
const id = resolveChatRowId(insertResult);
|
|
75
|
+
await patchCancellationChatArabic(manager, id, messageAr, statusAr);
|
|
76
|
+
return id;
|
|
77
|
+
}
|
|
@@ -10,12 +10,17 @@ type WorkflowChatI18nCatalog = {
|
|
|
10
10
|
};
|
|
11
11
|
/** Read-only view of the shared workflow/chat translation catalog. */
|
|
12
12
|
export declare function getWorkflowChatI18nCatalog(): WorkflowChatI18nCatalog;
|
|
13
|
-
export declare function buildBilingualFromTemplate(templateCatalog: Record<string, BilingualText>, key: string, params?: Record<string, string>): BilingualText;
|
|
14
|
-
export declare function workflowTemplate(key: string, params?: Record<string, string>): BilingualText;
|
|
15
|
-
export declare function chatTemplate(key: string, params?: Record<string, string>): BilingualText;
|
|
13
|
+
export declare function buildBilingualFromTemplate(templateCatalog: Record<string, BilingualText>, key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
14
|
+
export declare function workflowTemplate(key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
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
|
+
/** Prefer Arabic name for Arabic content; never fall back to English. */
|
|
19
|
+
export declare function pickArabicName(arabicName?: string | null, fallback?: string): string;
|
|
20
|
+
/** Prefer Arabic for Arabic locale; English for English locale. */
|
|
18
21
|
export declare function pickLocalizedName(englishName?: string | null, arabicName?: string | null, fallback?: string): string;
|
|
22
|
+
/** Build dept/section label from Arabic columns only (for content_ar). */
|
|
23
|
+
export declare function joinDeptSectionArabicLabels(deptArabic?: string | null, sectionArabic?: string | null): string;
|
|
19
24
|
export declare function buildApprovalWorkflowContent(params: {
|
|
20
25
|
status: 'Approved' | 'Rejected' | 'Pending' | string;
|
|
21
26
|
roleName?: string | null;
|
|
@@ -35,6 +40,10 @@ export declare function buildApprovalChatMessage(params: {
|
|
|
35
40
|
roleArabicName?: string | null;
|
|
36
41
|
comment?: string | null;
|
|
37
42
|
}): BilingualText;
|
|
43
|
+
/** Resolve Arabic workflow content from a stored English content string. */
|
|
44
|
+
export declare function resolveWorkflowContentAr(content: string | null | undefined): string | null;
|
|
45
|
+
/** Resolve Arabic chat message from a stored English message string. */
|
|
46
|
+
export declare function resolveChatMessageAr(message: string | null | undefined): string | null;
|
|
38
47
|
export declare function enrichCancellationWorkflowLog(log: Record<string, unknown>): Record<string, unknown>;
|
|
39
48
|
export declare function enrichCancellationChatMessage(chat: Record<string, unknown>): Record<string, unknown>;
|
|
40
49
|
export {};
|
|
@@ -9,10 +9,14 @@ exports.workflowTemplate = workflowTemplate;
|
|
|
9
9
|
exports.chatTemplate = chatTemplate;
|
|
10
10
|
exports.resolveWorkflowStatusAr = resolveWorkflowStatusAr;
|
|
11
11
|
exports.resolveChatStatusAr = resolveChatStatusAr;
|
|
12
|
+
exports.pickArabicName = pickArabicName;
|
|
12
13
|
exports.pickLocalizedName = pickLocalizedName;
|
|
14
|
+
exports.joinDeptSectionArabicLabels = joinDeptSectionArabicLabels;
|
|
13
15
|
exports.buildApprovalWorkflowContent = buildApprovalWorkflowContent;
|
|
14
16
|
exports.buildHumanApprovalWorkflowContent = buildHumanApprovalWorkflowContent;
|
|
15
17
|
exports.buildApprovalChatMessage = buildApprovalChatMessage;
|
|
18
|
+
exports.resolveWorkflowContentAr = resolveWorkflowContentAr;
|
|
19
|
+
exports.resolveChatMessageAr = resolveChatMessageAr;
|
|
16
20
|
exports.enrichCancellationWorkflowLog = enrichCancellationWorkflowLog;
|
|
17
21
|
exports.enrichCancellationChatMessage = enrichCancellationChatMessage;
|
|
18
22
|
const workflow_chat_i18n_json_1 = __importDefault(require("./workflow-chat-i18n.json"));
|
|
@@ -27,21 +31,22 @@ function getWorkflowChatI18nCatalog() {
|
|
|
27
31
|
function interpolate(template, params = {}) {
|
|
28
32
|
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? '');
|
|
29
33
|
}
|
|
30
|
-
function buildBilingualFromTemplate(templateCatalog, key, params = {}) {
|
|
34
|
+
function buildBilingualFromTemplate(templateCatalog, key, params = {}, arParams) {
|
|
31
35
|
const tpl = templateCatalog[key];
|
|
32
36
|
if (!tpl) {
|
|
33
37
|
return { en: key, ar: key };
|
|
34
38
|
}
|
|
39
|
+
const arabicParams = arParams ?? params;
|
|
35
40
|
return {
|
|
36
41
|
en: interpolate(tpl.en, params),
|
|
37
|
-
ar: interpolate(tpl.ar,
|
|
42
|
+
ar: interpolate(tpl.ar, arabicParams),
|
|
38
43
|
};
|
|
39
44
|
}
|
|
40
|
-
function workflowTemplate(key, params = {}) {
|
|
41
|
-
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params);
|
|
45
|
+
function workflowTemplate(key, params = {}, arParams) {
|
|
46
|
+
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
|
|
42
47
|
}
|
|
43
|
-
function chatTemplate(key, params = {}) {
|
|
44
|
-
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params);
|
|
48
|
+
function chatTemplate(key, params = {}, arParams) {
|
|
49
|
+
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params, arParams);
|
|
45
50
|
}
|
|
46
51
|
function resolveWorkflowStatusAr(status) {
|
|
47
52
|
if (status == null || status === '')
|
|
@@ -53,6 +58,11 @@ function resolveChatStatusAr(status) {
|
|
|
53
58
|
return null;
|
|
54
59
|
return CHAT_STATUS_LABELS[status] ?? status;
|
|
55
60
|
}
|
|
61
|
+
/** Prefer Arabic name for Arabic content; never fall back to English. */
|
|
62
|
+
function pickArabicName(arabicName, fallback = '') {
|
|
63
|
+
return arabicName?.trim() || fallback;
|
|
64
|
+
}
|
|
65
|
+
/** Prefer Arabic for Arabic locale; English for English locale. */
|
|
56
66
|
function pickLocalizedName(englishName, arabicName, fallback = '') {
|
|
57
67
|
const ar = arabicName?.trim();
|
|
58
68
|
if (ar)
|
|
@@ -62,52 +72,63 @@ function pickLocalizedName(englishName, arabicName, fallback = '') {
|
|
|
62
72
|
return en;
|
|
63
73
|
return fallback;
|
|
64
74
|
}
|
|
75
|
+
function joinDeptSectionLabels(dept, section) {
|
|
76
|
+
return [dept, section].map((s) => s?.trim()).filter(Boolean).join(' - ');
|
|
77
|
+
}
|
|
78
|
+
/** Build dept/section label from Arabic columns only (for content_ar). */
|
|
79
|
+
function joinDeptSectionArabicLabels(deptArabic, sectionArabic) {
|
|
80
|
+
return joinDeptSectionLabels(deptArabic, sectionArabic);
|
|
81
|
+
}
|
|
65
82
|
function buildApprovalWorkflowContent(params) {
|
|
66
83
|
const nameEn = params.roleName?.trim() || '';
|
|
67
|
-
const nameAr =
|
|
84
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
68
85
|
let base;
|
|
69
86
|
if (params.status === 'Approved') {
|
|
70
87
|
base = nameEn
|
|
71
88
|
? workflowTemplate('request_approved_by', { name: nameEn })
|
|
72
89
|
: workflowTemplate('request_approved');
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
base.ar = nameAr
|
|
91
|
+
? workflowTemplate('request_approved_by', { name: nameAr }).ar
|
|
92
|
+
: workflowTemplate('request_approved').ar;
|
|
76
93
|
}
|
|
77
94
|
else if (params.status === 'Rejected') {
|
|
78
95
|
base = nameEn
|
|
79
96
|
? workflowTemplate('request_rejected_by', { name: nameEn })
|
|
80
97
|
: workflowTemplate('request_rejected');
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
base.ar = nameAr
|
|
99
|
+
? workflowTemplate('request_rejected_by', { name: nameAr }).ar
|
|
100
|
+
: workflowTemplate('request_rejected').ar;
|
|
84
101
|
}
|
|
85
102
|
else {
|
|
86
103
|
base = nameEn
|
|
87
104
|
? workflowTemplate('request_approval_pending_from', { name: nameEn })
|
|
88
105
|
: workflowTemplate('request_approval_pending');
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
base.ar = nameAr
|
|
107
|
+
? workflowTemplate('request_approval_pending_from', { name: nameAr }).ar
|
|
108
|
+
: workflowTemplate('request_approval_pending').ar;
|
|
92
109
|
}
|
|
93
110
|
const comment = params.comment?.trim();
|
|
94
111
|
if (!comment)
|
|
95
112
|
return base;
|
|
96
113
|
return {
|
|
97
114
|
en: `${base.en}: ${comment}`,
|
|
98
|
-
ar:
|
|
115
|
+
ar: base.ar,
|
|
99
116
|
};
|
|
100
117
|
}
|
|
101
118
|
function buildHumanApprovalWorkflowContent(params) {
|
|
102
119
|
const nameEn = params.roleName?.trim() || params.deptSectionEn?.trim() || '';
|
|
103
120
|
const nameAr = params.roleName
|
|
104
|
-
?
|
|
105
|
-
: params.deptSectionAr?.trim() ||
|
|
121
|
+
? pickArabicName(params.roleArabicName)
|
|
122
|
+
: (params.deptSectionAr?.trim() || '');
|
|
106
123
|
if (nameEn) {
|
|
107
124
|
const key = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
108
125
|
return {
|
|
109
126
|
en: workflowTemplate(key, { name: nameEn }).en,
|
|
110
|
-
ar:
|
|
127
|
+
ar: nameAr
|
|
128
|
+
? workflowTemplate(key, { name: nameAr }).ar
|
|
129
|
+
: params.isFirst
|
|
130
|
+
? workflowTemplate('request_approval_in_progress').ar
|
|
131
|
+
: workflowTemplate('request_approval_pending').ar,
|
|
111
132
|
};
|
|
112
133
|
}
|
|
113
134
|
return params.isFirst
|
|
@@ -116,25 +137,54 @@ function buildHumanApprovalWorkflowContent(params) {
|
|
|
116
137
|
}
|
|
117
138
|
function buildApprovalChatMessage(params) {
|
|
118
139
|
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
119
|
-
const roleAr =
|
|
140
|
+
const roleAr = pickArabicName(params.roleArabicName);
|
|
120
141
|
const commentSuffix = params.comment?.trim() ? ` - ${params.comment.trim()}` : '';
|
|
121
142
|
const key = params.status === 'Approved' ? 'request_approved_by_role' : 'request_rejected_by_role';
|
|
122
143
|
return {
|
|
123
144
|
en: chatTemplate(key, { roleName: roleEn, comment: commentSuffix }).en,
|
|
124
|
-
ar: chatTemplate(key, { roleName: roleAr, comment:
|
|
145
|
+
ar: chatTemplate(key, { roleName: roleAr, comment: '' }).ar,
|
|
125
146
|
};
|
|
126
147
|
}
|
|
148
|
+
/** Resolve Arabic workflow content from a stored English content string. */
|
|
149
|
+
function resolveWorkflowContentAr(content) {
|
|
150
|
+
if (content == null || content.trim() === '')
|
|
151
|
+
return null;
|
|
152
|
+
const normalized = content.trim();
|
|
153
|
+
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
154
|
+
if (tpl.en === normalized)
|
|
155
|
+
return tpl.ar;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
/** Resolve Arabic chat message from a stored English message string. */
|
|
160
|
+
function resolveChatMessageAr(message) {
|
|
161
|
+
if (message == null || message.trim() === '')
|
|
162
|
+
return null;
|
|
163
|
+
const normalized = message.trim();
|
|
164
|
+
for (const tpl of Object.values(CHAT_TEMPLATES)) {
|
|
165
|
+
if (tpl.en === normalized)
|
|
166
|
+
return tpl.ar;
|
|
167
|
+
}
|
|
168
|
+
if (normalized === 'Request Received') {
|
|
169
|
+
return CHAT_TEMPLATES.request_received?.ar ?? null;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
127
173
|
function enrichCancellationWorkflowLog(log) {
|
|
128
174
|
const status = log.status != null ? String(log.status) : null;
|
|
175
|
+
const content = log.content != null ? String(log.content) : null;
|
|
129
176
|
return {
|
|
130
177
|
...log,
|
|
178
|
+
content_ar: log.content_ar ?? resolveWorkflowContentAr(content),
|
|
131
179
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
132
180
|
};
|
|
133
181
|
}
|
|
134
182
|
function enrichCancellationChatMessage(chat) {
|
|
135
183
|
const status = chat.status != null ? String(chat.status) : null;
|
|
184
|
+
const message = chat.message != null ? String(chat.message) : null;
|
|
136
185
|
return {
|
|
137
186
|
...chat,
|
|
187
|
+
message_ar: chat.message_ar ?? resolveChatMessageAr(message),
|
|
138
188
|
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
139
189
|
};
|
|
140
190
|
}
|
package/package.json
CHANGED
|
@@ -26,24 +26,34 @@ function interpolate(template: string, params: Record<string, string> = {}): str
|
|
|
26
26
|
export function buildBilingualFromTemplate(
|
|
27
27
|
templateCatalog: Record<string, BilingualText>,
|
|
28
28
|
key: string,
|
|
29
|
-
params: Record<string, string> = {}
|
|
29
|
+
params: Record<string, string> = {},
|
|
30
|
+
arParams?: Record<string, string>,
|
|
30
31
|
): BilingualText {
|
|
31
32
|
const tpl = templateCatalog[key];
|
|
32
33
|
if (!tpl) {
|
|
33
34
|
return { en: key, ar: key };
|
|
34
35
|
}
|
|
36
|
+
const arabicParams = arParams ?? params;
|
|
35
37
|
return {
|
|
36
38
|
en: interpolate(tpl.en, params),
|
|
37
|
-
ar: interpolate(tpl.ar,
|
|
39
|
+
ar: interpolate(tpl.ar, arabicParams),
|
|
38
40
|
};
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export function workflowTemplate(
|
|
42
|
-
|
|
43
|
+
export function workflowTemplate(
|
|
44
|
+
key: string,
|
|
45
|
+
params: Record<string, string> = {},
|
|
46
|
+
arParams?: Record<string, string>,
|
|
47
|
+
): BilingualText {
|
|
48
|
+
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
export function chatTemplate(
|
|
46
|
-
|
|
51
|
+
export function chatTemplate(
|
|
52
|
+
key: string,
|
|
53
|
+
params: Record<string, string> = {},
|
|
54
|
+
arParams?: Record<string, string>,
|
|
55
|
+
): BilingualText {
|
|
56
|
+
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params, arParams);
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
export function resolveWorkflowStatusAr(status: string | null | undefined): string | null {
|
|
@@ -56,6 +66,12 @@ export function resolveChatStatusAr(status: string | null | undefined): string |
|
|
|
56
66
|
return CHAT_STATUS_LABELS[status] ?? status;
|
|
57
67
|
}
|
|
58
68
|
|
|
69
|
+
/** Prefer Arabic name for Arabic content; never fall back to English. */
|
|
70
|
+
export function pickArabicName(arabicName?: string | null, fallback = ''): string {
|
|
71
|
+
return arabicName?.trim() || fallback;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Prefer Arabic for Arabic locale; English for English locale. */
|
|
59
75
|
export function pickLocalizedName(
|
|
60
76
|
englishName?: string | null,
|
|
61
77
|
arabicName?: string | null,
|
|
@@ -68,6 +84,21 @@ export function pickLocalizedName(
|
|
|
68
84
|
return fallback;
|
|
69
85
|
}
|
|
70
86
|
|
|
87
|
+
function joinDeptSectionLabels(
|
|
88
|
+
dept?: string | null,
|
|
89
|
+
section?: string | null,
|
|
90
|
+
): string {
|
|
91
|
+
return [dept, section].map((s) => s?.trim()).filter(Boolean).join(' - ');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Build dept/section label from Arabic columns only (for content_ar). */
|
|
95
|
+
export function joinDeptSectionArabicLabels(
|
|
96
|
+
deptArabic?: string | null,
|
|
97
|
+
sectionArabic?: string | null,
|
|
98
|
+
): string {
|
|
99
|
+
return joinDeptSectionLabels(deptArabic, sectionArabic);
|
|
100
|
+
}
|
|
101
|
+
|
|
71
102
|
export function buildApprovalWorkflowContent(params: {
|
|
72
103
|
status: 'Approved' | 'Rejected' | 'Pending' | string;
|
|
73
104
|
roleName?: string | null;
|
|
@@ -75,30 +106,30 @@ export function buildApprovalWorkflowContent(params: {
|
|
|
75
106
|
comment?: string | null;
|
|
76
107
|
}): BilingualText {
|
|
77
108
|
const nameEn = params.roleName?.trim() || '';
|
|
78
|
-
const nameAr =
|
|
109
|
+
const nameAr = pickArabicName(params.roleArabicName);
|
|
79
110
|
|
|
80
111
|
let base: BilingualText;
|
|
81
112
|
if (params.status === 'Approved') {
|
|
82
113
|
base = nameEn
|
|
83
114
|
? workflowTemplate('request_approved_by', { name: nameEn })
|
|
84
115
|
: workflowTemplate('request_approved');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
116
|
+
base.ar = nameAr
|
|
117
|
+
? workflowTemplate('request_approved_by', { name: nameAr }).ar
|
|
118
|
+
: workflowTemplate('request_approved').ar;
|
|
88
119
|
} else if (params.status === 'Rejected') {
|
|
89
120
|
base = nameEn
|
|
90
121
|
? workflowTemplate('request_rejected_by', { name: nameEn })
|
|
91
122
|
: workflowTemplate('request_rejected');
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
123
|
+
base.ar = nameAr
|
|
124
|
+
? workflowTemplate('request_rejected_by', { name: nameAr }).ar
|
|
125
|
+
: workflowTemplate('request_rejected').ar;
|
|
95
126
|
} else {
|
|
96
127
|
base = nameEn
|
|
97
128
|
? workflowTemplate('request_approval_pending_from', { name: nameEn })
|
|
98
129
|
: workflowTemplate('request_approval_pending');
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
130
|
+
base.ar = nameAr
|
|
131
|
+
? workflowTemplate('request_approval_pending_from', { name: nameAr }).ar
|
|
132
|
+
: workflowTemplate('request_approval_pending').ar;
|
|
102
133
|
}
|
|
103
134
|
|
|
104
135
|
const comment = params.comment?.trim();
|
|
@@ -106,7 +137,7 @@ export function buildApprovalWorkflowContent(params: {
|
|
|
106
137
|
|
|
107
138
|
return {
|
|
108
139
|
en: `${base.en}: ${comment}`,
|
|
109
|
-
ar:
|
|
140
|
+
ar: base.ar,
|
|
110
141
|
};
|
|
111
142
|
}
|
|
112
143
|
|
|
@@ -119,14 +150,18 @@ export function buildHumanApprovalWorkflowContent(params: {
|
|
|
119
150
|
}): BilingualText {
|
|
120
151
|
const nameEn = params.roleName?.trim() || params.deptSectionEn?.trim() || '';
|
|
121
152
|
const nameAr = params.roleName
|
|
122
|
-
?
|
|
123
|
-
: params.deptSectionAr?.trim() ||
|
|
153
|
+
? pickArabicName(params.roleArabicName)
|
|
154
|
+
: (params.deptSectionAr?.trim() || '');
|
|
124
155
|
|
|
125
156
|
if (nameEn) {
|
|
126
157
|
const key = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
127
158
|
return {
|
|
128
159
|
en: workflowTemplate(key, { name: nameEn }).en,
|
|
129
|
-
ar:
|
|
160
|
+
ar: nameAr
|
|
161
|
+
? workflowTemplate(key, { name: nameAr }).ar
|
|
162
|
+
: params.isFirst
|
|
163
|
+
? workflowTemplate('request_approval_in_progress').ar
|
|
164
|
+
: workflowTemplate('request_approval_pending').ar,
|
|
130
165
|
};
|
|
131
166
|
}
|
|
132
167
|
|
|
@@ -142,28 +177,55 @@ export function buildApprovalChatMessage(params: {
|
|
|
142
177
|
comment?: string | null;
|
|
143
178
|
}): BilingualText {
|
|
144
179
|
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
145
|
-
const roleAr =
|
|
180
|
+
const roleAr = pickArabicName(params.roleArabicName);
|
|
146
181
|
const commentSuffix = params.comment?.trim() ? ` - ${params.comment.trim()}` : '';
|
|
147
182
|
const key = params.status === 'Approved' ? 'request_approved_by_role' : 'request_rejected_by_role';
|
|
148
183
|
|
|
149
184
|
return {
|
|
150
185
|
en: chatTemplate(key, { roleName: roleEn, comment: commentSuffix }).en,
|
|
151
|
-
ar: chatTemplate(key, { roleName: roleAr, comment:
|
|
186
|
+
ar: chatTemplate(key, { roleName: roleAr, comment: '' }).ar,
|
|
152
187
|
};
|
|
153
188
|
}
|
|
154
189
|
|
|
190
|
+
/** Resolve Arabic workflow content from a stored English content string. */
|
|
191
|
+
export function resolveWorkflowContentAr(content: string | null | undefined): string | null {
|
|
192
|
+
if (content == null || content.trim() === '') return null;
|
|
193
|
+
const normalized = content.trim();
|
|
194
|
+
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
195
|
+
if (tpl.en === normalized) return tpl.ar;
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Resolve Arabic chat message from a stored English message string. */
|
|
201
|
+
export function resolveChatMessageAr(message: string | null | undefined): string | null {
|
|
202
|
+
if (message == null || message.trim() === '') return null;
|
|
203
|
+
const normalized = message.trim();
|
|
204
|
+
for (const tpl of Object.values(CHAT_TEMPLATES)) {
|
|
205
|
+
if (tpl.en === normalized) return tpl.ar;
|
|
206
|
+
}
|
|
207
|
+
if (normalized === 'Request Received') {
|
|
208
|
+
return CHAT_TEMPLATES.request_received?.ar ?? null;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
155
213
|
export function enrichCancellationWorkflowLog(log: Record<string, unknown>): Record<string, unknown> {
|
|
156
214
|
const status = log.status != null ? String(log.status) : null;
|
|
215
|
+
const content = log.content != null ? String(log.content) : null;
|
|
157
216
|
return {
|
|
158
217
|
...log,
|
|
218
|
+
content_ar: log.content_ar ?? resolveWorkflowContentAr(content),
|
|
159
219
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
160
220
|
};
|
|
161
221
|
}
|
|
162
222
|
|
|
163
223
|
export function enrichCancellationChatMessage(chat: Record<string, unknown>): Record<string, unknown> {
|
|
164
224
|
const status = chat.status != null ? String(chat.status) : null;
|
|
225
|
+
const message = chat.message != null ? String(chat.message) : null;
|
|
165
226
|
return {
|
|
166
227
|
...chat,
|
|
228
|
+
message_ar: chat.message_ar ?? resolveChatMessageAr(message),
|
|
167
229
|
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
168
230
|
};
|
|
169
231
|
}
|