diff --git a/app/share/[id]/page.tsx b/app/share/[id]/page.tsx
index bc2f445..9360a52 100644
--- a/app/share/[id]/page.tsx
+++ b/app/share/[id]/page.tsx
@@ -11,7 +11,7 @@ import TopReferrers from '@/components/dashboard/TopReferrers'
import Locations from '@/components/dashboard/Locations'
import TechSpecs from '@/components/dashboard/TechSpecs'
import PerformanceStats from '@/components/dashboard/PerformanceStats'
-import { Select, DatePicker as DatePickerModal } from '@ciphera-net/ui'
+import { Select, DatePicker as DatePickerModal, Captcha } from '@ciphera-net/ui'
import { ZapIcon } from '@ciphera-net/ui'
// Helper to get date ranges
@@ -37,6 +37,11 @@ export default function PublicDashboardPage() {
const [password, setPassword] = useState(passwordParam || '')
const [isPasswordProtected, setIsPasswordProtected] = useState(false)
+ // Captcha State
+ const [captchaId, setCaptchaId] = useState('')
+ const [captchaSolution, setCaptchaSolution] = useState('')
+ const [captchaToken, setCaptchaToken] = useState('')
+
// Date range state
const [dateRange, setDateRange] = useState(getDateRange(30))
const [isDatePickerOpen, setIsDatePickerOpen] = useState(false)
@@ -69,16 +74,29 @@ export default function PublicDashboardPage() {
dateRange.end,
10,
dateRange.start === dateRange.end ? todayInterval : multiDayInterval,
- password
+ password,
+ {
+ captcha_id: captchaId,
+ captcha_solution: captchaSolution,
+ captcha_token: captchaToken
+ }
)
setData(dashboardData)
setIsPasswordProtected(false)
+ // Reset captcha
+ setCaptchaId('')
+ setCaptchaSolution('')
+ setCaptchaToken('')
} catch (error: any) {
if ((error.status === 401 || error.response?.status === 401) && (error.data?.is_protected || error.response?.data?.is_protected)) {
setIsPasswordProtected(true)
if (password) {
- toast.error('Invalid password')
+ toast.error('Invalid password or captcha')
+ // Reset captcha on failure
+ setCaptchaId('')
+ setCaptchaSolution('')
+ setCaptchaToken('')
}
} else if (error.status === 404 || error.response?.status === 404) {
toast.error('Site not found')
@@ -126,6 +144,16 @@ export default function PublicDashboardPage() {
autoFocus
/>
+
+ {
+ setCaptchaId(id)
+ setCaptchaSolution(solution)
+ setCaptchaToken(token || '')
+ }}
+ apiUrl={process.env.NEXT_PUBLIC_CAPTCHA_API_URL}
+ />
+
+
+ {
+ setCaptchaId(id)
+ setCaptchaSolution(solution)
+ setCaptchaToken(token || '')
+ }}
+ apiUrl={process.env.NEXT_PUBLIC_CAPTCHA_API_URL}
+ />
+
diff --git a/lib/api/organization.ts b/lib/api/organization.ts
index e2f447f..7d047de 100644
--- a/lib/api/organization.ts
+++ b/lib/api/organization.ts
@@ -81,10 +81,19 @@ export async function getOrganizationMembers(organizationId: string): Promise {
+export async function sendInvitation(
+ organizationId: string,
+ email: string,
+ role: string = 'member',
+ captcha?: { captcha_id?: string, captcha_solution?: string, captcha_token?: string }
+): Promise {
return await authFetch(`/auth/organizations/${organizationId}/invites`, {
method: 'POST',
- body: JSON.stringify({ email, role }),
+ body: JSON.stringify({
+ email,
+ role,
+ ...captcha
+ }),
})
}
diff --git a/lib/api/stats.ts b/lib/api/stats.ts
index 6e480a9..68c80da 100644
--- a/lib/api/stats.ts
+++ b/lib/api/stats.ts
@@ -236,12 +236,24 @@ export async function getDashboard(siteId: string, startDate?: string, endDate?:
return apiRequest(`/sites/${siteId}/dashboard?${params.toString()}`)
}
-export async function getPublicDashboard(siteId: string, startDate?: string, endDate?: string, limit = 10, interval?: string, password?: string): Promise {
+export async function getPublicDashboard(
+ siteId: string,
+ startDate?: string,
+ endDate?: string,
+ limit = 10,
+ interval?: string,
+ password?: string,
+ captcha?: { captcha_id?: string, captcha_solution?: string, captcha_token?: string }
+): Promise {
const params = new URLSearchParams()
if (startDate) params.append('start_date', startDate)
if (endDate) params.append('end_date', endDate)
if (interval) params.append('interval', interval)
if (password) params.append('password', password)
+ if (captcha?.captcha_id) params.append('captcha_id', captcha.captcha_id)
+ if (captcha?.captcha_solution) params.append('captcha_solution', captcha.captcha_solution)
+ if (captcha?.captcha_token) params.append('captcha_token', captcha.captcha_token)
+
params.append('limit', limit.toString())
return apiRequest(`/public/sites/${siteId}/dashboard?${params.toString()}`)
}