Skip to content

Commit

Permalink
Refactor AddProject form: Add project thumbnail upload functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
CuriousCoder00 committed Oct 20, 2024
1 parent 7abfaf7 commit dc54b74
Showing 1 changed file with 124 additions and 1 deletion.
125 changes: 124 additions & 1 deletion src/components/user-multistep-form/add-project-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Button } from '../ui/button';
import { Textarea } from '../ui/textarea';
import { useToast } from '../ui/use-toast';
import { addUserProjects } from '@/actions/user.profile.actions';
import { useState } from 'react';
import { useRef, useState } from 'react';
import { LoadingSpinner } from '../loading-spinner';
import {
Select,
Expand All @@ -26,11 +26,16 @@ import {
SelectTrigger,
SelectValue,
} from '../ui/select';
import { uploadFileAction } from '@/actions/upload-to-cdn';
import { FaFileUpload } from 'react-icons/fa';
import Image from 'next/image';
import { X } from 'lucide-react';

export const AddProject = () => {
const form = useForm<projectSchemaType>({
resolver: zodResolver(projectSchema),
defaultValues: {
projectThumbnail: '',
projectName: '',
projectSummary: '',
projectGithub: '',
Expand All @@ -40,10 +45,80 @@ export const AddProject = () => {
});
const [isLoading, setIsLoading] = useState<boolean>(false);
const { toast } = useToast();
const [file, setFile] = useState<File | null>(null);
const [previewImg, setPreviewImg] = useState<string | null>(null);

const projectThumbnail = useRef<HTMLImageElement>(null);

const handleClick = () => {
const fileInput = document.getElementById('fileInput') as HTMLInputElement;

if (fileInput) {
fileInput.click();
}
};
const clearImage = () => {
const fileInput = document.getElementById('fileInput') as HTMLInputElement;

if (fileInput) {
fileInput.value = '';
}
setPreviewImg(null);
setFile(null);
};

const submitImage = async (file: File | null) => {
if (!file) return;

const formData = new FormData();
formData.append('file', file);

try {
const uniqueFileName = `${Date.now()}-${file.name}`;
formData.append('uniqueFileName', uniqueFileName);

const res = await uploadFileAction(formData, 'webp');
if (!res) {
throw new Error('Failed to upload image');
}

const uploadRes = res;
return uploadRes.url;
} catch (error) {
console.error('Image upload failed:', error);
}
};

const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = e.target.files ? e.target.files[0] : null;
if (!selectedFile) {
return;
}
if (!selectedFile.type.includes('image')) {
toast({
title:
'Invalid file format. Please upload an image file (e.g., .png, .jpg, .jpeg, .svg ) for the company logo',
variant: 'destructive',
});
return;
}
const reader = new FileReader();
reader.onload = () => {
if (projectThumbnail.current) {
projectThumbnail.current.src = reader.result as string;
}
setPreviewImg(reader.result as string);
};
reader.readAsDataURL(selectedFile);
if (selectedFile) {
setFile(selectedFile);
}
};

const onSubmit = async (data: projectSchemaType) => {
try {
setIsLoading(true);
data.projectThumbnail = (await submitImage(file)) ?? '';
const response = await addUserProjects(data);
if (!response.status) {
return toast({
Expand All @@ -55,6 +130,7 @@ export const AddProject = () => {
title: response.message,
variant: 'success',
});
setPreviewImg(null);
form.reset(form.formState.defaultValues);
} catch (_error) {
toast({
Expand All @@ -70,6 +146,53 @@ export const AddProject = () => {
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="projectThumbnail"
render={({ field }) => (
<FormItem>
<FormLabel>Project Thumbnail</FormLabel>
<FormControl>
<Input
id="fileInput"
accept="image/*"
type="file"
className="hidden"
{...field}
onChange={handleFileChange}
/>
</FormControl>
</FormItem>
)}
/>
<div className="relative">
<div
className="w-full h-20 dark:bg-gray-700 bg-gray-300 border border-dashed border-gray-500 rounded-md flex items-center justify-center cursor-pointer mt-4"
onClick={handleClick}
>
{previewImg ? (
<Image
src={previewImg}
ref={projectThumbnail}
className="object-contain w-full h-full"
alt="Company Logo"
width={200}
height={150}
/>
) : (
<FaFileUpload className="text-white text-2xl" />
)}
</div>
{previewImg && (
<button
type="button"
onClick={clearImage}
className="absolute top-0 right-0 w-5 h-5 bg-red-500 rounded-full items-center flex justify-center cursor-pointer translate-x-1/2 -translate-y-1/2"
>
<X size="16" />
</button>
)}
</div>
<FormField
control={form.control}
name="projectName"
Expand Down

0 comments on commit dc54b74

Please sign in to comment.