0.1.6 • Published 5 months ago

@pubflow/react-native v0.1.6

Weekly downloads
-
License
AGPL-3.0-or-later
Repository
github
Last release
5 months ago

@pubflow/react-native

React Native adapter for the Pubflow framework with Expo support.

Overview

@pubflow/react-native provides React Native-specific implementations and utilities for the Pubflow framework, including:

  • Secure storage with Expo SecureStore (with AsyncStorage fallback)
  • React Native-specific components
  • Hooks optimized for mobile applications
  • Support for offline mode with mutation queuing

Installation

# Install the core package and React Native adapter
npm install @pubflow/core @pubflow/react-native

# Install required peer dependencies
npm install @react-native-async-storage/async-storage

# Optional: Install Expo SecureStore for enhanced security
npm install expo-secure-store

# Optional: Install NetInfo for better offline support
npm install @react-native-community/netinfo

# Optional: Install Zod for schema validation
npm install zod

Persistent Cache

Pubflow React Native adapter supports persistent caching to improve performance and offline experience:

import React from 'react';
import { PubflowProvider, createPersistentCache } from '@pubflow/react-native';

function App() {
  // Create a persistent cache provider
  const persistentCacheProvider = createPersistentCache({
    prefix: 'my_rn_app_cache',
    ttl: 24 * 60 * 60 * 1000, // 24 hours
    debug: __DEV__
  });

  return (
    <PubflowProvider
      config={{
        baseUrl: 'https://api.example.com',
        bridgeBasePath: '/bridge',
        authBasePath: '/auth'
      }}
      persistentCache={{
        enabled: true,
        provider: persistentCacheProvider
      }}
    >
      <YourApp />
    </PubflowProvider>
  );
}

export default App;

For more information, see the persistent cache documentation.

Usage

Provider Setup

// App.js
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { PubflowProvider } from '@pubflow/react-native';
import AppNavigator from './navigation';

export default function App() {
  return (
    <SafeAreaProvider>
      <PubflowProvider
        config={{
          baseUrl: 'https://api.example.com',
          bridgeBasePath: '/bridge',
          authBasePath: '/auth',
          useSecureStorage: true // Use Expo SecureStore when available
        }}
      >
        <AppNavigator />
      </PubflowProvider>
    </SafeAreaProvider>
  );
}

Authentication

// screens/LoginScreen.js
import React, { useState } from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
import { useAuth } from '@pubflow/react-native';

export default function LoginScreen({ navigation }) {
  const { login, isLoading } = useAuth();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  const handleLogin = async () => {
    setError('');

    try {
      const result = await login({ email, password });

      if (result.success) {
        navigation.navigate('Home');
      } else {
        setError(result.error || 'Login failed');
      }
    } catch (err) {
      setError('An error occurred during login');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Login</Text>
      {error ? <Text style={styles.error}>{error}</Text> : null}

      <TextInput
        style={styles.input}
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
        autoCapitalize="none"
        keyboardType="email-address"
      />

      <TextInput
        style={styles.input}
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />

      <Button
        title={isLoading ? "Logging in..." : "Login"}
        onPress={handleLogin}
        disabled={isLoading}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  input: {
    height: 50,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 5,
    marginBottom: 15,
    paddingHorizontal: 10,
  },
  error: {
    color: 'red',
    marginBottom: 10,
  },
});

Protected Screens

// screens/ProfileScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { useAuth, BridgeView } from '@pubflow/react-native';

export default function ProfileScreen({ navigation }) {
  const { user, logout } = useAuth();

  const handleLogout = async () => {
    await logout();
    navigation.navigate('Login');
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Profile</Text>

      {user ? (
        <>
          <Text style={styles.text}>Name: {user.name}</Text>
          <Text style={styles.text}>Email: {user.email}</Text>

          <BridgeView
            allowedTypes={['admin']}
            fallback={<Text>Admin-only content is hidden</Text>}
          >
            <Text style={styles.adminText}>Admin-only content</Text>
          </BridgeView>

          <Button title="Logout" onPress={handleLogout} />
        </>
      ) : (
        <Text>Loading user data...</Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  text: {
    fontSize: 16,
    marginBottom: 10,
  },
  adminText: {
    fontSize: 16,
    marginVertical: 20,
    color: 'purple',
    fontWeight: 'bold',
  },
});

Data Operations

// screens/UsersScreen.js
import React from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet } from 'react-native';
import { useBridgeCrud } from '@pubflow/react-native';

export default function UsersScreen({ navigation }) {
  const {
    items: users,
    loading,
    error,
    refresh,
    deleteItem
  } = useBridgeCrud({
    entityConfig: {
      endpoint: 'users'
    }
  });

  const handleDelete = (id) => {
    deleteItem(id);
  };

  if (loading) {
    return (
      <View style={styles.centered}>
        <Text>Loading...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.centered}>
        <Text style={styles.error}>Error: {error.message}</Text>
        <Button title="Retry" onPress={refresh} />
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Users</Text>

      <FlatList
        data={users}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <View style={styles.item}>
            <Text style={styles.name}>{item.name}</Text>
            <Text style={styles.email}>{item.email}</Text>
            <TouchableOpacity
              style={styles.deleteButton}
              onPress={() => handleDelete(item.id)}
            >
              <Text style={styles.deleteText}>Delete</Text>
            </TouchableOpacity>
          </View>
        )}
        refreshing={loading}
        onRefresh={refresh}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  centered: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  item: {
    padding: 15,
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
  },
  name: {
    fontSize: 18,
    fontWeight: 'bold',
  },
  email: {
    fontSize: 14,
    color: '#666',
  },
  error: {
    color: 'red',
    marginBottom: 10,
  },
  deleteButton: {
    marginTop: 10,
    padding: 5,
    backgroundColor: '#ffdddd',
    borderRadius: 5,
    alignSelf: 'flex-start',
  },
  deleteText: {
    color: 'red',
  },
});

