@djangocfg/ext-support 1.0.21 → 1.0.22
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/config.cjs +8 -1
- package/dist/config.js +8 -1
- package/dist/hooks.cjs +389 -91
- package/dist/hooks.js +361 -63
- package/dist/i18n.cjs +246 -0
- package/dist/i18n.d.cts +99 -0
- package/dist/i18n.d.ts +99 -0
- package/dist/i18n.js +220 -0
- package/dist/index.cjs +389 -91
- package/dist/index.js +361 -63
- package/package.json +15 -8
- package/src/i18n/index.ts +23 -0
- package/src/i18n/locales/en.ts +76 -0
- package/src/i18n/locales/ko.ts +76 -0
- package/src/i18n/locales/ru.ts +76 -0
- package/src/i18n/types.ts +99 -0
- package/src/layouts/SupportLayout/SupportLayout.tsx +19 -7
- package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +42 -17
- package/src/layouts/SupportLayout/components/MessageInput.tsx +20 -11
- package/src/layouts/SupportLayout/components/MessageList.tsx +32 -11
- package/src/layouts/SupportLayout/components/TicketCard.tsx +37 -14
- package/src/layouts/SupportLayout/components/TicketList.tsx +19 -6
package/dist/index.js
CHANGED
|
@@ -3,7 +3,9 @@ import pRetry, { AbortError } from 'p-retry';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
5
|
import { ArrowLeft, LifeBuoy, Plus, MessageSquare, Loader2, Send, Headphones, User, Clock } from 'lucide-react';
|
|
6
|
-
import
|
|
6
|
+
import React8, { createContext, useState, useCallback, useEffect, useMemo, useContext, useRef } from 'react';
|
|
7
|
+
import { createExtensionI18n, createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
8
|
+
import { useT } from '@djangocfg/i18n';
|
|
7
9
|
import { Button, ResizablePanelGroup, ResizablePanel, ResizableHandle, Skeleton, ScrollArea, Textarea, useToast as useToast$1, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormMessage, Avatar, AvatarImage, AvatarFallback, Card, CardContent, Badge } from '@djangocfg/ui-core';
|
|
8
10
|
import useSWR, { useSWRConfig } from 'swr';
|
|
9
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1615,6 +1617,219 @@ var API = class {
|
|
|
1615
1617
|
};
|
|
1616
1618
|
initializeExtensionAPI(configureAPI);
|
|
1617
1619
|
var apiSupport = createExtensionAPI(API);
|
|
1620
|
+
|
|
1621
|
+
// src/i18n/locales/en.ts
|
|
1622
|
+
var en = {
|
|
1623
|
+
layout: {
|
|
1624
|
+
title: "Support Center",
|
|
1625
|
+
titleShort: "Support",
|
|
1626
|
+
subtitle: "Get help from our support team",
|
|
1627
|
+
newTicket: "New Ticket"
|
|
1628
|
+
},
|
|
1629
|
+
status: {
|
|
1630
|
+
open: "Open",
|
|
1631
|
+
waitingForUser: "Waiting for you",
|
|
1632
|
+
waitingForAdmin: "Waiting for support",
|
|
1633
|
+
resolved: "Resolved",
|
|
1634
|
+
closed: "Closed"
|
|
1635
|
+
},
|
|
1636
|
+
ticketList: {
|
|
1637
|
+
noTickets: "No tickets yet",
|
|
1638
|
+
noTicketsDescription: "Create your first support ticket to get help",
|
|
1639
|
+
loadingMore: "Loading more...",
|
|
1640
|
+
loadMore: "Load more",
|
|
1641
|
+
allLoaded: "All {count} tickets loaded"
|
|
1642
|
+
},
|
|
1643
|
+
createTicket: {
|
|
1644
|
+
title: "New Support Ticket",
|
|
1645
|
+
description: "Describe your issue and we will help you",
|
|
1646
|
+
subjectLabel: "Subject",
|
|
1647
|
+
subjectPlaceholder: "Brief description of your issue",
|
|
1648
|
+
messageLabel: "Message",
|
|
1649
|
+
messagePlaceholder: "Describe your issue in detail...",
|
|
1650
|
+
cancel: "Cancel",
|
|
1651
|
+
creating: "Creating...",
|
|
1652
|
+
create: "Create Ticket"
|
|
1653
|
+
},
|
|
1654
|
+
validation: {
|
|
1655
|
+
subjectRequired: "Subject is required",
|
|
1656
|
+
subjectTooLong: "Subject is too long (max 200 characters)",
|
|
1657
|
+
messageRequired: "Message is required",
|
|
1658
|
+
messageTooLong: "Message is too long (max 5000 characters)"
|
|
1659
|
+
},
|
|
1660
|
+
messages: {
|
|
1661
|
+
ticketCreated: "Ticket created successfully",
|
|
1662
|
+
ticketCreateFailed: "Failed to create ticket",
|
|
1663
|
+
messageSent: "Message sent",
|
|
1664
|
+
messageSendFailed: "Failed to send message"
|
|
1665
|
+
},
|
|
1666
|
+
messageInput: {
|
|
1667
|
+
placeholder: "Type your message...",
|
|
1668
|
+
ticketClosed: "Ticket closed",
|
|
1669
|
+
ticketClosedDescription: "This ticket has been closed. Create a new ticket if you need further assistance."
|
|
1670
|
+
},
|
|
1671
|
+
messageList: {
|
|
1672
|
+
noTicketSelected: "No ticket selected",
|
|
1673
|
+
noTicketSelectedDescription: "Select a ticket from the list to view messages",
|
|
1674
|
+
noMessages: "No messages yet",
|
|
1675
|
+
noMessagesDescription: "Start the conversation by sending a message",
|
|
1676
|
+
loadingOlder: "Loading older messages...",
|
|
1677
|
+
loadOlder: "Load older messages",
|
|
1678
|
+
supportTeam: "Support Team",
|
|
1679
|
+
staff: "Staff"
|
|
1680
|
+
},
|
|
1681
|
+
time: {
|
|
1682
|
+
justNow: "Just now",
|
|
1683
|
+
minutesAgo: "{count} min ago",
|
|
1684
|
+
hoursAgo: "{count}h ago",
|
|
1685
|
+
daysAgo: "{count}d ago"
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
// src/i18n/locales/ru.ts
|
|
1690
|
+
var ru = {
|
|
1691
|
+
layout: {
|
|
1692
|
+
title: "\u0426\u0435\u043D\u0442\u0440 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0438",
|
|
1693
|
+
titleShort: "\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430",
|
|
1694
|
+
subtitle: "\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u0435 \u043F\u043E\u043C\u043E\u0449\u044C \u043E\u0442 \u043D\u0430\u0448\u0435\u0439 \u043A\u043E\u043C\u0430\u043D\u0434\u044B \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0438",
|
|
1695
|
+
newTicket: "\u041D\u043E\u0432\u043E\u0435 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435"
|
|
1696
|
+
},
|
|
1697
|
+
status: {
|
|
1698
|
+
open: "\u041E\u0442\u043A\u0440\u044B\u0442",
|
|
1699
|
+
waitingForUser: "\u041E\u0436\u0438\u0434\u0430\u0435\u0442 \u0432\u0430\u0441",
|
|
1700
|
+
waitingForAdmin: "\u041E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443",
|
|
1701
|
+
resolved: "\u0420\u0435\u0448\u0451\u043D",
|
|
1702
|
+
closed: "\u0417\u0430\u043A\u0440\u044B\u0442"
|
|
1703
|
+
},
|
|
1704
|
+
ticketList: {
|
|
1705
|
+
noTickets: "\u041D\u0435\u0442 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0439",
|
|
1706
|
+
noTicketsDescription: "\u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u043F\u0435\u0440\u0432\u043E\u0435 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435, \u0447\u0442\u043E\u0431\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043F\u043E\u043C\u043E\u0449\u044C",
|
|
1707
|
+
loadingMore: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430...",
|
|
1708
|
+
loadMore: "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0435\u0449\u0451",
|
|
1709
|
+
allLoaded: "\u0412\u0441\u0435 {count} \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043E"
|
|
1710
|
+
},
|
|
1711
|
+
createTicket: {
|
|
1712
|
+
title: "\u041D\u043E\u0432\u043E\u0435 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435",
|
|
1713
|
+
description: "\u041E\u043F\u0438\u0448\u0438\u0442\u0435 \u0432\u0430\u0448\u0443 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0443, \u0438 \u043C\u044B \u043F\u043E\u043C\u043E\u0436\u0435\u043C \u0432\u0430\u043C",
|
|
1714
|
+
subjectLabel: "\u0422\u0435\u043C\u0430",
|
|
1715
|
+
subjectPlaceholder: "\u041A\u0440\u0430\u0442\u043A\u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u044B",
|
|
1716
|
+
messageLabel: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435",
|
|
1717
|
+
messagePlaceholder: "\u041E\u043F\u0438\u0448\u0438\u0442\u0435 \u0432\u0430\u0448\u0443 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0443 \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u043E...",
|
|
1718
|
+
cancel: "\u041E\u0442\u043C\u0435\u043D\u0430",
|
|
1719
|
+
creating: "\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435...",
|
|
1720
|
+
create: "\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435"
|
|
1721
|
+
},
|
|
1722
|
+
validation: {
|
|
1723
|
+
subjectRequired: "\u0422\u0435\u043C\u0430 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u0430",
|
|
1724
|
+
subjectTooLong: "\u0422\u0435\u043C\u0430 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\u0438\u043D\u043D\u0430\u044F (\u043C\u0430\u043A\u0441. 200 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432)",
|
|
1725
|
+
messageRequired: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E",
|
|
1726
|
+
messageTooLong: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043B\u0438\u043D\u043D\u043E\u0435 (\u043C\u0430\u043A\u0441. 5000 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432)"
|
|
1727
|
+
},
|
|
1728
|
+
messages: {
|
|
1729
|
+
ticketCreated: "\u041E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435 \u0441\u043E\u0437\u0434\u0430\u043D\u043E",
|
|
1730
|
+
ticketCreateFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435",
|
|
1731
|
+
messageSent: "\u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E",
|
|
1732
|
+
messageSendFailed: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435"
|
|
1733
|
+
},
|
|
1734
|
+
messageInput: {
|
|
1735
|
+
placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435...",
|
|
1736
|
+
ticketClosed: "\u041E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u043E",
|
|
1737
|
+
ticketClosedDescription: "\u042D\u0442\u043E \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u043E. \u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u043E\u0435, \u0435\u0441\u043B\u0438 \u0432\u0430\u043C \u043D\u0443\u0436\u043D\u0430 \u043F\u043E\u043C\u043E\u0449\u044C."
|
|
1738
|
+
},
|
|
1739
|
+
messageList: {
|
|
1740
|
+
noTicketSelected: "\u041E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E",
|
|
1741
|
+
noTicketSelectedDescription: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0435 \u0438\u0437 \u0441\u043F\u0438\u0441\u043A\u0430 \u0434\u043B\u044F \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0430 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439",
|
|
1742
|
+
noMessages: "\u041D\u0435\u0442 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439",
|
|
1743
|
+
noMessagesDescription: "\u041D\u0430\u0447\u043D\u0438\u0442\u0435 \u0434\u0438\u0430\u043B\u043E\u0433, \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0432 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435",
|
|
1744
|
+
loadingOlder: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0441\u0442\u0430\u0440\u044B\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439...",
|
|
1745
|
+
loadOlder: "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0441\u0442\u0430\u0440\u044B\u0435",
|
|
1746
|
+
supportTeam: "\u0421\u043B\u0443\u0436\u0431\u0430 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0438",
|
|
1747
|
+
staff: "\u0421\u043E\u0442\u0440\u0443\u0434\u043D\u0438\u043A"
|
|
1748
|
+
},
|
|
1749
|
+
time: {
|
|
1750
|
+
justNow: "\u0422\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u043E",
|
|
1751
|
+
minutesAgo: "{count} \u043C\u0438\u043D \u043D\u0430\u0437\u0430\u0434",
|
|
1752
|
+
hoursAgo: "{count}\u0447 \u043D\u0430\u0437\u0430\u0434",
|
|
1753
|
+
daysAgo: "{count}\u0434 \u043D\u0430\u0437\u0430\u0434"
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1757
|
+
// src/i18n/locales/ko.ts
|
|
1758
|
+
var ko = {
|
|
1759
|
+
layout: {
|
|
1760
|
+
title: "\uACE0\uAC1D\uC9C0\uC6D0 \uC13C\uD130",
|
|
1761
|
+
titleShort: "\uACE0\uAC1D\uC9C0\uC6D0",
|
|
1762
|
+
subtitle: "\uACE0\uAC1D\uC9C0\uC6D0\uD300\uC758 \uB3C4\uC6C0\uC744 \uBC1B\uC73C\uC138\uC694",
|
|
1763
|
+
newTicket: "\uC0C8 \uBB38\uC758"
|
|
1764
|
+
},
|
|
1765
|
+
status: {
|
|
1766
|
+
open: "\uC5F4\uB9BC",
|
|
1767
|
+
waitingForUser: "\uD68C\uC2E0 \uB300\uAE30",
|
|
1768
|
+
waitingForAdmin: "\uC9C0\uC6D0\uD300 \uB300\uAE30",
|
|
1769
|
+
resolved: "\uD574\uACB0\uB428",
|
|
1770
|
+
closed: "\uC885\uB8CC"
|
|
1771
|
+
},
|
|
1772
|
+
ticketList: {
|
|
1773
|
+
noTickets: "\uBB38\uC758 \uB0B4\uC5ED \uC5C6\uC74C",
|
|
1774
|
+
noTicketsDescription: "\uCCAB \uBC88\uC9F8 \uBB38\uC758\uB97C \uB4F1\uB85D\uD558\uC5EC \uB3C4\uC6C0\uC744 \uBC1B\uC73C\uC138\uC694",
|
|
1775
|
+
loadingMore: "\uBD88\uB7EC\uC624\uB294 \uC911...",
|
|
1776
|
+
loadMore: "\uB354 \uBCF4\uAE30",
|
|
1777
|
+
allLoaded: "\uCD1D {count}\uAC1C\uC758 \uBB38\uC758\uAC00 \uB85C\uB4DC\uB428"
|
|
1778
|
+
},
|
|
1779
|
+
createTicket: {
|
|
1780
|
+
title: "\uC0C8 \uBB38\uC758",
|
|
1781
|
+
description: "\uBB38\uC81C\uB97C \uC124\uBA85\uD574 \uC8FC\uC2DC\uBA74 \uB3C4\uC6C0\uC744 \uB4DC\uB9AC\uACA0\uC2B5\uB2C8\uB2E4",
|
|
1782
|
+
subjectLabel: "\uC81C\uBAA9",
|
|
1783
|
+
subjectPlaceholder: "\uBB38\uC81C\uC5D0 \uB300\uD55C \uAC04\uB7B5\uD55C \uC124\uBA85",
|
|
1784
|
+
messageLabel: "\uB0B4\uC6A9",
|
|
1785
|
+
messagePlaceholder: "\uBB38\uC81C\uB97C \uC790\uC138\uD788 \uC124\uBA85\uD574 \uC8FC\uC138\uC694...",
|
|
1786
|
+
cancel: "\uCDE8\uC18C",
|
|
1787
|
+
creating: "\uC0DD\uC131 \uC911...",
|
|
1788
|
+
create: "\uBB38\uC758 \uB4F1\uB85D"
|
|
1789
|
+
},
|
|
1790
|
+
validation: {
|
|
1791
|
+
subjectRequired: "\uC81C\uBAA9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694",
|
|
1792
|
+
subjectTooLong: "\uC81C\uBAA9\uC774 \uB108\uBB34 \uAE41\uB2C8\uB2E4 (\uCD5C\uB300 200\uC790)",
|
|
1793
|
+
messageRequired: "\uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694",
|
|
1794
|
+
messageTooLong: "\uB0B4\uC6A9\uC774 \uB108\uBB34 \uAE41\uB2C8\uB2E4 (\uCD5C\uB300 5000\uC790)"
|
|
1795
|
+
},
|
|
1796
|
+
messages: {
|
|
1797
|
+
ticketCreated: "\uBB38\uC758\uAC00 \uB4F1\uB85D\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
1798
|
+
ticketCreateFailed: "\uBB38\uC758 \uB4F1\uB85D\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
|
|
1799
|
+
messageSent: "\uBA54\uC2DC\uC9C0\uAC00 \uC804\uC1A1\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
1800
|
+
messageSendFailed: "\uBA54\uC2DC\uC9C0 \uC804\uC1A1\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4"
|
|
1801
|
+
},
|
|
1802
|
+
messageInput: {
|
|
1803
|
+
placeholder: "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD558\uC138\uC694...",
|
|
1804
|
+
ticketClosed: "\uBB38\uC758 \uC885\uB8CC\uB428",
|
|
1805
|
+
ticketClosedDescription: "\uC774 \uBB38\uC758\uB294 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCD94\uAC00 \uB3C4\uC6C0\uC774 \uD544\uC694\uD558\uC2DC\uBA74 \uC0C8 \uBB38\uC758\uB97C \uB4F1\uB85D\uD574 \uC8FC\uC138\uC694."
|
|
1806
|
+
},
|
|
1807
|
+
messageList: {
|
|
1808
|
+
noTicketSelected: "\uBB38\uC758\uAC00 \uC120\uD0DD\uB418\uC9C0 \uC54A\uC74C",
|
|
1809
|
+
noTicketSelectedDescription: "\uBA54\uC2DC\uC9C0\uB97C \uBCF4\uB824\uBA74 \uBAA9\uB85D\uC5D0\uC11C \uBB38\uC758\uB97C \uC120\uD0DD\uD558\uC138\uC694",
|
|
1810
|
+
noMessages: "\uBA54\uC2DC\uC9C0 \uC5C6\uC74C",
|
|
1811
|
+
noMessagesDescription: "\uBA54\uC2DC\uC9C0\uB97C \uBCF4\uB0B4 \uB300\uD654\uB97C \uC2DC\uC791\uD558\uC138\uC694",
|
|
1812
|
+
loadingOlder: "\uC774\uC804 \uBA54\uC2DC\uC9C0 \uBD88\uB7EC\uC624\uB294 \uC911...",
|
|
1813
|
+
loadOlder: "\uC774\uC804 \uBA54\uC2DC\uC9C0 \uBCF4\uAE30",
|
|
1814
|
+
supportTeam: "\uACE0\uAC1D\uC9C0\uC6D0\uD300",
|
|
1815
|
+
staff: "\uB2F4\uB2F9\uC790"
|
|
1816
|
+
},
|
|
1817
|
+
time: {
|
|
1818
|
+
justNow: "\uBC29\uAE08 \uC804",
|
|
1819
|
+
minutesAgo: "{count}\uBD84 \uC804",
|
|
1820
|
+
hoursAgo: "{count}\uC2DC\uAC04 \uC804",
|
|
1821
|
+
daysAgo: "{count}\uC77C \uC804"
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
|
|
1825
|
+
// src/i18n/index.ts
|
|
1826
|
+
var SUPPORT_NAMESPACE = "support";
|
|
1827
|
+
var supportI18n = createExtensionI18n({
|
|
1828
|
+
namespace: SUPPORT_NAMESPACE,
|
|
1829
|
+
defaultLocale: "en",
|
|
1830
|
+
locales: { en, ru, ko }
|
|
1831
|
+
});
|
|
1832
|
+
supportI18n.getAllTranslations();
|
|
1618
1833
|
function useSupportTicketsList(params, client) {
|
|
1619
1834
|
return useSWR(
|
|
1620
1835
|
params ? ["cfg-support-tickets", params] : "cfg-support-tickets",
|
|
@@ -1829,18 +2044,36 @@ var getStatusBadgeVariant = (status) => {
|
|
|
1829
2044
|
return "default";
|
|
1830
2045
|
}
|
|
1831
2046
|
};
|
|
1832
|
-
var formatRelativeTime = (date) => {
|
|
1833
|
-
if (!date) return "N/A";
|
|
1834
|
-
const m = moment2.utc(date).local();
|
|
1835
|
-
const now = moment2();
|
|
1836
|
-
const diffInSeconds = now.diff(m, "seconds");
|
|
1837
|
-
if (diffInSeconds < 60) return "Just now";
|
|
1838
|
-
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|
|
1839
|
-
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
|
|
1840
|
-
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`;
|
|
1841
|
-
return m.format("MMM D, YYYY");
|
|
1842
|
-
};
|
|
1843
2047
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
2048
|
+
const baseT = useT();
|
|
2049
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2050
|
+
const labels = useMemo(() => ({
|
|
2051
|
+
status: {
|
|
2052
|
+
open: st("status.open"),
|
|
2053
|
+
waiting_for_user: st("status.waitingForUser"),
|
|
2054
|
+
waiting_for_admin: st("status.waitingForAdmin"),
|
|
2055
|
+
resolved: st("status.resolved"),
|
|
2056
|
+
closed: st("status.closed")
|
|
2057
|
+
},
|
|
2058
|
+
time: {
|
|
2059
|
+
justNow: st("time.justNow"),
|
|
2060
|
+
minutesAgo: st("time.minutesAgo"),
|
|
2061
|
+
hoursAgo: st("time.hoursAgo"),
|
|
2062
|
+
daysAgo: st("time.daysAgo")
|
|
2063
|
+
}
|
|
2064
|
+
}), [st]);
|
|
2065
|
+
const formatRelativeTime = useCallback((date) => {
|
|
2066
|
+
if (!date) return "N/A";
|
|
2067
|
+
const m = moment2.utc(date).local();
|
|
2068
|
+
const now = moment2();
|
|
2069
|
+
const diffInSeconds = now.diff(m, "seconds");
|
|
2070
|
+
if (diffInSeconds < 60) return labels.time.justNow;
|
|
2071
|
+
if (diffInSeconds < 3600) return labels.time.minutesAgo.replace("{count}", String(Math.floor(diffInSeconds / 60)));
|
|
2072
|
+
if (diffInSeconds < 86400) return labels.time.hoursAgo.replace("{count}", String(Math.floor(diffInSeconds / 3600)));
|
|
2073
|
+
if (diffInSeconds < 604800) return labels.time.daysAgo.replace("{count}", String(Math.floor(diffInSeconds / 86400)));
|
|
2074
|
+
return m.format("MMM D, YYYY");
|
|
2075
|
+
}, [labels.time]);
|
|
2076
|
+
const statusLabel = labels.status[ticket.status] || ticket.status || labels.status.open;
|
|
1844
2077
|
return /* @__PURE__ */ jsx(
|
|
1845
2078
|
Card,
|
|
1846
2079
|
{
|
|
@@ -1864,7 +2097,7 @@ var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
|
1864
2097
|
)
|
|
1865
2098
|
] }),
|
|
1866
2099
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1867
|
-
/* @__PURE__ */ jsx(Badge, { variant: getStatusBadgeVariant(ticket.status || "open"), className: "text-xs", children:
|
|
2100
|
+
/* @__PURE__ */ jsx(Badge, { variant: getStatusBadgeVariant(ticket.status || "open"), className: "text-xs", children: statusLabel }),
|
|
1868
2101
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1869
2102
|
/* @__PURE__ */ jsx(Clock, { className: "h-3 w-3" }),
|
|
1870
2103
|
/* @__PURE__ */ jsx("span", { children: formatRelativeTime(ticket.created_at) })
|
|
@@ -2139,6 +2372,8 @@ function useSupportLayoutContext() {
|
|
|
2139
2372
|
return context;
|
|
2140
2373
|
}
|
|
2141
2374
|
var TicketList = () => {
|
|
2375
|
+
const baseT = useT();
|
|
2376
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2142
2377
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
2143
2378
|
const {
|
|
2144
2379
|
tickets,
|
|
@@ -2149,6 +2384,13 @@ var TicketList = () => {
|
|
|
2149
2384
|
totalCount,
|
|
2150
2385
|
refresh
|
|
2151
2386
|
} = useInfiniteTickets();
|
|
2387
|
+
const labels = useMemo(() => ({
|
|
2388
|
+
noTickets: st("ticketList.noTickets"),
|
|
2389
|
+
noTicketsDescription: st("ticketList.noTicketsDescription"),
|
|
2390
|
+
loadingMore: st("ticketList.loadingMore"),
|
|
2391
|
+
loadMore: st("ticketList.loadMore"),
|
|
2392
|
+
allLoaded: st("ticketList.allLoaded")
|
|
2393
|
+
}), [st]);
|
|
2152
2394
|
const scrollRef = useRef(null);
|
|
2153
2395
|
const observerRef = useRef(null);
|
|
2154
2396
|
const loadMoreRef = useRef(null);
|
|
@@ -2194,8 +2436,8 @@ var TicketList = () => {
|
|
|
2194
2436
|
if (!tickets || tickets.length === 0) {
|
|
2195
2437
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-full p-8 text-center animate-in fade-in zoom-in-95 duration-300", children: [
|
|
2196
2438
|
/* @__PURE__ */ jsx(MessageSquare, { className: "h-16 w-16 text-muted-foreground mb-4 animate-bounce" }),
|
|
2197
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children:
|
|
2198
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children:
|
|
2439
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: labels.noTickets }),
|
|
2440
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children: labels.noTicketsDescription })
|
|
2199
2441
|
] });
|
|
2200
2442
|
}
|
|
2201
2443
|
return /* @__PURE__ */ jsx(ScrollArea, { className: "h-full", viewportRef: scrollRef, children: /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-2", children: [
|
|
@@ -2218,7 +2460,7 @@ var TicketList = () => {
|
|
|
2218
2460
|
/* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "h-2" }),
|
|
2219
2461
|
isLoadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
2220
2462
|
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
2221
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm", children:
|
|
2463
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: labels.loadingMore })
|
|
2222
2464
|
] }) }),
|
|
2223
2465
|
hasMore && !isLoadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxs(
|
|
2224
2466
|
Button,
|
|
@@ -2228,17 +2470,14 @@ var TicketList = () => {
|
|
|
2228
2470
|
onClick: loadMore,
|
|
2229
2471
|
className: "text-xs",
|
|
2230
2472
|
children: [
|
|
2231
|
-
|
|
2473
|
+
labels.loadMore,
|
|
2474
|
+
" (",
|
|
2232
2475
|
totalCount > 0 ? `${tickets.length}/${totalCount}` : "",
|
|
2233
2476
|
")"
|
|
2234
2477
|
]
|
|
2235
2478
|
}
|
|
2236
2479
|
) }),
|
|
2237
|
-
!hasMore && tickets.length > 0 && /* @__PURE__ */
|
|
2238
|
-
"All ",
|
|
2239
|
-
totalCount,
|
|
2240
|
-
" tickets loaded"
|
|
2241
|
-
] })
|
|
2480
|
+
!hasMore && tickets.length > 0 && /* @__PURE__ */ jsx("div", { className: "text-center py-4 text-sm text-muted-foreground", children: labels.allLoaded.replace("{count}", String(totalCount)) })
|
|
2242
2481
|
] }) });
|
|
2243
2482
|
};
|
|
2244
2483
|
var formatTime = (date) => {
|
|
@@ -2249,7 +2488,7 @@ var formatDate = (date) => {
|
|
|
2249
2488
|
if (!date) return "";
|
|
2250
2489
|
return moment2.utc(date).local().format("MMM D, YYYY");
|
|
2251
2490
|
};
|
|
2252
|
-
var MessageBubble = ({ message, isFromUser, currentUser }) => {
|
|
2491
|
+
var MessageBubble = ({ message, isFromUser, currentUser, labels }) => {
|
|
2253
2492
|
const sender = message.sender;
|
|
2254
2493
|
const senderInitial = sender?.display_username?.charAt(0)?.toUpperCase() || sender?.initials || "S";
|
|
2255
2494
|
const userInitial = currentUser?.display_username?.charAt(0)?.toUpperCase() || currentUser?.email?.charAt(0)?.toUpperCase() || currentUser?.initials || null;
|
|
@@ -2259,11 +2498,11 @@ var MessageBubble = ({ message, isFromUser, currentUser }) => {
|
|
|
2259
2498
|
className: `flex gap-3 ${isFromUser ? "justify-end" : "justify-start"}
|
|
2260
2499
|
animate-in fade-in slide-in-from-bottom-2 duration-300`,
|
|
2261
2500
|
children: [
|
|
2262
|
-
!isFromUser && /* @__PURE__ */ jsx(Avatar, { className: "h-8 w-8 shrink-0", children: sender?.avatar ? /* @__PURE__ */ jsx(AvatarImage, { src: sender.avatar, alt: sender.display_username ||
|
|
2501
|
+
!isFromUser && /* @__PURE__ */ jsx(Avatar, { className: "h-8 w-8 shrink-0", children: sender?.avatar ? /* @__PURE__ */ jsx(AvatarImage, { src: sender.avatar, alt: sender.display_username || labels.supportTeam }) : /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary text-primary-foreground", children: sender?.is_staff ? /* @__PURE__ */ jsx(Headphones, { className: "h-4 w-4" }) : senderInitial }) }),
|
|
2263
2502
|
/* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-1 flex-1 max-w-[80%] ${isFromUser ? "items-end" : "items-start"}`, children: [
|
|
2264
2503
|
!isFromUser && sender && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground px-1", children: [
|
|
2265
|
-
sender.display_username || sender.email ||
|
|
2266
|
-
sender.is_staff &&
|
|
2504
|
+
sender.display_username || sender.email || labels.supportTeam,
|
|
2505
|
+
sender.is_staff && ` (${labels.staff})`
|
|
2267
2506
|
] }),
|
|
2268
2507
|
/* @__PURE__ */ jsx(
|
|
2269
2508
|
Card,
|
|
@@ -2280,8 +2519,20 @@ var MessageBubble = ({ message, isFromUser, currentUser }) => {
|
|
|
2280
2519
|
);
|
|
2281
2520
|
};
|
|
2282
2521
|
var MessageList = () => {
|
|
2522
|
+
const baseT = useT();
|
|
2523
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2283
2524
|
const { selectedTicket } = useSupportLayoutContext();
|
|
2284
2525
|
const { user } = useAuth();
|
|
2526
|
+
const labels = useMemo(() => ({
|
|
2527
|
+
noTicketSelected: st("messageList.noTicketSelected"),
|
|
2528
|
+
noTicketSelectedDescription: st("messageList.noTicketSelectedDescription"),
|
|
2529
|
+
noMessages: st("messageList.noMessages"),
|
|
2530
|
+
noMessagesDescription: st("messageList.noMessagesDescription"),
|
|
2531
|
+
loadingOlder: st("messageList.loadingOlder"),
|
|
2532
|
+
loadOlder: st("messageList.loadOlder"),
|
|
2533
|
+
supportTeam: st("messageList.supportTeam"),
|
|
2534
|
+
staff: st("messageList.staff")
|
|
2535
|
+
}), [st]);
|
|
2285
2536
|
const {
|
|
2286
2537
|
messages,
|
|
2287
2538
|
isLoading,
|
|
@@ -2339,8 +2590,8 @@ var MessageList = () => {
|
|
|
2339
2590
|
if (!selectedTicket) {
|
|
2340
2591
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-full p-8 text-center animate-in fade-in zoom-in-95 duration-300", children: [
|
|
2341
2592
|
/* @__PURE__ */ jsx(MessageSquare, { className: "h-16 w-16 text-muted-foreground mb-4 animate-bounce" }),
|
|
2342
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children:
|
|
2343
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children:
|
|
2593
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: labels.noTicketSelected }),
|
|
2594
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children: labels.noTicketSelectedDescription })
|
|
2344
2595
|
] });
|
|
2345
2596
|
}
|
|
2346
2597
|
if (isLoading) {
|
|
@@ -2360,15 +2611,15 @@ var MessageList = () => {
|
|
|
2360
2611
|
if (!messages || messages.length === 0) {
|
|
2361
2612
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-full p-8 text-center animate-in fade-in zoom-in-95 duration-300", children: [
|
|
2362
2613
|
/* @__PURE__ */ jsx(MessageSquare, { className: "h-16 w-16 text-muted-foreground mb-4 animate-bounce" }),
|
|
2363
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children:
|
|
2364
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children:
|
|
2614
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: labels.noMessages }),
|
|
2615
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children: labels.noMessagesDescription })
|
|
2365
2616
|
] });
|
|
2366
2617
|
}
|
|
2367
2618
|
return /* @__PURE__ */ jsx(ScrollArea, { className: "h-full bg-muted/50", viewportRef: scrollAreaRef, children: /* @__PURE__ */ jsxs("div", { className: "p-6 space-y-4", ref: scrollRef, children: [
|
|
2368
2619
|
/* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "h-2" }),
|
|
2369
2620
|
isLoadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
2370
2621
|
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
2371
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm", children:
|
|
2622
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: labels.loadingOlder })
|
|
2372
2623
|
] }) }),
|
|
2373
2624
|
hasMore && !isLoadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxs(
|
|
2374
2625
|
Button,
|
|
@@ -2378,7 +2629,8 @@ var MessageList = () => {
|
|
|
2378
2629
|
onClick: handleLoadMore,
|
|
2379
2630
|
className: "text-xs",
|
|
2380
2631
|
children: [
|
|
2381
|
-
|
|
2632
|
+
labels.loadOlder,
|
|
2633
|
+
" (",
|
|
2382
2634
|
totalCount > 0 ? `${messages.length}/${totalCount}` : "",
|
|
2383
2635
|
")"
|
|
2384
2636
|
]
|
|
@@ -2393,7 +2645,7 @@ var MessageList = () => {
|
|
|
2393
2645
|
const isFromUser = message.sender?.id && user?.id && String(message.sender.id) === String(user.id) || message.sender?.email && user?.email && message.sender.email === user.email || message.is_from_author && selectedTicket?.user && user?.id && String(selectedTicket.user) === String(user.id);
|
|
2394
2646
|
const previousMessage = index > 0 ? messages[index - 1] : null;
|
|
2395
2647
|
const showDateSeparator = previousMessage && moment2.utc(previousMessage.created_at || "").format("YYYY-MM-DD") !== moment2.utc(message.created_at || "").format("YYYY-MM-DD");
|
|
2396
|
-
return /* @__PURE__ */ jsxs(
|
|
2648
|
+
return /* @__PURE__ */ jsxs(React8.Fragment, { children: [
|
|
2397
2649
|
showDateSeparator && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 my-4", children: [
|
|
2398
2650
|
/* @__PURE__ */ jsx("div", { className: "flex-1 h-px bg-border" }),
|
|
2399
2651
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: formatDate(message.created_at) }),
|
|
@@ -2404,7 +2656,8 @@ var MessageList = () => {
|
|
|
2404
2656
|
{
|
|
2405
2657
|
message,
|
|
2406
2658
|
isFromUser: !!isFromUser,
|
|
2407
|
-
currentUser: user
|
|
2659
|
+
currentUser: user,
|
|
2660
|
+
labels: { supportTeam: labels.supportTeam, staff: labels.staff }
|
|
2408
2661
|
}
|
|
2409
2662
|
) })
|
|
2410
2663
|
] }, message.uuid);
|
|
@@ -2418,10 +2671,19 @@ var logger = createConsola({
|
|
|
2418
2671
|
}).withTag("ext-support");
|
|
2419
2672
|
var supportLogger = logger;
|
|
2420
2673
|
var MessageInput = () => {
|
|
2674
|
+
const baseT = useT();
|
|
2675
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2421
2676
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2422
2677
|
const { toast } = useToast();
|
|
2423
2678
|
const [message, setMessage] = useState("");
|
|
2424
2679
|
const [isSending, setIsSending] = useState(false);
|
|
2680
|
+
const labels = useMemo(() => ({
|
|
2681
|
+
placeholder: st("messageInput.placeholder"),
|
|
2682
|
+
ticketClosed: st("messageInput.ticketClosed"),
|
|
2683
|
+
ticketClosedDescription: st("messageInput.ticketClosedDescription"),
|
|
2684
|
+
messageSent: st("messages.messageSent"),
|
|
2685
|
+
messageSendFailed: st("messages.messageSendFailed")
|
|
2686
|
+
}), [st]);
|
|
2425
2687
|
const handleSubmit = async (e) => {
|
|
2426
2688
|
e.preventDefault();
|
|
2427
2689
|
if (!message.trim() || !selectedTicket) return;
|
|
@@ -2429,10 +2691,10 @@ var MessageInput = () => {
|
|
|
2429
2691
|
try {
|
|
2430
2692
|
await sendMessage(message.trim());
|
|
2431
2693
|
setMessage("");
|
|
2432
|
-
toast.success(
|
|
2694
|
+
toast.success(labels.messageSent);
|
|
2433
2695
|
} catch (error) {
|
|
2434
2696
|
supportLogger.error("Failed to send message:", error);
|
|
2435
|
-
toast.error(
|
|
2697
|
+
toast.error(labels.messageSendFailed);
|
|
2436
2698
|
} finally {
|
|
2437
2699
|
setIsSending(false);
|
|
2438
2700
|
}
|
|
@@ -2455,8 +2717,8 @@ var MessageInput = () => {
|
|
|
2455
2717
|
value: message,
|
|
2456
2718
|
onChange: (e) => setMessage(e.target.value),
|
|
2457
2719
|
onKeyDown: handleKeyDown,
|
|
2458
|
-
placeholder: canSendMessage ?
|
|
2459
|
-
className: "min-h-[60px] max-h-[200px] transition-all duration-200
|
|
2720
|
+
placeholder: canSendMessage ? labels.placeholder : labels.ticketClosed,
|
|
2721
|
+
className: "min-h-[60px] max-h-[200px] transition-all duration-200\n focus:ring-2 focus:ring-primary/20",
|
|
2460
2722
|
disabled: !canSendMessage || isSending
|
|
2461
2723
|
}
|
|
2462
2724
|
),
|
|
@@ -2471,17 +2733,38 @@ var MessageInput = () => {
|
|
|
2471
2733
|
}
|
|
2472
2734
|
)
|
|
2473
2735
|
] }),
|
|
2474
|
-
!canSendMessage && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-2 animate-in fade-in slide-in-from-top-1 duration-200", children:
|
|
2736
|
+
!canSendMessage && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-2 animate-in fade-in slide-in-from-top-1 duration-200", children: labels.ticketClosedDescription })
|
|
2475
2737
|
] });
|
|
2476
2738
|
};
|
|
2477
|
-
var createTicketSchema = z.object({
|
|
2478
|
-
subject: z.string().min(1, "Subject is required").max(200, "Subject too long"),
|
|
2479
|
-
message: z.string().min(1, "Message is required").max(5e3, "Message too long")
|
|
2480
|
-
});
|
|
2481
2739
|
var CreateTicketDialog = () => {
|
|
2740
|
+
const baseT = useT();
|
|
2741
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2482
2742
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2483
2743
|
const { toast } = useToast$1();
|
|
2484
|
-
const [isSubmitting, setIsSubmitting] =
|
|
2744
|
+
const [isSubmitting, setIsSubmitting] = React8.useState(false);
|
|
2745
|
+
const labels = useMemo(() => ({
|
|
2746
|
+
title: st("createTicket.title"),
|
|
2747
|
+
description: st("createTicket.description"),
|
|
2748
|
+
subjectLabel: st("createTicket.subjectLabel"),
|
|
2749
|
+
subjectPlaceholder: st("createTicket.subjectPlaceholder"),
|
|
2750
|
+
messageLabel: st("createTicket.messageLabel"),
|
|
2751
|
+
messagePlaceholder: st("createTicket.messagePlaceholder"),
|
|
2752
|
+
cancel: st("createTicket.cancel"),
|
|
2753
|
+
creating: st("createTicket.creating"),
|
|
2754
|
+
create: st("createTicket.create"),
|
|
2755
|
+
ticketCreated: st("messages.ticketCreated"),
|
|
2756
|
+
ticketCreateFailed: st("messages.ticketCreateFailed"),
|
|
2757
|
+
validation: {
|
|
2758
|
+
subjectRequired: st("validation.subjectRequired"),
|
|
2759
|
+
subjectTooLong: st("validation.subjectTooLong"),
|
|
2760
|
+
messageRequired: st("validation.messageRequired"),
|
|
2761
|
+
messageTooLong: st("validation.messageTooLong")
|
|
2762
|
+
}
|
|
2763
|
+
}), [st]);
|
|
2764
|
+
const createTicketSchema = useMemo(() => z.object({
|
|
2765
|
+
subject: z.string().min(1, labels.validation.subjectRequired).max(200, labels.validation.subjectTooLong),
|
|
2766
|
+
message: z.string().min(1, labels.validation.messageRequired).max(5e3, labels.validation.messageTooLong)
|
|
2767
|
+
}), [labels.validation]);
|
|
2485
2768
|
const form = useForm({
|
|
2486
2769
|
resolver: zodResolver(createTicketSchema),
|
|
2487
2770
|
defaultValues: {
|
|
@@ -2494,10 +2777,10 @@ var CreateTicketDialog = () => {
|
|
|
2494
2777
|
try {
|
|
2495
2778
|
await createTicket(data);
|
|
2496
2779
|
form.reset();
|
|
2497
|
-
toast.success(
|
|
2780
|
+
toast.success(labels.ticketCreated);
|
|
2498
2781
|
} catch (error) {
|
|
2499
2782
|
supportLogger.error("Failed to create ticket:", error);
|
|
2500
|
-
toast.error(
|
|
2783
|
+
toast.error(labels.ticketCreateFailed);
|
|
2501
2784
|
} finally {
|
|
2502
2785
|
setIsSubmitting(false);
|
|
2503
2786
|
}
|
|
@@ -2510,9 +2793,9 @@ var CreateTicketDialog = () => {
|
|
|
2510
2793
|
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2511
2794
|
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
2512
2795
|
/* @__PURE__ */ jsx(Plus, { className: "h-5 w-5" }),
|
|
2513
|
-
|
|
2796
|
+
labels.title
|
|
2514
2797
|
] }),
|
|
2515
|
-
/* @__PURE__ */ jsx(DialogDescription, { children:
|
|
2798
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: labels.description })
|
|
2516
2799
|
] }),
|
|
2517
2800
|
/* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-6", children: [
|
|
2518
2801
|
/* @__PURE__ */ jsx(
|
|
@@ -2521,8 +2804,8 @@ var CreateTicketDialog = () => {
|
|
|
2521
2804
|
control: form.control,
|
|
2522
2805
|
name: "subject",
|
|
2523
2806
|
render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
|
|
2524
|
-
/* @__PURE__ */ jsx(FormLabel, { children:
|
|
2525
|
-
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(Input, { placeholder:
|
|
2807
|
+
/* @__PURE__ */ jsx(FormLabel, { children: labels.subjectLabel }),
|
|
2808
|
+
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(Input, { placeholder: labels.subjectPlaceholder, ...field }) }),
|
|
2526
2809
|
/* @__PURE__ */ jsx(FormMessage, {})
|
|
2527
2810
|
] })
|
|
2528
2811
|
}
|
|
@@ -2533,11 +2816,11 @@ var CreateTicketDialog = () => {
|
|
|
2533
2816
|
control: form.control,
|
|
2534
2817
|
name: "message",
|
|
2535
2818
|
render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
|
|
2536
|
-
/* @__PURE__ */ jsx(FormLabel, { children:
|
|
2819
|
+
/* @__PURE__ */ jsx(FormLabel, { children: labels.messageLabel }),
|
|
2537
2820
|
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
|
|
2538
2821
|
Textarea,
|
|
2539
2822
|
{
|
|
2540
|
-
placeholder:
|
|
2823
|
+
placeholder: labels.messagePlaceholder,
|
|
2541
2824
|
className: "min-h-[120px]",
|
|
2542
2825
|
...field
|
|
2543
2826
|
}
|
|
@@ -2554,24 +2837,32 @@ var CreateTicketDialog = () => {
|
|
|
2554
2837
|
variant: "outline",
|
|
2555
2838
|
onClick: handleClose,
|
|
2556
2839
|
disabled: isSubmitting,
|
|
2557
|
-
children:
|
|
2840
|
+
children: labels.cancel
|
|
2558
2841
|
}
|
|
2559
2842
|
),
|
|
2560
2843
|
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting, children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2561
2844
|
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
|
|
2562
|
-
|
|
2845
|
+
labels.creating
|
|
2563
2846
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2564
2847
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
2565
|
-
|
|
2848
|
+
labels.create
|
|
2566
2849
|
] }) })
|
|
2567
2850
|
] })
|
|
2568
2851
|
] }) })
|
|
2569
2852
|
] }) });
|
|
2570
2853
|
};
|
|
2571
2854
|
var SupportLayoutContent = () => {
|
|
2855
|
+
const baseT = useT();
|
|
2856
|
+
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2572
2857
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } = useSupportLayoutContext();
|
|
2573
|
-
const [isMobile, setIsMobile] =
|
|
2574
|
-
|
|
2858
|
+
const [isMobile, setIsMobile] = React8.useState(false);
|
|
2859
|
+
const labels = useMemo(() => ({
|
|
2860
|
+
title: st("layout.title"),
|
|
2861
|
+
titleShort: st("layout.titleShort"),
|
|
2862
|
+
subtitle: st("layout.subtitle"),
|
|
2863
|
+
newTicket: st("layout.newTicket")
|
|
2864
|
+
}), [st]);
|
|
2865
|
+
React8.useEffect(() => {
|
|
2575
2866
|
const checkMobile = () => setIsMobile(window.innerWidth <= 768);
|
|
2576
2867
|
checkMobile();
|
|
2577
2868
|
window.addEventListener("resize", checkMobile);
|
|
@@ -2592,12 +2883,12 @@ var SupportLayoutContent = () => {
|
|
|
2592
2883
|
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-5 w-5" })
|
|
2593
2884
|
}
|
|
2594
2885
|
) : /* @__PURE__ */ jsx(LifeBuoy, { className: "h-6 w-6 text-primary" }),
|
|
2595
|
-
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: selectedTicket ? selectedTicket.subject :
|
|
2886
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: selectedTicket ? selectedTicket.subject : labels.titleShort }),
|
|
2596
2887
|
unreadCount > 0 && !selectedTicket && /* @__PURE__ */ jsx("div", { className: "h-5 w-5 bg-red-500 text-white text-xs rounded-full flex items-center justify-center", children: unreadCount })
|
|
2597
2888
|
] }),
|
|
2598
2889
|
!selectedTicket && /* @__PURE__ */ jsxs(Button, { onClick: openCreateDialog, size: "sm", children: [
|
|
2599
2890
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
2600
|
-
|
|
2891
|
+
labels.newTicket
|
|
2601
2892
|
] })
|
|
2602
2893
|
] }),
|
|
2603
2894
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: selectedTicket ? (
|
|
@@ -2618,14 +2909,14 @@ var SupportLayoutContent = () => {
|
|
|
2618
2909
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2619
2910
|
/* @__PURE__ */ jsx(LifeBuoy, { className: "h-7 w-7 text-primary" }),
|
|
2620
2911
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
2621
|
-
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children:
|
|
2622
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2912
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children: labels.title }),
|
|
2913
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.subtitle })
|
|
2623
2914
|
] }),
|
|
2624
2915
|
unreadCount > 0 && /* @__PURE__ */ jsx("div", { className: "h-6 w-6 bg-red-500 text-white text-sm rounded-full flex items-center justify-center", children: unreadCount })
|
|
2625
2916
|
] }),
|
|
2626
2917
|
/* @__PURE__ */ jsxs(Button, { onClick: openCreateDialog, children: [
|
|
2627
2918
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
2628
|
-
|
|
2919
|
+
labels.newTicket
|
|
2629
2920
|
] })
|
|
2630
2921
|
] }),
|
|
2631
2922
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxs(ResizablePanelGroup, { direction: "horizontal", className: "h-full", children: [
|
|
@@ -2646,7 +2937,7 @@ var SupportLayout = () => {
|
|
|
2646
2937
|
// package.json
|
|
2647
2938
|
var package_default = {
|
|
2648
2939
|
name: "@djangocfg/ext-support",
|
|
2649
|
-
version: "1.0.
|
|
2940
|
+
version: "1.0.22",
|
|
2650
2941
|
description: "Support ticket system extension for DjangoCFG",
|
|
2651
2942
|
keywords: [
|
|
2652
2943
|
"django",
|
|
@@ -2692,6 +2983,11 @@ var package_default = {
|
|
|
2692
2983
|
types: "./dist/config.d.ts",
|
|
2693
2984
|
import: "./dist/config.js",
|
|
2694
2985
|
require: "./dist/config.cjs"
|
|
2986
|
+
},
|
|
2987
|
+
"./i18n": {
|
|
2988
|
+
types: "./dist/i18n.d.ts",
|
|
2989
|
+
import: "./dist/i18n.js",
|
|
2990
|
+
require: "./dist/i18n.cjs"
|
|
2695
2991
|
}
|
|
2696
2992
|
},
|
|
2697
2993
|
files: [
|
|
@@ -2707,6 +3003,7 @@ var package_default = {
|
|
|
2707
3003
|
peerDependencies: {
|
|
2708
3004
|
"@djangocfg/api": "workspace:*",
|
|
2709
3005
|
"@djangocfg/ext-base": "workspace:*",
|
|
3006
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2710
3007
|
"@djangocfg/ui-core": "workspace:*",
|
|
2711
3008
|
consola: "^3.4.2",
|
|
2712
3009
|
"lucide-react": "^0.545.0",
|
|
@@ -2722,6 +3019,7 @@ var package_default = {
|
|
|
2722
3019
|
devDependencies: {
|
|
2723
3020
|
"@djangocfg/api": "workspace:*",
|
|
2724
3021
|
"@djangocfg/ext-base": "workspace:*",
|
|
3022
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2725
3023
|
"@djangocfg/ui-core": "workspace:*",
|
|
2726
3024
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2727
3025
|
"@types/node": "^24.7.2",
|