Skip to main content

Migration Plan: Big Bang Approach

Strategy Overview

The Big Bang approach rewrites the @digiwedge/react-native-paper wrapper library to use Gluestack UI v3 internals while maintaining backward-compatible exports where feasible. All mobile apps are migrated simultaneously, eliminating the need for dual-library support.

Note: @digiwedge/react-native-paper has been removed from the workspace; legacy screens/hooks now live in @digiwedge/mobile-auth. References below capture the migration record.

┌──────────────────────────────────────────────────────────────────┐
│ BIG BANG MIGRATION │
│ │
│ Week 1-2 Week 3-4 Week 5-6 Week 7-8 Week 9-10 │
│ ──────── ──────── ──────── ──────── ────────── │
│ Foundation Forms Overlays Business Integration │
│ & Setup & Input & Modals Logic & QA │
│ │
│ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ │
└──────────────────────────────────────────────────────────────────┘

Pre-Migration Checklist

Environment Setup

  • Expo SDK 54 aligned across all apps
  • React Native 0.81.5 baseline
  • Node 22 LTS
  • pnpm workspace configured

Audit Tasks

  • Complete grep audit for all react-native-paper imports
  • Document all custom theme tokens in use
  • List all third-party packages depending on Paper
  • Screenshot all major screens for visual comparison

Team Preparation

  • NativeWind/Tailwind training session
  • Gluestack v3 component API walkthrough
  • Compound component pattern explanation
  • Code review guidelines for migration PRs

Phase 1: Foundation & Setup (Week 1-2)

Goals

  • Initialize Gluestack UI v3 in monorepo
  • Configure NativeWind across all mobile apps
  • Create new wrapper library scaffold
  • Port core primitives

Tasks

1.1 Initialize Gluestack UI

# Use the existing libs/ui/gluestack-ui scaffold.
# Only run the CLI in libs/ui/gluestack-ui when adding new components.
cd libs/ui/gluestack-ui
pnpm dlx gluestack-ui add box text icon divider spinner

1.2 Create @digiwedge/gluestack-ui Library

libs/ui/gluestack-ui/
├── src/
│ ├── index.ts # Main exports
│ ├── components/
│ │ ├── primitives/ # Box, Text, Icon, Divider, Spinner
│ │ ├── forms/ # Button, Input, Switch, etc.
│ │ ├── overlays/ # Modal, Menu, Toast, etc.
│ │ └── business/ # Auth, Profile, Booking modals
│ ├── hooks/ # Re-export existing hooks unchanged
│ ├── stores/ # Re-export existing stores unchanged
│ ├── types/ # Re-export existing types unchanged
│ └── theme/
│ ├── tokens.ts # Design tokens
│ ├── tailwind.config.js # Tailwind configuration
│ └── Provider.tsx # GluestackUIProvider wrapper
├── package.json
└── tsconfig.json

1.3 Configure NativeWind in Apps

Each app needs:

// metro.config.js
const { withNxMetro } = require('@nx/expo');
const { getDefaultConfig } = require('@expo/metro-config');
const { mergeConfig } = require('metro-config');
const { withNativeWind } = require('nativewind/metro');

const defaultConfig = getDefaultConfig(__dirname);
const baseConfig = withNxMetro(mergeConfig(defaultConfig, {}), {
watchFolders: [],
extensions: [],
});

module.exports = withNativeWind(baseConfig, { input: './global.css' });

// .babelrc.*
module.exports = function (api) {
api.cache(true);
const isTest =
process.env.BABEL_ENV === 'test' || process.env.NODE_ENV === 'test';

return {
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }]],
plugins: isTest ? [] : ['nativewind/babel'],
};
};

// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'../../libs/ui/gluestack-ui/src/**/*.{js,jsx,ts,tsx}',
],
presets: [require('nativewind/preset')],
theme: {
extend: {
colors: {
primary: { /* token values */ },
secondary: { /* token values */ },
},
},
},
};

1.4 Port Primitives

Paper ComponentGluestack ComponentMigration Notes
TextTextDirect mapping, add className support
SurfaceBoxReplace with Box, use bg-* classes
DividerDividerDirect mapping
ActivityIndicatorSpinnerRename import
IconIconConfigure with lucide-react-native

Deliverables

  • @digiwedge/gluestack-ui library created
  • NativeWind configured in all 4 apps
  • Primitives (Box, Text, Icon, Divider, Spinner) working
  • Apps build successfully with new provider (QA pending)

Phase 2: Form Components (Week 3-4)

Goals

  • Migrate all form-related components
  • Implement compound component wrappers
  • Update form validation patterns

