feat: Phase 2 - Frontend meta fields components (Level 1)

Implemented: Frontend Components for Level 1 Compatibility

Created Components:
- MetaFields.tsx - Generic meta field renderer
- useMetaFields.ts - Hook for field registry

Integrated Into:
- Orders/Edit.tsx - Meta fields after OrderForm
- Products/Edit.tsx - Meta fields after ProductForm

Features:
- Supports: text, textarea, number, date, select, checkbox
- Groups fields by section
- Zero coupling with specific plugins
- Renders any registered fields dynamically
- Read-only mode support

How It Works:
1. Backend exposes meta via API (Phase 1)
2. PHP registers fields via MetaFieldsRegistry (Phase 3 - next)
3. Fields localized to window.WooNooWMetaFields
4. useMetaFields hook reads registry
5. MetaFields component renders fields
6. User edits fields
7. Form submission includes meta
8. Backend saves via update_order_meta_data()

Result:
- Generic, reusable components
- Zero plugin-specific code
- Works with any registered fields
- Clean separation of concerns

Next: Phase 3 - PHP MetaFieldsRegistry system
This commit is contained in:
dwindown
2025-11-20 12:32:06 +07:00
parent 9f731bfe0a
commit 0c5efa3efc
4 changed files with 281 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import OrderForm from '@/routes/Orders/partials/OrderForm';
@@ -10,6 +10,8 @@ import { __, sprintf } from '@/lib/i18n';
import { usePageHeader } from '@/contexts/PageHeaderContext';
import { Button } from '@/components/ui/button';
import { useFABConfig } from '@/hooks/useFABConfig';
import { MetaFields } from '@/components/MetaFields';
import { useMetaFields } from '@/hooks/useMetaFields';
export default function OrdersEdit() {
const { id } = useParams();
@@ -19,6 +21,10 @@ export default function OrdersEdit() {
const { setPageHeader, clearPageHeader } = usePageHeader();
const formRef = useRef<HTMLFormElement>(null);
// Level 1 compatibility: Meta fields from plugins
const metaFields = useMetaFields('orders');
const [metaData, setMetaData] = useState<Record<string, any>>({});
// Hide FAB on edit page
useFABConfig('none');
@@ -46,6 +52,13 @@ export default function OrdersEdit() {
}, [countriesQ.data]);
const order = orderQ.data || {};
// Sync meta data from order
useEffect(() => {
if (order.meta) {
setMetaData(order.meta);
}
}, [order.meta]);
// Set page header with back button and save button
useEffect(() => {
@@ -104,11 +117,22 @@ export default function OrdersEdit() {
formRef={formRef}
hideSubmitButton={true}
onSubmit={(form) => {
const payload = { ...form } as any;
const payload = { ...form, meta: metaData } as any;
upd.mutate(payload);
}}
/>
{/* 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>
);
}