Skip to content
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

I tried to update values metadata and gives an error #10921

Open
alsherif-khalaf opened this issue Jan 12, 2025 · 2 comments
Open

I tried to update values metadata and gives an error #10921

alsherif-khalaf opened this issue Jan 12, 2025 · 2 comments

Comments

@alsherif-khalaf
Copy link

          I tried to update values metadata and gives an error 
import { useState } from "react";
import { defineWidgetConfig } from "@medusajs/admin-sdk";
import { Button, Container, Heading, toast, Toaster } from "@medusajs/ui";
import { Form } from "../components/Form/Form";
import { z } from "zod";
import { AdminProduct, DetailWidgetProps } from "@medusajs/framework/types";
import { withQueryClient } from "../components/QueryClientProvider";
import { sdk } from "../lib/config";
import { useMutation } from "@tanstack/react-query";

const detailsFormSchema = z.object({
    image: z.string().optional(),
});

const ProductColorWidget: React.FC<DetailWidgetProps<AdminProduct>> = ({ data }) => {
    const productColors = data.options?.find(
        (option) => option.title.toLowerCase() === "color"
    );

    const [colors, setColors] = useState<{ [key: string]: string }>(
        productColors?.values?.reduce((acc, color) => {
            acc[color.id] = String(color?.metadata?.value) || "#eeeeee";
            return acc;
        }, {} as { [key: string]: string }) || {}
    );

    const { mutateAsync } = useMutation({
        mutationFn: async () => {
            if (!productColors?.id || !productColors.values) {
                throw new Error("No color options found");
            }
    
            try {
                // Prepare the metadata object
                const metadata = {
                    colors: productColors.values.reduce((acc, value) => {
                        acc[value.id] = colors[value.id]; // Map value ID to color
                        return acc;
                    }, {} as { [key: string]: string })
                };
    
                // Update the product option with full value objects and metadata
                await sdk.client.fetch(
                    `/admin/products/${data.id}/options/${productColors.id}`,
                    {
                        method: "POST",
                        body: {
                            title: productColors.title,
                            values: productColors.values.map((value) => ({
                                ...value,
                                metadata: { color: colors[value.id] },
                            })),
                        },
                    }
                );
    
                console.log("Colors and metadata updated successfully");
            } catch (error) {
                console.error("API error:", error);
                throw error;
            }
        },
        onSuccess: () => toast.success("Colors updated successfully"),
        onError: () => toast.error("Failed to update colors"),
    });
    

    const handleColorChange = (id: string, newColor: string) => {
        setColors((prevColors) => ({
            ...prevColors,
            [id]: newColor,
        }));
    };

    const handleUpdate = async () => {
        try {
            await mutateAsync();
        } catch (error) {
            console.error("Update failed:", error);
        }
    };

    return (
        <Container className="divide-y p-0">
            <div className="flex items-center justify-between px-6 py-4">
                <Heading level="h2">Product Colors</Heading>
            </div>

            <Form
                schema={detailsFormSchema}
                onSubmit={handleUpdate}
            >
                <div className="p-6">
                    {productColors?.values?.map((color) => (
                        <div key={color.id} className="flex items-center justify-between mb-4">
                            <div className="flex items-center">
                                <div
                                    className="w-6 h-6 rounded-full mr-4"
                                    style={{ backgroundColor: colors[color.id] }}
                                ></div>
                                <input
                                    type="color"
                                    value={colors[color.id]}
                                    onChange={(e) => handleColorChange(color.id, e.target.value)}
                                    className="mr-2"
                                />
                                <span>{color.value}</span>
                            </div>
                        </div>
                    ))}
                    <Button type="submit">Save</Button>
                </div>
            </Form>
            <Toaster />
        </Container>
    );
};

export const config = defineWidgetConfig({
    zone: "product.details.side.before",
});

export default withQueryClient(ProductColorWidget);
Update failed: FetchError: Invalid request: Expected type: 'string' for field 'values, 0', got: 'object'; Expected type: 'string' for field 'values, 1', got: 'object'
    at client.ts:84:11
    at Generator.next (<anonymous>)
    at fulfilled (client.ts:2:16)
    
    
    ````

