@djangocfg/layouts 2.1.9 → 2.1.14

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 (106) hide show
  1. package/README.md +53 -161
  2. package/package.json +6 -6
  3. package/src/components/RedirectPage/RedirectPage.tsx +1 -1
  4. package/src/index.ts +0 -6
  5. package/src/layouts/AppLayout/AppLayout.tsx +1 -1
  6. package/src/layouts/AppLayout/BaseApp.tsx +1 -1
  7. package/src/layouts/AuthLayout/AuthContext.tsx +1 -1
  8. package/src/layouts/AuthLayout/OAuthCallback.tsx +1 -1
  9. package/src/layouts/AuthLayout/OAuthProviders.tsx +1 -1
  10. package/src/layouts/PrivateLayout/PrivateLayout.tsx +1 -1
  11. package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +1 -1
  12. package/src/layouts/ProfileLayout/components/AvatarSection.tsx +2 -2
  13. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
  14. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +1 -1
  15. package/src/layouts/_components/UserMenu.tsx +1 -1
  16. package/src/layouts/index.ts +0 -2
  17. package/src/snippets/Analytics/useAnalytics.ts +1 -1
  18. package/src/snippets/McpChat/hooks/useAIChat.ts +16 -3
  19. package/src/snippets/index.ts +0 -3
  20. package/src/auth/README.md +0 -962
  21. package/src/auth/context/AccountsContext.tsx +0 -240
  22. package/src/auth/context/AuthContext.tsx +0 -604
  23. package/src/auth/context/index.ts +0 -4
  24. package/src/auth/context/types.ts +0 -68
  25. package/src/auth/hooks/index.ts +0 -17
  26. package/src/auth/hooks/useAuthForm.ts +0 -332
  27. package/src/auth/hooks/useAuthGuard.ts +0 -25
  28. package/src/auth/hooks/useAuthRedirect.ts +0 -51
  29. package/src/auth/hooks/useAutoAuth.ts +0 -49
  30. package/src/auth/hooks/useGithubAuth.ts +0 -184
  31. package/src/auth/hooks/useLocalStorage.ts +0 -214
  32. package/src/auth/hooks/useProfileCache.ts +0 -146
  33. package/src/auth/hooks/useSessionStorage.ts +0 -189
  34. package/src/auth/index.ts +0 -10
  35. package/src/auth/middlewares/index.ts +0 -1
  36. package/src/auth/middlewares/proxy.ts +0 -32
  37. package/src/auth/server.ts +0 -6
  38. package/src/auth/utils/errors.ts +0 -34
  39. package/src/auth/utils/index.ts +0 -2
  40. package/src/auth/utils/validation.ts +0 -14
  41. package/src/contexts/LeadsContext.tsx +0 -156
  42. package/src/contexts/NewsletterContext.tsx +0 -263
  43. package/src/contexts/SupportContext.tsx +0 -256
  44. package/src/contexts/index.ts +0 -59
  45. package/src/contexts/knowbase/ChatContext.tsx +0 -174
  46. package/src/contexts/knowbase/DocumentsContext.tsx +0 -304
  47. package/src/contexts/knowbase/SessionsContext.tsx +0 -174
  48. package/src/contexts/knowbase/index.ts +0 -61
  49. package/src/contexts/payments/BalancesContext.tsx +0 -65
  50. package/src/contexts/payments/CurrenciesContext.tsx +0 -66
  51. package/src/contexts/payments/OverviewContext.tsx +0 -174
  52. package/src/contexts/payments/PaymentsContext.tsx +0 -132
  53. package/src/contexts/payments/README.md +0 -201
  54. package/src/contexts/payments/RootPaymentsContext.tsx +0 -68
  55. package/src/contexts/payments/index.ts +0 -50
  56. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +0 -92
  57. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +0 -291
  58. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +0 -290
  59. package/src/layouts/PaymentsLayout/components/index.ts +0 -2
  60. package/src/layouts/PaymentsLayout/events.ts +0 -47
  61. package/src/layouts/PaymentsLayout/index.ts +0 -16
  62. package/src/layouts/PaymentsLayout/types.ts +0 -6
  63. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +0 -128
  64. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +0 -142
  65. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
  66. package/src/layouts/PaymentsLayout/views/overview/index.tsx +0 -20
  67. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +0 -276
  68. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
  69. package/src/layouts/PaymentsLayout/views/payments/index.tsx +0 -17
  70. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +0 -273
  71. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +0 -1
  72. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +0 -17
  73. package/src/layouts/SupportLayout/README.md +0 -91
  74. package/src/layouts/SupportLayout/SupportLayout.tsx +0 -179
  75. package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +0 -155
  76. package/src/layouts/SupportLayout/components/MessageInput.tsx +0 -92
  77. package/src/layouts/SupportLayout/components/MessageList.tsx +0 -314
  78. package/src/layouts/SupportLayout/components/TicketCard.tsx +0 -96
  79. package/src/layouts/SupportLayout/components/TicketList.tsx +0 -153
  80. package/src/layouts/SupportLayout/components/index.ts +0 -6
  81. package/src/layouts/SupportLayout/context/SupportLayoutContext.tsx +0 -263
  82. package/src/layouts/SupportLayout/context/index.ts +0 -2
  83. package/src/layouts/SupportLayout/events.ts +0 -33
  84. package/src/layouts/SupportLayout/hooks/index.ts +0 -2
  85. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +0 -119
  86. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +0 -92
  87. package/src/layouts/SupportLayout/index.ts +0 -8
  88. package/src/layouts/SupportLayout/types.ts +0 -21
  89. package/src/snippets/Chat/ChatUIContext.tsx +0 -110
  90. package/src/snippets/Chat/ChatWidget.tsx +0 -476
  91. package/src/snippets/Chat/README.md +0 -122
  92. package/src/snippets/Chat/components/MessageInput.tsx +0 -124
  93. package/src/snippets/Chat/components/MessageList.tsx +0 -169
  94. package/src/snippets/Chat/components/SessionList.tsx +0 -192
  95. package/src/snippets/Chat/components/index.ts +0 -9
  96. package/src/snippets/Chat/hooks/index.ts +0 -6
  97. package/src/snippets/Chat/hooks/useInfiniteSessions.ts +0 -82
  98. package/src/snippets/Chat/index.tsx +0 -45
  99. package/src/snippets/Chat/types.ts +0 -80
  100. package/src/snippets/ContactForm/ContactForm.tsx +0 -346
  101. package/src/snippets/ContactForm/ContactFormProvider.tsx +0 -153
  102. package/src/snippets/ContactForm/ContactInfo.tsx +0 -114
  103. package/src/snippets/ContactForm/ContactPage.tsx +0 -131
  104. package/src/snippets/ContactForm/dynamic.tsx +0 -55
  105. package/src/snippets/ContactForm/index.ts +0 -34
  106. package/src/snippets/ContactForm/types.ts +0 -110
