@catandbox/schrodinger-web-adapter 0.1.32 → 0.1.33
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/client/portal.js
CHANGED
|
@@ -35,6 +35,7 @@ export async function renderSupportPortal(container, options = {}) {
|
|
|
35
35
|
</s-card>
|
|
36
36
|
`;
|
|
37
37
|
}
|
|
38
|
+
const locale = options.locale;
|
|
38
39
|
async function navigate(view, ticketId) {
|
|
39
40
|
currentView = view;
|
|
40
41
|
if (ticketId !== undefined) {
|
|
@@ -44,11 +45,11 @@ export async function renderSupportPortal(container, options = {}) {
|
|
|
44
45
|
showLoading();
|
|
45
46
|
switch (currentView) {
|
|
46
47
|
case "list":
|
|
47
|
-
await renderTicketList(container, client, emitter);
|
|
48
|
+
await renderTicketList(container, client, emitter, locale);
|
|
48
49
|
break;
|
|
49
50
|
case "detail":
|
|
50
51
|
if (selectedTicketId) {
|
|
51
|
-
await renderTicketDetail(container, client, selectedTicketId, emitter);
|
|
52
|
+
await renderTicketDetail(container, client, selectedTicketId, emitter, locale);
|
|
52
53
|
}
|
|
53
54
|
break;
|
|
54
55
|
case "create":
|
|
@@ -6,4 +6,4 @@ export interface TicketDetailEvents {
|
|
|
6
6
|
"ticket:closed": string;
|
|
7
7
|
"ticket:reopened": string;
|
|
8
8
|
}
|
|
9
|
-
export declare function renderTicketDetail(container: HTMLElement, client: SupportApiClient, ticketId: string, emitter: EventEmitter<TicketDetailEvents
|
|
9
|
+
export declare function renderTicketDetail(container: HTMLElement, client: SupportApiClient, ticketId: string, emitter: EventEmitter<TicketDetailEvents>, locale?: string): Promise<void>;
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { renderStatusBadge } from "./status-badge";
|
|
2
2
|
import { createFileUpload } from "./file-upload";
|
|
3
3
|
import { setInnerHtml, escapeHtml, formatBodyText, renderFormattingField, attachFormattingField } from "./dom-utils";
|
|
4
|
-
function formatTimestamp(timestamp) {
|
|
4
|
+
function formatTimestamp(timestamp, locale) {
|
|
5
5
|
const date = new Date(timestamp * 1000);
|
|
6
6
|
const now = new Date();
|
|
7
7
|
const isToday = date.toDateString() === now.toDateString();
|
|
8
8
|
if (isToday) {
|
|
9
|
-
return date.toLocaleTimeString(
|
|
9
|
+
return date.toLocaleTimeString(locale, { hour: "numeric", minute: "2-digit" });
|
|
10
10
|
}
|
|
11
|
-
return date.toLocaleDateString(
|
|
11
|
+
return date.toLocaleDateString(locale, {
|
|
12
12
|
month: "short",
|
|
13
13
|
day: "numeric",
|
|
14
14
|
hour: "numeric",
|
|
15
15
|
minute: "2-digit"
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
function formatFullDate(timestamp) {
|
|
19
|
-
return new Date(timestamp * 1000).toLocaleDateString(
|
|
18
|
+
function formatFullDate(timestamp, locale) {
|
|
19
|
+
return new Date(timestamp * 1000).toLocaleDateString(locale, {
|
|
20
20
|
month: "long",
|
|
21
21
|
day: "numeric",
|
|
22
22
|
year: "numeric",
|
|
@@ -24,7 +24,7 @@ function formatFullDate(timestamp) {
|
|
|
24
24
|
minute: "2-digit"
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
export async function renderTicketDetail(container, client, ticketId, emitter) {
|
|
27
|
+
export async function renderTicketDetail(container, client, ticketId, emitter, locale) {
|
|
28
28
|
container.innerHTML = `
|
|
29
29
|
<s-card>
|
|
30
30
|
<s-box padding="large">
|
|
@@ -64,7 +64,7 @@ export async function renderTicketDetail(container, client, ticketId, emitter) {
|
|
|
64
64
|
${renderStatusBadge(ticket.status)}
|
|
65
65
|
<s-text tone="neutral">#${ticket.id.slice(0, 8)}</s-text>
|
|
66
66
|
<s-text tone="neutral">·</s-text>
|
|
67
|
-
<s-text tone="neutral">Created ${formatFullDate(ticket.createdAt)}</s-text>
|
|
67
|
+
<s-text tone="neutral">Created ${formatFullDate(ticket.createdAt, locale)}</s-text>
|
|
68
68
|
</s-stack>
|
|
69
69
|
</div>
|
|
70
70
|
${!isOpen ? `<s-button id="sch-reopen-ticket-btn">Reopen</s-button>` : ""}
|
|
@@ -99,7 +99,7 @@ export async function renderTicketDetail(container, client, ticketId, emitter) {
|
|
|
99
99
|
</s-box>
|
|
100
100
|
</s-card>`
|
|
101
101
|
: `<s-stack gap="small-100">
|
|
102
|
-
${messages.map((msg) => renderMessage(msg, aliasMap.get(msg.authorAliasId ?? "") ?? null)).join("")}
|
|
102
|
+
${messages.map((msg) => renderMessage(msg, aliasMap.get(msg.authorAliasId ?? "") ?? null, locale)).join("")}
|
|
103
103
|
</s-stack>`}
|
|
104
104
|
</div>
|
|
105
105
|
|
|
@@ -223,7 +223,7 @@ function getInitials(displayName) {
|
|
|
223
223
|
}
|
|
224
224
|
return displayName.slice(0, 2).toUpperCase();
|
|
225
225
|
}
|
|
226
|
-
function renderMessage(msg, alias) {
|
|
226
|
+
function renderMessage(msg, alias, locale) {
|
|
227
227
|
const isSystem = msg.authorType === "system";
|
|
228
228
|
const isAgent = msg.authorType === "agent" || msg.authorType === "admin";
|
|
229
229
|
const isCustomer = !isSystem && !isAgent;
|
|
@@ -245,7 +245,7 @@ function renderMessage(msg, alias) {
|
|
|
245
245
|
<div style="min-width:0;">
|
|
246
246
|
<s-stack direction="inline" alignItems="baseline" gap="small" justifyContent="${isCustomer ? "end" : "start"}" style="margin-bottom:4px;">
|
|
247
247
|
<s-text type="strong">${label}</s-text>
|
|
248
|
-
<s-text tone="neutral">${formatTimestamp(msg.createdAt)}</s-text>
|
|
248
|
+
<s-text tone="neutral">${formatTimestamp(msg.createdAt, locale)}</s-text>
|
|
249
249
|
</s-stack>
|
|
250
250
|
<div style="background:${bubbleBg}; padding:10px 14px; border-radius:12px; display:inline-block; text-align:left; max-width:100%;">
|
|
251
251
|
<s-text style="white-space:pre-wrap; word-break:break-word;">${formatBodyText(msg.bodyPlain)}</s-text>
|
|
@@ -5,4 +5,4 @@ export interface TicketListEvents {
|
|
|
5
5
|
"ticket:select": string;
|
|
6
6
|
"ticket:create": void;
|
|
7
7
|
}
|
|
8
|
-
export declare function renderTicketList(container: HTMLElement, client: SupportApiClient, emitter: EventEmitter<TicketListEvents
|
|
8
|
+
export declare function renderTicketList(container: HTMLElement, client: SupportApiClient, emitter: EventEmitter<TicketListEvents>, locale?: string): Promise<void>;
|
|
@@ -164,27 +164,28 @@ function initHydrogenLogo(el) {
|
|
|
164
164
|
renderer.dispose();
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
|
-
function formatDate(timestamp) {
|
|
168
|
-
return new Date(timestamp * 1000).toLocaleDateString(
|
|
167
|
+
function formatDate(timestamp, locale) {
|
|
168
|
+
return new Date(timestamp * 1000).toLocaleDateString(locale, {
|
|
169
169
|
month: "short",
|
|
170
170
|
day: "numeric",
|
|
171
171
|
year: "numeric"
|
|
172
172
|
});
|
|
173
173
|
}
|
|
174
|
-
function timeAgo(timestamp) {
|
|
174
|
+
function timeAgo(timestamp, locale) {
|
|
175
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
175
176
|
const seconds = Math.floor(Date.now() / 1000 - timestamp);
|
|
176
177
|
if (seconds < 60)
|
|
177
|
-
return
|
|
178
|
+
return rtf.format(-seconds, "second");
|
|
178
179
|
const minutes = Math.floor(seconds / 60);
|
|
179
180
|
if (minutes < 60)
|
|
180
|
-
return
|
|
181
|
+
return rtf.format(-minutes, "minute");
|
|
181
182
|
const hours = Math.floor(minutes / 60);
|
|
182
183
|
if (hours < 24)
|
|
183
|
-
return
|
|
184
|
+
return rtf.format(-hours, "hour");
|
|
184
185
|
const days = Math.floor(hours / 24);
|
|
185
186
|
if (days < 7)
|
|
186
|
-
return
|
|
187
|
-
return formatDate(timestamp);
|
|
187
|
+
return rtf.format(-days, "day");
|
|
188
|
+
return formatDate(timestamp, locale);
|
|
188
189
|
}
|
|
189
190
|
const STATUS_OPTIONS = [
|
|
190
191
|
{ value: "", label: "All statuses" },
|
|
@@ -198,7 +199,7 @@ const ORDER_OPTIONS = [
|
|
|
198
199
|
{ value: "newest", label: "Latest first" },
|
|
199
200
|
{ value: "oldest", label: "Oldest first" }
|
|
200
201
|
];
|
|
201
|
-
export async function renderTicketList(container, client, emitter) {
|
|
202
|
+
export async function renderTicketList(container, client, emitter, locale) {
|
|
202
203
|
// Load tickets, categories and Three.js in parallel
|
|
203
204
|
const [result, portalConfig] = await Promise.all([
|
|
204
205
|
client.listTickets({}).catch(() => ({ items: [] })),
|
|
@@ -319,7 +320,7 @@ export async function renderTicketList(container, client, emitter) {
|
|
|
319
320
|
<s-text variant="bodyMd" fontWeight="semibold">${escapeHtml(ticket.title)}</s-text>
|
|
320
321
|
</div>
|
|
321
322
|
<div style="margin-top:2px;">
|
|
322
|
-
<s-text variant="bodySm" tone="subdued">#${ticket.id.slice(0, 8)} · Updated ${timeAgo(ticket.updatedAt)}</s-text>
|
|
323
|
+
<s-text variant="bodySm" tone="subdued">#${ticket.id.slice(0, 8)} · Updated ${timeAgo(ticket.updatedAt, locale)}</s-text>
|
|
323
324
|
</div>
|
|
324
325
|
</div>
|
|
325
326
|
</div>
|