diff --git a/src/api/allowedUsers.api.ts b/src/api/allowedUsers.api.ts index d01525b..9e2ff45 100644 --- a/src/api/allowedUsers.api.ts +++ b/src/api/allowedUsers.api.ts @@ -106,7 +106,6 @@ export const updateAllowedUsersSettings = async (settings: AllowedUsersSettings) } }; - console.log('Sending to backend:', JSON.stringify(nestedSettings, null, 2)); const response = await fetch(`${config.baseURL}/api/settings`, { method: 'POST', @@ -118,10 +117,8 @@ export const updateAllowedUsersSettings = async (settings: AllowedUsersSettings) }); const text = await response.text(); - console.log('Backend response:', response.status, text); if (!response.ok) { - console.error('Backend error:', response.status, text); throw new Error(`HTTP error! status: ${response.status}, response: ${text}`); } @@ -147,9 +144,14 @@ export const getReadNpubs = async (page = 1, pageSize = 20): Promise ({ + ...npub, + tier: npub.tier_name || npub.tier || 'basic' + })); + return { - npubs: data.npubs || [], + npubs: transformedNpubs, total: data.pagination?.total || 0, page: data.pagination?.page || page, pageSize: data.pagination?.pageSize || pageSize @@ -161,13 +163,16 @@ export const getReadNpubs = async (page = 1, pageSize = 20): Promise => { const token = readToken(); + const requestBody = { npub, tier }; + + const response = await fetch(`${config.baseURL}/api/allowed-npubs/read`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, - body: JSON.stringify({ npub, tier }), + body: JSON.stringify(requestBody), }); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); @@ -213,9 +218,14 @@ export const getWriteNpubs = async (page = 1, pageSize = 20): Promise ({ + ...npub, + tier: npub.tier_name || npub.tier || 'basic' + })); + return { - npubs: data.npubs || [], + npubs: transformedNpubs, total: data.pagination?.total || 0, page: data.pagination?.page || page, pageSize: data.pagination?.pageSize || pageSize @@ -227,13 +237,16 @@ export const getWriteNpubs = async (page = 1, pageSize = 20): Promise => { const token = readToken(); + const requestBody = { npub, tier }; + + const response = await fetch(`${config.baseURL}/api/allowed-npubs/write`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, - body: JSON.stringify({ npub, tier }), + body: JSON.stringify(requestBody), }); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); diff --git a/src/components/allowed-users/components/NPubManagement/NPubManagement.tsx b/src/components/allowed-users/components/NPubManagement/NPubManagement.tsx index ca9465f..620c9c1 100644 --- a/src/components/allowed-users/components/NPubManagement/NPubManagement.tsx +++ b/src/components/allowed-users/components/NPubManagement/NPubManagement.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { Button, Input, Table, Space, Modal, Form, Select, message, Popconfirm } from 'antd'; -import { PlusOutlined, UploadOutlined, DeleteOutlined, DownloadOutlined } from '@ant-design/icons'; +import { PlusOutlined, UploadOutlined, DeleteOutlined, DownloadOutlined, EditOutlined } from '@ant-design/icons'; import { useAllowedUsersNpubs, useAllowedUsersValidation } from '@app/hooks/useAllowedUsers'; import { AllowedUsersSettings, AllowedUsersMode } from '@app/types/allowedUsers.types'; import * as S from './NPubManagement.styles'; @@ -30,10 +30,13 @@ export const NPubManagement: React.FC = ({ mode }) => { const [isAddModalVisible, setIsAddModalVisible] = useState(false); + const [isEditModalVisible, setIsEditModalVisible] = useState(false); const [isBulkModalVisible, setIsBulkModalVisible] = useState(false); const [bulkText, setBulkText] = useState(''); const [unifiedUsers, setUnifiedUsers] = useState([]); + const [editingUser, setEditingUser] = useState(null); const [addForm] = Form.useForm(); + const [editForm] = Form.useForm(); const readNpubs = useAllowedUsersNpubs('read'); const writeNpubs = useAllowedUsersNpubs('write'); @@ -47,7 +50,7 @@ export const NPubManagement: React.FC = ({ readNpubs.npubs.forEach(npub => { allNpubs.set(npub.npub, { npub: npub.npub, - tier: npub.tier, + tier: npub.tier || settings.tiers[0]?.name || 'basic', readAccess: true, writeAccess: false, added_at: npub.added_at @@ -59,10 +62,12 @@ export const NPubManagement: React.FC = ({ const existing = allNpubs.get(npub.npub); if (existing) { existing.writeAccess = true; + // Preserve the tier from read access, or use write tier, or fallback + existing.tier = existing.tier || npub.tier || settings.tiers[0]?.name || 'basic'; } else { allNpubs.set(npub.npub, { npub: npub.npub, - tier: npub.tier, + tier: npub.tier || settings.tiers[0]?.name || 'basic', readAccess: false, writeAccess: true, added_at: npub.added_at @@ -71,7 +76,7 @@ export const NPubManagement: React.FC = ({ }); setUnifiedUsers(Array.from(allNpubs.values())); - }, [readNpubs.npubs, writeNpubs.npubs]); + }, [readNpubs.npubs, writeNpubs.npubs, settings.tiers]); const tierOptions = settings.tiers.map(tier => { const displayFormat = tier.unlimited ? 'unlimited' @@ -108,16 +113,19 @@ export const NPubManagement: React.FC = ({ const user = unifiedUsers.find(u => u.npub === npub); if (!user) return; + // Ensure we have a valid tier - fallback to first available tier if undefined + const tierToUse = user.tier || settings.tiers[0]?.name || 'basic'; + try { if (type === 'read') { if (enabled) { - await readNpubs.addNpub(npub, user.tier); + await readNpubs.addNpub(npub, tierToUse); } else { await readNpubs.removeNpub(npub); } } else { if (enabled) { - await writeNpubs.addNpub(npub, user.tier); + await writeNpubs.addNpub(npub, tierToUse); } else { await writeNpubs.removeNpub(npub); } @@ -127,6 +135,67 @@ export const NPubManagement: React.FC = ({ } }; + const handleEditUser = (user: UnifiedUser) => { + setEditingUser(user); + setIsEditModalVisible(true); + // Set form values after modal is visible + setTimeout(() => { + editForm.setFieldsValue({ + npub: user.npub, + tier: user.tier, + readAccess: user.readAccess, + writeAccess: user.writeAccess + }); + }, 0); + }; + + const handleSaveEdit = async () => { + try { + const values = await editForm.validateFields(); + const originalUser = editingUser!; + + // Check what actually changed + const readChanged = originalUser.readAccess !== values.readAccess; + const writeChanged = originalUser.writeAccess !== values.writeAccess; + const tierChanged = originalUser.tier !== values.tier; + + // Handle read access changes + if (readChanged || (tierChanged && values.readAccess)) { + if (values.readAccess) { + // Remove old entry if exists and re-add with new tier + if (originalUser.readAccess) { + await readNpubs.removeNpub(values.npub); + } + await readNpubs.addNpub(values.npub, values.tier); + } else { + // Remove read access + await readNpubs.removeNpub(values.npub); + } + } + + // Handle write access changes + if (writeChanged || (tierChanged && values.writeAccess)) { + if (values.writeAccess) { + // Remove old entry if exists and re-add with new tier + if (originalUser.writeAccess) { + await writeNpubs.removeNpub(values.npub); + } + await writeNpubs.addNpub(values.npub, values.tier); + } else { + // Remove write access + await writeNpubs.removeNpub(values.npub); + } + } + + setIsEditModalVisible(false); + setEditingUser(null); + editForm.resetFields(); + } catch (error) { + console.error('Edit user error:', error); + message.error('Failed to update user'); + } + }; + const handleRemoveUser = async (npub: string) => { try { // Remove from both lists @@ -257,17 +326,27 @@ export const NPubManagement: React.FC = ({ title: 'Actions', key: 'actions', render: (_: any, record: UnifiedUser) => ( - handleRemoveUser(record.npub)} - > +