Saturday, June 2, 2018

Swift 4: getter and setter directly in a struct or class

Leave a Comment

I am trying to come up with a way to access UserDefaults using properties. However, I am stuck because I can't figure out how to make the properties dynamic, so to speak.

This is the generic idea, that API that I want:

class AppUserDefaults {   var username = DefaultsKey<String>("username", defaultValue: "Unknown")   var age = DefaultsKey<Int?>("age", defaultValue: nil) }  let props = AppUserDefaults() props.username = "bla" print("username: \(props.username)") 

But that (of course) doesn't work, since the type is DefaultsKey<String>, not String. So I have to add a value property to the DefaultsKey implementation just to add the getter and the setter, like this:

struct DefaultsKey<ValueType> {   private let key: String   private let defaultValue: ValueType    public init(_ key: String, defaultValue: ValueType) {     self.key = key     self.defaultValue = defaultValue   }    var value: ValueType {     get {       let value = UserDefaults.standard.object(forKey: key)       return value as? ValueType ?? defaultValue     }     set {       UserDefaults.standard.setValue(newValue, forKey: key)       UserDefaults.standard.synchronize()     }   } } 

and then use it like this:

let props = AppUserDefaults() props.username.value = "bla" print("username: \(props.username.value)") 

But I find that rather ugly. I also tried a subscript method, but then you're still required to add [] instead of .value:

struct DefaultsKey<ValueType> {   ...   subscript() -> ValueType {     get {       let value = UserDefaults.standard.object(forKey: key)       return value as? ValueType ?? defaultValue     }     set {       UserDefaults.standard.setValue(newValue, forKey: key)       UserDefaults.standard.synchronize()     }   } }  let props = AppUserDefaults() props.username[] = "bla" print("username: \(props.username[])") 

Basically what I want is that I can define the getter and the setter directly on DefaultsKey instead of having to go through that value property. Is this simply not possible with Swift? Is there another way to get the behaviour that I want, where properties defined on AppUserDefaults are "dynamic" and go through a getter and setter, without having to define it on the property declaration inside of AppUserDefaults?

I hope I am using the correct terms here and made the question clear for everyone.

4 Answers

Answers 1

The only thing I can think of is this:

struct DefaultsKey<ValueType> {   private let key: String   private let defaultValue: ValueType    public init(_ key: String, defaultValue: ValueType) {     self.key = key     self.defaultValue = defaultValue   }    var value: ValueType {     get {       let value = UserDefaults.standard.object(forKey: key)       return value as? ValueType ?? defaultValue     }     set {       UserDefaults.standard.setValue(newValue, forKey: key)       UserDefaults.standard.synchronize()     }   } }  class AppUserDefaults {   private var _username = DefaultsKey<String>("username", defaultValue: "Unknown")   var username: String {     set {       _username.value = newValue     },     get {       return _username.value     }   } }  let props = AppUserDefaults() props.username = "bla" print("username: \(props.username)") 

Answers 2

Besides all proposed variants you can also define your custom operator for assigning value to DefaultsKey structure.

For that your DefaultsKey structure should look like this:

struct DefaultsKey<ValueType> {     private let key: String     private let defaultValue: ValueType      public init(_ key: String, defaultValue: ValueType) {         self.key = key         self.defaultValue = defaultValue     }     public private(set) var value: ValueType {         get {             let value = UserDefaults.standard.object(forKey: key)             return value as? ValueType ?? defaultValue         }         set {             UserDefaults.standard.setValue(newValue, forKey: key)         }     } } 

Explanation for DefaultsKey block of code:

  1. private(set) var means that you can set value of this property only where you can access it with private access level (also you can write internal(set) or fileprivate(set) to be able to set it from internal and fileprivate access levels accordingly).

    You will need to set value property later. To access this value getter is defined as public (by writing public before private(set)).

  2. You do not need to use synchronize() method (" this method is unnecessary and shouldn't be used", reference: https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize).

Now it's time to define custom operator (you can name it as you want, this is just for example):

infix operator <<< extension DefaultsKey {     static func <<<(left: inout DefaultsKey<ValueType>, right: ValueType) {         left.value = right     } } 

With this operator you couldn't set value of wrong type, so it's type-safe.

To test you can use a bit modified your code:

