File size: 6,986 Bytes
eecbedf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import { useRef, useState } from "react";
import { Images, Upload } from "lucide-react";
import Image from "next/image";

import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { Page, Project } from "@/types";
import Loading from "@/components/loading";
import { RiCheckboxCircleFill } from "react-icons/ri";
import { useUser } from "@/hooks/useUser";
import { LoginModal } from "@/components/login-modal";
import { DeployButtonContent } from "../deploy-button/content";

export const Uploader = ({
  pages,
  onLoading,
  isLoading,
  onFiles,
  onSelectFile,
  selectedFiles,
  files,
  project,
}: {
  pages: Page[];
  onLoading: (isLoading: boolean) => void;
  isLoading: boolean;
  files: string[];
  onFiles: React.Dispatch<React.SetStateAction<string[]>>;
  onSelectFile: (file: string) => void;
  selectedFiles: string[];
  project?: Project | null;
}) => {
  const { user } = useUser();

  const [open, setOpen] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const uploadFiles = async (files: FileList | null) => {
    if (!files) return;
    if (!project) return;

    onLoading(true);

    const images = Array.from(files).filter((file) => {
      return file.type.startsWith("image/");
    });

    const data = new FormData();
    images.forEach((image) => {
      data.append("images", image);
    });

    const response = await fetch(
      `/api/me/projects/${project.space_id}/images`,
      {
        method: "POST",
        body: data,
      }
    );
    if (response.ok) {
      const data = await response.json();
      onFiles((prev) => [...prev, ...data.uploadedFiles]);
    }
    onLoading(false);
  };

  // TODO FIRST PUBLISH YOUR PROJECT TO UPLOAD IMAGES.
  return user?.id ? (
    <Popover open={open} onOpenChange={setOpen}>
      <form>
        <PopoverTrigger asChild>
          <Button
            size="iconXs"
            variant="outline"
            className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
          >
            <Images className="size-4" />
          </Button>
        </PopoverTrigger>
        <PopoverContent
          align="start"
          className="!rounded-2xl !p-0 !bg-white !border-neutral-100 min-w-xs text-center overflow-hidden"
        >
          {project?.space_id ? (
            <>
              <header className="bg-neutral-50 p-6 border-b border-neutral-200/60">
                <div className="flex items-center justify-center -space-x-4 mb-3">
                  <div className="size-9 rounded-full bg-pink-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
                    🎨
                  </div>
                  <div className="size-11 rounded-full bg-amber-200 shadow-2xl flex items-center justify-center text-2xl z-2">
                    🖼️
                  </div>
                  <div className="size-9 rounded-full bg-sky-200 shadow-2xs flex items-center justify-center text-xl opacity-50">
                    💻
                  </div>
                </div>
                <p className="text-xl font-semibold text-neutral-950">
                  Add Custom Images
                </p>
                <p className="text-sm text-neutral-500 mt-1.5">
                  Upload images to your project and use them with DeepSite!
                </p>
              </header>
              <main className="space-y-4 p-5">
                <div>
                  <p className="text-xs text-left text-neutral-700 mb-2">
                    Uploaded Images
                  </p>
                  <div className="grid grid-cols-4 gap-1 flex-wrap max-h-40 overflow-y-auto">
                    {files.map((file) => (
                      <div
                        key={file}
                        className="select-none relative cursor-pointer bg-white rounded-md border-[2px] border-white hover:shadow-2xl transition-all duration-300"
                        onClick={() => onSelectFile(file)}
                      >
                        <Image
                          src={file}
                          alt="uploaded image"
                          width={56}
                          height={56}
                          className="object-cover w-full rounded-sm aspect-square"
                        />
                        {selectedFiles.includes(file) && (
                          <div className="absolute top-0 right-0 h-full w-full flex items-center justify-center bg-black/50 rounded-md">
                            <RiCheckboxCircleFill className="size-6 text-neutral-100" />
                          </div>
                        )}
                      </div>
                    ))}
                  </div>
                </div>
                <div>
                  <p className="text-xs text-left text-neutral-700 mb-2">
                    Or import images from your computer
                  </p>
                  <Button
                    variant="black"
                    onClick={() => fileInputRef.current?.click()}
                    className="relative w-full"
                  >
                    {isLoading ? (
                      <>
                        <Loading
                          overlay={false}
                          className="ml-2 size-4 animate-spin"
                        />
                        Uploading image(s)...
                      </>
                    ) : (
                      <>
                        <Upload className="size-4" />
                        Upload Images
                      </>
                    )}
                  </Button>
                  <input
                    ref={fileInputRef}
                    type="file"
                    className="hidden"
                    multiple
                    accept="image/*"
                    onChange={(e) => uploadFiles(e.target.files)}
                  />
                </div>
              </main>
            </>
          ) : (
            <DeployButtonContent
              pages={pages}
              prompts={[]}
              options={{
                description: "Publish your project first to add custom images.",
              }}
            />
          )}
        </PopoverContent>
      </form>
    </Popover>
  ) : (
    <>
      <Button
        size="iconXs"
        variant="outline"
        className="!border-neutral-600 !text-neutral-400 !hover:!border-neutral-500 hover:!text-neutral-300"
        onClick={() => setOpen(true)}
      >
        <Images className="size-4" />
      </Button>
      <LoginModal
        open={open}
        onClose={() => setOpen(false)}
        pages={pages}
        title="Log In to add Custom Images"
        description="Log In through your Hugging Face account to publish your project and increase your monthly free limit."
      />
    </>
  );
};