- 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)
226 lines
8.4 KiB
TypeScript
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>
|
|
);
|