Skip to content

Commit

Permalink
it works (#7)
Browse files Browse the repository at this point in the history
* it works

* fixed linting errors
  • Loading branch information
benhalverson authored Oct 23, 2024
1 parent 5289406 commit edba3e1
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 41 deletions.
59 changes: 53 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.1",
"three": "^0.167.1",
"three-stdlib": "^2.32.1"
"three-stdlib": "^2.32.1",
"zustand": "^5.0.0"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20240821.1",
Expand Down
17 changes: 12 additions & 5 deletions src/components/PreviewComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { usePreviewService } from "../hooks/usePreview";
import { useColorStore } from '../store/colorStore';

const GRID_SIZE = 250; // in mm
const LIMIT_DIMENSIONS_MM = { length: 250, width: 250, height: 310 }; // in mm
Expand All @@ -19,9 +20,9 @@ const PreviewComponent: React.FC<PreviewComponentProps> = ({
onExceedsLimit,
onError,
}) => {
const {color} = useColorStore()
const previewRef = useRef<HTMLDivElement | null>(null);
const { loadModel } =
usePreviewService();
const { loadModel } = usePreviewService();
const scene = useRef(new THREE.Scene()).current;
const camera = useRef(
new THREE.PerspectiveCamera(
Expand Down Expand Up @@ -72,9 +73,10 @@ const PreviewComponent: React.FC<PreviewComponentProps> = ({
};
}, []);

// Whenever the URL or color changes, reload the model
useEffect(() => {
loadModelAndCheckDimensions(url);
}, [url]);
}, [url, color]);

const initializeScene = () => {
renderer.setSize(600, 400); // Fixed size
Expand All @@ -94,7 +96,13 @@ const PreviewComponent: React.FC<PreviewComponentProps> = ({
try {
const geometry = await loadModel(url);
if (geometry) {
const material = new THREE.MeshStandardMaterial({ color: 0xb3b3b3 });
// Convert color string to hexadecimal number for Three.js
// Remove any `#` and convert the string to a number using base 16
const hexColor = parseInt(color.replace("#", ""), 16);
console.log('hexColor', hexColor);

const material = new THREE.MeshStandardMaterial({ color: hexColor }); // Apply the hex color

meshRef.current = new THREE.Mesh(geometry, material);

let boundingBox = new THREE.Box3().setFromObject(meshRef.current);
Expand Down Expand Up @@ -127,7 +135,6 @@ const PreviewComponent: React.FC<PreviewComponentProps> = ({
"Invalid file: Could not load the 3D model from the provided file."
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error(error);
setErrorMessage(error.message);
Expand Down
49 changes: 24 additions & 25 deletions src/components/colorPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,54 @@
import { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import { useEffect } from "react";
import { Radio, RadioGroup } from "@headlessui/react";
import { ColorsResponse } from "../interfaces";
// const BASE_URL = import.meta.env.VITE_BASE_URL;
const BASE_URL = "https://3dprinter-web-api.benhalverson.workers.dev";

import { useColorStore } from "../store/colorStore";


const ColorPicker: React.FC<Props> = ({filamentType}) => {
const url = new URL(`${BASE_URL}/colors`);
const {colorOptions, isLoading, setIsLoading, color, setColorOptions, setColor} = useColorStore();

const fetchColors = async (filamentType: string) => {
const fetchColors = async (filamentType?: string) => {

if(filamentType) {
url.searchParams.set("filamentType", filamentType);
}
const response = await fetch(url.toString());
return response.json() as Promise<ColorsResponse[]>;

};

const useColors = (filamentType: string) => {
return useQuery<ColorsResponse[]>({
queryKey: ["colors", filamentType],
queryFn: () => fetchColors(filamentType)
});
setColorOptions(await (response.json() as Promise<ColorsResponse[]>));
return response

};

const { data, error, isLoading } = useColors(filamentType);

const [selectedColor, setSelectedColor] = useState<string>("");

useEffect(() => {
if (data ) {
setSelectedColor(data[0]?.colorTag); // Default to the first color
if(filamentType) {

setIsLoading(true);
fetchColors(filamentType);
}
}, [data]);
setIsLoading(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [filamentType]);


if (isLoading) return <div>Loading...</div>;
if (error) return <div>No data available</div>;
// if (error) return <div>No data available</div>;

console.log('colorOptions', colorOptions);
console.log('color', color)
return (
<fieldset aria-label="Choose a color" className="mt-2">
<RadioGroup
value={selectedColor}
onChange={setSelectedColor}
value={color}
onChange={setColor}
className="flex items-center space-x-3"
>
{data?.map((color) => (
{colorOptions?.map((color, i) => (
<Radio
key={color.colorTag}
value={color.colorTag}
key={i}
value={color.hexColor}
className={({ checked }) =>
`relative -m-0.5 flex cursor-pointer items-center justify-center rounded-full p-0.5 focus:outline-none ${
checked ? "ring-2 ring-offset-1 ring-blue-500" : ""
Expand Down
66 changes: 66 additions & 0 deletions src/data/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// TODO: implent the transformData function that takes in an array of RawDataEntry objects and from manf and returns structured json for backend endpoint.
// Define the structure of a color entry
interface ColorEntry {
color: string;
hexColor: string;
colorTag: string;
}

// Define the raw data structure
interface RawDataEntry {
filament: string;
hexColor: string;
colorTag: string;
}

// Define the structure of the transformed output
interface TransformedData {
[key: string]: ColorEntry[];
}

export const rawData: RawDataEntry[] = [
{ filament: "PETG WHITE", hexColor: "f6efef", colorTag: "petgWhite" },
{ filament: "PETG BLACK", hexColor: "000000", colorTag: "petgBlack" },
{ filament: "PLA BLACK", hexColor: "000000", colorTag: "black" },
{ filament: "PLA GRAY", hexColor: "666666", colorTag: "gray" },
{ filament: "PLA WHITE", hexColor: "ffffff", colorTag: "white" },
{ filament: "PLA YELLOW", hexColor: "f5c211", colorTag: "yellow" },
{ filament: "PLA RED", hexColor: "f91010", colorTag: "red" },
{ filament: "PLA GOLD", hexColor: "d5b510", colorTag: "gold" },
{ filament: "PLA LUNAR REGOLITH", hexColor: "7d7e7e", colorTag: "lunarRegolith" },
{ filament: "PLA MATTE BLACK", hexColor: "000000", colorTag: "matteBlack" }
];

export const transformData = (data: RawDataEntry[]): TransformedData[] => {
const filamentMap: TransformedData = {};

data.forEach((item) => {
const [type, color] = item.filament.split(' '); // Split filament into type and color

const colorEntry: ColorEntry = {
color: color.toUpperCase(), // Capitalize color name
hexColor: item.hexColor,
colorTag: item.colorTag,
};

// If the filament type doesn't exist, initialize it
if (!filamentMap[type]) {
filamentMap[type] = [];
}

console.log(filamentMap);
// Push the color entry to the corresponding filament type
filamentMap[type].push(colorEntry);
});

// Convert the map into an array of objects, sorted by PLA first, PETG second
return Object.entries(filamentMap)
.sort(([keyA], [keyB]) => {
if (keyA === 'PLA') return -1;
if (keyB === 'PLA') return 1;
return keyA.localeCompare(keyB); // Sort alphabetically otherwise
})
.map(([filamentType, colors]) => ({
[filamentType]: colors,
}));
};
4 changes: 2 additions & 2 deletions src/pages/Product.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { lazy, Suspense, useState } from "react";
import { ShoppingBagIcon, UserIcon } from "@heroicons/react/24/outline";
import ColorPicker from "../components/colorPicker";
import FilamentDropdown from '../components/filamentDropdown';

const PreviewComponent = lazy(() => import("../components/PreviewComponent"));

const product = {
Expand Down Expand Up @@ -93,10 +94,9 @@ export default function ProductPage() {

<div className="mt-8 lg:col-span-5">
<form>

<div>
<h2 className="text-sm font-medium text-gray-900">Filament Selection</h2>
<FilamentDropdown selectedFilament={selectedFilament} setSelectedFilament={setSelectedFilament}/>
<FilamentDropdown selectedFilament={selectedFilament} setSelectedFilament={setSelectedFilament} />
</div>
<div>
<h2 className="text-sm font-medium text-gray-900">Color</h2>
Expand Down
5 changes: 3 additions & 2 deletions src/pages/ProductList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useEffect, useState } from "react";
// import { ProductResponse } from '../interfaces';

const BASE_URL = "https://3dprinter-web-api.benhalverson.workers.dev/list";
// const BASE_URL = "http://localhost:8787/products";

function ProductList() {
const [products, setProducts] = useState<ProductResponse[]>([]);
Expand All @@ -24,8 +25,8 @@ function ProductList() {
}, []);
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
{products.map((product, i) => (
<li key={i}>{product.name}</li>
))}
</ul>
);
Expand Down
27 changes: 27 additions & 0 deletions src/store/colorStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { create } from 'zustand';
import { ColorsResponse } from '../interfaces';

interface ColorState {
// State
colorOptions: ColorsResponse[];
color: string;
isLoading: boolean;

// Actions
setColorOptions: (colorOptions: ColorsResponse[]) => void;
setColor: (color: string) => void;
setIsLoading: (isLoading: boolean) => void;

}

export const useColorStore = create<ColorState>((set) => ({
// State
colorOptions: [],
color: '000000',
isLoading: false,

// Actions
setColorOptions: (colorOptions: ColorsResponse[]) => set({ colorOptions }),
setColor: (color: string) => set({ color }),
setIsLoading: (isLoading: boolean) => set({ isLoading }),
}));

0 comments on commit edba3e1

Please sign in to comment.