claudmax 2.0.0 → 2.0.1

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 (124) hide show
  1. package/claudmax-1.0.16.tgz +0 -0
  2. package/{packages/cli/index.js → index.js} +2 -0
  3. package/package.json +27 -55
  4. package/.claude/settings.local.json +0 -7
  5. package/.env.example +0 -24
  6. package/.github/workflows/publish.yml +0 -31
  7. package/README.md +0 -178
  8. package/claudmax-mcp-1.0.2.tgz +0 -0
  9. package/help +0 -0
  10. package/help-wal +0 -0
  11. package/next-env.d.ts +0 -6
  12. package/next.config.mjs +0 -43
  13. package/packages/cli/claudmax-1.0.16.tgz +0 -0
  14. package/packages/cli/package.json +0 -33
  15. package/packages/mcp/claudmax-mcp-1.0.0.tgz +0 -0
  16. package/packages/mcp/claudmax-mcp-1.0.1.tgz +0 -0
  17. package/packages/mcp/claudmax-mcp-1.0.2.tgz +0 -0
  18. package/packages/mcp/claudmax-mcp-1.0.3.tgz +0 -0
  19. package/packages/mcp/index.js +0 -129
  20. package/packages/mcp/package-lock.json +0 -1146
  21. package/packages/mcp/package.json +0 -32
  22. package/postcss.config.mjs +0 -6
  23. package/prisma/schema.prisma +0 -130
  24. package/prisma/seed.ts +0 -27
  25. package/public/favicon.svg +0 -10
  26. package/public/robots.txt +0 -10
  27. package/run_build.sh +0 -4
  28. package/scripts/migrate-plans.js +0 -98
  29. package/scripts/seed-blog.ts +0 -1014
  30. package/src/app/admin/dashboard/AdminDashboardClient.tsx +0 -1546
  31. package/src/app/admin/dashboard/page.tsx +0 -13
  32. package/src/app/admin/page.tsx +0 -132
  33. package/src/app/api/admin/auth/me/route.ts +0 -34
  34. package/src/app/api/admin/health/route.ts +0 -110
  35. package/src/app/api/admin/keys/[id]/route.ts +0 -116
  36. package/src/app/api/admin/keys/route.ts +0 -192
  37. package/src/app/api/admin/keys-list/route.ts +0 -81
  38. package/src/app/api/admin/login/route.ts +0 -72
  39. package/src/app/api/admin/logout/route.ts +0 -8
  40. package/src/app/api/admin/migrate/route.ts +0 -133
  41. package/src/app/api/admin/plans/[id]/route.ts +0 -65
  42. package/src/app/api/admin/plans/route.ts +0 -66
  43. package/src/app/api/admin/posts/[id]/route.ts +0 -81
  44. package/src/app/api/admin/posts/route.ts +0 -83
  45. package/src/app/api/admin/seed/route.ts +0 -145
  46. package/src/app/api/admin/settings/route.ts +0 -44
  47. package/src/app/api/admin/stats/route.ts +0 -74
  48. package/src/app/api/admin/users/[id]/route.ts +0 -166
  49. package/src/app/api/admin/users/plans/route.ts +0 -45
  50. package/src/app/api/admin/users/route.ts +0 -202
  51. package/src/app/api/blog/[slug]/route.ts +0 -22
  52. package/src/app/api/blog/route.ts +0 -40
  53. package/src/app/api/cron/daily-status/route.ts +0 -208
  54. package/src/app/api/support/chat/route.ts +0 -55
  55. package/src/app/api/support/chat/session/route.ts +0 -62
  56. package/src/app/api/support/chat/stream/route.ts +0 -44
  57. package/src/app/api/support/email/route.ts +0 -63
  58. package/src/app/api/tools/understand_image/route.ts +0 -113
  59. package/src/app/api/tools/upload/route.ts +0 -179
  60. package/src/app/api/tools/web_search/route.ts +0 -99
  61. package/src/app/api/v1/audio/route.ts +0 -67
  62. package/src/app/api/v1/audio/speech/route.ts +0 -73
  63. package/src/app/api/v1/chat/completions/route.ts +0 -3
  64. package/src/app/api/v1/chat/route.ts +0 -1079
  65. package/src/app/api/v1/images/generations/route.ts +0 -93
  66. package/src/app/api/v1/info/route.ts +0 -30
  67. package/src/app/api/v1/key-status/route.ts +0 -109
  68. package/src/app/api/v1/key-status/stream/route.ts +0 -135
  69. package/src/app/api/v1/messages/count_tokens/route.ts +0 -22
  70. package/src/app/api/v1/messages/route.ts +0 -807
  71. package/src/app/api/v1/models/route.ts +0 -14
  72. package/src/app/api/v1/route.ts +0 -18
  73. package/src/app/blog/BlogClient.tsx +0 -193
  74. package/src/app/blog/[slug]/page.tsx +0 -117
  75. package/src/app/blog/page.tsx +0 -20
  76. package/src/app/check-usage/CheckUsageClient.tsx +0 -186
  77. package/src/app/check-usage/layout.tsx +0 -11
  78. package/src/app/check-usage/page.tsx +0 -15
  79. package/src/app/docs/layout.tsx +0 -16
  80. package/src/app/docs/page.tsx +0 -1055
  81. package/src/app/faq/FAQClient.tsx +0 -227
  82. package/src/app/faq/page.tsx +0 -21
  83. package/src/app/globals.css +0 -75
  84. package/src/app/layout.tsx +0 -80
  85. package/src/app/page.tsx +0 -256
  86. package/src/app/reseller/ResellerClient.tsx +0 -435
  87. package/src/app/reseller/page.tsx +0 -15
  88. package/src/app/setup.ps1/route.ts +0 -79
  89. package/src/app/setup.sh/route.ts +0 -113
  90. package/src/app/sitemap.ts +0 -50
  91. package/src/app/status/StatusClient.tsx +0 -103
  92. package/src/app/status/layout.tsx +0 -11
  93. package/src/app/status/page.tsx +0 -15
  94. package/src/app/support/SupportClient.tsx +0 -411
  95. package/src/app/support/page.tsx +0 -25
  96. package/src/app/v1/chat/completions/route.ts +0 -3
  97. package/src/app/v1/chat/route.ts +0 -4
  98. package/src/app/v1/messages/route.ts +0 -3
  99. package/src/components/Footer.tsx +0 -120
  100. package/src/components/Header.tsx +0 -131
  101. package/src/components/landing/features.tsx +0 -99
  102. package/src/components/ui/badge.tsx +0 -32
  103. package/src/components/ui/button.tsx +0 -46
  104. package/src/components/ui/card.tsx +0 -50
  105. package/src/components/ui/dialog.tsx +0 -97
  106. package/src/components/ui/dropdown-menu.tsx +0 -156
  107. package/src/components/ui/input.tsx +0 -21
  108. package/src/components/ui/label.tsx +0 -15
  109. package/src/components/ui/separator.tsx +0 -22
  110. package/src/components/ui/switch.tsx +0 -27
  111. package/src/components/ui/tabs.tsx +0 -51
  112. package/src/components/ui/toast.tsx +0 -103
  113. package/src/lib/auth.ts +0 -45
  114. package/src/lib/prisma.ts +0 -20
  115. package/src/lib/providers.ts +0 -158
  116. package/src/lib/security.ts +0 -165
  117. package/src/lib/utils.ts +0 -14
  118. package/src/middleware.ts +0 -30
  119. package/tailwind.config.ts +0 -53
  120. package/tsconfig.json +0 -41
  121. package/tsconfig.tsbuildinfo +0 -1
  122. package/vercel.json +0 -8
  123. /package/{packages/cli/bin → bin}/claudmax.js +0 -0
  124. /package/{packages/cli/claudmax-1.0.17.tgz → claudmax-1.0.17.tgz} +0 -0
