Skip to content

Commit d93ba8c

Browse files
committed
feat(test/docs/ci): add ci/cd pipeline and deployment & enhance testing docs
1 parent 3f7bdcf commit d93ba8c

9 files changed

Lines changed: 1389 additions & 89 deletions

File tree

.idea/caches/deviceStreaming.xml

Lines changed: 835 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/deviceManager.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# TaskNexus - Task Manager React Native App 📱
22

3+
**Time to get organized!** TaskNexus is a modern, cross-platform task management app built with React Native, Expo, and TypeScript. It allows users to efficiently manage their daily tasks with features like task addition, completion, deletion, drag-and-drop reordering, and interactive statistics visualization.
4+
35
<p align="center">
46
<!-- Core -->
57
<img src="https://img.shields.io/badge/React_Native-red?style=for-the-badge&logo=react&logoColor=white" alt="React Native" />
@@ -128,20 +130,35 @@ I hope its name and branding convey a sense of connectivity and organization, wi
128130
<img src="img/android.gif" alt="Task Manager App - Android" width="47%" style="border-radius: 10px;">
129131
</p>
130132

133+
> [!IMPORTANT]
134+
> The above GIFs and images may not fully represent the app's current state, as they were recorded during development. The app has since been updated with new features and improvements. Please clone the repository and run the app to see the latest version in action!
135+
131136
## Features
132137

133138
### Task Management
134139

135140
- **Add, Update & Delete Tasks:** Easily manage your daily tasks through an interactive interface.
136141
- **Drag-and-Drop Reordering:** Rearrange tasks using a smooth, touch-friendly drag-and-drop mechanism.
137142
- **Global State Management:** Uses React Context to manage task state across the app for consistent data handling.
143+
- **Task Completion Toggle:** Mark tasks as complete or incomplete with a simple checkbox interaction.
144+
- **Task Deletion:** Remove tasks with a dedicated delete action, ensuring a clean task list.
145+
146+
### Cloud Synchronization
147+
148+
- **Supabase Integration:** Utilizes Supabase for real-time data synchronization, ensuring tasks are always up-to-date across devices.
149+
- **User Authentication:** Supports user authentication with Supabase, allowing users to securely manage their tasks.
150+
- **Automatic Realtime Synchronization:** Changes made to tasks are instantly reflected across all devices, providing a seamless user experience.
151+
- **PostgreSQL Database:** Stores tasks in a PostgreSQL database, providing robust data management and querying capabilities.
152+
- **Backup Option:** Includes a Ruby on Rails backend as an optional backup for task management, ensuring data persistence and reliability.
153+
- **Manual Refresh:** Users can manually refresh the task list if they wish to ensure they have the latest data from the server.
138154

139155
### Statistics Visualization
140156

141157
- **Pie Chart:** Visualizes the ratio of completed vs. incomplete tasks.
142158
- **Bar Chart:** Compares overdue and upcoming tasks with wider, closely spaced bars.
143159
- **Line Chart:** Plots tasks over time (by month), ensuring continuity even if only a single month is available.
144160
- **Transparent & Themed Charts:** All charts feature transparent backgrounds and adjust seamlessly to the current theme.
161+
- **Immediate Data Updates:** Charts update in real-time as tasks are added, completed, or deleted.
145162

146163
### Theme & UI
147164

@@ -175,6 +192,14 @@ TaskNexus is built using a modern tech stack that includes both core and third-p
175192
- **React Native Reanimated:** Powers animations and transitions for a fluid user experience.
176193
- **React Native Safe Area:** Ensures proper layout and spacing on devices with notches or rounded corners.
177194

195+
### **Backend & Data:**
196+
197+
- **Supabase:** Provides real-time database, authentication, and storage services.
198+
- **PostgreSQL:** The underlying database for storing tasks and user data.
199+
- **Ruby on Rails (Optional):** A backup backend for task management, providing an alternative data persistence layer.
200+
- **Docker:** Containerization for the Ruby backend, allowing easy deployment and management.
201+
- **AWS:** Used for hosting the Ruby backend and managing cloud resources.
202+
178203
### **Third-Party Dependencies:**
179204

