A simple CRUD app displaying a user's contacts.
The default dashboard for the app looks like the following:
To create a contact, click the create contact button:
To view or edit a contact, click the row corresponding to that contact:
You can toggle light mode using the lightbulb button on the top right:
You can toggle minified mode using the bar button on the top right:
If not logged in, the user is prompted to do so:
Storage of contact data is handled through FireStore and contact objects, whereas editing is handled through the buffer.
The storage for the entire application is the following:
users
- user1
- contacts
- ...
- displayName
- email
- emailVerified
- photoURL
- userID
- ...
Contacts are stored as an array of Contact objects, and each object has the following structure:
export interface Contact {
birthday: string
email: string
lastContact: string
name: string
phone: string
picture: string
}
The buffer is a locally-stored Contact that contains the information of the currently edited contact. When a new Contact is being created, the buffer is blank. A user edits the buffer through the Add/Edit Contact modal, and upon submit, the buffer is sent to the FireStore.
Vuex stores relevant data from FireStore and globally accessible UI properties for this project, with the following namespaced modules:
-
Index: This stores general states that the user is in
- Dialog: Toggles whether to open and overlay the contact modal
- Editing mode: Toggles whether the contact modal's UI should display text for editing or creating a new contact
- Contacts: The contacts of the users, stored as an array of contact objects
- VuexFire bindings: VuexFire mutations create a one-way binding from a user's contacts on Firestore with the contacts in this Vuex store. More elaborated in the Vuexfire section
-
Auth: This stores a user's login status and credentials
- signedIn: The user is signed in, used to change elements of UI
- signingIn: Whether the user is signed in
- userCredentials: Stores user email, name, profile picture, user ID pulled from Firebase Auth
-
Buffer: This stores information of the currently edited contact, which is displayed when the modal is opened. Before the modal opens, it is autopopulated when a contact is clicked, and cleared when the "Add Contact" is clicked.
Vuexfire is used to set a real-time one way binding from a user's contacts on Firestore to their contacts in Vuex. Therefore, Firestore is the source of truth over Vuex for user contacts.
When adding and editing contacts, the changes are written to Firestore directly, which are then automatically pulled and updated into the Vuex store, which subsequently updates the application.
You may encounter the mapFields plugin, which is used to simplify a two-way data-binding with a form. This is used to synchronize the modal values with the values stored in the buffer module of the Vuex store
- Clone this repo to your local machine
- Add a .env file to the root with the following variables
FIREBASE_API_KEY
FIREBASE_AUTH_DOMAIN
FIREBASE_PROJECT_ID
FIREBASE_STORAGE_BUCKET
FIREBASE_MESSAGING_SENDER_ID
FIREBASE_APP_ID
FIREBASE_MEASUREMENT_ID
# install dependencies
$ npm install
# serve with hot reload at localhost:3000
$ npm run dev
# generate static project, for hosting on CDN/serverless platforms like Netlify
$ npm run generate
# serve using statically generated project
$ npm run start
-
Unique Contact ID's
- Currently, contact names are used as the document names in Firestore.
- Because of this, changing a contact's name creates a new contact rather than editing that contact directly
- Creating a unique id per each contact would help avoid overwriting contacts when there is name collision.
-
Make certain fields required
-
Logout button/Proper Logout handling
- Currently, logging in with other accounts temporarily displays residual information from the last account, because there is no proper logout handling
- Create a button that triggers the logout function in Firebase auth. You can respond to the logout detected state in auth.js. Make sure to clear the Vuex store.
-
Persistent login
- The login state of Vuex does not last after a refresh or close/open.
- Make the Vuex persist, perhaps through writing to cookies or storing a JWT token
-
Profile Upload (with Firebase storage)
- Hook up Firebase storage so profile pictures are uploaded, then store the url with the rest of the buffer into the contact
-
Change data types
- Dates and phone numbers are currently stored as strings; changing these to the appropriate types could be useful.