diff --git a/src/components/admin/UserManagementPanel.jsx b/src/components/admin/UserManagementPanel.jsx
index f671937..f2ccdfa 100644
--- a/src/components/admin/UserManagementPanel.jsx
+++ b/src/components/admin/UserManagementPanel.jsx
@@ -3,7 +3,7 @@ import { Panel } from '../UI/Panel';
import { Badge } from '../UI/Badge';
import { Input } from '../UI/Input';
-import { supabase } from '../../supabaseClient';
+import { supabase, supabaseUrl } from '../../supabaseClient';
const ROLES = ['admin', 'driver', 'logistician', 'manager', 'mega_admin'];
@@ -23,19 +23,45 @@ const ROLE_TONES = {
driver: 'accent',
};
+/* ── Call manage-users edge function ── */
+async function adminApi(method, body) {
+ const { data: { session } } = await supabase.auth.getSession();
+ const token = session?.access_token;
+ if (!token) throw new Error('Не авторизован');
+
+ const opts = {
+ method,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${token}`,
+ 'apikey': import.meta.env.VITE_SUPABASE_ANON_KEY,
+ },
+ };
+ if (body && method !== 'DELETE') opts.body = JSON.stringify(body);
+
+ const url = method === 'DELETE' && body?.id
+ ? `${supabaseUrl}/functions/v1/manage-users?id=${body.id}`
+ : `${supabaseUrl}/functions/v1/manage-users`;
+
+ const res = await fetch(url, opts);
+ const json = await res.json();
+ if (!res.ok) throw new Error(json.error || `Ошибка ${res.status}`);
+ return json;
+}
+
/* ── Custom dropdown (matches app design system) ── */
-function RoleDropdown({ value, onChange, onClose }) {
+function RoleDropdown({ value, onChange }) {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
- const onDown = (e) => { if (ref.current && !ref.current.contains(e.target)) { setOpen(false); onClose?.(); } };
- const onKey = (e) => { if (e.key === 'Escape') { setOpen(false); onClose?.(); } };
+ const onDown = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
+ const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
document.addEventListener('pointerdown', onDown);
document.addEventListener('keydown', onKey);
return () => { document.removeEventListener('pointerdown', onDown); document.removeEventListener('keydown', onKey); };
- }, [open, onClose]);
+ }, [open]);
const pick = (role) => { onChange(role); setOpen(false); };
@@ -50,7 +76,7 @@ function RoleDropdown({ value, onChange, onClose }) {
▾
{open && (
-
+
{ROLES.map((r) => {
const sel = r === value;
return (
@@ -59,7 +85,7 @@ function RoleDropdown({ value, onChange, onClose }) {
type="button"
onClick={() => pick(r)}
className={[
- 'flex w-full items-center justify-between px-4 py-3 text-left text-sm transition',
+ 'flex w-full items-center justify-between px-4 py-2.5 text-left text-sm transition',
sel ? 'bg-[var(--color-accent-soft)] text-[var(--color-text)]' : 'text-[var(--color-text)] hover:bg-[var(--color-surface-strong)]',
].join(' ')}
>
@@ -119,24 +145,14 @@ export default function UserManagementPanel() {
return match ? match.id : null;
};
- /* ── Add ── */
+ /* ── Add via edge function ── */
const handleAddUser = async (e) => {
e.preventDefault();
setAddError(null);
if (!addForm.name || !addForm.email || !addForm.role) { setAddError('Все поля обязательны.'); return; }
setAddSubmitting(true);
try {
- const roleId = getRoleId(addForm.role);
- const { data: authData, error: authErr } = await supabase.auth.admin.createUser({
- email: addForm.email,
- email_confirm: true,
- user_metadata: { name: addForm.name },
- });
- if (authErr) throw authErr;
- const { error: insertErr } = await supabase
- .from('users')
- .insert({ id: authData.user.id, email: addForm.email, name: addForm.name, role_id: roleId });
- if (insertErr) throw insertErr;
+ await adminApi('POST', { email: addForm.email, name: addForm.name, role: addForm.role });
await fetchUsers();
setShowAddForm(false);
setAddForm({ name: '', email: '', role: '' });
@@ -145,7 +161,7 @@ export default function UserManagementPanel() {
} finally { setAddSubmitting(false); }
};
- /* ── Edit ── */
+ /* ── Edit via edge function ── */
const startEdit = (user) => {
setEditingId(user.id);
setEditForm({ name: user.name || '', email: user.email || '', role: getRoleName(user) });
@@ -155,24 +171,17 @@ export default function UserManagementPanel() {
const saveEdit = async () => {
setSaving(true);
try {
- const roleId = getRoleId(editForm.role);
- const { error: err } = await supabase
- .from('users')
- .update({ name: editForm.name, email: editForm.email, role_id: roleId })
- .eq('id', editingId);
- if (err) throw err;
+ await adminApi('PATCH', { id: editingId, name: editForm.name, email: editForm.email, role: editForm.role });
setEditingId(null);
await fetchUsers();
} catch (err) { setError(err.message || 'Не удалось сохранить.'); }
finally { setSaving(false); }
};
- /* ── Delete ── */
+ /* ── Delete via edge function ── */
const handleDeleteUser = async (userId) => {
try {
- const { error: err } = await supabase.from('users').delete().eq('id', userId);
- if (err) throw err;
- try { await supabase.auth.admin.deleteUser(userId); } catch {}
+ await adminApi('DELETE', { id: userId });
setDeleteConfirmId(null);
await fetchUsers();
} catch (err) { setError(err.message || 'Не удалось удалить.'); }
@@ -197,38 +206,34 @@ export default function UserManagementPanel() {
- {/* Add form */}
+ {/* Add form — compact column */}
{showAddForm && (
-
)}
@@ -252,29 +257,28 @@ export default function UserManagementPanel() {
return (
-
+
setEditForm((f) => ({ ...f, name: e.target.value }))}
- className="flex-1 min-w-[140px]!"
+ className="w-[200px]!"
/>
setEditForm((f) => ({ ...f, email: e.target.value }))}
- className="flex-1 min-w-[180px]!"
+ className="w-[240px]!"
/>
setEditForm((f) => ({ ...f, role: r }))}
- onClose={undefined}
/>
-
+