Files
WooNooW/types/woonoow-addon.d.ts
Dwindi Ramadhana c6cef97ef8 feat: Implement Phase 2, 3, 4 - Module Settings System with Schema Forms and Addon API
Phase 2: Schema-Based Form System
- Add ModuleSettingsController with GET/POST/schema endpoints
- Create SchemaField component supporting 8 field types (text, textarea, email, url, number, toggle, checkbox, select)
- Create SchemaForm component for automatic form generation from schema
- Add ModuleSettings page with dynamic routing (/settings/modules/:moduleId)
- Add useModuleSettings React hook for settings management
- Implement NewsletterSettings as example with 8 configurable fields
- Add has_settings flag to module registry
- Settings stored as woonoow_module_{module_id}_settings

Phase 3: Advanced Features
- Create windowAPI.ts exposing React, hooks, components, icons, utils to addons via window.WooNooW
- Add DynamicComponentLoader for loading external React components
- Create TypeScript definitions (woonoow-addon.d.ts) for addon developers
- Initialize Window API in App.tsx on mount
- Enable custom React components for addon settings pages

Phase 4: Production Polish & Example
- Create complete Biteship addon example demonstrating both approaches:
  * Schema-based settings (no build required)
  * Custom React component (with build)
- Add comprehensive README with installation and testing guide
- Include package.json with esbuild configuration
- Demonstrate window.WooNooW API usage in custom component

Bug Fixes:
- Fix footer newsletter form visibility (remove redundant module check)
- Fix footer contact_data and social_links not saving (parameter name mismatch: snake_case vs camelCase)
- Fix useModules hook returning undefined (remove .data wrapper, add fallback)
- Add optional chaining to footer settings rendering
- Fix TypeScript errors in woonoow-addon.d.ts (use any for external types)

Files Added (15):
- includes/Api/ModuleSettingsController.php
- includes/Modules/NewsletterSettings.php
- admin-spa/src/components/forms/SchemaField.tsx
- admin-spa/src/components/forms/SchemaForm.tsx
- admin-spa/src/routes/Settings/ModuleSettings.tsx
- admin-spa/src/hooks/useModuleSettings.ts
- admin-spa/src/lib/windowAPI.ts
- admin-spa/src/components/DynamicComponentLoader.tsx
- types/woonoow-addon.d.ts
- examples/biteship-addon/biteship-addon.php
- examples/biteship-addon/src/Settings.jsx
- examples/biteship-addon/package.json
- examples/biteship-addon/README.md
- PHASE_2_3_4_SUMMARY.md

Files Modified (11):
- admin-spa/src/App.tsx
- admin-spa/src/hooks/useModules.ts
- admin-spa/src/routes/Appearance/Footer.tsx
- admin-spa/src/routes/Settings/Modules.tsx
- customer-spa/src/hooks/useModules.ts
- customer-spa/src/layouts/BaseLayout.tsx
- customer-spa/src/components/NewsletterForm.tsx
- includes/Api/Routes.php
- includes/Api/ModulesController.php
- includes/Core/ModuleRegistry.php
- woonoow.php

API Endpoints Added:
- GET /woonoow/v1/modules/{module_id}/settings
- POST /woonoow/v1/modules/{module_id}/settings
- GET /woonoow/v1/modules/{module_id}/schema

For Addon Developers:
- Schema-based: Define settings via woonoow/module_settings_schema filter
- Custom React: Build component using window.WooNooW API, externalize react/react-dom
- Both approaches use same storage and retrieval methods
- TypeScript definitions provided for type safety
- Complete working example (Biteship) included
2025-12-26 21:16:06 +07:00

162 lines
4.4 KiB
TypeScript

/**
* WooNooW Addon TypeScript Definitions
*
* Type definitions for addon developers using the WooNooW API
*
* @package WooNooW
* @version 1.0.0
*/
import type { ComponentType } from 'react';
declare global {
interface Window {
/**
* WooNooW API exposed to addon developers
*/
WooNooW: {
React: typeof import('react');
ReactDOM: typeof import('react-dom/client');
hooks: {
useQuery: any;
useMutation: any;
useQueryClient: any;
useModules: () => {
isEnabled: (moduleId: string) => boolean;
modules: string[];
};
useModuleSettings: (moduleId: string) => {
settings: Record<string, any>;
isLoading: boolean;
updateSettings: {
mutate: (settings: Record<string, any>) => void;
isPending: boolean;
};
saveSetting: (key: string, value: any) => void;
};
};
components: {
Button: ComponentType<any>;
Input: ComponentType<any>;
Label: ComponentType<any>;
Textarea: ComponentType<any>;
Switch: ComponentType<any>;
Select: ComponentType<any>;
SelectContent: ComponentType<any>;
SelectItem: ComponentType<any>;
SelectTrigger: ComponentType<any>;
SelectValue: ComponentType<any>;
Checkbox: ComponentType<any>;
Badge: ComponentType<any>;
Card: ComponentType<any>;
CardContent: ComponentType<any>;
CardDescription: ComponentType<any>;
CardFooter: ComponentType<any>;
CardHeader: ComponentType<any>;
CardTitle: ComponentType<any>;
SettingsLayout: ComponentType<{
title: string;
description?: string;
isLoading?: boolean;
children: React.ReactNode;
}>;
SettingsCard: ComponentType<{
title: string;
description?: string;
children: React.ReactNode;
}>;
SettingsSection: ComponentType<any>;
SchemaForm: ComponentType<{
schema: FormSchema;
initialValues?: Record<string, any>;
onSubmit: (values: Record<string, any>) => void | Promise<void>;
isSubmitting?: boolean;
submitLabel?: string;
errors?: Record<string, string>;
}>;
SchemaField: ComponentType<any>;
};
icons: {
Settings: ComponentType<any>;
Save: ComponentType<any>;
Trash2: ComponentType<any>;
Edit: ComponentType<any>;
Plus: ComponentType<any>;
X: ComponentType<any>;
Check: ComponentType<any>;
AlertCircle: ComponentType<any>;
Info: ComponentType<any>;
Loader2: ComponentType<any>;
ChevronDown: ComponentType<any>;
ChevronUp: ComponentType<any>;
ChevronLeft: ComponentType<any>;
ChevronRight: ComponentType<any>;
};
utils: {
api: {
get: (endpoint: string) => Promise<any>;
post: (endpoint: string, data?: any) => Promise<any>;
put: (endpoint: string, data?: any) => Promise<any>;
delete: (endpoint: string) => Promise<any>;
};
toast: {
success: (message: string) => void;
error: (message: string) => void;
info: (message: string) => void;
warning: (message: string) => void;
};
__: (text: string, domain?: string) => string;
};
};
}
}
/**
* Form Schema Types
*/
export type FieldType = 'text' | 'textarea' | 'email' | 'url' | 'number' | 'toggle' | 'checkbox' | 'select';
export interface FieldSchema {
type: FieldType;
label: string;
description?: string;
placeholder?: string;
required?: boolean;
default?: any;
options?: Record<string, string>;
min?: number;
max?: number;
}
export type FormSchema = Record<string, FieldSchema>;
/**
* Module Registration
*/
export interface ModuleRegistration {
id: string;
name: string;
description: string;
version: string;
author: string;
category: 'marketing' | 'customers' | 'products' | 'shipping' | 'payments' | 'analytics' | 'other';
icon: string;
features: string[];
has_settings?: boolean;
settings_component?: string;
spa_bundle?: string;
}
/**
* Settings Schema Registration
*/
export interface SettingsSchemaRegistration {
[moduleId: string]: FormSchema;
}
export {};