# @iblai/data-layer

A Redux Toolkit-based data layer package for IBL AI applications, providing centralized state management and API integrations using RTK Query.

## Installation

```bash
pnpm add @iblai/data-layer
```

## Overview

The data-layer package provides:
- **RTK Query API slices** for all IBL AI API endpoints
- **Redux store configuration** with pre-configured slices
- **Type-safe API hooks** for React components
- **Centralized state management** for auth, chat, subscriptions, and more

## Getting Started

### 1. Setup Redux Store

Wrap your application with the Redux Provider:

```tsx
import { Provider } from 'react-redux';
import { store } from '@iblai/data-layer';

function App() {
  return (
    <Provider store={store}>
      <YourApp />
    </Provider>
  );
}
```

### 2. Using API Hooks

The package provides auto-generated hooks for all API endpoints:

```tsx
import { useGetUserProfileQuery, useUpdateUserProfileMutation } from '@iblai/data-layer';

function UserProfile() {
  // Query hook - automatically fetches data
  const { data: profile, isLoading, error } = useGetUserProfileQuery();

  // Mutation hook - for updates
  const [updateProfile, { isLoading: isUpdating }] = useUpdateUserProfileMutation();

  const handleSave = async (data) => {
    await updateProfile(data).unwrap();
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>{profile.name}</h1>
      {/* Your profile UI */}
    </div>
  );
}
```

## Available API Slices

### Core APIs

```tsx
import {
  // User & Auth
  useGetUserProfileQuery,
  useUpdateUserProfileMutation,
  useLoginMutation,

  // Tenants
  useGetTenantsQuery,
  useGetTenantQuery,
  useCreateTenantMutation,

  // Platform
  useGetPlatformConfigQuery,
} from '@iblai/data-layer';
```

### AI & Chat APIs

```tsx
import {
  // Mentors
  useGetMentorsQuery,
  useGetMentorQuery,
  useCreateMentorMutation,

  // Chat Sessions
  useGetChatSessionsQuery,
  useCreateChatSessionMutation,

  // Memory
  useGetMemoriesQuery,
  useCreateMemoryMutation,
} from '@iblai/data-layer';
```

### Subscription APIs

```tsx
import {
  // Stripe Integration
  useGetSubscriptionQuery,
  useCreateCheckoutSessionMutation,
  useCreateCustomerPortalSessionMutation,

  // Pricing
  useGetPricingPlansQuery,
} from '@iblai/data-layer';
```

## Features

### Automatic Caching

RTK Query automatically caches API responses and handles cache invalidation:

```tsx
// This query result is cached
const { data } = useGetUserProfileQuery();

// Subsequent calls use cached data
const { data: sameData } = useGetUserProfileQuery(); // No network request
```

### Optimistic Updates

```tsx
const [updateProfile] = useUpdateUserProfileMutation();

const handleUpdate = async (newData) => {
  try {
    await updateProfile({
      id: userId,
      ...newData,
    }).unwrap();
    // UI updates optimistically before API response
  } catch (error) {
    // Error handling
  }
};
```

### Manual Cache Invalidation

```tsx
import { useDispatch } from 'react-redux';
import { apiSlice } from '@iblai/data-layer';

function RefreshButton() {
  const dispatch = useDispatch();

  const handleRefresh = () => {
    // Invalidate specific tags
    dispatch(apiSlice.util.invalidateTags(['User']));

    // Or reset entire API state
    dispatch(apiSlice.util.resetApiState());
  };

  return <button onClick={handleRefresh}>Refresh</button>;
}
```

### Polling

```tsx
// Poll every 5 seconds
const { data } = useGetChatSessionsQuery(undefined, {
  pollingInterval: 5000,
});
```

### Conditional Fetching

```tsx
// Only fetch when userId is available
const { data } = useGetUserProfileQuery(userId, {
  skip: !userId,
});
```

## Store Structure

The store includes the following slices:

```typescript
{
  api: RTKQueryState,           // All API data
  auth: AuthState,              // Authentication state
  chat: ChatState,              // Chat sessions and messages
  files: FilesState,            // File uploads and attachments
  subscription: SubscriptionState, // Subscription info
}
```

### Accessing Store State

```tsx
import { useSelector } from 'react-redux';
import { selectIsLoggedIn, selectCurrentUser } from '@iblai/data-layer';

function Header() {
  const isLoggedIn = useSelector(selectIsLoggedIn);
  const user = useSelector(selectCurrentUser);

  return (
    <header>
      {isLoggedIn ? `Welcome ${user.name}` : 'Please log in'}
    </header>
  );
}
```

## TypeScript Support

All APIs are fully typed:

```tsx
import type { UserProfile, Tenant, Mentor } from '@iblai/data-layer';

const { data } = useGetUserProfileQuery();
// data is typed as UserProfile | undefined

const { data: tenant } = useGetTenantQuery(tenantId);
// tenant is typed as Tenant | undefined
```

## Error Handling

```tsx
const { data, error, isError } = useGetUserProfileQuery();

if (isError) {
  if ('status' in error) {
    // RTK Query error
    const errMsg = 'error' in error ? error.error : JSON.stringify(error.data);
    return <div>Error: {errMsg}</div>;
  } else {
    // Serialized error
    return <div>Error: {error.message}</div>;
  }
}
```

## Advanced Usage

### Custom Endpoints

Extend the API slice with custom endpoints:

```tsx
import { apiSlice } from '@iblai/data-layer';

const extendedApi = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    getCustomData: builder.query({
      query: () => '/custom-endpoint',
    }),
  }),
});

export const { useGetCustomDataQuery } = extendedApi;
```

### Prefetching

```tsx
import { useDispatch } from 'react-redux';
import { apiSlice } from '@iblai/data-layer';

function PrefetchExample() {
  const dispatch = useDispatch();

  const prefetchUserProfile = () => {
    dispatch(
      apiSlice.util.prefetch('getUserProfile', userId, { force: true })
    );
  };

  return <button onMouseEnter={prefetchUserProfile}>Hover to prefetch</button>;
}
```

## Contributing

We welcome contributions! Please read our [contributing guidelines](CONTRIBUTING.md).

## Development

### Local Development Setup

When developing locally, use a local registry to publish packages:

```bash
make publish-local
```

Configure your `.npmrc`:

```bash
//localhost:4873/:_authToken=<token>
@iblai:registry=http://localhost:4873/
```

### Building

```bash
pnpm build
```

### Testing

```bash
pnpm test
```

## License

ISC
