feat: tags admin ui

This commit is contained in:
Damien Ostler 2024-06-02 17:35:10 -04:00
parent b6736651c5
commit 02872252b5
2 changed files with 60 additions and 13 deletions

View File

@ -5,8 +5,29 @@ import { createClient } from "@/utils/supabase/server";
export async function GET(request: Request) { export async function GET(request: Request) {
const supabase = createClient(); const supabase = createClient();
let { data: tags, error } = await supabase let { data: tags, error } = await supabase
.from('tags') .from('tags')
.select('*') .select('*')
.order('name', { ascending: true });
return NextResponse.json(tags) return NextResponse.json(tags)
} }
export async function POST(request: Request) {
const supabase = createClient();
const data = await request.json();
const { data: tag, error } = await supabase.from('tags').insert({ name: data.tag }).single();
console.log(error)
if (error) {
return NextResponse.error();
}
return NextResponse.json(tag);
}
export async function PUT(request: Request) {
const supabase = createClient();
const data = await request.json();
const { data: tag, error } = await supabase.from('tags').delete().eq('name', data.tag).single();
if (error) {
return NextResponse.error();
}
return NextResponse.json(tag);
}

View File

@ -10,12 +10,13 @@ function PageComponent() {
const supabase = createClient(); const supabase = createClient();
const user = supabase.auth.getUser(); const user = supabase.auth.getUser();
const [tags, setTags] = useState([]); const [tags, setTags] = useState<any[]>([]);
const [nsfwState, setNsfwState] = useState<boolean>(false); const [nsfwState, setNsfwState] = useState<boolean>(false);
const [tagsState, setTagsState] = useState<string[]>([]); const [tagsState, setTagsState] = useState<string[]>([]);
const [searchState, setSearchState] = useState<string>(""); const [searchState, setSearchState] = useState<string>("");
const [galleries, setGalleries] = useState([]); const [galleries, setGalleries] = useState([]);
const [tagSearch, setTagSearch] = useState<string>('');
const [newTagName, setNewTagName] = useState<string>('');
const getData = async () => { const getData = async () => {
const tagsResponse = await fetch(`/api/galleries/tags`); const tagsResponse = await fetch(`/api/galleries/tags`);
const tagsData = await tagsResponse.json(); const tagsData = await tagsResponse.json();
@ -31,6 +32,30 @@ function PageComponent() {
setGalleries(galleriesData); setGalleries(galleriesData);
} }
const createTag = async () => {
const tagsResponse = await fetch(`/api/galleries/tags`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ tag: newTagName })
});
const tagsData = await tagsResponse.json();
getData();
}
const deleteTag = async (tagParam: string) => {
const tagsResponse = await fetch(`/api/galleries/tags`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ tag:tagParam })
});
const tagsData = await tagsResponse.json();
getData();
}
useEffect(() => { useEffect(() => {
getData(); getData();
}, [tagsState]); }, [tagsState]);
@ -41,18 +66,17 @@ function PageComponent() {
{ id: 3, name: "Item 3", imageCount: 8, tier: "Tier 1" }, { id: 3, name: "Item 3", imageCount: 8, tier: "Tier 1" },
]; ];
return ( return (
<div className="w-full h-1/2 text-white flex justify-center items-center animate-in"> <div className="w-full h-1/2 text-white flex justify-center items-center animate-in">
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur"> <div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
<div className="w-full flex"> <div className="w-full flex">
<input type="text" className="mb-8 mr-2 rounded-md bg-secondary p-2 w-1/2 text-white shadow-lg" placeholder="Tag Name" /> <input type="text" onChange={(e)=>{setNewTagName(e.target.value)}} className="mb-8 mr-2 rounded-md bg-secondary p-2 w-1/2 text-white shadow-lg" placeholder="Tag Name" />
<button className="ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center"> <button onClick={createTag} className="ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
Create Create
</button> </button>
</div> </div>
<div className="w-full flex"> <div className="w-full flex">
<input type="text" className="mb-8 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white" placeholder="Search all tags by name" /> <input type="text" value={tagSearch} onChange={(e)=>{setTagSearch(e.target.value)}} className="mb-8 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white" placeholder="Search all tags by name" />
</div> </div>
<div className="w-full h-96 overflow-y-scroll no-scrollbar"> <div className="w-full h-96 overflow-y-scroll no-scrollbar">
<table className="w-full"> <table className="w-full">
@ -63,11 +87,13 @@ function PageComponent() {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{tags.map((item:any) => ( {tags.filter((value,index,array)=>{
return value.name.toLowerCase().includes(tagSearch.toLowerCase());
}).map((item:any) => (
<tr key={item.name} className="animate-in"> <tr key={item.name} className="animate-in">
<td className="px-4 py-2">{item.name}</td> <td className="px-4 py-2">{item.name}</td>
<td className="px-4 py-2"> <td className="px-4 py-2">
<button className="bg-error shadow-lg hover:bg-error-light text-white font-bold py-2 px-4 rounded float-right"> <button onClick={()=>{deleteTag(item.name)}} className="bg-error shadow-lg hover:bg-error-light text-white font-bold py-2 px-4 rounded float-right">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
<path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" /> <path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
</svg> </svg>
@ -107,12 +133,12 @@ function PageComponent() {
<td className="px-4 py-2">{item.imageCount}</td> <td className="px-4 py-2">{item.imageCount}</td>
<td className="px-4 py-2">{item.tier.replace("Tier","")}</td> <td className="px-4 py-2">{item.tier.replace("Tier","")}</td>
<td className="px-4 py-2"> <td className="px-4 py-2">
<a href="/gallery/admin/view" className="bg-secondary shadow-lg hover:bg-secondary-light text-white font-bold py-2 px-4 rounded float-right"> <button className="bg-secondary shadow-lg hover:bg-secondary-light text-white font-bold py-2 px-4 rounded float-right">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Zm3.75 11.625a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" /> <path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Zm3.75 11.625a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
</svg> </svg>
</a> </button>
</td> </td>
</tr> </tr>
))} ))}