gilded / client /src /components /modals /CreateServerModal.jsx
OmegaOne
Upload 41 files
0a8fe79 verified
import React, { useState, useRef } from 'react';
export default function CreateServerModal({ onClose, onCreated, token }) {
const [name, setName] = useState('');
const [icon, setIcon] = useState(null);
const [iconPreview, setIconPreview] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const fileRef = useRef(null);
const handleIconChange = (e) => {
const file = e.target.files?.[0];
if (file) {
setIcon(file);
const reader = new FileReader();
reader.onloadend = () => setIconPreview(reader.result);
reader.readAsDataURL(file);
}
};
const handleCreate = async (e) => {
e.preventDefault();
if (!name.trim()) { setError('Server name is required'); return; }
setLoading(true);
setError('');
try {
// Upload icon first if provided
let iconUrl = null;
if (icon) {
const form = new FormData();
form.append('file', icon);
const uploadRes = await fetch('/api/upload', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: form,
});
if (uploadRes.ok) {
const uploadData = await uploadRes.json();
iconUrl = uploadData.url;
}
}
const body = { name: name.trim() };
if (iconUrl) body.icon = iconUrl;
const res = await fetch('/api/servers', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) {
const data = await res.json().catch(() => ({}));
throw new Error(data.error || 'Failed to create server');
}
const data = await res.json();
onCreated(data.server || data);
onClose();
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50" onClick={onClose}>
<div className="bg-[#1e1e22] rounded-xl p-6 max-w-md w-full mx-4 shadow-2xl" onClick={e => e.stopPropagation()}>
<h2 className="text-xl font-bold text-[#FFD700] mb-6 text-center">Create Your Server</h2>
<form onSubmit={handleCreate}>
{/* Icon upload */}
<div className="flex justify-center mb-6">
<button
type="button"
onClick={() => fileRef.current?.click()}
className="w-20 h-20 rounded-full bg-[#25252a] border-2 border-dashed border-[#3a3a42] hover:border-[#FFD700]/50 flex items-center justify-center transition-colors duration-200 overflow-hidden"
>
{iconPreview ? (
<img src={iconPreview} alt="" className="w-full h-full object-cover" />
) : (
<div className="text-center">
<svg className="w-6 h-6 text-gray-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span className="text-[10px] text-gray-500">Icon</span>
</div>
)}
</button>
<input ref={fileRef} type="file" accept="image/*" className="hidden" onChange={handleIconChange} />
</div>
{/* Server name */}
<div className="mb-4">
<label className="block text-sm font-medium text-gray-300 mb-1.5">Server Name</label>
<input
type="text"
value={name}
onChange={e => setName(e.target.value)}
placeholder="My Awesome Server"
className="w-full bg-[#111114] border border-[#3a3a42] rounded-lg px-4 py-2.5 text-gray-100 placeholder-gray-500 outline-none focus:border-[#FFD700]/50 transition-colors duration-200"
autoFocus
maxLength={100}
/>
</div>
{error && <p className="text-red-400 text-sm mb-4">{error}</p>}
{/* Buttons */}
<div className="flex gap-3 justify-end">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-gray-400 hover:text-gray-200 transition-colors duration-200 rounded-lg"
>
Cancel
</button>
<button
type="submit"
disabled={loading || !name.trim()}
className="px-6 py-2 bg-[#FFD700] text-black font-semibold rounded-lg hover:bg-yellow-400 disabled:opacity-50 disabled:cursor-not-allowed transition-colors duration-200"
>
{loading ? 'Creating…' : 'Create'}
</button>
</div>
</form>
</div>
</div>
);
}