feat: add captcha functionality to PublicDashboardPage and OrganizationSettings components
This commit is contained in:
@@ -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
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<Captcha
|
||||
onVerify={(id, solution, token) => {
|
||||
setCaptchaId(id)
|
||||
setCaptchaSolution(solution)
|
||||
setCaptchaToken(token || '')
|
||||
}}
|
||||
apiUrl={process.env.NEXT_PUBLIC_CAPTCHA_API_URL}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full btn-primary"
|
||||
|
||||
@@ -22,9 +22,10 @@ import {
|
||||
AlertTriangleIcon,
|
||||
PlusIcon,
|
||||
BoxIcon,
|
||||
UserIcon,
|
||||
CheckIcon,
|
||||
UserIcon,
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
Captcha
|
||||
} from '@ciphera-net/ui'
|
||||
// @ts-ignore
|
||||
import { Button, Input } from '@ciphera-net/ui'
|
||||
@@ -47,6 +48,11 @@ export default function OrganizationSettings() {
|
||||
const [inviteEmail, setInviteEmail] = useState('')
|
||||
const [inviteRole, setInviteRole] = useState('member')
|
||||
const [isInviting, setIsInviting] = useState(false)
|
||||
|
||||
// Captcha State
|
||||
const [captchaId, setCaptchaId] = useState('')
|
||||
const [captchaSolution, setCaptchaSolution] = useState('')
|
||||
const [captchaToken, setCaptchaToken] = useState('')
|
||||
|
||||
// Org Update State
|
||||
const [orgDetails, setOrgDetails] = useState<Organization | null>(null)
|
||||
@@ -358,6 +364,16 @@ export default function OrganizationSettings() {
|
||||
Invite
|
||||
</Button>
|
||||
</form>
|
||||
<div className="mt-4">
|
||||
<Captcha
|
||||
onVerify={(id, solution, token) => {
|
||||
setCaptchaId(id)
|
||||
setCaptchaSolution(solution)
|
||||
setCaptchaToken(token || '')
|
||||
}}
|
||||
apiUrl={process.env.NEXT_PUBLIC_CAPTCHA_API_URL}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -81,10 +81,19 @@ export async function getOrganizationMembers(organizationId: string): Promise<Or
|
||||
}
|
||||
|
||||
// Send an invitation
|
||||
export async function sendInvitation(organizationId: string, email: string, role: string = 'member'): Promise<OrganizationInvitation> {
|
||||
export async function sendInvitation(
|
||||
organizationId: string,
|
||||
email: string,
|
||||
role: string = 'member',
|
||||
captcha?: { captcha_id?: string, captcha_solution?: string, captcha_token?: string }
|
||||
): Promise<OrganizationInvitation> {
|
||||
return await authFetch<OrganizationInvitation>(`/auth/organizations/${organizationId}/invites`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email, role }),
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
role,
|
||||
...captcha
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -236,12 +236,24 @@ export async function getDashboard(siteId: string, startDate?: string, endDate?:
|
||||
return apiRequest<DashboardData>(`/sites/${siteId}/dashboard?${params.toString()}`)
|
||||
}
|
||||
|
||||
export async function getPublicDashboard(siteId: string, startDate?: string, endDate?: string, limit = 10, interval?: string, password?: string): Promise<DashboardData> {
|
||||
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<DashboardData> {
|
||||
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<DashboardData>(`/public/sites/${siteId}/dashboard?${params.toString()}`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user