| | import React, { useState } from 'react'; |
| | import { motion } from 'framer-motion'; |
| | import { Upload, Image as ImageIcon, Loader } from 'lucide-react'; |
| | import axios from 'axios'; |
| |
|
| | const InteriorStyleTransformer = () => { |
| | const [selectedImage, setSelectedImage] = useState(null); |
| | const [styleInput, setStyleInput] = useState(''); |
| | const [generatedImage, setGeneratedImage] = useState(null); |
| | const [isLoading, setIsLoading] = useState(false); |
| | const [error, setError] = useState(null); |
| |
|
| | |
| | const handleImageUpload = (event) => { |
| | const file = event.target.files[0]; |
| | if (file) { |
| | setSelectedImage(URL.createObjectURL(file)); |
| | setGeneratedImage(null); |
| | setError(null); |
| | } |
| | }; |
| |
|
| | |
| | const handleStyleInput = (event) => { |
| | setStyleInput(event.target.value); |
| | }; |
| |
|
| | |
| | const handleSubmit = async () => { |
| | if (!selectedImage || !styleInput) { |
| | setError('Please upload an image and specify a design style.'); |
| | return; |
| | } |
| |
|
| | setIsLoading(true); |
| | setError(null); |
| |
|
| | try { |
| | |
| | const formData = new FormData(); |
| | const fileInput = document.querySelector('input[type="file"]'); |
| | formData.append('image', fileInput.files[0]); |
| | formData.append('style', styleInput); |
| |
|
| | |
| | const response = await axios.post('https://api.example.com/transform-interior', formData, { |
| | headers: { 'Content-Type': 'multipart/form-data' }, |
| | }); |
| |
|
| | |
| | setGeneratedImage(response.data.imageUrl); |
| | } catch (err) { |
| | setError('Failed to process the image. Please try again.'); |
| | console.error(err); |
| | } finally { |
| | setIsLoading(false); |
| | } |
| | }; |
| |
|
| | return ( |
| | <section className="py-20 bg-[#0B1118]"> |
| | <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| | <motion.div |
| | initial={{ opacity: 0, y: 20 }} |
| | whileInView={{ opacity: 1, y: 0 }} |
| | transition={{ duration: 0.8 }} |
| | className="text-center mb-12" |
| | > |
| | <h2 className="text-3xl md:text-4xl font-bold mb-4 text-white"> |
| | Transform Your Interior Design |
| | </h2> |
| | <p className="text-xl text-gray-400"> |
| | Upload a photo of your space and specify your desired interior design style. |
| | </p> |
| | </motion.div> |
| | |
| | <div className="grid grid-cols-1 md:grid-cols-2 gap-8"> |
| | {/* Image Upload Section */} |
| | <motion.div |
| | initial={{ opacity: 0, scale: 0.9 }} |
| | whileInView={{ opacity: 1, scale: 1 }} |
| | transition={{ duration: 0.5 }} |
| | className="bg-gray-800/30 rounded-lg p-6 border border-gray-700 hover:border-blue-500/50" |
| | > |
| | <h3 className="text-xl font-semibold mb-4 text-white">Upload Your Room Photo</h3> |
| | <div className="flex flex-col items-center"> |
| | <label className="w-full flex flex-col items-center px-4 py-6 bg-gray-900/50 rounded-lg border-2 border-dashed border-gray-600 cursor-pointer hover:border-blue-500"> |
| | <Upload className="h-12 w-12 text-blue-500 mb-4" /> |
| | <span className="text-gray-400"> |
| | {selectedImage ? 'Change Image' : 'Upload an Image'} |
| | </span> |
| | <input |
| | type="file" |
| | accept="image/*" |
| | className="hidden" |
| | onChange={handleImageUpload} |
| | /> |
| | </label> |
| | {selectedImage && ( |
| | <img |
| | src={selectedImage} |
| | alt="Uploaded room" |
| | className="mt-4 max-h-64 w-full object-contain rounded-lg" |
| | /> |
| | )} |
| | </div> |
| | </motion.div> |
| | |
| | {/* Style Input and Generated Image Section */} |
| | <motion.div |
| | initial={{ opacity: 0, scale: 0.9 }} |
| | whileInView={{ opacity: 1, scale: 1 }} |
| | transition={{ duration: 0.5 }} |
| | className="bg-gray-800/30 rounded-lg p-6 border border-gray-700 hover:border-blue-500/50" |
| | > |
| | <h3 className="text-xl font-semibold mb-4 text-white">Specify Design Style</h3> |
| | <input |
| | type="text" |
| | placeholder="e.g., Modern, Scandinavian, Minimalist" |
| | value={styleInput} |
| | onChange={handleStyleInput} |
| | className="w-full px-4 py-2 bg-gray-900 text-white rounded-lg border border-gray-600 focus:outline-none focus:border-blue-500 mb-4" |
| | /> |
| | <motion.button |
| | whileHover={{ scale: 1.05 }} |
| | whileTap={{ scale: 0.95 }} |
| | onClick={handleSubmit} |
| | disabled={isLoading} |
| | className="w-full px-4 py-2 bg-blue-600 text-white rounded-lg font-semibold hover:bg-blue-700 disabled:bg-gray-600" |
| | > |
| | {isLoading ? ( |
| | <div className="flex items-center justify-center"> |
| | <Loader className="h-6 w-6 animate-spin mr-2" /> |
| | Processing... |
| | </div> |
| | ) : ( |
| | 'Generate Design' |
| | )} |
| | </motion.button> |
| | {error && <p className="text-red-500 mt-4">{error}</p>} |
| | {generatedImage && ( |
| | <div className="mt-4"> |
| | <h3 className="text-lg font-semibold text-white mb-2">Generated Design</h3> |
| | <img |
| | src={generatedImage} |
| | alt="Generated interior design" |
| | className="max-h-64 w-full object-contain rounded-lg" |
| | /> |
| | </div> |
| | )} |
| | </motion.div> |
| | </div> |
| | </div> |
| | </section> |
| | ); |
| | }; |
| |
|
| | export default InteriorStyleTransformer; |