180205
- **Expo:** Provides a robust development workflow and build process.
@@ -186,12 +211,15 @@ TaskNexus is built using a modern tech stack that includes both core and third-p
186211
- **React Native Draggable FlatList:** Enables drag-and-drop reordering of tasks.
187212
- **React Native DateTime Picker:** Provides a user-friendly date and time selection interface.
188213
- **Prettier:** Maintains code quality and consistent formatting.
214+
- **Docker:** Containerizes the React Native app for easier deployment and testing.
189215

190216
### **Other:**
191217

218+
- **Jest & React Testing Library:** For unit and integration testing of components and functionality.
192219
- **JSDoc & TypeScript Definitions:** Documented code for better understanding and type safety.
193220
- **Google Fonts:** Includes custom Google fonts (Roboto) and images for branding.
194221
- **Shell Scripts:** Simplify common tasks with custom shell scripts.
222+
- **GitHub Actions:** CI/CD pipeline for automated testing and deployment.
195223

196224
## Installation & Setup
197225

@@ -203,8 +231,18 @@ TaskNexus is built using a modern tech stack that includes both core and third-p
203231
```bash
204232
npm install -g expo-cli
205233
```
206-
- Android/iOS Emulator or Physical Device: For testing on mobile platforms.
234+
- **Android/iOS Emulator or Physical Device:** For testing on mobile platforms.
207235
- This is required for testing the app on Android/iOS devices. Alternatively, you can use the web version for a quick preview.
236+
- **Supabase Account:** For cloud synchronization and user authentication.
237+
- Sign up for a free account at [Supabase](https://supabase.io/) and create a new project.
238+
- Set up the PostgreSQL database and configure the necessary tables for tasks.
239+
- Create a `.env` file in the root directory of the project with your Supabase credentials:
240+
```
241+
EXPO_PUBLIC_SUPABASE_URL=your_supabase_url
242+
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
243+
```
244+
- **Docker (Optional):** For containerization and running the app in a Docker environment.
245+
- If you want to run the app in a Docker container, ensure that Docker is installed and running on your system.
208246
209247
### Clone the Repository
210248
@@ -290,12 +328,21 @@ Task-Manager-ReactNative
290328
├── .gitignore # Git ignore file
291329
├── Dockerfile # Dockerfile for containerization
292330
├── docker-compose.yml # Docker Compose file for containerization
331+
├── jest.config.js # Jest configuration for testing
332+
├── babel.config.js # Babel configuration for transpiling code
333+
├── jest.setup.js # Jest setup file for testing
334+
├── .env # Environment variables for Supabase credentials
335+
├── .github
336+
│ └── workflows
337+
│ └── ci.yml # GitHub Actions CI/CD workflow configuration
293338
├── app
294339
│ ├── _layout.tsx # Main layout with theme, navigation, and context providers
295340
│ ├── index.tsx # Flash screen and redirection to home screen
296341
│ ├── +not-found.tsx # Custom Not Found screen for undefined routes
297342
│ └── (tabs)
298343
│ ├── _layout.tsx # Layout for tabbed screens
344+
│ ├── register.tsx # Registration screen for user authentication
345+
│ ├── login.tsx # Login screen for user authentication
299346
│ ├── home.tsx # Home screen for task management
300347
│ └── stats.tsx # Stats screen for displaying charts and statistics
301348
├── components
@@ -310,29 +357,50 @@ Task-Manager-ReactNative
310357
│ └── TaskContext.tsx # React Context for global task state management
311358
├── hooks
312359
│ └── usePrevious.ts # Custom hook to capture previous state values
360+
├── lib
361+
│ └── supabaseClient.ts # Supabase client configuration for database interactions
313362
├── scripts
314363
│ └── reset-project.js # Script to reset project state (if needed)
315364
├── styles
316365
│ ├── HomeScreenStyles.ts # Custom styles for the Home screen
317366
│ ├── StatsScreenStyles.ts # Custom styles for the Stats screen
318367
│ ├── IndexStyles.ts # Custom styles for the Flash screen and redirection
319368
│ ├── LayoutStyles.ts # Custom styles for the main layout
320-
│ ├── TaskModalStyles.ts # Custom styles for the task add modal
369+
│ ├── TaskModalStyles.ts # Custom styles for the task add modal
321370
│ ├── TaskItemStyles.ts # Custom styles for individual task items
322371
│ ├── NotFoundStyles.ts # Custom styles for the Not Found screen
323372
│ └── CustomTabStyles.ts # Custom styles for the tab bar and related UI components
373+
├── ruby # Ruby backend for backup task management (optional)
374+
│ ├── Gemfile # Ruby dependencies for the backup Rails backend
375+
│ ├── app.rb # Main Ruby API application file
376+
│ ├── config.ru # Rack configuration file for the Ruby app
377+
│ ├── app/ # Ruby app directory
378+
│ │ ├── controllers/ # Ruby app controllers directory
379+
│ │ ├── models/ # Ruby app models directory
380+
│ ├── config/ # Ruby app configuration directory
381+
│ ├── initializers/ # Ruby app initializers directory
324382
├── types
325383
│ └── types.ts # TypeScript type definitions for the project
326384
├── assets
327385
│ ├── fonts # Custom fonts for the app (Roboto)
328386
│ └── images # Images used in the app
387+
├── aws # AWS configuration files
388+
│ ├── main.tf # Terraform configuration for AWS resources
389+
│ ├── variables.tf # Variables for AWS configuration
390+
│ ├── outputs.tf # Outputs for AWS configuration
391+
│ └── lambda
392+
│ └── handler.js # Lambda function handler for AWS
393+
├── __tests__ # Test files for the project
394+
├── __mocks__ # Mock files for testing
329395
├── img # Screenshots and GIFs for the README
330396
└── shell # Shell scripts for common tasks
331397
├── run-platform.sh # Script to run the app on a specific platform
332398
├── format.sh # Script to format the project code
333399
├── start.sh # Script to start the app
334400
├── reset.sh # Script to reset the project state
335401
└── update.sh # Script to update project dependencies
402+
403+
(...and more files not listed here...)
336404
```
337405

338406
## Scripts & Tools
@@ -358,11 +426,14 @@ Task-Manager-ReactNative
358426

359427
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
360428

429+
> [!CAUTION]
430+
> This project is for educational purposes only and is not intended for production use. It is a personal project to demonstrate my skills in React Native, Expo, and TypeScript. Please be sure to credit the original author if you use any part of this code in your own projects, regardless of use case.
431+
361432
## Contact
362433

363434
For any questions, feedback, or suggestions, please contact:
364435

365-
- **Name:** Son Nguyen
436+
- **Name:** [Son Nguyen](https://sonnguyenhoang.com)
366437
- **Email:** [hoangson091104@gmail.com](mailto:hoangson091104@gmail.com)
367438
- **GitHub:** [@hoangsonww](https://github.com/hoangsonww)
368439

app/(tabs)/home.tsx

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -155,37 +155,63 @@ function HomeScreen() {
155155
Add Task
156156
</Button>
157157

158-
<DraggableFlatList
159-
data={tasks}
160-
keyExtractor={(item) => item.id.toString()}
161-
renderItem={({ item, drag, isActive }) => (
162-
<ScaleDecorator>
163-
<Animated.View
164-
style={[{ overflow: "visible", zIndex: isActive ? 9999 : 0 }]}
165-
entering={SlideInDown}
166-
exiting={SlideOutUp}
167-
layout={Layout.springify()}
168-
>
169-
<TaskItem
170-
task={item}
171-
onToggleComplete={toggleTask}
172-
onDelete={deleteTask}
173-
drag={drag}
174-
onEdit={handleEditTask}
175-
/>
176-
</Animated.View>
177-
</ScaleDecorator>
178-
)}
179-
onDragEnd={onDragEnd}
180-
dragItemOverflow={true}
181-
removeClippedSubviews={false}
182-
style={{ overflow: "visible" }}
183-
contentContainerStyle={{
184-
flexGrow: 1,
185-
overflow: "visible",
186-
marginTop: 16,
187-
}}
188-
/>
158+
{/* If there are no tasks yet, invite the user to add one */}
159+
{tasks.length === 0 ? (
160+
<View
161+
style={{
162+
flex: 1,
163+
alignItems: "center",
164+
justifyContent: "center",
165+
padding: 24,
166+
}}
167+
>
168+
<Text
169+
style={{
170+
color: colors.onBackground,
171+
fontSize: 16,
172+
textAlign: "center",
173+
}}
174+
>
175+
You have no tasks yet!{"\n"}Tap "Add Task" above to create your
176+
first task.
177+
</Text>
178+
</View>
179+
) : (
180+
<DraggableFlatList
181+
data={tasks}
182+
keyExtractor={(item) => item.id.toString()}
183+
renderItem={({ item, drag, isActive }) => (
184+
<ScaleDecorator>
185+
<Animated.View
186+
style={{
187+
overflow: "visible",
188+
zIndex: isActive ? 9999 : 0,
189+
}}
190+
entering={SlideInDown}
191+
exiting={SlideOutUp}
192+
layout={Layout.springify()}
193+
>
194+
<TaskItem
195+
task={item}
196+
onToggleComplete={toggleTask}
197+
onDelete={deleteTask}
198+
drag={drag}
199+
onEdit={handleEditTask}
200+
/>
201+
</Animated.View>
202+
</ScaleDecorator>
203+
)}
204+
onDragEnd={onDragEnd}
205+
dragItemOverflow={true}
206+
removeClippedSubviews={false}
207+
style={{ overflow: "visible" }}
208+
contentContainerStyle={{
209+
flexGrow: 1,
210+
overflow: "visible",
211+
marginTop: 16,
212+
}}
213+
/>
214+
)}
189215

190216
<TaskAddModal
191217
visible={modalVisible}

components/CustomTabBar.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,15 @@ export default function CustomTabBar(props: BottomTabBarProps) {
2525
const { colors } = useTheme();
2626
const { colorSchemeOverride, setColorSchemeOverride } =
2727
useContext(ThemeOverrideContext);
28-
const { user, signOut } = useContext(TaskContext);
28+
const { user, signOut, fetchTasks } = useContext(TaskContext);
2929

3030
// Animate background transitions
3131
const prevSurface = usePrevious(colors.surface) || colors.surface;
32-
33-
// Shared value for animation progress
3432
const progress = useSharedValue(1);
35-
36-
// Animate progress when colors.surface changes with duration 200ms
3733
useEffect(() => {
3834
progress.value = 0;
3935
progress.value = withTiming(1, { duration: 200 });
4036
}, [colors.surface]);
41-
42-
// Animated style that interpolates between the previous and current background color
4337
const animatedStyle = useAnimatedStyle(() => {
4438
const bg = interpolateColor(
4539
progress.value,
@@ -56,6 +50,21 @@ export default function CustomTabBar(props: BottomTabBarProps) {
5650
setColorSchemeOverride(colorSchemeOverride === "dark" ? "light" : "dark");
5751
};
5852

53+
/**
54+
* handleReload now just re-fetches tasks
55+
*/
56+
const handleReload = async () => {
57+
try {
58+
await fetchTasks();
59+
} catch (e: any) {
60+
const err =
61+
e.message ||
62+
"An error occurred - Could not refresh tasks. Please try again.";
63+
if (Platform.OS === "android") ToastAndroid.show(err, ToastAndroid.LONG);
64+
else Alert.alert("Error", err);
65+
}
66+
};
67+
5968
/**
6069
* renderTab function renders a single tab button
6170
*
@@ -106,14 +115,24 @@ export default function CustomTabBar(props: BottomTabBarProps) {
106115
{renderTab("stats", "stats-chart", 1)}
107116

108117
{user ? (
109-
// If signed in: show logout icon
110-
<TouchableOpacity
111-
onPress={handleLogout}
112-
style={styles.tabButton}
113-
activeOpacity={0.8}
114-
>
115-
<Ionicons name="log-out" size={24} color={colors.onBackground} />
116-
</TouchableOpacity>
118+
// If signed in: show reload + logout icons
119+
<>
120+
<TouchableOpacity
121+
onPress={handleReload}
122+
style={styles.tabButton}
123+
activeOpacity={0.8}
124+
>
125+
<Ionicons name="reload" size={24} color={colors.onBackground} />
126+
</TouchableOpacity>
127+
128+
<TouchableOpacity
129+
onPress={handleLogout}
130+
style={styles.tabButton}
131+
activeOpacity={0.8}
132+
>
133+
<Ionicons name="log-out" size={24} color={colors.onBackground} />
134+
</TouchableOpacity>
135+
</>
117136
) : (
118137
// If not signed in: ALWAYS show sign-in and register
119138
<>

0 commit comments

Comments
 (0)