Tasks

2.1 Button Migration

Before (Paper):

<Button mode="contained" icon="plus" onPress={handlePress}>
Add Item
</Button>

After (Gluestack wrapper):

// @digiwedge/gluestack-ui/components/forms/Button.tsx
export const Button = ({
mode = 'contained',
icon,
children,
...props
}) => {
const variant = mode === 'contained' ? 'solid'
: mode === 'outlined' ? 'outline'
: 'link';

return (
<GlueButton variant={variant} {...props}>
{icon && <ButtonIcon as={getIcon(icon)} />}
<ButtonText>{children}</ButtonText>
</GlueButton>
);
};

2.2 TextInput → Input Migration

Before (Paper):

<TextInput
label="Email"
value={email}
onChangeText={setEmail}
error={!!errors.email}
mode="outlined"
/>
<HelperText type="error" visible={!!errors.email}>
{errors.email}
</HelperText>

After (Gluestack wrapper):

// @digiwedge/gluestack-ui/components/forms/TextInput.tsx
export const TextInput = ({
label,
error,
helperText,
mode = 'outlined',
...props
}) => {
const variant = mode === 'outlined' ? 'outline' : 'underlined';

return (
<FormControl isInvalid={!!error}>
{label && <FormControlLabel><FormControlLabelText>{label}</FormControlLabelText></FormControlLabel>}
<Input variant={variant}>
<InputField {...props} />
</Input>
{(error || helperText) && (
<FormControlHelper>
<FormControlHelperText className={error ? 'text-error-500' : ''}>
{error || helperText}
</FormControlHelperText>
</FormControlHelper>
)}
</FormControl>
);
};

2.3 IconButton Migration

Before (Paper):

<IconButton icon="menu" size={24} onPress={openMenu} />

After (Gluestack wrapper):

// @digiwedge/gluestack-ui/components/forms/IconButton.tsx
export const IconButton = ({ icon, size = 24, ...props }) => {
return (
<GlueButton variant="link" className="p-2" {...props}>
<ButtonIcon as={getIcon(icon)} size={size} />
</GlueButton>
);
};

2.4 Other Form Components

ComponentApproach
SwitchDirect mapping with className styling
CheckboxDirect mapping
RadioButtonUse Gluestack Radio group
SearchbarCompose from Input + InputSlot + Icon

Deliverables

  • Button, IconButton components with Paper-like API
  • TextInput with label, error, helperText support
  • Switch, Checkbox, Radio components
  • Searchbar composite component
  • All form screens updated and working

Phase 3: Overlay Components (Week 5-6)

Goals

  • Migrate modal and overlay components
  • Implement Portal-based overlays
  • Update toast notification system

Tasks

3.1 Modal/Dialog Migration

Before (Paper):

<Portal>
<Dialog visible={visible} onDismiss={hide}>
<Dialog.Title>Confirm</Dialog.Title>
<Dialog.Content>
<Text>Are you sure?</Text>
</Dialog.Content>
<Dialog.Actions>
<Button onPress={hide}>Cancel</Button>
<Button onPress={confirm}>OK</Button>
</Dialog.Actions>
</Dialog>
</Portal>

After (Gluestack wrapper):

// @digiwedge/gluestack-ui/components/overlays/Dialog.tsx
export const Dialog = ({ visible, onDismiss, children }) => {
return (
<AlertDialog isOpen={visible} onClose={onDismiss}>
<AlertDialogBackdrop />
<AlertDialogContent>
{children}
</AlertDialogContent>
</AlertDialog>
);
};

Dialog.Title = ({ children }) => (
<AlertDialogHeader>
<Heading>{children}</Heading>
</AlertDialogHeader>
);

Dialog.Content = ({ children }) => (
<AlertDialogBody>{children}</AlertDialogBody>
);

Dialog.Actions = ({ children }) => (
<AlertDialogFooter>{children}</AlertDialogFooter>
);

3.2 Menu Migration

Before (Paper):

<Menu
visible={visible}
onDismiss={closeMenu}
anchor={<IconButton icon="dots-vertical" onPress={openMenu} />}
>
<Menu.Item onPress={edit} title="Edit" />
<Menu.Item onPress={delete} title="Delete" />
</Menu>

After (Gluestack wrapper):

// @digiwedge/gluestack-ui/components/overlays/Menu.tsx
export const Menu = ({ visible, onDismiss, anchor, children }) => {
return (
<GlueMenu
isOpen={visible}
onClose={onDismiss}
trigger={(props) => cloneElement(anchor, props)}
>
{children}
</GlueMenu>
);
};

