# Notifications Store

The notifications store provides centralized state management for application-wide notifications. It handles the creation, management, and lifecycle of toast-style notifications with support for multiple types, positions, and interactive actions.

## Overview

- **Location**: `src/stores/notifications.js`
- **Type**: Pinia Store
- **Purpose**: Global notification state management
- **Integration**: Used by NotificationDisplay component

## Installation & Setup

```javascript
// Import in your component
import { useNotificationStore } from "@/stores/notifications";

// Use in component
const notificationStore = useNotificationStore();
```

## State Structure

### Core State Properties

```javascript
state: {
  notifications: [],        // Array of active notifications
  defaultDuration: 4000,    // Default auto-dismiss time (ms)
  maxNotifications: 5,      // Maximum concurrent notifications
  position: 'top-right',    // Default position
  nextId: 1                // Auto-incrementing ID counter
}
```

### Notification Object Structure

```javascript
{
  id: 1,                           // Unique identifier
  type: 'success',                 // 'success' | 'error' | 'warning' | 'info'
  title: 'Operation Complete',     // Notification title
  message: 'Data saved successfully', // Main message
  duration: 4000,                  // Auto-dismiss time (0 = no auto-dismiss)
  persistent: false,               // If true, won't auto-dismiss
  actions: [],                     // Array of action buttons
  data: null,                      // Additional data for handlers
  timestamp: '2025-11-12T10:30:00Z', // Creation timestamp
  dismissed: false,                // Whether notification is dismissed
  seen: false                      // Whether user has interacted with it
}
```

## Getters

### `getNotificationsByType(type)`

Get all notifications of a specific type.

```javascript
const errorNotifications = notificationStore.getNotificationsByType("error");
```

### `activeNotifications`

Get all non-dismissed notifications.

```javascript
const active = notificationStore.activeNotifications;
```

### `activeCount`

Get count of active notifications.

```javascript
const count = notificationStore.activeCount;
```

### `hasErrorNotifications`

Check if there are any active error notifications.

```javascript
const hasErrors = notificationStore.hasErrorNotifications;
```

### `hasSuccessNotifications`

Check if there are any active success notifications.

```javascript
const hasSuccess = notificationStore.hasSuccessNotifications;
```

## Actions

### Core Notification Methods

#### `addNotification(notification)`

Add a new notification with full configuration options.

```javascript
const notificationId = notificationStore.addNotification({
  type: "warning",
  title: "Confirm Action",
  message: "This will permanently delete the item.",
  persistent: true,
  actions: [
    {
      label: "Delete",
      variant: "danger",
      handler: () => performDelete(),
    },
    {
      label: "Cancel",
      variant: "secondary",
    },
  ],
  data: { itemId: 123 },
});
```

#### Convenience Methods

```javascript
// Quick success notification
notificationStore.addSuccess("Operation completed!");
notificationStore.addSuccess("Custom message", "Custom Title", {
  duration: 6000,
});

// Quick error notification
notificationStore.addError("Something went wrong!");
notificationStore.addError("Custom error", "Error Title", { persistent: true });

// Quick warning notification
notificationStore.addWarning("Please confirm this action");

// Quick info notification
notificationStore.addInfo("New feature available");
```

### Notification Management

#### `dismissNotification(id)`

Mark a notification as dismissed (hides it but keeps in history).

```javascript
notificationStore.dismissNotification(notificationId);
```

#### `removeNotification(id)`

Completely remove a notification from the store.

```javascript
notificationStore.removeNotification(notificationId);
```

#### `markAsSeen(id)`

Mark a notification as seen (user has interacted with it).

```javascript
notificationStore.markAsSeen(notificationId);
```

#### `updateNotification(id, updates)`

Update an existing notification's properties.

```javascript
notificationStore.updateNotification(notificationId, {
  type: "success",
  message: "Updated message",
  persistent: false,
});
```

### Bulk Operations

#### `clearType(type)`

Remove all notifications of a specific type.

```javascript
notificationStore.clearType("error"); // Remove all error notifications
```

#### `clearAll()`

Remove all notifications.

```javascript
notificationStore.clearAll();
```

#### `clearDismissed()`

Remove all dismissed notifications from history.

```javascript
notificationStore.clearDismissed();
```

### Loading Notifications

#### `showLoadingNotification(message, title)`

Show a persistent loading notification that can be updated later.

```javascript
const loadingId = notificationStore.showLoadingNotification(
  "Uploading file...",
  "Please Wait",
);
```

