Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | 3x 3x 118x 118x 118x 118x 118x 108x 1x 1x 1x 1x 1x 1x 1x 1x 1x 118x 118x 118x 118x | import { useState, useEffect } from 'react';
import { adminService, type Configuration, type AvailableProvider } from '@/services/admin.service';
import { AppDialog } from '@/components/common/AppDialog';
import { Button } from '@/components/ui/button';
import { ConfigurationForm } from './ConfigurationForm';
import { Loader2, ArrowLeft, BadgeCheck } from 'lucide-react';
import { ScrollArea } from '@/components/ui/scroll-area';
import { ProviderLogo } from '@/components/common/ProviderLogo';
import { useToast } from '@/hooks/use-toast';
// List of providers that have been manually tested and verified
const VERIFIED_PROVIDERS = ['google'];
interface AddProviderModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onConfigCreated: () => void;
category?: string;
accountId?: string;
existingConfigs?: Configuration[];
}
export const AddProviderModal = ({
open,
onOpenChange,
onConfigCreated,
category,
accountId,
existingConfigs = [],
}: AddProviderModalProps) => {
const [selectedProvider, setSelectedProvider] = useState<AvailableProvider | null>(null);
const [availableProviders, setAvailableProviders] = useState<AvailableProvider[]>([]);
const [isLoading, setIsLoading] = useState(false);
const { toast } = useToast();
useEffect(() => {
if (open) {
const loadProviders = async () => {
setIsLoading(true);
try {
const data = await adminService.getAvailableProviders(category);
// Filter out already configured providers and explicitly exclude email_password
const filtered = data.filter(
(p: AvailableProvider) =>
p.provider_name !== "email_password" &&
!existingConfigs.some((ec) => ec.provider_name === p.provider_name) &&
// System settings are only applicable to system level (no accountId)
!(p.category === 'system_settings' && accountId) &&
// Storage providers are system-level only
!(p.category === 'storage_providers' && accountId)
);
setAvailableProviders(filtered);
} catch (error) {
console.error("Failed to load providers", error);
toast({
title: "Error",
description: "Failed to load available providers.",
variant: "destructive",
});
} finally {
setIsLoading(false);
}
};
loadProviders();
setSelectedProvider(null);
}
}, [open, category, accountId, existingConfigs, toast]);
const handleSuccess = () => {
onConfigCreated();
onOpenChange(false);
};
const title = (
<div className="flex items-center gap-2">
{selectedProvider && (
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
onClick={() => setSelectedProvider(null)}
>
<ArrowLeft className="h-4 w-4" />
</Button>
)}
{selectedProvider
? `Configure ${selectedProvider.display_name}`
: 'Add Provider'}
</div>
);
const description = selectedProvider
? `Fill in the details to set up ${selectedProvider.display_name}.`
: 'Select a provider to add to your configuration.';
return (
<AppDialog
open={open}
onOpenChange={onOpenChange}
title={title}
description={description}
className="sm:max-w-xl"
bodyClassName="p-5 overflow-hidden flex flex-col"
>
<div className="flex-1 overflow-hidden h-full flex flex-col">
{isLoading ? (
<div className="flex items-center justify-center p-8">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
) : selectedProvider ? (
<ConfigurationForm
category={selectedProvider.category}
providerName={selectedProvider.provider_name}
displayName={selectedProvider.display_name}
logoUrl={selectedProvider.logo_url}
accountId={accountId}
onSuccess={handleSuccess}
onCancel={() => setSelectedProvider(null)}
/>
) : (
<ScrollArea className="flex-1">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 py-2">
{availableProviders.map((p) => {
const isVerified = VERIFIED_PROVIDERS.includes(p.provider_name);
return (
<Button
key={`${p.category}:${p.provider_name}`}
variant="outline"
className="h-24 flex flex-col items-center justify-center gap-2 hover:border-primary hover:bg-primary/5 transition-all text-center p-4 relative"
onClick={() => setSelectedProvider(p)}
>
{isVerified && (
<div className="absolute top-2 right-2">
<BadgeCheck className="h-4 w-4 text-green-600 dark:text-green-500" />
</div>
)}
<ProviderLogo
logoUrl={p.logo_url}
providerName={p.provider_name}
className="h-8 w-8"
size={32}
/>
<div className="flex flex-col">
<span className="font-medium text-sm line-clamp-1">{p.display_name}</span>
<span className="text-[10px] text-muted-foreground uppercase">{p.category.replace('_', ' ')}</span>
</div>
</Button>
);
})}
{availableProviders.length === 0 && (
<div className="col-span-full py-12 text-center text-muted-foreground">
No providers available for this category.
</div>
)}
</div>
</ScrollArea>
)}
</div>
</AppDialog>
);
};
|