@@ -1,153 +0,0 @@
1
- 'use client';
2
-
3
- import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
4
- import { configureAPI, createLeadsSubmitCreate, Enums } from '@djangocfg/api';
5
- import type {
6
- ContactFormContextValue,
7
- ContactFormProviderProps,
8
- LeadSubmissionData,
9
- LeadSubmissionResult,
10
- } from './types';
11
-
12
- // ============================================================================
13
- // Context
14
- // ============================================================================
15
-
16
- const ContactFormContext = createContext<ContactFormContextValue | undefined>(undefined);
17
-
18
- // ============================================================================
19
- // Helpers
20
- // ============================================================================
21
-
22
- const CONTACT_TYPE_MAP: Record<string, Enums.LeadSubmissionRequestContactType> = {
23
- email: Enums.LeadSubmissionRequestContactType.EMAIL,
24
- telegram: Enums.LeadSubmissionRequestContactType.TELEGRAM,
25
- whatsapp: Enums.LeadSubmissionRequestContactType.WHATSAPP,
26
- phone: Enums.LeadSubmissionRequestContactType.PHONE,
27
- other: Enums.LeadSubmissionRequestContactType.OTHER,
28
- };
29
-
30
- // ============================================================================
31
- // Provider
32
- // ============================================================================
33
-
34
- /**
35
- * ContactFormProvider - Configures API and provides submit functionality
36
- *
37
- * Uses the generated Django-CFG API client for lead submission.
38
- *
39
- * @example
40
- * ```tsx
41
- * import { ContactFormProvider, ContactForm } from '@djangocfg/layouts';
42
- *
43
- * <ContactFormProvider apiUrl="https://api.example.com">
44
- * <ContactForm fields={fields} />
45
- * </ContactFormProvider>
46
- * ```
47
- */
48
- export function ContactFormProvider({ children, apiUrl }: ContactFormProviderProps) {
49
- const [isSubmitting, setIsSubmitting] = useState(false);
50
- const [error, setError] = useState<Error | null>(null);
51
- const [lastResponse, setLastResponse] = useState<LeadSubmissionResult | null>(null);
52
-
53
- // Always use local API route to avoid CORS issues
54
- // Pass apiUrl in request body so route.ts knows where to proxy
55
-
56
- // Submit function - always uses local API route
57
- const submit = useCallback(async (data: LeadSubmissionData): Promise<LeadSubmissionResult> => {
58
- setIsSubmitting(true);
59
- setError(null);
60
-
61
- try {
62
- // Always use local Next.js API route to avoid CORS issues
63
- // Pass apiUrl from ContactPage in the request body so route.ts knows where to proxy
64
- const res = await fetch('/api/contact', {
65
- method: 'POST',
66
- headers: {
67
- 'Content-Type': 'application/json',
68
- },
69
- body: JSON.stringify({
70
- _apiUrl: apiUrl || '', // Pass apiUrl to route.ts for proxying (can be empty for fallback)
71
- name: data.name,
72
- email: data.email,
73
- message: data.message,
74
- company: data.company,
75
- company_site: data.company_site,
76
- contact_type: data.contact_type,
77
- contact_value: data.contact_value,
78
- subject: data.subject,
79
- extra: data.extra,
80
- site_url: data.site_url || (typeof window !== 'undefined' ? window.location.origin : undefined),
81
- }),
82
- });
83
-
84
- if (!res.ok) {
85
- const errorData = await res.json().catch(() => ({ message: 'Failed to submit contact form' }));
86
- throw new Error(errorData.message || `HTTP ${res.status}`);
87
- }
88
-
89
- const response: LeadSubmissionResult = await res.json();
90
-
91
- const result: LeadSubmissionResult = {
92
- success: response.success,
93
- message: response.message,
94
- lead_id: response.lead_id,
95
- };
96
-
97
- setLastResponse(result);
98
- return result;
99
- } catch (err) {
100
- const error = err instanceof Error ? err : new Error(String(err));
101
- setError(error);
102
- throw error;
103
- } finally {
104
- setIsSubmitting(false);
105
- }
106
- }, [apiUrl]);
107
-
108
- // Reset error state
109
- const resetError = useCallback(() => {
110
- setError(null);
111
- }, []);
112
-
113
- const value: ContactFormContextValue = {
114
- apiUrl: '/api/contact', // Always use local endpoint
115
- submit,
116
- isSubmitting,
117
- error,
118
- lastResponse,
119
- resetError,
120
- };
121
-
122
- return (
123
- <ContactFormContext.Provider value={value}>
124
- {children}
125
- </ContactFormContext.Provider>
126
- );
127
- }
128
-
129
- // ============================================================================
130
- // Hooks
131
- // ============================================================================
132
-
133
- /**
134
- * useContactForm - Access contact form context
135
- *
136
- * Must be used within ContactFormProvider
137
- */
138
- export function useContactForm(): ContactFormContextValue {
139
- const context = useContext(ContactFormContext);
140
- if (!context) {
141
- throw new Error('useContactForm must be used within ContactFormProvider');
142
- }
143
- return context;
144
- }
145
-
146
- /**
147
- * useContactFormOptional - Access contact form context (optional)
148
- *
149
- * Returns null if not within ContactFormProvider
150
- */
151
- export function useContactFormOptional(): ContactFormContextValue | null {
152
- return useContext(ContactFormContext) ?? null;
153
- }
@@ -1,114 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
- import {
5
- Card,
6
- CardHeader,
7
- CardTitle,
8
- CardContent,
9
- Button,
10
- cn,
11
- } from '@djangocfg/ui-nextjs';
12
- import type { ContactInfoProps, ContactDetail } from './types';
13
- import { DEFAULT_INFO_TITLE } from './types';
14
-
15
- /**
16
- * ContactInfo - Display contact information with optional action card
17
- *
18
- * @example
19
- * ```tsx
20
- * import { ContactInfo } from '@djangocfg/layouts';
21
- * import { Mail, Phone, MapPin, Calendar } from 'lucide-react';
22
- *
23
- * const details = [
24
- * { icon: <Mail />, label: 'Email', value: 'hello@example.com', href: 'mailto:hello@example.com' },
25
- * { icon: <Phone />, label: 'Phone', value: '+1 234 567 890', href: 'tel:+1234567890' },
26
- * { icon: <MapPin />, label: 'Address', value: '123 Main St, City' },
27
- * ];
28
- *
29
- * <ContactInfo
30
- * details={details}
31
- * action={{
32
- * title: 'Schedule a Meeting',
33
- * description: 'Book a 30-minute call',
34
- * button: {
35
- * icon: <Calendar />,
36
- * label: 'Book Now',
37
- * href: 'https://calendly.com/...',
38
- * },
39
- * }}
40
- * />
41
- * ```
42
- */
43
- export function ContactInfo({
44
- details,
45
- title = DEFAULT_INFO_TITLE,
46
- action,
47
- className,
48
- }: ContactInfoProps) {
49
- const renderDetail = (detail: ContactDetail, index: number) => {
50
- const content = (
51
- <div className="flex items-start gap-3">
52
- <div className="text-muted-foreground mt-0.5">{detail.icon}</div>
53
- <div>
54
- <p className="text-sm text-muted-foreground">{detail.label}</p>
55
- <p className="font-medium">{detail.value}</p>
56
- </div>
57
- </div>
58
- );
59
-
60
- if (detail.href) {
61
- return (
62
- <a
63
- key={index}
64
- href={detail.href}
65
- target={detail.external !== false ? '_blank' : undefined}
66
- rel={detail.external !== false ? 'noopener noreferrer' : undefined}
67
- className="block hover:bg-muted/50 rounded-lg p-2 -m-2 transition-colors"
68
- >
69
- {content}
70
- </a>
71
- );
72
- }
73
-
74
- return <div key={index}>{content}</div>;
75
- };
76
-
77
- return (
78
- <div className={cn('space-y-6', className)}>
79
- {/* Contact Details Card */}
80
- <Card>
81
- <CardHeader>
82
- <CardTitle>{title}</CardTitle>
83
- </CardHeader>
84
- <CardContent className="space-y-4">
85
- {details.map(renderDetail)}
86
- </CardContent>
87
- </Card>
88
-
89
- {/* Action Card */}
90
- {action && (
91
- <Card className="bg-primary/5 border-primary/20">
92
- <CardContent className="pt-6">
93
- <h3 className="font-semibold mb-2">{action.title}</h3>
94
- {action.description && (
95
- <p className="text-sm text-muted-foreground mb-4">
96
- {action.description}
97
- </p>
98
- )}
99
- <Button asChild className="w-full">
100
- <a
101
- href={action.button.href}
102
- target={action.button.external !== false ? '_blank' : undefined}
103
- rel={action.button.external !== false ? 'noopener noreferrer' : undefined}
104
- >
105
- {action.button.icon}
106
- <span className="ml-2">{action.button.label}</span>
107
- </a>
108
- </Button>
109
- </CardContent>
110
- </Card>
111
- )}
112
- </div>
113
- );
114
- }
@@ -1,131 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
- import { Mail, MapPin, Calendar, MessageCircle } from 'lucide-react';
5
- import { ContactFormBase as ContactForm } from './ContactForm';
6
- import { ContactInfo } from './ContactInfo';
7
- import type { ContactDetail, LeadSubmissionResult } from './types';
8
-
9
- // ============================================================================
10
- // Config
11
- // ============================================================================
12
-
13
- const DEFAULT_CONFIG = {
14
- apiUrl: 'https://api.reforms.ai',
15
- email: 'markolofsen@gmail.com',
16
- whatsapp: '+62 813 39646301',
17
- calendly: 'https://calendly.com/markolofsen/meeting',
18
- };
19
-
20
- // ============================================================================
21
- // Props
22
- // ============================================================================
23
-
24
- export interface ContactPageProps {
25
- /** Override API URL (defaults to DEFAULT_CONFIG.apiUrl) */
26
- apiUrl?: string;
27
- /** Override email */
28
- email?: string;
29
- /** Override whatsapp */
30
- whatsapp?: string;
31
- /** Override calendly link */
32
- calendlyUrl?: string;
33
- /** Page title */
34
- title?: React.ReactNode;
35
- /** Page subtitle */
36
- subtitle?: string;
37
- /** Location text */
38
- location?: string;
39
- /** Hide calendly action card */
40
- hideCalendly?: boolean;
41
- /** Additional className */
42
- className?: string;
43
- /** Callback after successful submit */
44
- onSuccess?: (result: LeadSubmissionResult) => void;
45
- }
46
-
47
- // ============================================================================
48
- // Component
49
- // ============================================================================
50
-
51
- /**
52
- * ContactPageBase - Pre-configured contact page component
53
- *
54
- * NOTE: Use ContactPage from index.ts which is dynamically imported (ssr: false)
55
- *
56
- * @example
57
- * ```tsx
58
- * import { ContactPage } from '@djangocfg/layouts';
59
- * <ContactPage />
60
- * ```
61
- */
62
- export function ContactPageBase({
63
- apiUrl = DEFAULT_CONFIG.apiUrl,
64
- email = DEFAULT_CONFIG.email,
65
- whatsapp = DEFAULT_CONFIG.whatsapp,
66
- calendlyUrl = DEFAULT_CONFIG.calendly,
67
- title = 'Get in Touch',
68
- subtitle = "Have a question or want to work together? We'd love to hear from you.",
69
- location = 'Remote-first team',
70
- hideCalendly = false,
71
- className,
72
- onSuccess,
73
- }: ContactPageProps) {
74
- // Format phone for WhatsApp link (remove spaces and special chars)
75
- const whatsappPhone = whatsapp.replace(/[\s\-\(\)]/g, '');
76
-
77
- const contactDetails: ContactDetail[] = [
78
- {
79
- icon: <Mail className="h-5 w-5" />,
80
- label: 'Email',
81
- value: email,
82
- href: `mailto:${email}`,
83
- },
84
- {
85
- icon: <MessageCircle className="h-5 w-5" />,
86
- label: 'WhatsApp',
87
- value: whatsapp,
88
- href: `https://wa.me/${whatsappPhone}`,
89
- },
90
- {
91
- icon: <MapPin className="h-5 w-5" />,
92
- label: 'Location',
93
- value: location,
94
- },
95
- ];
96
-
97
- return (
98
- <div className={className}>
99
- {/* Header */}
100
- <div className="text-center mb-8 md:mb-12">
101
- <h1 className="text-3xl sm:text-4xl md:text-5xl font-bold mb-4">
102
- {title}
103
- </h1>
104
- <p className="text-base sm:text-lg text-muted-foreground max-w-2xl mx-auto px-4">
105
- {subtitle}
106
- </p>
107
- </div>
108
-
109
- {/* Content Grid */}
110
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 w-full">
111
- <div>
112
- <ContactForm apiUrl={apiUrl} onSuccess={onSuccess} />
113
- </div>
114
- <div>
115
- <ContactInfo
116
- details={contactDetails}
117
- action={hideCalendly ? undefined : {
118
- title: 'Schedule a Meeting',
119
- description: 'Book a time that works for you',
120
- button: {
121
- icon: <Calendar className="h-4 w-4" />,
122
- label: 'Book a Call',
123
- href: calendlyUrl,
124
- },
125
- }}
126
- />
127
- </div>
128
- </div>
129
- </div>
130
- );
131
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * Dynamic ContactForm components (ssr: false)
3
- *
4
- * Avoids hydration mismatch when using localStorage for form drafts.
5
- * Components are loaded client-side only.
6
- */
7
-
8
- 'use client';
9
-
10
- import dynamic from 'next/dynamic';
11
- import { Skeleton } from '@djangocfg/ui-nextjs';
12
- import type { ContactFormProps } from './ContactForm';
13
- import type { ContactPageProps } from './ContactPage';
14
-
15
- function ContactFormSkeleton() {
16
- return (
17
- <div className="space-y-4">
18
- <Skeleton className="w-full h-10" />
19
- <Skeleton className="w-full h-10" />
20
- <Skeleton className="w-full h-10" />
21
- <Skeleton className="w-full h-24" />
22
- <Skeleton className="w-full h-10" />
23
- </div>
24
- );
25
- }
26
-
27
- function ContactPageSkeleton() {
28
- return (
29
- <div>
30
- <div className="text-center mb-8 md:mb-12">
31
- <Skeleton className="w-64 h-12 mx-auto mb-4" />
32
- <Skeleton className="w-96 h-6 mx-auto" />
33
- </div>
34
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
35
- <div className="lg:col-span-2">
36
- <ContactFormSkeleton />
37
- </div>
38
- <div className="space-y-4">
39
- <Skeleton className="w-full h-32" />
40
- <Skeleton className="w-full h-24" />
41
- </div>
42
- </div>
43
- </div>
44
- );
45
- }
46
-
47
- export const ContactForm = dynamic<ContactFormProps>(
48
- () => import('./ContactForm').then((mod) => mod.ContactFormBase),
49
- { ssr: false, loading: () => <ContactFormSkeleton /> }
50
- );
51
-
52
- export const ContactPage = dynamic<ContactPageProps>(
53
- () => import('./ContactPage').then((mod) => mod.ContactPageBase),
54
- { ssr: false, loading: () => <ContactPageSkeleton /> }
55
- );
@@ -1,34 +0,0 @@
1
- // ============================================================================
2
- // ContactForm - Contact form using Django-CFG Lead API
3
- // ============================================================================
4
-
5
- // Components (dynamic import, ssr: false - no hydration issues)
6
- export { ContactForm, ContactPage } from './dynamic';
7
- export { ContactInfo } from './ContactInfo';
8
-
9
- // Types
10
- export type { ContactFormProps } from './ContactForm';
11
- export type { ContactPageProps } from './ContactPage';
12
-
13
- // Provider & Hooks
14
- export {
15
- ContactFormProvider,
16
- useContactForm,
17
- useContactFormOptional,
18
- } from './ContactFormProvider';
19
-
20
- // Types
21
- export type {
22
- ContactFormProviderProps,
23
- ContactFormContextValue,
24
- LeadSubmissionData,
25
- LeadSubmissionResult,
26
- UseContactFormReturn,
27
- ContactFormTexts,
28
- ContactDetail,
29
- ContactAction,
30
- ContactInfoProps,
31
- } from './types';
32
-
33
- // Constants
34
- export { DEFAULT_FORM_TEXTS, DEFAULT_INFO_TITLE } from './types';
@@ -1,110 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import type { Schemas } from '@djangocfg/api';
3
-
4
- // ============================================================================
5
- // Re-export API Types
6
- // ============================================================================
7
-
8
- /** Lead submission request data - uses generated API type */
9
- export type LeadSubmissionData = Schemas.LeadSubmissionRequest;
10
-
11
- /** Lead submission response - uses generated API type */
12
- export type LeadSubmissionResult = Schemas.LeadSubmissionResponse;
13
-
14
- // ============================================================================
15
- // Provider Types
16
- // ============================================================================
17
-
18
- export interface ContactFormProviderProps {
19
- children: ReactNode;
20
- /**
21
- * API base URL for lead submission
22
- * If not provided or empty, will use local Next.js API route (/api/contact)
23
- * @example "https://api.example.com" or undefined to use /api/contact
24
- */
25
- apiUrl?: string;
26
- }
27
-
28
- // ============================================================================
29
- // Hook Types
30
- // ============================================================================
31
-
32
- export interface UseContactFormReturn {
33
- /** Submit lead data */
34
- submit: (data: LeadSubmissionData) => Promise<LeadSubmissionResult>;
35
- /** Is currently submitting */
36
- isSubmitting: boolean;
37
- /** Last error */
38
- error: Error | null;
39
- /** Last successful response */
40
- lastResponse: LeadSubmissionResult | null;
41
- /** Reset error state */
42
- resetError: () => void;
43
- }
44
-
45
- // ============================================================================
46
- // Context Types
47
- // ============================================================================
48
-
49
- export interface ContactFormContextValue extends UseContactFormReturn {
50
- /** API base URL */
51
- apiUrl: string;
52
- }
53
-
54
- // ============================================================================
55
- // Form Texts
56
- // ============================================================================
57
-
58
- export interface ContactFormTexts {
59
- title?: string;
60
- description?: string;
61
- submitText?: string;
62
- loadingText?: string;
63
- successTitle?: string;
64
- successMessage?: string;
65
- errorTitle?: string;
66
- errorMessage?: string;
67
- }
68
-
69
- export const DEFAULT_FORM_TEXTS: Required<ContactFormTexts> = {
70
- title: 'Send us a message',
71
- description: "Fill out the form below and we'll get back to you as soon as possible",
72
- submitText: 'Send Message',
73
- loadingText: 'Sending...',
74
- successTitle: 'Message Sent!',
75
- successMessage: "We'll get back to you within 24 hours.",
76
- errorTitle: 'Error',
77
- errorMessage: 'Failed to send message. Please try again.',
78
- };
79
-
80
- // ============================================================================
81
- // Contact Info Types
82
- // ============================================================================
83
-
84
- export interface ContactDetail {
85
- icon: ReactNode;
86
- label: string;
87
- value: string;
88
- href?: string;
89
- external?: boolean;
90
- }
91
-
92
- export interface ContactAction {
93
- icon: ReactNode;
94
- label: string;
95
- href: string;
96
- external?: boolean;
97
- }
98
-
99
- export interface ContactInfoProps {
100
- details: ContactDetail[];
101
- title?: string;
102
- action?: {
103
- title: string;
104
- description?: string;
105
- button: ContactAction;
106
- };
107
- className?: string;
108
- }
109
-
110
- export const DEFAULT_INFO_TITLE = 'Contact Information';