@djangocfg/ext-leads
v1.0.29
Published
Lead management and contact forms extension for DjangoCFG
Maintainers
Readme

View in Marketplace • Documentation • GitHub
@djangocfg/ext-leads
Lead capture extension with ready-to-use contact forms for DjangoCFG.
Part of DjangoCFG — modern Django framework for production-ready SaaS applications.
Features
- Contact Form - Ready-to-use form with validation and localStorage draft
- Contact Page - Full-page layout with form, contact info, and Calendly integration
- API Integration - Submits leads to DjangoCFG backend via Next.js API route
- Customizable - Override texts, styling, and callbacks
Install
pnpm add @djangocfg/ext-leadsUsage
ContactPage (Recommended)
Full contact page with form, contact details, and optional Calendly booking.
'use client';
import { ContactPage } from '@djangocfg/ext-leads/hooks';
export default function Contact() {
return (
<ContactPage
email="[email protected]"
whatsapp="+1 234 567 890"
calendlyUrl="https://calendly.com/your-link"
title="Get in Touch"
subtitle="We'd love to hear from you."
onSuccess={(result) => console.log('Lead created:', result.lead_id)}
/>
);
}ContactForm (Standalone)
Just the form component, wrapped in a card.
'use client';
import { ContactForm } from '@djangocfg/ext-leads/hooks';
export default function ContactSection() {
return (
<ContactForm
onSuccess={(result) => console.log('Submitted:', result)}
onError={(error) => console.error('Failed:', error)}
/>
);
}Custom Form with Provider
For full control, use the provider and hook directly.
'use client';
import { ContactFormProvider, useContactForm } from '@djangocfg/ext-leads/hooks';
import type { LeadSubmissionRequest } from '@djangocfg/ext-leads';
function MyCustomForm() {
const { submit, isSubmitting, error } = useContactForm();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: LeadSubmissionRequest = {
name: formData.get('name') as string,
email: formData.get('email') as string,
message: formData.get('message') as string,
company: formData.get('company') as string,
subject: formData.get('subject') as string,
};
const result = await submit(data);
console.log('Lead ID:', result.lead_id);
};
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<input name="company" placeholder="Company" />
<input name="subject" placeholder="Subject" />
<textarea name="message" placeholder="Message" required />
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Sending...' : 'Send'}
</button>
{error && <p>{error.message}</p>}
</form>
);
}
export default function Page() {
return (
<ContactFormProvider>
<MyCustomForm />
</ContactFormProvider>
);
}API Reference
Components
| Component | Description |
|-----------|-------------|
| ContactPage | Full contact page with form and contact info |
| ContactForm | Standalone contact form with card wrapper |
| ContactInfo | Contact details display component |
Hooks
| Hook | Description |
|------|-------------|
| useContactForm() | Access form context (submit, isSubmitting, error) |
| useContactFormOptional() | Same as above, returns null outside provider |
Types
interface LeadSubmissionRequest {
name: string;
email: string;
message: string;
company?: string;
subject?: string;
site_url?: string;
// ... additional optional fields
}
interface LeadSubmissionResponse {
success: boolean;
message: string;
lead_id?: number;
}ContactPageProps
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| email | string | '[email protected]' | Contact email |
| whatsapp | string | '+1 234 567 890' | WhatsApp number |
| calendlyUrl | string | - | Calendly booking link |
| title | ReactNode | 'Get in Touch' | Page title |
| subtitle | string | - | Page subtitle |
| location | string | 'Remote-first team' | Location text |
| hideCalendly | boolean | false | Hide Calendly card |
| onSuccess | (result) => void | - | Success callback |
ContactFormProps
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| texts | ContactFormTexts | - | Override form texts |
| showCard | boolean | true | Show card wrapper |
| resetOnSuccess | boolean | true | Clear form after submit |
| onSuccess | (result) => void | - | Success callback |
| onError | (error) => void | - | Error callback |
Next.js API Route
Create /app/api/contact/route.ts to proxy requests to your backend:
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const body = await request.json();
const { _apiUrl, ...data } = body;
const apiUrl = _apiUrl || process.env.API_URL;
const response = await fetch(`${apiUrl}/api/ext_leads/leads/submit/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
const result = await response.json();
return NextResponse.json(result, { status: response.status });
}License
MIT
