Minderva / Project

A Language Learning Tool Built with React and Firebase

Minderva is a language learning app that uses translation, text-to-speech and flashcards to help language learners collect and review vocabulary. This is a short review of the app and the tech stack I used to create it.

Live Site | Github

minderva_screen_01.webp

Introduction

While learning Japanese I wanted a tool that would allow for quick translation of words and phrases, provide accurate pronunciation and also allow me to save those translations for later review. It's out of this idea that Minderva was born. I first did some experiments with vanilla Javascript before developing the tool finally in React with a Firebase Backend.

The tech stack

React: Using this library I could quickly organize the project into components and focus on their singular functionality. I built it off a create-react-app installation that I then later customized.

Firebase Platform:

  • Cloud Firestore: A NoSQL database that uses JSON documents to store data. For the minimal amount of data I wanted to hold I thought this was a perfect fit.

  • OAuth2: Firebase made the management and authentication of users somewhat painless.

  • Google Cloud Functions: The cloud functions make communicating with other Google services very straight forward. Since your account is linked within Firebase you can bypass many API authentication headaches. I also use Cloud Functions to create a default user profile whenever a new user signs up.

  • Google Translate and Text-to-Speech: The cloud functions handle getting translations from the Google Translate API, and then passing that translation to the Google Text-to-Speech API, which creates an mp3 file that is then saved to storage. This allows for quick pronunciation retrieval when a user is reviewing their saved translations.

minderva_screen_03.webp

Chakra UI: Chakra UI is a component library for React that puts accessibility first. It provided an excellent foundation for the user interface. It allows for theming, and it's nicely customizable. I really wanted to focus on the UX of the app, making its functions and actions clear, and Chakra UI helped immensely.

My Development Process

I started very basic, with no styling or other concerns and just worked on getting logic working. For instance for my very first version, I just wanted to get the most basic elements working CRUD working on sample data. This is an example of my MVP:

  • The user can explore their card collection
  • The user can add cards
  • The user can delete cards
  • The user can edit cards
  • The user can quiz themselves their cards

And from there I would add piece by piece the functionality I wanted to achieve. Starting with backend concerns and then moving to frontend implementation. Obviously, the project grew in complexity, and had to be split into separate concerns, ie, UX/UI, backend, bugs. Github was used extensively throughout the project for version control and bug tracking.

Overall this working process served me well and allowed me to complete the project in a short amount of time.

Unique Challenges

Learning how to wield React and state management were the first real challenges. I decided to go all in on React Hooks and I'm glad I did. I found the code much less cluttered than with Class based components, and there was no functionality missed. Getting my head around certain concepts, like useEffect, took awhile, but after many applications I see the power of them.

For instance, here's how I randomize the cards for the Quiz section of the site:

1// Function to shuffle the cards
2const shuffleCards = (cards) =>
3  cards
4    .map((a) => ({ sort: Math.random(), value: a }))
5    .sort((a, b) => a.sort - b.sort)
6    .map((a) => a.value);
7
8// On loading the quiz, create a quiz object that shuffles the cards by an order number
9useEffect(() => {
10  const quizData = () => {
11    const cards = cardCollection.map((card, index) => {
12      return { order: index, ...card };
13    });
14    return shuffleCards(cards);
15  };
16
17  setQuizCards(quizData());
18}, [cardCollection, quizReset]);

And here's what the user sees. Just the cards, randomized on each quiz reload.

minderva_screen_02.webp

In conclusion

Overall I'm happy with the functionality of the app. I would love to take it further and inject it with more personality and some concepts that I've discovered from my research into language learning. So, it's a project that will stay on my radar and grow. 頑張ったね!

Portrait of Dwaine Best