Files
GNX-WEB/gnx-react/components/admin/ServiceImageUpload.tsx
Iliyan Angelov fe26b7cca4 GNXSOFT.COM
2025-09-26 00:15:37 +03:00

184 lines
4.8 KiB
TypeScript

"use client";
import { useState, useRef } from "react";
import Image from "next/image";
import { useServiceManagement } from "@/lib/hooks/useServices";
interface ServiceImageUploadProps {
serviceSlug: string;
currentImageUrl?: string;
onImageUploaded?: (service: any) => void;
}
const ServiceImageUpload: React.FC<ServiceImageUploadProps> = ({
serviceSlug,
currentImageUrl,
onImageUploaded,
}) => {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [uploading, setUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const { uploadServiceImage, loading, error } = useServiceManagement();
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
// Validate file type
if (!file.type.startsWith('image/')) {
alert('Please select an image file');
return;
}
// Validate file size (5MB limit)
if (file.size > 5 * 1024 * 1024) {
alert('File size must be less than 5MB');
return;
}
setSelectedFile(file);
// Create preview URL
const url = URL.createObjectURL(file);
setPreviewUrl(url);
}
};
const handleUpload = async () => {
if (!selectedFile) return;
try {
setUploading(true);
const updatedService = await uploadServiceImage(serviceSlug, selectedFile);
// Clean up preview URL
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
}
setSelectedFile(null);
setPreviewUrl(null);
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
if (onImageUploaded) {
onImageUploaded(updatedService);
}
alert('Image uploaded successfully!');
} catch (err) {
console.error('Upload failed:', err);
alert('Failed to upload image. Please try again.');
} finally {
setUploading(false);
}
};
const handleCancel = () => {
setSelectedFile(null);
if (previewUrl) {
URL.revokeObjectURL(previewUrl);
setPreviewUrl(null);
}
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
return (
<div className="service-image-upload">
<div className="mb-3">
<label htmlFor="image-upload" className="form-label">
Service Image
</label>
<input
ref={fileInputRef}
type="file"
id="image-upload"
className="form-control"
accept="image/*"
onChange={handleFileSelect}
disabled={uploading || loading}
/>
<div className="form-text">
Select an image file (JPG, PNG, GIF). Maximum size: 5MB.
</div>
</div>
{/* Current Image */}
{currentImageUrl && !previewUrl && (
<div className="mb-3">
<label className="form-label">Current Image:</label>
<div className="current-image">
<Image
src={currentImageUrl}
alt="Current service image"
className="img-thumbnail"
width={200}
height={200}
style={{ maxWidth: '200px', maxHeight: '200px', objectFit: 'cover' }}
/>
</div>
</div>
)}
{/* Preview */}
{previewUrl && (
<div className="mb-3">
<label className="form-label">Preview:</label>
<div className="image-preview">
<Image
src={previewUrl}
alt="Preview"
className="img-thumbnail"
width={200}
height={200}
style={{ maxWidth: '200px', maxHeight: '200px', objectFit: 'cover' }}
/>
</div>
</div>
)}
{/* Error Display */}
{error && (
<div className="alert alert-danger" role="alert">
{error}
</div>
)}
{/* Action Buttons */}
{selectedFile && (
<div className="d-flex gap-2">
<button
type="button"
className="btn btn-primary"
onClick={handleUpload}
disabled={uploading || loading}
>
{uploading || loading ? (
<>
<span className="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
Uploading...
</>
) : (
'Upload Image'
)}
</button>
<button
type="button"
className="btn btn-secondary"
onClick={handleCancel}
disabled={uploading || loading}
>
Cancel
</button>
</div>
)}
</div>
);
};
export default ServiceImageUpload;