@djangocfg/ext-support 1.0.8 → 1.0.10
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 +2 -2
- package/dist/config.js +2 -2
- package/dist/hooks.cjs +91 -62
- package/dist/hooks.js +49 -20
- package/dist/index.cjs +91 -62
- package/dist/index.d.cts +35 -12
- package/dist/index.d.ts +35 -12
- package/dist/index.js +49 -20
- package/package.json +6 -6
- package/src/api/generated/ext_support/CLAUDE.md +1 -8
- package/src/api/generated/ext_support/api-instance.ts +61 -13
- package/src/api/generated/ext_support/client.ts +23 -2
- package/src/api/generated/ext_support/http.ts +8 -2
- package/src/api/generated/ext_support/index.ts +3 -1
- package/src/api/index.ts +6 -1
- package/src/contexts/SupportContext.tsx +3 -0
- package/src/layouts/SupportLayout/SupportLayout.tsx +1 -1
- package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +3 -10
- package/src/layouts/SupportLayout/components/MessageInput.tsx +2 -1
- package/src/layouts/SupportLayout/components/MessageList.tsx +1 -1
- package/src/layouts/SupportLayout/components/TicketCard.tsx +1 -1
- package/src/layouts/SupportLayout/components/TicketList.tsx +1 -1
package/dist/config.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var import_ext_base = require("@djangocfg/ext-base");
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@djangocfg/ext-support",
|
|
30
|
-
version: "1.0.
|
|
30
|
+
version: "1.0.10",
|
|
31
31
|
description: "Support ticket system extension for DjangoCFG",
|
|
32
32
|
keywords: [
|
|
33
33
|
"django",
|
|
@@ -89,7 +89,6 @@ var package_default = {
|
|
|
89
89
|
"@djangocfg/api": "workspace:*",
|
|
90
90
|
"@djangocfg/ext-base": "workspace:*",
|
|
91
91
|
"@djangocfg/ui-core": "workspace:*",
|
|
92
|
-
"@djangocfg/ui-nextjs": "workspace:*",
|
|
93
92
|
consola: "^3.4.2",
|
|
94
93
|
"lucide-react": "^0.545.0",
|
|
95
94
|
moment: "^2.30.1",
|
|
@@ -103,6 +102,7 @@ var package_default = {
|
|
|
103
102
|
devDependencies: {
|
|
104
103
|
"@djangocfg/api": "workspace:*",
|
|
105
104
|
"@djangocfg/ext-base": "workspace:*",
|
|
105
|
+
"@djangocfg/ui-core": "workspace:*",
|
|
106
106
|
"@djangocfg/typescript-config": "workspace:*",
|
|
107
107
|
"@types/node": "^24.7.2",
|
|
108
108
|
"@types/react": "^19.0.0",
|
package/dist/config.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createExtensionConfig } from "@djangocfg/ext-base";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@djangocfg/ext-support",
|
|
7
|
-
version: "1.0.
|
|
7
|
+
version: "1.0.10",
|
|
8
8
|
description: "Support ticket system extension for DjangoCFG",
|
|
9
9
|
keywords: [
|
|
10
10
|
"django",
|
|
@@ -66,7 +66,6 @@ var package_default = {
|
|
|
66
66
|
"@djangocfg/api": "workspace:*",
|
|
67
67
|
"@djangocfg/ext-base": "workspace:*",
|
|
68
68
|
"@djangocfg/ui-core": "workspace:*",
|
|
69
|
-
"@djangocfg/ui-nextjs": "workspace:*",
|
|
70
69
|
consola: "^3.4.2",
|
|
71
70
|
"lucide-react": "^0.545.0",
|
|
72
71
|
moment: "^2.30.1",
|
|
@@ -80,6 +79,7 @@ var package_default = {
|
|
|
80
79
|
devDependencies: {
|
|
81
80
|
"@djangocfg/api": "workspace:*",
|
|
82
81
|
"@djangocfg/ext-base": "workspace:*",
|
|
82
|
+
"@djangocfg/ui-core": "workspace:*",
|
|
83
83
|
"@djangocfg/typescript-config": "workspace:*",
|
|
84
84
|
"@types/node": "^24.7.2",
|
|
85
85
|
"@types/react": "^19.0.0",
|
package/dist/hooks.cjs
CHANGED
|
@@ -6,13 +6,14 @@ var zod = require('zod');
|
|
|
6
6
|
var api = require('@djangocfg/ext-base/api');
|
|
7
7
|
var lucideReact = require('lucide-react');
|
|
8
8
|
var React7 = require('react');
|
|
9
|
-
var
|
|
9
|
+
var uiCore = require('@djangocfg/ui-core');
|
|
10
10
|
var useSWR = require('swr');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
12
|
var moment2 = require('moment');
|
|
13
13
|
var lib = require('@djangocfg/ui-core/lib');
|
|
14
14
|
var auth = require('@djangocfg/api/auth');
|
|
15
15
|
var useSWRInfinite = require('swr/infinite');
|
|
16
|
+
var hooks = require('@djangocfg/ui-core/hooks');
|
|
16
17
|
var reactHookForm = require('react-hook-form');
|
|
17
18
|
var zod$1 = require('@hookform/resolvers/zod');
|
|
18
19
|
var extBase = require('@djangocfg/ext-base');
|
|
@@ -162,7 +163,7 @@ var models_exports = {};
|
|
|
162
163
|
// src/api/generated/ext_support/http.ts
|
|
163
164
|
var FetchAdapter = class {
|
|
164
165
|
async request(request) {
|
|
165
|
-
const { method, url, headers, body, params, formData } = request;
|
|
166
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
166
167
|
let finalUrl = url;
|
|
167
168
|
if (params) {
|
|
168
169
|
const searchParams = new URLSearchParams();
|
|
@@ -180,6 +181,9 @@ var FetchAdapter = class {
|
|
|
180
181
|
let requestBody;
|
|
181
182
|
if (formData) {
|
|
182
183
|
requestBody = formData;
|
|
184
|
+
} else if (binaryBody) {
|
|
185
|
+
finalHeaders["Content-Type"] = "application/octet-stream";
|
|
186
|
+
requestBody = binaryBody;
|
|
183
187
|
} else if (body) {
|
|
184
188
|
finalHeaders["Content-Type"] = "application/json";
|
|
185
189
|
requestBody = JSON.stringify(body);
|
|
@@ -504,11 +508,13 @@ var APIClient = class {
|
|
|
504
508
|
httpClient;
|
|
505
509
|
logger = null;
|
|
506
510
|
retryConfig = null;
|
|
511
|
+
tokenGetter = null;
|
|
507
512
|
// Sub-clients
|
|
508
513
|
ext_support_support;
|
|
509
514
|
constructor(baseUrl, options) {
|
|
510
515
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
511
516
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
517
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
512
518
|
if (options?.loggerConfig !== void 0) {
|
|
513
519
|
this.logger = new APILogger(options.loggerConfig);
|
|
514
520
|
}
|
|
@@ -531,6 +537,19 @@ var APIClient = class {
|
|
|
531
537
|
}
|
|
532
538
|
return null;
|
|
533
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Get the base URL for building streaming/download URLs.
|
|
542
|
+
*/
|
|
543
|
+
getBaseUrl() {
|
|
544
|
+
return this.baseUrl;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
548
|
+
* Returns null if no token getter is configured or no token is available.
|
|
549
|
+
*/
|
|
550
|
+
getToken() {
|
|
551
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
552
|
+
}
|
|
534
553
|
/**
|
|
535
554
|
* Make HTTP request with Django CSRF and session handling.
|
|
536
555
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -561,7 +580,7 @@ var APIClient = class {
|
|
|
561
580
|
const headers = {
|
|
562
581
|
...options?.headers || {}
|
|
563
582
|
};
|
|
564
|
-
if (!options?.formData && !headers["Content-Type"]) {
|
|
583
|
+
if (!options?.formData && !options?.binaryBody && !headers["Content-Type"]) {
|
|
565
584
|
headers["Content-Type"] = "application/json";
|
|
566
585
|
}
|
|
567
586
|
if (this.logger) {
|
|
@@ -580,7 +599,8 @@ var APIClient = class {
|
|
|
580
599
|
headers,
|
|
581
600
|
params: options?.params,
|
|
582
601
|
body: options?.body,
|
|
583
|
-
formData: options?.formData
|
|
602
|
+
formData: options?.formData,
|
|
603
|
+
binaryBody: options?.binaryBody
|
|
584
604
|
});
|
|
585
605
|
const duration = Date.now() - startTime;
|
|
586
606
|
if (response.status >= 400) {
|
|
@@ -994,15 +1014,28 @@ __export(fetchers_exports, {
|
|
|
994
1014
|
|
|
995
1015
|
// src/api/generated/ext_support/api-instance.ts
|
|
996
1016
|
var globalAPI = null;
|
|
1017
|
+
var autoConfigAttempted = false;
|
|
1018
|
+
function tryAutoConfigureFromEnv() {
|
|
1019
|
+
if (autoConfigAttempted) return;
|
|
1020
|
+
autoConfigAttempted = true;
|
|
1021
|
+
if (globalAPI) return;
|
|
1022
|
+
if (typeof process === "undefined" || !process.env) return;
|
|
1023
|
+
const baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.VITE_API_URL || process.env.REACT_APP_API_URL || process.env.API_URL;
|
|
1024
|
+
if (baseUrl) {
|
|
1025
|
+
globalAPI = new API(baseUrl);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
997
1028
|
function getAPIInstance() {
|
|
1029
|
+
tryAutoConfigureFromEnv();
|
|
998
1030
|
if (!globalAPI) {
|
|
999
1031
|
throw new Error(
|
|
1000
|
-
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
1032
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })\n\nOr set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
1001
1033
|
);
|
|
1002
1034
|
}
|
|
1003
1035
|
return globalAPI;
|
|
1004
1036
|
}
|
|
1005
1037
|
function isAPIConfigured() {
|
|
1038
|
+
tryAutoConfigureFromEnv();
|
|
1006
1039
|
return globalAPI !== null;
|
|
1007
1040
|
}
|
|
1008
1041
|
function configureAPI(config) {
|
|
@@ -1485,7 +1518,8 @@ var API = class {
|
|
|
1485
1518
|
this._loadTokensFromStorage();
|
|
1486
1519
|
this._client = new APIClient(this.baseUrl, {
|
|
1487
1520
|
retryConfig: this.options?.retryConfig,
|
|
1488
|
-
loggerConfig: this.options?.loggerConfig
|
|
1521
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1522
|
+
tokenGetter: () => this.getToken()
|
|
1489
1523
|
});
|
|
1490
1524
|
this._injectAuthHeader();
|
|
1491
1525
|
this.ext_support_support = this._client.ext_support_support;
|
|
@@ -1497,7 +1531,8 @@ var API = class {
|
|
|
1497
1531
|
_reinitClients() {
|
|
1498
1532
|
this._client = new APIClient(this.baseUrl, {
|
|
1499
1533
|
retryConfig: this.options?.retryConfig,
|
|
1500
|
-
loggerConfig: this.options?.loggerConfig
|
|
1534
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1535
|
+
tokenGetter: () => this.getToken()
|
|
1501
1536
|
});
|
|
1502
1537
|
this._injectAuthHeader();
|
|
1503
1538
|
this.ext_support_support = this._client.ext_support_support;
|
|
@@ -1588,6 +1623,7 @@ var API = class {
|
|
|
1588
1623
|
return "./schema.json";
|
|
1589
1624
|
}
|
|
1590
1625
|
};
|
|
1626
|
+
api.initializeExtensionAPI(configureAPI);
|
|
1591
1627
|
var apiSupport = api.createExtensionAPI(API);
|
|
1592
1628
|
function useSupportTicketsList(params, client) {
|
|
1593
1629
|
return useSWR__default.default(
|
|
@@ -1816,7 +1852,7 @@ var formatRelativeTime = (date) => {
|
|
|
1816
1852
|
};
|
|
1817
1853
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
1818
1854
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1819
|
-
|
|
1855
|
+
uiCore.Card,
|
|
1820
1856
|
{
|
|
1821
1857
|
className: lib.cn(
|
|
1822
1858
|
"cursor-pointer transition-all duration-200 ease-out",
|
|
@@ -1825,11 +1861,11 @@ var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
|
1825
1861
|
isSelected && "bg-accent border-primary shadow-sm"
|
|
1826
1862
|
),
|
|
1827
1863
|
onClick,
|
|
1828
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1864
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(uiCore.CardContent, { className: "p-4", children: [
|
|
1829
1865
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between mb-2", children: [
|
|
1830
1866
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-sm line-clamp-2 flex-1", children: ticket.subject }),
|
|
1831
1867
|
(ticket.unanswered_messages_count || 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1832
|
-
|
|
1868
|
+
uiCore.Badge,
|
|
1833
1869
|
{
|
|
1834
1870
|
variant: "destructive",
|
|
1835
1871
|
className: "ml-2 shrink-0 animate-pulse",
|
|
@@ -1838,7 +1874,7 @@ var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
|
1838
1874
|
)
|
|
1839
1875
|
] }),
|
|
1840
1876
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1841
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1877
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.Badge, { variant: getStatusBadgeVariant(ticket.status || "open"), className: "text-xs", children: ticket.status || "open" }),
|
|
1842
1878
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1843
1879
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3 w-3" }),
|
|
1844
1880
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: formatRelativeTime(ticket.created_at) })
|
|
@@ -2158,7 +2194,7 @@ var TicketList = () => {
|
|
|
2158
2194
|
}, [hasMore, isLoadingMore, loadMore]);
|
|
2159
2195
|
if (isLoading) {
|
|
2160
2196
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 space-y-2", children: [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2161
|
-
|
|
2197
|
+
uiCore.Skeleton,
|
|
2162
2198
|
{
|
|
2163
2199
|
className: "h-24 w-full animate-pulse",
|
|
2164
2200
|
style: { animationDelay: `${i * 100}ms` }
|
|
@@ -2172,7 +2208,7 @@ var TicketList = () => {
|
|
|
2172
2208
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children: "Create your first support ticket to get help from our team" })
|
|
2173
2209
|
] });
|
|
2174
2210
|
}
|
|
2175
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2211
|
+
return /* @__PURE__ */ jsxRuntime.jsx(uiCore.ScrollArea, { className: "h-full", viewportRef: scrollRef, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-2", children: [
|
|
2176
2212
|
tickets.map((ticket, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2177
2213
|
"div",
|
|
2178
2214
|
{
|
|
@@ -2195,7 +2231,7 @@ var TicketList = () => {
|
|
|
2195
2231
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: "Loading more tickets..." })
|
|
2196
2232
|
] }) }),
|
|
2197
2233
|
hasMore && !isLoadingMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2198
|
-
|
|
2234
|
+
uiCore.Button,
|
|
2199
2235
|
{
|
|
2200
2236
|
variant: "outline",
|
|
2201
2237
|
size: "sm",
|
|
@@ -2233,22 +2269,22 @@ var MessageBubble = ({ message, isFromUser, currentUser }) => {
|
|
|
2233
2269
|
className: `flex gap-3 ${isFromUser ? "justify-end" : "justify-start"}
|
|
2234
2270
|
animate-in fade-in slide-in-from-bottom-2 duration-300`,
|
|
2235
2271
|
children: [
|
|
2236
|
-
!isFromUser && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2272
|
+
!isFromUser && /* @__PURE__ */ jsxRuntime.jsx(uiCore.Avatar, { className: "h-8 w-8 shrink-0", children: sender?.avatar ? /* @__PURE__ */ jsxRuntime.jsx(uiCore.AvatarImage, { src: sender.avatar, alt: sender.display_username || "Support" }) : /* @__PURE__ */ jsxRuntime.jsx(uiCore.AvatarFallback, { className: "bg-primary text-primary-foreground", children: sender?.is_staff ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Headphones, { className: "h-4 w-4" }) : senderInitial }) }),
|
|
2237
2273
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col gap-1 flex-1 max-w-[80%] ${isFromUser ? "items-end" : "items-start"}`, children: [
|
|
2238
2274
|
!isFromUser && sender && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground px-1", children: [
|
|
2239
2275
|
sender.display_username || sender.email || "Support Team",
|
|
2240
2276
|
sender.is_staff && " (Staff)"
|
|
2241
2277
|
] }),
|
|
2242
2278
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2243
|
-
|
|
2279
|
+
uiCore.Card,
|
|
2244
2280
|
{
|
|
2245
2281
|
className: `${isFromUser ? "bg-primary text-primary-foreground" : "bg-muted"} transition-all duration-200 hover:shadow-md`,
|
|
2246
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2282
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-wrap break-words", children: message.text }) })
|
|
2247
2283
|
}
|
|
2248
2284
|
),
|
|
2249
2285
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground px-1", children: formatTime(message.created_at) })
|
|
2250
2286
|
] }),
|
|
2251
|
-
isFromUser && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2287
|
+
isFromUser && /* @__PURE__ */ jsxRuntime.jsx(uiCore.Avatar, { className: "h-8 w-8 shrink-0", children: currentUser?.avatar ? /* @__PURE__ */ jsxRuntime.jsx(uiCore.AvatarImage, { src: currentUser.avatar, alt: currentUser.display_username || currentUser.email || "You" }) : /* @__PURE__ */ jsxRuntime.jsx(uiCore.AvatarFallback, { className: "bg-primary/10 text-primary font-semibold", children: userInitial || /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }) }) })
|
|
2252
2288
|
]
|
|
2253
2289
|
}
|
|
2254
2290
|
);
|
|
@@ -2324,8 +2360,8 @@ var MessageList = () => {
|
|
|
2324
2360
|
className: "flex gap-3 animate-pulse",
|
|
2325
2361
|
style: { animationDelay: `${i * 100}ms` },
|
|
2326
2362
|
children: [
|
|
2327
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2328
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2363
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.Skeleton, { className: "h-8 w-8 rounded-full" }),
|
|
2364
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.Skeleton, { className: "h-16 flex-1 max-w-[70%]" })
|
|
2329
2365
|
]
|
|
2330
2366
|
},
|
|
2331
2367
|
i
|
|
@@ -2338,14 +2374,14 @@ var MessageList = () => {
|
|
|
2338
2374
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground max-w-sm", children: "Start the conversation by sending a message below" })
|
|
2339
2375
|
] });
|
|
2340
2376
|
}
|
|
2341
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2377
|
+
return /* @__PURE__ */ jsxRuntime.jsx(uiCore.ScrollArea, { className: "h-full bg-muted/50", viewportRef: scrollAreaRef, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-4", ref: scrollRef, children: [
|
|
2342
2378
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "h-2" }),
|
|
2343
2379
|
isLoadingMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
2344
2380
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
2345
2381
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: "Loading older messages..." })
|
|
2346
2382
|
] }) }),
|
|
2347
2383
|
hasMore && !isLoadingMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2348
|
-
|
|
2384
|
+
uiCore.Button,
|
|
2349
2385
|
{
|
|
2350
2386
|
variant: "outline",
|
|
2351
2387
|
size: "sm",
|
|
@@ -2393,7 +2429,7 @@ var logger = consola.createConsola({
|
|
|
2393
2429
|
var supportLogger = logger;
|
|
2394
2430
|
var MessageInput = () => {
|
|
2395
2431
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2396
|
-
const { toast } =
|
|
2432
|
+
const { toast } = hooks.useToast();
|
|
2397
2433
|
const [message, setMessage] = React7.useState("");
|
|
2398
2434
|
const [isSending, setIsSending] = React7.useState(false);
|
|
2399
2435
|
const handleSubmit = async (e) => {
|
|
@@ -2424,7 +2460,7 @@ var MessageInput = () => {
|
|
|
2424
2460
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "p-4 border-t bg-background/50 backdrop-blur-sm flex-shrink-0", children: [
|
|
2425
2461
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
2426
2462
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2427
|
-
|
|
2463
|
+
uiCore.Textarea,
|
|
2428
2464
|
{
|
|
2429
2465
|
value: message,
|
|
2430
2466
|
onChange: (e) => setMessage(e.target.value),
|
|
@@ -2435,7 +2471,7 @@ var MessageInput = () => {
|
|
|
2435
2471
|
}
|
|
2436
2472
|
),
|
|
2437
2473
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2438
|
-
|
|
2474
|
+
uiCore.Button,
|
|
2439
2475
|
{
|
|
2440
2476
|
type: "submit",
|
|
2441
2477
|
size: "icon",
|
|
@@ -2454,7 +2490,7 @@ var createTicketSchema = zod.z.object({
|
|
|
2454
2490
|
});
|
|
2455
2491
|
var CreateTicketDialog = () => {
|
|
2456
2492
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2457
|
-
const { toast } =
|
|
2493
|
+
const { toast } = uiCore.useToast();
|
|
2458
2494
|
const [isSubmitting, setIsSubmitting] = React7__default.default.useState(false);
|
|
2459
2495
|
const form = reactHookForm.useForm({
|
|
2460
2496
|
resolver: zod$1.zodResolver(createTicketSchema),
|
|
@@ -2468,17 +2504,10 @@ var CreateTicketDialog = () => {
|
|
|
2468
2504
|
try {
|
|
2469
2505
|
await createTicket(data);
|
|
2470
2506
|
form.reset();
|
|
2471
|
-
toast(
|
|
2472
|
-
title: "Success",
|
|
2473
|
-
description: "Support ticket created successfully"
|
|
2474
|
-
});
|
|
2507
|
+
toast.success("Support ticket created successfully");
|
|
2475
2508
|
} catch (error) {
|
|
2476
2509
|
supportLogger.error("Failed to create ticket:", error);
|
|
2477
|
-
toast(
|
|
2478
|
-
title: "Error",
|
|
2479
|
-
description: "Failed to create ticket. Please try again.",
|
|
2480
|
-
variant: "destructive"
|
|
2481
|
-
});
|
|
2510
|
+
toast.error("Failed to create ticket. Please try again.");
|
|
2482
2511
|
} finally {
|
|
2483
2512
|
setIsSubmitting(false);
|
|
2484
2513
|
}
|
|
@@ -2487,49 +2516,49 @@ var CreateTicketDialog = () => {
|
|
|
2487
2516
|
form.reset();
|
|
2488
2517
|
closeCreateDialog();
|
|
2489
2518
|
};
|
|
2490
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2491
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2492
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2519
|
+
return /* @__PURE__ */ jsxRuntime.jsx(uiCore.Dialog, { open: uiState.isCreateDialogOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiCore.DialogContent, { className: "sm:max-w-[600px] animate-in fade-in slide-in-from-bottom-4 duration-300", children: [
|
|
2520
|
+
/* @__PURE__ */ jsxRuntime.jsxs(uiCore.DialogHeader, { children: [
|
|
2521
|
+
/* @__PURE__ */ jsxRuntime.jsxs(uiCore.DialogTitle, { className: "flex items-center gap-2", children: [
|
|
2493
2522
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-5 w-5" }),
|
|
2494
2523
|
"Create Support Ticket"
|
|
2495
2524
|
] }),
|
|
2496
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2525
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.DialogDescription, { children: "Describe your issue and we'll help you resolve it as quickly as possible." })
|
|
2497
2526
|
] }),
|
|
2498
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2527
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.handleSubmit(onSubmit), className: "space-y-6", children: [
|
|
2499
2528
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2500
|
-
|
|
2529
|
+
uiCore.FormField,
|
|
2501
2530
|
{
|
|
2502
2531
|
control: form.control,
|
|
2503
2532
|
name: "subject",
|
|
2504
|
-
render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2505
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2506
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2507
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2533
|
+
render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiCore.FormItem, { children: [
|
|
2534
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormLabel, { children: "Subject" }),
|
|
2535
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.Input, { placeholder: "Brief description of your issue...", ...field }) }),
|
|
2536
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormMessage, {})
|
|
2508
2537
|
] })
|
|
2509
2538
|
}
|
|
2510
2539
|
),
|
|
2511
2540
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2512
|
-
|
|
2541
|
+
uiCore.FormField,
|
|
2513
2542
|
{
|
|
2514
2543
|
control: form.control,
|
|
2515
2544
|
name: "message",
|
|
2516
|
-
render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2517
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2518
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2519
|
-
|
|
2545
|
+
render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiCore.FormItem, { children: [
|
|
2546
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormLabel, { children: "Message" }),
|
|
2547
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2548
|
+
uiCore.Textarea,
|
|
2520
2549
|
{
|
|
2521
2550
|
placeholder: "Describe your issue in detail. Include any error messages, steps to reproduce, or relevant information...",
|
|
2522
2551
|
className: "min-h-[120px]",
|
|
2523
2552
|
...field
|
|
2524
2553
|
}
|
|
2525
2554
|
) }),
|
|
2526
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2555
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.FormMessage, {})
|
|
2527
2556
|
] })
|
|
2528
2557
|
}
|
|
2529
2558
|
),
|
|
2530
2559
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-3 pt-4", children: [
|
|
2531
2560
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2532
|
-
|
|
2561
|
+
uiCore.Button,
|
|
2533
2562
|
{
|
|
2534
2563
|
type: "button",
|
|
2535
2564
|
variant: "outline",
|
|
@@ -2538,7 +2567,7 @@ var CreateTicketDialog = () => {
|
|
|
2538
2567
|
children: "Cancel"
|
|
2539
2568
|
}
|
|
2540
2569
|
),
|
|
2541
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2570
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.Button, { type: "submit", disabled: isSubmitting, children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2542
2571
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 mr-2 animate-spin" }),
|
|
2543
2572
|
"Creating..."
|
|
2544
2573
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -2564,7 +2593,7 @@ var SupportLayoutContent = () => {
|
|
|
2564
2593
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 border-b bg-background flex-shrink-0", children: [
|
|
2565
2594
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2566
2595
|
selectedTicket ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2567
|
-
|
|
2596
|
+
uiCore.Button,
|
|
2568
2597
|
{
|
|
2569
2598
|
variant: "ghost",
|
|
2570
2599
|
size: "sm",
|
|
@@ -2576,7 +2605,7 @@ var SupportLayoutContent = () => {
|
|
|
2576
2605
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: selectedTicket ? selectedTicket.subject : "Support" }),
|
|
2577
2606
|
unreadCount > 0 && !selectedTicket && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 w-5 bg-red-500 text-white text-xs rounded-full flex items-center justify-center", children: unreadCount })
|
|
2578
2607
|
] }),
|
|
2579
|
-
!selectedTicket && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2608
|
+
!selectedTicket && /* @__PURE__ */ jsxRuntime.jsxs(uiCore.Button, { onClick: openCreateDialog, size: "sm", children: [
|
|
2580
2609
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
|
|
2581
2610
|
"New Ticket"
|
|
2582
2611
|
] })
|
|
@@ -2604,15 +2633,15 @@ var SupportLayoutContent = () => {
|
|
|
2604
2633
|
] }),
|
|
2605
2634
|
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-6 bg-red-500 text-white text-sm rounded-full flex items-center justify-center", children: unreadCount })
|
|
2606
2635
|
] }),
|
|
2607
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2636
|
+
/* @__PURE__ */ jsxRuntime.jsxs(uiCore.Button, { onClick: openCreateDialog, children: [
|
|
2608
2637
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
|
|
2609
2638
|
"New Ticket"
|
|
2610
2639
|
] })
|
|
2611
2640
|
] }),
|
|
2612
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2613
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2614
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2615
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2641
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(uiCore.ResizablePanelGroup, { direction: "horizontal", className: "h-full", children: [
|
|
2642
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.ResizablePanel, { defaultSize: 35, minSize: 25, maxSize: 50, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full border-r overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(TicketList, {}) }) }),
|
|
2643
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.ResizableHandle, { withHandle: true, className: "hover:bg-accent transition-colors" }),
|
|
2644
|
+
/* @__PURE__ */ jsxRuntime.jsx(uiCore.ResizablePanel, { defaultSize: 65, minSize: 50, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col overflow-hidden", children: [
|
|
2616
2645
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(MessageList, {}) }),
|
|
2617
2646
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(MessageInput, {}) })
|
|
2618
2647
|
] }) })
|
|
@@ -2627,7 +2656,7 @@ var SupportLayout = () => {
|
|
|
2627
2656
|
// package.json
|
|
2628
2657
|
var package_default = {
|
|
2629
2658
|
name: "@djangocfg/ext-support",
|
|
2630
|
-
version: "1.0.
|
|
2659
|
+
version: "1.0.10",
|
|
2631
2660
|
description: "Support ticket system extension for DjangoCFG",
|
|
2632
2661
|
keywords: [
|
|
2633
2662
|
"django",
|
|
@@ -2689,7 +2718,6 @@ var package_default = {
|
|
|
2689
2718
|
"@djangocfg/api": "workspace:*",
|
|
2690
2719
|
"@djangocfg/ext-base": "workspace:*",
|
|
2691
2720
|
"@djangocfg/ui-core": "workspace:*",
|
|
2692
|
-
"@djangocfg/ui-nextjs": "workspace:*",
|
|
2693
2721
|
consola: "^3.4.2",
|
|
2694
2722
|
"lucide-react": "^0.545.0",
|
|
2695
2723
|
moment: "^2.30.1",
|
|
@@ -2703,6 +2731,7 @@ var package_default = {
|
|
|
2703
2731
|
devDependencies: {
|
|
2704
2732
|
"@djangocfg/api": "workspace:*",
|
|
2705
2733
|
"@djangocfg/ext-base": "workspace:*",
|
|
2734
|
+
"@djangocfg/ui-core": "workspace:*",
|
|
2706
2735
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2707
2736
|
"@types/node": "^24.7.2",
|
|
2708
2737
|
"@types/react": "^19.0.0",
|