Skip to content

Mock Data Development Guide

Purpose: Guide for building features with local/mock data before backend integration


Build UI features with mock data first, integrate backend later

  • ✅ Rapid development without backend dependencies
  • ✅ Easy to test and iterate on UX
  • ✅ Clear understanding of data requirements
  • ✅ Smooth transition to backend when ready

All mock data is in shaker/data/ directory:

shaker/data/
├── products/ # Product inventory
├── ingredients/ # Generic ingredients
├── recipes/ # Cocktail recipes
├── events/ # Events and menus
├── guests/ # Guest lists
├── venues/ # Venue information
└── themes/ # Event themes

Each data module exports:

  • Data array - mockProducts, mockRecipes, etc.
  • Getter functions - getById(), getAll(), getByType(), etc.
  • Update functions - updateProduct(), addRecipe(), etc.
  • Helper functions - Calculations, filtering, etc.

Build the form with validation, just like you would for a real backend.

Example: Product editing form

const [formData, setFormData] = useState<FormData>(initialFormData);
const [errors, setErrors] = useState<FormErrors>({});
const handleSubmit = async () => {
const validationErrors = validateForm(formData);
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
return;
}
// Continue to Step 2...
};

Use the same data preparation as you would for GraphQL.

Example:

const mutationData = prepareMutationData(formData, getCurrentLevelValue);
console.log('📤 Mutation data:', JSON.stringify(mutationData, null, 2));

Call the update function from the data module.

Example:

import { updateProduct } from '@/data/products';
// Update local mock data
const updatedProduct = updateProduct(id, {
name: formData.name,
brand: formData.brand,
type: formData.type,
// ... other fields
});
console.log('✅ Updated successfully!', updatedProduct);

Use inline alerts (not blocking modals).

Example:

// Show success message
setShowSuccess(true);
// Auto-hide and navigate
setTimeout(() => {
setShowSuccess(false);
router.back();
}, 3000);

Comment where the GraphQL mutation will go.

Example:

// TODO: Replace with actual GraphQL mutation when UpdateProduct is available
// await updateProductMutation.mutate({ id, input: mutationData });
// Simulate API call for now
await new Promise(resolve => setTimeout(resolve, 1000));
// Update local mock data until backend is ready
const updatedProduct = updateProduct(id, { /* ... */ });

<augment_code_snippet path=“shaker/app/(tabs)/inventory/products/edit-product.tsx” mode=“EXCERPT”>

const handleSubmit = async () => {
// Step 1: Validate
const validationErrors = validateForm(formData);
setErrors(validationErrors);
if (Object.keys(validationErrors).length > 0) return;
setIsSubmitting(true);
try {
// Step 2: Prepare mutation data
const mutationData = prepareMutationData(formData, getCurrentLevelValue);
console.log('📤 Update mutation data:', JSON.stringify(mutationData, null, 2));
// Step 5: TODO for backend
// TODO: Replace with actual GraphQL mutation when UpdateProduct is available
// await updateProductMutation.mutate({ id, input: mutationData });
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
// Step 3: Update mock data
const currentLevelValue = getCurrentLevelValue(formData.currentLevel, formData.volume);
const updatedProduct = updateProduct(id, {
name: formData.name,
brand: formData.brand,
type: formData.type as ProductTypeValue,
currentLevel: {
currentAmount: currentLevelValue,
totalCapacity: parseFloat(formData.volume),
percentage: (currentLevelValue / parseFloat(formData.volume)) * 100,
status: calculateLevelStatus(currentLevelValue, parseFloat(formData.volume)),
lastUpdated: new Date().toISOString(),
},
// ... other fields
});
console.log('✅ Product updated successfully!', updatedProduct);
// Step 4: Show success
setShowSuccess(true);
setTimeout(() => {
setShowSuccess(false);
router.back();
}, 3000);
} catch (error) {
console.error('❌ Error updating product:', error);
RNAlert.alert('Error', 'Failed to update product. Please try again.');
} finally {
setIsSubmitting(false);
}
};

</augment_code_snippet>


When backend is ready, the transition is simple:

// TODO: Replace with actual GraphQL mutation
// await updateProductMutation.mutate({ id, input: mutationData });
await new Promise(resolve => setTimeout(resolve, 1000));
const updatedProduct = updateProduct(id, { /* ... */ });
// Backend integration
const result = await updateProductMutation.mutate({ id, input: mutationData });
const updatedProduct = result.data.updateProduct;

That’s it! The mutation data is already prepared correctly.


  • ✅ Use the same data shapes as GraphQL schema
  • ✅ Prepare mutation data even for mock updates
  • ✅ Log mutation data for debugging
  • ✅ Add clear TODO comments for backend
  • ✅ Use inline success alerts (not blocking modals)
  • ✅ Simulate API delay for realistic UX
  • ✅ Update updatedAt timestamps
  • ❌ Skip validation because it’s “just mock data”
  • ❌ Use different data shapes than backend
  • ❌ Forget to update related data (e.g., timestamps)
  • ❌ Use blocking alerts for success messages
  • ❌ Skip error handling
  • ❌ Forget TODO comments

Current Approach:

  1. Build complete UI with validation
  2. Prepare data for GraphQL (even though not using yet)
  3. Update mock data directly
  4. Show success feedback
  5. Add TODO for backend integration

Future Transition:

  1. Uncomment GraphQL mutation
  2. Remove mock data update
  3. Done! ✅

This approach gives us:

  • Fast development now
  • Easy backend integration later
  • Production-quality UX throughout