Andrey Prokopenko's Blog

Visa Calculator

Disclaimer

Please aware that this blog was previously written in Russian. I will not adopt previous articles but try to use blog to describe state of my mind. I really love cool success stories about software and find interesting the whole process: from generation of some awesome idea through the thrilling details of its implementation till its delivery and going with a live system.

Abstract

In this blog post you can find the story about small project which purpose is to make calculations about visa restrictions and limitations (if it’s applicable for your country when you are going to travel abroad). Starting from the beginning only time I had was 10 minutes per day or, actually, per week. Once sceleton and algorithm were implemented in some way I started to be excited of final result. And here we are. If you want to try it right now please use following link: https://an-pro.org/tools/visa-calculator

Idea

Consider you are frequent traveller. You have Shengen visa (or any visa) which allows you to stay somewhere X days during shift for Y days, e.g. 30 days per 90. It means that when you reach first limit you have to wait from home extra 60 days (90 days in total) to decrease first limit (30) and get new free days to plan your return.

For Shengen visa there is calculator. I found it quite tricky, working in unstable way and making all calculations on server side. I thought there is no need to make any requests to server. They are redundant by definition.

Another case appeared when I was in a business trip in Ecuador. We were discussing with teammates how often we are travelling abroad and how many days left to become a non-resident. I don’t pretty know how it’s going in your country but I can say about Russia. Non-resident status will increase your taxes as a citizen from 13% to 30% till you get out from this period. Ah, limit is half a year per year.

The idea is simple: do not break the visa rules and try not to become non-resident. You have to do a lot of excel calculations to count all that days in a different ways:

  • You have your own previous trips history (past).
  • And you might be currently in the trip (present).
  • And actually you would plan next trips (future).

PureScript

I had some Haskell experience to try it in a browser. Somehow, I discovered few alternatives like Elm and PureScript. I followed advise to try PureScript when it was quite unstable, one year ago there was compiler upgrade and tooling transition through dependency hell (0.10 to 0.11 if my memories are correct). Ok. What’s next?

Frameworks: Pux vs. Halogen? Halogen did not worked for me (I hope because of major upgrade). But Pux worked fine and I focused on it. If you are familiar with MVC then rest will be obvious.

Revision

So I started from top to bottom. And when I reached the algorithm situation became tough. There was user input. There were some pretty well validations: date format, date range compliance and number of days format and compliance. User could give array of ranges and two numbers. Good. What’s next. I decided there will be no explicit button. Every input should trigger validations and calcluations if it’s possible.

Once data reached validations what should be the result? How can I represent it? What it actually should be? After some analysis I realized that visa could have several types from user input perspective, that result could be both positive and negative. Which date from future range (which one?) should be taken as a start point?

I did not understand pretty well what I am going to produce. After answering all that questions following State was discovered:

newtype State = State
  { title :: String
  , route :: Route
  , loaded :: Boolean
  , userRanges :: Array UserRange
  , today :: MaybeDate
  , visa :: Visa
  , ranges :: Array DateRange
  , nextId :: Int
  , result :: String
  }

newtype UserRange = UserRange
  { start :: DateWidget
  , end :: DateWidget
  , id :: Int
  , msg :: ErrorMsg
  }

newtype DateRange = DateRange
  { start :: MaybeDate
  , end :: MaybeDate
  , id :: Int
  , diff :: MaybeInt
  }

newtype DateWidget = DateWidget
  { widgetDate :: String, widgetMsg :: ErrorMsg }

MaybeDate, MaybeInt and ErrorMsg are the simple newtype wrappers to avoid orphans.

User might add and/or remove previous, planned trips and visa restrictions. When data passed all validations Calculation started immediately.

Algorithm

Client application received visa parameters, user ranges and validated date ranges. Client started with following steps:

  1. Resolve all overlaps
  2. Define what situation is:
    • Is there are any future trips, otherwise get today as a start point.
  3. Get all past trips
  4. For each future trip split range onto array of dates.
  5. For each future date go through all past trips started from upper visa limit.
  6. If limit is reached then calculate the exact date when it happened.
    • if it was in the past then get first future or today point and generate final text.

Try it

https://an-pro.org/tools/visa-calculator

What’s next?

I have plans to implement following features:

  • Make export/import all trips
  • Make datepicker for Pux. Halogen has its own :)
  • Add rest visa types (choosing widget, algorithms and samples for rest types).
  • Add widget for converting weeks/monthes/years to days and vice versa.
  • Whatever you ask.

I will really appreciate your feedback.

Thank you.


Posted on 2018-06-06 by agr . Powered by Hakyll. Inspired by Yann Esposito.