npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

platefullai-react-native-sdk

v1.0.18

Published

React Native SDK for PlatefullAI dietary customization platform

Readme

PlatefullAI React Native SDK

A React Native SDK for integrating PlatefullAI's dietary customization platform into mobile applications. This SDK provides OAuth authentication and dietary preference management for third-party apps.

Features

  • 🔐 OAuth 2.0 Authentication - Secure sign-in with PlatefullAI
  • 🎨 PlatefullButton Component - Flexible button component for authentication and settings management
  • 🍽️ Menu Item Processing - Analyze menu items for dietary compatibility
  • 🔄 Token Management - Automatic token refresh and secure storage
  • ⚙️ Environment Configuration - Support for dev/staging/production environments

Installation

Prerequisites

  • React Native 0.60+
  • React 16.8+
  • iOS 11+ or Android API 21+

Dependencies

The SDK requires the following peer dependencies:

npm install axios @react-native-async-storage/async-storage react-native-url-polyfill react-native-webview

Install the SDK

npm install platefullai-react-native-sdk

Quick Start

1. Initialize the SDK

import PlatefullAI from 'platefullai-react-native-sdk';

// Initialize with production environment
PlatefullAI.initialize({
  environment: 'production',
  config: {
    baseUrl: 'https://www.platefullai.com',
    oauthClientId: 'your-client-id'
  }
});

2. Add PlatefullButton to Your App

import React from 'react';
import { View } from 'react-native';
import { PlatefullButton } from 'platefullai-react-native-sdk';

const MyApp = () => {
  const handleComplete = (result) => {
    console.log('Authentication complete:', result);
    // result contains user data, dietary preferences, and health concerns
  };

  const handleError = (error) => {
    console.error('Authentication error:', error);
  };

  return (
    <View>
      <PlatefullButton
        userEmail="[email protected]"  // Required: User's email from your auth system
        clientId="your-client-id"     // Required: Your PlatefullAI client ID
        onComplete={handleComplete}
        onError={handleError}
        theme="light"                 // Optional: 'light' or 'dark'
        size="medium"                 // Optional: 'small', 'medium', 'large'
      />
    </View>
  );
};

3. Process Menu Items

import React from 'react';
import { useProcessItems } from 'platefullai-react-native-sdk';

const MenuScreen = () => {
  const { processItems, isProcessing, processedItems, error } = useProcessItems({
    userEmail: '[email protected]'  // Required: User's email for personalized analysis
  });

  const menuItems = [
    {
      name: 'Grilled Chicken Salad',
      description: 'Fresh mixed greens with grilled chicken breast, tomatoes, and <olive oil dressing>'
    },
    {
      name: 'Vegetarian Pasta',
      description: 'Penne pasta with marinara sauce, <parmesan cheese>, and fresh basil'
    }
  ];

  const handleProcessMenu = async () => {
    try {
      const result = await processItems(menuItems);
      console.log('Processed items:', result.processed_items);
      console.log('Analysis summary:', result.summary);
    } catch (err) {
      console.error('Processing failed:', err);
    }
  };

  return (
    <View>
      <Button 
        title={isProcessing ? "Processing..." : "Analyze Menu"} 
        onPress={handleProcessMenu}
        disabled={isProcessing}
      />
      
      {processedItems && (
        <View>
          {processedItems.map((item, index) => (
            <Text key={index}>
              {item.name}: {item.dietary_compatibility}
            </Text>
          ))}
        </View>
      )}
    </View>
  );
};

PlatefullButton Component

The PlatefullButton is a flexible button component that launches the OAuth/onboarding flow. It can be used with default PlatefullAI styling or fully customized to blend seamlessly into your app's settings screen.

Props

Required Props

| Prop | Type | Description | |------|------|-------------| | userEmail | string | User's email from your authentication system | | clientId | string | Your PlatefullAI OAuth client ID |

Optional Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | baseUrl | string | 'https://platefullai.com' | API base URL | | onComplete | function | - | Called when authentication completes | | onError | function | - | Called on authentication errors | | theme | 'light' \| 'dark' | 'light' | Button theme | | size | 'small' \| 'medium' \| 'large' | 'medium' | Button size | | width | number | Auto | Custom button width | | height | number | Auto | Custom button height | | hideOnComplete | boolean | false | Hide button after successful auth | | customText | string | - | Custom button text | | disabled | boolean | false | Disable the button | | showLoading | boolean | true | Show loading indicator | | customButton | ReactElement | - | Fully custom button content (overrides default styling) |

