NativeScript UI Calendar
Tags: nativescript, calendar, android, ios
Published: 2021-07-25 11:18:03

When building this App one big key component is to allow captains to manage their calendar so obviously I needed to some type of Calendar pluging / package, and it has to be NativeScript specific so the obvious choice (and possibly only?) is [nativescript-ui-calendar](https://www.npmjs.com/package/nativescript-ui-calendar), which use `RadCalendar` and has a unified API for customizations and abstractions.  Installation is rather simple since it's a nativescript pluging `tns plugin add nativescript-ui-calendar` and then in the component that you are going to use you simply add `<RadCalendar />` but please keep in mind I'm using nativescript-vue and angular / plain javascript / typesscript / are all imported slightly differently.  Please check the documentation for your specific use case.  RadCalendar also exposes quite of bit of methods / properties and this is my full component:
```
          <RadCalendar id="calendar"
            :marginTop="getTopMargin"
            :class="loading? 'opaque' : ''"
            ref="calendar"
            :eventSource="calendarEvents"
            :eventsViewMode="eventsViewMode"
            :selectionMode="deviceType"
            viewMode="Month"
            :monthViewStyle='monthViewStyle'
            :weekViewStyle='weekViewStyle'
            transitionMode="Slide"
            locale="en-US"
            @loaded="onLoaded"
            @inlineEventSelected="eventAction"
            @dateSelected="onDateSelected"
            @dateDeselected="onDateDeselected"
            @navigatedToDate="onNavigatedToDate"
          />
```
If you know Vue then you know that `@` represents a function and `:` is a property and for properties you can solely pass strings but I'm binding them to specific computed properties based on a few things.  But you can look at all that on your own and customize for your particular needs.  [RadCalendar API](https://v7.docs.nativescript.org/ns-ui-api-reference/classes/radcalendar.html) in case you want to look at every possible option / scenario (warning it's a rabbit hole).

The whole purpose of this calendar is to allow captains to manage their bookings.  So from the calendar they can view "events".  These events are bookings (pending / confirmed), and blocked dates.  The true functionality of the calendar though is to allow captains to block off dates in which they are not available.  RadCalendar has a property called `selectionMode`, which has 4 options:
1. None
2. Single
3. Multiple
4. Range
For our purposes we decided to go with Multiple, which will allow captains to click on any number of dates and then to "block"them off.  The one big thing to take away from all of this is that this calendar acts differently on IOS / Android, but for me I need them to act the same.  So I came up with an interesting solution. 

```
     :eventsViewMode="eventsViewMode"
     :selectionMode="deviceType"
```
Those two properties are pretty much the heart of my calendar vue.  Ideally when a single event is clicked on I want the event to be displayed `Inline`, which comes up directly below the date selected.  When multiple dates are clicked, I don't want any events to show up, reason being is I don't want any of our users to be confused.  If they are blocking off multiple dates there is no need for an event to be propagated below the date.  
```
      eventsViewMode() {
        return this.newRanges.length == 1 ? "Inline" : "None";
      },
```
So I have a data property on the vue called newRanges and it's an array that gets dates pushed in and sliced out when they are selected / deselected, and as you can see from that computed property if the range has 1 entry, events are displayed, otherwise they don't show up.  Pretty simple but works really well, on IOS.  So I thought I was super clever and bam I was all excited when this was working on IOS, then I loaded up my Android emulator and what did I get?  CRASH CRASH CRASH.

So on Android if you set `selectionMode="Multiple"` and `eventsViewMode="Inline"`, you can an instant crash with an error message reading `The selected events display mode requires Single or None selection modes to be present.`  So now I have a couple of options.  Captains using android can only do single date selections, inline events cannot be viewed, or come up with a solution that mimics IOS with little to no downside.  Unfortunately for my situation it's option 3, which is the toughest cause what I see as easy / intuitive, well these captains will not.  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wuxbonpvm0f6qlubxeg.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s58heuq3k1bh2bqo6x3l.png)
So as you can see the only difference in my two calendars is a little toggle switch, that allows captains to either View Events or Block off Multiple Dates.  I personally don't like the copy that my company has chosen, but hey that's not my problem.  Anyways, so yea by default this toggle switch is set to true and it allows captain to select multiple dates and even if only 1 date is selected the Inline view will not show up.  I accomplish this by the following computed property:
```
      deviceType() {
        if(isIOS) return 'Multiple';
        return this.androidMultipleCheck ? 'Multiple' : 'Single';
      },
```
isIOS is a nativescript core module component (that I'm hoping you can assume what it does), so then if the androidMultipleCheck (Boolean) is true it's multiple otherwise single selection.  And by now you can guess that `Switch` in nativescript is set to that model.  And in the template file I had to add a little conditional, which I know you probably shouldn't do but it works and I don't use these often so I think for the one off component it is alright.  
```
          <FlexBoxLayout v-if="!isApple" flexDirection="row" justifyContent="center" alignItems="center" :class="loading ? 'opaque' : ''" flexWrap="wrap">
            <Label @tap="swapSwitch" class="calendar-container-switch-text" :text="androidMultipleCheck ? 'Block Mulitple Dates' : 'Unblock Dates'" />
            <Switch v-model="androidMultipleCheck" />
          </FlexBoxLayout>
```
isApple just returns isIOS (core component).  

The only thing that I didn't really go over is the Dropdown component which is a package that just takes in an array of values.  Pretty simple and as you can guess it each captain can select a specific charter to block dates / manage bookings.  Ideally this would be all done in one calendar color coded and whatnot but I'm a one man team with no mobile experience and I truly think that a calendar that "simple / intuitive" would 100% screw up our user base even more.  So next week I'll be bundling up the app and throwing it on test flight / google developer so we can test it and I'm super excited / nervous.  This is completely uncharted territory for myself and as smooth as I want this to go I'm expecting a shit show for the next 2 - 3 weeks.  I shall keep a bottle of Jameson and a bowl of fresh medicine handy.