In the previous article, I’ve finished part I about how to create an E-Commerce app using firebase services and the previous part included the Home page, Items, etc…
Now it’s time to deep dive into part II and start using the data, of course, no e-commerce app exists without users to buy, sell, and put items in the app that’s why the first thing I will start with is the user model which will include login functions and saving users data into my database.
I will create a file called User to use it as a model to hold the user’s data.
In the previous block of code, I have created variables for each user and each user must have an email and password for logging in and some other data like address, first name, last name, items he/she has purchased, etc…
Then I have initialized each user using
init() by giving these variables some values to be able to work on in the future.
As we learned before, I need to set a constant for each variable to be able to pass it to the dictionary while using this dictionary in firebase, that’s why I have used the below block of code to be able to set my constants.
Now to be able to use these variables and to be able to pass them to firebase, I need to create the same
init() as before but here I will do it passing a dictionary to this function.
In the previous block of code, I have achieved what I said before and now I have a dictionary initializer with some default values preventing me from having some errors.
After showing the variables I’m using in my model and my initializers, it is time now to show the functions that will be used in the user model
In the previous block of code, I have created two functions:
1- A function to return current user ID which I’m using a firebase built-in function to return it
2- A function to return the current user, I’m checking each time if the user exists or not and if the user exists, I’m getting it from my user defaults which is a place to save the data locally.
There are many ways to help the user login like using Email and password, Phone number, Facebook, Google, etc…
But how can I enable or disable these methods in firebase? You will follow some steps to be able to help users access your app and to enable the method you want as well, follow the images below:
I have chosen the smoothest way which is Email and Password and I have enabled the verification option as I need each user to verify the email to be able to log in to the app and ensure the other methods are documented in the second image. Don’t worry if you don’t know how to use these methods because I will make an article collecting these methods and shows you how to use each one of them.
After knowing the method, it is time to show some code about registering and logging out…
In the previous block of code, I have used two functions, one for registering a user using email and password and the second one for logging the user out…
1- The Register function is taking two parameters which are email and password and also taking an escaping completion which has an error to be returned if there is an error and if not, a verification email will be sent to the user’s email.
2- The Log out function is just taking an escaping completion which returns if there is one otherwise user will be removed from user defaults and will be logged out.
Still, save the user locally and using dictionaries and save the user to firebase but don’t do anything from all of these things that’s why I’m starting now by using the below:
In the previous block of code, I have used multiple functions starting with:
1- Function to transform the user into a dictionary to be able to use it, so the parameter will be an instance from User and it will return user dictionary.
Don’t forget: Firebase is dealing with dictionaries.
2- Function to be able to save user dictionary locally in user defaults and I’m passing a dictionary to save in a constant created before called
3- Function to be able to save the user to firebase and this function is taking a user instance as a parameter and then accessing collection reference for a user which is called
.User and using the general ID for the user and finally transform the user into a dictionary to be saved into firebase.
4- Function to be able to save the user to firebase fire store and it takes two parameters which are user email and user ID by using the same collection reference for the user as before but here I used user ID not general ID as I need each user to be saved individually. I’m getting a snapshot each time to check on it if it exists or not and if it exists I’m saving the user locally using the function created before otherwise I will create a new user instance and save it to firebase.
The previous functions need some editions on firebase to be able to access the database and save items in it so you will need to follow the below images to enable it and edit some rules…
After creating functions to be able to register, save the user to firebase, save the user to fire store, and log out but there is one thing left which is the login function…
As I said before, I’m logging in by using email and password that’s why they are the function parameters and passing closure with a boolean called email verified to check whether mail is verified or not and an error will be returned if there is an error but if not I will check if the email is verified or not and if it’s verified I will save it into my firebase fire store.
Now I will create a view controller called
LoginViewController.swift and all of these functions will be used in it, after making the suitable design with all the constraints, I will have my view controller which contains a welcome label, text fields, buttons, check the image below:
Let’s start coding in
In the previous block of code, I’ve created the file with some outlets connected to the view and imported some of the pods that will be used like progress HUD and activity indicator, and creating their variables to be able to use them like what I did in view did load function.
No one can log in or register with empty fields and of course, I can’t show activity indicator without removing it that’s why I have created some functions to support me instead of repeating the same code many times.
The previous block of code has a function to help the user to dismiss the current view and getting back to the previous view also it has a function that preventing the user from login or register with empty fields so the function is checking the fields and return boolean and the final two functions are used to show and hide activity indicator as If it’s only shown without being dismissed or hidden it will be an issue for the user and of course at each time I’m checking on it as it can’t be nil.
Now I will start using login and register functions starting by register as the user needs to register first to be able to log in…
As I said before, I have to check on the text fields first to make sure that I don’t have any empty text fields. Then the activity indicator will be shown and I will call the function register from the user model that will show the user message in all cases using progress HUD pod but the message depends on having an error or not and in all cases, activity indicator will be removed as the user can continue navigating the app and after that, I will use my login function:
In the login function, I’m doing the same as register but the only difference here is that I’m using an extra case which is checking if the user’s email is verified or not, and if not the user will see a message that directs him to verify his mail.
Finally, the last thing to do in this view controller is to connect the actions of the buttons as I did before in outlets and call the functions I’ve created before in these actions and these actions are documented here:
The question now is: I have created so many variables but I didn’t use them and I have used only the user email so when and how will I use the rest? The answer simply is that I won’t let the user be able to add items to the cart if the user didn’t complete his profile. By completing his profile I mean that the user needs to enter all of these values to be able to add items to his/her cart but this means that the user will update his profile not save it as I did before so I need to create a new function in the user model to be able to update the user data at every time he updates or changes any value in his/her profile.
Now the function can be used and that’s why I will create a new view controller called
FinishProfileViewController.Swift and of course, I have created its view controller in the storyboard and after adding the suitable constraints it will be like the image below:
Of course, all text fields are mandatory and as in the image done button will be grey if all the text fields or only one of them is empty, let’s create some code:
In the previous code, I have imported the used pods and connected the outlets and the new thing here is that I have added a function for each text field called add target to be able to check after each change in these text fields to decide when to enable or disable done button and the function used in this add target
textFieldDidChanged will be mentioned later.
In the previous block of code, I have used the
textFieldDidChanged function and inside it I have called another function which is used to update button status and it’s almost close to the function I used before to check if the text fields are empty or not but the only difference here that this one is changing the button color and its status.
One thing left is creating a function to use to update user in fire store function in it:
In the previous block of code, I have used the function created before which called
UpdateUserInFS()and used the text in my text fields as values for the dictionary and show a message for the user in all cases even if it’s a success or an error message.
Hold a moment, How can I finish the registration view? To answer such a question I created a new table view controller called
ProfileTableViewController.swift which has some buttons in cells to be able to access these views, check the image below:
This is one of the tab bar controllers and as you can see it has two connections that are navigated to one for a purchased list and the second one for edit profile and both will be created, finish registration view controller is reached using push in a navigation controller, get help and about won’t be created as they can be images or text and they are so simple and note that this is a static table view not dynamic, let’s create its code:
In the previous block of code, I have created the table view controller then connected the outlets for the buttons I will use, and created a bar button item variable, I have set the footer for the table view to avoid extra empty cells in it finally I have created two functions needed to be called at each time the view is called and these two functions will be declared but first I need to create the bar button item functions:
The first function is to create the bar button item with specific color and title and in this function, I have called its action called
loginEditAction which is the second function and in this one I’m checking each time whether the title for the button is Login or Edit and I’m calling a specific function which is one of the two functions declared after that and the first one is
showLoginView which is created just to show the login view but if the user already logged in I will use the second one which is
showEditView using segue as I have done it before and this segue will connect my table view controller with the new controller which I will create and called
EditProfileViewController.swift which is almost the same as the finish registration view but the difference here that I have the logout button instead of the done button but I won’t go into it now as I will discuss it later and the most important thing is to set the design and constraints for it for now and check the segue identifier, this image will explain more:
Now I have used two functions before but I still didn’t create them:
Before creating these two functions, I’m sure that I have only four cells with four buttons and that’s why I have returned four in the table view method. My two functions created are:
checkBarButtonStatus – The function is used to check if the user is logged in or not and depends on it to create the right bar button item with the suitable title and color.
checkCurrentStatus– Before talking about the function, there is something that needs to be clear which is the button titles are changeable depending on the user status which means that if the user has logged in and finished his profile then the button title will be “Account is active” and if he didn’t finish his profile this button title will be “Finish Registration” and if the user logged out it will be “Logged Out” and this is describing how the function is working and the colors are up to you, one thing left in this controller is to activate the action of finish registration:
In the previous function, I just checked the button title and created an instance from the controller to be able to show it.
As I have mentioned
EditProfileViewController.swift and showed its design, I think it is time to work on its code:
I have created the file with the pod imported and the outlets of the text fields then created a function called
loadDataToUI() to check if the user is saved locally. I will put his/her data into the text fields and I have called this function in my view did load function.
I will continue the code and don’t freak out if you find huge amount of lines, it’s easy and smooth…
I have created an empty check function as I did it before to return a boolean, if any text field is empty or not then I created another function called
saveUpdatedData() to save the updated data and it seems the function used before in finish registration. So here I’m checking if the is a text field or not and if not I will create
withValues dictionary with user constants and the values in the text fields after that, I will use this dictionary to be saved using the function created before in the user model called
updateUserInFS() and as usual in all cases, I will show the user a message with success or failure using my progress HUD pod, the last function is
t() and I have called the logout function from the user model and poped the view.
Don’t forget that all of these functions are being called in the actions of the buttons.
Once the user has registered, logged in and he/she is now able to add items for selling, there is something left which is the cart and its methods and that’s why I’ve created a bar button item in
ItemDetailsViewController.swift to be used to add this item to the cart
This button code will be declared but after creating the cart model and design and as usual. I will start by adding cart constants as I did before in other models
After adding these constants, I can use them now in my cart model so I will create a file called
Cart.swift to be able to work on:
I have created the class, its variables, and its initializers but the first one is empty and the second one using the dictionary and as usual, the final function is to transform the cart instance into a dictionary to be usable in firebase, let’s add the rest of the functions for the cart model:
The first function is the same as I used before in user, category, and item models but here I’m getting the cart collection reference which called
.Cart and using its ID to be saved and don’t forget to transform it into a dictionary to be saved successfully, the second function is about updating tec cart and it seems like the function used before to update the user and I’m taking the values passed in the function and then use them to update the cart and the last function is to download the cart items to be viewed in the cart view (“Will be created later”) and of course, each user has its cart that’s why the cart will be used by each user ID using the constant
ConstantOwnerID and as I did before I will get the snapshot and check if it is empty or not and if not I will create a new cart and get it in the escaping completion.
After finishing the model I will go directly to the design and note that the cart is a main view controller for the tab bar:
Before i start working on
CartViewController.swift , I will make the action for the bar button item created to add the item into the cart in
I have added two functions, the first one is for adding an item into the cart by creating an instance from the cart and adding the item ID only into the cart and the second one is to update the cart if the cart was already existing by calling the function created before in cart model which called
updateCartInFS()and passes the values in the dictionary. There are two functions left which are documented below:
In the previous code, I have created a function to present me the login view once it is called and in the second one I’m calling the action for the button created and at each time I’m checking if the user is logged in or not, if not I will call the
showLoginView() function and if the user is logged in I will check if he has items in the cart before or not by calling the function created in the cart model which called
downloadCartFromFS(), if not I will add the item, if there is a cart I will update it using the function created before which called
updateCart(), now I can start writing
In the previous code, I have added the pods that will be used and created the needed variables, and in the
viewDidLoad() function I have connected the cell to the table view and set the footer as well, I have created a function to update the labels at each time, another function to check out, and a function to return the total price and in its body. I will use the same function I have used before which called
At each time I’m using the
updateLabels() function, I will give either true or false and dependent on its parameter will set the values and colors for the labels and at the end. I’m calling
checkOutStatus() which is used to check the button status and changes the color and the status dependent on the case which is about the number of items in the cart and I have also used a function called
returnTotalPrice() which is responsible for returning the total price including the tax and the delivery fees and you can change these fees as you want and finally I’m calling the action for the button and checking if the user completed his/her profile or not and if not he/she will have a message and if yes he/she will be directed to a new method which called
finishPayment()which will be declared with other methods:
In the previous block of code, I’m using a function to empty the cart and the array of the items as well and update the labels and finally update the cart in the firebase as well and using another function to add the items to the purchased list by adding the item ID to the array of items’ IDs and then update the user in firebase and I’m using most of the previous functions in the bodyviewDidAppear of
finishPayment() to show the user the payment options, now I have some cart functions needed to be declared as they are already used and called in
I’m using a function to get specific cart items by using function
downloadSpecificItems() (Will be explained later) and set these items to my variable
allItems and in the other function, I’m using it to load all cart items and called the function created before which called
getAllCartItems() to be able to load the specific items which are only for this user, then I have created a function to enable me to remove any item from the cart and this function will be used late in table view methods and at the end, I have given the user the option to be able to open the item details from the cart view controller by using the last function called
Now there is one thing left before going to table view methods which are seeing and understanding the code of
This function is created to be able to download specific items like cart items or searched items “Will be explained later” and this function takes an array of items’ IDs and returns an escaping closure items array and as usual I’m using the item collection reference which called . Item and check on the snapshot to be able to return the items array in the completion, Let’s finish the cart view controller by doing the last thing which is table view methods:
The first thing is to know how many cells will be returned and it’s obvious that I’m using the same
allItems array which is used before the cart functions and since I’m using the same cell for the item I called its attributes and returned the cell and here the usage of
showItemDetails() function which is called in the
didSelectRowAt() function and finally the function is used to delete a cell or an item from the cart. All I have done in this function is using the function I have created before which called
removeItemFromCart() then update the cart in firebase.
In this view controller, I have mentioned two things, the first thing is the payment which will not be involved within this article, and the second thing the purchased Items list which I have created its design to be the same as the Items list like the image below:
Of course, I will use the same custom item cell which used before in both cart and item view controllers, I have created
In this controller, I have connected my outlets as usual and registered the cell and the footer then used a function called
loadPurchasedItems()in which I used the function created before to download specific items and then used table view methods to return the array count and shows the cell attributes and now the last thing to do to finish the application is to create the search controller which is based on algolia service that’s why I have added my constants:
I knew that I set all of the constants to empty string as these data is private and can’t be shared with anyone but I will say how can you got them from the image below:
Then I have created a file called
I have imported the pod used for the search and created my client and index and searched by
ItemName attribute, then created the design for
Note that the view in the top which contains the search button and text field is changeable and can be hidden or not once you click on the search icon on the top right, let’s dig more in its code and see how to animate it
As usual, I started by importing the pods to be used in my controller, creating my variables, setting the footer for the table view, and registered the cell but the extra thing here is that I have added the empty data set delegate and source and added the target to the text field as I did before. Finally, I set the activity indicator in my
viewDidAppear() and now I will create some functions and two of them are mentioned below:
The first function shows and hides the view within a specific period of time and if the view was shown, it will be hidden to the opposite. Then the check text field function which used before in the target of the text field and its body I’m calling another function to update the search button which checks if the text field is empty or not and dependent on it. I’m changing the color and the status of the button and disable and empty text field functions. Before continuing in the code for the controller I need to add the main search functions in item model to be able to use them:
In these functions, to be able to search in Algolia, you need to save the item in it so I will save the item into Algolia using the index, then I can search in it using the text which is in the text field and returning the items’ IDs containing this string and use a query to search with item name and item price (“You can add whatever you want”) and each time I will add the object ID to the array and return the completion of the array of IDs, back to
Now I can use the search function and that’s why I have created it to be able to call the function created before in it and return all items and reload the table view to be able to show it. The second function shows item details and I have used it before many times. Only two things left to finish the app , the first one is to call the actions of the buttons and the second thing is to use table view methods and empty data set methods, starting by the actions:
I have only used the functions created before in the correct sequence to avoid any errors and now only table view methods and empty data set methods:
I have called the counter for the searched items and used the function to return the cell which is the same cell I used before in cart, item, etc…
As before, I’m using the show details function in didSelectRowAt() in the empty data set as I used it before(I used the data). I want it to be shown in the controller even if it’s an image or a text or both but the only difference here is that I have added another function to call the action for the button using
Now everything is done and the app is ready for use, Have a nice programming day…
Thanks for reading️! Help spread the word & wait for the coming articles 📝 …
Do you have questions, suggestions, comments, or ideas for upcoming blog posts? Contact me on LinkedIn or write a comment! You can also follow me on GitHub & check my Stackoverflow answers and questions.