- Fix CSS conflicts between WP-Admin and SPA (radio buttons, chart text) - Add Tailwind important selector scoped to #woonoow-admin-app - Remove overly aggressive inline SVG styles from Assets.php - Add targeted WordPress admin CSS overrides in index.css - Fix add-to-cart redirect to use woocommerce_add_to_cart_redirect filter - Let WooCommerce handle cart operations natively for proper session management - Remove duplicate tailwind.config.cjs
146 lines
4.4 KiB
TypeScript
146 lines
4.4 KiB
TypeScript
import React, { useRef, useEffect, useState } from 'react';
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import { api } from '@/lib/api';
|
|
import { __ } from '@/lib/i18n';
|
|
import { toast } from 'sonner';
|
|
import { useFABConfig } from '@/hooks/useFABConfig';
|
|
import { usePageHeader } from '@/contexts/PageHeaderContext';
|
|
import { ProductFormTabbed as ProductForm, ProductFormData } from './partials/ProductFormTabbed';
|
|
import { Button } from '@/components/ui/button';
|
|
import { ErrorCard } from '@/components/ErrorCard';
|
|
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import { MetaFields } from '@/components/MetaFields';
|
|
import { useMetaFields } from '@/hooks/useMetaFields';
|
|
|
|
export default function ProductEdit() {
|
|
const { id } = useParams<{ id: string }>();
|
|
const navigate = useNavigate();
|
|
const queryClient = useQueryClient();
|
|
const formRef = useRef<HTMLFormElement>(null);
|
|
const { setPageHeader, clearPageHeader } = usePageHeader();
|
|
|
|
// Level 1 compatibility: Meta fields from plugins
|
|
const metaFields = useMetaFields('products');
|
|
const [metaData, setMetaData] = useState<Record<string, any>>({});
|
|
|
|
// Hide FAB on edit product page
|
|
useFABConfig('none');
|
|
|
|
// Fetch product
|
|
const productQ = useQuery({
|
|
queryKey: ['products', id],
|
|
queryFn: () => api.get(`/products/${id}`),
|
|
enabled: !!id,
|
|
});
|
|
|
|
// Update mutation
|
|
const updateMutation = useMutation({
|
|
mutationFn: async (data: ProductFormData) => {
|
|
return api.put(`/products/${id}`, data);
|
|
},
|
|
onSuccess: (response: any) => {
|
|
toast.success(__('Product updated successfully'));
|
|
queryClient.invalidateQueries({ queryKey: ['products'] });
|
|
queryClient.invalidateQueries({ queryKey: ['products', id] });
|
|
|
|
// Navigate back to products list
|
|
navigate('/products');
|
|
},
|
|
onError: (error: any) => {
|
|
toast.error(error.message || __('Failed to update product'));
|
|
},
|
|
});
|
|
|
|
const handleSubmit = async (data: ProductFormData) => {
|
|
// Merge meta data with form data (Level 1 compatibility)
|
|
const payload = { ...data, meta: metaData };
|
|
await updateMutation.mutateAsync(payload);
|
|
};
|
|
|
|
// Sync meta data from product
|
|
useEffect(() => {
|
|
if (productQ.data?.meta) {
|
|
setMetaData(productQ.data.meta);
|
|
}
|
|
}, [productQ.data?.meta]);
|
|
|
|
// Smart back handler: go back in history if available, otherwise fallback to /products
|
|
const handleBack = () => {
|
|
if (window.history.state?.idx > 0) {
|
|
navigate(-1); // Go back in history
|
|
} else {
|
|
navigate('/products'); // Fallback to products index
|
|
}
|
|
};
|
|
|
|
// Set page header with back button and save button
|
|
useEffect(() => {
|
|
const actions = (
|
|
<div className="flex gap-2">
|
|
<Button size="sm" variant="ghost" onClick={handleBack}>
|
|
{__('Back')}
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
onClick={() => formRef.current?.requestSubmit()}
|
|
disabled={updateMutation.isPending || productQ.isLoading}
|
|
>
|
|
{updateMutation.isPending ? __('Saving...') : __('Save')}
|
|
</Button>
|
|
</div>
|
|
);
|
|
setPageHeader(__('Edit Product'), actions);
|
|
return () => clearPageHeader();
|
|
}, [updateMutation.isPending, productQ.isLoading, setPageHeader, clearPageHeader, navigate]);
|
|
|
|
// Loading state
|
|
if (productQ.isLoading) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<Skeleton className="h-12 w-full" />
|
|
<Skeleton className="h-64 w-full" />
|
|
<Skeleton className="h-32 w-full" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Error state
|
|
if (productQ.isError) {
|
|
return (
|
|
<ErrorCard
|
|
title={__('Failed to load product')}
|
|
message={getPageLoadErrorMessage(productQ.error)}
|
|
onRetry={() => productQ.refetch()}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const product = productQ.data;
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<ProductForm
|
|
mode="edit"
|
|
initial={product}
|
|
onSubmit={handleSubmit}
|
|
formRef={formRef}
|
|
hideSubmitButton={true}
|
|
productId={product.id}
|
|
/>
|
|
|
|
{/* Level 1 compatibility: Custom meta fields from plugins */}
|
|
{metaFields.length > 0 && (
|
|
<MetaFields
|
|
meta={metaData}
|
|
fields={metaFields}
|
|
onChange={(key, value) => {
|
|
setMetaData(prev => ({ ...prev, [key]: value }));
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|