Giter VIP home page Giter VIP logo

quibill-ionic's People

Contributors

b-oltman avatar tloltman avatar tzaddiko avatar

Watchers

 avatar

quibill-ionic's Issues

Add a checkbox to the recurring-deposit page to specify an entry as the primary income

Since we want to display the next pay date, we need to have a primary income to base this on. For now we just need to have the constructor in the recurring-transaction page look at the parameter passed in to see if the page is a deposit. (It seems bad to have to just check the whole string passed in, but I guess that's fine for now unless you want to change that up a little). Anyways, if it is a deposit the class should have some boolean var to indicate this.

Using that boolean var you can look into angular's *ngIf attribute to see how to show/hide the element based on the value of the boolean.

You can just label the checkbox: "Mark as primary income" or whatever you think sounds good. We'll worry about actually making the checkbox do something later.

Update Ionic storage module/Add sqlite cordova plugin

This ionic storage is what's used for storing more permanent data on the device. Basically it has a priority of different ways to store data, and goes through each one to see if the device supports it, then chooses that as the method of storing data, which is pretty cool. Pretty much all devices support sqlite databases, so we'll want to use that.

Follow these instructions to update the @ionic/storage module. Note: for us where those instructions say "instead of import { IonicStorage } from '@ionic/storage'" it would actually be "instead of import { Storage } from '@ionic/storage'".

Then you can look at this guide to install the cordova plugin for sqlite and see how to use it in our services/pages (the usage in services/pages doesn't change from how it was before). I'm pretty sure once you install the sqlite plugin, ionic storage will automatically use that.

We're going to start using this to store user data, but that'll be another issue

Implement typescript interfaces for login response data

We should use this process when possible from now on to define the data we get back from the server. For now we'll just implement it for the login method:

  • In authentication-service.ts:
    Underneath the AuthService class define a typescript interface called LoginResponse or something.
    Add properties to the interface that correspond to this test response I got using fiddler:
    image

Note for the .expires and .issued properties we can't just use those names since they have periods, but you can name javascript properties using quoted strings so for example:
interface LoginResponse {
'.expires': string,
...
}

I think for the sake of consistency then we should just name all the properties in the interface with quotes. We probably won't ever use most of the properties in this response, but we'll just include them all anyways.

You will then need to set the Observable return type by changing
getToken(username: string, password: string): Observable<any>
to
getToken(username: string, password: string): Observable<LoginResponse>

  • In login.ts
    Nothing will actually change here, that's all we need to set up, but to see how this method helps go to the login method where you access the response data with data.access_token. Before we would have had to send the test request with fiddler then look at the reponse to see that the access_token was the name of the property we wanted, so now if you erase the data.access_token then just type data. you will see visual studio lists all the possible properties held by the data object, and you can see your access_token property.

Also notice that if you use the . syntax to access a property (as in data.someProperty) you won't get the intellisense for the interface properties that have bad name formatting (like .expires etc..). So just in case we ever need to access one of these properties you would use the data['.expires'] syntax to access them.

Withdrawal and Deposit buttons should open the "New With./Dep." page

There's only a single Ionic "page" for both the New Withdrawal and New Deposit Page. We will use the Ionic navPush along with a parameter (just a string) which specifies if the page should represent a new withdrawal or deposit.

We don't need to add any functionality to the withdrawal/deposit page besides maybe having the cancel button close (pop) the page when it's clicked. Just make the two buttons on the "home" page push the withdrawal/deposit pages with the correct parameter so that the title shows "New Withdrawal" or "New Deposit" accordingly.

Add Basic Front End Validation for Login page

We should probably add another validation check on the front end, that way the user won't have to submit an HTTP post in order to find out they don't have the correct information in the forms.

Add transactions page

Should be based on the image, I added the actual page files to the develop branch, but the content needs to be added. The page also should be opened when the "View All Transaction" button is pressed on the home page.

The "All Withdrawal Deposit" tabs should be clickable, but they don't need to do anything yet.
The <ion-segment seems like the perfect candidate for this.

quibill-transactions

Buttons on home page should open recurring-transaction pages

This is basically the exact same issue as the last one you did. Just make sure when you're creating a new branch on github that 'develop' is the currently selected one so you get the most updated code. The recurring-transaction page and recurring withdrawal/deposit buttons are already set up, so just like before all you should have to do is set up an angular (click) to push the page with the correct parameter to pass to the title.

Also I have the variable that stores the transaction type string that goes in the set up slightly differently than you did so you might have to fix the recurring-transacton.html value to work with the system you had.

Choose a color scheme

modify the color variables in the $colors map in src/theme/variables.scss to whatever you think looks good. These colors are what Ionic (and sometimes our css) uses for UI components. I think you'll do a much better job than I could with this. You can add/remove/change any of these colors depending on what you need.
quibill_scss_variables

Add css to make the transactions page pretty

We can try to go through how this all works when we get together next. It looks like we'll mostly just be changing the spacing/size of certain things. We might also want to think about putting the search bar as part of the header and other stuff..

Add a "how much can I spend?" page

Issue to be expanded. To develop a page that will quickly display to the user how much extra cash they can safely spend before their next paycheck. It should take into account how much cash they need for bills between each pay-period.

Fix login/registration error formatting

For now this can still be pretty similar to what's already there, but we'll just want to make it more user-friendly.

There's a few different formats that the error data could come back in which were included in the example I used to set up the original ajax login on the server side. Look in the Quibill.Web/Scripts/login.js under the showError function. The 'error' object you get back in the angular http request will be the same as this 'response' var in the showError function.

In this showError function you can see there are a couple different properties that are checked to see if they hold errors. I'm pretty sure that error_description will always be there for the login errors, whereas that ModelState property will always have the errors from the registration. So knowing that, it might be easiest to separate the error handling between the login and registration so that the login page just looks for that error_description value and the registration page would have to iterate through the ModelState properties like as shown in the showError function. Note that the 'appendError' method in the showError function could basically be replaced by just adding the error string to the page's error array like we've been doing..

Another small change is that we want previous errors that no longer apply to be cleared from the page when the user submits. This is as easy as clearing (setting equal to an empty array) the page's errors array property at the beginning of the login/registerUser methods.

You'll also need to move the '.input-errors ion-item {...}' css entry from the login.scss to src/app/app.scss so that the error styles are applied globally.

Refine the login/registration process

  • So first things first, when the user opens the app we're going to want to check if they're logged in. If they aren't, we want to show the login page, if they are we want to show the home page.

This functionality can be set up using the constructor in the app.component.ts file. This typescript file is basically what sets up the whole app when it starts. Inside the constructor (after the initializeApp method is called) we can use our AuthService to check if the user is logged in. We'll then set the rootPage property of the MyApp class to either the HomePage or the LoginPage depending on logged in check. That should be enough to give us the functionality.

I think it would be best to add a little method to the AuthService class called 'userLoggedIn' or something that simply returns a boolean stating whether the authtoken property is empty or not.

Honestly this functionality doesn't make much sense at the moment because we just store the authtoken in temporary storage so every time we close the app it goes away. This means every time we open the app we'll have to log in, but we'll shortly change the authService to store the token in a sqlite database so that this will all make more sense.

  • The next thing to do is to simply have the login page open the home page when the user successfully logs in. Instead of just pushing the home page, though, we'll want to make sure we set it as the root page.

  • Finally we're going to want the registration page automatically log the user in if the registration is successful. (The Home page should open as well). It's okay if the login and registration page have some duplicated code for now because we can always go fix it later if we need to..

Create AppSettings

Inside the src folder create a simple typescript file named app-settings.ts

In this file all you'll do is export a const javascript object named AppSettings. For now this constant object will only have a single property, the 'serverUrl' or whatever you want to call it. I'm sure you can remember/find what the value of this property should be.

To test the AppSettings just go into one of the services or pages, then in the typescript file add an import for the object like: import { AppSettings } from '../app-settings';
You can then access the object from anywhere in your class like: AppSettings.serverUrl etc..

You'll want to change the _myServerRoot value in the authentication-service to the value of this new AppSetting.

Then whenever you want to change the value just edit the app-settings.ts file and the new value should be updated while you're running your 'ionic serve'.

We'll be adding more settings to this as the project goes on.

Remove http request from Logout

This really makes no sense to have because we just logout by clearing the OAuth token. We don't want more http requests than we need to, and having this there also couples our app to the MVC part (if a user logs out using this http request from the mobile app, they would also be logged out of the web site if signed in at the same time. We don't want that..)

All we should have in the AuthService logout method is clearing the token.

Store user data using ionic/storage

  • Add a property to appSettings to store the string key we'll use to store/access the userData in ionic storage, then add a property to hold that value inside authService.

  • Add a method to AuthService called loadUserFromStorage or something. It has no params, and returns a Promise<any>. This will use @ionic/storage to get the userdata object from permanent storage. If it is successful the method will set the userId property to the gotten value, and call the resolve function, or reject if it doesn't get it successfully. (This is probably the most confusion part of this issue, use this guide as a helper, notice you'll be responding to two different promises: ready(), and get() inside this method)

  • Add a method to the AuthService called saveUserToStorage or something. It takes in our LoginResponse interface type as a parameter and builds a UserData from the param. It then uses @ionic/storage set() with the key from our appSettings to store that UserData object. If the set() promise resolves, we'll also want to set the userId property to the UserData object.

  • Notice you can probably get rid of the setUserData method (There's a chance we'll use it eventually, but I'm not sure..)

  • Finally in our app.component constructor you'll want to call the loadUserFromStorage method from the authService, then if it resolves, use the nav.setroot to switch to the homepage. If it rejects you can just log something to the console for now or whatever, but the Login Page should already be set as teh default so you don't need to worry about it too much. You'll want to get rid of the check if user is logged in part).

Add login functionality

So I updated the Quibill-ionic project so you should be able to clone it into visual studio, run 'npm install', then run 'ionic serve' to run the project.

I added a simple login page that doesn't do anything so your next task will be to set up the login functionality. The sample login page in the backend project should give you a good idea of how to do this (look at the login.js file in the Quibill.Web/Scripts folder).

You'll have to add a button to the ionic login page, then tie the button to the login() method in the login.ts script. That method will use an ajax request to post the username/password data to the server. The server should respond by sending a token which you can store in javascript sessionStorage. We might want to alter how the token is stored eventually. If the login was successful the app should use the navcontroller setroot to the 'Home' page. That will be enough work for this issue I think.

Within the login.ts there's also an array property to hold any login errors. This property should be model-binded to the login.html page under the specified <ion-list using the angular *ngFor technique (a good example is on the all-transactions.html page). The backend login sample shows most of how you will extract the errors from the ajax response, but angular will make things even easier since you can just use the errors.push() method to push any new errors into the array property instead of using jquery to add new elements to the page.

It will probably take some time to get back into all the ionic stuff (it did for me) and this might be a tricky task so let me know if you have any questions or need clarification!

Add the "new withdrawal/deposit" pages

We need a different page for singular and recurring withdrawal/deposits.

Since these are so similar they can be done at the same time. I think the best way to do this is to have a single template for singular withdrawal/deposit and another single template for recurring withdrawal/deposits. Then we can use parameters or something to differentiate between whether the user wants to make a withdrawal or a deposit.

Store username along with token for login

We'll want the user to be able to see the email they're logged in with, so I think the easiest solution would be instead of just storing the auth token string when we get the login response, we set up a small class to hold both that token and the username/email we get with the response.

So.. We'll need to put this new class somewhere. It could either be in it's own file (I'm not really sure what folder it would go in because it's not really a page and not really a service..) So you can make a new folder and name it whatever you want, then add this UserData typescript file which is a simple class. OR we can just add the class to the authservice file itself. It's a small class so this might be the easiest way to do it, but you can choose whichever you'd like.

The class will simply have two properties, one to store a username and one to store a token. You'll want to add a constructor that sets the two properties as well.

Then you'll want to change the private authToken property in the authservice accordingly and add a setUserData and getUserData (or something) method to the authservice. I think the easiest way to have the setter work is to have it take in a single parameter of the ILoginResponse type, then create a new instance of your new class and store that in the authservice's property that you changed.

We also won't be able to check/set the prop to an empty string if the user is logged out, but I think the best way to set this up is to use the 'undefined' value to denote an empty object (Note: in javascript objects can be sort of treated like booleans. They're either considered "truthy" or "falsy". There are different conditions under which an object is truthy or falsy that you could look up, but I know for sure if an object is undefined it's falsy). So all this means is that when you check if user is logged in you can just say something like if(property){ ... } Which basically means "if property is defined".

THEN You'll just need to change the login and registration pages to use the new set method and just pass in the whole 'data' object.

Once you get this working we should add some way to display the username when the user logs in. We can always change the way we do this, but for now I think we can just have the username/email displayed in the footer of the home page. (You can put it wherever you want if you have a better idea)

Change the transaction pages to use <ion-datetime> element for date picker

This should be done to the single-transaction in the Date input, and the recurring-transaction in the Start Date input, not the recurrence input yet.

For now we can just allow the date (month/day/year), we'll probably have to allow specific times eventually too. The element has attributes to determine what date values can be chosen and displayed. There will have to be a field on the class in the ts file for angular to store this value.

Add a transaction provider (service) to deal with new transactions

A service (ionic calls them providers) is simply a typescript file that carries out certain activities which need to be performed by multiple ionic pages in the project. Making it a service allows the app to store just a single instance of the file which can be accessed by any other page once it's imported. It also allows us to store one set of data (in this case all our transactions) and share that data between our pages.

We'll use this same service to create new single withdrawal/deposits as well as recurring withdrawal/deposits. The service will have methods such as addSingleWithdrawal and addRecurringDeposit etc.. which can be called from the corresponding ionic pages when the user submits data for a new transaction. These methods will take in the user's input as parameters and use them to build a new transaction object. Eventually we'll end up sending these transaction to be stored in the server, but for now We'll save them using ionic's native storage which will keep them in memory unless the user erases the app's data.

Add registration functionality

Add a new register method to the authentication-service file that takes in three string params: email, password, and confirm password and returns an observable. This method should post the params to the server's /api/account/register method and will be a lot like the getToken method.

Add a new ionic page called register. In register.ts add three properties to hold the params, import the AuthService and add a param for it to the constructor. Add a register method that calls the register method in the AuthService class and passes in the three properties. If the registration is successful you can just have the registration page pop back to the login page for now and we'll change it to automatically log in later. In register.html add three input elements for the three inputs and use angular model binding to bind them to the properties in the .ts file. Then add a "register" or "submit" button and bind the click event to the register method.

In login.ts add a method that simply pushes the registration page. In login.html add a link or button that says something like "Sign Up", and bind the button to the method in the .ts file.

Move logout button to the side menu

This should be pretty straightforward, but I was messing around a little and ran into an issue that took me a long time to figure out.. Basically I disabled the sidemenu in the login page and never had it re-enabled in the home page so we'll want to fix that.

To fix it we'll just need to set up an event handler for one of the ionic lifecycle events which they made very convenient. We'll want to do this in the home.ts file. First you need to import the ionic MenuController class and add it as a constructor param just like in our login.ts file. Then all you do is create a method called ionViewDidEnter and inside it you set the MenuController's enable property to true. If you look in the consctructor of the login.ts file you can see that the exact opposite is done so you can just follow that, but we'll actually want to move that from the constructor to the ionViewDidEnter method in the login.ts file as well. (I think the method is already defined in there it just logs some useless info). Setting up these lifecycle event handlers just ensures that every time either page is opened the menu is enabled/disabled properly.

The side menu is all set up in the app.html and app.component.ts files. If you look in the app.html the
ion-menu is pretty much the only thing there. Currently the menu sets up a list of pages and allows the user to navigate through those pages, but we don't really want that functionality at the moment.

So what you'll need to do is just have a single button inside the ion-list contained in the ion-menu's ion-content element. It will just have the text 'Logout' shown on it, and be bound to a click event called logout() or whatever you want.

Then in the app.component.ts files you'll implement that logout method by doing the same thing you currently have in the logout button on the Login page. Instead of just showing an alert, we'll want to use the this.nav to set the root back to the login page.

Add create single transaction functionality

Now that we have the single transaction functionality set up we can add create transaction to the ionic app.

This should be pretty straightforward with all that we've set up so far. These will be the steps:
In transaction-service.ts:

  • Import the modules we need to use (we'll need Http, Headers, RequestOptions from angular, Observable from rxjs, our AppSettings for the server url, and AuthService).
  • Add a private property to hold the server Url just like we had in AuthService
  • Add an http, and authService param to the constructor
  • Add a return type to the addSingleTransaction method of Observable so we can subscribe to it
  • Change the addSingleTransaction method to post data to the server

This is the biggest change you'll make. All we need to do is build the typescript object that represents a singletransaction, then add the data from the parameters. Then post the data to the server using the angular http. I realized I left the "Note" property out of the transaction classes in the server domain models (oops..) You can either create/finish that issue on your own or we can deal with it later. I think you'll want to define a typescript class to represent this SingleTransaction like we did with the UserData. The only properties we'll want to include are the amount, note, transactionDate (not AddDate), and the type. Look in the shared/UserData.ts for how to set up this class. Then in the addSingleTransaction method of the transaction-service you just create a new SingleTransaction object using the constructor to inject the parameter values passed in. Then you can follow the AuthService getToken() method to remember the process of posting data.
The differences here are:

  1. The Content-Type header value will be application/json
  2. You need to add another header called Authorization with a value of 'Bearer currentUserToken' where the current user token is gotten from the authService.
  3. The url for the http.post will be the server root + '/api/Transactions'
  4. The data you're posting will be a JSON.stringified version of the SingleTransaction object you created
  5. This post won't really return any data so we should just be able to leave out the .map part of the request and have the .catch do the Observable.throw like we do in the authService.

In single-transaction.ts:

  • Once you have the addSingleTransaction method set up you will call it from the single-transaction.ts file when the user submits a transaction (either deposit or withdrawal.
  • So import the transactionService in the single-transaction file, then inside the submitTransaction method simply subscribe to the addSingleTransaction and pass in the appropriate values for the parameters. For the 'resolve' method of this subscribe you can just do the popToRoot, and the 'reject' can just log whatever get's passed into the error param. They're not really called resolve/reject in the observable style, but it's basically the same thing

That should be all we need for this! ;)

update package.json for ionic 2.0.0-rc.3

This isn't all that necessary at this point, but it's good to keep the project up to date as the framework(s) release new versions. Go Here to see which changes need to be made in our package.json, then just change the numbers in that file.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.