# useNotice Hook

A custom React hook for displaying WordPress snackbar notifications in GrowthStack plugin admin pages.

## Overview

The `useNotice` module provides two ways to show notifications:
1. **Direct import** - Standalone functions for simple use cases
2. **Hook** - Memoized functions with stable references for use in React dependencies

## Installation

The hook uses WordPress's built-in notices store and requires the following dependencies:

```json
{
  "dependencies": {
    "@wordpress/data": "^9.0.0",
    "@wordpress/notices": "^4.0.0",
    "@wordpress/element": "^5.0.0"
  }
}
```

Ensure your PHP file enqueues the required WordPress scripts:

```php
wp_enqueue_script(
    'your-script-handle',
    $script_url,
    array(
        'wp-element',
        'wp-data',
        'wp-notices',
        'wp-components', // Required for SnackbarList
    ),
    $version,
    true
);
```

## Usage

### Option 1: Direct Import (Recommended for most cases)

Use this approach for event handlers and simple callbacks. These functions don't require calling a hook.

```tsx
import { showSuccess, showError, showWarning, showInfo } from '../shared/useNotice';

export default function MyComponent() {
    const handleSave = async () => {
        try {
            await saveData();
            showSuccess( 'Data saved successfully!' );
        } catch ( error ) {
            showError( 'Failed to save data' );
        }
    };

    const handleClick = () => {
        showInfo( 'Button clicked!' );
    };

    return (
        <div>
            <button onClick={ handleSave }>Save</button>
            <button onClick={ handleClick }>Click Me</button>
        </div>
    );
}
```

#### Use cases for direct import:
- ✅ Event handlers (onClick, onSubmit, etc.)
- ✅ Try/catch blocks
- ✅ Promise chains
- ✅ Simple inline callbacks

### Option 2: Hook (For dependency arrays)

Use this approach when functions need stable references across renders.

```tsx
import useNotice from '../shared/useNotice';

export default function MyComponent() {
    const { showSuccess, showError } = useNotice();

    // ✅ Function is used in useEffect dependencies
    useEffect( () => {
        if ( someCondition ) {
            showSuccess( 'Component loaded successfully!' );
        }
    }, [ showSuccess, someCondition ] );

    // ✅ Function is passed to useCallback
    const memoizedHandler = useCallback( () => {
        showSuccess( 'Action completed!' );
    }, [ showSuccess ] );

    // ✅ Passed to memoized child components
    const MemoChild = React.memo( ChildComponent );

    return <MemoChild onSuccess={ showSuccess } />;
}
```

#### Use cases for hook:
- ✅ Functions in `useEffect` dependency arrays
- ✅ Functions in `useCallback` dependency arrays
- ✅ Functions passed as props to `React.memo` components
- ✅ When you need stable function references

## API Reference

### Direct Import Functions

All direct import functions can be used without calling the hook.

#### `showNotice(type, message, options?)`

Generic function to show any type of notice.

**Parameters:**
- `type` (string): Notice type - `'success'`, `'error'`, `'warning'`, `'info'`, or `'default'`
- `message` (string): The notification message
- `options` (object, optional): Configuration options

**Example:**
```tsx
import { showNotice } from '../shared/useNotice';

showNotice( 'success', 'Operation completed!', {
    id: 'my-custom-notice',
    isDismissible: true,
} );
```

#### `showSuccess(message, options?)`

Display a success notification with green border.

```tsx
import { showSuccess } from '../shared/useNotice';

showSuccess( 'Settings saved successfully!' );
```

#### `showError(message, options?)`

Display an error notification with red border.

```tsx
import { showError } from '../shared/useNotice';

showError( 'Failed to save settings' );
```

#### `showWarning(message, options?)`

Display a warning notification with orange border.

```tsx
import { showWarning } from '../shared/useNotice';

showWarning( 'Some fields are missing' );
```

#### `showInfo(message, options?)`

Display an info notification with blue border.

```tsx
import { showInfo } from '../shared/useNotice';

showInfo( 'Processing your request...' );
```

#### `removeNotice(id)`

Remove a specific notice by ID.

```tsx
import { removeNotice } from '../shared/useNotice';

removeNotice( 'my-custom-notice' );
```

### Options Object

```typescript
interface NoticeOptions {
    id?: string;                  // Unique identifier for the notice
    isDismissible?: boolean;      // Show close button (default: true)
    type?: 'default' | 'snackbar'; // Display type (default: 'snackbar')
    actions?: Array<{
        label: string;
        onClick: () => void;
        variant?: 'primary' | 'secondary' | 'tertiary' | 'link';
    }>;
    icon?: JSX.Element;           // Custom icon
    explicitDismiss?: boolean;    // Require explicit dismissal
}
```

## Complete Examples

### Basic Form Submission

```tsx
import { showSuccess, showError } from '../shared/useNotice';

export default function FormComponent() {
    const handleSubmit = async ( event: React.FormEvent ) => {
        event.preventDefault();

        try {
            const response = await saveFormData( formData );
            showSuccess( 'Form submitted successfully!' );
        } catch ( error ) {
            showError( error.message || 'Submission failed' );
        }
    };

    return <form onSubmit={ handleSubmit }>...</form>;
}
```

### With Custom Options

