veza/apps/web/src/components/settings/cloud/CloudIntegrationView.tsx
senke 132da11941 aesthetic-improvements: replace secondary cyan hover states with steel (batch 2)
- Card components: CartItem, WishlistView, PostCard, GroupCard, PlaylistsView, UserCard (7 files)
- Settings components: BackupsView, SessionManagement, CloudIntegrationView, OfflineQueueManager (4 files)
- DashboardPage: stat cards and activity items hover states (2 instances)
- FeedView: input and button hover states (2 instances)
- Upload zones: MetadataForm, CreatePlaylistModal, CreateProductView, AddEquipmentView, CreateGroupModal (5 files, 6 instances)
- UserCard: avatar border hover state
- Total: ~18 files, ~20 instances replaced
- Preserved: Focus rings (cyan), active/selected states (cyan)
- Action 11.3.1.2 in progress (second batch complete)
2026-01-16 10:53:34 +01:00

226 lines
8.4 KiB
TypeScript

import React, { useState } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { Input } from '../../ui/input';
import { Cloud, CheckCircle, RefreshCw, Server, Shield } from 'lucide-react';
import { useToast } from '../../../context/ToastContext';
import { ProgressBar } from '../../ui/progress';
export const CloudIntegrationView: React.FC = () => {
const { addToast } = useToast();
const [isConnected, setIsConnected] = useState(false);
const [url, setUrl] = useState('');
const [username, setUsername] = useState('');
const [autoSync, setAutoSync] = useState(true);
const handleConnect = () => {
if (!url || !username) return;
// Simulate connection
addToast('Connecting to Nextcloud...', 'info');
setTimeout(() => {
setIsConnected(true);
addToast('Connected to Cloud Storage', 'success');
}, 1500);
};
return (
<div className="max-w-4xl mx-auto space-y-8 animate-fadeIn">
{/* Connection Status */}
<Card variant="default" className="border-t-4 border-t-kodo-cyan">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
<div className="flex items-center gap-4">
<div
className={`w-16 h-16 rounded-full flex items-center justify-center ${isConnected ? 'bg-kodo-cyan text-black' : 'bg-kodo-steel text-kodo-content-dim'}`}
>
<Cloud className="w-8 h-8" />
</div>
<div>
<h2 className="text-2xl font-bold text-white">
Nextcloud Integration
</h2>
<p className="text-kodo-content-dim text-sm">
Sync your projects, samples, and presets.
</p>
</div>
</div>
{isConnected && (
<div className="flex items-center gap-2 text-kodo-lime bg-kodo-lime/10 px-4 py-2 rounded-lg border border-kodo-lime/20">
<CheckCircle className="w-5 h-5" /> Connected
</div>
)}
</div>
{!isConnected ? (
<div className="mt-8 space-y-4 max-w-md">
<Input
label="Server URL"
placeholder="https://cloud.example.com"
value={url}
onChange={(e) => setUrl(e.target.value)}
icon={<GlobeIcon className="w-4 h-4" />}
/>
<Input
label="Username"
placeholder="user@example.com"
value={username}
onChange={(e) => setUsername(e.target.value)}
icon={<UserIcon className="w-4 h-4" />}
/>
<Input
label="Password / App Token"
type="password"
placeholder="••••••••"
icon={<LockIcon className="w-4 h-4" />}
/>
<Button
variant="primary"
className="w-full"
onClick={handleConnect}
>
Connect Account
</Button>
</div>
) : (
<div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="bg-kodo-ink p-4 rounded-lg border border-kodo-steel text-center">
<Server className="w-6 h-6 text-kodo-cyan mx-auto mb-2" />
<div className="text-sm font-bold text-white">{url}</div>
<div className="text-xs text-kodo-content-dim">Host</div>
</div>
<div className="bg-kodo-ink p-4 rounded-lg border border-kodo-steel text-center">
<RefreshCw className="w-6 h-6 text-kodo-gold mx-auto mb-2" />
<div className="text-sm font-bold text-white">Every 15 mins</div>
<div className="text-xs text-kodo-content-dim">Sync Frequency</div>
</div>
<div className="bg-kodo-ink p-4 rounded-lg border border-kodo-steel text-center">
<Shield className="w-6 h-6 text-kodo-lime mx-auto mb-2" />
<div className="text-sm font-bold text-white">Encrypted</div>
<div className="text-xs text-kodo-content-dim">Status</div>
</div>
</div>
)}
</Card>
{/* Sync Settings */}
{isConnected && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<Card variant="default">
<h3 className="font-bold text-white mb-4 border-b border-kodo-steel pb-2">
Sync Preferences
</h3>
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<div className="text-sm text-white font-bold">Auto-Sync</div>
<div className="text-xs text-kodo-content-dim">
Automatically upload new projects
</div>
</div>
<div
onClick={() => setAutoSync(!autoSync)}
className={`w-10 h-5 rounded-full relative cursor-pointer transition-colors ${autoSync ? 'bg-kodo-cyan' : 'bg-kodo-steel'}`}
>
<div
className={`absolute top-1 w-3 h-3 bg-white rounded-full transition-all ${autoSync ? 'left-6' : 'left-1'}`}
></div>
</div>
</div>
<div>
<label className="block text-xs font-bold text-kodo-content-dim uppercase mb-2">
Sync Frequency
</label>
<select className="w-full bg-kodo-ink border border-kodo-steel rounded p-2 text-white outline-none focus:border-kodo-cyan">
<option>Every 15 minutes</option>
<option>Hourly</option>
<option>Daily</option>
<option>Manual Only</option>
</select>
</div>
<div>
<label className="block text-xs font-bold text-kodo-content-dim uppercase mb-2">
Selective Sync
</label>
<div className="flex gap-2">
{['Projects', 'Samples', 'Presets'].map((type) => (
<span
key={type}
className="px-3 py-1 bg-kodo-slate rounded text-xs text-white border border-kodo-steel cursor-pointer hover:border-kodo-steel/50"
>
{type}
</span>
))}
</div>
</div>
</div>
</Card>
<Card variant="default">
<h3 className="font-bold text-white mb-4 border-b border-kodo-steel pb-2">
Storage Quota
</h3>
<div className="space-y-6">
<div className="text-center">
<div className="text-4xl font-mono font-bold text-white mb-1">
65.4 GB
</div>
<div className="text-sm text-kodo-content-dim">used of 100 GB</div>
</div>
<ProgressBar value={65.4} color="cyan" />
<div className="text-xs text-kodo-content-dim flex justify-between">
<span>0 GB</span>
<span>100 GB</span>
</div>
<Button variant="gaming" className="w-full">
UPGRADE STORAGE
</Button>
</div>
</Card>
</div>
)}
</div>
);
};
// Helper icons
const GlobeIcon = ({ className }: { className?: string }) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<circle cx="12" cy="12" r="10" />
<line x1="2" y1="12" x2="22" y2="12" />
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
</svg>
);
const UserIcon = ({ className }: { className?: string }) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
);
const LockIcon = ({ className }: { className?: string }) => (
<svg
className={className}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</svg>
);