BridgeForm Component

Pubflow provides a powerful form component that integrates with Zod schemas and Bridge API:

import { BridgeForm } from '@pubflow/react-native';
import { z } from 'zod';

// Define schema
const userSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  role: z.enum(['user', 'admin'], 'Role must be either user or admin')
});

function CreateUser() {
  return (
    <View style={{ flex: 1, padding: 16 }}>
      <Text style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 16 }}>
        Create User
      </Text>
      <BridgeForm
        schema={userSchema}
        mode="create"
        entityConfig={{ endpoint: 'users' }}
        mainColor="#c30000"
        onSuccess={(data) => {
          console.log('User created:', data);
          // Navigate or show success message
        }}
      />
    </View>
  );
}

For more information, see the BridgeForm documentation.

Offline Support

The adapter includes robust support for offline operations:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { useBridgeCrud, OfflineIndicator } from '@pubflow/react-native';

export default function ProductsScreen() {
  const {
    items: products,
    createItem,
    isOffline,
    queuedMutations
  } = useBridgeCrud({
    entityConfig: {
      endpoint: 'products'
    },
    offlineConfig: {
      queueMutations: true, // Enable mutation queuing
      showOfflineAlerts: true // Show alerts when operations are queued
    }
  });

  return (
    <View>
      {/* Offline indicator */}
      <OfflineIndicator />

      {/* Pending operations counter */}
      {queuedMutations > 0 && (
        <Text>
          {queuedMutations} operations pending synchronization
        </Text>
      )}

      {/* Create button works even offline */}
      <Button
        title="Add Product"
        onPress={() => createItem({ name: 'New Product', price: 99.99 })}
      />
    </View>
  );
}

For detailed documentation on offline support, see the full documentation.

Debugging Tools

Pubflow provides utilities for debugging storage-related issues:

import { PubflowProvider, debugStorage, clearStorageByPrefix } from '@pubflow/react-native';

// Enable debug tools in the provider
function App() {
  return (
    <PubflowProvider
      config={config}
      enableDebugTools={__DEV__} // Only enable in development
    >
      {/* Your app components */}
    </PubflowProvider>
  );
}

// Use debug utilities
async function debugStorageIssues() {
  // Inspect storage
  const storage = await debugStorage('prefix');
  console.log(storage.keys, storage.values);

  // Clear storage with specific prefix
  await clearStorageByPrefix('prefix');
}

For more information, see the debugging documentation.

Logging Control

Pubflow allows you to control the verbosity of logs to optimize performance:

import { PubflowProvider } from '@pubflow/react-native';

function App() {
  return (
    <PubflowProvider
      config={config}
      loggingConfig={{
        enabled: __DEV__, // Only enable logs in development
        level: 'warn',    // Only show warnings and errors
        storage: false    // Disable storage logs which can be verbose
      }}
    >
      {/* Your app components */}
    </PubflowProvider>
  );
}

For more information, see the logging control documentation.

License

AGPL-3.0-or-later