mirror of
				https://github.com/D4M13N-D3V/neroshitron.git
				synced 2025-11-03 02:55:35 +00:00 
			
		
		
		
	feat: gallery management pages
This commit is contained in:
		
							parent
							
								
									534cbf2957
								
							
						
					
					
						commit
						28414630a4
					
				
							
								
								
									
										34
									
								
								app/api/galleries/[id]/images/names/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/api/galleries/[id]/images/names/route.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
import { NextResponse } from "next/server";
 | 
			
		||||
import { createClient } from "@/utils/supabase/server";
 | 
			
		||||
 | 
			
		||||
export async function GET(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    { params }: { params: { id: string } }
 | 
			
		||||
) {
 | 
			
		||||
    const galleryId = params.id;
 | 
			
		||||
    const supabase = createClient();
 | 
			
		||||
 | 
			
		||||
    const { data: gallery, error: galleryError } = await supabase
 | 
			
		||||
        .from('galleries')
 | 
			
		||||
        .select('*')
 | 
			
		||||
        .eq('name', galleryId)
 | 
			
		||||
        .single();
 | 
			
		||||
 | 
			
		||||
    // List all files in the galleryId path
 | 
			
		||||
    let { data: files, error } = await supabase.storage
 | 
			
		||||
        .from('galleries')
 | 
			
		||||
        .list(params.id.toLowerCase().replace(/\s+/g, '_'));
 | 
			
		||||
 | 
			
		||||
    if (files == null || error) {
 | 
			
		||||
        //console.error('Error listing files:', error);
 | 
			
		||||
        return NextResponse.error();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Extract file names from the list of files
 | 
			
		||||
    const fileNames = files.map((file) => file.name);
 | 
			
		||||
 | 
			
		||||
    // Return a JSON response with the array of file names
 | 
			
		||||
    return new Response(JSON.stringify(fileNames), {
 | 
			
		||||
        headers: { 'content-type': 'application/json' },
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
@ -28,13 +28,18 @@ export async function GET(
 | 
			
		||||
    .select('*')
 | 
			
		||||
    .eq('name', params.id)
 | 
			
		||||
    .single();
 | 
			
		||||
  let { data: files, error } = await supabase.storage.from('galleries').list(params.id);
 | 
			
		||||
  if (files == null || files?.length == 0) {
 | 
			
		||||
    return NextResponse.error();
 | 
			
		||||
 | 
			
		||||
  var thumbnailFile = gallery.thumbnail_file;
 | 
			
		||||
  if(thumbnailFile==null || thumbnailFile==""){
 | 
			
		||||
    let { data: files, error } = await supabase.storage.from('galleries').list(params.id);
 | 
			
		||||
    if (files == null || files?.length == 0) {
 | 
			
		||||
      return NextResponse.error();
 | 
			
		||||
    }
 | 
			
		||||
    thumbnailFile = files[0].name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Loop through each file, download it, convert it to base64, and add the data URL to the array
 | 
			
		||||
  let { data: blobdata, error: fileError } = await supabase.storage.from('galleries').download(params.id + "/" + files[0].name);
 | 
			
		||||
  let { data: blobdata, error: fileError } = await supabase.storage.from('galleries').download(params.id + "/" + thumbnailFile);
 | 
			
		||||
  if (fileError || blobdata == null) {
 | 
			
		||||
    //console.error('Error downloading file:', error);
 | 
			
		||||
    return NextResponse.error();
 | 
			
		||||
@ -50,7 +55,7 @@ export async function GET(
 | 
			
		||||
  if(nsfw && gallery.nsfw){
 | 
			
		||||
    blobBuffer = await blurImage(blobBuffer);
 | 
			
		||||
  }
 | 
			
		||||
  const contentType = files[0].name.endsWith('.png') ? 'image/png' : 'image/jpeg';
 | 
			
		||||
  const contentType = thumbnailFile.endsWith('.png') ? 'image/png' : 'image/jpeg';
 | 
			
		||||
  const dataUrl = `data:${contentType};base64,${blobBuffer.toString('base64')}`;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,21 +13,54 @@ export async function GET(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export async function PUT(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    { params }: { params: { id: string } }
 | 
			
		||||
  ) {
 | 
			
		||||
    const id = params.id;
 | 
			
		||||
    { params }: { params: { id: string } }){
 | 
			
		||||
 | 
			
		||||
    const supabase = createClient();
 | 
			
		||||
    const formData = await request.formData();
 | 
			
		||||
    const tags = formData.getAll('tags');
 | 
			
		||||
    const name = formData.get('name');
 | 
			
		||||
    const nsfw = formData.get('nsfw');
 | 
			
		||||
    const tier = formData.get('tier');
 | 
			
		||||
    console.log(id)
 | 
			
		||||
    const { data: gallery, error } = await supabase.from('galleries').update({ name, tags, nsfw, tier }).eq('name', id).single();
 | 
			
		||||
    const tags = JSON.parse(formData.getAll('tags').toString()) as string[];
 | 
			
		||||
    const originalName = formData.get('originalName');
 | 
			
		||||
    const name = formData.get('name')?.toString();
 | 
			
		||||
    const nsfw = formData.get('nsfw')?.toString();
 | 
			
		||||
    const tier = formData.get('tier')?.toString();
 | 
			
		||||
    const thumbnail = formData.get('thumbnail');
 | 
			
		||||
 | 
			
		||||
    console.log(tier)
 | 
			
		||||
    const { error } = await supabase.from('galleries').update({name, tags, nsfw, tier, thumbnail_file:thumbnail}).eq('name', originalName ?? '');
 | 
			
		||||
    
 | 
			
		||||
    async function renameFolder(oldFolderName: any, newFolderName: string) {
 | 
			
		||||
        // Get a list of all files in the old folder
 | 
			
		||||
        let { data: oldFiles, error } = await supabase.storage.from('galleries').list(oldFolderName);
 | 
			
		||||
        if (error) {
 | 
			
		||||
            console.error('Error fetching files:', error);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
        // Move each file to the new folder
 | 
			
		||||
        if (oldFiles) {
 | 
			
		||||
            for (let file of oldFiles) {
 | 
			
		||||
                let oldPath = file.name;
 | 
			
		||||
                let newPath = newFolderName + '/' + oldPath.split('/').pop();
 | 
			
		||||
 | 
			
		||||
                let { error: moveError } = await supabase.storage.from('galleries').move(oldPath, newPath);
 | 
			
		||||
                if (moveError) {
 | 
			
		||||
                    console.error(`Error moving file ${oldPath} to ${newPath}:`, moveError);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Delete the old folder
 | 
			
		||||
        let { error: deleteError } = await supabase.storage.from('galleries').remove([oldFolderName]);
 | 
			
		||||
        if (deleteError) {
 | 
			
		||||
            console.error('Error deleting old folder:', deleteError);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renameFolder(originalName, name ?? '');
 | 
			
		||||
 | 
			
		||||
    if(error){
 | 
			
		||||
        console.log(error)
 | 
			
		||||
        return NextResponse.error();
 | 
			
		||||
    }
 | 
			
		||||
    let { data: galleries, error:galleriesError } = await supabase
 | 
			
		||||
@ -36,6 +69,7 @@ export async function PUT(
 | 
			
		||||
    return NextResponse.json({ success: true, galleries });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export async function DELETE(
 | 
			
		||||
    request: Request,
 | 
			
		||||
    { params }: { params: { id: string } }
 | 
			
		||||
 | 
			
		||||
@ -16,19 +16,19 @@ export async function POST(request: Request) {
 | 
			
		||||
    const supabase = createClient();
 | 
			
		||||
    const formData = await request.formData();
 | 
			
		||||
    const files = formData.getAll('files');
 | 
			
		||||
    const tags = formData.getAll('tags');
 | 
			
		||||
    const tags = JSON.parse(formData.getAll('tags').toString()) as string[];
 | 
			
		||||
    const name = formData.get('name');
 | 
			
		||||
    const nsfw = formData.get('nsfw');
 | 
			
		||||
    const tier = formData.get('tier');
 | 
			
		||||
    const thumbnail = formData.get('thumbnail');
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < files.length; i++) {
 | 
			
		||||
        const file = files[i] as File; // Cast 'file' to 'File' type
 | 
			
		||||
        supabase.storage.from('galleries').upload(`${name}/${file.name}`, file);
 | 
			
		||||
    }
 | 
			
		||||
    const { data: gallery, error } = await supabase.from('galleries').insert({ name, tags, nsfw, thumbnail_file:thumbnail, tier, column_number: 3 }).single();
 | 
			
		||||
 | 
			
		||||
    const { data: gallery, error } = await supabase.from('galleries').insert({ name, tags, nsfw, tier, column_number: 3 }).single();
 | 
			
		||||
 | 
			
		||||
    let { data: galleries, error: galleriesError } = await supabase
 | 
			
		||||
    let { data: galleries, error: galleriesError } = await supabase 
 | 
			
		||||
        .from('galleries')
 | 
			
		||||
        .select('*');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ function PageComponent() {
 | 
			
		||||
    const [nsfw, setNsfw] = useState<boolean>(false);
 | 
			
		||||
    const [tags, setTags] = useState<string[]>([]);
 | 
			
		||||
    const [tier, setTier] = useState<string>('Free');
 | 
			
		||||
    const [thumbnail, setThumbnail] = useState<string>("");
 | 
			
		||||
    const [files, setFiles] = useState<FileList>();
 | 
			
		||||
 | 
			
		||||
    const supabase = createClient();
 | 
			
		||||
@ -38,6 +39,7 @@ function PageComponent() {
 | 
			
		||||
        }
 | 
			
		||||
        formData.append('tags', JSON.stringify(tags));
 | 
			
		||||
        formData.append('nsfw', nsfw.toString());
 | 
			
		||||
        formData.append('thumbnail', thumbnail);
 | 
			
		||||
        formData.append('tier', tier);
 | 
			
		||||
        const response = await fetch('/api/galleries/admin', {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
@ -46,6 +48,7 @@ function PageComponent() {
 | 
			
		||||
 | 
			
		||||
        if (response.ok) {
 | 
			
		||||
            const data = await response.json();
 | 
			
		||||
            window.location.href = "/gallery/admin/view?id="+name;
 | 
			
		||||
        } else {
 | 
			
		||||
            console.log(response)
 | 
			
		||||
        }
 | 
			
		||||
@ -100,6 +103,7 @@ function PageComponent() {
 | 
			
		||||
                            placeholderTags={[
 | 
			
		||||
                                { value: "tags", label: "❗️ click here to add tags" },
 | 
			
		||||
                            ]}
 | 
			
		||||
                            startingTags={tags}
 | 
			
		||||
                            nsfwButtonEnabled={true}
 | 
			
		||||
                            searchChanged={(search) => { }}
 | 
			
		||||
                            nsfwChanged={(nsfw) => { }}
 | 
			
		||||
@ -121,8 +125,11 @@ function PageComponent() {
 | 
			
		||||
                            <option value="Tier 2" selected={tier === "Tier 2"}>Tier 2</option>
 | 
			
		||||
                            <option value="Tier 3" selected={tier === "Tier 3"}>Tier 3</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <select className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                            <option value="" disabled selected>Select New Thumbnail</option>
 | 
			
		||||
                        <select  onChange={e=>{setThumbnail(e.target.value)}}  className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                            <option value="" disabled selected>Select Thumbnail</option>
 | 
			
		||||
                            {files && Array.from(files).map((file: File, index: number) => (
 | 
			
		||||
                                <option key={index} value={file.name}>{file.name}</option>
 | 
			
		||||
                            ))}
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <input
 | 
			
		||||
                            className="relative m-0 block w-full min-w-0 flex-auto cursor-pointer rounded border border-solid border-secondary-lighter bg-transparent bg-clip-padding px-3 py-[0.32rem] text-base font-normal text-surface transition duration-300 ease-in-out file:-mx-3 file:-my-[0.32rem] file:me-3 file:cursor-pointer file:overflow-hidden file:rounded-none file:border-0 file:border-e file:border-solid file:border-inherit file:bg-transparent file:px-3  file:py-[0.32rem] file:text-surface focus:border-primary focus:text-gray-700 focus:shadow-inset focus:outline-none dark:border-white/70 dark:text-white  file:dark:text-white"
 | 
			
		||||
 | 
			
		||||
@ -12,10 +12,14 @@ function PageComponent() {
 | 
			
		||||
    const supabase = createClient();
 | 
			
		||||
    const user = supabase.auth.getUser();
 | 
			
		||||
    const [gallery , setGallery] = useState<any>(null);
 | 
			
		||||
    const [originalName, setOriginalGalleryName] = useState<string>('');
 | 
			
		||||
    const [galleryName, setGalleryName] = useState<string>('');
 | 
			
		||||
    const [nsfw, setNsfw] = useState<boolean>(false);
 | 
			
		||||
    const [tags, setTags] = useState<string[]>([]);
 | 
			
		||||
    const [tier, setTier] = useState<string>('Free');
 | 
			
		||||
    const [thumbnail, setThumbnail] = useState<string>();
 | 
			
		||||
    const [fileNames, setFileNames] = useState<string[]>([]);
 | 
			
		||||
    const [selectedTags, setSelectedTags] = useState<string[]>([]);
 | 
			
		||||
 | 
			
		||||
    const getData = async () => {
 | 
			
		||||
        const urlParams = new URLSearchParams(window.location.search);
 | 
			
		||||
@ -28,14 +32,29 @@ function PageComponent() {
 | 
			
		||||
        });
 | 
			
		||||
        const galleryData = await galleryResponse.json();
 | 
			
		||||
        setGallery(galleryData.gallery);
 | 
			
		||||
 | 
			
		||||
        const filesResponse = await fetch(`/api/galleries/${id}/images/names`, {
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            headers: {
 | 
			
		||||
            'Content-Type': 'application/json'
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        const filesData = await filesResponse.json();
 | 
			
		||||
        setFileNames(filesData);
 | 
			
		||||
 | 
			
		||||
        setNsfw(galleryData.gallery.nsfw);
 | 
			
		||||
        setTags(galleryData.gallery.tags);
 | 
			
		||||
        setTier(galleryData.gallery.tier);
 | 
			
		||||
        setGalleryName(galleryData.gallery.name);
 | 
			
		||||
        if(originalName === ''){
 | 
			
		||||
            setOriginalGalleryName(galleryData.gallery.name);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        getData();
 | 
			
		||||
    }, []);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    }, [gallery]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    }, [gallery, ]);
 | 
			
		||||
@ -54,29 +73,55 @@ function PageComponent() {
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
        formData.append('id', gallery.id);
 | 
			
		||||
        formData.append('name', galleryName);
 | 
			
		||||
        formData.append('tags', JSON.stringify(tags));
 | 
			
		||||
        formData.append('thumbnail', thumbnail ?? '');
 | 
			
		||||
        formData.append('originalName', originalName);
 | 
			
		||||
        formData.append('tags', JSON.stringify(selectedTags));
 | 
			
		||||
        formData.append('nsfw', nsfw.toString());
 | 
			
		||||
        formData.append('tier', tier);
 | 
			
		||||
        const response = await fetch(`/api/galleries/admin/${id}`, {
 | 
			
		||||
        const response = await fetch(`/api/galleries/admin/${originalName}`, {
 | 
			
		||||
            method: 'PUT',
 | 
			
		||||
            body: formData,
 | 
			
		||||
            body: formData
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (response.ok) {
 | 
			
		||||
            console.log(response)
 | 
			
		||||
            const data = await response.json();
 | 
			
		||||
        } else {
 | 
			
		||||
            console.log(response)
 | 
			
		||||
        }
 | 
			
		||||
        if(originalName != galleryName){
 | 
			
		||||
            window.location.href=`/gallery/admin/view?id=${galleryName}`
 | 
			
		||||
        }
 | 
			
		||||
        else{
 | 
			
		||||
            window.location.reload();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const deleteGallery = async () => {
 | 
			
		||||
        const urlParams = new URLSearchParams(window.location.search);
 | 
			
		||||
        const id = urlParams.get('id');
 | 
			
		||||
        const response = await fetch(`/api/gallery/admin/${id}`, {
 | 
			
		||||
            method: 'DELETE',
 | 
			
		||||
            headers: {
 | 
			
		||||
            'Content-Type': 'application/json'
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        if (response.ok) {
 | 
			
		||||
            const data = await response.json();
 | 
			
		||||
            window.location.href = "/gallery/admin";
 | 
			
		||||
        } else {
 | 
			
		||||
            console.log(response)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="w-full text-white flex justify-center items-center animate-in">
 | 
			
		||||
        <div  className="w-full text-white flex justify-center items-center animate-in">
 | 
			
		||||
            <div className="w-full lg:w-1/2 rounded-md p-12 mt-14 ">
 | 
			
		||||
                <div className="w-full flex pb-60">
 | 
			
		||||
                    {gallery != null && (
 | 
			
		||||
                        <GalleryThumbnail
 | 
			
		||||
                            key={"galleryThumbnail"+galleryName+"-"+tags.join("")}
 | 
			
		||||
                            id={galleryName}
 | 
			
		||||
                            id={originalName}
 | 
			
		||||
                            columns={3}
 | 
			
		||||
                            onSelect={function (id: string, columns: number): void {}}
 | 
			
		||||
                            title={galleryName}
 | 
			
		||||
@ -97,7 +142,7 @@ function PageComponent() {
 | 
			
		||||
                    />
 | 
			
		||||
                    <div className="w-1/6">
 | 
			
		||||
                        <button
 | 
			
		||||
                            onClick={() => (window.location.href = "/gallery/admin")}
 | 
			
		||||
                            onClick={() => deleteGallery()}
 | 
			
		||||
                            className="w-full bg-error hover:bg-error-light text-white rounded-md p-2"
 | 
			
		||||
                        >
 | 
			
		||||
                            Delete
 | 
			
		||||
@ -119,32 +164,43 @@ function PageComponent() {
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className="w-full flex opacity-90 backdrop-blur-lg bg-primary  shadow-lg p-8 pt-0 rounded">
 | 
			
		||||
                    <div className="w-1/2 mr-2">
 | 
			
		||||
                        {gallery &&(
 | 
			
		||||
                        <SearchInput
 | 
			
		||||
                            placeholderTags={[
 | 
			
		||||
                                { value: "tags", label: "❗️ click here to add tags" },
 | 
			
		||||
                            ]}
 | 
			
		||||
                        placeholderTags={[
 | 
			
		||||
                            { value: "tags", label: "❗️ click here to add tags" },
 | 
			
		||||
                        ]}
 | 
			
		||||
                            startingTags={gallery.tags}
 | 
			
		||||
                            nsfwButtonEnabled={true}
 | 
			
		||||
                            searchChanged={(search) => {}}
 | 
			
		||||
                            nsfwChanged={(nsfw) => {}}
 | 
			
		||||
                            tagsChanged={(tags) => {}}
 | 
			
		||||
                            tagsChanged={(tags) => { setSelectedTags(tags) }}
 | 
			
		||||
                        />
 | 
			
		||||
                        )}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div className="w-1/2">
 | 
			
		||||
                    {gallery != null && (<>
 | 
			
		||||
                        <select value={nsfw ? "NSFW" : "SFW"} className="mb-2 shadow-lg rounded-md bg-secondary p-2 w-full text-white" onChange={e=>{
 | 
			
		||||
                            setNsfw(e.target.value === "NSFW");
 | 
			
		||||
                            setNsfw(e.target.value == "NSFW");
 | 
			
		||||
                        }}>
 | 
			
		||||
                            <option value="" disabled >Set NSFW</option>
 | 
			
		||||
                            <option value="NSFW" selected={nsfw}>NSFW</option>
 | 
			
		||||
                            <option value="SFW" selected={nsfw}>SFW</option>
 | 
			
		||||
                            <option value="SFW" selected={!nsfw}>SFW</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <select className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                        <select onChange={e=>{
 | 
			
		||||
                            setTier(e.target.value);
 | 
			
		||||
                        
 | 
			
		||||
                        }} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                            <option value="" disabled >Select New Tier</option>
 | 
			
		||||
                            <option value="Free"   selected={tier === "Free"}>Free</option>
 | 
			
		||||
                            <option value="Tier 1" selected={tier === "Tier 1"}>Tier 1</option>
 | 
			
		||||
                            <option value="Tier 2" selected={tier === "Tier 2"}>Tier 2</option>
 | 
			
		||||
                            <option value="Tier 3" selected={tier === "Tier 3"}>Tier 3</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <select className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                        <select onChange={e=>{setThumbnail(e.target.value)}} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
 | 
			
		||||
                            <option value="" disabled selected>Select New Thumbnail</option>
 | 
			
		||||
                            {fileNames.map((name, index) => (
 | 
			
		||||
                                <option selected={name==gallery.thumbnail_file} key={index} value={name}>{name}</option>
 | 
			
		||||
                            ))}
 | 
			
		||||
                        </select>
 | 
			
		||||
                        <Masonry breakpointCols={3} className="my-masonry-grid pl-6 col-span-2">
 | 
			
		||||
                            {filePreviews.map((preview, index) => (
 | 
			
		||||
 | 
			
		||||
@ -11,14 +11,15 @@ interface SearchInputProps {
 | 
			
		||||
  nsfwChanged: (nsfw: boolean) => void;
 | 
			
		||||
  nsfwButtonEnabled: boolean | null;
 | 
			
		||||
  placeholderTags: Option[];
 | 
			
		||||
  startingTags: string[] | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SearchInput = ({ tagsChanged, searchChanged, nsfwChanged, nsfwButtonEnabled, placeholderTags }: SearchInputProps) => {
 | 
			
		||||
const SearchInput = ({ tagsChanged, searchChanged, nsfwChanged, nsfwButtonEnabled, placeholderTags, startingTags }: SearchInputProps) => {
 | 
			
		||||
 | 
			
		||||
  const [tagSearch, setTagSearch] = useState<string>('');
 | 
			
		||||
  const [nsfw, setNsfw] = useState<boolean>(false);
 | 
			
		||||
  const [selectedTags, setSelectedTags] = useState<string[]>([]);
 | 
			
		||||
  const [selectedTagsInput, setSelectedTagsInput] = useState<Option[]>(placeholderTags);
 | 
			
		||||
  const [selectedTags, setSelectedTags] = useState<string[]>(startingTags ?? []);
 | 
			
		||||
  const [selectedTagsInput, setSelectedTagsInput] = useState<Option[]>(startingTags?.map((tag) => ({ value: tag, label: tag })) || []);
 | 
			
		||||
  const [selectingTags, setSelectingTags] = useState<boolean>(false);
 | 
			
		||||
  const tagSelectorRef = React.useRef(null);
 | 
			
		||||
  const [tags, setTags] = useState<any[]>([]);
 | 
			
		||||
@ -29,9 +30,6 @@ const SearchInput = ({ tagsChanged, searchChanged, nsfwChanged, nsfwButtonEnable
 | 
			
		||||
    setTags(tagsData);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  const updateTags = (newTags: string[]) => {
 | 
			
		||||
    setSelectedTags(newTags)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -100,7 +100,14 @@ INSERT INTO "auth"."audit_log_entries" ("instance_id", "id", "payload", "created
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 'bf2935a0-244a-449d-925c-ca7ad6bf91d6', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 21:49:06.535623+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '88b130fb-5418-49ec-9e54-7db1df9b9353', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 21:49:06.536554+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '2aafc337-642d-4f4c-b550-b1c88b0f698a', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 22:47:33.949246+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '7b7bc3c1-3751-4e00-a08c-14b5bb3cf892', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 22:47:33.950537+00', '');
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '7b7bc3c1-3751-4e00-a08c-14b5bb3cf892', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 22:47:33.950537+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '7b3b5a37-ed60-4b75-84ae-0caba9254581', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-03 00:10:51.713229+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 'd984ff2d-6d96-43d9-9a39-703de7400fd1', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 01:10:47.663131+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 'e996a172-f818-489a-84b3-8dc8b8a1068b', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 01:10:47.663668+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '0f07359e-4c78-40a7-8711-4127dc74c0fb', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 02:08:53.524332+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 'b8f1d6e8-4e3f-473c-b0be-98f4540da6f3', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 02:08:53.525533+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '1043d8ee-0301-46e0-a451-2bb043fe6634', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 03:07:09.462821+00', ''),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '6924eb3a-0588-46ff-94dc-b45f29a06e74', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 03:07:09.463674+00', '');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -115,7 +122,7 @@ INSERT INTO "auth"."audit_log_entries" ("instance_id", "id", "payload", "created
 | 
			
		||||
 | 
			
		||||
INSERT INTO "auth"."users" ("instance_id", "id", "aud", "role", "email", "encrypted_password", "email_confirmed_at", "invited_at", "confirmation_token", "confirmation_sent_at", "recovery_token", "recovery_sent_at", "email_change_token_new", "email_change", "email_change_sent_at", "last_sign_in_at", "raw_app_meta_data", "raw_user_meta_data", "is_super_admin", "created_at", "updated_at", "phone", "phone_confirmed_at", "phone_change", "phone_change_token", "phone_change_sent_at", "email_change_token_current", "email_change_confirm_status", "banned_until", "reauthentication_token", "reauthentication_sent_at", "is_sso_user", "deleted_at", "is_anonymous") VALUES
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 'e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd', 'authenticated', 'authenticated', 'damienostler1@gmail.com', '', '2024-05-28 02:01:35.370491+00', '2024-05-27 15:44:27.171961+00', '', '2024-05-27 15:44:27.171961+00', '', NULL, '', '', NULL, '2024-05-28 02:01:35.372861+00', '{"provider": "email", "providers": ["email"]}', '{}', NULL, '2024-05-27 15:44:27.167772+00', '2024-06-01 01:54:12.344577+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '893c7701-d5df-4415-80bd-1ec089764400', 'authenticated', 'authenticated', 'damienostler1@outlook.com', '$2a$10$ISYdoWsKL7gxfRz7c5IKDOTsmcjNpGgg9OOApYLMOvtOoNTo4HGM6', '2024-05-27 14:10:29.639017+00', NULL, '', NULL, '', NULL, '', '', NULL, '2024-06-02 07:19:23.345098+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "893c7701-d5df-4415-80bd-1ec089764400", "email": "damienostler1@outlook.com", "email_verified": false, "phone_verified": false}', NULL, '2024-05-27 14:10:29.634157+00', '2024-06-02 22:47:33.95328+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false);
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', '893c7701-d5df-4415-80bd-1ec089764400', 'authenticated', 'authenticated', 'damienostler1@outlook.com', '$2a$10$ISYdoWsKL7gxfRz7c5IKDOTsmcjNpGgg9OOApYLMOvtOoNTo4HGM6', '2024-05-27 14:10:29.639017+00', NULL, '', NULL, '', NULL, '', '', NULL, '2024-06-03 00:10:51.713875+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "893c7701-d5df-4415-80bd-1ec089764400", "email": "damienostler1@outlook.com", "email_verified": false, "phone_verified": false}', NULL, '2024-05-27 14:10:29.634157+00', '2024-06-03 03:07:09.465697+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -138,7 +145,8 @@ INSERT INTO "auth"."identities" ("provider_id", "user_id", "identity_data", "pro
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
INSERT INTO "auth"."sessions" ("id", "user_id", "created_at", "updated_at", "factor_id", "aal", "not_after", "refreshed_at", "user_agent", "ip", "tag") VALUES
 | 
			
		||||
	('d3d3a53c-1b42-47cb-8701-fc95698d7106', '893c7701-d5df-4415-80bd-1ec089764400', '2024-06-02 07:19:23.345142+00', '2024-06-02 22:47:33.954405+00', NULL, 'aal1', NULL, '2024-06-02 22:47:33.954341', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', '192.168.65.1', NULL);
 | 
			
		||||
	('d3d3a53c-1b42-47cb-8701-fc95698d7106', '893c7701-d5df-4415-80bd-1ec089764400', '2024-06-02 07:19:23.345142+00', '2024-06-02 22:47:33.954405+00', NULL, 'aal1', NULL, '2024-06-02 22:47:33.954341', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', '192.168.65.1', NULL),
 | 
			
		||||
	('93e61e5f-de83-43c0-8736-57075b701efb', '893c7701-d5df-4415-80bd-1ec089764400', '2024-06-03 00:10:51.713915+00', '2024-06-03 03:07:09.466859+00', NULL, 'aal1', NULL, '2024-06-03 03:07:09.466798', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', '192.168.65.1', NULL);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -146,7 +154,8 @@ INSERT INTO "auth"."sessions" ("id", "user_id", "created_at", "updated_at", "fac
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
INSERT INTO "auth"."mfa_amr_claims" ("session_id", "created_at", "updated_at", "authentication_method", "id") VALUES
 | 
			
		||||
	('d3d3a53c-1b42-47cb-8701-fc95698d7106', '2024-06-02 07:19:23.346896+00', '2024-06-02 07:19:23.346896+00', 'password', '0d591b77-28af-4a30-a301-daacc838d19c');
 | 
			
		||||
	('d3d3a53c-1b42-47cb-8701-fc95698d7106', '2024-06-02 07:19:23.346896+00', '2024-06-02 07:19:23.346896+00', 'password', '0d591b77-28af-4a30-a301-daacc838d19c'),
 | 
			
		||||
	('93e61e5f-de83-43c0-8736-57075b701efb', '2024-06-03 00:10:51.715581+00', '2024-06-03 00:10:51.715581+00', 'password', 'c6b47f07-cd77-4dfa-be78-eb7bbccce167');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -179,7 +188,11 @@ INSERT INTO "auth"."refresh_tokens" ("instance_id", "id", "token", "user_id", "r
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 68, 'p7WgXO_PVshB62rUN5xU7A', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-02 20:49:23.87952+00', '2024-06-02 21:49:06.536985+00', '3Ycsbg5jBAuM3LxZn1UGAw', 'd3d3a53c-1b42-47cb-8701-fc95698d7106'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 69, 'p5zdPnIXjOLqif0nIF3dSg', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-02 21:49:06.537664+00', '2024-06-02 22:47:33.951389+00', 'p7WgXO_PVshB62rUN5xU7A', 'd3d3a53c-1b42-47cb-8701-fc95698d7106'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 70, 'TyWiGmwbMN4hLag9hdEfJw', '893c7701-d5df-4415-80bd-1ec089764400', false, '2024-06-02 22:47:33.952392+00', '2024-06-02 22:47:33.952392+00', 'p5zdPnIXjOLqif0nIF3dSg', 'd3d3a53c-1b42-47cb-8701-fc95698d7106'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 63, 'Fdh3420OVU8_AcHtT7SOEQ', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-02 07:19:23.345863+00', '2024-06-02 08:17:36.071756+00', NULL, 'd3d3a53c-1b42-47cb-8701-fc95698d7106');
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 63, 'Fdh3420OVU8_AcHtT7SOEQ', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-02 07:19:23.345863+00', '2024-06-02 08:17:36.071756+00', NULL, 'd3d3a53c-1b42-47cb-8701-fc95698d7106'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 71, 'K42SmAHYG6ial6I2WsSp2Q', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-03 00:10:51.714543+00', '2024-06-03 01:10:47.66392+00', NULL, '93e61e5f-de83-43c0-8736-57075b701efb'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 72, 'YrwUhJkYZp_5uG5hP-MIdw', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-03 01:10:47.664502+00', '2024-06-03 02:08:53.525987+00', 'K42SmAHYG6ial6I2WsSp2Q', '93e61e5f-de83-43c0-8736-57075b701efb'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 73, 'QCdIahteFhdcLV35WOcclw', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-03 02:08:53.52661+00', '2024-06-03 03:07:09.464089+00', 'YrwUhJkYZp_5uG5hP-MIdw', '93e61e5f-de83-43c0-8736-57075b701efb'),
 | 
			
		||||
	('00000000-0000-0000-0000-000000000000', 74, 'ib_wWqebr4i9I1enr1X16A', '893c7701-d5df-4415-80bd-1ec089764400', false, '2024-06-03 03:07:09.464595+00', '2024-06-03 03:07:09.464595+00', 'QCdIahteFhdcLV35WOcclw', '93e61e5f-de83-43c0-8736-57075b701efb');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -224,24 +237,26 @@ INSERT INTO "public"."admins" ("user_id", "created_at", "assigner") VALUES
 | 
			
		||||
-- Data for Name: galleries; Type: TABLE DATA; Schema: public; Owner: postgres
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
INSERT INTO "public"."galleries" ("name", "column_number", "tier", "tags", "nsfw") VALUES
 | 
			
		||||
	('Another Test Gallery', 3, 'Free', '{Hentai}', true),
 | 
			
		||||
	('Test Gallery', 3, 'Tier 1', '{Dojin}', true),
 | 
			
		||||
	('More Test Gallery', 3, 'Tier 3', '{Hentai,VTuber}', true),
 | 
			
		||||
	('Some More Testing', 3, 'Tier 2', '{Hentai,Dojin}', false),
 | 
			
		||||
	('Even More Testing', 3, 'Free', '{VTuber}', false),
 | 
			
		||||
	('Killa Testing Here', 3, 'Tier 1', '{VTuber,Dojin}', false),
 | 
			
		||||
	('Popcorn Tester', 3, 'Free', '{Hentai}', true);
 | 
			
		||||
INSERT INTO "public"."galleries" ("name", "column_number", "tier", "nsfw", "tags") VALUES
 | 
			
		||||
	('Another Test Gallery', 3, 'Free', true, '{Hentai}'),
 | 
			
		||||
	('Test Gallery', 3, 'Tier 1', true, '{Dojin}'),
 | 
			
		||||
	('More Test Gallery', 3, 'Tier 3', true, '{Hentai,VTuber}'),
 | 
			
		||||
	('Some More Testing', 3, 'Tier 2', false, '{Hentai,Dojin}'),
 | 
			
		||||
	('Even More Testing', 3, 'Free', false, '{VTuber}'),
 | 
			
		||||
	('Killa Testing Here', 3, 'Tier 1', false, '{VTuber,Dojin}'),
 | 
			
		||||
	('Popcorn Tester', 3, 'Free', true, '{Hentai}'),
 | 
			
		||||
	('test', 3, 'Free', false, '{"[\"hentai\"]"}'),
 | 
			
		||||
	('testtttt', 3, 'Free', false, '{"[\"hentai\"]"}');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Data for Name: tags; Type: TABLE DATA; Schema: public; Owner: postgres
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
INSERT INTO "public"."tags" ("name") VALUES
 | 
			
		||||
	('vtuber'),
 | 
			
		||||
	('hentai'),
 | 
			
		||||
	('test');
 | 
			
		||||
INSERT INTO "public"."tags" ("name", "gallery_name") VALUES
 | 
			
		||||
	('vtuber', NULL),
 | 
			
		||||
	('hentai', NULL),
 | 
			
		||||
	('test', NULL);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -256,6 +271,9 @@ INSERT INTO "public"."user_subscriptions" ("user_id", "tier") VALUES
 | 
			
		||||
-- Data for Name: buckets; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Data for Name: objects; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -270,6 +288,11 @@ INSERT INTO "public"."user_subscriptions" ("user_id", "tier") VALUES
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Data for Name: hooks; Type: TABLE DATA; Schema: supabase_functions; Owner: supabase_functions_admin
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Data for Name: secrets; Type: TABLE DATA; Schema: vault; Owner: supabase_admin
 | 
			
		||||
@ -281,7 +304,7 @@ INSERT INTO "public"."user_subscriptions" ("user_id", "tier") VALUES
 | 
			
		||||
-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 70, true);
 | 
			
		||||
SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 74, true);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
@ -291,6 +314,12 @@ SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 70, true);
 | 
			
		||||
SELECT pg_catalog.setval('"pgsodium"."key_key_id_seq"', 1, false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- Name: hooks_id_seq; Type: SEQUENCE SET; Schema: supabase_functions; Owner: supabase_functions_admin
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
-- PostgreSQL database dump complete
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user