completed some features in market place

This commit is contained in:
Poovizhi99 2025-03-28 16:25:53 +05:30
parent a00df5716e
commit dc73c1a50b
12 changed files with 286 additions and 142 deletions

View File

@ -1,11 +1,15 @@
import React from "react";
import React, { Suspense, useEffect } from "react";
import assetImage from "../../assets/image/image.png";
import { FiileedStarsIconSmall } from "../../components/icons/marketPlaceIcons";
import { Canvas, useThree } from "@react-three/fiber";
import { ContactShadows, OrbitControls, Text } from "@react-three/drei";
import GltfLoader from "./GltfLoader";
import * as THREE from "three";
// Define the shape of the selected card
interface SelectedCard {
assetName: string;
uploadedOn: string;
uploadedOn: number;
price: number;
rating: number;
views: number;
@ -17,6 +21,14 @@ interface AssetPreviewProps {
setSelectedCard: React.Dispatch<React.SetStateAction<SelectedCard | null>>; // Type for setter function
}
function Ui() {
return (
<Text color="#6f42c1" anchorX="center" anchorY="middle" scale={0.3}>
Loading your model...
</Text>
);
}
const AssetPreview: React.FC<AssetPreviewProps> = ({
selectedCard,
setSelectedCard,
@ -27,8 +39,6 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
Math.min(5, isNaN(selectedCard.rating) ? 0 : selectedCard.rating)
);
console.log("selectedCard: ", selectedCard);
// Ensure that the rating is a valid positive integer for array length
const starsArray = Array.from({ length: rating }, (_, index) => index);
@ -36,8 +46,38 @@ const AssetPreview: React.FC<AssetPreviewProps> = ({
<div className="assetPreview-wrapper">
<div className="assetPreview">
<div className="image-preview">
<img src={assetImage} alt="" />
{/* <img src={assetImage} alt="" /> */}
{/* Add canvas here */}
<div className="canvas-container" style={{ height: "100%" }}>
<Canvas
flat
shadows
color="#FFFFFF"
camera={{ fov: 75 }}
gl={{
preserveDrawingBuffer: true,
}}
onCreated={({ scene }) => {
scene.background = new THREE.Color(0xffffff);
}}
>
<Suspense fallback={<Ui />}>
{selectedCard.assetName && (
<GltfLoader fromServer={selectedCard.assetName} />
)}
<OrbitControls minPolarAngle={0} maxPolarAngle={Math.PI / 2} />
<ContactShadows
renderOrder={2}
frames={1}
resolution={1024}
scale={120}
blur={2}
opacity={0.4}
far={100}
/>
</Suspense>
</Canvas>
</div>
</div>
<div className="asset-details-preview">

View File

@ -8,6 +8,7 @@ import {
} from "../../components/icons/marketPlaceIcons";
import assetImage from "../../assets/image/image.png";
import { getAssetDownload } from "../../services/marketplace/getAssetDownload";
interface CardProps {
assetName: string;
@ -40,9 +41,9 @@ const Card: React.FC<CardProps> = ({
return (
<div className="card-container">
<div className="icon">
{/* <a href={getAssetDownload(assetName)} download className="icon">
<DownloadIcon />
</div>
</a> */}
<div className="image-container">
<img src={image} alt={assetName} />
</div>

View File

@ -16,109 +16,11 @@ interface ModelData {
uploadDate: number;
_id: string;
}
interface ModelsProps {
models: ModelData[];
}
const CardsContainer: React.FC = () => {
const [models, setModels] = useState<ModelData[]>([]);
const array = [
{
id: 1,
name: "Asset 1",
uploadedOn: "12 Jan 23",
price: 36500,
rating: 4.5,
views: 500,
},
{
id: 2,
name: "Asset 2",
uploadedOn: "14 Jan 23",
price: 45000,
rating: 4.0,
views: 500,
},
{
id: 3,
name: "Asset 3",
uploadedOn: "15 Jan 23",
price: 52000,
rating: 4.8,
views: 500,
},
{
id: 4,
name: "Asset 4",
uploadedOn: "18 Jan 23",
price: 37000,
rating: 3.9,
views: 500,
},
{
id: 5,
name: "Asset 5",
uploadedOn: "20 Jan 23",
price: 60000,
rating: 5.0,
views: 500,
},
{
id: 6,
name: "Asset 6",
uploadedOn: "22 Jan 23",
price: 46000,
rating: 4.2,
views: 500,
},
{
id: 7,
name: "Asset 7",
uploadedOn: "25 Jan 23",
price: 38000,
rating: 4.3,
views: 500,
},
{
id: 8,
name: "Asset 8",
uploadedOn: "27 Jan 23",
price: 41000,
rating: 4.1,
views: 500,
},
{
id: 9,
name: "Asset 9",
uploadedOn: "30 Jan 23",
price: 55000,
rating: 4.6,
views: 500,
},
{
id: 10,
name: "Asset 10",
uploadedOn: "2 Feb 23",
price: 49000,
rating: 4.4,
views: 500,
},
{
id: 11,
name: "Asset 11",
uploadedOn: "5 Feb 23",
price: 62000,
rating: 5.0,
views: 500,
},
{
id: 12,
name: "Asset 12",
uploadedOn: "7 Feb 23",
price: 53000,
rating: 4.7,
views: 500,
},
];
const CardsContainer: React.FC<ModelsProps> = ({ models }) => {
const [selectedCard, setSelectedCard] = useState<{
assetName: string;
uploadedOn: number;
@ -136,33 +38,11 @@ const CardsContainer: React.FC = () => {
}) => {
setSelectedCard(cardData);
};
const getAllAssets = async () => {
try {
const assetsData = await fetchAssets();
const reversedData = [...assetsData]?.reverse().slice(0, 8);
setModels(reversedData);
} catch (error) {
} finally {
}
};
useEffect(() => {
getAllAssets();
}, []);
return (
<div className="cards-container-container">
<div className="header">Products You May Like</div>
<div className="cards-wrapper-container">
{/* {array.map((asset) => (
<Card
key={asset.id}
assetName={asset.name}
uploadedOn={asset.uploadedOn}
price={asset.price}
rating={asset.rating}
views={asset.views}
onSelectCard={handleCardSelect}
/>
))} */}
{models.length > 0 &&
models.map((assetDetail) => (
<Card
@ -171,7 +51,7 @@ const CardsContainer: React.FC = () => {
uploadedOn={assetDetail.uploadDate}
price={36500}
rating={4.5}
views={500}
views={800}
onSelectCard={handleCardSelect}
image={assetDetail.thumbnail}
/>

View File

@ -1,19 +1,69 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
// import RegularDropDown from "./ui/inputs/RegularDropDown";
import Search from "../../components/ui/inputs/Search";
import { StarsIcon } from "../../components/icons/marketPlaceIcons";
import RegularDropDown from "../../components/ui/inputs/RegularDropDown";
const FilterSearch: React.FC = () => {
import { getSortedAssets } from "../../services/marketplace/getSortedAssets";
interface ModelData {
CreatedBy: string;
animated: string | null;
category: string;
description: string;
filename: string;
isArchieve: boolean;
modelfileID: string;
tags: string;
thumbnail: string;
uploadDate: number;
_id: string;
}
interface ModelsProps {
models: ModelData[];
setModels: React.Dispatch<React.SetStateAction<ModelData[]>>;
filteredModels: ModelData[];
}
const FilterSearch: React.FC<ModelsProps> = ({
models,
setModels,
filteredModels,
}) => {
const [activeOption, setActiveOption] = useState("Sort by"); // State for active option
console.log("filteredModels: ", filteredModels);
const handleSelect = (option: string) => {
setActiveOption(option);
console.log("option: ", option);
// Alphabet ascending
// Alphabet descending
// All
};
useEffect(() => {
if (activeOption == "Alphabet ascending") {
let ascending = models
?.slice()
.sort((a, b) => a.filename.localeCompare(b.filename))
.map((val) => val);
setModels(ascending);
} else if (activeOption == "Alphabet descending") {
let descending = models
?.slice()
.sort((a, b) => b.filename.localeCompare(a.filename))
.map((val) => val);
setModels(descending);
}
}, [activeOption]);
const handleSearch = (val: string) => {
const filteredModel = filteredModels?.filter((model) =>
model.filename.toLowerCase().includes(val.toLowerCase())
);
setModels(filteredModel);
};
return (
<div className="filter-search-container">
<Search onChange={() => {}} />
<Search onChange={handleSearch} />
<RegularDropDown
header={activeOption}
options={["Alphabet ascending", "Alphabet descending", ""]}

View File

@ -0,0 +1,79 @@
import { useRef, useEffect } from "react";
import { useFrame } from "@react-three/fiber";
import { Stage, useGLTF } from "@react-three/drei";
import { AnimationMixer, AnimationAction, Object3D } from "three";
import * as THREE from "three";
import { fetchGltfUrl } from "../../services/marketplace/fetchGltfUrl";
interface GltfLoaderProps {
glbdata?: boolean;
fromServer?: string;
setAnimations?: (animations?: string[]) => void;
selectedAnimation?: string;
setSelectedAnimation?: (animation: string) => void;
}
// const getGLTFUrl = (url: string) => url; // Placeholder for your actual function
const GltfLoader: React.FC<GltfLoaderProps> = ({
glbdata,
fromServer,
setAnimations,
selectedAnimation,
}) => {
const modelUrl: any = fromServer ? fetchGltfUrl(fromServer) : glbdata;
const { scene, animations } = useGLTF(modelUrl ?? "") as {
scene: Object3D;
animations: THREE.AnimationClip[];
};
const mixer = useRef<AnimationMixer | null>(
scene ? new AnimationMixer(scene) : null
);
const actions = useRef<Record<string, AnimationAction>>({});
useEffect(() => {
if (animations.length > 0 && mixer.current && setAnimations) {
const animationNames = animations.map((animation) => animation.name);
setAnimations(animationNames);
animations.forEach((animation) => {
const action = mixer.current!.clipAction(animation);
actions.current[animation.name] = action;
});
} else {
setAnimations && setAnimations([]);
}
}, [animations, setAnimations]);
useEffect(() => {
if (actions.current && selectedAnimation) {
const action = actions.current[selectedAnimation];
if (action) {
action.reset().fadeIn(0.5).play();
return () => {
action.fadeOut(0.5);
};
}
}
}, [selectedAnimation]);
useFrame((_, delta) => {
if (mixer.current) {
mixer.current.update(delta);
}
});
return (
<Stage
adjustCamera={false}
intensity={0.5}
shadows="contact"
environment="city"
>
<primitive object={scene} scale={1} />
</Stage>
);
};
export default GltfLoader;

View File

@ -1,14 +1,46 @@
import React from "react";
import React, { useEffect, useState } from "react";
import FilterSearch from "./FilterSearch";
import CardsContainer from "./CardsContainer";
import { fetchAssets } from "../../services/marketplace/fetchAssets";
import { getAssetImages } from "../../services/factoryBuilder/assest/assets/getAssetImages";
interface ModelData {
CreatedBy: string;
animated: string | null;
category: string;
description: string;
filename: string;
isArchieve: boolean;
modelfileID: string;
tags: string;
thumbnail: string;
uploadDate: number;
_id: string;
}
const MarketPlace = () => {
const [models, setModels] = useState<ModelData[]>([]);
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
useEffect(() => {
const filteredAssets = async () => {
try {
const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6");
setModels(filt.items);
setFilteredModels(filt.items);
} catch {}
};
filteredAssets();
}, []);
return (
<div className="marketplace-wrapper">
<div className="marketplace-container">
<div className="marketPlace">
<FilterSearch />
<CardsContainer />
<FilterSearch
models={models}
setModels={setModels}
filteredModels={filteredModels}
/>
<CardsContainer models={models} />
</div>
</div>
</div>

View File

@ -0,0 +1,22 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getAssetDetails = async (filename: string) => {
try {
const response = await fetch(`${BackEnd_url}/api/v1/assetDetails`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ filename }),
});
if (!response.ok) {
throw new Error("Failed to fetch asset details");
}
const result = await response.json();
return result;
} catch (error: any) {
// console.error("Error fetching category:", error.message);
throw new Error(error.message);
}
};

View File

@ -6,6 +6,8 @@ export const fetchAssets = async () => {
throw new Error("Network response was not ok");
}
const result = await response.json();
const last10Assets = result.slice(-10);
console.log('last10Assets: ', last10Assets);
return result;
} catch (error) {
console.log("error: ", error);

View File

@ -0,0 +1,7 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const fetchGltfUrl = (filename: string) => {
if (filename) {
return `${BackEnd_url}/api/v1/getAssetFile/${filename}`;
}
return null; // or handle the case when filename is not provided
};

View File

@ -0,0 +1,4 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getAssetDownload = (filename: any) => {
return `${BackEnd_url}/api/v1/getAssetFile/${filename}.gltf`;
};

View File

@ -0,0 +1,25 @@
let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
export const getSortedAssets = async (category: any, orders: any) => {
try {
const response = await fetch(
`${BackEnd_url}/api/v1/categoryWise/${category}?sortBy=${orders}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const result = await response.json();
return result; // Return the result to be used later
} catch (error: any) {
console.error("Error fetching category:", error.message);
throw new Error(error.message);
}
};

View File

@ -126,6 +126,8 @@
display: flex;
max-height: 180px;
justify-content: center;
border-radius: #{$border-radius-medium};
overflow: hidden;
img{
height: inherit;
width: 100%;
@ -211,7 +213,7 @@
background-color: var(--background-color);
display: flex;
gap: 12px;
z-index: 100;
overflow: hidden;
border-radius: 20px;
}