@djangocfg/ext-support 1.0.22 → 1.0.23
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 +4 -2
- package/dist/config.js +4 -2
- package/dist/hooks.cjs +33 -24
- package/dist/hooks.js +33 -24
- package/dist/i18n.cjs +35 -15
- package/dist/i18n.d.cts +27 -14
- package/dist/i18n.d.ts +27 -14
- package/dist/i18n.js +31 -13
- package/dist/index.cjs +33 -24
- package/dist/index.js +33 -24
- package/package.json +13 -11
- package/src/i18n/index.ts +20 -17
- package/src/i18n/types.ts +11 -5
- package/src/i18n/useSupportT.ts +60 -0
- package/src/layouts/SupportLayout/SupportLayout.tsx +2 -5
- package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +2 -5
- package/src/layouts/SupportLayout/components/MessageInput.tsx +2 -5
- package/src/layouts/SupportLayout/components/MessageList.tsx +2 -5
- package/src/layouts/SupportLayout/components/TicketCard.tsx +2 -5
- package/src/layouts/SupportLayout/components/TicketList.tsx +2 -5
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.23",
|
|
31
31
|
description: "Support ticket system extension for DjangoCFG",
|
|
32
32
|
keywords: [
|
|
33
33
|
"django",
|
|
@@ -95,14 +95,15 @@ var package_default = {
|
|
|
95
95
|
"@djangocfg/ext-base": "workspace:*",
|
|
96
96
|
"@djangocfg/i18n": "workspace:*",
|
|
97
97
|
"@djangocfg/ui-core": "workspace:*",
|
|
98
|
+
"@hookform/resolvers": "^5.2.2",
|
|
98
99
|
consola: "^3.4.2",
|
|
99
100
|
"lucide-react": "^0.545.0",
|
|
100
101
|
moment: "^2.30.1",
|
|
101
102
|
next: "^16",
|
|
103
|
+
"next-intl": "^4",
|
|
102
104
|
"p-retry": "^7.0.0",
|
|
103
105
|
react: "^19",
|
|
104
106
|
"react-hook-form": "^7.69.0",
|
|
105
|
-
"@hookform/resolvers": "^5.2.2",
|
|
106
107
|
swr: "^2.3.7",
|
|
107
108
|
zod: "^4.3.4"
|
|
108
109
|
},
|
|
@@ -116,6 +117,7 @@ var package_default = {
|
|
|
116
117
|
"@types/react": "^19.0.0",
|
|
117
118
|
consola: "^3.4.2",
|
|
118
119
|
moment: "^2.30.1",
|
|
120
|
+
"next-intl": "^4.1.0",
|
|
119
121
|
"p-retry": "^7.0.0",
|
|
120
122
|
swr: "^2.3.7",
|
|
121
123
|
tsup: "^8.5.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.23",
|
|
8
8
|
description: "Support ticket system extension for DjangoCFG",
|
|
9
9
|
keywords: [
|
|
10
10
|
"django",
|
|
@@ -72,14 +72,15 @@ var package_default = {
|
|
|
72
72
|
"@djangocfg/ext-base": "workspace:*",
|
|
73
73
|
"@djangocfg/i18n": "workspace:*",
|
|
74
74
|
"@djangocfg/ui-core": "workspace:*",
|
|
75
|
+
"@hookform/resolvers": "^5.2.2",
|
|
75
76
|
consola: "^3.4.2",
|
|
76
77
|
"lucide-react": "^0.545.0",
|
|
77
78
|
moment: "^2.30.1",
|
|
78
79
|
next: "^16",
|
|
80
|
+
"next-intl": "^4",
|
|
79
81
|
"p-retry": "^7.0.0",
|
|
80
82
|
react: "^19",
|
|
81
83
|
"react-hook-form": "^7.69.0",
|
|
82
|
-
"@hookform/resolvers": "^5.2.2",
|
|
83
84
|
swr: "^2.3.7",
|
|
84
85
|
zod: "^4.3.4"
|
|
85
86
|
},
|
|
@@ -93,6 +94,7 @@ var package_default = {
|
|
|
93
94
|
"@types/react": "^19.0.0",
|
|
94
95
|
consola: "^3.4.2",
|
|
95
96
|
moment: "^2.30.1",
|
|
97
|
+
"next-intl": "^4.1.0",
|
|
96
98
|
"p-retry": "^7.0.0",
|
|
97
99
|
swr: "^2.3.7",
|
|
98
100
|
tsup: "^8.5.0",
|
package/dist/hooks.cjs
CHANGED
|
@@ -6,8 +6,7 @@ var zod = require('zod');
|
|
|
6
6
|
var api = require('@djangocfg/ext-base/api');
|
|
7
7
|
var lucideReact = require('lucide-react');
|
|
8
8
|
var React8 = require('react');
|
|
9
|
-
var
|
|
10
|
-
var i18n$1 = require('@djangocfg/i18n');
|
|
9
|
+
var nextIntl = require('next-intl');
|
|
11
10
|
var uiCore = require('@djangocfg/ui-core');
|
|
12
11
|
var useSWR = require('swr');
|
|
13
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -1832,14 +1831,28 @@ var ko = {
|
|
|
1832
1831
|
}
|
|
1833
1832
|
};
|
|
1834
1833
|
|
|
1835
|
-
// src/i18n/
|
|
1836
|
-
var
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1834
|
+
// src/i18n/useSupportT.ts
|
|
1835
|
+
var translations = { en, ru, ko };
|
|
1836
|
+
function getNestedValue(obj, path) {
|
|
1837
|
+
const keys = path.split(".");
|
|
1838
|
+
let result = obj;
|
|
1839
|
+
for (const key of keys) {
|
|
1840
|
+
if (result && typeof result === "object" && key in result) {
|
|
1841
|
+
result = result[key];
|
|
1842
|
+
} else {
|
|
1843
|
+
return path;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return typeof result === "string" ? result : path;
|
|
1847
|
+
}
|
|
1848
|
+
function useSupportT() {
|
|
1849
|
+
const locale = nextIntl.useLocale();
|
|
1850
|
+
const t = React8.useMemo(() => translations[locale] || translations.en, [locale]);
|
|
1851
|
+
return React8.useCallback(
|
|
1852
|
+
(key) => getNestedValue(t, key),
|
|
1853
|
+
[t]
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1843
1856
|
function useSupportTicketsList(params, client) {
|
|
1844
1857
|
return useSWR__default.default(
|
|
1845
1858
|
params ? ["cfg-support-tickets", params] : "cfg-support-tickets",
|
|
@@ -2055,8 +2068,7 @@ var getStatusBadgeVariant = (status) => {
|
|
|
2055
2068
|
}
|
|
2056
2069
|
};
|
|
2057
2070
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
2058
|
-
const
|
|
2059
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2071
|
+
const st = useSupportT();
|
|
2060
2072
|
const labels = React8.useMemo(() => ({
|
|
2061
2073
|
status: {
|
|
2062
2074
|
open: st("status.open"),
|
|
@@ -2382,8 +2394,7 @@ function useSupportLayoutContext() {
|
|
|
2382
2394
|
return context;
|
|
2383
2395
|
}
|
|
2384
2396
|
var TicketList = () => {
|
|
2385
|
-
const
|
|
2386
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2397
|
+
const st = useSupportT();
|
|
2387
2398
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
2388
2399
|
const {
|
|
2389
2400
|
tickets,
|
|
@@ -2529,8 +2540,7 @@ var MessageBubble = ({ message, isFromUser, currentUser, labels }) => {
|
|
|
2529
2540
|
);
|
|
2530
2541
|
};
|
|
2531
2542
|
var MessageList = () => {
|
|
2532
|
-
const
|
|
2533
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2543
|
+
const st = useSupportT();
|
|
2534
2544
|
const { selectedTicket } = useSupportLayoutContext();
|
|
2535
2545
|
const { user } = auth.useAuth();
|
|
2536
2546
|
const labels = React8.useMemo(() => ({
|
|
@@ -2681,8 +2691,7 @@ var logger = consola.createConsola({
|
|
|
2681
2691
|
}).withTag("ext-support");
|
|
2682
2692
|
var supportLogger = logger;
|
|
2683
2693
|
var MessageInput = () => {
|
|
2684
|
-
const
|
|
2685
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2694
|
+
const st = useSupportT();
|
|
2686
2695
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2687
2696
|
const { toast } = hooks.useToast();
|
|
2688
2697
|
const [message, setMessage] = React8.useState("");
|
|
@@ -2747,8 +2756,7 @@ var MessageInput = () => {
|
|
|
2747
2756
|
] });
|
|
2748
2757
|
};
|
|
2749
2758
|
var CreateTicketDialog = () => {
|
|
2750
|
-
const
|
|
2751
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2759
|
+
const st = useSupportT();
|
|
2752
2760
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2753
2761
|
const { toast } = uiCore.useToast();
|
|
2754
2762
|
const [isSubmitting, setIsSubmitting] = React8__default.default.useState(false);
|
|
@@ -2862,8 +2870,7 @@ var CreateTicketDialog = () => {
|
|
|
2862
2870
|
] }) });
|
|
2863
2871
|
};
|
|
2864
2872
|
var SupportLayoutContent = () => {
|
|
2865
|
-
const
|
|
2866
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2873
|
+
const st = useSupportT();
|
|
2867
2874
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } = useSupportLayoutContext();
|
|
2868
2875
|
const [isMobile, setIsMobile] = React8__default.default.useState(false);
|
|
2869
2876
|
const labels = React8.useMemo(() => ({
|
|
@@ -2947,7 +2954,7 @@ var SupportLayout = () => {
|
|
|
2947
2954
|
// package.json
|
|
2948
2955
|
var package_default = {
|
|
2949
2956
|
name: "@djangocfg/ext-support",
|
|
2950
|
-
version: "1.0.
|
|
2957
|
+
version: "1.0.23",
|
|
2951
2958
|
description: "Support ticket system extension for DjangoCFG",
|
|
2952
2959
|
keywords: [
|
|
2953
2960
|
"django",
|
|
@@ -3015,14 +3022,15 @@ var package_default = {
|
|
|
3015
3022
|
"@djangocfg/ext-base": "workspace:*",
|
|
3016
3023
|
"@djangocfg/i18n": "workspace:*",
|
|
3017
3024
|
"@djangocfg/ui-core": "workspace:*",
|
|
3025
|
+
"@hookform/resolvers": "^5.2.2",
|
|
3018
3026
|
consola: "^3.4.2",
|
|
3019
3027
|
"lucide-react": "^0.545.0",
|
|
3020
3028
|
moment: "^2.30.1",
|
|
3021
3029
|
next: "^16",
|
|
3030
|
+
"next-intl": "^4",
|
|
3022
3031
|
"p-retry": "^7.0.0",
|
|
3023
3032
|
react: "^19",
|
|
3024
3033
|
"react-hook-form": "^7.69.0",
|
|
3025
|
-
"@hookform/resolvers": "^5.2.2",
|
|
3026
3034
|
swr: "^2.3.7",
|
|
3027
3035
|
zod: "^4.3.4"
|
|
3028
3036
|
},
|
|
@@ -3036,6 +3044,7 @@ var package_default = {
|
|
|
3036
3044
|
"@types/react": "^19.0.0",
|
|
3037
3045
|
consola: "^3.4.2",
|
|
3038
3046
|
moment: "^2.30.1",
|
|
3047
|
+
"next-intl": "^4.1.0",
|
|
3039
3048
|
"p-retry": "^7.0.0",
|
|
3040
3049
|
swr: "^2.3.7",
|
|
3041
3050
|
tsup: "^8.5.0",
|
package/dist/hooks.js
CHANGED
|
@@ -4,8 +4,7 @@ import { z } from 'zod';
|
|
|
4
4
|
import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
5
|
import { Clock, MessageSquare, Loader2, Send, Plus, Headphones, User, ArrowLeft, LifeBuoy } from 'lucide-react';
|
|
6
6
|
import React8, { createContext, useContext, useMemo, useCallback, useState, useEffect, useRef } from 'react';
|
|
7
|
-
import {
|
|
8
|
-
import { useT } from '@djangocfg/i18n';
|
|
7
|
+
import { useLocale } from 'next-intl';
|
|
9
8
|
import { Card, CardContent, Badge, Skeleton, ScrollArea, Button, Textarea, useToast as useToast$1, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormMessage, Avatar, AvatarImage, AvatarFallback, ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@djangocfg/ui-core';
|
|
10
9
|
import useSWR, { useSWRConfig } from 'swr';
|
|
11
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1822,14 +1821,28 @@ var ko = {
|
|
|
1822
1821
|
}
|
|
1823
1822
|
};
|
|
1824
1823
|
|
|
1825
|
-
// src/i18n/
|
|
1826
|
-
var
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1824
|
+
// src/i18n/useSupportT.ts
|
|
1825
|
+
var translations = { en, ru, ko };
|
|
1826
|
+
function getNestedValue(obj, path) {
|
|
1827
|
+
const keys = path.split(".");
|
|
1828
|
+
let result = obj;
|
|
1829
|
+
for (const key of keys) {
|
|
1830
|
+
if (result && typeof result === "object" && key in result) {
|
|
1831
|
+
result = result[key];
|
|
1832
|
+
} else {
|
|
1833
|
+
return path;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return typeof result === "string" ? result : path;
|
|
1837
|
+
}
|
|
1838
|
+
function useSupportT() {
|
|
1839
|
+
const locale = useLocale();
|
|
1840
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
1841
|
+
return useCallback(
|
|
1842
|
+
(key) => getNestedValue(t, key),
|
|
1843
|
+
[t]
|
|
1844
|
+
);
|
|
1845
|
+
}
|
|
1833
1846
|
function useSupportTicketsList(params, client) {
|
|
1834
1847
|
return useSWR(
|
|
1835
1848
|
params ? ["cfg-support-tickets", params] : "cfg-support-tickets",
|
|
@@ -2045,8 +2058,7 @@ var getStatusBadgeVariant = (status) => {
|
|
|
2045
2058
|
}
|
|
2046
2059
|
};
|
|
2047
2060
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
2048
|
-
const
|
|
2049
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2061
|
+
const st = useSupportT();
|
|
2050
2062
|
const labels = useMemo(() => ({
|
|
2051
2063
|
status: {
|
|
2052
2064
|
open: st("status.open"),
|
|
@@ -2372,8 +2384,7 @@ function useSupportLayoutContext() {
|
|
|
2372
2384
|
return context;
|
|
2373
2385
|
}
|
|
2374
2386
|
var TicketList = () => {
|
|
2375
|
-
const
|
|
2376
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2387
|
+
const st = useSupportT();
|
|
2377
2388
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
2378
2389
|
const {
|
|
2379
2390
|
tickets,
|
|
@@ -2519,8 +2530,7 @@ var MessageBubble = ({ message, isFromUser, currentUser, labels }) => {
|
|
|
2519
2530
|
);
|
|
2520
2531
|
};
|
|
2521
2532
|
var MessageList = () => {
|
|
2522
|
-
const
|
|
2523
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2533
|
+
const st = useSupportT();
|
|
2524
2534
|
const { selectedTicket } = useSupportLayoutContext();
|
|
2525
2535
|
const { user } = useAuth();
|
|
2526
2536
|
const labels = useMemo(() => ({
|
|
@@ -2671,8 +2681,7 @@ var logger = createConsola({
|
|
|
2671
2681
|
}).withTag("ext-support");
|
|
2672
2682
|
var supportLogger = logger;
|
|
2673
2683
|
var MessageInput = () => {
|
|
2674
|
-
const
|
|
2675
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2684
|
+
const st = useSupportT();
|
|
2676
2685
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2677
2686
|
const { toast } = useToast();
|
|
2678
2687
|
const [message, setMessage] = useState("");
|
|
@@ -2737,8 +2746,7 @@ var MessageInput = () => {
|
|
|
2737
2746
|
] });
|
|
2738
2747
|
};
|
|
2739
2748
|
var CreateTicketDialog = () => {
|
|
2740
|
-
const
|
|
2741
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2749
|
+
const st = useSupportT();
|
|
2742
2750
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2743
2751
|
const { toast } = useToast$1();
|
|
2744
2752
|
const [isSubmitting, setIsSubmitting] = React8.useState(false);
|
|
@@ -2852,8 +2860,7 @@ var CreateTicketDialog = () => {
|
|
|
2852
2860
|
] }) });
|
|
2853
2861
|
};
|
|
2854
2862
|
var SupportLayoutContent = () => {
|
|
2855
|
-
const
|
|
2856
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2863
|
+
const st = useSupportT();
|
|
2857
2864
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } = useSupportLayoutContext();
|
|
2858
2865
|
const [isMobile, setIsMobile] = React8.useState(false);
|
|
2859
2866
|
const labels = useMemo(() => ({
|
|
@@ -2937,7 +2944,7 @@ var SupportLayout = () => {
|
|
|
2937
2944
|
// package.json
|
|
2938
2945
|
var package_default = {
|
|
2939
2946
|
name: "@djangocfg/ext-support",
|
|
2940
|
-
version: "1.0.
|
|
2947
|
+
version: "1.0.23",
|
|
2941
2948
|
description: "Support ticket system extension for DjangoCFG",
|
|
2942
2949
|
keywords: [
|
|
2943
2950
|
"django",
|
|
@@ -3005,14 +3012,15 @@ var package_default = {
|
|
|
3005
3012
|
"@djangocfg/ext-base": "workspace:*",
|
|
3006
3013
|
"@djangocfg/i18n": "workspace:*",
|
|
3007
3014
|
"@djangocfg/ui-core": "workspace:*",
|
|
3015
|
+
"@hookform/resolvers": "^5.2.2",
|
|
3008
3016
|
consola: "^3.4.2",
|
|
3009
3017
|
"lucide-react": "^0.545.0",
|
|
3010
3018
|
moment: "^2.30.1",
|
|
3011
3019
|
next: "^16",
|
|
3020
|
+
"next-intl": "^4",
|
|
3012
3021
|
"p-retry": "^7.0.0",
|
|
3013
3022
|
react: "^19",
|
|
3014
3023
|
"react-hook-form": "^7.69.0",
|
|
3015
|
-
"@hookform/resolvers": "^5.2.2",
|
|
3016
3024
|
swr: "^2.3.7",
|
|
3017
3025
|
zod: "^4.3.4"
|
|
3018
3026
|
},
|
|
@@ -3026,6 +3034,7 @@ var package_default = {
|
|
|
3026
3034
|
"@types/react": "^19.0.0",
|
|
3027
3035
|
consola: "^3.4.2",
|
|
3028
3036
|
moment: "^2.30.1",
|
|
3037
|
+
"next-intl": "^4.1.0",
|
|
3029
3038
|
"p-retry": "^7.0.0",
|
|
3030
3039
|
swr: "^2.3.7",
|
|
3031
3040
|
tsup: "^8.5.0",
|
package/dist/i18n.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -19,12 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
20
|
// src/i18n/index.ts
|
|
20
21
|
var i18n_exports = {};
|
|
21
22
|
__export(i18n_exports, {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
en: () => en,
|
|
24
|
+
ko: () => ko,
|
|
25
|
+
ru: () => ru,
|
|
26
|
+
useSupportT: () => useSupportT
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(i18n_exports);
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
// src/i18n/useSupportT.ts
|
|
31
|
+
var import_next_intl = require("next-intl");
|
|
32
|
+
var import_react = require("react");
|
|
28
33
|
|
|
29
34
|
// src/i18n/locales/en.ts
|
|
30
35
|
var en = {
|
|
@@ -230,17 +235,32 @@ var ko = {
|
|
|
230
235
|
}
|
|
231
236
|
};
|
|
232
237
|
|
|
233
|
-
// src/i18n/
|
|
234
|
-
var
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
// src/i18n/useSupportT.ts
|
|
239
|
+
var translations = { en, ru, ko };
|
|
240
|
+
function getNestedValue(obj, path) {
|
|
241
|
+
const keys = path.split(".");
|
|
242
|
+
let result = obj;
|
|
243
|
+
for (const key of keys) {
|
|
244
|
+
if (result && typeof result === "object" && key in result) {
|
|
245
|
+
result = result[key];
|
|
246
|
+
} else {
|
|
247
|
+
return path;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return typeof result === "string" ? result : path;
|
|
251
|
+
}
|
|
252
|
+
function useSupportT() {
|
|
253
|
+
const locale = (0, import_next_intl.useLocale)();
|
|
254
|
+
const t = (0, import_react.useMemo)(() => translations[locale] || translations.en, [locale]);
|
|
255
|
+
return (0, import_react.useCallback)(
|
|
256
|
+
(key) => getNestedValue(t, key),
|
|
257
|
+
[t]
|
|
258
|
+
);
|
|
259
|
+
}
|
|
241
260
|
// Annotate the CommonJS export names for ESM import in node:
|
|
242
261
|
0 && (module.exports = {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
262
|
+
en,
|
|
263
|
+
ko,
|
|
264
|
+
ru,
|
|
265
|
+
useSupportT
|
|
246
266
|
});
|
package/dist/i18n.d.cts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
-
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Support Extension I18n Types
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
4
|
/**
|
|
9
|
-
*
|
|
5
|
+
* Helper type to get dot-notation paths from nested object
|
|
10
6
|
*/
|
|
11
|
-
type
|
|
7
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object ? {
|
|
8
|
+
[K in keyof T]: K extends string ? T[K] extends object ? PathKeys<T[K], `${Prefix}${K}.`> : `${Prefix}${K}` : never;
|
|
9
|
+
}[keyof T] : never;
|
|
12
10
|
/**
|
|
13
|
-
* Keys
|
|
11
|
+
* Keys for support translations
|
|
14
12
|
*/
|
|
15
13
|
type SupportLocalKeys = PathKeys<SupportTranslations>;
|
|
16
14
|
interface SupportTranslations {
|
|
@@ -89,11 +87,26 @@ interface SupportTranslations {
|
|
|
89
87
|
};
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Self-contained translation hook for support extension
|
|
92
|
+
*
|
|
93
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
94
|
+
* No need to add translations to app's i18n config.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* function TicketList() {
|
|
99
|
+
* const t = useSupportT();
|
|
100
|
+
* return <h1>{t('layout.title')}</h1>;
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare function useSupportT(): (key: SupportLocalKeys) => string;
|
|
105
|
+
|
|
106
|
+
declare const en: SupportTranslations;
|
|
107
|
+
|
|
108
|
+
declare const ru: SupportTranslations;
|
|
109
|
+
|
|
110
|
+
declare const ko: SupportTranslations;
|
|
98
111
|
|
|
99
|
-
export {
|
|
112
|
+
export { type SupportLocalKeys, type SupportTranslations, en, ko, ru, useSupportT };
|
package/dist/i18n.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
-
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Support Extension I18n Types
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
4
|
/**
|
|
9
|
-
*
|
|
5
|
+
* Helper type to get dot-notation paths from nested object
|
|
10
6
|
*/
|
|
11
|
-
type
|
|
7
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object ? {
|
|
8
|
+
[K in keyof T]: K extends string ? T[K] extends object ? PathKeys<T[K], `${Prefix}${K}.`> : `${Prefix}${K}` : never;
|
|
9
|
+
}[keyof T] : never;
|
|
12
10
|
/**
|
|
13
|
-
* Keys
|
|
11
|
+
* Keys for support translations
|
|
14
12
|
*/
|
|
15
13
|
type SupportLocalKeys = PathKeys<SupportTranslations>;
|
|
16
14
|
interface SupportTranslations {
|
|
@@ -89,11 +87,26 @@ interface SupportTranslations {
|
|
|
89
87
|
};
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Self-contained translation hook for support extension
|
|
92
|
+
*
|
|
93
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
94
|
+
* No need to add translations to app's i18n config.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* function TicketList() {
|
|
99
|
+
* const t = useSupportT();
|
|
100
|
+
* return <h1>{t('layout.title')}</h1>;
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare function useSupportT(): (key: SupportLocalKeys) => string;
|
|
105
|
+
|
|
106
|
+
declare const en: SupportTranslations;
|
|
107
|
+
|
|
108
|
+
declare const ru: SupportTranslations;
|
|
109
|
+
|
|
110
|
+
declare const ko: SupportTranslations;
|
|
98
111
|
|
|
99
|
-
export {
|
|
112
|
+
export { type SupportLocalKeys, type SupportTranslations, en, ko, ru, useSupportT };
|
package/dist/i18n.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/i18n/useSupportT.ts
|
|
4
|
+
import { useLocale } from "next-intl";
|
|
5
|
+
import { useMemo, useCallback } from "react";
|
|
3
6
|
|
|
4
7
|
// src/i18n/locales/en.ts
|
|
5
8
|
var en = {
|
|
@@ -205,16 +208,31 @@ var ko = {
|
|
|
205
208
|
}
|
|
206
209
|
};
|
|
207
210
|
|
|
208
|
-
// src/i18n/
|
|
209
|
-
var
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
211
|
+
// src/i18n/useSupportT.ts
|
|
212
|
+
var translations = { en, ru, ko };
|
|
213
|
+
function getNestedValue(obj, path) {
|
|
214
|
+
const keys = path.split(".");
|
|
215
|
+
let result = obj;
|
|
216
|
+
for (const key of keys) {
|
|
217
|
+
if (result && typeof result === "object" && key in result) {
|
|
218
|
+
result = result[key];
|
|
219
|
+
} else {
|
|
220
|
+
return path;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return typeof result === "string" ? result : path;
|
|
224
|
+
}
|
|
225
|
+
function useSupportT() {
|
|
226
|
+
const locale = useLocale();
|
|
227
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
228
|
+
return useCallback(
|
|
229
|
+
(key) => getNestedValue(t, key),
|
|
230
|
+
[t]
|
|
231
|
+
);
|
|
232
|
+
}
|
|
216
233
|
export {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
234
|
+
en,
|
|
235
|
+
ko,
|
|
236
|
+
ru,
|
|
237
|
+
useSupportT
|
|
220
238
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -6,8 +6,7 @@ var zod = require('zod');
|
|
|
6
6
|
var api = require('@djangocfg/ext-base/api');
|
|
7
7
|
var lucideReact = require('lucide-react');
|
|
8
8
|
var React8 = require('react');
|
|
9
|
-
var
|
|
10
|
-
var i18n$1 = require('@djangocfg/i18n');
|
|
9
|
+
var nextIntl = require('next-intl');
|
|
11
10
|
var uiCore = require('@djangocfg/ui-core');
|
|
12
11
|
var useSWR = require('swr');
|
|
13
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -1832,14 +1831,28 @@ var ko = {
|
|
|
1832
1831
|
}
|
|
1833
1832
|
};
|
|
1834
1833
|
|
|
1835
|
-
// src/i18n/
|
|
1836
|
-
var
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1834
|
+
// src/i18n/useSupportT.ts
|
|
1835
|
+
var translations = { en, ru, ko };
|
|
1836
|
+
function getNestedValue(obj, path) {
|
|
1837
|
+
const keys = path.split(".");
|
|
1838
|
+
let result = obj;
|
|
1839
|
+
for (const key of keys) {
|
|
1840
|
+
if (result && typeof result === "object" && key in result) {
|
|
1841
|
+
result = result[key];
|
|
1842
|
+
} else {
|
|
1843
|
+
return path;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return typeof result === "string" ? result : path;
|
|
1847
|
+
}
|
|
1848
|
+
function useSupportT() {
|
|
1849
|
+
const locale = nextIntl.useLocale();
|
|
1850
|
+
const t = React8.useMemo(() => translations[locale] || translations.en, [locale]);
|
|
1851
|
+
return React8.useCallback(
|
|
1852
|
+
(key) => getNestedValue(t, key),
|
|
1853
|
+
[t]
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1843
1856
|
function useSupportTicketsList(params, client) {
|
|
1844
1857
|
return useSWR__default.default(
|
|
1845
1858
|
params ? ["cfg-support-tickets", params] : "cfg-support-tickets",
|
|
@@ -2055,8 +2068,7 @@ var getStatusBadgeVariant = (status) => {
|
|
|
2055
2068
|
}
|
|
2056
2069
|
};
|
|
2057
2070
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
2058
|
-
const
|
|
2059
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2071
|
+
const st = useSupportT();
|
|
2060
2072
|
const labels = React8.useMemo(() => ({
|
|
2061
2073
|
status: {
|
|
2062
2074
|
open: st("status.open"),
|
|
@@ -2382,8 +2394,7 @@ function useSupportLayoutContext() {
|
|
|
2382
2394
|
return context;
|
|
2383
2395
|
}
|
|
2384
2396
|
var TicketList = () => {
|
|
2385
|
-
const
|
|
2386
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2397
|
+
const st = useSupportT();
|
|
2387
2398
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
2388
2399
|
const {
|
|
2389
2400
|
tickets,
|
|
@@ -2529,8 +2540,7 @@ var MessageBubble = ({ message, isFromUser, currentUser, labels }) => {
|
|
|
2529
2540
|
);
|
|
2530
2541
|
};
|
|
2531
2542
|
var MessageList = () => {
|
|
2532
|
-
const
|
|
2533
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2543
|
+
const st = useSupportT();
|
|
2534
2544
|
const { selectedTicket } = useSupportLayoutContext();
|
|
2535
2545
|
const { user } = auth.useAuth();
|
|
2536
2546
|
const labels = React8.useMemo(() => ({
|
|
@@ -2681,8 +2691,7 @@ var logger = consola.createConsola({
|
|
|
2681
2691
|
}).withTag("ext-support");
|
|
2682
2692
|
var supportLogger = logger;
|
|
2683
2693
|
var MessageInput = () => {
|
|
2684
|
-
const
|
|
2685
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2694
|
+
const st = useSupportT();
|
|
2686
2695
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2687
2696
|
const { toast } = hooks.useToast();
|
|
2688
2697
|
const [message, setMessage] = React8.useState("");
|
|
@@ -2747,8 +2756,7 @@ var MessageInput = () => {
|
|
|
2747
2756
|
] });
|
|
2748
2757
|
};
|
|
2749
2758
|
var CreateTicketDialog = () => {
|
|
2750
|
-
const
|
|
2751
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2759
|
+
const st = useSupportT();
|
|
2752
2760
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2753
2761
|
const { toast } = uiCore.useToast();
|
|
2754
2762
|
const [isSubmitting, setIsSubmitting] = React8__default.default.useState(false);
|
|
@@ -2862,8 +2870,7 @@ var CreateTicketDialog = () => {
|
|
|
2862
2870
|
] }) });
|
|
2863
2871
|
};
|
|
2864
2872
|
var SupportLayoutContent = () => {
|
|
2865
|
-
const
|
|
2866
|
-
const st = i18n.createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2873
|
+
const st = useSupportT();
|
|
2867
2874
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } = useSupportLayoutContext();
|
|
2868
2875
|
const [isMobile, setIsMobile] = React8__default.default.useState(false);
|
|
2869
2876
|
const labels = React8.useMemo(() => ({
|
|
@@ -2947,7 +2954,7 @@ var SupportLayout = () => {
|
|
|
2947
2954
|
// package.json
|
|
2948
2955
|
var package_default = {
|
|
2949
2956
|
name: "@djangocfg/ext-support",
|
|
2950
|
-
version: "1.0.
|
|
2957
|
+
version: "1.0.23",
|
|
2951
2958
|
description: "Support ticket system extension for DjangoCFG",
|
|
2952
2959
|
keywords: [
|
|
2953
2960
|
"django",
|
|
@@ -3015,14 +3022,15 @@ var package_default = {
|
|
|
3015
3022
|
"@djangocfg/ext-base": "workspace:*",
|
|
3016
3023
|
"@djangocfg/i18n": "workspace:*",
|
|
3017
3024
|
"@djangocfg/ui-core": "workspace:*",
|
|
3025
|
+
"@hookform/resolvers": "^5.2.2",
|
|
3018
3026
|
consola: "^3.4.2",
|
|
3019
3027
|
"lucide-react": "^0.545.0",
|
|
3020
3028
|
moment: "^2.30.1",
|
|
3021
3029
|
next: "^16",
|
|
3030
|
+
"next-intl": "^4",
|
|
3022
3031
|
"p-retry": "^7.0.0",
|
|
3023
3032
|
react: "^19",
|
|
3024
3033
|
"react-hook-form": "^7.69.0",
|
|
3025
|
-
"@hookform/resolvers": "^5.2.2",
|
|
3026
3034
|
swr: "^2.3.7",
|
|
3027
3035
|
zod: "^4.3.4"
|
|
3028
3036
|
},
|
|
@@ -3036,6 +3044,7 @@ var package_default = {
|
|
|
3036
3044
|
"@types/react": "^19.0.0",
|
|
3037
3045
|
consola: "^3.4.2",
|
|
3038
3046
|
moment: "^2.30.1",
|
|
3047
|
+
"next-intl": "^4.1.0",
|
|
3039
3048
|
"p-retry": "^7.0.0",
|
|
3040
3049
|
swr: "^2.3.7",
|
|
3041
3050
|
tsup: "^8.5.0",
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,7 @@ 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
6
|
import React8, { createContext, useState, useCallback, useEffect, useMemo, useContext, useRef } from 'react';
|
|
7
|
-
import {
|
|
8
|
-
import { useT } from '@djangocfg/i18n';
|
|
7
|
+
import { useLocale } from 'next-intl';
|
|
9
8
|
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';
|
|
10
9
|
import useSWR, { useSWRConfig } from 'swr';
|
|
11
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1822,14 +1821,28 @@ var ko = {
|
|
|
1822
1821
|
}
|
|
1823
1822
|
};
|
|
1824
1823
|
|
|
1825
|
-
// src/i18n/
|
|
1826
|
-
var
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1824
|
+
// src/i18n/useSupportT.ts
|
|
1825
|
+
var translations = { en, ru, ko };
|
|
1826
|
+
function getNestedValue(obj, path) {
|
|
1827
|
+
const keys = path.split(".");
|
|
1828
|
+
let result = obj;
|
|
1829
|
+
for (const key of keys) {
|
|
1830
|
+
if (result && typeof result === "object" && key in result) {
|
|
1831
|
+
result = result[key];
|
|
1832
|
+
} else {
|
|
1833
|
+
return path;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return typeof result === "string" ? result : path;
|
|
1837
|
+
}
|
|
1838
|
+
function useSupportT() {
|
|
1839
|
+
const locale = useLocale();
|
|
1840
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
1841
|
+
return useCallback(
|
|
1842
|
+
(key) => getNestedValue(t, key),
|
|
1843
|
+
[t]
|
|
1844
|
+
);
|
|
1845
|
+
}
|
|
1833
1846
|
function useSupportTicketsList(params, client) {
|
|
1834
1847
|
return useSWR(
|
|
1835
1848
|
params ? ["cfg-support-tickets", params] : "cfg-support-tickets",
|
|
@@ -2045,8 +2058,7 @@ var getStatusBadgeVariant = (status) => {
|
|
|
2045
2058
|
}
|
|
2046
2059
|
};
|
|
2047
2060
|
var TicketCard = ({ ticket, isSelected, onClick }) => {
|
|
2048
|
-
const
|
|
2049
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2061
|
+
const st = useSupportT();
|
|
2050
2062
|
const labels = useMemo(() => ({
|
|
2051
2063
|
status: {
|
|
2052
2064
|
open: st("status.open"),
|
|
@@ -2372,8 +2384,7 @@ function useSupportLayoutContext() {
|
|
|
2372
2384
|
return context;
|
|
2373
2385
|
}
|
|
2374
2386
|
var TicketList = () => {
|
|
2375
|
-
const
|
|
2376
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2387
|
+
const st = useSupportT();
|
|
2377
2388
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
2378
2389
|
const {
|
|
2379
2390
|
tickets,
|
|
@@ -2519,8 +2530,7 @@ var MessageBubble = ({ message, isFromUser, currentUser, labels }) => {
|
|
|
2519
2530
|
);
|
|
2520
2531
|
};
|
|
2521
2532
|
var MessageList = () => {
|
|
2522
|
-
const
|
|
2523
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2533
|
+
const st = useSupportT();
|
|
2524
2534
|
const { selectedTicket } = useSupportLayoutContext();
|
|
2525
2535
|
const { user } = useAuth();
|
|
2526
2536
|
const labels = useMemo(() => ({
|
|
@@ -2671,8 +2681,7 @@ var logger = createConsola({
|
|
|
2671
2681
|
}).withTag("ext-support");
|
|
2672
2682
|
var supportLogger = logger;
|
|
2673
2683
|
var MessageInput = () => {
|
|
2674
|
-
const
|
|
2675
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2684
|
+
const st = useSupportT();
|
|
2676
2685
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
2677
2686
|
const { toast } = useToast();
|
|
2678
2687
|
const [message, setMessage] = useState("");
|
|
@@ -2737,8 +2746,7 @@ var MessageInput = () => {
|
|
|
2737
2746
|
] });
|
|
2738
2747
|
};
|
|
2739
2748
|
var CreateTicketDialog = () => {
|
|
2740
|
-
const
|
|
2741
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2749
|
+
const st = useSupportT();
|
|
2742
2750
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
2743
2751
|
const { toast } = useToast$1();
|
|
2744
2752
|
const [isSubmitting, setIsSubmitting] = React8.useState(false);
|
|
@@ -2852,8 +2860,7 @@ var CreateTicketDialog = () => {
|
|
|
2852
2860
|
] }) });
|
|
2853
2861
|
};
|
|
2854
2862
|
var SupportLayoutContent = () => {
|
|
2855
|
-
const
|
|
2856
|
-
const st = createTypedExtensionT(baseT, SUPPORT_NAMESPACE);
|
|
2863
|
+
const st = useSupportT();
|
|
2857
2864
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } = useSupportLayoutContext();
|
|
2858
2865
|
const [isMobile, setIsMobile] = React8.useState(false);
|
|
2859
2866
|
const labels = useMemo(() => ({
|
|
@@ -2937,7 +2944,7 @@ var SupportLayout = () => {
|
|
|
2937
2944
|
// package.json
|
|
2938
2945
|
var package_default = {
|
|
2939
2946
|
name: "@djangocfg/ext-support",
|
|
2940
|
-
version: "1.0.
|
|
2947
|
+
version: "1.0.23",
|
|
2941
2948
|
description: "Support ticket system extension for DjangoCFG",
|
|
2942
2949
|
keywords: [
|
|
2943
2950
|
"django",
|
|
@@ -3005,14 +3012,15 @@ var package_default = {
|
|
|
3005
3012
|
"@djangocfg/ext-base": "workspace:*",
|
|
3006
3013
|
"@djangocfg/i18n": "workspace:*",
|
|
3007
3014
|
"@djangocfg/ui-core": "workspace:*",
|
|
3015
|
+
"@hookform/resolvers": "^5.2.2",
|
|
3008
3016
|
consola: "^3.4.2",
|
|
3009
3017
|
"lucide-react": "^0.545.0",
|
|
3010
3018
|
moment: "^2.30.1",
|
|
3011
3019
|
next: "^16",
|
|
3020
|
+
"next-intl": "^4",
|
|
3012
3021
|
"p-retry": "^7.0.0",
|
|
3013
3022
|
react: "^19",
|
|
3014
3023
|
"react-hook-form": "^7.69.0",
|
|
3015
|
-
"@hookform/resolvers": "^5.2.2",
|
|
3016
3024
|
swr: "^2.3.7",
|
|
3017
3025
|
zod: "^4.3.4"
|
|
3018
3026
|
},
|
|
@@ -3026,6 +3034,7 @@ var package_default = {
|
|
|
3026
3034
|
"@types/react": "^19.0.0",
|
|
3027
3035
|
consola: "^3.4.2",
|
|
3028
3036
|
moment: "^2.30.1",
|
|
3037
|
+
"next-intl": "^4.1.0",
|
|
3029
3038
|
"p-retry": "^7.0.0",
|
|
3030
3039
|
swr: "^2.3.7",
|
|
3031
3040
|
tsup: "^8.5.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ext-support",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"description": "Support ticket system extension for DjangoCFG",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -64,31 +64,33 @@
|
|
|
64
64
|
"check": "tsc --noEmit"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@djangocfg/api": "^2.1.
|
|
68
|
-
"@djangocfg/ext-base": "^1.0.
|
|
69
|
-
"@djangocfg/i18n": "^2.1.
|
|
70
|
-
"@djangocfg/ui-core": "^2.1.
|
|
67
|
+
"@djangocfg/api": "^2.1.124",
|
|
68
|
+
"@djangocfg/ext-base": "^1.0.18",
|
|
69
|
+
"@djangocfg/i18n": "^2.1.124",
|
|
70
|
+
"@djangocfg/ui-core": "^2.1.124",
|
|
71
|
+
"@hookform/resolvers": "^5.2.2",
|
|
71
72
|
"consola": "^3.4.2",
|
|
72
73
|
"lucide-react": "^0.545.0",
|
|
73
74
|
"moment": "^2.30.1",
|
|
74
75
|
"next": "^16",
|
|
76
|
+
"next-intl": "^4",
|
|
75
77
|
"p-retry": "^7.0.0",
|
|
76
78
|
"react": "^19",
|
|
77
79
|
"react-hook-form": "^7.69.0",
|
|
78
|
-
"@hookform/resolvers": "^5.2.2",
|
|
79
80
|
"swr": "^2.3.7",
|
|
80
81
|
"zod": "^4.3.4"
|
|
81
82
|
},
|
|
82
83
|
"devDependencies": {
|
|
83
|
-
"@djangocfg/api": "^2.1.
|
|
84
|
-
"@djangocfg/ext-base": "^1.0.
|
|
85
|
-
"@djangocfg/i18n": "^2.1.
|
|
86
|
-
"@djangocfg/ui-core": "^2.1.
|
|
87
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
84
|
+
"@djangocfg/api": "^2.1.124",
|
|
85
|
+
"@djangocfg/ext-base": "^1.0.18",
|
|
86
|
+
"@djangocfg/i18n": "^2.1.124",
|
|
87
|
+
"@djangocfg/ui-core": "^2.1.124",
|
|
88
|
+
"@djangocfg/typescript-config": "^2.1.124",
|
|
88
89
|
"@types/node": "^24.7.2",
|
|
89
90
|
"@types/react": "^19.0.0",
|
|
90
91
|
"consola": "^3.4.2",
|
|
91
92
|
"moment": "^2.30.1",
|
|
93
|
+
"next-intl": "^4.1.0",
|
|
92
94
|
"p-retry": "^7.0.0",
|
|
93
95
|
"swr": "^2.3.7",
|
|
94
96
|
"tsup": "^8.5.0",
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Support Extension I18n
|
|
3
|
+
*
|
|
4
|
+
* Self-contained translations - no app configuration needed.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useSupportT } from '@djangocfg/ext-support/i18n';
|
|
9
|
+
*
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const t = useSupportT();
|
|
12
|
+
* return <h1>{t('layout.title')}</h1>;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
3
15
|
*/
|
|
4
16
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { en } from './locales/en';
|
|
8
|
-
import { ru } from './locales/ru';
|
|
9
|
-
import { ko } from './locales/ko';
|
|
10
|
-
|
|
11
|
-
/** Support extension namespace */
|
|
12
|
-
export const SUPPORT_NAMESPACE = 'support' as const;
|
|
13
|
-
|
|
14
|
-
export const supportI18n = createExtensionI18n<SupportTranslations>({
|
|
15
|
-
namespace: SUPPORT_NAMESPACE,
|
|
16
|
-
defaultLocale: 'en',
|
|
17
|
-
locales: { en, ru, ko },
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export const supportTranslations = supportI18n.getAllTranslations();
|
|
17
|
+
// Self-contained hook (recommended)
|
|
18
|
+
export { useSupportT } from './useSupportT';
|
|
21
19
|
|
|
22
20
|
// Types
|
|
23
|
-
export type { SupportTranslations,
|
|
21
|
+
export type { SupportTranslations, SupportLocalKeys } from './types';
|
|
22
|
+
|
|
23
|
+
// Locales (for direct access if needed)
|
|
24
|
+
export { en } from './locales/en';
|
|
25
|
+
export { ru } from './locales/ru';
|
|
26
|
+
export { ko } from './locales/ko';
|
package/src/i18n/types.ts
CHANGED
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
* Support Extension I18n Types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
6
|
+
* Helper type to get dot-notation paths from nested object
|
|
9
7
|
*/
|
|
10
|
-
|
|
8
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object
|
|
9
|
+
? {
|
|
10
|
+
[K in keyof T]: K extends string
|
|
11
|
+
? T[K] extends object
|
|
12
|
+
? PathKeys<T[K], `${Prefix}${K}.`>
|
|
13
|
+
: `${Prefix}${K}`
|
|
14
|
+
: never;
|
|
15
|
+
}[keyof T]
|
|
16
|
+
: never;
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
|
-
* Keys
|
|
19
|
+
* Keys for support translations
|
|
14
20
|
*/
|
|
15
21
|
export type SupportLocalKeys = PathKeys<SupportTranslations>;
|
|
16
22
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Self-contained translation hook for ext-support
|
|
5
|
+
*
|
|
6
|
+
* Uses built-in translations, no app configuration needed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useLocale } from 'next-intl';
|
|
10
|
+
import { useMemo, useCallback } from 'react';
|
|
11
|
+
|
|
12
|
+
import type { SupportTranslations, SupportLocalKeys } from './types';
|
|
13
|
+
import { en } from './locales/en';
|
|
14
|
+
import { ru } from './locales/ru';
|
|
15
|
+
import { ko } from './locales/ko';
|
|
16
|
+
|
|
17
|
+
const translations: Record<string, SupportTranslations> = { en, ru, ko };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get nested value from object by dot-notation path
|
|
21
|
+
*/
|
|
22
|
+
function getNestedValue(obj: Record<string, unknown>, path: string): string {
|
|
23
|
+
const keys = path.split('.');
|
|
24
|
+
let result: unknown = obj;
|
|
25
|
+
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
if (result && typeof result === 'object' && key in result) {
|
|
28
|
+
result = (result as Record<string, unknown>)[key];
|
|
29
|
+
} else {
|
|
30
|
+
return path; // Return key if not found
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return typeof result === 'string' ? result : path;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Self-contained translation hook for support extension
|
|
39
|
+
*
|
|
40
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
41
|
+
* No need to add translations to app's i18n config.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* function TicketList() {
|
|
46
|
+
* const t = useSupportT();
|
|
47
|
+
* return <h1>{t('layout.title')}</h1>;
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function useSupportT(): (key: SupportLocalKeys) => string {
|
|
52
|
+
const locale = useLocale();
|
|
53
|
+
|
|
54
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
55
|
+
|
|
56
|
+
return useCallback(
|
|
57
|
+
(key: SupportLocalKeys): string => getNestedValue(t as unknown as Record<string, unknown>, key),
|
|
58
|
+
[t]
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
import { ArrowLeft, LifeBuoy, Plus } from 'lucide-react';
|
|
10
10
|
import React, { useMemo } from 'react';
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import { useT } from '@djangocfg/i18n';
|
|
14
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../i18n';
|
|
12
|
+
import { useSupportT } from '../../i18n';
|
|
15
13
|
import { Button, ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@djangocfg/ui-core';
|
|
16
14
|
|
|
17
15
|
import { SupportProvider } from '../../contexts/SupportContext';
|
|
@@ -23,8 +21,7 @@ import { SupportLayoutProvider, useSupportLayoutContext } from './context';
|
|
|
23
21
|
// ─────────────────────────────────────────────────────────────────────────
|
|
24
22
|
|
|
25
23
|
const SupportLayoutContent: React.FC = () => {
|
|
26
|
-
const
|
|
27
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
24
|
+
const st = useSupportT();
|
|
28
25
|
const { selectedTicket, selectTicket, openCreateDialog, getUnreadCount } =
|
|
29
26
|
useSupportLayoutContext();
|
|
30
27
|
const [isMobile, setIsMobile] = React.useState(false);
|
|
@@ -11,9 +11,7 @@ import React, { useMemo } from 'react';
|
|
|
11
11
|
import { useForm } from 'react-hook-form';
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
import { useT } from '@djangocfg/i18n';
|
|
16
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../../i18n';
|
|
14
|
+
import { useSupportT } from '../../../i18n';
|
|
17
15
|
import {
|
|
18
16
|
Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Form, FormControl,
|
|
19
17
|
FormField, FormItem, FormLabel, FormMessage, Input, Textarea, useToast
|
|
@@ -26,8 +24,7 @@ import { useSupportLayoutContext } from '../context';
|
|
|
26
24
|
import type { TicketFormData } from '../types';
|
|
27
25
|
|
|
28
26
|
export const CreateTicketDialog: React.FC = () => {
|
|
29
|
-
const
|
|
30
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
27
|
+
const st = useSupportT();
|
|
31
28
|
const { uiState, createTicket, closeCreateDialog } = useSupportLayoutContext();
|
|
32
29
|
const { toast } = useToast();
|
|
33
30
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
import { Send } from 'lucide-react';
|
|
9
9
|
import React, { useState, useMemo } from 'react';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { useT } from '@djangocfg/i18n';
|
|
13
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../../i18n';
|
|
11
|
+
import { useSupportT } from '../../../i18n';
|
|
14
12
|
import { Button, Textarea } from '@djangocfg/ui-core';
|
|
15
13
|
import { useToast } from '@djangocfg/ui-core/hooks';
|
|
16
14
|
|
|
@@ -18,8 +16,7 @@ import { supportLogger } from '../../../utils/logger';
|
|
|
18
16
|
import { useSupportLayoutContext } from '../context';
|
|
19
17
|
|
|
20
18
|
export const MessageInput: React.FC = () => {
|
|
21
|
-
const
|
|
22
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
19
|
+
const st = useSupportT();
|
|
23
20
|
const { selectedTicket, sendMessage } = useSupportLayoutContext();
|
|
24
21
|
const { toast } = useToast();
|
|
25
22
|
const [message, setMessage] = useState('');
|
|
@@ -10,9 +10,7 @@ import moment from 'moment';
|
|
|
10
10
|
import React, { useCallback, useEffect, useRef, useMemo } from 'react';
|
|
11
11
|
|
|
12
12
|
import { useAuth } from '@djangocfg/api/auth';
|
|
13
|
-
import {
|
|
14
|
-
import { useT } from '@djangocfg/i18n';
|
|
15
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../../i18n';
|
|
13
|
+
import { useSupportT } from '../../../i18n';
|
|
16
14
|
import {
|
|
17
15
|
Avatar, AvatarFallback, AvatarImage, Button, Card, CardContent, ScrollArea, Skeleton
|
|
18
16
|
} from '@djangocfg/ui-core';
|
|
@@ -124,8 +122,7 @@ const MessageBubble: React.FC<MessageBubbleProps> = ({ message, isFromUser, curr
|
|
|
124
122
|
};
|
|
125
123
|
|
|
126
124
|
export const MessageList: React.FC = () => {
|
|
127
|
-
const
|
|
128
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
125
|
+
const st = useSupportT();
|
|
129
126
|
const { selectedTicket } = useSupportLayoutContext();
|
|
130
127
|
const { user } = useAuth();
|
|
131
128
|
|
|
@@ -9,9 +9,7 @@ import { Clock, MessageSquare } from 'lucide-react';
|
|
|
9
9
|
import moment from 'moment';
|
|
10
10
|
import React, { useMemo, useCallback } from 'react';
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import { useT } from '@djangocfg/i18n';
|
|
14
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../../i18n';
|
|
12
|
+
import { useSupportT } from '../../../i18n';
|
|
15
13
|
import { Badge, Card, CardContent } from '@djangocfg/ui-core';
|
|
16
14
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
17
15
|
|
|
@@ -43,8 +41,7 @@ const getStatusBadgeVariant = (
|
|
|
43
41
|
};
|
|
44
42
|
|
|
45
43
|
export const TicketCard: React.FC<TicketCardProps> = ({ ticket, isSelected, onClick }) => {
|
|
46
|
-
const
|
|
47
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
44
|
+
const st = useSupportT();
|
|
48
45
|
|
|
49
46
|
const labels = useMemo(() => ({
|
|
50
47
|
status: {
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
import { Loader2, MessageSquare } from 'lucide-react';
|
|
9
9
|
import React, { useEffect, useRef, useMemo } from 'react';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { useT } from '@djangocfg/i18n';
|
|
13
|
-
import { SUPPORT_NAMESPACE, type SupportTranslations } from '../../../i18n';
|
|
11
|
+
import { useSupportT } from '../../../i18n';
|
|
14
12
|
import { Button, ScrollArea, Skeleton } from '@djangocfg/ui-core';
|
|
15
13
|
|
|
16
14
|
import { useSupportLayoutContext } from '../context';
|
|
@@ -19,8 +17,7 @@ import { useInfiniteTickets } from '../hooks';
|
|
|
19
17
|
import { TicketCard } from './TicketCard';
|
|
20
18
|
|
|
21
19
|
export const TicketList: React.FC = () => {
|
|
22
|
-
const
|
|
23
|
-
const st = createTypedExtensionT<typeof SUPPORT_NAMESPACE, SupportTranslations>(baseT, SUPPORT_NAMESPACE);
|
|
20
|
+
const st = useSupportT();
|
|
24
21
|
const { selectedTicket, selectTicket } = useSupportLayoutContext();
|
|
25
22
|
const {
|
|
26
23
|
tickets,
|