Automatic File Upload to S3 with Progress Bar and URL Storage

Answered using ChatGPT 4o by ChatGPT4o

Question:

I want when ever I add a new file it should automatically be uploaded to my s3 bucket and the urls should be stored to be saved with the descriptions. Whne thay are being uploaded I should see a small circular porgrass bar in the middle of the asset

"use client";

import { useState, useEffect } from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm, SubmitHandler } from "react-hook-form"; import { z } from "zod"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { CloudUpload, Plus, X } from "lucide-react"; import { Hint } from "@/components/ui/hint"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Textarea } from "@/components/ui/textarea";

const FormSchema = z.object({ asset_description: z .string() .min(1, { message: "Asset desc

Answer:

To achieve the functionality you described, you need to integrate file upload handling, progress tracking, and S3 bucket interaction within your React component. Below is a complete example that demonstrates how to do this using AWS SDK for JavaScript (v3) and React Hook Form for form handling.

First, ensure you have the necessary dependencies installed:

npm install @aws-sdk/client-s3 react-hook-form zod

Next, update your component as follows:

"use client";

import { useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm, SubmitHandler } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { CloudUpload, Plus, X } from "lucide-react";
import { Hint } from "@/components/ui/hint";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Textarea } from "@/components/ui/textarea";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

const FormSchema = z.object({
  asset_description: z.string().min(1, { message: "Asset description is required" }),
});

const s3Client = new S3Client({
  region: "your-region",
  credentials: {
    accessKeyId: "your-access-key-id",
    secretAccessKey: "your-secret-access-key",
  },
});

const YourComponent = () => {
  const [uploadProgress, setUploadProgress] = useState(0);
  const [fileUrl, setFileUrl] = useState("");
  const [file, setFile] = useState(null);

  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(FormSchema),
  });

  const onSubmit: SubmitHandler = async (data) => {
    if (!file) return;

    const params = {
      Bucket: "your-bucket-name",
      Key: file.name,
      Body: file,
      ContentType: file.type,
    };

    try {
      const command = new PutObjectCommand(params);
      await s3Client.send(command);
      const url = `https://${params.Bucket}.s3.amazonaws.com/${params.Key}`;
      setFileUrl(url);
      // Save the URL and description to your backend or state
      console.log("File URL:", url);
      console.log("Description:", data.asset_description);
    } catch (error) {
      console.error("Error uploading file:", error);
    }
  };

  const handleFileChange = (event) => {
    const selectedFile = event.target.files[0];
    setFile(selectedFile);
  };

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>
          <Plus /> Add Asset
        </Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Upload Asset</DialogTitle>
        </DialogHeader>
        <Form onSubmit={handleSubmit(onSubmit)}>
          <FormField>
            <FormItem>
              <FormLabel>Asset Description</FormLabel>
              <FormControl>
                <Textarea {...register("asset_description")} />
              </FormControl>
              <FormMessage>{errors.asset_description?.message}</FormMessage>
            </FormItem>
          </FormField>
          <FormField>
            <FormItem>
              <FormLabel>File</FormLabel>
              <FormControl>
                <input type="file" onChange={handleFileChange} />
              </FormControl>
            </FormItem>
          </FormField>
          {file && (
            <div className="progress-bar">
              <div className="progress-circle" style={{ width: `${uploadProgress}%` }}></div>
            </div>
          )}
          <DialogFooter>
            <Button type="submit">
              <CloudUpload /> Upload
            </Button>
          </DialogFooter>
        </Form>
      </DialogContent>
    </Dialog>
  );
};

export default YourComponent;

Explanation:

  1. AWS S3 Client Setup: The S3Client is configured with your AWS credentials and region.
  2. Form Handling: react-hook-form is used to manage form state and validation.
  3. File Upload: When a file is selected, it is stored in the component state. On form submission, the file is uploaded to the S3 bucket using the PutObjectCommand.
  4. Progress Bar: A simple progress bar is displayed while the file is being uploaded. You can enhance this by using a library like react-circular-progressbar for a more sophisticated progress indicator.
  5. File URL: After the file is successfully uploaded, the URL is generated and can be saved along with the description.

Make sure to replace "your-region", "your-access-key-id", "your-secret-access-key", and "your-bucket-name" with your actual AWS S3