| import { useState } from "react"; | |
| import { X, Loader2 } from "lucide-react"; | |
| import api from "@/lib/api"; | |
| import { toast } from "react-toastify"; | |
| interface Props { | |
| isOpen: boolean; | |
| onClose: () => void; | |
| onSuccess?: () => void; | |
| } | |
| export function CreateCollectionModal({ isOpen, onClose, onSuccess }: Props) { | |
| const [name, setName] = useState(""); | |
| const [description, setDescription] = useState(""); | |
| const [isPublic, setIsPublic] = useState(false); | |
| const [loading, setLoading] = useState(false); | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (!name.trim()) { | |
| toast.warning("Please enter a collection name"); | |
| return; | |
| } | |
| setLoading(true); | |
| try { | |
| const response = await api.post("/collections", { | |
| name: name.trim(), | |
| description: description.trim() || undefined, | |
| isPublic: isPublic | |
| }); | |
| if (response.data) { | |
| toast.success("Collection created successfully!"); | |
| setName(""); | |
| setDescription(""); | |
| setIsPublic(false); | |
| onSuccess?.(); | |
| onClose(); | |
| } | |
| } catch (err: any) { | |
| console.error("Create collection error:", err); | |
| const errorMsg = err.response?.data?.error || "Failed to create collection"; | |
| toast.error(errorMsg); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (!isOpen) return null; | |
| return ( | |
| <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4"> | |
| <div className="relative w-full max-w-md rounded-2xl bg-white dark:bg-gray-800 shadow-2xl"> | |
| {/* Header */} | |
| <div className="flex items-center justify-between border-b border-gray-200 dark:border-gray-700 p-5"> | |
| <h2 className="text-xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent"> | |
| Create New Collection | |
| </h2> | |
| <button | |
| onClick={onClose} | |
| className="p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition" | |
| > | |
| <X className="w-5 h-5 text-gray-500" /> | |
| </button> | |
| </div> | |
| {/* Form */} | |
| <form onSubmit={handleSubmit} className="p-5 space-y-4"> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> | |
| Collection Name * | |
| </label> | |
| <input | |
| type="text" | |
| value={name} | |
| onChange={(e) => setName(e.target.value)} | |
| placeholder="e.g., Machine Learning Papers" | |
| className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary dark:bg-gray-700 transition" | |
| required | |
| disabled={loading} | |
| /> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> | |
| Description | |
| </label> | |
| <textarea | |
| value={description} | |
| onChange={(e) => setDescription(e.target.value)} | |
| placeholder="Brief description of this collection" | |
| rows={3} | |
| className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary dark:bg-gray-700 transition resize-none" | |
| disabled={loading} | |
| /> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <input | |
| type="checkbox" | |
| id="isPublic" | |
| checked={isPublic} | |
| onChange={(e) => setIsPublic(e.target.checked)} | |
| className="w-4 h-4 text-primary rounded border-gray-300 focus:ring-primary" | |
| disabled={loading} | |
| /> | |
| <label htmlFor="isPublic" className="text-sm text-gray-700 dark:text-gray-300"> | |
| Make this collection public | |
| </label> | |
| </div> | |
| {/* Buttons */} | |
| <div className="flex gap-3 pt-2"> | |
| <button | |
| type="button" | |
| onClick={onClose} | |
| className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition" | |
| disabled={loading} | |
| > | |
| Cancel | |
| </button> | |
| <button | |
| type="submit" | |
| disabled={loading} | |
| className="flex-1 px-4 py-2 bg-gradient-to-r from-primary to-secondary text-white rounded-lg font-medium hover:shadow-lg transition disabled:opacity-50 flex items-center justify-center gap-2" | |
| > | |
| {loading ? ( | |
| <> | |
| <Loader2 className="w-4 h-4 animate-spin" /> | |
| Creating... | |
| </> | |
| ) : ( | |
| "Create Collection" | |
| )} | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| ); | |
| } |
Xet Storage Details
- Size:
- 5.05 kB
- Xet hash:
- 0fde1c376b77616be76c7c658520264bca4401c795c1dcc993f21e90b46c2882
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.