@payload-auth/better-auth-plugin
Version:
A Payload CMS plugin for Better Auth
283 lines (282 loc) • 13.3 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useEffect, useState } from 'react';
import { adminClient } from 'better-auth/client/plugins';
import { createAuthClient } from 'better-auth/react';
import { usePathname, useRouter } from 'next/navigation';
import { toast } from 'sonner';
import { Toaster } from 'sonner';
import './styles.css';
import '@payloadcms/ui/styles.css';
function getIdFromUrl(path, userSlug) {
const urlParts = path.split('/');
// Find the part after the userSlug in the URL
const userSlugIndex = urlParts.findIndex((part)=>part === userSlug);
if (userSlugIndex !== -1 && userSlugIndex < urlParts.length - 1) {
return urlParts[userSlugIndex + 1];
}
const potentialIdFromUrl = urlParts[urlParts.length - 1];
return potentialIdFromUrl;
}
async function getDocumentData(id, path) {
const apiUrl = `${path}/api`;
try {
// Try to load the /api page and parse the HTML response
const response = await fetch(apiUrl);
if (response.ok) {
const htmlResponse = await response.text();
// Parse the HTML to extract user data
try {
let documentData = null;
const parser = new DOMParser();
const doc = parser.parseFromString(htmlResponse, 'text/html');
// Look for the JSON data in the query inspector
const jsonRows = doc.querySelectorAll('.query-inspector__row-line');
if (jsonRows.length > 0) {
documentData = {};
jsonRows.forEach((row)=>{
const keyMatch = row.innerHTML.match(/"([^"]+)"\s*:/);
if (keyMatch) {
const key = keyMatch[1].trim();
const valueElement = row.querySelector('.query-inspector__value');
if (valueElement) {
let value = valueElement.textContent?.trim() ?? '';
// Convert values to appropriate types
if (value === 'true') value = 'true';
else if (value === 'false') value = 'false';
else if (value === 'null') value = 'null';
else if (!isNaN(Number(value))) value = Number(value).toString();
else if (value.startsWith('"') && value.endsWith('"')) {
value = value.substring(1, value.length - 1).trim();
}
documentData[key] = value;
}
}
});
}
return documentData;
} catch (parseError) {
console.error('Error parsing document data from HTML:', parseError);
return null;
}
}
} catch (apiError) {
console.error('Error fetching document data from API:', apiError);
}
}
export default function AdminButtons({ userSlug }) {
const router = useRouter();
const path = usePathname();
const [id, setId] = useState('');
const [documentData, setDocumentData] = useState(null);
const authClient = createAuthClient({
plugins: [
adminClient()
]
});
useEffect(()=>{
async function fetchDocumentData() {
const id = getIdFromUrl(path, userSlug);
const documentData = await getDocumentData(id, path);
console.log('doc id', id);
console.dir([
'doc data',
documentData
], {
depth: 2,
colors: true
});
setId(id);
setDocumentData(documentData);
}
fetchDocumentData();
}, []);
const handleImpersonate = async ()=>{
await authClient.admin.impersonateUser({
userId: id,
fetchOptions: {
onSuccess () {
router.push('/');
},
onError (error) {
console.error('Error impersonating user:', error);
toast.error('Failed to impersonate user');
}
}
});
};
const handleBan = async ()=>{
await authClient.admin.banUser({
userId: id,
fetchOptions: {
onSuccess () {
toast.success('User banned successfully');
router.refresh();
},
onError (error) {
console.error('Error banning user:', error);
toast.error('Failed to ban user');
}
}
});
};
const handleUnban = async ()=>{
await authClient.admin.unbanUser({
userId: id,
fetchOptions: {
onSuccess () {
toast.success('User unbanned successfully');
router.refresh();
},
onError (error) {
console.error('Error unbanning user:', error);
toast.error('Failed to unban user');
}
}
});
};
const handleRevokeAllSessions = async ()=>{
await authClient.admin.revokeUserSessions({
userId: id,
fetchOptions: {
onSuccess () {
toast.success('All sessions revoked successfully');
router.refresh();
},
onError (error) {
console.error('Error revoking all sessions:', error);
toast.error('Failed to revoke all sessions');
}
}
});
};
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "admin-actions-container",
style: {
display: 'flex',
flexDirection: 'column',
gap: '8px',
padding: '10px',
marginBottom: '24px',
border: '1px solid var(--theme-elevation-150)',
borderRadius: 'var(--style-radius-s)',
backgroundColor: 'var(--theme-input-bg',
color: 'var(--text-color, #334155)',
transitionProperty: 'border, box-shadow, background-color',
transitionDuration: '.1s, .1s, .5s',
transitionTimingFunction: 'cubic-bezier(0, .2, .2, 1)'
},
onMouseOver: (e)=>e.currentTarget.style.border = '1px solid var(--theme-elevation-250)',
onMouseOut: (e)=>e.currentTarget.style.border = '1px solid var(--theme-elevation-150)',
children: [
/*#__PURE__*/ _jsx("h3", {
style: {
margin: '0 0 0px 0',
fontSize: '16px',
fontWeight: '600',
color: 'var(--heading-color, #334155)'
},
children: "Admin Actions"
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
flexWrap: 'wrap',
gap: '12px'
},
children: [
/*#__PURE__*/ _jsx("button", {
onClick: handleImpersonate,
type: "button",
style: {
padding: '8px 16px',
backgroundColor: 'var(--impersonate-bg, #f97316)',
color: 'var(--button-text, white)',
border: '1px solid var(--impersonate-border, #ea580c)',
borderRadius: 'var(--style-radius-s)',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
},
onMouseOver: (e)=>e.currentTarget.style.backgroundColor = 'var(--impersonate-hover, #ea580c)',
onMouseOut: (e)=>e.currentTarget.style.backgroundColor = 'var(--impersonate-bg, #f97316)',
children: "Impersonate"
}),
/*#__PURE__*/ _jsx("button", {
onClick: handleRevokeAllSessions,
type: "button",
style: {
padding: '8px 16px',
backgroundColor: 'var(--revoke-bg, #64748b)',
color: 'var(--button-text, white)',
border: '1px solid var(--revoke-border, #475569)',
borderRadius: 'var(--style-radius-s)',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
},
onMouseOver: (e)=>e.currentTarget.style.backgroundColor = 'var(--revoke-hover, #475569)',
onMouseOut: (e)=>e.currentTarget.style.backgroundColor = 'var(--revoke-bg, #64748b)',
children: "Revoke All Sessions"
}),
/*#__PURE__*/ _jsx("button", {
onClick: handleBan,
type: "button",
style: {
padding: '8px 16px',
backgroundColor: 'var(--ban-bg, #ef4444)',
color: 'var(--button-text, white)',
border: '1px solid var(--ban-border, #dc2626)',
borderRadius: 'var(--style-radius-s)',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
},
onMouseOver: (e)=>e.currentTarget.style.backgroundColor = 'var(--ban-hover, #dc2626)',
onMouseOut: (e)=>e.currentTarget.style.backgroundColor = 'var(--ban-bg, #ef4444)',
children: "Ban"
}),
/*#__PURE__*/ _jsx("button", {
onClick: handleUnban,
type: "button",
style: {
padding: '8px 16px',
backgroundColor: 'var(--unban-bg, #22c55e)',
color: 'var(--button-text, white)',
border: '1px solid var(--unban-border, #16a34a)',
borderRadius: 'var(--style-radius-s)',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'background-color 0.2s ease',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
},
onMouseOver: (e)=>e.currentTarget.style.backgroundColor = 'var(--unban-hover, #16a34a)',
onMouseOut: (e)=>e.currentTarget.style.backgroundColor = 'var(--unban-bg, #22c55e)',
children: "Unban"
})
]
})
]
}),
/*#__PURE__*/ _jsx(Toaster, {})
]
});
}
//# sourceMappingURL=admin-buttons.js.map