class AppUserDefaults {     var username = DefaultsKey<String>("username", defaultValue: "Unknown")     var age = DefaultsKey<Int?>("age", defaultValue: nil) }  let props = AppUserDefaults() props.username <<< "bla" props.age <<< 21 props.username <<< "Yo man" print("username: \(props.username.value)") print("username: \(props.age.value)") 

Hope it helps.

Answers 3

There is a really good blog post from radex.io about Statically-typed NSUserDefaults that you might find useful, if I understand what you are trying to do.

I've updated it for the latest Swift (since we now have conditional conformance) and added a default value for my implementation, which I've set out below.

class DefaultsKeys {}  class DefaultsKey<T>: DefaultsKeys {     let key: String     let defaultResult: T      init (_ key: String, default defaultResult: T) {         self.key = key         self.defaultResult = defaultResult     } }  extension UserDefaults {     subscript<T>(key: DefaultsKey<T>) -> T {         get {             return object(forKey: key.key) as? T ?? key.defaultResult         }         set {             set(newValue, forKey: key.key)         }     } }  // usage - setting up the keys extension DefaultsKeys {     static let baseCurrencyKey = DefaultsKey<String>("Base Currency", default: Locale.current.currencyCode!)     static let archiveFrequencyKey = DefaultsKey<Int>("Archive Frequency", default: 30)     static let usePasswordKey = DefaultsKey<Bool>("Use Password", default: false) }  // usage - getting and setting a value let uDefaults = UserDefaults.standard uDefaults[.baseCurrencyKey] = "GBP" let currency = uDefaults[.baseCurrencyKey] 

Answers 4

Here is how we are doing that in my current project. It is similar to some other answers but I think even less boiler plate. Using isFirstLaunch as an example.

enum UserDafaultsKeys: String {     case isFirstLaunch }  extension UserDefaults {      var isFirstLaunch: Bool {         set {             set(!newValue, forKey: UserDafaultsKeys.isFirstLaunch.rawValue)             synchronize()         }         get { return !bool(forKey: UserDafaultsKeys.isFirstLaunch.rawValue) }     }  } 

It is then used like this.

UserDefaults.standard.isFirstLaunch = true 

It has the benefits of not needing to learn a separate object to use and is very clear where the variable is stored.

Read More

Laravel Botman Studio

Leave a Comment

I've installed botman studio on my existing laravel project to create a chat bot. The chatbot works. However, im looking for complex conversations where user can ask chatbot "What is Example" and Chat box searches from the database table and answers back.

I do not find any tutorial or links that can help me get started. Does anyone know how to do this? A simple example could help me

1 Answers

Answers 1

This would be a possible implementation to tipical questions where you listen for the last keyword, so you could configure bot to listen What is + *keyword_to_search*

$botman->hears('What is (^[a-zA-Z0-9_]*$)', function ($bot, $keyword) {     $answer = \App\Answer::where('keyword', 'LIKE', $keyword)->get();     $bot->reply('Answer: '.$answer); }); 

This is extremly simple, you could start chat with --help and list all keywoards that a user can ask for example, it would be kinda cool I guess.

If you would like to implement more complex stuff you could try to learn about Natural Language Processing(NPL), you can read more about it on botman docs.

Read More

Friday, June 1, 2018

Firefox not updating application associations in Preferences on a Windows machine

Leave a Comment

When a JNLP is launched from a Firefox browser, the first time, it shows the following dialog . If I check the "do this automatically" check box, from the next time on, it doesn't ask this question.

The preferences seem to get stored in Firefox-> Options-> General-> Preferences.

Preferences

This works just fine on my machine. At a customer site, it doesn't seem to get updated. Even after checking the checkbox, each time it asks again & preferences also don't seem to get updated. What kind of permission/privilege issues could be causing this? How can I troubleshoot this?

1 Answers

Answers 1

Try and reinstall Firefox on the customer site

Read More

wordpress err_connection_reset in Chrome from specific country

Leave a Comment

I volunteer supporting a news website in Russia, which was hand-crafted in PHP back in 2002-2004. Needless to say, I was super excited when editors hired some folks to build a new version, based on WordPress. The old site is running on mydomain.press. I put the new WordPress version, which is meant to replace the old one, on subdomain.mydomain.press.

And there's a mysterious problem with it.

