@multiplayer-app/session-recorder-react-native 0.0.1-alpha.1 → 0.0.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/constants.d.ts +19 -0
- package/dist/config/constants.js +1 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/defaults.d.ts +4 -0
- package/dist/config/defaults.js +1 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/masking.d.ts +2 -30
- package/dist/config/masking.js +1 -1
- package/dist/config/masking.js.map +1 -1
- package/dist/config/session-recorder.d.ts +2 -0
- package/dist/config/session-recorder.js +1 -0
- package/dist/config/session-recorder.js.map +1 -0
- package/dist/config/validators.d.ts +10 -0
- package/dist/config/validators.js +1 -0
- package/dist/config/validators.js.map +1 -0
- package/dist/expo.d.ts +2 -2
- package/dist/expo.js +1 -1
- package/dist/expo.js.map +1 -1
- package/dist/exporters.d.ts +3 -0
- package/dist/exporters.js +1 -0
- package/dist/exporters.js.map +1 -0
- package/dist/index.d.ts +3 -9
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/otel/helpers.d.ts +45 -3
- package/dist/otel/helpers.js +1 -1
- package/dist/otel/helpers.js.map +1 -1
- package/dist/otel/index.d.ts +9 -5
- package/dist/otel/index.js +1 -1
- package/dist/otel/index.js.map +1 -1
- package/dist/otel/instrumentations/index.js +1 -1
- package/dist/otel/instrumentations/index.js.map +1 -1
- package/dist/patch/index.d.ts +1 -0
- package/dist/patch/index.js +1 -0
- package/dist/patch/index.js.map +1 -0
- package/dist/patch/xhr.d.ts +2 -0
- package/dist/patch/xhr.js +1 -0
- package/dist/patch/xhr.js.map +1 -0
- package/dist/recorder/gestureRecorder.js +1 -1
- package/dist/recorder/gestureRecorder.js.map +1 -1
- package/dist/recorder/navigationTracker.js +1 -1
- package/dist/recorder/navigationTracker.js.map +1 -1
- package/dist/recorder/screenRecorder.d.ts +1 -0
- package/dist/recorder/screenRecorder.js +1 -1
- package/dist/recorder/screenRecorder.js.map +1 -1
- package/dist/services/api.service.d.ts +62 -10
- package/dist/services/api.service.js +1 -1
- package/dist/services/api.service.js.map +1 -1
- package/dist/services/storage.service.d.ts +23 -16
- package/dist/services/storage.service.js +1 -1
- package/dist/services/storage.service.js.map +1 -1
- package/dist/session-recorder.d.ts +131 -0
- package/dist/session-recorder.js +1 -0
- package/dist/session-recorder.js.map +1 -0
- package/dist/sessionRecorder.d.ts +113 -34
- package/dist/sessionRecorder.js +1 -1
- package/dist/sessionRecorder.js.map +1 -1
- package/dist/types/index.d.ts +2 -81
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/session-recorder.d.ts +366 -0
- package/dist/types/session-recorder.js +1 -0
- package/dist/types/session-recorder.js.map +1 -0
- package/dist/types/session.d.ts +59 -0
- package/dist/types/session.js +1 -0
- package/dist/types/session.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/platform.d.ts +5 -0
- package/dist/utils/platform.js +1 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/request-utils.d.ts +21 -0
- package/dist/utils/request-utils.js +1 -0
- package/dist/utils/request-utils.js.map +1 -0
- package/dist/utils/session.d.ts +5 -0
- package/dist/utils/session.js +1 -0
- package/dist/utils/session.js.map +1 -0
- package/dist/utils/time.d.ts +4 -0
- package/dist/utils/time.js +1 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/type-utils.d.ts +16 -0
- package/dist/utils/type-utils.js +1 -0
- package/dist/utils/type-utils.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/config/constants.ts +60 -0
- package/src/config/defaults.ts +82 -0
- package/src/config/index.ts +6 -0
- package/src/config/masking.ts +10 -61
- package/src/config/session-recorder.ts +55 -0
- package/src/config/validators.ts +31 -0
- package/src/expo.ts +2 -22
- package/src/index.ts +3 -15
- package/src/otel/helpers.ts +247 -11
- package/src/otel/index.ts +109 -76
- package/src/otel/instrumentations/index.ts +8 -8
- package/src/patch/index.ts +1 -0
- package/src/patch/xhr.ts +142 -0
- package/src/recorder/gestureRecorder.ts +12 -12
- package/src/recorder/navigationTracker.ts +10 -10
- package/src/recorder/screenRecorder.ts +26 -26
- package/src/services/api.service.ts +169 -37
- package/src/services/storage.service.ts +101 -74
- package/src/session-recorder.ts +570 -0
- package/src/types/index.ts +2 -88
- package/src/types/session-recorder.ts +423 -0
- package/src/types/session.ts +65 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/platform.ts +13 -0
- package/src/utils/request-utils.ts +61 -0
- package/src/utils/session.ts +18 -0
- package/src/utils/time.ts +17 -0
- package/src/utils/type-utils.ts +75 -0
- package/src/version.ts +1 -1
- package/examples/sample-expo-app/README.md +0 -142
- package/examples/sample-expo-app/app/(tabs)/_layout.tsx +0 -60
- package/examples/sample-expo-app/app/(tabs)/explore.tsx +0 -110
- package/examples/sample-expo-app/app/(tabs)/index.tsx +0 -125
- package/examples/sample-expo-app/app/(tabs)/posts.tsx +0 -96
- package/examples/sample-expo-app/app/(tabs)/users.tsx +0 -131
- package/examples/sample-expo-app/app/+not-found.tsx +0 -32
- package/examples/sample-expo-app/app/_layout.tsx +0 -53
- package/examples/sample-expo-app/app/post/[id].tsx +0 -199
- package/examples/sample-expo-app/app/user/[id].tsx +0 -270
- package/examples/sample-expo-app/app.json +0 -42
- package/examples/sample-expo-app/assets/fonts/SpaceMono-Regular.ttf +0 -0
- package/examples/sample-expo-app/assets/images/adaptive-icon.png +0 -0
- package/examples/sample-expo-app/assets/images/favicon.png +0 -0
- package/examples/sample-expo-app/assets/images/icon.png +0 -0
- package/examples/sample-expo-app/assets/images/partial-react-logo.png +0 -0
- package/examples/sample-expo-app/assets/images/react-logo.png +0 -0
- package/examples/sample-expo-app/assets/images/react-logo@2x.png +0 -0
- package/examples/sample-expo-app/assets/images/react-logo@3x.png +0 -0
- package/examples/sample-expo-app/assets/images/splash-icon.png +0 -0
- package/examples/sample-expo-app/components/Collapsible.tsx +0 -45
- package/examples/sample-expo-app/components/ErrorView.tsx +0 -52
- package/examples/sample-expo-app/components/ExternalLink.tsx +0 -24
- package/examples/sample-expo-app/components/HapticTab.tsx +0 -18
- package/examples/sample-expo-app/components/HelloWave.tsx +0 -40
- package/examples/sample-expo-app/components/LoadingSpinner.tsx +0 -34
- package/examples/sample-expo-app/components/ParallaxScrollView.tsx +0 -82
- package/examples/sample-expo-app/components/ThemedText.tsx +0 -60
- package/examples/sample-expo-app/components/ThemedView.tsx +0 -14
- package/examples/sample-expo-app/components/ui/IconSymbol.ios.tsx +0 -32
- package/examples/sample-expo-app/components/ui/IconSymbol.tsx +0 -41
- package/examples/sample-expo-app/components/ui/TabBarBackground.ios.tsx +0 -19
- package/examples/sample-expo-app/components/ui/TabBarBackground.tsx +0 -6
- package/examples/sample-expo-app/constants/Colors.ts +0 -26
- package/examples/sample-expo-app/eslint.config.js +0 -10
- package/examples/sample-expo-app/hooks/useApi.ts +0 -41
- package/examples/sample-expo-app/hooks/useColorScheme.ts +0 -1
- package/examples/sample-expo-app/hooks/useColorScheme.web.ts +0 -21
- package/examples/sample-expo-app/hooks/useThemeColor.ts +0 -21
- package/examples/sample-expo-app/metro.config.js +0 -26
- package/examples/sample-expo-app/package-lock.json +0 -26296
- package/examples/sample-expo-app/package.json +0 -59
- package/examples/sample-expo-app/scripts/reset-project.js +0 -112
- package/examples/sample-expo-app/services/api.ts +0 -98
- package/examples/sample-expo-app/tsconfig.json +0 -17
- package/examples/sample-expo-app/utils/navigation.ts +0 -19
- package/src/sessionRecorder.ts +0 -367
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Enhanced Sample Expo React Native App
|
|
2
|
-
|
|
3
|
-
This is an enhanced sample Expo React Native app that demonstrates multiple pages, navigation, and API integration with JSONPlaceholder.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
### 🏠 Home Screen
|
|
8
|
-
|
|
9
|
-
- Welcome page with feature overview
|
|
10
|
-
- Quick navigation to Posts and Users sections
|
|
11
|
-
- Information about the app's capabilities
|
|
12
|
-
|
|
13
|
-
### 📝 Posts Tab
|
|
14
|
-
|
|
15
|
-
- Displays posts from JSONPlaceholder API
|
|
16
|
-
- Pull-to-refresh functionality
|
|
17
|
-
- Tap to view post details with comments
|
|
18
|
-
- Loading states and error handling
|
|
19
|
-
|
|
20
|
-
### 👥 Users Tab
|
|
21
|
-
|
|
22
|
-
- Shows user profiles from JSONPlaceholder API
|
|
23
|
-
- User avatars and basic information
|
|
24
|
-
- Tap to view detailed user profiles
|
|
25
|
-
- Displays user's posts
|
|
26
|
-
|
|
27
|
-
### 📄 Post Details
|
|
28
|
-
|
|
29
|
-
- Full post content with title and body
|
|
30
|
-
- Comments section with all post comments
|
|
31
|
-
- Navigation to user profile
|
|
32
|
-
- Back navigation
|
|
33
|
-
|
|
34
|
-
### 👤 User Details
|
|
35
|
-
|
|
36
|
-
- Complete user profile information
|
|
37
|
-
- Contact details (email, phone, website)
|
|
38
|
-
- Company information
|
|
39
|
-
- Address details
|
|
40
|
-
- User's posts list
|
|
41
|
-
- Navigation to individual posts
|
|
42
|
-
|
|
43
|
-
## API Integration
|
|
44
|
-
|
|
45
|
-
The app integrates with [JSONPlaceholder](https://jsonplaceholder.typicode.com/) API to demonstrate:
|
|
46
|
-
|
|
47
|
-
- **Posts API**: Fetch all posts, individual posts, and post comments
|
|
48
|
-
- **Users API**: Fetch all users, individual users, and user posts
|
|
49
|
-
- **Error Handling**: Proper error states with retry functionality
|
|
50
|
-
- **Loading States**: Loading spinners and progress indicators
|
|
51
|
-
- **Data Management**: Custom hooks for API state management
|
|
52
|
-
|
|
53
|
-
## Technical Stack
|
|
54
|
-
|
|
55
|
-
- **Expo Router**: File-based navigation
|
|
56
|
-
- **React Native**: Cross-platform mobile development
|
|
57
|
-
- **TypeScript**: Type-safe development
|
|
58
|
-
- **Axios**: HTTP client for API requests
|
|
59
|
-
- **Custom Hooks**: Reusable API state management
|
|
60
|
-
- **Themed Components**: Consistent UI with dark/light mode support
|
|
61
|
-
|
|
62
|
-
## Project Structure
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
app/
|
|
66
|
-
├── (tabs)/
|
|
67
|
-
│ ├── index.tsx # Home screen
|
|
68
|
-
│ ├── posts.tsx # Posts list
|
|
69
|
-
│ ├── users.tsx # Users list
|
|
70
|
-
│ ├── explore.tsx # Original explore screen
|
|
71
|
-
│ └── _layout.tsx # Tab navigation layout
|
|
72
|
-
├── post/
|
|
73
|
-
│ └── [id].tsx # Post detail page
|
|
74
|
-
├── user/
|
|
75
|
-
│ └── [id].tsx # User detail page
|
|
76
|
-
└── _layout.tsx # Root layout
|
|
77
|
-
|
|
78
|
-
components/
|
|
79
|
-
├── LoadingSpinner.tsx # Loading component
|
|
80
|
-
├── ErrorView.tsx # Error display component
|
|
81
|
-
└── ... # Other UI components
|
|
82
|
-
|
|
83
|
-
services/
|
|
84
|
-
└── api.ts # API service with JSONPlaceholder integration
|
|
85
|
-
|
|
86
|
-
hooks/
|
|
87
|
-
└── useApi.ts # Custom hook for API state management
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Getting Started
|
|
91
|
-
|
|
92
|
-
1. Install dependencies:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
npm install
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
2. Start the development server:
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npm start
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
3. Run on your preferred platform:
|
|
105
|
-
```bash
|
|
106
|
-
npm run ios # iOS simulator
|
|
107
|
-
npm run android # Android emulator
|
|
108
|
-
npm run web # Web browser
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## API Endpoints Used
|
|
112
|
-
|
|
113
|
-
- `GET /posts` - Fetch all posts
|
|
114
|
-
- `GET /posts/:id` - Fetch specific post
|
|
115
|
-
- `GET /posts/:id/comments` - Fetch post comments
|
|
116
|
-
- `GET /users` - Fetch all users
|
|
117
|
-
- `GET /users/:id` - Fetch specific user
|
|
118
|
-
- `GET /users/:id/posts` - Fetch user's posts
|
|
119
|
-
|
|
120
|
-
## Navigation Flow
|
|
121
|
-
|
|
122
|
-
1. **Home** → **Posts** → **Post Detail** → **User Detail**
|
|
123
|
-
2. **Home** → **Users** → **User Detail** → **Post Detail**
|
|
124
|
-
3. **Posts** → **Post Detail** → **User Detail**
|
|
125
|
-
4. **Users** → **User Detail** → **Post Detail**
|
|
126
|
-
|
|
127
|
-
## Customization
|
|
128
|
-
|
|
129
|
-
The app is designed to be easily customizable:
|
|
130
|
-
|
|
131
|
-
- **API Service**: Modify `services/api.ts` to integrate with different APIs
|
|
132
|
-
- **UI Components**: Update components in the `components/` directory
|
|
133
|
-
- **Navigation**: Add new routes in the `app/` directory
|
|
134
|
-
- **Styling**: Modify styles in individual component files
|
|
135
|
-
|
|
136
|
-
## Session Recording Integration
|
|
137
|
-
|
|
138
|
-
This sample app includes the session recorder integration, demonstrating how to capture user interactions and API calls for debugging and analytics purposes.
|
|
139
|
-
|
|
140
|
-
## Contributing
|
|
141
|
-
|
|
142
|
-
Feel free to enhance this sample app with additional features, better error handling, or different API integrations.
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Tabs } from 'expo-router'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import { Platform } from 'react-native'
|
|
4
|
-
|
|
5
|
-
import { HapticTab } from '@/components/HapticTab'
|
|
6
|
-
import { IconSymbol } from '@/components/ui/IconSymbol'
|
|
7
|
-
import TabBarBackground from '@/components/ui/TabBarBackground'
|
|
8
|
-
import { Colors } from '@/constants/Colors'
|
|
9
|
-
import { useColorScheme } from '@/hooks/useColorScheme'
|
|
10
|
-
|
|
11
|
-
export default function TabLayout() {
|
|
12
|
-
const colorScheme = useColorScheme()
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<Tabs
|
|
16
|
-
screenOptions={{
|
|
17
|
-
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
|
18
|
-
headerShown: false,
|
|
19
|
-
tabBarButton: HapticTab,
|
|
20
|
-
tabBarBackground: TabBarBackground,
|
|
21
|
-
tabBarStyle: Platform.select({
|
|
22
|
-
ios: {
|
|
23
|
-
// Use a transparent background on iOS to show the blur effect
|
|
24
|
-
position: 'absolute'
|
|
25
|
-
},
|
|
26
|
-
default: {}
|
|
27
|
-
})
|
|
28
|
-
}}
|
|
29
|
-
>
|
|
30
|
-
<Tabs.Screen
|
|
31
|
-
name='index'
|
|
32
|
-
options={{
|
|
33
|
-
title: 'Home',
|
|
34
|
-
tabBarIcon: ({ color }) => <IconSymbol size={28} name='house.fill' color={color} />
|
|
35
|
-
}}
|
|
36
|
-
/>
|
|
37
|
-
<Tabs.Screen
|
|
38
|
-
name='posts'
|
|
39
|
-
options={{
|
|
40
|
-
title: 'Posts',
|
|
41
|
-
tabBarIcon: ({ color }) => <IconSymbol size={28} name='doc.text.fill' color={color} />
|
|
42
|
-
}}
|
|
43
|
-
/>
|
|
44
|
-
<Tabs.Screen
|
|
45
|
-
name='users'
|
|
46
|
-
options={{
|
|
47
|
-
title: 'Users',
|
|
48
|
-
tabBarIcon: ({ color }) => <IconSymbol size={28} name='person.2.fill' color={color} />
|
|
49
|
-
}}
|
|
50
|
-
/>
|
|
51
|
-
<Tabs.Screen
|
|
52
|
-
name='explore'
|
|
53
|
-
options={{
|
|
54
|
-
title: 'Explore',
|
|
55
|
-
tabBarIcon: ({ color }) => <IconSymbol size={28} name='paperplane.fill' color={color} />
|
|
56
|
-
}}
|
|
57
|
-
/>
|
|
58
|
-
</Tabs>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { Image } from 'expo-image';
|
|
2
|
-
import { Platform, StyleSheet } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { Collapsible } from '@/components/Collapsible';
|
|
5
|
-
import { ExternalLink } from '@/components/ExternalLink';
|
|
6
|
-
import ParallaxScrollView from '@/components/ParallaxScrollView';
|
|
7
|
-
import { ThemedText } from '@/components/ThemedText';
|
|
8
|
-
import { ThemedView } from '@/components/ThemedView';
|
|
9
|
-
import { IconSymbol } from '@/components/ui/IconSymbol';
|
|
10
|
-
|
|
11
|
-
export default function TabTwoScreen() {
|
|
12
|
-
return (
|
|
13
|
-
<ParallaxScrollView
|
|
14
|
-
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
|
|
15
|
-
headerImage={
|
|
16
|
-
<IconSymbol
|
|
17
|
-
size={310}
|
|
18
|
-
color="#808080"
|
|
19
|
-
name="chevron.left.forwardslash.chevron.right"
|
|
20
|
-
style={styles.headerImage}
|
|
21
|
-
/>
|
|
22
|
-
}>
|
|
23
|
-
<ThemedView style={styles.titleContainer}>
|
|
24
|
-
<ThemedText type="title">Explore</ThemedText>
|
|
25
|
-
</ThemedView>
|
|
26
|
-
<ThemedText>This app includes example code to help you get started.</ThemedText>
|
|
27
|
-
<Collapsible title="File-based routing">
|
|
28
|
-
<ThemedText>
|
|
29
|
-
This app has two screens:{' '}
|
|
30
|
-
<ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
|
|
31
|
-
<ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
|
|
32
|
-
</ThemedText>
|
|
33
|
-
<ThemedText>
|
|
34
|
-
The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
|
|
35
|
-
sets up the tab navigator.
|
|
36
|
-
</ThemedText>
|
|
37
|
-
<ExternalLink href="https://docs.expo.dev/router/introduction">
|
|
38
|
-
<ThemedText type="link">Learn more</ThemedText>
|
|
39
|
-
</ExternalLink>
|
|
40
|
-
</Collapsible>
|
|
41
|
-
<Collapsible title="Android, iOS, and web support">
|
|
42
|
-
<ThemedText>
|
|
43
|
-
You can open this project on Android, iOS, and the web. To open the web version, press{' '}
|
|
44
|
-
<ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
|
|
45
|
-
</ThemedText>
|
|
46
|
-
</Collapsible>
|
|
47
|
-
<Collapsible title="Images">
|
|
48
|
-
<ThemedText>
|
|
49
|
-
For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
|
|
50
|
-
<ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
|
|
51
|
-
different screen densities
|
|
52
|
-
</ThemedText>
|
|
53
|
-
<Image source={require('@/assets/images/react-logo.png')} style={{ alignSelf: 'center' }} />
|
|
54
|
-
<ExternalLink href="https://reactnative.dev/docs/images">
|
|
55
|
-
<ThemedText type="link">Learn more</ThemedText>
|
|
56
|
-
</ExternalLink>
|
|
57
|
-
</Collapsible>
|
|
58
|
-
<Collapsible title="Custom fonts">
|
|
59
|
-
<ThemedText>
|
|
60
|
-
Open <ThemedText type="defaultSemiBold">app/_layout.tsx</ThemedText> to see how to load{' '}
|
|
61
|
-
<ThemedText style={{ fontFamily: 'SpaceMono' }}>
|
|
62
|
-
custom fonts such as this one.
|
|
63
|
-
</ThemedText>
|
|
64
|
-
</ThemedText>
|
|
65
|
-
<ExternalLink href="https://docs.expo.dev/versions/latest/sdk/font">
|
|
66
|
-
<ThemedText type="link">Learn more</ThemedText>
|
|
67
|
-
</ExternalLink>
|
|
68
|
-
</Collapsible>
|
|
69
|
-
<Collapsible title="Light and dark mode components">
|
|
70
|
-
<ThemedText>
|
|
71
|
-
This template has light and dark mode support. The{' '}
|
|
72
|
-
<ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
|
|
73
|
-
what the user's current color scheme is, and so you can adjust UI colors accordingly.
|
|
74
|
-
</ThemedText>
|
|
75
|
-
<ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
|
|
76
|
-
<ThemedText type="link">Learn more</ThemedText>
|
|
77
|
-
</ExternalLink>
|
|
78
|
-
</Collapsible>
|
|
79
|
-
<Collapsible title="Animations">
|
|
80
|
-
<ThemedText>
|
|
81
|
-
This template includes an example of an animated component. The{' '}
|
|
82
|
-
<ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
|
|
83
|
-
the powerful <ThemedText type="defaultSemiBold">react-native-reanimated</ThemedText>{' '}
|
|
84
|
-
library to create a waving hand animation.
|
|
85
|
-
</ThemedText>
|
|
86
|
-
{Platform.select({
|
|
87
|
-
ios: (
|
|
88
|
-
<ThemedText>
|
|
89
|
-
The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
|
|
90
|
-
component provides a parallax effect for the header image.
|
|
91
|
-
</ThemedText>
|
|
92
|
-
),
|
|
93
|
-
})}
|
|
94
|
-
</Collapsible>
|
|
95
|
-
</ParallaxScrollView>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const styles = StyleSheet.create({
|
|
100
|
-
headerImage: {
|
|
101
|
-
color: '#808080',
|
|
102
|
-
bottom: -90,
|
|
103
|
-
left: -35,
|
|
104
|
-
position: 'absolute',
|
|
105
|
-
},
|
|
106
|
-
titleContainer: {
|
|
107
|
-
flexDirection: 'row',
|
|
108
|
-
gap: 8,
|
|
109
|
-
},
|
|
110
|
-
});
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { Image } from 'expo-image'
|
|
2
|
-
import { StyleSheet, TouchableOpacity } from 'react-native'
|
|
3
|
-
|
|
4
|
-
import { HelloWave } from '@/components/HelloWave'
|
|
5
|
-
import ParallaxScrollView from '@/components/ParallaxScrollView'
|
|
6
|
-
import { ThemedText } from '@/components/ThemedText'
|
|
7
|
-
import { ThemedView } from '@/components/ThemedView'
|
|
8
|
-
import { IconSymbol } from '@/components/ui/IconSymbol'
|
|
9
|
-
import { Colors } from '@/constants/Colors'
|
|
10
|
-
import { useColorScheme } from '@/hooks/useColorScheme'
|
|
11
|
-
|
|
12
|
-
export default function HomeScreen() {
|
|
13
|
-
const colorScheme = useColorScheme()
|
|
14
|
-
|
|
15
|
-
const handleNavigateToPosts = () => {
|
|
16
|
-
// Navigate to posts tab
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const handleNavigateToUsers = () => {
|
|
20
|
-
// Navigate to users tab
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<ParallaxScrollView
|
|
25
|
-
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
|
|
26
|
-
headerImage={<Image source={require('@/assets/images/partial-react-logo.png')} style={styles.reactLogo} />}
|
|
27
|
-
>
|
|
28
|
-
<ThemedView style={styles.titleContainer}>
|
|
29
|
-
<ThemedText type='title'>Welcome!</ThemedText>
|
|
30
|
-
<HelloWave />
|
|
31
|
-
</ThemedView>
|
|
32
|
-
|
|
33
|
-
<ThemedView style={styles.stepContainer}>
|
|
34
|
-
<ThemedText type='subtitle'>Enhanced Sample App</ThemedText>
|
|
35
|
-
<ThemedText>
|
|
36
|
-
This sample app now includes multiple pages, navigation, and API integration with JSONPlaceholder.
|
|
37
|
-
</ThemedText>
|
|
38
|
-
</ThemedView>
|
|
39
|
-
|
|
40
|
-
<ThemedView style={styles.featuresContainer}>
|
|
41
|
-
<ThemedText type='subtitle' style={styles.featuresTitle}>
|
|
42
|
-
Features
|
|
43
|
-
</ThemedText>
|
|
44
|
-
|
|
45
|
-
<TouchableOpacity style={styles.featureCard} onPress={handleNavigateToPosts} activeOpacity={0.7}>
|
|
46
|
-
<IconSymbol name='doc.text.fill' size={24} color={Colors[colorScheme ?? 'light'].tint} />
|
|
47
|
-
<ThemedView style={styles.featureContent}>
|
|
48
|
-
<ThemedText type='defaultSemiBold'>Posts</ThemedText>
|
|
49
|
-
<ThemedText style={styles.featureDescription}>Browse posts from JSONPlaceholder API with comments</ThemedText>
|
|
50
|
-
</ThemedView>
|
|
51
|
-
<IconSymbol name='chevron.right' size={16} color={Colors[colorScheme ?? 'light'].tint} />
|
|
52
|
-
</TouchableOpacity>
|
|
53
|
-
|
|
54
|
-
<TouchableOpacity style={styles.featureCard} onPress={handleNavigateToUsers} activeOpacity={0.7}>
|
|
55
|
-
<IconSymbol name='person.2.fill' size={24} color={Colors[colorScheme ?? 'light'].tint} />
|
|
56
|
-
<ThemedView style={styles.featureContent}>
|
|
57
|
-
<ThemedText type='defaultSemiBold'>Users</ThemedText>
|
|
58
|
-
<ThemedText style={styles.featureDescription}>View user profiles with their posts and details</ThemedText>
|
|
59
|
-
</ThemedView>
|
|
60
|
-
<IconSymbol name='chevron.right' size={16} color={Colors[colorScheme ?? 'light'].tint} />
|
|
61
|
-
</TouchableOpacity>
|
|
62
|
-
</ThemedView>
|
|
63
|
-
|
|
64
|
-
<ThemedView style={styles.stepContainer}>
|
|
65
|
-
<ThemedText type='subtitle'>Navigation</ThemedText>
|
|
66
|
-
<ThemedText>
|
|
67
|
-
Use the bottom tabs to navigate between different sections, or tap the feature cards above to explore the new
|
|
68
|
-
functionality.
|
|
69
|
-
</ThemedText>
|
|
70
|
-
</ThemedView>
|
|
71
|
-
|
|
72
|
-
<ThemedView style={styles.stepContainer}>
|
|
73
|
-
<ThemedText type='subtitle'>API Integration</ThemedText>
|
|
74
|
-
<ThemedText>
|
|
75
|
-
The app demonstrates real API calls to JSONPlaceholder with proper loading states, error handling, and data management.
|
|
76
|
-
</ThemedText>
|
|
77
|
-
</ThemedView>
|
|
78
|
-
</ParallaxScrollView>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const styles = StyleSheet.create({
|
|
83
|
-
titleContainer: {
|
|
84
|
-
flexDirection: 'row',
|
|
85
|
-
alignItems: 'center',
|
|
86
|
-
gap: 8
|
|
87
|
-
},
|
|
88
|
-
stepContainer: {
|
|
89
|
-
gap: 8,
|
|
90
|
-
marginBottom: 8
|
|
91
|
-
},
|
|
92
|
-
featuresContainer: {
|
|
93
|
-
marginBottom: 16
|
|
94
|
-
},
|
|
95
|
-
featuresTitle: {
|
|
96
|
-
marginBottom: 12
|
|
97
|
-
},
|
|
98
|
-
featureCard: {
|
|
99
|
-
flexDirection: 'row',
|
|
100
|
-
alignItems: 'center',
|
|
101
|
-
padding: 16,
|
|
102
|
-
marginBottom: 12,
|
|
103
|
-
borderRadius: 12,
|
|
104
|
-
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
105
|
-
borderWidth: 1,
|
|
106
|
-
borderColor: 'rgba(255, 255, 255, 0.2)'
|
|
107
|
-
},
|
|
108
|
-
featureContent: {
|
|
109
|
-
flex: 1,
|
|
110
|
-
marginLeft: 12,
|
|
111
|
-
marginRight: 12
|
|
112
|
-
},
|
|
113
|
-
featureDescription: {
|
|
114
|
-
fontSize: 14,
|
|
115
|
-
opacity: 0.7,
|
|
116
|
-
marginTop: 2
|
|
117
|
-
},
|
|
118
|
-
reactLogo: {
|
|
119
|
-
height: 178,
|
|
120
|
-
width: 290,
|
|
121
|
-
bottom: 0,
|
|
122
|
-
left: 0,
|
|
123
|
-
position: 'absolute'
|
|
124
|
-
}
|
|
125
|
-
})
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { FlatList, StyleSheet, TouchableOpacity, RefreshControl } from 'react-native'
|
|
3
|
-
import { router } from 'expo-router'
|
|
4
|
-
import { ThemedView } from '@/components/ThemedView'
|
|
5
|
-
import { ThemedText } from '@/components/ThemedText'
|
|
6
|
-
import { LoadingSpinner } from '@/components/LoadingSpinner'
|
|
7
|
-
import { ErrorView } from '@/components/ErrorView'
|
|
8
|
-
import { useApi } from '@/hooks/useApi'
|
|
9
|
-
import { apiService, Post } from '@/services/api'
|
|
10
|
-
|
|
11
|
-
export default function PostsScreen() {
|
|
12
|
-
const { data: posts, loading, error, refetch } = useApi(() => apiService.getPosts())
|
|
13
|
-
|
|
14
|
-
const handlePostPress = (post: Post) => {
|
|
15
|
-
router.push(`/post/${post.id}`)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const renderPost = ({ item }: { item: Post }) => (
|
|
19
|
-
<TouchableOpacity style={styles.postCard} onPress={() => handlePostPress(item)} activeOpacity={0.7}>
|
|
20
|
-
<ThemedText type='subtitle' style={styles.postTitle}>
|
|
21
|
-
{item.title}
|
|
22
|
-
</ThemedText>
|
|
23
|
-
<ThemedText style={styles.postBody} numberOfLines={3}>
|
|
24
|
-
{item.body}
|
|
25
|
-
</ThemedText>
|
|
26
|
-
<ThemedText style={styles.postMeta}>
|
|
27
|
-
Post ID: {item.id} • User ID: {item.userId}
|
|
28
|
-
</ThemedText>
|
|
29
|
-
</TouchableOpacity>
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
if (loading) {
|
|
33
|
-
return <LoadingSpinner message='Loading posts...' />
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (error) {
|
|
37
|
-
return <ErrorView message={error} onRetry={refetch} />
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<ThemedView style={styles.container}>
|
|
42
|
-
<ThemedView style={styles.header}>
|
|
43
|
-
<ThemedText type='title'>Posts</ThemedText>
|
|
44
|
-
<ThemedText style={styles.subtitle}>Latest posts from JSONPlaceholder API</ThemedText>
|
|
45
|
-
</ThemedView>
|
|
46
|
-
|
|
47
|
-
<FlatList
|
|
48
|
-
data={posts}
|
|
49
|
-
renderItem={renderPost}
|
|
50
|
-
keyExtractor={(item) => item.id.toString()}
|
|
51
|
-
contentContainerStyle={styles.listContainer}
|
|
52
|
-
refreshControl={<RefreshControl refreshing={loading} onRefresh={refetch} />}
|
|
53
|
-
showsVerticalScrollIndicator={false}
|
|
54
|
-
/>
|
|
55
|
-
</ThemedView>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const styles = StyleSheet.create({
|
|
60
|
-
container: {
|
|
61
|
-
flex: 1
|
|
62
|
-
},
|
|
63
|
-
header: {
|
|
64
|
-
padding: 20,
|
|
65
|
-
paddingTop: 60,
|
|
66
|
-
paddingBottom: 10
|
|
67
|
-
},
|
|
68
|
-
subtitle: {
|
|
69
|
-
marginTop: 4,
|
|
70
|
-
opacity: 0.7
|
|
71
|
-
},
|
|
72
|
-
listContainer: {
|
|
73
|
-
padding: 20,
|
|
74
|
-
paddingTop: 10
|
|
75
|
-
},
|
|
76
|
-
postCard: {
|
|
77
|
-
padding: 16,
|
|
78
|
-
marginBottom: 12,
|
|
79
|
-
borderRadius: 12,
|
|
80
|
-
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
81
|
-
borderWidth: 1,
|
|
82
|
-
borderColor: 'rgba(255, 255, 255, 0.2)'
|
|
83
|
-
},
|
|
84
|
-
postTitle: {
|
|
85
|
-
marginBottom: 8,
|
|
86
|
-
fontWeight: '600'
|
|
87
|
-
},
|
|
88
|
-
postBody: {
|
|
89
|
-
marginBottom: 12,
|
|
90
|
-
lineHeight: 20
|
|
91
|
-
},
|
|
92
|
-
postMeta: {
|
|
93
|
-
fontSize: 12,
|
|
94
|
-
opacity: 0.6
|
|
95
|
-
}
|
|
96
|
-
})
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { FlatList, StyleSheet, TouchableOpacity, RefreshControl } from 'react-native'
|
|
3
|
-
import { router } from 'expo-router'
|
|
4
|
-
import { ThemedView } from '@/components/ThemedView'
|
|
5
|
-
import { ThemedText } from '@/components/ThemedText'
|
|
6
|
-
import { LoadingSpinner } from '@/components/LoadingSpinner'
|
|
7
|
-
import { ErrorView } from '@/components/ErrorView'
|
|
8
|
-
import { IconSymbol } from '@/components/ui/IconSymbol'
|
|
9
|
-
import { useApi } from '@/hooks/useApi'
|
|
10
|
-
import { apiService, User } from '@/services/api'
|
|
11
|
-
import { Colors } from '@/constants/Colors'
|
|
12
|
-
import { useColorScheme } from '@/hooks/useColorScheme'
|
|
13
|
-
|
|
14
|
-
export default function UsersScreen() {
|
|
15
|
-
const { data: users, loading, error, refetch } = useApi(() => apiService.getUsers())
|
|
16
|
-
const colorScheme = useColorScheme()
|
|
17
|
-
|
|
18
|
-
const handleUserPress = (user: User) => {
|
|
19
|
-
router.push(`/user/${user.id}`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const renderUser = ({ item }: { item: User }) => (
|
|
23
|
-
<TouchableOpacity style={styles.userCard} onPress={() => handleUserPress(item)} activeOpacity={0.7}>
|
|
24
|
-
<ThemedView style={styles.userAvatar}>
|
|
25
|
-
<IconSymbol name='person.fill' size={24} color={Colors[colorScheme ?? 'light'].tint} />
|
|
26
|
-
</ThemedView>
|
|
27
|
-
|
|
28
|
-
<ThemedView style={styles.userInfo}>
|
|
29
|
-
<ThemedText type='subtitle' style={styles.userName}>
|
|
30
|
-
{item.name}
|
|
31
|
-
</ThemedText>
|
|
32
|
-
<ThemedText style={styles.userUsername}>@{item.username}</ThemedText>
|
|
33
|
-
<ThemedText style={styles.userEmail} numberOfLines={1}>
|
|
34
|
-
{item.email}
|
|
35
|
-
</ThemedText>
|
|
36
|
-
<ThemedText style={styles.userCompany}>{item.company.name}</ThemedText>
|
|
37
|
-
</ThemedView>
|
|
38
|
-
|
|
39
|
-
<IconSymbol name='chevron.right' size={16} color={Colors[colorScheme ?? 'light'].tint} style={styles.chevron} />
|
|
40
|
-
</TouchableOpacity>
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
if (loading) {
|
|
44
|
-
return <LoadingSpinner message='Loading users...' />
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (error) {
|
|
48
|
-
return <ErrorView message={error} onRetry={refetch} />
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<ThemedView style={styles.container}>
|
|
53
|
-
<ThemedView style={styles.header}>
|
|
54
|
-
<ThemedText type='title'>Users</ThemedText>
|
|
55
|
-
<ThemedText style={styles.subtitle}>Users from JSONPlaceholder API</ThemedText>
|
|
56
|
-
</ThemedView>
|
|
57
|
-
|
|
58
|
-
<FlatList
|
|
59
|
-
data={users}
|
|
60
|
-
renderItem={renderUser}
|
|
61
|
-
keyExtractor={(item) => item.id.toString()}
|
|
62
|
-
contentContainerStyle={styles.listContainer}
|
|
63
|
-
refreshControl={<RefreshControl refreshing={loading} onRefresh={refetch} />}
|
|
64
|
-
showsVerticalScrollIndicator={false}
|
|
65
|
-
/>
|
|
66
|
-
</ThemedView>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const styles = StyleSheet.create({
|
|
71
|
-
container: {
|
|
72
|
-
flex: 1
|
|
73
|
-
},
|
|
74
|
-
header: {
|
|
75
|
-
padding: 20,
|
|
76
|
-
paddingTop: 60,
|
|
77
|
-
paddingBottom: 10
|
|
78
|
-
},
|
|
79
|
-
subtitle: {
|
|
80
|
-
marginTop: 4,
|
|
81
|
-
opacity: 0.7
|
|
82
|
-
},
|
|
83
|
-
listContainer: {
|
|
84
|
-
padding: 20,
|
|
85
|
-
paddingTop: 10
|
|
86
|
-
},
|
|
87
|
-
userCard: {
|
|
88
|
-
flexDirection: 'row',
|
|
89
|
-
alignItems: 'center',
|
|
90
|
-
padding: 16,
|
|
91
|
-
marginBottom: 12,
|
|
92
|
-
borderRadius: 12,
|
|
93
|
-
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
94
|
-
borderWidth: 1,
|
|
95
|
-
borderColor: 'rgba(255, 255, 255, 0.2)'
|
|
96
|
-
},
|
|
97
|
-
userAvatar: {
|
|
98
|
-
width: 48,
|
|
99
|
-
height: 48,
|
|
100
|
-
borderRadius: 24,
|
|
101
|
-
backgroundColor: 'rgba(255, 255, 255, 0.2)',
|
|
102
|
-
justifyContent: 'center',
|
|
103
|
-
alignItems: 'center',
|
|
104
|
-
marginRight: 12
|
|
105
|
-
},
|
|
106
|
-
userInfo: {
|
|
107
|
-
flex: 1
|
|
108
|
-
},
|
|
109
|
-
userName: {
|
|
110
|
-
marginBottom: 2,
|
|
111
|
-
fontWeight: '600'
|
|
112
|
-
},
|
|
113
|
-
userUsername: {
|
|
114
|
-
fontSize: 14,
|
|
115
|
-
opacity: 0.7,
|
|
116
|
-
marginBottom: 4
|
|
117
|
-
},
|
|
118
|
-
userEmail: {
|
|
119
|
-
fontSize: 12,
|
|
120
|
-
opacity: 0.6,
|
|
121
|
-
marginBottom: 2
|
|
122
|
-
},
|
|
123
|
-
userCompany: {
|
|
124
|
-
fontSize: 12,
|
|
125
|
-
opacity: 0.8,
|
|
126
|
-
fontStyle: 'italic'
|
|
127
|
-
},
|
|
128
|
-
chevron: {
|
|
129
|
-
opacity: 0.5
|
|
130
|
-
}
|
|
131
|
-
})
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Link, Stack } from 'expo-router';
|
|
2
|
-
import { StyleSheet } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import { ThemedText } from '@/components/ThemedText';
|
|
5
|
-
import { ThemedView } from '@/components/ThemedView';
|
|
6
|
-
|
|
7
|
-
export default function NotFoundScreen() {
|
|
8
|
-
return (
|
|
9
|
-
<>
|
|
10
|
-
<Stack.Screen options={{ title: 'Oops!' }} />
|
|
11
|
-
<ThemedView style={styles.container}>
|
|
12
|
-
<ThemedText type="title">This screen does not exist.</ThemedText>
|
|
13
|
-
<Link href="/" style={styles.link}>
|
|
14
|
-
<ThemedText type="link">Go to home screen!</ThemedText>
|
|
15
|
-
</Link>
|
|
16
|
-
</ThemedView>
|
|
17
|
-
</>
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const styles = StyleSheet.create({
|
|
22
|
-
container: {
|
|
23
|
-
flex: 1,
|
|
24
|
-
alignItems: 'center',
|
|
25
|
-
justifyContent: 'center',
|
|
26
|
-
padding: 20,
|
|
27
|
-
},
|
|
28
|
-
link: {
|
|
29
|
-
marginTop: 15,
|
|
30
|
-
paddingVertical: 15,
|
|
31
|
-
},
|
|
32
|
-
});
|