Documentation Index
Fetch the complete documentation index at: https://docs.everybite.com/llms.txt
Use this file to discover all available pages before exploring further.
Step-by-step implementations for common user journeys with the SmartMenu API.
Flow 1: First-Time User Setup
A new user sets up their dietary preferences for the first time.
Implementation
async function onboardNewUser(guestId) {
// 1. Start session - guest identity bound here
const { sessionId } = await startSession({
guestId,
});
// Store session ID for subsequent API calls
setSessionId(sessionId);
// 2. Get available options (uses X-Session-ID header)
const options = await getFilterOptions();
// 3. Show preference UI and wait for selection
const preferences = await showPreferenceSetupUI(options);
// 4. Save preferences locally
saveUserPreferences(preferences);
// 5. Fetch personalized menu (uses X-Session-ID header)
const menu = await searchWithPreferences(preferences);
return menu;
}
Flow 2: Returning User Quick Order
A returning user with saved preferences browses the menu.
async function loadMenuForReturningUser(guestId) {
// 1. Start session - guest identity bound here
const { sessionId } = await startSession({
guestId,
});
setSessionId(sessionId);
// 2. Load saved preferences
const preferences = loadUserPreferences();
// 3. Immediately fetch personalized menu (uses X-Session-ID header)
const menu = await searchWithPreferences(preferences);
// 4. Prefetch filter options in background
prefetchFilterOptions();
return menu;
}
Flow 3: Browsing with Dynamic Filters
User adjusts filters while browsing the menu.
function useMenuWithFilters() {
const [preferences, setPreferences] = useState(loadUserPreferences());
const [menu, setMenu] = useState(null);
const sessionId = useSession(); // Session already started with chain context
// Debounced search when preferences change
useEffect(() => {
const search = debounce(async () => {
// Uses X-Session-ID header automatically
const results = await searchWithPreferences(preferences);
setMenu(results);
}, 300);
search();
return () => search.cancel();
}, [preferences, sessionId]);
const updateDiet = (diet) => {
setPreferences(prev => ({
...prev,
diets: prev.diets.includes(diet)
? prev.diets.filter(d => d !== diet)
: [...prev.diets, diet]
}));
};
const updateAllergen = (allergen) => {
setPreferences(prev => ({
...prev,
excludeAllergens: prev.excludeAllergens.includes(allergen)
? prev.excludeAllergens.filter(a => a !== allergen)
: [...prev.excludeAllergens, allergen]
}));
};
return { menu, preferences, updateDiet, updateAllergen };
}
Flow 4: Viewing Dish Details
User taps on a dish to see full details.
async function viewDishDetails(dishId) {
// Fetch complete dish information (uses X-Session-ID header)
const dish = await getDishDetails(dishId);
// Track the view for analytics
trackEvent('dish_viewed', {
dishId,
matchStatus: dish.matchStatus,
category: dish.category
});
return dish;
}
Dish Detail UI Considerations
function DishDetailScreen({ dish }) {
return (
<View>
<Image source={{ uri: dish.imageUrl }} />
<Text style={styles.name}>{dish.name}</Text>
<Text style={styles.description}>{dish.description}</Text>
{/* Allergen warnings */}
{dish.allergens.length > 0 && (
<AllergenWarning allergens={dish.allergens} />
)}
{/* Nutrition facts */}
<NutritionLabel nutrition={dish.nutrition} />
{/* Diet badges */}
<DietBadges diets={dish.diets} />
{/* Ingredient list with allergen highlighting */}
<IngredientList
ingredients={dish.ingredients}
highlightAllergens={userPreferences.excludeAllergens}
/>
</View>
);
}
Flow 5: Handling “Almost Match” Scenarios
User views a dish that almost matches their preferences.
function AlmostMatchCard({ dish, matchReasons, onViewAnyway }) {
return (
<Card style={styles.almostMatch}>
<DishPreview dish={dish} />
<WarningBanner>
<Text>This dish almost matches your preferences:</Text>
{matchReasons.map(reason => (
<Text key={reason}>• {reason}</Text>
))}
</WarningBanner>
<Button onPress={() => onViewAnyway(dish.id)}>
View Anyway
</Button>
</Card>
);
}
Flow 6: Empty Results Handling
No dishes match the user’s strict preferences.
function EmptyResultsScreen({ preferences, onRelaxFilters }) {
const suggestions = getSuggestions(preferences);
return (
<View style={styles.emptyState}>
<Icon name="filter-off" size={64} />
<Text style={styles.title}>No exact matches found</Text>
<Text style={styles.subtitle}>
Try adjusting your filters to see more options
</Text>
{suggestions.map(suggestion => (
<SuggestionChip
key={suggestion.id}
label={suggestion.label}
onPress={() => onRelaxFilters(suggestion.change)}
/>
))}
<Button variant="secondary" onPress={() => onRelaxFilters('all')}>
Clear All Filters
</Button>
</View>
);
}
Complete Example: React Native
See the GitHub repository for a complete React Native implementation of these flows.
Download Sample App
Clone the sample app to see these flows in action