```tsx
import { showNotice } from '../shared/useNotice';

const handleAction = () => {
    showNotice( 'success', 'Action completed!', {
        id: 'custom-action-notice',
        isDismissible: true,
        actions: [
            {
                label: 'Undo',
                onClick: handleUndo,
                variant: 'secondary',
            },
        ],
    } );
};
```

### Using in useEffect

```tsx
import { useEffect } from '@wordpress/element';
import useNotice from '../shared/useNotice';

export default function DataComponent() {
    const { showSuccess, showError } = useNotice();

    useEffect( () => {
        const loadData = async () => {
            try {
                const data = await fetchData();
                showSuccess( 'Data loaded successfully!' );
            } catch ( error ) {
                showError( 'Failed to load data' );
            }
        };

        loadData();
    }, [ showSuccess, showError ] );

    return <div>...</div>;
}
```

### Multiple Notifications

```tsx
import { showInfo, showSuccess, showWarning } from '../shared/useNotice';

const processSteps = async () => {
    showInfo( 'Starting process...' );

    try {
        await step1();
        showSuccess( 'Step 1 completed' );

        await step2();
        showSuccess( 'Step 2 completed' );

        await step3();
        showSuccess( 'All steps completed!' );
    } catch ( error ) {
        showWarning( 'Process interrupted' );
    }
};
```

## Styling

Snackbar notifications are styled based on their type. The styling is handled by `Notice.scss`:

- **Success**: White background with green left border (`#00a32a`)
- **Error**: White background with red left border (`#d63638`)
- **Warning**: White background with orange left border (`#f0b849`)
- **Info**: White background with blue left border (`#2271b1`)

All notifications appear in the bottom-right corner and stack vertically.

## Rendering Notifications

Don't forget to include the `Notice` component in your layout to render the notifications:

```tsx
import Notice from '../shared/Notice';

export default function App() {
    return (
        <>
            <YourContent />
            <Notice />
        </>
    );
}
```

## Performance Considerations

### Why Two Approaches?

**Direct Import:**
- ✅ Simpler syntax
- ✅ No hook overhead
- ✅ Perfect for 90% of use cases
- ⚠️ Creates new function reference on every module evaluation

**Hook with useCallback:**
- ✅ Stable function references
- ✅ Prevents unnecessary re-renders
- ✅ Safe for dependency arrays
- ⚠️ Slightly more verbose

### When Reference Stability Matters

```tsx
// ❌ BAD: Direct import in useEffect dependency
import { showSuccess } from '../shared/useNotice';

useEffect( () => {
    showSuccess( 'Loaded' );
}, [ showSuccess ] ); // May cause unnecessary re-runs

// ✅ GOOD: Use hook for stable reference
const { showSuccess } = useNotice();

useEffect( () => {
    showSuccess( 'Loaded' );
}, [ showSuccess ] ); // Only runs when dependencies actually change
```

## TypeScript Support

The module includes full TypeScript definitions:

```typescript
type NoticeType = 'default' | 'success' | 'warning' | 'error' | 'info';

// Direct imports
export function showNotice(
    type: NoticeType,
    message: string,
    options?: NoticeOptions
): void;

export function showSuccess(message: string, options?: NoticeOptions): void;
export function showError(message: string, options?: NoticeOptions): void;
export function showWarning(message: string, options?: NoticeOptions): void;
export function showInfo(message: string, options?: NoticeOptions): void;
export function removeNotice(id: string): void;

// Hook
export default function useNotice(): {
    showNotice: (type: NoticeType, message: string, options?: NoticeOptions) => void;
    showSuccess: (message: string, options?: NoticeOptions) => void;
    showError: (message: string, options?: NoticeOptions) => void;
    showWarning: (message: string, options?: NoticeOptions) => void;
    showInfo: (message: string, options?: NoticeOptions) => void;
    removeNotice: (id: string) => void;
};
```

## Best Practices

1. **Use direct imports for event handlers**
   ```tsx
   import { showSuccess } from '../shared/useNotice';

   const onClick = () => showSuccess( 'Clicked!' );
   ```

2. **Use the hook for dependency arrays**
   ```tsx
   const { showSuccess } = useNotice();

   useEffect( () => {
       // ...
   }, [ showSuccess ] );
   ```

3. **Keep messages concise and actionable**
   ```tsx
   // ✅ Good
   showSuccess( 'Settings saved' );

   // ❌ Too verbose
   showSuccess( 'Your settings have been successfully saved to the database' );
   ```

4. **Use appropriate notice types**
   - `success`: Completed actions
   - `error`: Failed operations
   - `warning`: Caution or attention needed
   - `info`: General information

## Troubleshooting

### Notifications not appearing

1. Ensure `Notice` component is rendered in your layout
2. Check that WordPress scripts are enqueued (`wp-data`, `wp-notices`, `wp-components`)
3. Verify the notices store is available: `wp.data.select( 'core/notices' )`

### Notifications appearing without styles

1. Ensure `Notice.scss` is imported in your component
2. Check webpack configuration includes SCSS loader
3. Verify CSS is being compiled and loaded

### Multiple re-renders

1. Use the hook version with `useCallback` instead of direct imports in dependency arrays
2. Ensure proper dependency arrays in `useEffect` and `useCallback`

## Related Files

- `src-js/shared/useNotice.ts` - Hook implementation
- `src-js/shared/Notice.tsx` - Notification renderer component
- `src-js/shared/Notice.scss` - Notification styles
