this repo has no description
at main 239 lines 8.0 kB view raw
1"use client"; 2 3import { useState, useEffect } from "react"; 4import { useRouter } from "next/navigation"; 5 6interface MasterOwnerProfile { 7 name: string; 8} 9 10export function MasterOwnerForm() { 11 const router = useRouter(); 12 const [name, setName] = useState(""); 13 const [loading, setLoading] = useState(false); 14 const [error, setError] = useState<string | null>(null); 15 const [existingOwner, setExistingOwner] = useState<MasterOwnerProfile | null>(null); 16 const [existingOwnerUri, setExistingOwnerUri] = useState<string | null>(null); 17 const [isLoadingOwner, setIsLoadingOwner] = useState(true); 18 const [isEditing, setIsEditing] = useState(false); 19 const [showDeleteModal, setShowDeleteModal] = useState(false); 20 21 async function handleDelete() { 22 if (!existingOwnerUri) { 23 setError("Missing master owner URI"); 24 return; 25 } 26 27 setLoading(true); 28 setError(null); 29 30 try { 31 const res = await fetch("/api/master-owner", { 32 method: "DELETE", 33 headers: { "Content-Type": "application/json" }, 34 body: JSON.stringify({ uri: existingOwnerUri }), 35 }); 36 37 if (!res.ok) { 38 const data = await res.json(); 39 throw new Error(data.error || "Failed to delete master owner"); 40 } 41 42 setExistingOwner(null); 43 setExistingOwnerUri(null); 44 setIsEditing(false); 45 setShowDeleteModal(false); 46 setName(""); 47 router.refresh(); 48 } catch (err) { 49 console.error("Failed to delete master owner:", err); 50 setError((err as Error).message || "Failed to delete master owner"); 51 } finally { 52 setLoading(false); 53 } 54 } 55 56 // Fetch existing master owner profile on mount 57 useEffect(() => { 58 async function fetchOwner() { 59 try { 60 const res = await fetch("/api/master-owner"); 61 if (!res.ok) { 62 throw new Error("Failed to fetch master owner"); 63 } 64 const data = await res.json(); 65 if (data.masterOwner) { 66 setExistingOwner(data.masterOwner); 67 setExistingOwnerUri(typeof data.uri === "string" ? data.uri : null); 68 } 69 } catch (err) { 70 console.error("Failed to fetch master owner:", err); 71 } finally { 72 setIsLoadingOwner(false); 73 } 74 } 75 76 fetchOwner(); 77 }, []); 78 79 async function handleSubmit(e: React.FormEvent) { 80 e.preventDefault(); 81 setLoading(true); 82 setError(null); 83 84 try { 85 const method = isEditing ? "PUT" : "POST"; 86 const res = await fetch("/api/master-owner", { 87 method, 88 headers: { "Content-Type": "application/json" }, 89 body: JSON.stringify(isEditing ? { uri: existingOwnerUri, name } : { name }), 90 }); 91 92 if (!res.ok) { 93 throw new Error("Failed to update master owner"); 94 } 95 96 const data = await res.json(); 97 if (data.masterOwner) { 98 setExistingOwner(data.masterOwner); 99 setExistingOwnerUri(data.uri || existingOwnerUri); 100 } 101 102 setIsEditing(false); 103 setName(""); 104 105 router.refresh(); 106 } catch (err) { 107 console.error("Failed to update master owner:", err); 108 setError((err as Error).message || "Failed to save master owner"); 109 } finally { 110 setLoading(false); 111 } 112 } 113 114 // Show loading state while fetching owner 115 if (isLoadingOwner) { 116 return <div className="text-zinc-500">Loading master owner profile...</div>; 117 } 118 119 // Show existing owner profile 120 if (existingOwner && !isEditing) { 121 return ( 122 <div className="space-y-4"> 123 <div className="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800"> 124 <h3 className="text-sm font-medium text-green-900 dark:text-green-100 mb-2"> 125 Master Owner Profile Found 126 </h3> 127 <p className="mb-3 text-xs italic text-green-700 dark:text-green-300/90"> 128 A master owner owns the rights of the recording of a song. It is typically a record label and it generally assigns ISRC codes to recordings 129 </p> 130 <p className="text-sm text-green-800 dark:text-green-200"> 131 <strong>Name:</strong> {existingOwner.name} 132 </p> 133 </div> 134 <div className="flex items-center gap-2"> 135 <button 136 type="button" 137 onClick={() => { 138 setName(existingOwner.name || ""); 139 setError(null); 140 setIsEditing(true); 141 }} 142 className="inline-flex py-2 px-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50" 143 disabled={loading} 144 > 145 Edit Master Owner 146 </button> 147 <button 148 type="button" 149 onClick={() => { 150 setShowDeleteModal(true); 151 }} 152 className="inline-flex py-2 px-4 bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50" 153 disabled={loading} 154 > 155 {loading ? "Deleting..." : "Delete Master Owner"} 156 </button> 157 </div> 158 {error && <p className="text-red-500 text-sm">{error}</p>} 159 160 {showDeleteModal && ( 161 <div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50 p-4"> 162 <div className="bg-white dark:bg-zinc-900 rounded-lg shadow-lg p-4 w-full max-w-sm border border-zinc-200 dark:border-zinc-800"> 163 <h4 className="text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2"> 164 Delete Master Owner? 165 </h4> 166 <p className="text-sm text-zinc-600 dark:text-zinc-400 mb-4"> 167 This action cannot be undone. 168 </p> 169 <div className="flex gap-2 justify-end"> 170 <button 171 type="button" 172 onClick={() => setShowDeleteModal(false)} 173 className="py-2 px-3 border border-zinc-300 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg hover:bg-zinc-50 dark:hover:bg-zinc-800" 174 disabled={loading} 175 > 176 Cancel 177 </button> 178 <button 179 type="button" 180 onClick={() => { 181 void handleDelete(); 182 }} 183 className="py-2 px-3 bg-red-600 text-white rounded-lg hover:bg-red-700 disabled:opacity-50" 184 disabled={loading} 185 > 186 {loading ? "Deleting..." : "Delete"} 187 </button> 188 </div> 189 </div> 190 </div> 191 )} 192 </div> 193 ); 194 } 195 196 // Show form if no existing owner 197 return ( 198 <form onSubmit={handleSubmit} className="space-y-4"> 199 <div> 200 <label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1"> 201 Master owner name 202 </label> 203 <input 204 type="text" 205 value={name} 206 onChange={(e) => setName(e.target.value)} 207 className="w-full px-3 py-2 border border-zinc-300 dark:border-zinc-700 rounded-lg bg-white dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100" 208 disabled={loading} 209 /> 210 </div> 211 212 {error && <p className="text-red-500 text-sm">{error}</p>} 213 214 <div className="flex items-center gap-2"> 215 <button 216 type="submit" 217 disabled={loading || !name} 218 className="inline-flex py-2 px-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50" 219 > 220 {loading ? "Saving..." : isEditing ? "Update Master Owner" : "Save Master Owner"} 221 </button> 222 223 {isEditing && ( 224 <button 225 type="button" 226 onClick={() => { 227 setIsEditing(false); 228 setName(""); 229 setError(null); 230 }} 231 className="inline-flex py-2 px-4 border border-zinc-300 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg hover:bg-zinc-50 dark:hover:bg-zinc-800" 232 > 233 Cancel 234 </button> 235 )} 236 </div> 237 </form> 238 ); 239}