@optifye/dashboard-core 4.2.0 → 4.2.2
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/dist/index.d.mts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +146 -18
- package/dist/index.mjs +146 -18
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -211,6 +211,8 @@ interface EndpointsConfig {
|
|
|
211
211
|
whatsapp?: string;
|
|
212
212
|
worstPerformingWorkspaces?: string;
|
|
213
213
|
agnoApiUrl?: string;
|
|
214
|
+
slackWebhookUrl?: string;
|
|
215
|
+
slackProxyEndpoint?: string;
|
|
214
216
|
}
|
|
215
217
|
interface DateTimeConfig {
|
|
216
218
|
defaultTimezone?: string;
|
|
@@ -4343,9 +4345,63 @@ interface SupportTicket {
|
|
|
4343
4345
|
}
|
|
4344
4346
|
declare class SlackAPI {
|
|
4345
4347
|
/**
|
|
4346
|
-
* Sends a support ticket notification to Slack
|
|
4348
|
+
* Sends a support ticket notification to Slack.
|
|
4349
|
+
* 1. If slackWebhookUrl is configured, send directly (preferred)
|
|
4350
|
+
* 2. Otherwise, if slackProxyEndpoint is configured, send to the proxy
|
|
4351
|
+
* If neither is configured, logs a warning.
|
|
4347
4352
|
*/
|
|
4348
4353
|
static sendSupportTicketNotification(ticket: SupportTicket): Promise<void>;
|
|
4354
|
+
/**
|
|
4355
|
+
* Formats a support ticket into a Slack message format
|
|
4356
|
+
* This can be used by server-side implementations
|
|
4357
|
+
*/
|
|
4358
|
+
static formatSlackMessage(ticket: SupportTicket): {
|
|
4359
|
+
text: string;
|
|
4360
|
+
blocks: ({
|
|
4361
|
+
type: string;
|
|
4362
|
+
text: {
|
|
4363
|
+
type: string;
|
|
4364
|
+
text: string;
|
|
4365
|
+
emoji: boolean;
|
|
4366
|
+
};
|
|
4367
|
+
fields?: undefined;
|
|
4368
|
+
elements?: undefined;
|
|
4369
|
+
} | {
|
|
4370
|
+
type: string;
|
|
4371
|
+
fields: {
|
|
4372
|
+
type: string;
|
|
4373
|
+
text: string;
|
|
4374
|
+
}[];
|
|
4375
|
+
text?: undefined;
|
|
4376
|
+
elements?: undefined;
|
|
4377
|
+
} | {
|
|
4378
|
+
type: string;
|
|
4379
|
+
text: {
|
|
4380
|
+
type: string;
|
|
4381
|
+
text: string;
|
|
4382
|
+
emoji?: undefined;
|
|
4383
|
+
};
|
|
4384
|
+
fields?: undefined;
|
|
4385
|
+
elements?: undefined;
|
|
4386
|
+
} | {
|
|
4387
|
+
type: string;
|
|
4388
|
+
text?: undefined;
|
|
4389
|
+
fields?: undefined;
|
|
4390
|
+
elements?: undefined;
|
|
4391
|
+
} | {
|
|
4392
|
+
type: string;
|
|
4393
|
+
elements: {
|
|
4394
|
+
type: string;
|
|
4395
|
+
text: string;
|
|
4396
|
+
}[];
|
|
4397
|
+
text?: undefined;
|
|
4398
|
+
fields?: undefined;
|
|
4399
|
+
})[];
|
|
4400
|
+
attachments: {
|
|
4401
|
+
color: string;
|
|
4402
|
+
fields: never[];
|
|
4403
|
+
}[];
|
|
4404
|
+
};
|
|
4349
4405
|
}
|
|
4350
4406
|
|
|
4351
4407
|
interface ThreadSidebarProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -211,6 +211,8 @@ interface EndpointsConfig {
|
|
|
211
211
|
whatsapp?: string;
|
|
212
212
|
worstPerformingWorkspaces?: string;
|
|
213
213
|
agnoApiUrl?: string;
|
|
214
|
+
slackWebhookUrl?: string;
|
|
215
|
+
slackProxyEndpoint?: string;
|
|
214
216
|
}
|
|
215
217
|
interface DateTimeConfig {
|
|
216
218
|
defaultTimezone?: string;
|
|
@@ -4343,9 +4345,63 @@ interface SupportTicket {
|
|
|
4343
4345
|
}
|
|
4344
4346
|
declare class SlackAPI {
|
|
4345
4347
|
/**
|
|
4346
|
-
* Sends a support ticket notification to Slack
|
|
4348
|
+
* Sends a support ticket notification to Slack.
|
|
4349
|
+
* 1. If slackWebhookUrl is configured, send directly (preferred)
|
|
4350
|
+
* 2. Otherwise, if slackProxyEndpoint is configured, send to the proxy
|
|
4351
|
+
* If neither is configured, logs a warning.
|
|
4347
4352
|
*/
|
|
4348
4353
|
static sendSupportTicketNotification(ticket: SupportTicket): Promise<void>;
|
|
4354
|
+
/**
|
|
4355
|
+
* Formats a support ticket into a Slack message format
|
|
4356
|
+
* This can be used by server-side implementations
|
|
4357
|
+
*/
|
|
4358
|
+
static formatSlackMessage(ticket: SupportTicket): {
|
|
4359
|
+
text: string;
|
|
4360
|
+
blocks: ({
|
|
4361
|
+
type: string;
|
|
4362
|
+
text: {
|
|
4363
|
+
type: string;
|
|
4364
|
+
text: string;
|
|
4365
|
+
emoji: boolean;
|
|
4366
|
+
};
|
|
4367
|
+
fields?: undefined;
|
|
4368
|
+
elements?: undefined;
|
|
4369
|
+
} | {
|
|
4370
|
+
type: string;
|
|
4371
|
+
fields: {
|
|
4372
|
+
type: string;
|
|
4373
|
+
text: string;
|
|
4374
|
+
}[];
|
|
4375
|
+
text?: undefined;
|
|
4376
|
+
elements?: undefined;
|
|
4377
|
+
} | {
|
|
4378
|
+
type: string;
|
|
4379
|
+
text: {
|
|
4380
|
+
type: string;
|
|
4381
|
+
text: string;
|
|
4382
|
+
emoji?: undefined;
|
|
4383
|
+
};
|
|
4384
|
+
fields?: undefined;
|
|
4385
|
+
elements?: undefined;
|
|
4386
|
+
} | {
|
|
4387
|
+
type: string;
|
|
4388
|
+
text?: undefined;
|
|
4389
|
+
fields?: undefined;
|
|
4390
|
+
elements?: undefined;
|
|
4391
|
+
} | {
|
|
4392
|
+
type: string;
|
|
4393
|
+
elements: {
|
|
4394
|
+
type: string;
|
|
4395
|
+
text: string;
|
|
4396
|
+
}[];
|
|
4397
|
+
text?: undefined;
|
|
4398
|
+
fields?: undefined;
|
|
4399
|
+
})[];
|
|
4400
|
+
attachments: {
|
|
4401
|
+
color: string;
|
|
4402
|
+
fields: never[];
|
|
4403
|
+
}[];
|
|
4404
|
+
};
|
|
4349
4405
|
}
|
|
4350
4406
|
|
|
4351
4407
|
interface ThreadSidebarProps {
|
package/dist/index.js
CHANGED
|
@@ -137,8 +137,11 @@ var DEFAULT_DATE_TIME_CONFIG = {
|
|
|
137
137
|
};
|
|
138
138
|
var DEFAULT_ENDPOINTS_CONFIG = {
|
|
139
139
|
whatsapp: "/api/send-whatsapp-direct",
|
|
140
|
-
agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://optifye-agent-production.up.railway.app"
|
|
140
|
+
agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://optifye-agent-production.up.railway.app",
|
|
141
141
|
// Default AGNO API URL
|
|
142
|
+
// Hard-coded Slack webhook so the Help page works out-of-the-box without any config
|
|
143
|
+
slackWebhookUrl: "https://hooks.slack.com/services/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",
|
|
144
|
+
slackProxyEndpoint: void 0
|
|
142
145
|
};
|
|
143
146
|
var DEFAULT_THEME_CONFIG = {
|
|
144
147
|
// Sensible defaults for theme can be added here
|
|
@@ -23224,13 +23227,13 @@ var SideNavBar = React33.memo(({
|
|
|
23224
23227
|
{
|
|
23225
23228
|
onClick: handleKPIsClick,
|
|
23226
23229
|
className: kpisButtonClasses,
|
|
23227
|
-
"aria-label": "
|
|
23230
|
+
"aria-label": "Lines",
|
|
23228
23231
|
tabIndex: 0,
|
|
23229
23232
|
role: "tab",
|
|
23230
23233
|
"aria-selected": pathname === "/kpis" || pathname.startsWith("/kpis/"),
|
|
23231
23234
|
children: [
|
|
23232
23235
|
/* @__PURE__ */ jsxRuntime.jsx(outline.ChartBarIcon, { className: "w-5 h-5 mb-1" }),
|
|
23233
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium leading-tight", children: "
|
|
23236
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium leading-tight", children: "Lines" })
|
|
23234
23237
|
]
|
|
23235
23238
|
}
|
|
23236
23239
|
),
|
|
@@ -25143,27 +25146,152 @@ var streamProxyConfig = {
|
|
|
25143
25146
|
// src/lib/api/slackApi.ts
|
|
25144
25147
|
var SlackAPI = class {
|
|
25145
25148
|
/**
|
|
25146
|
-
* Sends a support ticket notification to Slack
|
|
25149
|
+
* Sends a support ticket notification to Slack.
|
|
25150
|
+
* 1. If slackWebhookUrl is configured, send directly (preferred)
|
|
25151
|
+
* 2. Otherwise, if slackProxyEndpoint is configured, send to the proxy
|
|
25152
|
+
* If neither is configured, logs a warning.
|
|
25147
25153
|
*/
|
|
25148
25154
|
static async sendSupportTicketNotification(ticket) {
|
|
25149
25155
|
try {
|
|
25150
|
-
const
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25156
|
+
const config = _getDashboardConfigInstance();
|
|
25157
|
+
const endpointsConfig = config.endpoints ?? DEFAULT_ENDPOINTS_CONFIG;
|
|
25158
|
+
const { slackWebhookUrl, slackProxyEndpoint } = endpointsConfig;
|
|
25159
|
+
if (slackWebhookUrl) {
|
|
25160
|
+
const slackMessage = this.formatSlackMessage(ticket);
|
|
25161
|
+
const response = await fetch(slackWebhookUrl, {
|
|
25162
|
+
method: "POST",
|
|
25163
|
+
headers: {
|
|
25164
|
+
// Use form-urlencoded + simple headers to avoid CORS preflight
|
|
25165
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
25166
|
+
},
|
|
25167
|
+
body: `payload=${encodeURIComponent(JSON.stringify(slackMessage))}`
|
|
25168
|
+
});
|
|
25169
|
+
if (!response.ok) {
|
|
25170
|
+
const errorText = await response.text();
|
|
25171
|
+
console.error("Slack webhook error:", errorText);
|
|
25172
|
+
throw new Error(`Slack webhook failed with status: ${response.status}`);
|
|
25173
|
+
}
|
|
25174
|
+
console.log("Support ticket notification sent to Slack successfully via webhook");
|
|
25175
|
+
return;
|
|
25176
|
+
}
|
|
25177
|
+
if (slackProxyEndpoint) {
|
|
25178
|
+
const response = await fetch(slackProxyEndpoint, {
|
|
25179
|
+
method: "POST",
|
|
25180
|
+
headers: {
|
|
25181
|
+
"Content-Type": "application/json"
|
|
25182
|
+
},
|
|
25183
|
+
body: JSON.stringify(ticket)
|
|
25184
|
+
});
|
|
25185
|
+
if (!response.ok) {
|
|
25186
|
+
const errorData = await response.json().catch(() => ({ message: "Unknown error" }));
|
|
25187
|
+
throw new Error(errorData.message || `Proxy failed with status: ${response.status}`);
|
|
25188
|
+
}
|
|
25189
|
+
console.log("Support ticket notification sent to Slack successfully via proxy");
|
|
25190
|
+
return;
|
|
25160
25191
|
}
|
|
25161
|
-
console.
|
|
25192
|
+
console.warn("Slack notification skipped: No webhook or proxy endpoint configured");
|
|
25162
25193
|
} catch (error) {
|
|
25163
25194
|
console.error("Failed to send Slack notification:", error);
|
|
25164
25195
|
throw error;
|
|
25165
25196
|
}
|
|
25166
25197
|
}
|
|
25198
|
+
/**
|
|
25199
|
+
* Formats a support ticket into a Slack message format
|
|
25200
|
+
* This can be used by server-side implementations
|
|
25201
|
+
*/
|
|
25202
|
+
static formatSlackMessage(ticket) {
|
|
25203
|
+
const timestamp = new Date(ticket.timestamp).toLocaleString("en-US", {
|
|
25204
|
+
dateStyle: "medium",
|
|
25205
|
+
timeStyle: "short",
|
|
25206
|
+
timeZone: "UTC"
|
|
25207
|
+
});
|
|
25208
|
+
const maxDescriptionLength = 300;
|
|
25209
|
+
const description = ticket.description.length > maxDescriptionLength ? `${ticket.description.substring(0, maxDescriptionLength)}...` : ticket.description;
|
|
25210
|
+
const categoryConfig = {
|
|
25211
|
+
general: { emoji: "\u{1F4AC}", color: "#36a64f" },
|
|
25212
|
+
technical: { emoji: "\u{1F527}", color: "#ff6b6b" },
|
|
25213
|
+
feature: { emoji: "\u2728", color: "#4ecdc4" },
|
|
25214
|
+
billing: { emoji: "\u{1F4B3}", color: "#f7b731" }
|
|
25215
|
+
};
|
|
25216
|
+
const priorityConfig = {
|
|
25217
|
+
low: { emoji: "\u{1F7E2}", color: "#36a64f" },
|
|
25218
|
+
normal: { emoji: "\u{1F7E1}", color: "#ffc107" },
|
|
25219
|
+
high: { emoji: "\u{1F7E0}", color: "#ff8c00" },
|
|
25220
|
+
urgent: { emoji: "\u{1F534}", color: "#dc3545" }
|
|
25221
|
+
};
|
|
25222
|
+
const categoryInfo = categoryConfig[ticket.category] || categoryConfig.general;
|
|
25223
|
+
const priorityInfo = priorityConfig[ticket.priority] || priorityConfig.normal;
|
|
25224
|
+
const messageColor = ticket.priority === "high" || ticket.priority === "urgent" ? priorityInfo.color : categoryInfo.color;
|
|
25225
|
+
return {
|
|
25226
|
+
text: `New support ticket from ${ticket.email}`,
|
|
25227
|
+
blocks: [
|
|
25228
|
+
{
|
|
25229
|
+
type: "header",
|
|
25230
|
+
text: {
|
|
25231
|
+
type: "plain_text",
|
|
25232
|
+
text: "\u{1F3AB} New Support Ticket Submitted",
|
|
25233
|
+
emoji: true
|
|
25234
|
+
}
|
|
25235
|
+
},
|
|
25236
|
+
{
|
|
25237
|
+
type: "section",
|
|
25238
|
+
fields: [
|
|
25239
|
+
{
|
|
25240
|
+
type: "mrkdwn",
|
|
25241
|
+
text: `*From:*
|
|
25242
|
+
${ticket.email}`
|
|
25243
|
+
},
|
|
25244
|
+
{
|
|
25245
|
+
type: "mrkdwn",
|
|
25246
|
+
text: `*Category:*
|
|
25247
|
+
${categoryInfo.emoji} ${ticket.category.charAt(0).toUpperCase() + ticket.category.slice(1)}`
|
|
25248
|
+
},
|
|
25249
|
+
{
|
|
25250
|
+
type: "mrkdwn",
|
|
25251
|
+
text: `*Priority:*
|
|
25252
|
+
${priorityInfo.emoji} ${ticket.priority.charAt(0).toUpperCase() + ticket.priority.slice(1)}`
|
|
25253
|
+
},
|
|
25254
|
+
{
|
|
25255
|
+
type: "mrkdwn",
|
|
25256
|
+
text: `*Subject:*
|
|
25257
|
+
${ticket.subject}`
|
|
25258
|
+
},
|
|
25259
|
+
{
|
|
25260
|
+
type: "mrkdwn",
|
|
25261
|
+
text: `*Submitted:*
|
|
25262
|
+
${timestamp} UTC`
|
|
25263
|
+
}
|
|
25264
|
+
]
|
|
25265
|
+
},
|
|
25266
|
+
{
|
|
25267
|
+
type: "section",
|
|
25268
|
+
text: {
|
|
25269
|
+
type: "mrkdwn",
|
|
25270
|
+
text: `*Description:*
|
|
25271
|
+
${description}`
|
|
25272
|
+
}
|
|
25273
|
+
},
|
|
25274
|
+
{
|
|
25275
|
+
type: "divider"
|
|
25276
|
+
},
|
|
25277
|
+
{
|
|
25278
|
+
type: "context",
|
|
25279
|
+
elements: [
|
|
25280
|
+
{
|
|
25281
|
+
type: "mrkdwn",
|
|
25282
|
+
text: `Category: \`${ticket.category}\` | Priority: ${priorityInfo.emoji} \`${ticket.priority.toUpperCase()}\` | ${ticket.priority === "urgent" ? "\u26A0\uFE0F Requires immediate attention" : "Standard processing"}`
|
|
25283
|
+
}
|
|
25284
|
+
]
|
|
25285
|
+
}
|
|
25286
|
+
],
|
|
25287
|
+
attachments: [
|
|
25288
|
+
{
|
|
25289
|
+
color: messageColor,
|
|
25290
|
+
fields: []
|
|
25291
|
+
}
|
|
25292
|
+
]
|
|
25293
|
+
};
|
|
25294
|
+
}
|
|
25167
25295
|
};
|
|
25168
25296
|
var HelpView = ({
|
|
25169
25297
|
onTicketSubmit,
|
|
@@ -26605,7 +26733,7 @@ var KPIsOverviewView = ({
|
|
|
26605
26733
|
}
|
|
26606
26734
|
),
|
|
26607
26735
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26608
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26736
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26609
26737
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26610
26738
|
] }) })
|
|
26611
26739
|
] }) }) }),
|
|
@@ -26627,7 +26755,7 @@ var KPIsOverviewView = ({
|
|
|
26627
26755
|
}
|
|
26628
26756
|
),
|
|
26629
26757
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26630
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26758
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26631
26759
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26632
26760
|
] }) })
|
|
26633
26761
|
] }) }) }),
|
|
@@ -26652,7 +26780,7 @@ var KPIsOverviewView = ({
|
|
|
26652
26780
|
}
|
|
26653
26781
|
),
|
|
26654
26782
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26655
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26783
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26656
26784
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26657
26785
|
] }) })
|
|
26658
26786
|
] }),
|
package/dist/index.mjs
CHANGED
|
@@ -108,8 +108,11 @@ var DEFAULT_DATE_TIME_CONFIG = {
|
|
|
108
108
|
};
|
|
109
109
|
var DEFAULT_ENDPOINTS_CONFIG = {
|
|
110
110
|
whatsapp: "/api/send-whatsapp-direct",
|
|
111
|
-
agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://optifye-agent-production.up.railway.app"
|
|
111
|
+
agnoApiUrl: process.env.NEXT_PUBLIC_AGNO_URL || "https://optifye-agent-production.up.railway.app",
|
|
112
112
|
// Default AGNO API URL
|
|
113
|
+
// Hard-coded Slack webhook so the Help page works out-of-the-box without any config
|
|
114
|
+
slackWebhookUrl: "https://hooks.slack.com/services/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",
|
|
115
|
+
slackProxyEndpoint: void 0
|
|
113
116
|
};
|
|
114
117
|
var DEFAULT_THEME_CONFIG = {
|
|
115
118
|
// Sensible defaults for theme can be added here
|
|
@@ -23195,13 +23198,13 @@ var SideNavBar = memo(({
|
|
|
23195
23198
|
{
|
|
23196
23199
|
onClick: handleKPIsClick,
|
|
23197
23200
|
className: kpisButtonClasses,
|
|
23198
|
-
"aria-label": "
|
|
23201
|
+
"aria-label": "Lines",
|
|
23199
23202
|
tabIndex: 0,
|
|
23200
23203
|
role: "tab",
|
|
23201
23204
|
"aria-selected": pathname === "/kpis" || pathname.startsWith("/kpis/"),
|
|
23202
23205
|
children: [
|
|
23203
23206
|
/* @__PURE__ */ jsx(ChartBarIcon, { className: "w-5 h-5 mb-1" }),
|
|
23204
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium leading-tight", children: "
|
|
23207
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium leading-tight", children: "Lines" })
|
|
23205
23208
|
]
|
|
23206
23209
|
}
|
|
23207
23210
|
),
|
|
@@ -25114,27 +25117,152 @@ var streamProxyConfig = {
|
|
|
25114
25117
|
// src/lib/api/slackApi.ts
|
|
25115
25118
|
var SlackAPI = class {
|
|
25116
25119
|
/**
|
|
25117
|
-
* Sends a support ticket notification to Slack
|
|
25120
|
+
* Sends a support ticket notification to Slack.
|
|
25121
|
+
* 1. If slackWebhookUrl is configured, send directly (preferred)
|
|
25122
|
+
* 2. Otherwise, if slackProxyEndpoint is configured, send to the proxy
|
|
25123
|
+
* If neither is configured, logs a warning.
|
|
25118
25124
|
*/
|
|
25119
25125
|
static async sendSupportTicketNotification(ticket) {
|
|
25120
25126
|
try {
|
|
25121
|
-
const
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
|
|
25127
|
+
const config = _getDashboardConfigInstance();
|
|
25128
|
+
const endpointsConfig = config.endpoints ?? DEFAULT_ENDPOINTS_CONFIG;
|
|
25129
|
+
const { slackWebhookUrl, slackProxyEndpoint } = endpointsConfig;
|
|
25130
|
+
if (slackWebhookUrl) {
|
|
25131
|
+
const slackMessage = this.formatSlackMessage(ticket);
|
|
25132
|
+
const response = await fetch(slackWebhookUrl, {
|
|
25133
|
+
method: "POST",
|
|
25134
|
+
headers: {
|
|
25135
|
+
// Use form-urlencoded + simple headers to avoid CORS preflight
|
|
25136
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
25137
|
+
},
|
|
25138
|
+
body: `payload=${encodeURIComponent(JSON.stringify(slackMessage))}`
|
|
25139
|
+
});
|
|
25140
|
+
if (!response.ok) {
|
|
25141
|
+
const errorText = await response.text();
|
|
25142
|
+
console.error("Slack webhook error:", errorText);
|
|
25143
|
+
throw new Error(`Slack webhook failed with status: ${response.status}`);
|
|
25144
|
+
}
|
|
25145
|
+
console.log("Support ticket notification sent to Slack successfully via webhook");
|
|
25146
|
+
return;
|
|
25147
|
+
}
|
|
25148
|
+
if (slackProxyEndpoint) {
|
|
25149
|
+
const response = await fetch(slackProxyEndpoint, {
|
|
25150
|
+
method: "POST",
|
|
25151
|
+
headers: {
|
|
25152
|
+
"Content-Type": "application/json"
|
|
25153
|
+
},
|
|
25154
|
+
body: JSON.stringify(ticket)
|
|
25155
|
+
});
|
|
25156
|
+
if (!response.ok) {
|
|
25157
|
+
const errorData = await response.json().catch(() => ({ message: "Unknown error" }));
|
|
25158
|
+
throw new Error(errorData.message || `Proxy failed with status: ${response.status}`);
|
|
25159
|
+
}
|
|
25160
|
+
console.log("Support ticket notification sent to Slack successfully via proxy");
|
|
25161
|
+
return;
|
|
25131
25162
|
}
|
|
25132
|
-
console.
|
|
25163
|
+
console.warn("Slack notification skipped: No webhook or proxy endpoint configured");
|
|
25133
25164
|
} catch (error) {
|
|
25134
25165
|
console.error("Failed to send Slack notification:", error);
|
|
25135
25166
|
throw error;
|
|
25136
25167
|
}
|
|
25137
25168
|
}
|
|
25169
|
+
/**
|
|
25170
|
+
* Formats a support ticket into a Slack message format
|
|
25171
|
+
* This can be used by server-side implementations
|
|
25172
|
+
*/
|
|
25173
|
+
static formatSlackMessage(ticket) {
|
|
25174
|
+
const timestamp = new Date(ticket.timestamp).toLocaleString("en-US", {
|
|
25175
|
+
dateStyle: "medium",
|
|
25176
|
+
timeStyle: "short",
|
|
25177
|
+
timeZone: "UTC"
|
|
25178
|
+
});
|
|
25179
|
+
const maxDescriptionLength = 300;
|
|
25180
|
+
const description = ticket.description.length > maxDescriptionLength ? `${ticket.description.substring(0, maxDescriptionLength)}...` : ticket.description;
|
|
25181
|
+
const categoryConfig = {
|
|
25182
|
+
general: { emoji: "\u{1F4AC}", color: "#36a64f" },
|
|
25183
|
+
technical: { emoji: "\u{1F527}", color: "#ff6b6b" },
|
|
25184
|
+
feature: { emoji: "\u2728", color: "#4ecdc4" },
|
|
25185
|
+
billing: { emoji: "\u{1F4B3}", color: "#f7b731" }
|
|
25186
|
+
};
|
|
25187
|
+
const priorityConfig = {
|
|
25188
|
+
low: { emoji: "\u{1F7E2}", color: "#36a64f" },
|
|
25189
|
+
normal: { emoji: "\u{1F7E1}", color: "#ffc107" },
|
|
25190
|
+
high: { emoji: "\u{1F7E0}", color: "#ff8c00" },
|
|
25191
|
+
urgent: { emoji: "\u{1F534}", color: "#dc3545" }
|
|
25192
|
+
};
|
|
25193
|
+
const categoryInfo = categoryConfig[ticket.category] || categoryConfig.general;
|
|
25194
|
+
const priorityInfo = priorityConfig[ticket.priority] || priorityConfig.normal;
|
|
25195
|
+
const messageColor = ticket.priority === "high" || ticket.priority === "urgent" ? priorityInfo.color : categoryInfo.color;
|
|
25196
|
+
return {
|
|
25197
|
+
text: `New support ticket from ${ticket.email}`,
|
|
25198
|
+
blocks: [
|
|
25199
|
+
{
|
|
25200
|
+
type: "header",
|
|
25201
|
+
text: {
|
|
25202
|
+
type: "plain_text",
|
|
25203
|
+
text: "\u{1F3AB} New Support Ticket Submitted",
|
|
25204
|
+
emoji: true
|
|
25205
|
+
}
|
|
25206
|
+
},
|
|
25207
|
+
{
|
|
25208
|
+
type: "section",
|
|
25209
|
+
fields: [
|
|
25210
|
+
{
|
|
25211
|
+
type: "mrkdwn",
|
|
25212
|
+
text: `*From:*
|
|
25213
|
+
${ticket.email}`
|
|
25214
|
+
},
|
|
25215
|
+
{
|
|
25216
|
+
type: "mrkdwn",
|
|
25217
|
+
text: `*Category:*
|
|
25218
|
+
${categoryInfo.emoji} ${ticket.category.charAt(0).toUpperCase() + ticket.category.slice(1)}`
|
|
25219
|
+
},
|
|
25220
|
+
{
|
|
25221
|
+
type: "mrkdwn",
|
|
25222
|
+
text: `*Priority:*
|
|
25223
|
+
${priorityInfo.emoji} ${ticket.priority.charAt(0).toUpperCase() + ticket.priority.slice(1)}`
|
|
25224
|
+
},
|
|
25225
|
+
{
|
|
25226
|
+
type: "mrkdwn",
|
|
25227
|
+
text: `*Subject:*
|
|
25228
|
+
${ticket.subject}`
|
|
25229
|
+
},
|
|
25230
|
+
{
|
|
25231
|
+
type: "mrkdwn",
|
|
25232
|
+
text: `*Submitted:*
|
|
25233
|
+
${timestamp} UTC`
|
|
25234
|
+
}
|
|
25235
|
+
]
|
|
25236
|
+
},
|
|
25237
|
+
{
|
|
25238
|
+
type: "section",
|
|
25239
|
+
text: {
|
|
25240
|
+
type: "mrkdwn",
|
|
25241
|
+
text: `*Description:*
|
|
25242
|
+
${description}`
|
|
25243
|
+
}
|
|
25244
|
+
},
|
|
25245
|
+
{
|
|
25246
|
+
type: "divider"
|
|
25247
|
+
},
|
|
25248
|
+
{
|
|
25249
|
+
type: "context",
|
|
25250
|
+
elements: [
|
|
25251
|
+
{
|
|
25252
|
+
type: "mrkdwn",
|
|
25253
|
+
text: `Category: \`${ticket.category}\` | Priority: ${priorityInfo.emoji} \`${ticket.priority.toUpperCase()}\` | ${ticket.priority === "urgent" ? "\u26A0\uFE0F Requires immediate attention" : "Standard processing"}`
|
|
25254
|
+
}
|
|
25255
|
+
]
|
|
25256
|
+
}
|
|
25257
|
+
],
|
|
25258
|
+
attachments: [
|
|
25259
|
+
{
|
|
25260
|
+
color: messageColor,
|
|
25261
|
+
fields: []
|
|
25262
|
+
}
|
|
25263
|
+
]
|
|
25264
|
+
};
|
|
25265
|
+
}
|
|
25138
25266
|
};
|
|
25139
25267
|
var HelpView = ({
|
|
25140
25268
|
onTicketSubmit,
|
|
@@ -26576,7 +26704,7 @@ var KPIsOverviewView = ({
|
|
|
26576
26704
|
}
|
|
26577
26705
|
),
|
|
26578
26706
|
/* @__PURE__ */ jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26579
|
-
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26707
|
+
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26580
26708
|
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26581
26709
|
] }) })
|
|
26582
26710
|
] }) }) }),
|
|
@@ -26598,7 +26726,7 @@ var KPIsOverviewView = ({
|
|
|
26598
26726
|
}
|
|
26599
26727
|
),
|
|
26600
26728
|
/* @__PURE__ */ jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26601
|
-
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26729
|
+
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26602
26730
|
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26603
26731
|
] }) })
|
|
26604
26732
|
] }) }) }),
|
|
@@ -26623,7 +26751,7 @@ var KPIsOverviewView = ({
|
|
|
26623
26751
|
}
|
|
26624
26752
|
),
|
|
26625
26753
|
/* @__PURE__ */ jsx("div", { className: "flex-1 flex justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
26626
|
-
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "
|
|
26754
|
+
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold text-gray-800 tracking-tight", children: "Shop-floor overview" }),
|
|
26627
26755
|
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-green-500 animate-pulse ring-2 ring-green-500/30 ring-offset-1" })
|
|
26628
26756
|
] }) })
|
|
26629
26757
|
] }),
|