@djangocfg/ext-support 1.0.4 → 1.0.7

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.
Files changed (37) hide show
  1. package/dist/config.cjs +3 -1
  2. package/dist/config.js +3 -1
  3. package/dist/hooks.cjs +75 -80
  4. package/dist/hooks.js +74 -80
  5. package/dist/index.cjs +75 -80
  6. package/dist/index.js +74 -80
  7. package/package.json +9 -7
  8. package/src/api/generated/ext_support/CLAUDE.md +80 -0
  9. package/src/api/generated/ext_support/_utils/fetchers/ext_support__support.ts +1 -0
  10. package/src/api/generated/ext_support/_utils/fetchers/index.ts +1 -0
  11. package/src/api/generated/ext_support/_utils/hooks/ext_support__support.ts +1 -0
  12. package/src/api/generated/ext_support/_utils/hooks/index.ts +1 -0
  13. package/src/api/generated/ext_support/_utils/schemas/index.ts +1 -0
  14. package/src/api/generated/ext_support/api-instance.ts +1 -0
  15. package/src/api/generated/ext_support/enums.ts +1 -0
  16. package/src/api/generated/ext_support/errors.ts +1 -0
  17. package/src/api/generated/ext_support/ext_support__support/index.ts +1 -0
  18. package/src/api/generated/ext_support/ext_support__support/models.ts +1 -0
  19. package/src/api/generated/ext_support/http.ts +1 -0
  20. package/src/api/generated/ext_support/index.ts +1 -0
  21. package/src/api/generated/ext_support/logger.ts +1 -0
  22. package/src/api/generated/ext_support/retry.ts +1 -0
  23. package/src/api/generated/ext_support/storage.ts +1 -0
  24. package/src/api/generated/ext_support/validation-events.ts +1 -0
  25. package/src/api/index.ts +2 -1
  26. package/src/config.ts +1 -0
  27. package/src/contexts/SupportContext.tsx +9 -13
  28. package/src/contexts/SupportExtensionProvider.tsx +1 -0
  29. package/src/layouts/SupportLayout/SupportLayout.tsx +5 -13
  30. package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +8 -18
  31. package/src/layouts/SupportLayout/components/MessageInput.tsx +3 -1
  32. package/src/layouts/SupportLayout/components/MessageList.tsx +25 -22
  33. package/src/layouts/SupportLayout/components/TicketCard.tsx +8 -9
  34. package/src/layouts/SupportLayout/components/TicketList.tsx +6 -4
  35. package/src/layouts/SupportLayout/context/SupportLayoutContext.tsx +9 -2
  36. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -0
  37. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -0
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * HTTP Client Adapter Pattern
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * Django CFG API - API Client with JWT Management
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * API Logger with Consola
3
4
  * Beautiful console logging for API requests and responses
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * Retry Configuration and Utilities
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * Storage adapters for cross-platform token storage.
3
4
  *
@@ -1,3 +1,4 @@
1
+ // Auto-generated by DjangoCFG - see CLAUDE.md
1
2
  /**
2
3
  * Zod Validation Events - Browser CustomEvent integration
3
4
  *
package/src/api/index.ts CHANGED
@@ -1,9 +1,10 @@
1
+ import { createExtensionAPI } from '@djangocfg/ext-base/api';
2
+
1
3
  /**
2
4
  * Support Extension API
3
5
  *
4
6
  * Pre-configured API instance with shared authentication
5
7
  */
6
8
  import { API } from './generated/ext_support';
7
- import { createExtensionAPI } from '@djangocfg/ext-base/api';
8
9
 
9
10
  export const apiSupport = createExtensionAPI(API);
package/src/config.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { createExtensionConfig } from '@djangocfg/ext-base';
6
+
6
7
  import packageJson from '../package.json';
7
8
 