@@ -1,50 +0,0 @@
1
- import { MetadataRoute } from 'next';
2
-
3
- export default function sitemap(): MetadataRoute.Sitemap {
4
- const baseUrl = 'https://claudmax.pro';
5
-
6
- return [
7
- {
8
- url: baseUrl,
9
- lastModified: new Date(),
10
- changeFrequency: 'weekly',
11
- priority: 1.0,
12
- },
13
- {
14
- url: `${baseUrl}/docs`,
15
- lastModified: new Date(),
16
- changeFrequency: 'weekly',
17
- priority: 0.9,
18
- },
19
- {
20
- url: `${baseUrl}/status`,
21
- lastModified: new Date(),
22
- changeFrequency: 'daily',
23
- priority: 0.7,
24
- },
25
- {
26
- url: `${baseUrl}/check-usage`,
27
- lastModified: new Date(),
28
- changeFrequency: 'weekly',
29
- priority: 0.6,
30
- },
31
- {
32
- url: `${baseUrl}/support`,
33
- lastModified: new Date(),
34
- changeFrequency: 'monthly',
35
- priority: 0.5,
36
- },
37
- {
38
- url: `${baseUrl}/faq`,
39
- lastModified: new Date(),
40
- changeFrequency: 'monthly',
41
- priority: 0.5,
42
- },
43
- {
44
- url: `${baseUrl}/blog`,
45
- lastModified: new Date(),
46
- changeFrequency: 'weekly',
47
- priority: 0.8,
48
- },
49
- ];
50
- }
@@ -1,103 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useEffect } from 'react';
4
- import Header from '@/components/Header';
5
- import Footer from '@/components/Footer';
6
-
7
- const ENDPOINTS = [
8
- { name: 'Chat Completions', path: '/api/v1/chat/completions', desc: 'Core chat API' },
9
- { name: 'Messages', path: '/api/v1/messages', desc: 'Claude messages API' },
10
- { name: 'Key Status', path: '/api/v1/key-status', desc: 'Usage tracking' },
11
- { name: 'Models', path: '/api/v1/models', desc: 'Model list' },
12
- { name: 'Image Generation', path: '/api/v1/images/generations', desc: 'Text-to-image API' },
13
- { name: 'Audio TTS', path: '/api/v1/audio/speech', desc: 'Text-to-speech API' },
14
- ];
15
-
16
- function StatusBadge({ up }: { up: boolean }) {
17
- return (
18
- <span className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium ${
19
- up ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'
20
- }`}>
21
- <span className={`w-2 h-2 rounded-full ${up ? 'bg-green-500' : 'bg-red-500'}`} />
22
- {up ? 'Operational' : 'Down'}
23
- </span>
24
- );
25
- }
26
-
27
- export default function StatusClient() {
28
- const [statuses, setStatuses] = useState<Record<string, boolean>>({});
29
- const [loading, setLoading] = useState(true);
30
- const [checkedAt, setCheckedAt] = useState<string>('');
31
-
32
- useEffect(() => {
33
- async function check() {
34
- setLoading(true);
35
- const results: Record<string, boolean> = {};
36
- for (const ep of ENDPOINTS) {
37
- try {
38
- const res = await fetch(`${location.origin}${ep.path}`, {
39
- method: 'POST',
40
- headers: { 'Content-Type': 'application/json' },
41
- body: JSON.stringify({ apiKey: 'test' }),
42
- signal: AbortSignal.timeout(5000),
43
- });
44
- // Any non-5xx response means the endpoint is up and responding (400/401 = auth required, but endpoint works)
45
- results[ep.path] = !(res.status >= 500 && res.status < 600);
46
- } catch {
47
- results[ep.path] = false;
48
- }
49
- }
50
- setStatuses(results);
51
- setCheckedAt(new Date().toLocaleTimeString());
52
- setLoading(false);
53
- }
54
- check();
55
- const interval = setInterval(check, 30000);
56
- return () => clearInterval(interval);
57
- }, []);
58
-
59
- const allUp = Object.values(statuses).length > 0 && Object.values(statuses).every(Boolean);
60
- const uptime = Object.values(statuses).filter(Boolean).length;
61
-
62
- return (
63
- <div className="min-h-screen bg-gray-50 flex flex-col">
64
- <Header />
65
- <main className="flex-1">
66
- <section className="bg-gradient-to-br from-indigo-600 via-purple-600 to-indigo-800 text-white py-14">
67
- <div className="max-w-3xl mx-auto px-6 text-center">
68
- <div className="text-sm font-medium text-indigo-200 mb-2">System Status</div>
69
- <div className="text-4xl font-bold mb-2">{allUp ? 'All Systems Operational' : `${uptime}/${ENDPOINTS.length} Systems Up`}</div>
70
- <div className="text-sm text-indigo-100">
71
- {loading ? 'Checking...' : `Last checked at ${checkedAt} · Updates every 30 seconds`}
72
- </div>
73
- </div>
74
- </section>
75
-
76
- <div className="max-w-3xl mx-auto px-6 -mt-8 pb-20">
77
- <div className="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
78
- <div className="px-6 py-4 border-b border-gray-100 flex items-center justify-between">
79
- <div className="text-sm font-semibold text-gray-900">Service Status</div>
80
- <div className="text-xs text-gray-400">{ENDPOINTS.length} endpoints monitored</div>
81
- </div>
82
- <div className="divide-y divide-gray-100">
83
- {ENDPOINTS.map(ep => (
84
- <div key={ep.path} className="flex items-center justify-between px-6 py-4 hover:bg-gray-50">
85
- <div>
86
- <div className="text-sm font-medium text-gray-900">{ep.name}</div>
87
- <div className="text-xs text-gray-400">{ep.desc} · {ep.path}</div>
88
- </div>
89
- {loading ? (
90
- <span className="text-xs text-gray-400">Checking...</span>
91
- ) : (
92
- <StatusBadge up={statuses[ep.path] ?? false} />
93
- )}
94
- </div>
95
- ))}
96
- </div>
97
- </div>
98
- </div>
99
- </main>
100
- <Footer />
101
- </div>
102
- );
103
- }
@@ -1,11 +0,0 @@
1
- import type { Metadata } from 'next';
2
-
3
- export const metadata: Metadata = {
4
- title: 'API Status — ClaudMax',
5
- description: 'Live status of ClaudMax API gateway services including key management, usage tracking, and OpenRouter proxy.',
6
- keywords: 'API status, ClaudMax status, uptime, API health',
7
- };
8
-
9
- export default function StatusLayout({ children }: { children: React.ReactNode }) {
10
- return children;
11
- }
@@ -1,15 +0,0 @@
1
- import type { Metadata } from 'next';
2
- import StatusClient from './StatusClient';
3
-
4
- export const metadata: Metadata = {
5
- title: 'API Status | ClaudMax',
6
- description: 'Real-time system status for ClaudMax — API uptime, response times, and service health. Check if all endpoints are operational.',
7
- keywords: 'ClaudMax status, Claude API status, API uptime, system status, API health',
8
- openGraph: { title: 'API Status | ClaudMax', description: 'Real-time system status for ClaudMax API.', type: 'website', url: 'https://claudmax.pro/status', siteName: 'ClaudMax' },
9
- twitter: { card: 'summary_large_image', title: 'API Status | ClaudMax' },
10
- robots: { index: true, follow: true },
11
- };
12
-
13
- export default function StatusPage() {
14
- return <StatusClient />;
15
- }
@@ -1,411 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useEffect, useRef } from 'react';
4
- import Header from '@/components/Header';
5
- import Footer from '@/components/Footer';
6
- import { MessageCircle, Send, X, ChevronDown, ChevronUp, ChevronRight, CheckCircle2, Mail, Phone } from 'lucide-react';
7
-
8
- const WHATSAPP = '917669217156';
9
-
10
- const FAQS = [
11
- {
12
- q: 'How do I get started with ClaudMax?',
13
- a: 'Sign up at claudmax.pro, create an API key from your dashboard, then use it with any Claude-compatible SDK. Your key is active immediately.',
14
- },
15
- {
16
- q: 'What models are available on ClaudMax?',
17
- a: 'ClaudMax provides access to Opus 4.6, Sonnet 4.6, Haiku 4.5, Vision, Image Generation, and Audio TTS — all through a unified API endpoint.',
18
- },
19
- {
20
- q: 'How does usage tracking work?',
21
- a: 'Usage is tracked per 5-hour rolling window. Your dashboard shows real-time token and request counts. Limits reset automatically when the window expires.',
22
- },
23
- {
24
- q: 'Can I use ClaudMax with Claude Code, Cursor, or Windsurf?',
25
- a: 'Yes. Set ANTHROPIC_BASE_URL=https://api.claudmax.pro and ANTHROPIC_API_KEY=your-key. Works with Claude Code, Cursor, Windsurf, Cline, Roo Code, and any Anthropic SDK.',
26
- },
27
- {
28
- q: 'What is the difference between the plans?',
29
- a: 'Free: 100 requests / 500K tokens per 5h. 5x: 500 requests / 5M tokens. 20x: 2,000 requests / 20M tokens. All plans include a 3x display multiplier on your dashboard.',
30
- },
31
- {
32
- q: 'How do I upgrade or change my plan?',
33
- a: 'Contact us via the chat form below or WhatsApp. We offer custom plans for high-volume users and resellers.',
34
- },
35
- {
36
- q: 'Is my API key secure?',
37
- a: 'Yes. Keys are hashed in our database, transmitted over HTTPS, and can be revoked instantly from your dashboard. Never share your key publicly.',
38
- },
39
- {
40
- q: 'Do you offer refunds?',
41
- a: 'We offer refunds within 7 days of purchase for any billing-related issues. Contact support for assistance.',
42
- },
43
- {
44
- q: 'How do I contact support?',
45
- a: 'Use the chat below for real-time help, message us on WhatsApp at +91-7669217156, or email codewpremium@gmail.com. We respond within 2 hours.',
46
- },
47
- {
48
- q: 'Can I resell ClaudMax keys?',
49
- a: 'Yes. We have a reseller program with bulk pricing. Contact us to apply — approved resellers get access to a dedicated dashboard and custom key generation limits.',
50
- },
51
- ];
52
-
53
- function ChatWidget() {
54
- const [open, setOpen] = useState(false);
55
- const [step, setStep] = useState<'form' | 'chat' | 'done'>('form');
56
- const [name, setName] = useState('');
57
- const [whatsapp, setWhatsapp] = useState('');
58
- const [email, setEmail] = useState('');
59
- const [message, setMessage] = useState('');
60
- const [messages, setMessages] = useState<Array<{ sender: string; content: string; createdAt: string }>>([]);
61
- const [loading, setLoading] = useState(false);
62
- const [sessionId, setSessionId] = useState<string | null>(null);
63
- const bottomRef = useRef<HTMLDivElement>(null);
64
-
65
- useEffect(() => {
66
- bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
67
- }, [messages]);
68
-
69
- // Poll for new messages when chat is open
70
- useEffect(() => {
71
- if (step !== 'chat' || !sessionId) return;
72
- const interval = setInterval(async () => {
73
- try {
74
- const res = await fetch(`/api/support/chat?sessionId=${sessionId}`);
75
- const data = await res.json();
76
- if (data.messages) {
77
- setMessages(data.messages.map((m: any) => ({
78
- sender: m.sender,
79
- content: m.content,
80
- createdAt: m.createdAt,
81
- })));
82
- }
83
- } catch { /* ignore */ }
84
- }, 4000);
85
- return () => clearInterval(interval);
86
- }, [step, sessionId]);
87
-
88
- async function handleStart(e: React.FormEvent) {
89
- e.preventDefault();
90
- if (!name.trim() || !email.trim()) return;
91
- setLoading(true);
92
- try {
93
- // Send email notification
94
- await fetch('/api/support/email', {
95
- method: 'POST',
96
- headers: { 'Content-Type': 'application/json' },
97
- body: JSON.stringify({ name, whatsapp, email, subject: 'Chat Request', content: message }),
98
- });
99
-
100
- // Build WhatsApp URL with pre-filled message
101
- const whatsappMsg = `Hi ClaudMax Team,
102
-
103
- Name: ${name}
104
- Email: ${email}
105
- WhatsApp: ${whatsapp || 'Not provided'}
106
-
107
- Message: ${message || 'No initial message'}`.trim();
108
-
109
- const whatsappUrl = `https://wa.me/${WHATSAPP}?text=${encodeURIComponent(whatsappMsg)}`;
110
- window.open(whatsappUrl, '_blank');
111
-
112
- setStep('done');
113
- setTimeout(() => setStep('form'), 3000);
114
- } catch { /* ignore */ }
115
- setLoading(false);
116
- }
117
-
118
- async function handleSend(e: React.FormEvent) {
119
- e.preventDefault();
120
- if (!message.trim() || !sessionId) return;
121
- const text = message.trim();
122
- setMessages(prev => [...prev, { sender: 'visitor', content: text, createdAt: new Date().toISOString() }]);
123
- setMessage('');
124
- try {
125
- await fetch('/api/support/chat', {
126
- method: 'POST',
127
- headers: { 'Content-Type': 'application/json' },
128
- body: JSON.stringify({ sessionId, content: text, sender: 'visitor' }),
129
- });
130
- } catch { /* ignore */ }
131
- }
132
-
133
- return (
134
- <div className="fixed bottom-4 right-4 z-50 flex flex-col items-end gap-2">
135
- {open && (
136
- <div className="bg-white rounded-2xl shadow-2xl border border-gray-200 w-[380px] max-h-[560px] flex flex-col overflow-hidden mb-2">
137
- {/* Header */}
138
- <div className="bg-gradient-to-r from-indigo-600 to-purple-600 px-5 py-4 flex items-center justify-between">
139
- <div>
140
- <div className="text-white font-semibold text-sm">ClaudMax Support</div>
141
- <div className="text-indigo-200 text-xs flex items-center gap-1 mt-0.5">
142
- <span className="w-2 h-2 rounded-full bg-green-400 inline-block animate-pulse" />
143
- Online — typically replies in 2h
144
- </div>
145
- </div>
146
- <button onClick={() => setOpen(false)} className="text-white/70 hover:text-white"><X className="w-5 h-5" /></button>
147
- </div>
148
-
149
- {step === 'form' ? (
150
- <form onSubmit={handleStart} className="p-5 flex flex-col gap-3 flex-1">
151
- <p className="text-sm text-gray-600 -mt-1">Fill in your details to start chatting with our team.</p>
152
- <div>
153
- <label className="text-xs font-medium text-gray-700 mb-1 block">Your Name *</label>
154
- <input required value={name} onChange={e => setName(e.target.value)} placeholder="Priya Sharma"
155
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent" />
156
- </div>
157
- <div>
158
- <label className="text-xs font-medium text-gray-700 mb-1 block">WhatsApp Number</label>
159
- <input value={whatsapp} onChange={e => setWhatsapp(e.target.value)} placeholder="+91 98765 43210"
160
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent" />
161
- </div>
162
- <div>
163
- <label className="text-xs font-medium text-gray-700 mb-1 block">Email Address *</label>
164
- <input required type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="priya@example.com"
165
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent" />
166
- </div>
167
- <div>
168
- <label className="text-xs font-medium text-gray-700 mb-1 block">How can we help?</label>
169
- <textarea value={message} onChange={e => setMessage(e.target.value)} placeholder="Describe your issue or question..."
170
- rows={3} className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm resize-none focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent" />
171
- </div>
172
- <button type="submit" disabled={loading}
173
- className="w-full py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50">
174
- {loading ? 'Connecting...' : 'Start Chat'}
175
- </button>
176
- </form>
177
- ) : (
178
- <>
179
- <div className="flex-1 overflow-y-auto p-4 space-y-3 min-h-[200px] max-h-[320px]">
180
- <div className="flex gap-2.5">
181
- <div className="w-7 h-7 rounded-full bg-indigo-100 flex items-center justify-center flex-shrink-0 mt-0.5">
182
- <span className="text-indigo-600 text-xs font-bold">CS</span>
183
- </div>
184
- <div className="bg-gray-100 rounded-2xl rounded-tl-sm px-3.5 py-2.5 text-sm text-gray-800">
185
- Hi {name.split(' ')[0]}! Thanks for reaching out. A team member will respond within 2 hours.
186
- {whatsapp && <span className="block text-xs text-gray-500 mt-1">Replied via WhatsApp: {whatsapp}</span>}
187
- </div>
188
- </div>
189
- {messages.map((m, i) => (
190
- <div key={i} className={`flex gap-2.5 ${m.sender === 'visitor' ? 'flex-row-reverse' : ''}`}>
191
- {m.sender !== 'visitor' && (
192
- <div className="w-7 h-7 rounded-full bg-indigo-100 flex items-center justify-center flex-shrink-0 mt-0.5">
193
- <span className="text-indigo-600 text-xs font-bold">CS</span>
194
- </div>
195
- )}
196
- <div className={`max-w-[75%] rounded-2xl px-3.5 py-2.5 text-sm ${
197
- m.sender === 'visitor' ? 'bg-indigo-600 text-white rounded-tr-sm' : 'bg-gray-100 text-gray-800 rounded-tl-sm'
198
- }`}>{m.content}</div>
199
- </div>
200
- ))}
201
- <div ref={bottomRef} />
202
- </div>
203
- <form onSubmit={handleSend} className="border-t border-gray-100 p-3 flex gap-2">
204
- <input value={message} onChange={e => setMessage(e.target.value)} placeholder="Type a message..."
205
- className="flex-1 px-3 py-2 border border-gray-200 rounded-full text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent" />
206
- <button type="submit" className="w-9 h-9 bg-indigo-600 hover:bg-indigo-700 text-white rounded-full flex items-center justify-center transition-colors flex-shrink-0">
207
- <Send className="w-3.5 h-3.5" />
208
- </button>
209
- </form>
210
- </>
211
- )}
212
- </div>
213
- )}
214
-
215
- <button onClick={() => setOpen(o => !o)}
216
- className="flex items-center gap-2.5 bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2.5 rounded-full shadow-lg transition-all hover:shadow-xl text-sm font-medium">
217
- <MessageCircle className="w-4.5 h-4.5" />
218
- {open ? 'Close Chat' : 'Chat with Us'}
219
- {!open && <span className="w-2 h-2 rounded-full bg-green-400 animate-pulse" />}
220
- </button>
221
- </div>
222
- );
223
- }
224
-
225
- function FAQItem({ q, a }: { q: string; a: string }) {
226
- const [expanded, setExpanded] = useState(false);
227
- return (
228
- <div className="border border-gray-200 rounded-xl overflow-hidden">
229
- <button onClick={() => setExpanded(e => !e)} className="w-full flex items-center justify-between px-5 py-4 text-left hover:bg-gray-50 transition-colors">
230
- <span className="text-sm font-medium text-gray-900 pr-4">{q}</span>
231
- {expanded ? <ChevronUp className="w-4 h-4 text-gray-400 flex-shrink-0" /> : <ChevronDown className="w-4 h-4 text-gray-400 flex-shrink-0" />}
232
- </button>
233
- {expanded && <div className="px-5 pb-4 text-sm text-gray-600 leading-relaxed">{a}</div>}
234
- </div>
235
- );
236
- }
237
-
238
- export default function SupportClient() {
239
- const [form, setForm] = useState({ name: '', whatsapp: '', email: '', subject: '', message: '' });
240
- const [sent, setSent] = useState(false);
241
- const [loading, setLoading] = useState(false);
242
-
243
- async function handleSubmit(e: React.FormEvent) {
244
- e.preventDefault();
245
- setLoading(true);
246
- try {
247
- // Send email notification
248
- await fetch('/api/support/email', {
249
- method: 'POST',
250
- headers: { 'Content-Type': 'application/json' },
251
- body: JSON.stringify(form),
252
- });
253
-
254
- // Build WhatsApp URL with pre-filled message
255
- const whatsappMsg = `Hi ClaudMax Team,
256
-
257
- Name: ${form.name}
258
- Email: ${form.email}
259
- WhatsApp: ${form.whatsapp || 'Not provided'}
260
- ${form.subject ? `Subject: ${form.subject}\n` : ''}
261
- Message: ${form.message || 'No message'}`.trim();
262
-
263
- const whatsappUrl = `https://wa.me/${WHATSAPP}?text=${encodeURIComponent(whatsappMsg)}`;
264
-
265
- // Open WhatsApp in new tab
266
- window.open(whatsappUrl, '_blank');
267
- setSent(true);
268
- } catch { /* ignore */ }
269
- setLoading(false);
270
- }
271
-
272
- return (
273
- <div className="min-h-screen bg-gray-50 flex flex-col">
274
- <Header />
275
- <main className="flex-1">
276
- {/* Hero */}
277
- <section className="bg-gradient-to-br from-indigo-600 via-purple-600 to-indigo-800 text-white py-16">
278
- <div className="max-w-4xl mx-auto px-6 text-center">
279
- <div className="w-14 h-14 rounded-2xl bg-white/10 flex items-center justify-center mx-auto mb-5">
280
- <MessageCircle className="w-7 h-7 text-white" />
281
- </div>
282
- <h1 className="text-3xl font-bold mb-3">How can we help you?</h1>
283
- <p className="text-indigo-100 text-base max-w-xl mx-auto">Reach out via chat, WhatsApp, or email. We typically respond within 2 hours and are available 24/7.</p>
284
- </div>
285
- </section>
286
-
287
- {/* Contact Cards */}
288
- <section className="max-w-4xl mx-auto px-6 -mt-6">
289
- <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-12">
290
- <a href={`https://wa.me/${WHATSAPP}?text=Hi%2C%20I%20need%20help%20with%20ClaudMax`} target="_blank" rel="noopener noreferrer"
291
- className="bg-white rounded-xl p-5 shadow-sm border border-gray-100 hover:shadow-md hover:border-green-200 transition-all group">
292
- <div className="w-11 h-11 rounded-xl bg-green-50 group-hover:bg-green-100 flex items-center justify-center mb-3 transition-colors">
293
- <MessageCircle className="w-5.5 h-5.5 text-green-600" />
294
- </div>
295
- <div className="text-sm font-semibold text-gray-900 mb-0.5">WhatsApp</div>
296
- <div className="text-xs text-gray-500">+91-7669217156</div>
297
- <div className="text-xs text-green-600 mt-1 group-hover:underline">Chat now →</div>
298
- </a>
299
- <a href={`mailto:codewpremium@gmail.com?subject=ClaudMax%20Support`}
300
- className="bg-white rounded-xl p-5 shadow-sm border border-gray-100 hover:shadow-md hover:border-blue-200 transition-all group">
301
- <div className="w-11 h-11 rounded-xl bg-blue-50 group-hover:bg-blue-100 flex items-center justify-center mb-3 transition-colors">
302
- <Mail className="w-5.5 h-5.5 text-blue-600" />
303
- </div>
304
- <div className="text-sm font-semibold text-gray-900 mb-0.5">Email</div>
305
- <div className="text-xs text-gray-500">codewpremium@gmail.com</div>
306
- <div className="text-xs text-blue-600 mt-1 group-hover:underline">Send email →</div>
307
- </a>
308
- <div className="bg-white rounded-xl p-5 shadow-sm border border-gray-100">
309
- <div className="w-11 h-11 rounded-xl bg-purple-50 flex items-center justify-center mb-3">
310
- <Phone className="w-5.5 h-5.5 text-purple-600" />
311
- </div>
312
- <div className="text-sm font-semibold text-gray-900 mb-0.5">Response Time</div>
313
- <div className="text-xs text-gray-500">Within 2 hours</div>
314
- <div className="text-xs text-purple-600 mt-1">24/7 availability</div>
315
- </div>
316
- </div>
317
- </section>
318
-
319
- {/* Chat + Form */}
320
- <section className="max-w-4xl mx-auto px-6 mb-16">
321
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
322
- {/* Message Form */}
323
- <div className="bg-white rounded-2xl shadow-sm border border-gray-100 p-6">
324
- <h2 className="text-lg font-bold text-gray-900 mb-1">Send us a message</h2>
325
- <p className="text-sm text-gray-500 mb-5">We&apos;ll get back to you within 2 hours.</p>
326
- {sent ? (
327
- <div className="text-center py-8">
328
- <CheckCircle2 className="w-12 h-12 text-green-500 mx-auto mb-3" />
329
- <div className="text-base font-semibold text-gray-900 mb-1">Message sent!</div>
330
- <div className="text-sm text-gray-500">We&apos;ll reply to {form.email || 'your email'} shortly.</div>
331
- </div>
332
- ) : (
333
- <form onSubmit={handleSubmit} className="flex flex-col gap-3">
334
- <div className="grid grid-cols-2 gap-3">
335
- <div>
336
- <label className="text-xs font-medium text-gray-700 mb-1 block">Your Name *</label>
337
- <input required value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))} placeholder="Rahul Verma"
338
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
339
- </div>
340
- <div>
341
- <label className="text-xs font-medium text-gray-700 mb-1 block">WhatsApp</label>
342
- <input value={form.whatsapp} onChange={e => setForm(f => ({ ...f, whatsapp: e.target.value }))} placeholder="+91 98765 43210"
343
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
344
- </div>
345
- </div>
346
- <div>
347
- <label className="text-xs font-medium text-gray-700 mb-1 block">Email Address *</label>
348
- <input required type="email" value={form.email} onChange={e => setForm(f => ({ ...f, email: e.target.value }))} placeholder="rahul@example.com"
349
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
350
- </div>
351
- <div>
352
- <label className="text-xs font-medium text-gray-700 mb-1 block">Subject</label>
353
- <input value={form.subject} onChange={e => setForm(f => ({ ...f, subject: e.target.value }))} placeholder="API key issue"
354
- className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
355
- </div>
356
- <div>
357
- <label className="text-xs font-medium text-gray-700 mb-1 block">Message *</label>
358
- <textarea required value={form.message} onChange={e => setForm(f => ({ ...f, message: e.target.value }))} placeholder="Describe your issue..."
359
- rows={4} className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm resize-none focus:outline-none focus:ring-2 focus:ring-indigo-500" />
360
- </div>
361
- <button type="submit" disabled={loading}
362
- className="w-full py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-medium transition-colors disabled:opacity-50">
363
- {loading ? 'Sending...' : 'Send Message'}
364
- </button>
365
- </form>
366
- )}
367
- </div>
368
-
369
- {/* Quick Links */}
370
- <div className="bg-white rounded-2xl shadow-sm border border-gray-100 p-6">
371
- <h2 className="text-lg font-bold text-gray-900 mb-1">Quick Help</h2>
372
- <p className="text-sm text-gray-500 mb-5">Common topics and helpful resources.</p>
373
- <div className="space-y-2.5">
374
- {[
375
- { label: 'Getting Started Guide', href: '/docs', desc: 'Step-by-step setup instructions' },
376
- { label: 'API Documentation', href: '/docs', desc: 'Full API reference and examples' },
377
- { label: 'Check Usage & Limits', href: '/check-usage', desc: 'View your current usage dashboard' },
378
- { label: 'Status Page', href: '/status', desc: 'Real-time system status' },
379
- { label: 'Billing & Plans', href: '/support', desc: 'Questions about your subscription' },
380
- { label: 'Reseller Program', href: '/support', desc: 'Partner with us as a reseller' },
381
- ].map(link => (
382
- <a key={link.label} href={link.href}
383
- className="flex items-center justify-between p-3 rounded-xl border border-gray-100 hover:border-indigo-200 hover:bg-indigo-50 transition-all group">
384
- <div>
385
- <div className="text-sm font-medium text-gray-900 group-hover:text-indigo-700">{link.label}</div>
386
- <div className="text-xs text-gray-500">{link.desc}</div>
387
- </div>
388
- <ChevronRight className="w-4 h-4 text-gray-300 group-hover:text-indigo-400 flex-shrink-0" />
389
- </a>
390
- ))}
391
- </div>
392
- </div>
393
- </div>
394
- </section>
395
-
396
- {/* FAQ */}
397
- <section className="max-w-3xl mx-auto px-6 pb-20">
398
- <div className="text-center mb-8">
399
- <h2 className="text-2xl font-bold text-gray-900 mb-2">Frequently Asked Questions</h2>
400
- <p className="text-sm text-gray-500">Quick answers to the most common questions about ClaudMax.</p>
401
- </div>
402
- <div className="space-y-2">
403
- {FAQS.map(faq => <FAQItem key={faq.q} q={faq.q} a={faq.a} />)}
404
- </div>
405
- </section>
406
- </main>
407
- <Footer />
408
- <ChatWidget />
409
- </div>
410
- );
411
- }
@@ -1,25 +0,0 @@
1
- import type { Metadata } from 'next';
2
- import SupportClient from './SupportClient';
3
-
4
- export const metadata: Metadata = {
5
- title: 'Support | ClaudMax — Claude API Gateway',
6
- description: 'Get help with ClaudMax. Chat with us directly via WhatsApp or open a support ticket. Available 24/7 for all your Claude API gateway questions.',
7
- keywords: 'ClaudMax support, Claude API help, chat support, WhatsApp support, Claude API gateway help',
8
- openGraph: {
9
- title: 'Support | ClaudMax',
10
- description: 'Chat with us via WhatsApp or open a support ticket. 24/7 availability.',
11
- type: 'website',
12
- url: 'https://claudmax.pro/support',
13
- siteName: 'ClaudMax',
14
- },
15
- twitter: {
16
- card: 'summary_large_image',
17
- title: 'Support | ClaudMax',
18
- description: 'Get help with ClaudMax. Chat with us via WhatsApp or open a support ticket.',
19
- },
20
- robots: { index: true, follow: true },
21
- };
22
-
23
- export default function SupportPage() {
24
- return <SupportClient />;
25
- }
@@ -1,3 +0,0 @@
1
- // Re-export from /api/v1/chat
2
- export { POST } from "@/app/api/v1/chat/route";
3
-
@@ -1,4 +0,0 @@
1
- // /v1/chat/completions — mirrors /api/v1/chat
2
- // Claude Code sends to /v1/chat/completions, our middleware rewrites to /api/v1/chat
3
- // But local dev needs direct /v1 routes too since middleware doesn't run on localhost:3000
4
- export { POST } from '@/app/api/v1/chat/route';
@@ -1,3 +0,0 @@
1
- // /v1/messages — mirrors /api/v1/messages
2
- // Claude Code uses Anthropic Messages API format
3
- export { POST } from '@/app/api/v1/messages/route';