# FlutterFlow Custom Actions Reference

This document provides a complete reference for all custom actions available in the FlutterFlow-Supabase Sync Middleware.

## 📋 Table of Contents

- [Initialization Actions](#initialization-actions)
- [Data Operations](#data-operations)
- [File Upload Actions](#file-upload-actions)
- [Sync Management](#sync-management)
- [Utility Actions](#utility-actions)

## 🚀 Initialization Actions

### InitializeSync

Initializes the sync client with server and Supabase configuration.

**Parameters:**
- `serverUrl` (String, required) - Your middleware server URL
- `supabaseUrl` (String, required) - Your Supabase project URL
- `supabaseAnonKey` (String, required) - Your Supabase anon key

**Usage:**
```dart
await InitializeSync(
  serverUrl: 'http://localhost:3000',
  supabaseUrl: 'https://your-project.supabase.co',
  supabaseAnonKey: 'your-anon-key',
);
```

**Returns:** `void`

**Example:**
```dart
// Call this in your app's initialization
Future<void> initializeApp() async {
  await InitializeSync(
    serverUrl: 'https://your-server.com',
    supabaseUrl: 'https://your-project.supabase.co',
    supabaseAnonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  );
}
```

## 📊 Data Operations

### ReadSyncData

Reads data from the sync system.

**Parameters:**
- `tableName` (String, required) - Name of the table to read from
- `where` (String, optional) - WHERE clause for filtering
- `whereArgs` (List<dynamic>, optional) - Arguments for the WHERE clause
- `orderBy` (String, optional) - ORDER BY clause
- `limit` (int, optional) - Maximum number of records to return

**Usage:**
```dart
final data = await ReadSyncData(
  tableName: 'store_user_link',
  where: 'user_id = ?',
  whereArgs: [currentUserId],
  orderBy: 'created_at DESC',
  limit: 50,
);
```

**Returns:** `List<Map<String, dynamic>>`

**Example:**
```dart
// Read all stores for current user
final stores = await ReadSyncData(
  tableName: 'store_user_link',
  where: 'user_id = ?',
  whereArgs: [FFAppState().currentUserId],
);

// Read recent tasks
final recentTasks = await ReadSyncData(
  tableName: 'task',
  orderBy: 'created_at DESC',
  limit: 10,
);
```

### WriteSyncData

Writes data to the sync system.

**Parameters:**
- `tableName` (String, required) - Name of the table to write to
- `operation` (String, required) - Operation type: "INSERT", "UPDATE", or "DELETE"
- `data` (Map<String, dynamic>, required) - Data to write

**Usage:**
```dart
await WriteSyncData(
  tableName: 'store_user_link',
  operation: 'INSERT',
  data: {
    'id': 'store_123',
    'name': 'My Store',
    'user_id': currentUserId,
    'created_at': DateTime.now().toIso8601String(),
  },
);
```

**Returns:** `void`

**Example:**
```dart
// Insert new store
await WriteSyncData(
  tableName: 'store_user_link',
  operation: 'INSERT',
  data: {
    'id': 'store_${DateTime.now().millisecondsSinceEpoch}',
    'name': storeNameController.text,
    'user_id': FFAppState().currentUserId,
    'created_at': DateTime.now().toIso8601String(),
  },
);

// Update existing store
await WriteSyncData(
  tableName: 'store_user_link',
  operation: 'UPDATE',
  data: {
    'id': storeId,
    'name': updatedName,
    'updated_at': DateTime.now().toIso8601String(),
  },
);

// Delete store
await WriteSyncData(
  tableName: 'store_user_link',
  operation: 'DELETE',
  data: {'id': storeId},
);
```

### InsertData

Convenience action for inserting data.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `data` (Map<String, dynamic>, required) - Data to insert

**Usage:**
```dart
await InsertData(
  tableName: 'survey_responses',
  data: {
    'id': 'response_123',
    'store_code': 'STORE001',
    'question_id': 'q1',
    'answer': 'Yes',
    'created_at': DateTime.now().toIso8601String(),
  },
);
```

### UpdateData

Convenience action for updating data.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `data` (Map<String, dynamic>, required) - Data to update (must include 'id')

**Usage:**
```dart
await UpdateData(
  tableName: 'survey_responses',
  data: {
    'id': 'response_123',
    'answer': 'Updated answer',
    'updated_at': DateTime.now().toIso8601String(),
  },
);
```

### DeleteData

Convenience action for deleting data.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `recordId` (String, required) - ID of the record to delete

**Usage:**
```dart
await DeleteData(
  tableName: 'survey_responses',
  recordId: 'response_123',
);
```

## 📁 File Upload Actions

### UploadFile

Uploads a single file to the server.

**Parameters:**
- `file` (File, required) - The file to upload
- `fieldName` (String, optional) - Field name for the upload (default: 'file')

**Usage:**
```dart
final result = await UploadFile(
  file: selectedFile,
  fieldName: 'document',
);
```

**Returns:** `Map<String, dynamic>?`

**Example:**
```dart
// Upload a document
final result = await UploadFile(file: documentFile);
if (result != null) {
  print('File uploaded: ${result['fileUrl']}');
  print('File size: ${result['fileSize']}');
}
```

### UploadImage

Uploads a single image with automatic processing.

**Parameters:**
- `imageFile` (File, required) - The image file to upload
- `fieldName` (String, optional) - Field name for the upload (default: 'file')

**Usage:**
```dart
final result = await UploadImage(
  imageFile: selectedImage,
);
```

**Returns:** `Map<String, dynamic>?`

**Example:**
```dart
// Upload product image
final result = await UploadImage(imageFile: productImage);
if (result != null) {
  // Save image reference to product
  await WriteSyncData(
    tableName: 'product_images',
    operation: 'INSERT',
    data: {
      'id': 'img_${DateTime.now().millisecondsSinceEpoch}',
      'product_id': productId,
      'image_url': result['fileUrl'],
      'thumbnail_url': result['thumbnailUrl'],
      'file_size': result['fileSize'],
    },
  );
}
```

### UploadFiles

Uploads multiple files at once.

**Parameters:**
- `files` (List<File>, required) - List of files to upload
- `fieldName` (String, optional) - Field name for the upload (default: 'files')

**Usage:**
```dart
final results = await UploadFiles(
  files: [file1, file2, file3],
);
```

**Returns:** `List<Map<String, dynamic>>`

**Example:**
```dart
// Upload multiple product images
final results = await UploadFiles(files: productImages);
for (final result in results) {
  await WriteSyncData(
    tableName: 'product_images',
    operation: 'INSERT',
    data: {
      'id': 'img_${DateTime.now().millisecondsSinceEpoch}',
      'product_id': productId,
      'image_url': result['fileUrl'],
      'thumbnail_url': result['thumbnailUrl'],
    },
  );
}
```

### GetUploadedFiles

Retrieves list of uploaded files for the current user.

**Parameters:**
- `limit` (int, optional) - Maximum number of files to return
- `offset` (int, optional) - Number of files to skip
- `mimeType` (String, optional) - Filter by MIME type (e.g., 'image/')

**Usage:**
```dart
final files = await GetUploadedFiles(
  limit: 20,
  mimeType: 'image/',
);
```

**Returns:** `List<Map<String, dynamic>>`

**Example:**
```dart
// Get all uploaded images
final images = await GetUploadedFiles(mimeType: 'image/');
for (final image in images) {
  print('Image: ${image['originalName']} - ${image['fileUrl']}');
}
```

### DeleteUploadedFile

Deletes an uploaded file.

**Parameters:**
- `fileId` (String, required) - ID of the file to delete

**Usage:**
```dart
await DeleteUploadedFile(fileId: 'file_123');
```

**Returns:** `void`

## 🔄 Sync Management

### PerformSync

Triggers a manual sync operation.

**Parameters:** None

**Usage:**
```dart
await PerformSync();
```

**Returns:** `void`

**Example:**
```dart
// Trigger sync when user pulls to refresh
Future<void> onRefresh() async {
  await PerformSync();
  // Refresh your data
  setState(() {
    // Update UI
  });
}
```

### GetSyncStatus

Gets the current sync status for the user.

**Parameters:** None

**Usage:**
```dart
final status = await GetSyncStatus();
```

**Returns:** `List<Map<String, dynamic>>`

**Example:**
```dart
// Check sync status
final status = await GetSyncStatus();
for (final item in status) {
  print('Table: ${item['table_name']} - Status: ${item['sync_status']}');
}
```

### GetSyncEvents

Gets the stream of sync events for real-time updates.

**Parameters:** None

**Usage:**
```dart
final events = GetSyncEvents();
```

**Returns:** `Stream<SyncEvent>`

**Example:**
```dart
// Listen for sync events
GetSyncEvents().listen((event) {
  if (event is SyncCompleted) {
    // Refresh data when sync completes
    setState(() {
      // Update UI
    });
  }
});
```

## 🔧 Utility Actions

### IsConnected

Checks if the sync client is connected to the server.

**Parameters:** None

**Usage:**
```dart
final connected = IsConnected();
```

**Returns:** `bool`

**Example:**
```dart
// Show connection status
final connected = IsConnected();
if (connected) {
  // Show online indicator
} else {
  // Show offline indicator
}
```

### GetCurrentUser

Gets the current authenticated user.

**Parameters:** None

**Usage:**
```dart
final user = GetCurrentUser();
```

**Returns:** `User?`

**Example:**
```dart
// Get current user info
final user = GetCurrentUser();
if (user != null) {
  print('User ID: ${user.id}');
  print('User Email: ${user.email}');
}
```

### ReadDataWithFilters

Reads data with advanced filtering options.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `filters` (Map<String, dynamic>, optional) - Filter conditions
- `orderBy` (String, optional) - ORDER BY clause
- `limit` (int, optional) - Maximum number of records
- `offset` (int, optional) - Number of records to skip

**Usage:**
```dart
final data = await ReadDataWithFilters(
  tableName: 'task',
  filters: {
    'status': 'pending',
    'store_code': 'STORE001',
  },
  orderBy: 'created_at DESC',
  limit: 20,
);
```

**Returns:** `List<Map<String, dynamic>>`

### SearchData

Searches data across multiple fields.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `searchTerm` (String, required) - Search term
- `searchFields` (List<String>, required) - Fields to search in
- `limit` (int, optional) - Maximum number of results

**Usage:**
```dart
final results = await SearchData(
  tableName: 'product_store',
  searchTerm: 'coffee',
  searchFields: ['name', 'description', 'category'],
  limit: 10,
);
```

**Returns:** `List<Map<String, dynamic>>`

### GetDataCount

Gets the count of records matching criteria.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `where` (String, optional) - WHERE clause

**Usage:**
```dart
final count = await GetDataCount(
  tableName: 'task',
  where: 'status = "pending"',
);
```

**Returns:** `int`

### RecordExists

Checks if a record exists with specific criteria.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `field` (String, required) - Field to check
- `value` (dynamic, required) - Value to check for

**Usage:**
```dart
final exists = await RecordExists(
  tableName: 'store_user_link',
  field: 'store_code',
  value: 'STORE001',
);
```

**Returns:** `bool`

### GetLatestRecords

Gets the most recent records from a table.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `dateField` (String, required) - Date field to sort by
- `limit` (int, optional) - Maximum number of records (default: 10)

**Usage:**
```dart
final latest = await GetLatestRecords(
  tableName: 'survey_responses',
  dateField: 'created_at',
  limit: 5,
);
```

**Returns:** `List<Map<String, dynamic>>`

### GetRecordsByDateRange

Gets records within a specific date range.

**Parameters:**
- `tableName` (String, required) - Name of the table
- `dateField` (String, required) - Date field to filter by
- `startDate` (DateTime, required) - Start date
- `endDate` (DateTime, required) - End date
- `orderBy` (String, optional) - ORDER BY clause
- `limit` (int, optional) - Maximum number of records

**Usage:**
```dart
final records = await GetRecordsByDateRange(
  tableName: 'task',
  dateField: 'created_at',
  startDate: DateTime.now().subtract(Duration(days: 7)),
  endDate: DateTime.now(),
  orderBy: 'created_at DESC',
);
```

**Returns:** `List<Map<String, dynamic>>`

## 📝 Best Practices

### Error Handling

Always wrap sync operations in try-catch blocks:

```dart
try {
  final data = await ReadSyncData(tableName: 'my_table');
  // Use data
} catch (e) {
  // Handle error
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('Error: $e')),
  );
}
```

### Loading States

Show loading indicators during operations:

```dart
bool _isLoading = false;

Future<void> _loadData() async {
  setState(() {
    _isLoading = true;
  });
  
  try {
    final data = await ReadSyncData(tableName: 'my_table');
    // Use data
  } finally {
    setState(() {
      _isLoading = false;
    });
  }
}
```

### Data Validation

Validate data before writing:

```dart
bool _validateData(Map<String, dynamic> data) {
  if (data['name'] == null || data['name'].isEmpty) {
    return false;
  }
  return true;
}

Future<void> _saveData(Map<String, dynamic> data) async {
  if (!_validateData(data)) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Invalid data')),
    );
    return;
  }
  
  await WriteSyncData(
    tableName: 'my_table',
    operation: 'INSERT',
    data: data,
  );
}
```

## 🎯 Common Use Cases

### User Profile Management

```dart
// Get user profile
final profile = await ReadSyncData(
  tableName: 'app_user',
  where: 'id = ?',
  whereArgs: [currentUserId],
);

// Update user profile
await UpdateData(
  tableName: 'app_user',
  data: {
    'id': currentUserId,
    'name': newName,
    'email': newEmail,
    'updated_at': DateTime.now().toIso8601String(),
  },
);
```

### Store Management

```dart
// Get user's stores
final stores = await ReadSyncData(
  tableName: 'store_user_link',
  where: 'user_id = ?',
  whereArgs: [currentUserId],
);

// Add new store
await InsertData(
  tableName: 'store_user_link',
  data: {
    'id': 'store_${DateTime.now().millisecondsSinceEpoch}',
    'name': storeName,
    'user_id': currentUserId,
    'store_code': storeCode,
    'created_at': DateTime.now().toIso8601String(),
  },
);
```

### Task Management

```dart
// Get pending tasks
final tasks = await ReadSyncData(
  tableName: 'task',
  where: 'status = ? AND store_code = ?',
  whereArgs: ['pending', storeCode],
  orderBy: 'created_at ASC',
);

// Complete task
await UpdateData(
  tableName: 'task',
  data: {
    'id': taskId,
    'status': 'completed',
    'completed_at': DateTime.now().toIso8601String(),
  },
);
```

### Image Gallery

```dart
// Get product images
final images = await GetUploadedFiles(mimeType: 'image/');

// Upload new image
final result = await UploadImage(imageFile: selectedImage);
if (result != null) {
  await InsertData(
    tableName: 'product_images',
    data: {
      'id': 'img_${DateTime.now().millisecondsSinceEpoch}',
      'product_id': productId,
      'image_url': result['fileUrl'],
      'thumbnail_url': result['thumbnailUrl'],
    },
  );
}
```

This reference covers all the custom actions available in the FlutterFlow-Supabase Sync Middleware. Use these actions to build powerful offline-first applications with FlutterFlow!