_Originally posted by @alsherif-khalaf in https://github.com/medusajs/medusa/pull/10883#discussion_r1910890973_
            
@alsherif-khalaf
Copy link
Author

This should work normal

import { useState } from "react";
import { defineWidgetConfig } from "@medusajs/admin-sdk";
import { Button, Container, Heading, toast, Toaster } from "@medusajs/ui";
import { Form } from "../components/Form/Form";
import { z } from "zod";
import { AdminProduct, DetailWidgetProps } from "@medusajs/framework/types";
import { withQueryClient } from "../components/QueryClientProvider";
import { sdk } from "../lib/config";
import { useMutation } from "@tanstack/react-query";

const detailsFormSchema = z.object({
    image: z.string().optional(),
});

const ProductColorWidget: React.FC<DetailWidgetProps<AdminProduct>> = ({ data }) => {
    const productColors = data.options?.find(
        (option) => option.title.toLowerCase() === "color"
    );

    const [colors, setColors] = useState<{ [key: string]: string }>(
        productColors?.values?.reduce((acc, color) => {
            acc[color.id] = String(color?.metadata?.value) || "#eeeeee";
            return acc;
        }, {} as { [key: string]: string }) || {}
    );

    const { mutateAsync } = useMutation({
        mutationFn: async () => {
            if (!productColors?.id || !productColors.values) {
                throw new Error("No color options found");
            }
    
            try {
                // Prepare the metadata object
                const metadata = {
                    colors: productColors.values.reduce((acc, value) => {
                        acc[value.id] = colors[value.id]; // Map value ID to color
                        return acc;
                    }, {} as { [key: string]: string })
                };

                console.log(
                   "productColors.values.map((value) => value.value), // Array of strings", productColors.values.map((value) => `${value.value} | "#hex`), // Array of strings
                );
    
                // Update the product option with string values and metadata
                await sdk.client.fetch(
                    `/admin/products/${data.id}/options/${productColors.id}`,
                    {
                        method: "POST",
                        body: {
                            title: productColors.title,
                            values: productColors.values.map((value) => ({
                                id: value.id,
                                value: value.value,
                                metadata: { color: colors[value.id] },
                            })),
                        }
                    }
                );
    
                console.log("Colors and metadata updated successfully");
            } catch (error) {
                console.error("API error:", error);
                throw error;
            }
        },
        onSuccess: () => toast.success("Colors updated successfully"),
        onError: () => toast.error("Failed to update colors")
    });

    const handleColorChange = (id: string, newColor: string) => {
        setColors((prevColors) => ({
            ...prevColors,
            [id]: newColor,
        }));
    };

    const handleUpdate = async () => {
        try {
            await mutateAsync();
        } catch (error) {
            console.error("Update failed:", error);
        }
    };

    return (
        <Container className="divide-y p-0">
            <div className="flex items-center justify-between px-6 py-4">
                <Heading level="h2">Product Colors</Heading>
            </div>

            <Form
                schema={detailsFormSchema}
                onSubmit={handleUpdate}
            >
                <div className="p-6">
                    {productColors?.values?.map((color) => (
                        <div key={color.id} className="flex items-center justify-between mb-4">
                            <div className="flex items-center">
                                <div
                                    className="w-6 h-6 rounded-full mr-4"
                                    style={{ backgroundColor: colors[color.id] }}
                                ></div>
                                <input
                                    type="color"
                                    value={colors[color.id]}
                                    onChange={(e) => handleColorChange(color.id, e.target.value)}
                                    className="mr-2"
                                />
                                <span>{color.value}</span>
                            </div>
                        </div>
                    ))}
                    <Button type="submit">Save</Button>
                </div>
            </Form>
            <Toaster />
        </Container>
    );
};

export const config = defineWidgetConfig({
    zone: "product.details.side.before",
});

export default withQueryClient(ProductColorWidget);

image

@alsherif-khalaf
Copy link
Author

image
related to #10883

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant