Fix modals
This commit is contained in:
parent
997646be35
commit
536dc3fcb8
2 changed files with 143 additions and 137 deletions
|
|
@ -129,7 +129,7 @@ const Channels: React.FC = () => {
|
|||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2 flex-1 min-w-0">
|
||||
<h3 className="text-lg font-medium text-gray-900 truncate">
|
||||
!{channel.name}@{channel.platform_instance?.url?.replace(/^https?:\/\//, '')}
|
||||
{channel.display_name || channel.name}
|
||||
</h3>
|
||||
<a
|
||||
href={`https://${channel.platform_instance?.url?.replace(/^https?:\/\//, '')}/c/${channel.name}`}
|
||||
|
|
@ -154,9 +154,9 @@ const Channels: React.FC = () => {
|
|||
)}
|
||||
</button>
|
||||
</div>
|
||||
{channel.display_name && (
|
||||
<p className="text-sm text-gray-500">{channel.display_name}</p>
|
||||
)}
|
||||
<p className="text-sm text-gray-500">
|
||||
!{channel.name}@{channel.platform_instance?.url?.replace(/^https?:\/\//, '')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -229,79 +229,77 @@ const Channels: React.FC = () => {
|
|||
|
||||
{/* Account Management Modal */}
|
||||
{showAccountModal && (
|
||||
<div className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" onClick={() => setShowAccountModal(null)}></div>
|
||||
<div className="fixed inset-0" style={{ zIndex: 9999 }} onClick={() => setShowAccountModal(null)}>
|
||||
<div
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-xl p-6"
|
||||
style={{ width: '500px', maxHeight: '80vh', overflowY: 'auto' }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="flex-shrink-0 flex items-center justify-center h-10 w-10 rounded-full bg-blue-100">
|
||||
<Link2 className="h-6 w-6 text-blue-600" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<h3 className="text-lg font-medium text-gray-900">
|
||||
Manage Accounts for {showAccountModal.channelName}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen">​</span>
|
||||
<div className="mb-4">
|
||||
<p className="text-sm text-gray-500 mb-4">
|
||||
Select a platform account to link to this channel:
|
||||
</p>
|
||||
|
||||
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
|
||||
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div className="sm:flex sm:items-start">
|
||||
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<Link2 className="h-6 w-6 text-blue-600" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left flex-1">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||
Manage Accounts for {showAccountModal.channelName}
|
||||
</h3>
|
||||
<div className="mt-4">
|
||||
<p className="text-sm text-gray-500 mb-4">
|
||||
Select a platform account to link to this channel:
|
||||
</p>
|
||||
|
||||
{accounts && accounts.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{accounts
|
||||
.filter(account => !channels?.find(c => c.id === showAccountModal.channelId)?.platform_accounts?.some(pa => pa.id === account.id))
|
||||
.map((account) => (
|
||||
<button
|
||||
key={account.id}
|
||||
onClick={() => handleAttachAccount(showAccountModal.channelId, account.id)}
|
||||
disabled={attachAccountMutation.isPending}
|
||||
className="w-full text-left px-3 py-2 border border-gray-200 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:opacity-50"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-900">@{account.username}</p>
|
||||
{account.display_name && (
|
||||
<p className="text-xs text-gray-500">{account.display_name}</p>
|
||||
)}
|
||||
</div>
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
|
||||
account.is_active
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{account.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
|
||||
{accounts.filter(account => !channels?.find(c => c.id === showAccountModal.channelId)?.platform_accounts?.some(pa => pa.id === account.id)).length === 0 && (
|
||||
<p className="text-sm text-gray-500 text-center py-4">
|
||||
All available accounts are already linked to this channel.
|
||||
</p>
|
||||
{accounts && accounts.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{accounts
|
||||
.filter(account => !channels?.find(c => c.id === showAccountModal.channelId)?.platform_accounts?.some(pa => pa.id === account.id))
|
||||
.map((account) => (
|
||||
<button
|
||||
key={account.id}
|
||||
onClick={() => handleAttachAccount(showAccountModal.channelId, account.id)}
|
||||
disabled={attachAccountMutation.isPending}
|
||||
className="w-full text-left px-3 py-2 border border-gray-200 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:opacity-50"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-900">@{account.username}</p>
|
||||
{account.display_name && (
|
||||
<p className="text-xs text-gray-500">{account.display_name}</p>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 text-center py-4">
|
||||
No platform accounts available. Create a platform account first.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
|
||||
account.is_active
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{account.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
|
||||
{accounts.filter(account => !channels?.find(c => c.id === showAccountModal.channelId)?.platform_accounts?.some(pa => pa.id === account.id)).length === 0 && (
|
||||
<p className="text-sm text-gray-500 text-center py-4">
|
||||
All available accounts are already linked to this channel.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
onClick={() => setShowAccountModal(null)}
|
||||
className="w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 text-center py-4">
|
||||
No platform accounts available. Create a platform account first.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end pt-4 border-t">
|
||||
<button
|
||||
onClick={() => setShowAccountModal(null)}
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -280,11 +280,16 @@ const CreateRouteModal: React.FC<CreateRouteModalProps> = ({ feeds, channels, on
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
||||
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
|
||||
<div className="mt-3">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Create New Route</h3>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="fixed inset-0 overflow-y-auto" style={{ zIndex: 9999 }}>
|
||||
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="fixed inset-0 transition-opacity" onClick={onClose}></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen">​</span>
|
||||
|
||||
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Create New Route</h3>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="feed_id" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Feed
|
||||
|
|
@ -356,7 +361,8 @@ const CreateRouteModal: React.FC<CreateRouteModalProps> = ({ feeds, channels, on
|
|||
{isLoading ? 'Creating...' : 'Create Route'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -379,63 +385,65 @@ const EditRouteModal: React.FC<EditRouteModalProps> = ({ route, onClose, onSubmi
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
|
||||
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white max-h-[80vh] overflow-y-auto">
|
||||
<div className="mt-3">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Edit Route</h3>
|
||||
<div className="mb-4 p-3 bg-gray-50 rounded-md">
|
||||
<p className="text-sm text-gray-600">
|
||||
<strong>Feed:</strong> {route.feed?.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-600">
|
||||
<strong>Channel:</strong> {route.platform_channel?.display_name || route.platform_channel?.name}
|
||||
</p>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="priority" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Priority
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="priority"
|
||||
min="0"
|
||||
value={priority}
|
||||
onChange={(e) => setPriority(parseInt(e.target.value))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-sm text-gray-500 mt-1">Higher priority routes are processed first</p>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-4">
|
||||
<KeywordManager
|
||||
feedId={route.feed_id}
|
||||
channelId={route.platform_channel_id}
|
||||
keywords={route.keywords || []}
|
||||
onKeywordChange={() => {
|
||||
// Keywords will be refreshed via React Query invalidation
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-3 pt-4 border-t">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? 'Updating...' : 'Update Route'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="fixed inset-0" style={{ zIndex: 9999 }} onClick={onClose}>
|
||||
<div
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-xl p-6"
|
||||
style={{ width: '500px', maxHeight: '80vh', overflowY: 'auto' }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Edit Route</h3>
|
||||
<div className="mb-4 p-3 bg-gray-50 rounded-md">
|
||||
<p className="text-sm text-gray-600">
|
||||
<strong>Feed:</strong> {route.feed?.name}
|
||||
</p>
|
||||
<p className="text-sm text-gray-600">
|
||||
<strong>Channel:</strong> {route.platform_channel?.display_name || route.platform_channel?.name}
|
||||
</p>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="priority" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Priority
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="priority"
|
||||
min="0"
|
||||
value={priority}
|
||||
onChange={(e) => setPriority(parseInt(e.target.value))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-sm text-gray-500 mt-1">Higher priority routes are processed first</p>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-4">
|
||||
<KeywordManager
|
||||
feedId={route.feed_id}
|
||||
channelId={route.platform_channel_id}
|
||||
keywords={route.keywords || []}
|
||||
onKeywordChange={() => {
|
||||
// Keywords will be refreshed via React Query invalidation
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-3 pt-4 border-t">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? 'Updating...' : 'Update Route'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue