diff --git a/package-lock.json b/package-lock.json index f7cd28a..876f4b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "react-router-dom": "^6.28.0", "sonner": "^1.7.1", "tailwind-merge": "^2.5.4", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.13.0", @@ -5204,6 +5205,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index a5979fc..7afc156 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "react-router-dom": "^6.28.0", "sonner": "^1.7.1", "tailwind-merge": "^2.5.4", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.13.0", diff --git a/src/components/ThumbnailPageComponents/ImageComparisonSlider.tsx b/src/components/ThumbnailPageComponents/ImageComparisonSlider.tsx index 332bba2..bc7d83e 100644 --- a/src/components/ThumbnailPageComponents/ImageComparisonSlider.tsx +++ b/src/components/ThumbnailPageComponents/ImageComparisonSlider.tsx @@ -43,7 +43,7 @@ const ImageComparisonSlider: React.FC = ({ ref={containerRef} style={{ position: "relative", - width: "600px", + width: "100%", height: "400px", overflow: "hidden", borderRadius: "12px", diff --git a/src/components/ThumbnailPageComponents/Modal.tsx b/src/components/ThumbnailPageComponents/Modal.tsx new file mode 100644 index 0000000..803c439 --- /dev/null +++ b/src/components/ThumbnailPageComponents/Modal.tsx @@ -0,0 +1,111 @@ +// import React, { useState } from "react"; + + +// const Modal: React.FC = () => { +// const [newModelName, setNewModelName] = useState(""); + + +// return ( +// <> + +//
+//

Create a New Model

+// setNewModelName(e.target.value)} +// style={{ +// width: "100%", +// padding: "10px", +// marginBottom: "15px", +// borderRadius: "8px", +// border: "1px solid #ccc", +// }} +// /> + +//
+//

+// Start from a photo +//

+// +// +//

{`${uploadedImages.length} file(s) selected`}

+//
+ +//
+// +// +//
+//
+ + +// +// ); +// }; + +// export default Modal; \ No newline at end of file diff --git a/src/components/ThumbnailPageComponents/Modalcontainer.tsx b/src/components/ThumbnailPageComponents/Modalcontainer.tsx new file mode 100644 index 0000000..b220ef6 --- /dev/null +++ b/src/components/ThumbnailPageComponents/Modalcontainer.tsx @@ -0,0 +1,49 @@ +import React, { useState } from "react"; +import useCounterStore from "../../store/counterstore"; + +interface ButtonProps { + triggerFunction: () => void; // Function passed as a prop +} + +const Modalcontainer: React.FC = ({ triggerFunction }) => { + const [selectedFilter, setSelectedFilter] = useState(2); + const { image_coming_from_BE, } = useCounterStore(); // ✅ Changed 'counter' to 'count' + + return ( +
+ {image_coming_from_BE && + image_coming_from_BE.map((img, index) => ( +
setSelectedFilter(index)} + className={`flex flex-col items-center cursor-pointer transition-all rounded-xl p-1 + ${ + selectedFilter === index + ? "border-2 border-purple-500" + : "border border-transparent" + } + overflow-hidden`} + > + {`Uploaded + + +
+ ))} + + {/* More Button */} + +
+ ); +}; + +export default Modalcontainer; diff --git a/src/pages/FineTuneImage/FineTuneImage.tsx b/src/pages/FineTuneImage/FineTuneImage.tsx index e4cea29..566a95f 100644 --- a/src/pages/FineTuneImage/FineTuneImage.tsx +++ b/src/pages/FineTuneImage/FineTuneImage.tsx @@ -2,6 +2,8 @@ import React, { useState, useEffect } from "react"; import mtn from "../../assets/mtn.jpg"; import Imageslider from "../../components/ThumbnailPageComponents/ImageComparisonSlider"; import JSZip from "jszip"; +import Modalcontainer from "@/components/ThumbnailPageComponents/Modalcontainer"; +import useCounterStore from "../../store/counterstore"; interface Model { name: string; @@ -18,9 +20,10 @@ const ThumbnailPage: React.FC = () => { const [inputText3, setInputText3] = useState(""); const [generatedImage, setGeneratedImage] = useState(mtn); const [uploaded_image, setuploaded_image] = useState(""); - const [image_uploaded_identifier, setimage_uploaded_identifier] = - useState(false); - + const [image_uploaded_identifier, setimage_uploaded_identifier] =useState(false); + const [image_urls, setimage_urls] = useState([]) + const {image_coming_from_BE,image_to_show_in_modal_list}=useCounterStore(); + const handleOpenModal = () => { setIsModalOpen(true); }; @@ -32,14 +35,21 @@ const ThumbnailPage: React.FC = () => { }; const handleAddModel = async () => { - if (newModelName.trim() && uploadedImages.length > 0) { + if (newModelName.trim() && uploadedImages.length >=15) { const imageUrls = uploadedImages.map((file) => URL.createObjectURL(file)); + + console.log(imageUrls,"imageURLs") + setimage_urls(imageUrls) + image_to_show_in_modal_list(imageUrls[0]); + + setModels([...models, { name: newModelName, images: imageUrls }]); const zip = new JSZip(); uploadedImages.forEach((file) => { zip.file(file.name, file); }); + // if(uploadedImages.length>=15) try { const zipBlob = await zip.generateAsync({ type: "blob" }); const formData = new FormData(); @@ -58,10 +68,16 @@ const ThumbnailPage: React.FC = () => { console.error("Error uploading zip file:", error); alert("An error occurred while uploading the zip file."); } - } else { - alert("Please provide a model name and upload at least one image."); + + + } + + + else { + alert("Please provide a model name and upload at least 15 image."); } handleCloseModal(); + setimage_uploaded_identifier(true); }; const handleGenerateImage = () => { @@ -78,13 +94,26 @@ const ThumbnailPage: React.FC = () => { setUploadedImages(filesArray); const uploadedImg = URL.createObjectURL(event.target.files[0]); setuploaded_image(uploadedImg); - setimage_uploaded_identifier(true); + // setimage_uploaded_identifier(true); + } }; useEffect(() => { console.log(uploadedImages, "uploaded images Array"); - }, [uploadedImages]); + + + let timeoutId: ReturnType; + if (image_uploaded_identifier) { + timeoutId = setTimeout(() => { + setimage_uploaded_identifier(true); + }, 4000); // 4 seconds + } + }, [image_uploaded_identifier]); + + + + return ( <> @@ -155,34 +184,7 @@ const ThumbnailPage: React.FC = () => { fontSize: "1rem", }} /> -
- setInputText2(e.target.value)} - style={{ - width: "100%", - padding: "10px 40px 10px 10px", - border: "1px solid #ccc", - borderRadius: "8px", - fontSize: "1rem", - }} - /> -
- setInputText3(e.target.value)} - style={{ - width: "100%", - padding: "10px 40px 10px 10px", - border: "1px solid #ccc", - borderRadius: "8px", - fontSize: "1rem", - }} - /> +
+ + + + +
+ + + + + + +
{ flexWrap: "wrap", gap: "10px", }} - > - {models.map((model, index) => ( - - ))} + >
+ + + + - {/*
- {models.map((model, index) => ( - - ))} -
*/} + {/* */} + {isModalOpen && ( -
+
e.stopPropagation()} // 🟢 Prevents modal from closing on clicking inside + style={{ + background: "#fff", + padding: "20px", + borderRadius: "12px", + width: "400px", + boxShadow: "0px 4px 10px rgba(46, 43, 43, 0.2)", + textAlign: "center", + position: "relative", // For positioning the close button relative to the modal + }} + > + {/* ❌ Close Button at Modal Corner */} + + + {/* 🔲 Dashed Border for Inputs and Create Button */} +
+ {/* 📋 Model Name Input */} + setNewModelName(e.target.value)} style={{ - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0, 0, 0, 0.5)", - display: "flex", - justifyContent: "center", - alignItems: "center", - zIndex: 1000, + width: "100%", + padding: "10px", + marginBottom: "15px", + borderRadius: "8px", + border: "1px solid #ccc", + }} + /> + + {/* 📤 File Upload */} +
+
+)} -
- - -
-
- - )} ); }; diff --git a/src/store/counterstore.ts b/src/store/counterstore.ts new file mode 100644 index 0000000..9369ee6 --- /dev/null +++ b/src/store/counterstore.ts @@ -0,0 +1,24 @@ +import {create} from 'zustand'; + +// Define the state type +interface CounterState { + count: number; + increment: () => void; + decrement: () => void; + reset: () => void; + image_coming_from_BE:string[] ; + image_to_show_in_modal_list:(url:string)=>void; +} + +// Create the store +const useCounterStore = create((set) => ({ + count: 0, + image_coming_from_BE:[], + increment: () => set((state) => ({ count: state.count + 1 })), + decrement: () => set((state) => ({ count: state.count - 1 })), + reset: () => set({ count: 0 }), + image_to_show_in_modal_list:(url) => set((state) => ({ image_coming_from_BE: [...state.image_coming_from_BE, url],})), + +})); + +export default useCounterStore;