@djangocfg/ext-support
Customer support and ticketing system extension for DjangoCFG.
Part of DjangoCFG — modern Django framework for production-ready SaaS applications.
Features
- 🎫 Ticket Management - Create, track, and resolve support tickets
- 💬 Real-time Chat - Live chat support integration
- 📧 Email Integration - Convert emails to tickets automatically
- 🏷️ Categories & Tags - Organize tickets with custom categories
- 👥 Team Assignment - Assign tickets to support agents
- 📊 Analytics - Track response times and resolution rates
- 🔔 Notifications - Real-time ticket updates
- 📎 Attachments - Support for file attachments
Install
pnpm add @djangocfg/ext-support
Usage
Provider Setup
import { SupportExtensionProvider } from '@djangocfg/ext-support/hooks';
export default function RootLayout({ children }) {
return (
<SupportExtensionProvider>
{children}
</SupportExtensionProvider>
);
}
Create Support Ticket
import { useSupportContext } from '@djangocfg/ext-support/hooks';
function ContactSupport() {
const { createTicket, isCreatingTicket } = useSupportContext();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await createTicket({
subject: formData.get('subject') as string,
description: formData.get('description') as string,
category: 'technical',
priority: 'medium',
});
};
return (
<form onSubmit={handleSubmit}>
<input name="subject" placeholder="Subject" required />
<textarea name="description" placeholder="Describe your issue" required />
<button type="submit" disabled={isCreatingTicket}>
{isCreatingTicket ? 'Submitting...' : 'Submit Ticket'}
</button>
</form>
);
}
View Tickets
import { useSupportContext } from '@djangocfg/ext-support/hooks';
function TicketsPage() {
const { tickets, isLoadingTickets, updateTicket } = useSupportContext();
const handleStatusChange = async (ticketId: string, status: string) => {
await updateTicket(ticketId, { status });
};
return (
<div>
<h2>Support Tickets</h2>
{tickets.map(ticket => (
<div key={ticket.id}>
<h3>{ticket.subject}</h3>
<p>{ticket.description}</p>
<span>Status: {ticket.status}</span>
<span>Priority: {ticket.priority}</span>
<select
value={ticket.status}
onChange={(e) => handleStatusChange(ticket.id, e.target.value)}
>
<option value="open">Open</option>
<option value="in_progress">In Progress</option>
<option value="resolved">Resolved</option>
<option value="closed">Closed</option>
</select>
</div>
))}
</div>
);
}
import { useSupportContext } from '@djangocfg/ext-support/hooks';
function TicketDetails({ ticketId }: { ticketId: string }) {
const { getTicketById, addComment } = useSupportContext();
const [ticket, setTicket] = useState(null);
useEffect(() => {
getTicketById(ticketId).then(setTicket);
}, [ticketId]);
const handleAddComment = async (text: string) => {
await addComment(ticketId, {
text,
is_internal: false,
});
getTicketById(ticketId).then(setTicket);
};
if (!ticket) return <div>Loading...</div>;
return (
<div>
<h2>{ticket.subject}</h2>
<p>{ticket.description}</p>
<div>
<h3>Comments</h3>
{ticket.comments?.map(comment => (
<div key={comment.id}>
<strong>{comment.author}</strong>
<p>{comment.text}</p>
<span>{new Date(comment.created_at).toLocaleString()}</span>
</div>
))}
</div>
<textarea
placeholder="Add a comment..."
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleAddComment(e.currentTarget.value);
e.currentTarget.value = '';
}
}}
/>
</div>
);
}
Ticket Filters
import { useSupportContext } from '@djangocfg/ext-support/hooks';
function TicketFilters() {
const { tickets, filterTickets } = useSupportContext();
const handleFilter = (status: string) => {
filterTickets({ status });
};
return (
<div>
<button onClick={() => handleFilter('open')}>
Open ({tickets.filter(t => t.status === 'open').length})
</button>
<button onClick={() => handleFilter('in_progress')}>
In Progress ({tickets.filter(t => t.status === 'in_progress').length})
</button>
<button onClick={() => handleFilter('resolved')}>
Resolved ({tickets.filter(t => t.status === 'resolved').length})
</button>
</div>
);
}
API Reference
Support Context
tickets - List of all tickets
createTicket(data) - Create new ticket
updateTicket(id, data) - Update ticket
deleteTicket(id) - Delete ticket
getTicketById(id) - Get ticket details
addComment(ticketId, data) - Add comment to ticket
assignTicket(ticketId, agentId) - Assign ticket to agent
closeTicket(id) - Close ticket
reopenTicket(id) - Reopen closed ticket
filterTickets(filters) - Filter tickets by criteria
isLoadingTickets - Loading state
isCreatingTicket - Creation state
Ticket Properties
interface Ticket {
id: string;
subject: string;
description: string;
status: 'open' | 'in_progress' | 'resolved' | 'closed';
priority: 'low' | 'medium' | 'high' | 'urgent';
category: string;
assigned_to?: string;
created_at: string;
updated_at: string;
comments?: Comment[];
}
License
MIT
Links