#### `updateToSuccess(id, message, title)`

Update a loading notification to success and auto-dismiss.

```javascript
notificationStore.updateToSuccess(
  loadingId,
  "File uploaded successfully!",
  "Upload Complete",
);
```

#### `updateToError(id, message, title)`

Update a loading notification to error and auto-dismiss.

```javascript
notificationStore.updateToError(
  loadingId,
  "Upload failed. Please try again.",
  "Upload Failed",
);
```

### API Integration Helpers

#### `showApiSuccess(operation, customMessage)`

Show standardized success notifications for API operations.

```javascript
// Uses default messages based on operation
notificationStore.showApiSuccess("create"); // "Item created successfully"
notificationStore.showApiSuccess("update"); // "Item updated successfully"
notificationStore.showApiSuccess("delete"); // "Item deleted successfully"
notificationStore.showApiSuccess("fetch"); // "Data loaded successfully"

// With custom message
notificationStore.showApiSuccess("create", "New client added successfully!");
```

#### `showApiError(operation, error, customMessage)`

Show standardized error notifications for API operations.

```javascript
// Automatically extracts error message from different error formats
notificationStore.showApiError("create", apiError);
notificationStore.showApiError("update", "Network timeout occurred");
notificationStore.showApiError("delete", errorObject, "Custom error message");
```

### Configuration Methods

#### `setPosition(position)`

Set the global notification position.

```javascript
// Available positions:
notificationStore.setPosition("top-right"); // Default
notificationStore.setPosition("top-left");
notificationStore.setPosition("top-center");
notificationStore.setPosition("bottom-right");
notificationStore.setPosition("bottom-left");
notificationStore.setPosition("bottom-center");
```

#### `setDefaultDuration(duration)`

Set the default auto-dismiss duration (milliseconds).

```javascript
notificationStore.setDefaultDuration(5000); // 5 seconds
```

#### `setMaxNotifications(max)`

Set maximum number of concurrent notifications.

```javascript
notificationStore.setMaxNotifications(3);
```

### Advanced Workflow Helper

#### `withNotifications(operation, asyncFunction, options)`

Wrap an async operation with automatic loading/success/error notifications.

```javascript
const result = await notificationStore.withNotifications(
  "save",
  async () => {
    return await saveDataToApi();
  },
  {
    loadingMessage: "Saving changes...",
    successMessage: "Changes saved successfully!",
    errorMessage: null, // Use default error handling
    showLoading: true,
  },
);
```

## Action Button Configuration

### Action Object Structure

```javascript
{
  label: 'Button Text',           // Required: Button label
  variant: 'primary',             // Optional: 'primary' | 'danger' | 'secondary'
  icon: 'mdi mdi-check',         // Optional: Icon class
  handler: (notification) => {}, // Optional: Click handler function
  dismissAfter: true             // Optional: Auto-dismiss after click (default: true)
}
```

### Action Examples

```javascript
notificationStore.addNotification({
  type: "warning",
  title: "Unsaved Changes",
  message: "You have unsaved changes. What would you like to do?",
  persistent: true,
  actions: [
    {
      label: "Save",
      variant: "primary",
      icon: "mdi mdi-content-save",
      handler: (notification) => {
        saveChanges();
        // Access notification data if needed
        console.log("Saving from notification:", notification.data);
      },
    },
    {
      label: "Discard",
      variant: "danger",
      icon: "mdi mdi-delete",
      handler: () => {
        discardChanges();
      },
    },
    {
      label: "Keep Editing",
      variant: "secondary",
      dismissAfter: false, // Don't dismiss, let user continue editing
    },
  ],
});
```

## Usage Patterns

### Basic Notifications

```javascript
const notificationStore = useNotificationStore();

// Simple success
notificationStore.addSuccess("Data saved successfully!");

// Simple error
notificationStore.addError("Failed to connect to server");

// Custom duration
notificationStore.addWarning("Session expires in 5 minutes", "Warning", {
  duration: 8000,
});
```

### API Operation Notifications

```javascript
// Method 1: Manual handling
try {
  await apiCall();
  notificationStore.addSuccess("Operation completed successfully!");
} catch (error) {
  notificationStore.addError(error.message, "Operation Failed");
}

// Method 2: Using API helpers
try {
  await apiCall();
  notificationStore.showApiSuccess("create");
} catch (error) {
  notificationStore.showApiError("create", error);
}

// Method 3: Using workflow helper
await notificationStore.withNotifications("create", async () => {
  return await apiCall();
});
```