Menu.Item = ({ title, onPress, ...props }) => (
<MenuItem onPress={onPress} {...props}>
<MenuItemLabel>{title}</MenuItemLabel>
</MenuItem>
);

3.3 Toast Migration

import { useToast } from '@digiwedge/gluestack-ui';

const { showToast } = useToast();

showToast({
type: 'success',
text1: 'Saved',
text2: 'Your changes are live.',
});

Deliverables

  • Dialog/AlertDialog with compound API
  • Menu with Menu.Item pattern
  • Portal component
  • Popover, Tooltip components
  • Toast notification system
  • All modal screens migrated

Phase 4: Business Components (Week 7-8)

Goals

  • Migrate all domain-specific components
  • Update auth flows
  • Migrate booking and profile screens

Tasks

4.1 Auth Components

ComponentFilesNotes
LoginModal1Form inputs, social buttons
SignUpView1Multi-step form
ResetPasswordModal1Email input, confirmation
ConfirmOTPModal1OTP input, timer
MFAMessagingModal1Method selection
FullScreenAuthModal1Container wrapper

4.2 Profile Components

ComponentFilesNotes
ProfileSettings1Settings list, switches
EditProfileView1Form with avatar
ProfileAvatar1Avatar with camera
MyBuddies1List with actions

4.3 Booking Components

ComponentFilesNotes
BookingInformationModal1Read-only display
DeletePaymentCardModal1Confirmation dialog
MakeCardDefault1Selection modal
ClubContactForm1Contact form

4.4 Buddy Management

ComponentFilesNotes
BuddyList1Scrollable list
BuddyInputModal1Add buddy form
PlayerSearchModal1Search + select
DeleteBuddyModal1Confirmation
AddPlayersFromBuddies1Multi-select

Deliverables

  • All auth screens functional
  • Profile management working
  • Booking modals migrated
  • Buddy management complete
  • All business logic preserved

Phase 5: App Integration & QA (Week 9-10)

Goals

  • Remove react-native-paper dependency
  • Update all app entry points
  • Comprehensive visual QA
  • Performance validation

Tasks

5.1 Remove Paper Dependencies

# Remove from each app
pnpm remove react-native-paper --filter teetime-mobile
pnpm remove react-native-paper --filter teetime-country-club
pnpm remove react-native-paper --filter scl-mobile
pnpm remove react-native-paper --filter messaging_mobile

# Remove from root
pnpm remove react-native-paper -w

# Update workspace
pnpm install

5.2 Update App Providers

Before:

import { PaperProvider, MD3LightTheme } from 'react-native-paper';

export default function App() {
return (
<PaperProvider theme={MD3LightTheme}>
<NavigationContainer>
{/* ... */}
</NavigationContainer>
</PaperProvider>
);
}

After:

import { GluestackUIProvider } from '@digiwedge/gluestack-ui';
import '../global.css';

export default function App() {
return (
<GluestackUIProvider>
<NavigationContainer>
{/* ... */}
</NavigationContainer>
</GluestackUIProvider>
);
}

5.3 Visual QA Checklist

Screenteetime-mobileteetime-country-clubscl-mobilemessaging
Login[ ][ ][ ][ ]
Signup[ ][ ][ ][ ]
Home[ ][ ][ ][ ]
Profile[ ][ ][ ][ ]
Settings[ ][ ][ ][ ]
Booking[ ][ ]N/AN/A
Buddies[ ][ ]N/AN/A

5.4 Performance Validation

  • Measure initial bundle size (before/after)
  • Measure TTI (Time to Interactive)
  • Profile render performance
  • Test on low-end devices

Deliverables

  • Zero react-native-paper imports
  • All apps building successfully
  • Visual parity with before-state
  • Performance metrics documented
  • Dev clients rebuilt for all apps

Rollback Plan

If critical issues are discovered post-migration:

  1. Git Revert: All changes are in a single branch, easy to revert
  2. Package Restore: Re-add react-native-paper dependencies
  3. Provider Swap: Switch back to PaperProvider
# Emergency rollback
git revert --no-commit HEAD~N..HEAD
pnpm add react-native-paper@5.14.5 -w
pnpm install

Success Metrics

MetricTargetMeasurement
Build Success100%All 4 apps build
Test Pass Rate100%Existing tests pass
Bundle SizeNo more than currentBundle analyzer
Visual Parity95%+Screenshot diff
TTINo more than currentPerformance profiling
Paper Imports0grep audit

Post-Migration Tasks

  • Delete libs/ui/react-native-paper/ directory
  • Update CI/CD pipelines
  • Update developer documentation
  • Archive this migration epic
  • Communicate to team