-
Notifications
You must be signed in to change notification settings - Fork 0
wip #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wip #39
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,8 +16,29 @@ const ColorPicker: React.FC<Props> = ({ filamentType }) => { | |||||||||||||||||
| if (filamentType) url.searchParams.set("filamentType", filamentType); | ||||||||||||||||||
|
|
||||||||||||||||||
| const response = await fetch(url.toString()); | ||||||||||||||||||
| const colors = (await response.json()) as ColorsResponse[]; | ||||||||||||||||||
| dispatch({ type: "SET_COLOR_OPTIONS", payload: colors }); | ||||||||||||||||||
|
|
||||||||||||||||||
| // v1 /colors response shape | ||||||||||||||||||
| type V1ColorResponse = { | ||||||||||||||||||
| filament: string; | ||||||||||||||||||
| hexColor: string; | ||||||||||||||||||
| colorTag: string; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const rawColors = (await response.json()) as V1ColorResponse[]; | ||||||||||||||||||
|
|
||||||||||||||||||
| const mappedColors: ColorsResponse[] = rawColors.map((c) => ({ | ||||||||||||||||||
| name: c.filament, | ||||||||||||||||||
| provider: "", // not provided by v1 API | ||||||||||||||||||
| public: true, | ||||||||||||||||||
| available: true, | ||||||||||||||||||
| profile: c.colorTag, | ||||||||||||||||||
| color: c.filament, | ||||||||||||||||||
| hexValue: `#${c.hexColor.replace(/^#/, "")}`, | ||||||||||||||||||
| publicId: c.colorTag, | ||||||||||||||||||
| })); | ||||||||||||||||||
|
|
||||||||||||||||||
| console.log("Fetched colors (v1 mapped):", mappedColors); | ||||||||||||||||||
| dispatch({ type: "SET_COLOR_OPTIONS", payload: mappedColors }); | ||||||||||||||||||
| } catch (error) { | ||||||||||||||||||
| console.error("Failed to fetch colors:", error); | ||||||||||||||||||
|
Comment on lines
+40
to
43
|
||||||||||||||||||
| console.log("Fetched colors (v1 mapped):", mappedColors); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: mappedColors }); | |
| } catch (error) { | |
| console.error("Failed to fetch colors:", error); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: mappedColors }); | |
| } catch (error) { | |
| console.error("Failed to fetch colors:", error); | |
| console.error("Failed to fetch colors:", error); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,89 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| import { Radio, RadioGroup } from "@headlessui/react"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { BASE_URL } from "../config"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { useColorContext } from "../context/ColorContext"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import type { ColorsResponse } from "../interfaces"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| interface Props { | ||||||||||||||||||||||||||||||||||||||||||||||
| filamentType: string; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| // v2 ColorPicker: consumes the new /v2/colors API which already | ||||||||||||||||||||||||||||||||||||||||||||||
| // returns data in the ColorsResponse shape. | ||||||||||||||||||||||||||||||||||||||||||||||
| const ColorPickerV2: React.FC<Props> = ({ filamentType }) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const { state, dispatch } = useColorContext(); | ||||||||||||||||||||||||||||||||||||||||||||||
| const { colorOptions, isLoading, color } = state; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const fetchColors = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| dispatch({ type: "SET_IS_LOADING", payload: true }); | ||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||
| const url = new URL(`${BASE_URL}/v2/colors`); | ||||||||||||||||||||||||||||||||||||||||||||||
| if (filamentType) url.searchParams.set("profile", filamentType); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const response = await fetch(url.toString()); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| type V2ColorsEnvelope = { | ||||||||||||||||||||||||||||||||||||||||||||||
| success: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||
| message: string; | ||||||||||||||||||||||||||||||||||||||||||||||
| data: ColorsResponse[]; | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const json = (await response.json()) as V2ColorsEnvelope; | ||||||||||||||||||||||||||||||||||||||||||||||
| const colors = json.data ?? []; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+34
|
||||||||||||||||||||||||||||||||||||||||||||||
| const json = (await response.json()) as V2ColorsEnvelope; | |
| const colors = json.data ?? []; | |
| if (!response.ok) { | |
| console.error( | |
| `Failed to fetch v2 colors: ${response.status} ${response.statusText}` | |
| ); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: [] }); | |
| return; | |
| } | |
| const json = (await response.json()) as Partial<V2ColorsEnvelope>; | |
| if (!json || json.success !== true || !Array.isArray(json.data)) { | |
| console.error( | |
| "Unexpected v2 colors response shape or unsuccessful response:", | |
| json | |
| ); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: [] }); | |
| return; | |
| } | |
| const colors = json.data; |
Copilot
AI
Mar 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid leaving console.log statements in the component; it will clutter production logs for every product page visit. Remove it or guard it behind a debug flag.
| console.log("Fetched colors (v2):", colors); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: colors }); | |
| } catch (error) { | |
| console.error("Failed to fetch v2 colors:", error); | |
| dispatch({ type: "SET_COLOR_OPTIONS", payload: colors }); | |
| } catch (error) { | |
| console.error("Failed to fetch v2 colors:", error); | |
| console.error("Failed to fetch v2 colors:", error); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type React from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { COLOR_PICKER_VERSION } from "../config"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ColorPicker from "./ColorPicker"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ColorPickerV2 from "./ColorPickerV2"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface Props { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filamentType: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ColorPickerWrapper: React.FC<Props> = ({ filamentType }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (COLOR_PICKER_VERSION === "v2") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <ColorPickerV2 filamentType={filamentType} />; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Default to v1 implementation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <ColorPicker filamentType={filamentType} />; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+2
to
+16
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { COLOR_PICKER_VERSION } from "../config"; | |
| import ColorPicker from "./ColorPicker"; | |
| import ColorPickerV2 from "./ColorPickerV2"; | |
| interface Props { | |
| filamentType: string; | |
| } | |
| const ColorPickerWrapper: React.FC<Props> = ({ filamentType }) => { | |
| if (COLOR_PICKER_VERSION === "v2") { | |
| return <ColorPickerV2 filamentType={filamentType} />; | |
| } | |
| // Default to v1 implementation | |
| return <ColorPicker filamentType={filamentType} />; | |
| import { lazy, Suspense } from "react"; | |
| import { COLOR_PICKER_VERSION } from "../config"; | |
| const ColorPicker = lazy(() => import("./ColorPicker")); | |
| const ColorPickerV2 = lazy(() => import("./ColorPickerV2")); | |
| interface Props { | |
| filamentType: string; | |
| } | |
| const ColorPickerWrapper: React.FC<Props> = ({ filamentType }) => { | |
| if (COLOR_PICKER_VERSION === "v2") { | |
| return ( | |
| <Suspense fallback={null}> | |
| <ColorPickerV2 filamentType={filamentType} /> | |
| </Suspense> | |
| ); | |
| } | |
| // Default to v1 implementation | |
| return ( | |
| <Suspense fallback={null}> | |
| <ColorPicker filamentType={filamentType} />; | |
| </Suspense> | |
| ); |
Copilot
AI
Mar 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New ColorPicker version selection logic is introduced, but there’s no test coverage ensuring the wrapper renders v1 vs v2 based on COLOR_PICKER_VERSION. Adding a small unit test for ColorPickerWrapper would help prevent accidental regressions when toggling versions.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,9 +3,11 @@ import { z } from "zod"; | |||||||||||||||||||||||||
| const zEnv = z.object({ | ||||||||||||||||||||||||||
| VITE_BASE_URL: z.string().url(), | ||||||||||||||||||||||||||
| VITE_DOMAIN: z.string().min(1).max(100), | ||||||||||||||||||||||||||
| VITE_COLOR_PICKER_VERSION: z.enum(["v1", "v2"]).optional(), | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const parsed = zEnv.parse(import.meta.env); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export const BASE_URL = parsed.VITE_BASE_URL; | ||||||||||||||||||||||||||
| export const DOMAIN = parsed.VITE_DOMAIN; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| export const DOMAIN = parsed.VITE_DOMAIN; | |
| export const DOMAIN = parsed.VITE_DOMAIN; | |
| /** | |
| * Color picker implementation version selector. | |
| * | |
| * Backed by the `VITE_COLOR_PICKER_VERSION` env var. | |
| * Valid values: | |
| * - "v1" (default) | |
| * - "v2" | |
| * | |
| * When `VITE_COLOR_PICKER_VERSION` is not set, "v1" is used by default. | |
| */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ import ProductPage from "./Product"; | |
| vi.mock("../config", () => ({ | ||
| BASE_URL: "http://test.local", | ||
| DOMAIN: "http://test.local", | ||
| COLOR_PICKER_VERSION: "v1", | ||
| })); | ||
|
Comment on lines
15
to
19
|
||
|
|
||
| vi.mock("../components/PreviewComponent", () => ({ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The v1→ColorsResponse mapping sets
color(used for the option's accessible label) toc.filament, which will make every radio option label identical (e.g. all "PLA") and loses the actual color name (likelycolorTag). Map the display/label field(s) fromcolorTaginstead so options remain distinguishable and accessible.