How I Developed MyCrohnicles

Svadrut Krishnamurthy
6 min readMay 26, 2023

--

In the past few months, I developed an app with my sister Udhirna Krishnamurthy and my cousin Shravan Rajagopal. We named the app as MyCrohnicles — a digital tracker app designed to assist people with Inflammatory Bowel Disease (IBD), but it can also be used by anyone. IBD is a collective term that refers to Crohn’s disease and Ulcerative colitis inflammatory conditions that affect millions worldwide.

When choosing the technology stack, I had two options in mind: Flutter (which I had prior experience with) and React Native (I had experience only with React). I ultimately opted for React Native (Expo) because I hadn’t used Flutter recently.

One of the first decisions I made was to use Tailwind CSS for styling. However, since the regular Tailwind CSS package doesn’t work with React Native, I found an alternative called twrnc. Additionally, I needed a navigation package, and after some research, I discovered that @react-navigation/native was the most popular choice for React Native navigation.

During the development process, I realized I needed a database and an authentication provider. At the time, Firebase seemed like the easiest option since it worked seamlessly. Instead of using the react-native-firebase package, I used the default Firebase package in the app to avoid complications with Expo’s bare workflow. I encountered multiple issues with Firebase SDK version 9 and I had to downgrade to version 8.

I must admit that using JavaScript instead of TypeScript was a mistake. Initially, I intended to experiment with Expo and then transition to TypeScript. However, once I incorporated Firebase, I neglected adding TypeScript. Over time, I realized the benefits of type safety and auto-completion provided by TypeScript, especially since the Firebase package lacked proper auto-completion and types.

For authentication in the application, I implemented email, Google, and Apple authentication mechanisms. First, I focused on email authentication. I created custom signup and personal info pages, where users would enter their name, email, password, confirm password, as well as weight, height, and date of birth. To ensure email uniqueness during account creation, I had to create Cloud Functions through Firebase, which took some time.

Next, I focused on implementing Google authentication. Initially, I tried using an outdated Google Sign package from Expo, which required transitioning to a bare workflow. When I realized that the Google Sign package was deprecated, I switched to the new expo-auth package with the Google provider. I integrated this with the Firebase Google provider.

Then I focused on implementing Apple authentication, utilizing the expo-auth package for seamless integration. While working with Apple auth, I discovered the requirement of employing their exclusive button. Fortunately, the expo-auth package natively includes the Apple button functionality. Additionally, Firebase offers an Apple provider, further enhancing the authentication aspect of the application.

import {
AppleAuthenticationButton,
AppleAuthenticationButtonStyle,
AppleAuthenticationButtonType,
} from "expo-apple-authentication";
// helpers use expo-auth package internally
import { useAppleSignin } from "../../helpers/useAppleSignin";
import { useGoogleSignin } from "../../helpers/useGoogleSignin";

// ...

{/* Google Button */}
<TouchableOpacity
style={}
onPress={async () => {
// promptAsync from expo-auth google provider
await promptAsync({ useProxy: true });
}}
>
{/* Apple Button */}
{Platform.OS === "ios" && <AppleAuthenticationButton
buttonType={AppleAuthenticationButtonType.SIGN_IN}
buttonStyle={AppleAuthenticationButtonStyle.WHITE_OUTLINE}
cornerRadius={4}
onPress={appleOnPress}
style={{ width: 200, height: 46.9 }}
/>}

The app revolves around three main parts: Food, Bowel Movement (BM), and Exercise. Since the app calculates the average of these three components, I needed a pie chart to display the overall rating. Fortunately, I discovered a package called react-native-svg-charts, which included a ProgressCircle component that mimicked the activity rings on the Apple Watch. For the ring’s color, we created a gradient from dark red to bright green, with the color gradually shifting to more green with each 10% interval.

<ProgressCircle
style={{ height: 250, width: 250 }}
progress={getRating()}
progressColor={color}
strokeWidth={20}
/>

Once I found the package, I began working on the code for each part. The Food section consisted of four parts: breakfast, lunch, dinner, and snack. For these screens, I wanted to provide a selection process where users could input the consumed item and rate it out of ten. Instead of repeatedly typing regular food items, I implemented a modal using the react-native-modal package and a picker with the @react-native-picker/picker package. The modal contained a picker with default food items and an option to add custom food items. After selecting “done” in the modal, users would return to the page, where the chosen food item and a text input for rating would appear.

import Modal from "react-native-modal";
import { Picker } from "@react-native-picker/picker";

// ...

<Modal
isVisible={}
onModalHide={}
>
<Text
style={}
>
Options
</Text>
{/* Custom picker using the @react-native-picker/picker package */}
<BreakfastPicker
value={food}
setValue={setFood}
width={width}
items={items}
/>
</Modal>

Although the design was straightforward, fetching the data for the current day posed some challenges. In hindsight, creating a collection for each user would have simplified the data fetching process (which is what I did for the BM and Exercise pages).

To fetch the data, I utilized the regular useEffect hook. Since the data didn’t change, I didn’t require the useFocusEffect hook from react-navigation, which refetches data when the page is reopened. I also needed to create a list of the user’s previously used items for reuse, so I implemented data fetching for that as well. To achieve this, I had to find a way to identify the submission date and display the corresponding data on the main page. I utilized Firestore’s built-in where function and checked if the date field matched today’s date. Once identified, I set the state values to the correct snapshot.

For the picker lists, I created a document with collections for each meal type. Within each picker collection, I added documents with the user’s email as the ID. If no list existed, I provided a default list. If a list was available, I updated the pickerList state with the data from Firestore. I followed this pattern for all the food screens.

The next screen I developed was the Exercise screen. The goal was to enable users to add multiple exercises throughout the day. Clicking the “Add new” button would navigate to a new screen with a form where users could select an exercise (using the previously developed modal). They could specify the duration and provide a rating for the exercise. To save the exercises, I created a new collection called “exercise” and, within it, a document for users, each user having their own collection. Each user’s collection contained a collection of exercise documents, and each exercise document included a date field. After leaving the input screen, I used the useEffect hook to retrieve items from the user’s collection where the date matched today’s date. The summaryList state was then set to the necessary fields for display. To show all items, I utilized the map function to create a new View component for each item, which displayed the exercise type, rating, and duration.

Finally, we have the BM (bowel movement) screen. This screen featured two inputs: the number of bowel movements and their rating. It was relatively easy to implement since it involved storing two numerical values. Unlike the exercise page, I could use the date as the document ID. If a document’s ID matched today’s date, I populated the numberOfBms and ratingOfBms state with the corresponding values from Firestore.

In the end, I calculated the average of the three components and displayed it on the ProgressCircle component, as mentioned earlier.

In future, our goal is to incorporate machine learning to make it so that AI can give feedback to users about their diet and exercises.

You can download MyCrohnicles from the AppStore and the Play Store.

You can learn more about the design and the conceptualization of the app from these two blogs:

--

--