Complete Example

import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { PlatefullButton } from 'platefullai-react-native-sdk';

const AuthScreen = () => {
  const [userData, setUserData] = useState(null);

  const handleComplete = (result) => {
    setUserData(result);
    console.log('User authenticated:', result.userEmail);
    console.log('Dietary preferences:', result.dietaryPreferences);
    console.log('Health concerns:', result.healthConcerns);
  };

  const handleError = (error) => {
    console.error('Authentication failed:', error.message);
  };

  return (
    <View style={styles.container}>
      {!userData ? (
        <PlatefullButton
          userEmail="[email protected]"
          clientId="your-client-id"
          onComplete={handleComplete}
          onError={handleError}
          theme="light"
          size="large"
          customText="Connect with PlatefullAI"
          hideOnComplete={true}
        />
      ) : (
        <View>
          <Text>Welcome, {userData.userEmail}!</Text>
          <Text>Dietary Preferences: {userData.dietaryPreferences.join(', ')}</Text>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
});

Custom Button Example

For maximum flexibility, you can use the customButton prop to fully customize the button appearance. This is perfect for integrating into your app's settings screen:

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { PlatefullButton } from 'platefullai-react-native-sdk';

const SettingsScreen = () => {
  return (
    <View style={styles.container}>
      {/* Fully customized button - no PlatefullAI branding */}
      <PlatefullButton
        userEmail="[email protected]"
        clientId="your-client-id"
        customButton={
          <View style={styles.customButton}>
            <Text style={styles.customButtonText}>Dietary Preferences</Text>
            <Text style={styles.customButtonSubtext}>Manage your dietary restrictions</Text>
          </View>
        }
        style={styles.buttonContainer} // Optional: style the TouchableOpacity wrapper
        onComplete={(result) => {
          console.log('Settings updated:', result);
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  buttonContainer: {
    backgroundColor: '#f5f5f5',
    borderRadius: 12,
    padding: 16,
    marginVertical: 8,
  },
  customButton: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  customButtonText: {
    fontSize: 16,
    fontWeight: '600',
    color: '#000',
  },
  customButtonSubtext: {
    fontSize: 14,
    color: '#666',
    marginTop: 4,
  },
});

Note: When using customButton, the component provides only the TouchableOpacity wrapper with the OAuth flow logic. All visual styling and content is controlled by your custom React element. The button will automatically route users to the appropriate screen (dietary preferences if they're already authenticated with consent, or the full onboarding flow if needed).

Menu Item Processing

The useProcessItems hook provides easy integration for analyzing menu items against user dietary preferences.

Hook Usage

import { useProcessItems } from 'platefullai-react-native-sdk';

const { 
  processItems,      // Function to process menu items
  isProcessing,     // Boolean: currently processing
  processedItems,   // Array: processed menu items
  summary,          // Object: processing summary
  error,            // Error object if processing failed
  clearProcessedItems, // Function to clear results
  getStatus         // Function to get current status
} = useProcessItems({
  userEmail: '[email protected]',  // Required
  useBrackets: true,              // Parse <ingredients> in descriptions
  transformMenuItem: (item) => {  // Optional: transform items before processing
    return {
      name: item.title,
      description: item.details
    };
  },
  markup: {                       // Optional: field mapping
    name: 'name',
    description: 'description',
    container: 'menu-item'
  }
});

Menu Item Format

Menu items should be an array of objects with the following structure:

const menuItems = [
  {
    name: 'Grilled Salmon',
    description: 'Fresh Atlantic salmon grilled with herbs and <olive oil>',
    // Additional fields are optional and will be preserved
    price: 24.99,
    category: 'main-course'
  },
  {
    name: 'Caesar Salad',
    description: 'Romaine lettuce with <parmesan cheese>, croutons, and caesar dressing',
    price: 12.99,
    category: 'salad'
  }
];

Processing Results

The processItems function returns processed items with dietary analysis:

const result = await processItems(menuItems);

// result.processed_items contains:
[
  {
    name: 'Grilled Salmon',
    description: 'Fresh Atlantic salmon grilled with herbs and olive oil',
    dietary_compatibility: 'compatible', // 'compatible', 'conflict', 'neutral'
    dietary_notes: 'High in omega-3 fatty acids, good protein source',
    health_score: 8.5,
    // Original fields preserved
    price: 24.99,
    category: 'main-course'
  }
]

// result.summary contains:
{
  totalItems: 2,
  matches: 1,      // Items compatible with user preferences
  conflicts: 0,    // Items conflicting with user preferences  
  neutral: 1       // Items with neutral compatibility
}

Complete Processing Example

import React, { useState } from 'react';
import { View, Text, Button, FlatList, StyleSheet } from 'react-native';
import { useProcessItems } from 'platefullai-react-native-sdk';

const MenuScreen = () => {
  const [menuItems] = useState([
    {
      name: 'Grilled Chicken Breast',
      description: 'Tender chicken breast grilled with herbs and <olive oil>',
      price: 18.99
    },
    {
      name: 'Vegetarian Pasta',
      description: 'Penne pasta with marinara sauce and <parmesan cheese>',
      price: 16.99
    },
    {
      name: 'Caesar Salad',
      description: 'Romaine lettuce with <parmesan cheese> and croutons',
      price: 12.99
    }
  ]);

  const { 
    processItems, 
    isProcessing, 
    processedItems, 
    error 
  } = useProcessItems({
    userEmail: '[email protected]'
  });

  const handleAnalyzeMenu = async () => {
    try {
      const result = await processItems(menuItems);
      console.log('Analysis complete:', result.summary);
    } catch (err) {
      console.error('Analysis failed:', err);
    }
  };

  const renderMenuItem = ({ item }) => (
    <View style={styles.menuItem}>
      <Text style={styles.itemName}>{item.name}</Text>
      <Text style={styles.itemDescription}>{item.description}</Text>
      <Text style={styles.itemPrice}>${item.price}</Text>
      
      {item.dietary_compatibility && (
        <View style={[
          styles.compatibilityBadge,
          { backgroundColor: getCompatibilityColor(item.dietary_compatibility) }
        ]}>
          <Text style={styles.compatibilityText}>
            {item.dietary_compatibility.toUpperCase()}
          </Text>
        </View>
      )}
      
      {item.dietary_notes && (
        <Text style={styles.dietaryNotes}>{item.dietary_notes}</Text>
      )}
    </View>
  );

  const getCompatibilityColor = (compatibility) => {
    switch (compatibility) {
      case 'compatible': return '#4CAF50';
      case 'conflict': return '#F44336';
      case 'neutral': return '#FF9800';
      default: return '#9E9E9E';
    }
  };

  return (
    <View style={styles.container}>
      <Button
        title={isProcessing ? "Analyzing..." : "Analyze Menu"}
        onPress={handleAnalyzeMenu}
        disabled={isProcessing}
      />
      
      {error && (
        <Text style={styles.errorText}>
          Error: {error.message}
        </Text>
      )}
      
      <FlatList
        data={processedItems || menuItems}
        renderItem={renderMenuItem}
        keyExtractor={(item, index) => index.toString()}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
  },
  menuItem: {
    backgroundColor: '#fff',
    padding: 16,
    marginVertical: 8,
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  itemName: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  itemDescription: {
    fontSize: 14,
    color: '#666',
    marginVertical: 4,
  },
  itemPrice: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#4CAF50',
  },
  compatibilityBadge: {
    alignSelf: 'flex-start',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 4,
    marginTop: 8,
  },
  compatibilityText: {
    color: '#fff',
    fontSize: 12,
    fontWeight: 'bold',
  },
  dietaryNotes: {
    fontSize: 12,
    color: '#666',
    fontStyle: 'italic',
    marginTop: 4,
  },
  errorText: {
    color: '#F44336',
    textAlign: 'center',
    marginVertical: 16,
  },
});

export default MenuScreen;

Environment Configuration

Production Setup

import PlatefullAI from 'platefullai-react-native-sdk';

// Set production environment
PlatefullAI.initialize({
  environment: 'production',
  config: {
    baseUrl: 'https://www.platefullai.com',
    oauthClientId: 'your-production-client-id'
  }
});

Development Setup

import PlatefullAI from 'platefullai-react-native-sdk';

// Set development environment
PlatefullAI.initialize({
  environment: 'development',
  config: {
    baseUrl: 'http://localhost:8000',
    oauthClientId: 'your-dev-client-id'
  }
});

Deep Linking Setup

iOS Setup

Add URL scheme to ios/YourApp/Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>platefullai-oauth</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>platefullai</string>
    </array>
  </dict>
</array>

Android Setup

Add intent filter to android/app/src/main/AndroidManifest.xml:

<activity
  android:name=".MainActivity"
  android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="platefullai" />
  </intent-filter>
</activity>

Handle OAuth Callbacks

import { handleOAuthCallback } from 'platefullai-react-native-sdk';

// In your deep link handler
const handleDeepLink = async (url) => {
  if (url.startsWith('platefullai://')) {
    try {
      const result = await handleOAuthCallback(url);
      console.log('OAuth callback handled:', result);
    } catch (error) {
      console.error('OAuth callback error:', error);
    }
  }
};

API Reference

PlatefullButton Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | userEmail | string | ✅ | - | User's email from your auth system | | clientId | string | ✅ | - | PlatefullAI OAuth client ID | | baseUrl | string | ❌ | 'https://platefullai.com' | API base URL | | onComplete | function | ❌ | - | Called when auth completes | | onError | function | ❌ | - | Called on auth errors | | theme | 'light' \| 'dark' | ❌ | 'light' | Button theme | | size | 'small' \| 'medium' \| 'large' | ❌ | 'medium' | Button size | | width | number | ❌ | Auto | Custom button width | | height | number | ❌ | Auto | Custom button height | | hideOnComplete | boolean | ❌ | false | Hide after successful auth | | customText | string | ❌ | - | Custom button text | | disabled | boolean | ❌ | false | Disable button | | showLoading | boolean | ❌ | true | Show loading indicator | | customButton | ReactElement | ❌ | - | Fully custom button content (overrides default styling) |

useProcessItems Hook

| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | userEmail | string | ✅ | - | User's email for personalized analysis | | transformMenuItem | function | ❌ | - | Transform items before processing | | useBrackets | boolean | ❌ | true | Parse <ingredients> in descriptions | | markup | object | ❌ | {name: 'name', description: 'description', container: 'menu-item'} | Field mapping |

Return Values

| Property | Type | Description | |----------|------|-------------| | processItems | function | Process menu items | | isProcessing | boolean | Currently processing | | processedItems | array | Processed menu items | | summary | object | Processing summary | | error | Error | Processing error | | clearProcessedItems | function | Clear results | | getStatus | function | Get current status |

Error Handling

import { PlatefullButton, useProcessItems } from 'platefullai-react-native-sdk';

const MyComponent = () => {
  const { processItems } = useProcessItems({
    userEmail: '[email protected]'
  });

  const handleSignInError = (error) => {
    switch (error.code) {
      case 'NETWORK_ERROR':
        console.log('Network error - check internet connection');
        break;
      case 'INVALID_CLIENT':
        console.log('Invalid client ID - check configuration');
        break;
      case 'USER_DENIED':
        console.log('User denied consent');
        break;
      default:
        console.log('Authentication error:', error.message);
    }
  };

  const handleProcessError = async () => {
    try {
      await processItems(menuItems);
    } catch (error) {
      if (error.message.includes('userEmail')) {
        console.log('User email required for processing');
      } else if (error.message.includes('menuItems')) {
        console.log('Menu items must be a non-empty array');
      } else {
        console.log('Processing error:', error.message);
      }
    }
  };

  return (
    <PlatefullButton
      userEmail="[email protected]"
      clientId="your-client-id"
      onError={handleSignInError}
    />
  );
};

Security Considerations

  • ✅ All debugging logs removed for production
  • ✅ Error logging preserved for monitoring
  • ✅ OAuth tokens securely stored using AsyncStorage
  • ✅ Automatic token refresh prevents session expiration
  • ✅ HTTPS endpoints used for all production API calls
  • ✅ Client ID validation and secure token handling

Version Information

Current version: 1.0.17 (Production Ready)

Support

For support and questions:

License

MIT License - see LICENSE file for details.