Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add drag-and-drop image upload to Sanity storage #6

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 56 additions & 15 deletions components/StartupForm.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,68 @@
"use client";

import React, { useState, useActionState } from "react";
import React, { useState, useActionState, useCallback } from "react";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import MDEditor from "@uiw/react-md-editor";
import { Button } from "@/components/ui/button";
import { Send } from "lucide-react";
import { ImageIcon, Send } from "lucide-react";
import { formSchema } from "@/lib/validation";
import { z } from "zod";
import { useToast } from "@/hooks/use-toast";
import { useRouter } from "next/navigation";
import { createPitch } from "@/lib/actions";
import { createPitch, uploadImage } from "@/lib/actions";
import { useDropzone } from 'react-dropzone';
import Image from "next/image";


interface PreviewFile extends File {
preview: string;
}

const StartupForm = () => {
const [errors, setErrors] = useState<Record<string, string>>({});
const [pitch, setPitch] = useState("");
const { toast } = useToast();
const router = useRouter();
const [selectedImage, setSelectedImage] = useState<PreviewFile | null>(null);
const [selectedImageFile, setSelectedImageFile] = useState<File | null>(null);


// Configure react-dropzone
const onDrop = useCallback((acceptedFiles: File[]) => {
const file = acceptedFiles[0];
setSelectedImageFile(file)
setSelectedImage(
Object.assign(file, {
preview: URL.createObjectURL(file),
}) as PreviewFile
);
}, []);

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
'image/jpeg': ['.jpeg', '.jpg'],
'image/png': ['.png'],
},
maxFiles: 1
});

const handleFormSubmit = async (prevState: any, formData: FormData) => {
try {
// upload the image to sanity
if (!selectedImageFile) return toast({
title: "Success",
description: "Your startup pitch has been created successfully",
});;
const imageLink = await uploadImage(selectedImageFile)

const formValues = {
title: formData.get("title") as string,
description: formData.get("description") as string,
category: formData.get("category") as string,
link: formData.get("link") as string,
link: imageLink as string,
pitch,
};

await formSchema.parseAsync(formValues);

const result = await createPitch(prevState, formData, pitch);
Expand Down Expand Up @@ -129,16 +164,22 @@ const StartupForm = () => {

<div>
<label htmlFor="link" className="startup-form_label">
Image URL
Upload Image
</label>
<Input
id="link"
name="link"
className="startup-form_input"
required
placeholder="Startup Image URL"
/>

{/* implement the react-dropzone */}
<div {...getRootProps()} className="startup-form_textarea border-dashed cursor-pointer">
<input {...getInputProps()} />
{!isDragActive && !selectedImage ? (
<div className="flex flex-col items-center justify-center gap-y-3">
<ImageIcon size={70} className="stroke-1" />
<p className="text-black text-center">Drag 'n' Drop the image here (.png, .jpeg, .jpg) </p>
</div>
) : (
<div >
{selectedImage && <Image src={selectedImage?.preview} width={1000} height={1000} alt="Preview" className="h-full w-full object-cover" />}
</div>
)}
</div>
{errors.link && <p className="startup-form_error">{errors.link}</p>}
</div>

Expand Down
22 changes: 22 additions & 0 deletions lib/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { auth } from "@/auth";
import { parseServerActionResponse } from "@/lib/utils";
import slugify from "slugify";
import { writeClient } from "@/sanity/lib/write-client";
import { client } from "@/sanity/lib/client";

export const createPitch = async (
state: any,
Expand Down Expand Up @@ -57,3 +58,24 @@ export const createPitch = async (
});
}
};




export async function uploadImage(file:File) {
try {
// Check if the file is an image
if (!file.type.startsWith('image/')) {
throw new Error('File is not an image');
}

// Upload image to Sanity
const response = await writeClient.assets.upload('image', file);
// Get the image URL
const imageUrl = response.url;
return imageUrl;
} catch (error) {
console.error('Image upload failed:', error);
throw error;
}
}
Loading