When an editor is trying to access the site at subdomain.mydomain.press, her browser (Chrome in Russia) instantly reports err_connection_reset, in 9 cases out of 10. Not spinning trying to load the site - an instant error is reported. On my machine (Canada) the same website opens no problem. Well, a little slow (hence I mentioned she's not even seeing the delay - the error is instant), but it opens in 10 out of 10 trials. When her Chrome gets the content (in that 1/10 case), it also shows a slight delay. Only the error case is instantaneous. The old site at mydomain.press is opening 100% of the time.

Connecting remotely to her Windows machine (I'm using Mac OS X) via TeamViewer, I did observe the behaviour described when using Chrome. Interestingly enough, IE didn't show this problem - it loads consistently, except that once in ~10 reloads the page loads with a garbled styling. As if some css isn't loaded properly (but not in a way that would make it an invalid document, obviously).

I'm completely out of my depth. I tried disabling her Windows Defender to see if it's the culprit - nope. I've tried to reset her IP address (as suggested by the same page which offered the earlier way to try and fix the err_connection_reset) - no dice.

I'm not seeing either error from my own Chrome, nor the garbled css (though I didn't try with IExplorer from Canada).

I know they had some ISPs in Russia block them (silly political reason, AFAIK) in the past - but this doesn't look like blocking; she'd be 100% unable to view it otherwise. She's not under any firewall (nor is the website).

what else... nginx is the server used, the setup is "basic", I suppose (I'm not that proficient in configuring it to try anything fancy).

And to make things even more mysterious - the website at mydomain.press (the old version, php-hand-crafted) is opening just fine, 100% of trials.

Opening using the IP-address doesn't change the picture, so doesn't look like a DNS issue.

Any ideas?

1 Answers

Answers 1

There is an ongoing battle of Roskomnadzor against Telegram messenger in Russia, which affects subnets, DNS and DPI hardware around the country. Try to connect via proxy or VPN server outside Russia and see if the problem goes away.

Read More

How the flow of this context should be? ( Where to put the code to process the payment depending on the selected payment method?)

Leave a Comment

I have a multi-step form for a user to register in a conference, all steps are in the same registration.blade.php page, in step 1 and step 2 is done an ajax request to validate the form fields.

The steps are:

  • Step1 is to collect some info about the user (name and tin number)
  • Step 2 is to collect the payment method (credit card or references)
  • Step 3 is the payment
  • Step 4 shows a success message (this step only appears after a successful payment with a credit card, with the references payment method this step don't appear, with references payment method only the step 1, 2 and 3 appears)

My doubt is between the step 2 and 3.

If the selected payment method references is necessary to execute the code below, that generates some payment references and then present that references to the user in step 3. When the user pays the system receives a notification and should be inserted in the payments table the price, payment_method_id, registration_id and status (paid).

Code to process payments with references:

    public function ReferencesCharge(Request $request)         {            $payment_info = [         'name' => "user name",         'email' => 'user email',         'value' => 'registration total price',         'id' => 'registration id',     ];      $newPayment = new Payment($payment_info);     $reference = $newPayment->gererateReferences();      //$reference returns an array with necessary codes to present to the user so he can pay      // after generate references is necessary:             // show in step 3 the generated references             // insert an entry in the payments table when the system receives a notification from 3rd party service informing that the user did the payment  } 

If the selected payment was credit card is necessary to execute the code below to charge the credit card and after that is inserted in the payments table the price, payment_method_id, registration_id and status (paid). And then the user should be redirected to step 4 to show a success message:

Code to process credit card payments:

public function creditCardCharge(Request $request)     {         Stripe::setApiKey(config('services.stripe.secret'));         $source = $request->stripeToken;          try{             Charge::create([                 'currency' => 'eur',                 'amount' => 2500,                 'source' => $source,             ]);         }         catch(\Exception $e){             return response()->json(['status' => $e->getMessage()], 422);         }          // after charging the card with success:             // insert an entry in the payments table              // redirect to success confirmation step to inform the user that payment was done with success      } 

My doubt is how the flow should be, where the code to handle the payment with references and the code to handle the payment with a credit card should be placed. So is possible to achieve this scenario:

enter image description here

For now, I just have the step 1 and step 2 working properly. To handle step1 and step2 I have the RegistrationController. In the step1 the info introduced by the user is validated using an ajax post request to the storeUserInfo() method of the RegistrationController if returns 200 the user goes to step2.

In the step2, the user selects the payment method and clicks in "go to step 3" is also done an ajax request to the storePaymentMethods() of the RegistrationController to validate if the user selected at least 1 payment method. My doubt is after this method return code 200 how the process should be.

Depending on the payment method, it necessary to run the appropriate code above (code that generates payment references or code to charge credit card).

So, my doubt how to organize this code in terms of controllers and methods, where to put that code that should execute depending on the selected payment method. Do you know how the flow should be to achieve that?

Maybe an approach can be something like below in storePaymentMethods() but it doesn't seem very correct do everything in this method:

public function storePaymentMethods(Request $request){        $request->validate([             'payment_method' => 'required',         ]);          if($request->payment_method == "references"){           // generate codes and present to the user that codes         }         else if($request->payment_method == "credit_card"){           // show credit card inputs to the user           // and process the credit card payment with stripe         }            return response()->json([             'success' => true,             'message' => 'success',             'payment_method' => $request->payment_method,         ], 200);     } 

A full summary of the flow of the registration with the multistep form that I have for now:

So for the step1, there is the form:

<div>     <form method="post" id="step1form" action="">         {{csrf_field()}}         <!-- fields of the step 1-->         <input type="submit" href="#step2" id="goToStep2" class="btn next-step" value="Go to step 2"/>     </form> </div> 

step1 image to explain better:

enter image description here

when the user clicks in "Go to step 2" button is made an ajax request to validate the data and if there are no errors, code 200 is returned and the user go to the step 2:

$('#goToStep2').on('click', function (event) {     event.preventDefault();     var custom_form = $("#" + page_form_id_step1);     $.ajax({         method: "POST",         url: '{{ route('conferences.storeRegistrationInfo', compact('id','slug') ) }}',         data: custom_form.serialize(),         datatype: 'json',         success: function (data, textStatus, jqXHR) {             var $active = $('.nav-pills li a.active');             nextTab($active);         },         error: function (data) {                 // show errors         }     }); }); 

Then in the ConferencesController there is teh storeRegistrationInfo() to handle the above ajax request:

public function storeRegistrationInfo(Request $request, $id, $slug = null, Validator $validator){       $rules = [];     $messages = [];      $rules["name_invoice"] = 'required|max:255|string';     $rules["TIN_invoice"] = ['required', 'string', new ValidTIN()];      $validator = Validator::make($request->all(), $rules, $messages);      $errors = $validator->errors();     $errors =  json_decode($errors);      if($validator->fails()) {         return response()->json([             'success' => false,             'errors' => $errors         ], 422);     }     return response()->json([         'success' => true,         'message' => 'success'     ], 200); } 

So, if code 200 is returned user is in the step2form:

<div>     <form method="post" id="step2form" action="">         {{csrf_field()}}         <!-- fields of the step 2-->          <input type="submit" href="#step3" id="goToStep3" class="btn next-step" value="Go to step 3"/>     </form> </div> 

step2 image to explain better:

enter image description here

When the user clicks in "Go to step 3" button is made an ajax request to validate the data and if there are no errors, code 200 is returned and the user go to the step 3, ajax request:

$("#credit_card_section").hide(); $("#references_section").hide();  var page_form_id_step2 = "step2form";      $('#goToStep3').on('click', function (event) {         event.preventDefault();         var custom_form = $("#" + page_form_id_step2);         $.ajax({             method: "POST",             url: '{{ route('conferences.storePaymentMethods', compact('id','slug') ) }}',             data: custom_form.serialize(),             datatype: 'json',             success: function (data, textStatus, jqXHR) {                 var result = data;                 if(result['payment_method'] == 'credit_card'){                     $("#credit_card_section").show();                     $("#references_section").hide();                 }else{                     $("#references_section").show();                     $("#credit_card_section").hide();                 }                 var $active = $('.nav-pills li a.active');                 nextTab($active);             },             error: function (data) {                // show errors             }         });     }); 

The ConferenceController has the storePayment() to handle the ajax request above, it validates if the user selected a payment method and if yes returns code 200:

public function storePaymentMethods(Request $request){        $request->validate([             'payment_method' => 'required',         ]);         return response()->json([             'success' => true,             'message' => 'success',             'payment_method' => $request->payment_method,         ], 200);     } 

Then there is the step3 div. In the step3 div it will appear the div #credit_card_section visible or #references_section visible depending on the payment method selected in the previous step (credit card or references):

<div>     <form method="post" id="step3form" action="">             {{csrf_field()}}             <div id="credit_card_section">                 <!-- present necessary fields to                 payments with credit card-->             </div>               <div id="references_section">         <!-- present generated reference to the user so he can pay-->             </div>     </form> </div> 

step3 image to explain better, depending on the payment method the info that is necessary to show in step 3 is different. If the payment method was credit card also appears a step4 div showing a success message after a successful charge with a credit card:

enter image description here

Then there is the step 4 div that should show the success message, after a completed payment with a credit card:

<div id="step4">    <p>    <i class="fa fa-plus" aria-hidden="true"></i>    Payment and registration completed with  success.    </p> </div> 

// Resume of the methods of the RegistrationController that I have for now, the RegistrationController is the controller that I have that handles the multistep form

class RegistrationController extends Controller {     public :function storeQuantities(Request $request, $id, $slug = null){         // method that stores in session the ticket types         // selected by the user in the conference details page         Session::put('selectedRtypes', $selectedRtypes);         Session::put('allParticipants' , $allParticipants);         Session::put('customQuestions' ,  $selectedRtypes[$rtype->name]['questions']);          // and then redirects the user to the registartion page registration.blade.php          // using the route 'conferences.registration         // this route is associated with the displayRegistrationPage() method         return redirect(route('conferences.registration',['id' => $id, 'slug' => $slug]));     }     // method of the route 'conferences.registration' that displays  //  the registration.blade.php that is the page with the multi step form     public function displayRegistrationPage(Request $request, $id, $slug=null){         // get the session values         $selectedRtypes =  Session::get('selectedRtypes');         $allParticipants = Session::get('allParticipants');         $customQuestions = Session::get('customQuestions');     // redirect the user to the registration.blade.php         if(isset($selectedRtypes)) {             return view('conferences.registration',                 ['selectedRtypes' => $selectedRtypes, 'customQuestions' => $customQuestions, 'id' => $id, 'slug' => $slug]);         }         else{             // return user to the conference details page             return redirect(route('conferences.show',['id' => $id, 'slug' => $slug]));         }     }     /* the following methods are to handle the registration       multi step  form of the registration.blade.php view */     // method to handle the step1 of the multi step form     public function storeRegistrationInfo(Request $request, $id, $slug = null, Validator $validator){          // get and validate the fields of the step1         // and returns code 200 if al is ok          return response()->json([             'success' => true,             'message' => 'success'         ], 200);     }      // method to handle the step2 of the multi step form     public function storePaymentMethods(Request $request){          // validate if the payment_method field was filled         // if was filled return code 200          // and returns the payment_method          //so in the step 3 div is possible to show a section for        // when the payment_method is credit card (#credit_card_section)            or transfers ("transfers_section")         return response()->json([             'success' => true,             'message' => 'success',             'payment_method' => $request->payment_method,         ], 200);     } } 

Route for step1:

Route::post('/conference/{id}/{slug?}/registration/storeRegistrationInfo', [     'uses' => 'RegistrationController@storeRegistrationInfo',     'as'   =>'conferences.storeRegistrationInfo' ]); 

Route for step2:

Route::post('/conference/{id}/{slug?}/registration/storePaymentMethods', [     'uses' => 'RegistrationController@storePaymentMethods',     'as'   =>'conferences.storePaymentMethods' ]); 

2 Answers

Answers 1

As in your doubts, to better structure your code and separate logic (DRY concept), you should do few things:

  • Create PaymentsController with 3 functions (for the start, you will definitely add more here)

    1. for processing your references
    2. for processing credit cards
    3. for storing payment methods (store payment method in session, until user completes step3)

    You are totally free, on how you name these functions, but I would suggest something like processViaReferences, processViaCreditCard and storePaymentMethod.

    It will be much easier to read and validate, if you have them separated.

    Create corresponding post routes for them and reference appropriately, in cour code.

  • Create part views containing your forms only.

    Then include, these part views via @include to have it separated on view level. For your references in javascript/jQuery, remember to keep correct ids of them. You can extract javascript, to other view part views or separate js files also, if you have not done it already.

    Your view/form code should go to these part views...

Answers 2

There are no clear instructions, you need to decide for yourself how to organize your code.

If you can not choose exactly where to place the PHP code responsible for payment, then I would place processing of both payments in PaymentsController.php

So it is obvious that after choosing the method of payment you need to form something like an order in the database.

  1. In case of references they will have to be tied to this order.
  2. In case of using credit cards, payment will be tied to this order.
Read More

Chrome on Windows 10 Freezing on Script Execution, Works Perfectly on Mac

Leave a Comment

I have an issue I assumed was related to the Windows 10 April CU with Chrome freezing and BSOD, and may well be, but what I've noticed is that in Windows Chrome (v66 and v67dev) the main thread is blocked and frozen, and won't allow scrolling for example, even though other Windows and other panels of Chrome are functioning without being frozen.

The actual performance in Mac Chrome is comparable in terms of script execution, but scrolling is allowed and the main thread does not appear blocked.

This same code also works perfectly in Windows Edge and Firefox without the freezing behavior.

This particular app is written in Ember CLI, but appears to be Chrome and Windows specific.

Windows 10 Chrome - JS Execution of long running script

1 Answers

Answers 1

Windows 10 is a service, which means it gets better through periodic software updates.

This issue you report has plenty of media coverage and has to do with bugs in W10's April update:

. https://www.theguardian.com/technology/2018/may/04/windows-10-april-2018-update-bug-locks-machines-running-chrome-cortana

. https://www.cnet.com/news/windows-10-april-2018-update-bugs-microsoft-fix-may-8/

. https://www.theverge.com/2018/5/3/17315180/microsoft-windows-10-april-2018-update-chrome-crash-freezing-problems

The great news is you usually don’t have to do anything: If you have enabled automatic updates, new updates will automatically download and install whenever they’re available, so you don’t have to think about it.

Read More

How to use devise-jwt with devise for signin, signup and signout in rails api

Leave a Comment

I am using rails for the backend using devise-jwt and react for the frontend part.

I am following this https://github.com/waiting-for-dev/devise-jwt/blob/master/README.md

my routes.rb file contains:

 Rails.application.routes.draw do   # remove this in production   require 'sidekiq/web'   mount Sidekiq::Web => '/sidekiq'    namespace :api, defaults: { format: 'json' } do     namespace :v1 do       devise_for :users, :controllers => {sessions: 'api/v1/sessions', registrations: 'api/v1/registrations'}     end   end end 

my registrations_controller.rb (app/controllers/api/registrations_controller.rb)

class Api::V1::RegistrationsController < Devise::RegistrationsController   respond_to :json, :controllers => {sessions: 'sessions', registrations: 'registrations'}    before_action :sign_up_params, if: :devise_controller?, on: [:create]    def create     build_resource(sign_up_params)      if resource.save       render :json => resource, serializer: Api::V1::UserSerializer, meta: { message: 'Sign up success', token: request.headers["Authorization"] }, :status => :created     else       render :json => resource, adapter: :json_api, serializer: ActiveModel::Serializer::ErrorSerializer, meta: { message: 'Sign up success' }, :status => :created     end   end     protected    def sign_up_params     params.require(:sign_up).permit(:first_name, :last_name, :mobile, :email, :password, :password_confirmation)   end end 

my sessions_controller.rb (app/controllers/api/sessions_controller.rb)

class Api::SessionsController < Devise::SessionsController     respond_to :json end 

my application_controller.rb (app/controllers/application_controller.rb)

class ApplicationController < ActionController::Base end 

Basically what will be the next step to acees the token. I am confused. How will i get the acess token and use it to authenticate in the frontend react part.

1 Answers

Answers 1

Assuming you have your server-side setup the response will include an Authorization Header.

On the front-end you'll make request to sign in and have a callback to catch the response:

 window.fetch(LOGIN_URL, dataWithLoginInfo).then(response => {     const jwt = response.headers.get('Authorization').split('Bearer ')[1];     window.sessionStorage.setItem('jwt', jwt);   }).catch(handleError) 

Next make the requests with the Authorization header included:

const token =  window.sessionStorage.getItem('jwt') const headers = { Authorization: `Bearer ${token}` } 

or use it in your app after you decode it:

import jwt from 'jsonwebtoken'; const decodedToken = jwt.decode(window.sessionStorage.getItem('jwt'));  if (decodedToken.isAdmin) {   return <AdminPage />; } else {   return <NotAdminPage />; } 

You'll use something like https://www.npmjs.com/package/jwt-decode or https://www.npmjs.com/package/jsonwebtoken to decode the token and read the information from it like id, roles, permissions, etc.

You really need to follow a tutorial like: https://auth0.com/blog/secure-your-react-and-redux-app-with-jwt-authentication/ or http://jasonwatmore.com/post/2017/12/07/react-redux-jwt-authentication-tutorial-example. Then have some local expert take a look at all your code.

Read More