### Loading States

```javascript
// Show loading notification
const loadingId = notificationStore.showLoadingNotification("Processing...");

try {
  const result = await longRunningOperation();
  notificationStore.updateToSuccess(loadingId, "Operation completed!");
} catch (error) {
  notificationStore.updateToError(loadingId, "Operation failed");
}
```

### Interactive Notifications

```javascript
// Confirmation dialog
notificationStore.addNotification({
  type: "warning",
  title: "Delete Confirmation",
  message: `Are you sure you want to delete "${itemName}"?`,
  persistent: true,
  actions: [
    {
      label: "Yes, Delete",
      variant: "danger",
      handler: async () => {
        const deleteId =
          notificationStore.showLoadingNotification("Deleting...");
        try {
          await deleteItem(itemId);
          notificationStore.updateToSuccess(
            deleteId,
            "Item deleted successfully",
          );
          refreshData();
        } catch (error) {
          notificationStore.updateToError(deleteId, "Failed to delete item");
        }
      },
    },
    {
      label: "Cancel",
      variant: "secondary",
    },
  ],
});

// Multi-step workflow
notificationStore.addNotification({
  type: "info",
  title: "Export Complete",
  message: "Your data has been exported successfully.",
  actions: [
    {
      label: "Download",
      variant: "primary",
      icon: "mdi mdi-download",
      handler: () => downloadFile(),
    },
    {
      label: "Email",
      variant: "secondary",
      icon: "mdi mdi-email",
      handler: () => emailFile(),
    },
    {
      label: "View",
      variant: "secondary",
      icon: "mdi mdi-eye",
      handler: () => viewFile(),
    },
  ],
});
```

## Integration with Vue Components

### In Composition API

```javascript
import { useNotificationStore } from "@/stores/notifications";

export default {
  setup() {
    const notificationStore = useNotificationStore();

    const handleSubmit = async () => {
      try {
        await submitForm();
        notificationStore.addSuccess("Form submitted successfully!");
      } catch (error) {
        notificationStore.addError("Failed to submit form", "Submission Error");
      }
    };

    return {
      handleSubmit,
    };
  },
};
```

### In Options API

```javascript
import { mapActions, mapGetters } from "pinia";
import { useNotificationStore } from "@/stores/notifications";

export default {
  computed: {
    ...mapGetters(useNotificationStore, [
      "activeCount",
      "hasErrorNotifications",
    ]),
  },
  methods: {
    ...mapActions(useNotificationStore, ["addSuccess", "addError", "clearAll"]),

    async saveData() {
      try {
        await this.apiCall();
        this.addSuccess("Data saved!");
      } catch (error) {
        this.addError(error.message);
      }
    },
  },
};
```

## Best Practices

### Do's

- ✅ Use appropriate notification types for different scenarios
- ✅ Keep messages concise and actionable
- ✅ Use loading notifications for long-running operations
- ✅ Provide clear action buttons for next steps
- ✅ Set appropriate durations (longer for errors, shorter for success)
- ✅ Use persistent notifications for critical actions requiring user input

### Don'ts

- ❌ Don't overwhelm users with too many notifications
- ❌ Don't use persistent notifications for simple confirmations
- ❌ Don't make notification messages too long
- ❌ Don't forget to handle loading state cleanup
- ❌ Don't use success notifications for every small action

### Performance Considerations

- The store automatically limits concurrent notifications
- Dismissed notifications are kept in history for debugging
- Use `clearDismissed()` periodically to prevent memory leaks
- Action handlers should be lightweight to avoid blocking the UI

## Testing

### Unit Testing

```javascript
import { setActivePinia, createPinia } from "pinia";
import { useNotificationStore } from "@/stores/notifications";

describe("Notifications Store", () => {
  beforeEach(() => {
    setActivePinia(createPinia());
  });

  it("adds notifications correctly", () => {
    const store = useNotificationStore();
    const id = store.addSuccess("Test message");

    expect(store.activeNotifications).toHaveLength(1);
    expect(store.activeNotifications[0].message).toBe("Test message");
    expect(store.activeNotifications[0].type).toBe("success");
  });

  it("dismisses notifications", () => {
    const store = useNotificationStore();
    const id = store.addInfo("Test");

    store.dismissNotification(id);
    expect(store.activeNotifications).toHaveLength(0);
  });
});
```