8
9
  export const extensionConfig = createExtensionConfig(packageJson, {
@@ -1,20 +1,16 @@
1
1
  'use client';
2
2
 
3
- import React, { createContext, useContext, type ReactNode } from 'react';
3
+ import React, { createContext, ReactNode, useContext } from 'react';
4
+
4
5
  import {
5
- useSupportTicketsList,
6
- useSupportTicketsRetrieve,
7
- useCreateSupportTicketsCreate,
8
- useUpdateSupportTicketsUpdate,
9
- usePartialUpdateSupportTicketsPartialUpdate,
10
- useDeleteSupportTicketsDestroy,
11
- useSupportTicketsMessagesList,
12
- useSupportTicketsMessagesRetrieve,
13
- useCreateSupportTicketsMessagesCreate,
14
- useUpdateSupportTicketsMessagesUpdate,
15
- usePartialUpdateSupportTicketsMessagesPartialUpdate,
16
- useDeleteSupportTicketsMessagesDestroy,
6
+ useCreateSupportTicketsCreate, useCreateSupportTicketsMessagesCreate,
7
+ useDeleteSupportTicketsDestroy, useDeleteSupportTicketsMessagesDestroy,
8
+ usePartialUpdateSupportTicketsMessagesPartialUpdate,
9
+ usePartialUpdateSupportTicketsPartialUpdate, useSupportTicketsList,
10
+ useSupportTicketsMessagesList, useSupportTicketsMessagesRetrieve, useSupportTicketsRetrieve,
11
+ useUpdateSupportTicketsMessagesUpdate, useUpdateSupportTicketsUpdate
17
12
  } from '../api/generated/ext_support/_utils/hooks';
13
+
18
14
  import type {
19
15
  Ticket,
20
16
  TicketRequest,
@@ -8,6 +8,7 @@
8
8
 
9
9
  import type { ReactNode } from 'react';
10
10
  import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
11
+
11
12
  import { extensionConfig } from '../config';
12
13
  import { SupportProvider } from './SupportContext';
13
14
 
@@ -6,22 +6,14 @@
6
6
 
7
7
  'use client';
8
8
 
9
+ import { ArrowLeft, LifeBuoy, Plus } from 'lucide-react';
9
10
  import React from 'react';
11
+
12
+ import { Button, ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@djangocfg/ui-nextjs';
13
+
10
14
  import { SupportProvider } from '../../contexts/SupportContext';
15
+ import { CreateTicketDialog, MessageInput, MessageList, TicketList } from './components';
11
16
  import { SupportLayoutProvider, useSupportLayoutContext } from './context';
12
- import {
13
- TicketList,
14
- MessageList,
15
- MessageInput,
16
- CreateTicketDialog,
17
- } from './components';
18
- import {
19
- Button,
20
- ResizablePanelGroup,
21
- ResizablePanel,
22
- ResizableHandle,
23
- } from '@djangocfg/ui-nextjs';
24
- import { Plus, LifeBuoy, ArrowLeft } from 'lucide-react';
25
17
 
26
18
  // ─────────────────────────────────────────────────────────────────────────
27
19
  // Support Layout Content (with context)
@@ -6,30 +6,20 @@
6
6
 
7
7
  'use client';
8
8
 
9
+ import { Loader2, Plus } from 'lucide-react';
9
10
  import React from 'react';
11
+ import { useForm } from 'react-hook-form';
12
+ import { z } from 'zod';
13
+
10
14
  import {
11
- Dialog,
12
- DialogContent,
13
- DialogHeader,
14
- DialogTitle,
15
- DialogDescription,
16
- Button,
17
- Form,
18
- FormField,
19
- FormItem,
20
- FormLabel,
21
- FormControl,
22
- FormMessage,
23
- Input,
24
- Textarea,
15
+ Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Form, FormControl,
16
+ FormField, FormItem, FormLabel, FormMessage, Input, Textarea, useToast
25
17
  } from '@djangocfg/ui-nextjs';
26
- import { useForm } from 'react-hook-form';
27
18
  import { zodResolver } from '@hookform/resolvers/zod';
28
- import { z } from 'zod';
29
- import { Plus, Loader2 } from 'lucide-react';
19
+
30
20
  import { supportLogger } from '../../../utils/logger';
31
21
  import { useSupportLayoutContext } from '../context';
32
- import { useToast } from '@djangocfg/ui-nextjs';
22
+
33
23
  import type { TicketFormData } from '../types';
34
24
 
35
25
  const createTicketSchema = z.object({
@@ -5,9 +5,11 @@
5
5
 
6
6
  'use client';
7
7
 
8
+ import { Send } from 'lucide-react';
8
9
  import React, { useState } from 'react';
10
+
9
11
  import { Button, Textarea, useToast } from '@djangocfg/ui-nextjs';
10
- import { Send } from 'lucide-react';
12
+
11
13
  import { supportLogger } from '../../../utils/logger';
12
14
  import { useSupportLayoutContext } from '../context';
13
15
 
@@ -5,29 +5,28 @@
5
5
 
6
6
  'use client';
7
7
 
8
- import React, { useEffect, useRef, useCallback } from 'react';
9
- import { ScrollArea, Skeleton, Avatar, AvatarFallback, AvatarImage, Card, CardContent, Button } from '@djangocfg/ui-nextjs';
10
- import { MessageSquare, Loader2, User, Headphones } from 'lucide-react';
8
+ import { Headphones, Loader2, MessageSquare, User } from 'lucide-react';
9
+ import moment from 'moment';
10
+ import React, { useCallback, useEffect, useRef } from 'react';
11
+
12
+ import { useAuth } from '@djangocfg/api/auth';
13
+ import {
14
+ Avatar, AvatarFallback, AvatarImage, Button, Card, CardContent, ScrollArea, Skeleton
15
+ } from '@djangocfg/ui-nextjs';
16
+
11
17
  import { useSupportLayoutContext } from '../context';
12
18
  import { useInfiniteMessages } from '../hooks';
13
- import { useAuth } from '@djangocfg/api/auth';
19
+
14
20
  import type { Message } from '../../../api/generated/ext_support/_utils/schemas';
15
21
 
16
22
  const formatTime = (date: string | null | undefined): string => {
17
23
  if (!date) return '';
18
- return new Date(date).toLocaleTimeString('en-US', {
19
- hour: '2-digit',
20
- minute: '2-digit',
21
- });
24
+ return moment.utc(date).local().format('hh:mm A');
22
25
  };
23
26
 
24
27
  const formatDate = (date: string | null | undefined): string => {
25
28
  if (!date) return '';
26
- return new Date(date).toLocaleDateString('en-US', {
27
- year: 'numeric',
28
- month: 'short',
29
- day: 'numeric',
30
- });
29
+ return moment.utc(date).local().format('MMM D, YYYY');
31
30
  };
32
31
 
33
32
  interface MessageBubbleProps {
@@ -39,6 +38,15 @@ interface MessageBubbleProps {
39
38
  const MessageBubble: React.FC<MessageBubbleProps> = ({ message, isFromUser, currentUser }) => {
40
39
  const sender = message.sender;
41
40
 
41
+ // Pre-compute initials
42
+ const senderInitial = sender?.display_username?.charAt(0)?.toUpperCase()
43
+ || sender?.initials
44
+ || 'S';
45
+ const userInitial = currentUser?.display_username?.charAt(0)?.toUpperCase()
46
+ || currentUser?.email?.charAt(0)?.toUpperCase()
47
+ || currentUser?.initials
48
+ || null;
49
+
42
50
  return (
43
51
  <div
44
52
  className={`flex gap-3 ${isFromUser ? 'justify-end' : 'justify-start'}
@@ -54,9 +62,7 @@ const MessageBubble: React.FC<MessageBubbleProps> = ({ message, isFromUser, curr
54
62
  {sender?.is_staff ? (
55
63
  <Headphones className="h-4 w-4" />
56
64
  ) : (
57
- sender?.display_username?.charAt(0)?.toUpperCase() ||
58
- sender?.initials ||
59
- 'S'
65
+ senderInitial
60
66
  )}
61
67
  </AvatarFallback>
62
68
  )}
@@ -101,10 +107,7 @@ const MessageBubble: React.FC<MessageBubbleProps> = ({ message, isFromUser, curr
101
107
  <AvatarImage src={currentUser.avatar} alt={currentUser.display_username || currentUser.email || 'You'} />
102
108
  ) : (
103
109
  <AvatarFallback className="bg-primary/10 text-primary font-semibold">
104
- {currentUser?.display_username?.charAt(0)?.toUpperCase() ||
105
- currentUser?.email?.charAt(0)?.toUpperCase() ||
106
- currentUser?.initials ||
107
- <User className="h-4 w-4" />}
110
+ {userInitial || <User className="h-4 w-4" />}
108
111
  </AvatarFallback>
109
112
  )}
110
113
  </Avatar>
@@ -282,8 +285,8 @@ export const MessageList: React.FC = () => {
282
285
  // Show date separator if date changes
283
286
  const previousMessage = index > 0 ? messages[index - 1] : null;
284
287
  const showDateSeparator = previousMessage &&
285
- new Date(previousMessage.created_at || '').toDateString() !==
286
- new Date(message.created_at || '').toDateString();
288
+ moment.utc(previousMessage.created_at || '').format('YYYY-MM-DD') !==
289
+ moment.utc(message.created_at || '').format('YYYY-MM-DD');
287
290
 
288
291
  return (
289
292
  <React.Fragment key={message.uuid}>
@@ -5,9 +5,12 @@
5
5
 
6
6
  'use client';
7
7
 
8
+ import { Clock, MessageSquare } from 'lucide-react';
9
+ import moment from 'moment';
8
10
  import React from 'react';
11
+
9
12
  import { Badge, Card, CardContent, cn } from '@djangocfg/ui-nextjs';
10
- import { Clock, MessageSquare } from 'lucide-react';
13
+
11
14
  import type { Ticket } from '../../../api/generated/ext_support/_utils/schemas';
12
15
 
13
16
  interface TicketCardProps {
@@ -38,20 +41,16 @@ const getStatusBadgeVariant = (
38
41
  const formatRelativeTime = (date: string | null | undefined): string => {
39
42
  if (!date) return 'N/A';
40
43
 
41
- const now = new Date();
42
- const messageDate = new Date(date);
43
- const diffInSeconds = Math.floor((now.getTime() - messageDate.getTime()) / 1000);
44
+ const m = moment.utc(date).local();
45
+ const now = moment();
46
+ const diffInSeconds = now.diff(m, 'seconds');
44
47
 
45
48
  if (diffInSeconds < 60) return 'Just now';
46
49
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
47
50
  if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
48
51
  if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`;
49
52
 
50
- return new Date(date).toLocaleDateString('en-US', {
51
- year: 'numeric',
52
- month: 'short',
53
- day: 'numeric',
54
- });
53
+ return m.format('MMM D, YYYY');
55
54
  };
56
55
 
57
56
  export const TicketCard: React.FC<TicketCardProps> = ({ ticket, isSelected, onClick }) => {
@@ -5,13 +5,15 @@
5
5
 
6
6
  'use client';
7
7
 
8
+ import { Loader2, MessageSquare } from 'lucide-react';
8
9
  import React, { useEffect, useRef } from 'react';
9
- import { ScrollArea, Skeleton, Button } from '@djangocfg/ui-nextjs';
10
- import { TicketCard } from './TicketCard';
10
+
11
+ import { Button, ScrollArea, Skeleton } from '@djangocfg/ui-nextjs';
12
+
11
13
  import { useSupportLayoutContext } from '../context';
12
- import { MessageSquare, Loader2 } from 'lucide-react';
13
- import { useInfiniteTickets } from '../hooks';
14
14
  import { SUPPORT_LAYOUT_EVENTS } from '../events';
15
+ import { useInfiniteTickets } from '../hooks';
16
+ import { TicketCard } from './TicketCard';
15
17
 
16
18
  export const TicketList: React.FC = () => {
17
19
  const { selectedTicket, selectTicket } = useSupportLayoutContext();
@@ -5,11 +5,18 @@
5
5
 
6
6
  'use client';
7
7
 
8
- import React, { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from 'react';
9
- import { useSupportContext, type Ticket, type Message, type MessageCreateRequest } from '../../../contexts/SupportContext';
8
+ import React, {
9
+ createContext, ReactNode, useCallback, useContext, useEffect, useState
10
+ } from 'react';
11
+
10
12
  import { useAuth } from '@djangocfg/api/auth';
13
+
14
+ import {
15
+ Message, MessageCreateRequest, Ticket, useSupportContext
16
+ } from '../../../contexts/SupportContext';
11
17
  import { SUPPORT_LAYOUT_EVENTS } from '../events';
12
18
  import { useInfiniteMessages } from '../hooks';
19
+
13
20
  import type { SupportUIState, TicketFormData } from '../types';
14
21
 
15
22
  // ─────────────────────────────────────────────────────────────────────────
@@ -4,7 +4,9 @@
4
4
  */
5
5
 
6
6
  import useSWRInfinite from 'swr/infinite';
7
+
7
8
  import * as Fetchers from '../../../api/generated/ext_support/_utils/fetchers';
9
+
8
10
  import type { PaginatedMessageList, Message } from '../../../api/generated/ext_support/_utils/schemas';
9
11
 
10
12
  const PAGE_SIZE = 20;
@@ -4,7 +4,9 @@
4
4
  */
5
5
 
6
6
  import useSWRInfinite from 'swr/infinite';
7
+
7
8
  import * as Fetchers from '../../../api/generated/ext_support/_utils/fetchers';
9
+
8
10
  import type { PaginatedTicketList, Ticket } from '../../../api/generated/ext_support/_utils/schemas';
9
11
 
10
12
  const PAGE_SIZE = 20;