Habit Tracker is my final project for CS50's Introduction to Computer Science Course. What can I say, Habit Tracker keeps track of your habits 🎆 👌 🎉
A short video (2 minutes in length) where I present the project.
- create an account with using email and password
- authenticate using Facebook, GitHub or Google
- login as a guest
- add, edit and delete habits
- mark the habits as
completed
,failed
orskipped
- weekly performance is visualized in a bar chart
- brief summary of performance for last week, current week, current day and all time
- customize the app by changing
primary
andsecondary
color - toggle dark mode
- choose your language:
ES | EN | PL
- React
- React Query
- React Router
- React Hook Form
- Material UI
- Firebase
- Authentication
- Realtime Database
- Landing Page
- Sign up using Facebook, GitHub, Google or create a new account using your email address.
- Create new habit
- Manage your habits - preview, edit or delete your habits
- Keep track of your habits in the Dashboard
- Change your settings
- Customize the app the way you want
Below you'll find the instructions for setting up the project locally and a walkthrough video, where I'm following these instructions.
# Clone the repo
git clone https://github.com/sitek94/habit-tracker-app.git
# Install dependencies
cd habit-tracker-app
yarn
While you’re waiting for the dependencies to install, you can set up the Firebase.
-
Login to Firebase
-
Create project
-
Create Realtime Database
- In step 2, check “Start in test mode”
-
Authentication > Sign-in method > Sign-in providers, and add the following:
- Email/Password
- Anonymous
- (Optional): If you want to add Facebook and/or GitHub, you’ll have to get Client IDs and secrets from these services
-
Go to Project Overview and add a web app
-
You don’t need to run
npm install firebase
, it’s already installed -
You should see a
firebaseConfig
similar to this:const firebaseConfig = { apiKey: "<YOUR_API_KEY>", authDomain: "<YOUR_AUTH_DOMAIN>", databaseURL: "<YOUR_DATABASE_URL>", projectId: "<YOUR_PROJECT_ID>", storageBucket: "<YOUR_STORAGE_BUCKET>", messagingSenderId: "<YOUR_MESSAGING_SENDER_ID>", appId: "<YOUR_APP_ID>", measurementId: "<YOUR_MEASUREMENT_ID>", };
-
Create
.env.local
file, by duplicating.env.local.example
, and use config above to fill it out
# Start development server
yarn start
The app should be running at: http://localhost:3000
I learned a lot while building the project and for sure I'm going to learn a lot more while maintaining it. That's why I want to keep track of the challenges that I've had along the way so that I can reference them in the future.
How should I store habit's completion state for each day? Should each habit have an array with the dates when it was performed or should I store dates and each date would keep track of the habits that where performed on that day?
I tried to structure the data so that it is saved and retrieved as easily as possible. To do so I've been following Firebase guidelines and in the end came up with the following data structure:
{
"habits": {
"user-one": {
"habit-one": {
"name": "Reading",
"description": "Read a book for at least 30 min in the morning",
"frequency": [0,1,2,3,4]
}
}
},
"checkmarks": {
"user-one": {
"checkmark-id": {
"habitId": "habit-one",
"date": "2020-11-11",
"value": "completed"
}
}
},
"users": {
"user-one": {
"locale": {
"code": "en-GB"
},
"theme": {
"primaryColor": "blue",
"secondaryColor": "red",
"dark": true
},
"performanceGoal": 80
}
}
}
For quite some time I was using Private and Public routes to prevent an authenticated user from accessing the parts of the app available only for logged in user. It was fine, but I wanted to use a different layout for authenticated users (additional sidebar on the left).
I found the perfect solution in a blog post by Kent C. Dodds:
function App() {
const user = useUser();
return user ? <AuthenticatedApp /> : <UnauthenticatedApp />;
}
I've never before implemented this in an app, and I really wanted to give it a try. My main goal was to give the user an option to change their locale and language. Although this goal was achieved, the solution is far from ideal. First, I think that it would be better to split these two layers. For example in YouTube one can open settings and change either Language or Location.
This project was bootstrapped with Create React App.
For the detailed description of available scripts see CRA Documentation