Example #1
0
        private async Task PurchaseSubscription(string subCode)
        {
            if (_userCache.GetLoggedInAccount() == null)
            {
                throw new InvalidOperationException("User must be logged in to purchase a subscription.");
            }
            var sub = await _purchaseService.PurchaseItem(subCode, ItemType.Subscription, "payload");

            if (sub == null)
            {
                throw new InvalidOperationException($"Something went wrong when attempting to purchase. Please try again.");
            }

            var model = new Models.SubscriptionModel()
            {
                PurchaseId        = sub.Id,
                PurchaseToken     = sub.PurchaseToken,
                SubscriptionType  = SubscriptionUtility.GetTypeFromProductId(sub.ProductId),
                StartDateTime     = DateTimeOffset.UtcNow,
                PurchasedDateTime = DateTimeOffset.UtcNow,
                EndDateTime       = DateTimeOffset.UtcNow.AddMonths(1),
                PurchaseSource    = Device.RuntimePlatform == Device.Android ? Models.PurchaseSource.GooglePlay : Models.PurchaseSource.AppStore,
                UserId            = _userCache.GetLoggedInAccount().UserId,
                Email             = _userCache.GetLoggedInAccount().Email
            };

            try
            {
                _subCache.Put(model.PurchaseId, model);
            }
            catch { }
            _subService.AddSubscription(model);
        }
        public void LogError(string message, Exception ex, params object[] args)
        {
            try
            {
                var dict = new Dictionary <string, string>();
                dict.Add("source_name", typeof(T).ToString());
                dict.Add("message", message);
                dict.Add("app_platform", Device.RuntimePlatform);
                dict.Add("exception", ex?.Message);
                for (int i = 0; i < args.Length; i++)
                {
                    dict.Add($"metadata_{i}", JsonConvert.SerializeObject(args[i]));
                }
                if (_userCache.GetLoggedInAccount() != null)
                {
                    dict.Add("user_email", _userCache.GetLoggedInAccount().Email);
                }
                _service.LogEvent("app_error", dict);
#if DEBUG
                Debug.WriteLine(message);
                Debug.WriteLine(JsonConvert.SerializeObject(dict));
#endif
            }
            catch (Exception e)
            {
#if DEBUG
                Debug.WriteLine(e.ToString());
#endif
            }
        }
Example #3
0
        private async Task SetVisualStateForValidation()
        {
            try
            {
                var user = _userService.GetLoggedInAccount();
                if (user == null)
                {
                    MainLayoutVisible         = true;
                    CannotSubmitLayoutVisible = false;
                    return;
                }
                var validation = await _orderValidator.ValidateOrderRequest(user);

                var activeSub = SubscriptionUtility.SubscriptionActive(validation.Subscription);
                if (validation.RemainingOrders > 0)
                {
                    MainLayoutVisible         = true;
                    CannotSubmitLayoutVisible = false;
                    return;
                }
                switch (validation.State)
                {
                case ValidationState.NoReportsLeftInPeriod:
                    MainLayoutVisible         = false;
                    CannotSubmitHeaderText    = "You've been busy!";
                    CannotSubmitLabelText     = $"Sorry, you have used all of your reports for this month.";
                    CannotSubmitLayoutVisible = true;
                    PurchaseOptionsText       = $"Additional reports can be purchased at a reduced price of " +
                                                $"${SubscriptionUtility.GetSingleReportInfo(validation).Price} per report.";
                    PurchaseOptionsVisible = true;
                    break;

                case ValidationState.NoSubscriptionAndTrialValid:
                    MainLayoutVisible         = false;
                    CannotSubmitHeaderText    = "Thanks for trying Fair Squares!";
                    CannotSubmitLabelText     = $"Please claim your free one month subscription trial, or click below to view other options.";
                    CannotSubmitLayoutVisible = true;
                    PurchaseOptionsVisible    = false;
                    break;

                case ValidationState.NoSubscriptionAndTrialAlreadyUsed:
                    MainLayoutVisible         = false;
                    CannotSubmitHeaderText    = "Thanks for trying Fair Squares!";
                    CannotSubmitLabelText     = $"Click below to view options for getting more reports.";
                    CannotSubmitLayoutVisible = true;
                    PurchaseOptionsVisible    = false;
                    break;

                default:
                    MainLayoutVisible         = true;
                    CannotSubmitLayoutVisible = false;
                    break;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to set visual state on load.", ex);
            }
        }
Example #4
0
 public void LogError(string message, Exception ex, params object[] args)
 {
     try
     {
         var emailBody = $"<p>User with ID '{_userCache.GetLoggedInAccount()?.UserId ?? "Not logged in user"}' and email '{_userCache.GetLoggedInAccount().Email}' had the following issue: ";
         emailBody += @"<br/>" + message;
         foreach (var arg in args)
         {
             emailBody += @"<br/>" + JsonConvert.SerializeObject(arg, Formatting.Indented);
         }
         emailBody += @"<br/>" + Device.Idiom.ToString() + "</p>";
         Task.Run(() =>
         {
             _notifyService.Notify(new Models.NotificationRequest()
             {
                 From        = $"{Device.RuntimePlatform.ToString()}[email protected]",
                 To          = $"*****@*****.**",
                 Message     = emailBody,
                 MessageType = Models.MessageType.Email,
                 Subject     = $"{Device.RuntimePlatform.ToString()} Critical Error"
             });
         });
     }
     catch (Exception e)
     {
         Debug.WriteLine($"An error occurred while logging to email." + e.ToString());
     }
 }
Example #5
0
        public OrderViewModel(IOrderValidationService validator,
                              ICurrentUserService userCache,
                              IOrderService orderService,
                              IToastService toast,
                              IPageFactory pageFactory,
                              MainThreadNavigator nav,
                              IMessagingSubscriber topicSubscriber,
                              ILogger <OrderViewModel> logger,
                              string deviceType,
                              AlertUtility alertUtility,
                              Action <BaseNavPageType> baseNavigationAction,
                              ICache <Models.Order> orderCache)
        {
            _orderValidator       = validator;
            _userService          = userCache;
            _toast                = toast;
            _nav                  = nav;
            _orderService         = orderService;
            _pageFactory          = pageFactory;
            _orderCache           = orderCache;
            _alertUtility         = alertUtility;
            _topicSubscriber      = topicSubscriber;
            _baseNavigationAction = baseNavigationAction;
            _deviceType           = deviceType;
            _logger               = logger;

            PurchaseOptionsCommand = new Command(async() =>
            {
                var val = await _orderValidator.ValidateOrderRequest(_userService.GetLoggedInAccount());
                if (SubscriptionUtility.SubscriptionActive(val.Subscription))
                {
                    _nav.Push(_pageFactory.GetPage(PageType.SingleReportPurchase, val));
                }
                else
                {
                    _nav.Push(_pageFactory.GetPage(PageType.PurchaseOptions, val));
                }
            });
            OptionsInfoCommand = new Command(async() => await alertUtility.Display("Roof Option Selection",
                                                                                   $"Selecting a roof option allows Fair Squares to determine what roofs you would like measured at the submitted address.{Environment.NewLine}" +
                                                                                   $"{Environment.NewLine}Primary Only- Fair Squares will measure the primary structure, including attached garage.{Environment.NewLine}" +
                                                                                   $"Detached Garage- Fair Squares will also measure the detached garage on the property.{Environment.NewLine}" +
                                                                                   $"Shed/Barn- Fair Squares will also measure a shed or barn on the property.{Environment.NewLine}" +
                                                                                   $"{Environment.NewLine}NOTE: Fair Squares only supports measuring one primary structure per report (with a detached garage or shed/barn if needed).",
                                                                                   "Ok"));
            ErrorMessageRowHeight = 0;
            SelectedOptionIndex   = -1;
            SelectedStateIndex    = -1;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            SetVisualStateForValidation();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
        }
        private async Task PurchaseItem(string itemCode)
        {
            if (_userCache.GetLoggedInAccount() == null)
            {
                throw new InvalidOperationException("User must be logged in to purchase a report.");
            }
            var purchase = await _purchaseService.PurchaseItem(itemCode, ItemType.InAppPurchase, "payload");

            if (purchase == null)
            {
                throw new InvalidOperationException($"Something went wrong when attempting to purchase. Please try again.");
            }

            var model = new Models.PurchasedReportModel()
            {
                PurchaseId        = purchase.Id,
                PurchaseToken     = purchase.PurchaseToken,
                PurchasedDateTime = DateTimeOffset.UtcNow,
                PurchaseSource    = Device.RuntimePlatform == Device.Android ? Models.PurchaseSource.GooglePlay : Models.PurchaseSource.AppStore,
                UserId            = _userCache.GetLoggedInAccount().UserId,
                Email             = _userCache.GetLoggedInAccount().Email
            };

            try
            {
                _prService.AddPurchasedReport(model);
            }
            catch (Exception ex)
            {
                _emailLogger.LogError($"Purchase succeeded but failed to add purchase to server.", ex, model);
            }
            try
            {
                _prCache.Put(model.PurchaseId, model);
            }
            catch { }
        }
Example #7
0
        public AccountViewModel(ICurrentUserService userCache,
                                IOrderValidationService orderValidator,
                                MainThreadNavigator navigation,
                                IPageFactory pageFactory,
                                Action <string> changeLogInStyleClass,
                                Action <string> changeSubStyleClass,
                                ILogger <AccountViewModel> logger,
                                ICacheRefresher cacheRefresher)
        {
            _navigation            = navigation;
            _pageFactory           = pageFactory;
            _userCache             = userCache;
            _logger                = logger;
            _cacheRefresher        = cacheRefresher;
            _userCache.OnLoggedIn += async(s, e) =>
            {
                SetAccountState(e.Account);
                await SetSubState(e.Account);
            };
            _userCache.OnLoggedOut += async(s, e) =>
            {
                SetAccountState(null);
                await SetSubState(null);
            };
            _orderValidator        = orderValidator;
            _changeLoginStyleClass = changeLogInStyleClass;
            _changeSubStyleClass   = changeSubStyleClass;
            var user = userCache.GetLoggedInAccount();

            _logger             = logger;
            OnAppearingBehavior = new Command(async() =>
            {
                var u = _userCache.GetLoggedInAccount();
                SetAccountState(u);
                await SetSubState(u);
            });
            SetInitialState(user);
        }
        private async Task SubmitFeedback(string feedback)
        {
            if (string.IsNullOrWhiteSpace(feedback))
            {
                return;
            }
            var user = _userCache.GetLoggedInAccount();

            if (user == null)
            {
                var response = await _alertUtility.Display("Not Logged In", "Because you are not logged in, Fair Squares staff will not be able to respond to your feedback. " +
                                                           "Are you sure you want to continue?", "Continue", "Log In");

                if (!response)
                {
                    _nav.Push(_pageFactory.GetPage(PageType.Landing));
                    return;
                }
            }
            try
            {
                _notifier.Notify(new Models.NotificationRequest()
                {
                    From        = "*****@*****.**",
                    To          = "*****@*****.**",
                    Message     = feedback,
                    MessageType = Models.MessageType.Email,
                    Subject     = "Feedback from " + user?.Email
                });
                await _alertUtility.Display("Feedback Submitted", "Thank you for your feedback!", "Ok");
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to submit feedback.", ex, $"Feedback: {feedback}");
            }
            _nav.Pop();
        }
        public OrderDetailViewModel(Models.Order order,
                                    ICache <PropertyModel> propertyCache,
                                    ICache <ImageModel> imgCache,
                                    IPropertyService propService,
                                    IImageService imgService,
                                    IToastService toast,
                                    MainThreadNavigator nav,
                                    IPageFactory pageFactory,
                                    Func <string, string, string, Task> alertAction,
                                    ICurrentUserService userService,
                                    ILogger <OrderDetailViewModel> logger)
        {
            _order              = order;
            _propertyCache      = propertyCache;
            _imageCache         = imgCache;
            _propertyService    = propService;
            _pageFactory        = pageFactory;
            _imageService       = imgService;
            _userService        = userService;
            _toastService       = toast;
            _nav                = nav;
            _alertAction        = alertAction;
            _logger             = logger;
            OnAppearingBehavior = new Command(async() => await LoadPropertyAndImage());

            // Display message if order isn't fulfilled yet.
            if (!order.Fulfilled)
            {
                StatusMessageVisible = true;
                MainLayoutVisible    = false;
                // Have to do this because some dummy decided to store dates in EST
                DateTime displayTime = DateTime.Now;
                if (order.DateReceived != null)
                {
                    var timeInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Detroit");
                    var utc      = TimeZoneInfo.ConvertTimeToUtc(order.DateReceived.Value.DateTime);
                    displayTime = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
                }
                SubmittedDateText = $"Order #{order.OrderId} was submitted on {displayTime.ToString("dddd, MMMM dd yyyy")}" +
                                    $" at {displayTime.ToString("h:mm tt")}";
                if (order.Status == null)
                {
                    order.Status = new StatusModel()
                    {
                        Status = Status.Pending
                    };
                }
                switch (order.Status.Status)
                {
                case (Status.ActionRequired):
                    StatusMessageText       = $"Please respond to the message sent to {_userService.GetLoggedInAccount()?.Email ?? "your logged in email"} to continue with this order.";
                    StatusText              = "Action Required";
                    TimingDisclaimerVisible = false;
                    break;

                default:
                    StatusMessageText       = "Your order has been received and is being processed.";
                    StatusText              = "Pending";
                    TimingDisclaimerVisible = true;
                    break;
                }
                return;
            }
            else
            {
                StatusMessageVisible = false;
            }
            _property = _propertyCache.Get(order.OrderId);
            _image    = _property != null?_imageCache.Get(_property.OrderId) : null;

            SelectedRoofChangedCommand = new Command(() => SetUIMeasurements(_selectedRoofIndex));
            if ((_property == null || _image == null) && _order.Fulfilled)
            {
                MainLayoutVisible    = false;
                StatusMessageVisible = false;
                LoadingAnimVisible   = true;
                LoadingAnimRunning   = true;
            }
            else
            {
                MainLayoutVisible = true;
                if (_property.Roofs.Count > 1)
                {
                    RoofSelectionVisible = true;
                    RoofsSource          = _property.Roofs.Select(x => x.Name).Distinct().ToList();
                    RoofsSource          = new[] { "All" }.Concat(RoofsSource).ToList();
                }
                else
                {
                    RoofSelectionVisible = false;
                }
                SetUIMeasurements(0);
            }
        }
        public MyOrdersViewModel(IOrderService orderSvc,
                                 ICache <Models.Order> orderCache,
                                 ICache <PropertyModel> propertyCache,
                                 ICache <ImageModel> imageCache,
                                 ILogger <MyOrdersViewModel> logger,
                                 ICacheRefresher cacheRefresher,
                                 IOrderValidationService validator,
                                 IPageFactory pageFactory,
                                 ICurrentUserService userService,
                                 LaunchedFromPushModel pushModel,
                                 MainThreadNavigator nav,
                                 IMessagingCenter messagingCenter,
                                 Action <Action> uiInvoke,
                                 Action <BaseNavPageType> baseNavAction)
        {
            _orderService      = orderSvc;
            _orderCache        = orderCache;
            _propertyCache     = propertyCache;
            _imageCache        = imageCache;
            _logger            = logger;
            _uiInvoke          = uiInvoke;
            _cacheRefresher    = cacheRefresher;
            _validationService = validator;
            _pageFactory       = pageFactory;
            _userService       = userService;
            _messagingCenter   = messagingCenter;
            _nav                 = nav;
            _baseNavAction       = baseNavAction;
            ExampleReportCommand = new Command(() =>
            {
                try
                {
                    var order = JsonConvert.DeserializeObject <Models.Order>(Examples.ExampleOrder);
                    _imageCache.Put(order.OrderId, new ImageModel()
                    {
                        OrderId = order.OrderId,
                        Image   = Convert.FromBase64String(Examples.ExampleImage)
                    });
                    _propertyCache.Put(order.OrderId, JsonConvert.DeserializeObject <PropertyModel>(Examples.ExampleProperty));
                    _nav.Push(_pageFactory.GetPage(PageType.OrderDetail, order));
                }
                catch (Exception ex)
                {
                    _logger.LogError($"An error occurred while trying to open example order.", ex);
                }
            });
            Action refreshAction = async() =>
            {
                try
                {
                    OrderListRefreshing = true;
                    var fresh = await _orderService.GetMemberOrders(_userService.GetLoggedInAccount()?.UserId);

                    _orderCache.Put(fresh.ToDictionary(x => x.OrderId, x => x));
                    SetListViewSource(fresh.ToList());
                    OrderListRefreshing = false;
                }
                catch (Exception ex)
                {
                    _logger.LogError($"Failed to refresh order list.", ex);
                }
            };

            OrderListRefreshCommand = new Command(refreshAction);
            _messagingCenter.Subscribe <App>(this, "CacheInvalidated", async x =>
            {
                await this.SetViewState();
            });
            OnAppearingBehavior = new Command(async() =>
            {
                if (!_pmEventSubscribed)
                {
                    _pmEventSubscribed         = true;
                    pushModel.PropertyChanged += async(s, e) =>
                    {
                        if (!string.IsNullOrWhiteSpace(pushModel.OrderId))
                        {
                            var order = await _orderService.GetOrder(pushModel.OrderId);
                            _orderCache.Put(order.OrderId, order);
                            _nav.Push(_pageFactory.GetPage(PageType.OrderDetail, order));
                        }
                    };
                }
                await SetViewState();
            });
        }
        private async Task SetViewState()
        {
            var orders = new List <Models.Order>();

            try
            {
                var user = _userService.GetLoggedInAccount();
                if (user != null)
                {
                    if (_cacheRefresher.Invalidated)
                    {
                        MainLayoutVisible       = false;
                        FreeReportLayoutVisible = false;
                        LoginLayoutVisible      = false;
                        NoOrderLayoutVisible    = false;
                        LoadingLayoutVisible    = true;
                        LoadingAnimVisible      = true;
                        LoadingAnimRunning      = true;
                        // Just refresh order cache if cache refresh hasn't been started yet.
                        if (_cacheRefresher.RefreshTask == null || _cacheRefresher.RefreshTask.IsCompleted)
                        {
                            var fresh = await _orderService.GetMemberOrders(user.UserId);

                            _orderCache.Put(fresh.ToDictionary(x => x.OrderId, x => x));
                        }
                        else
                        {
                            await _cacheRefresher.RefreshTask;
                        }
                        MainLayoutVisible    = true;
                        LoadingLayoutVisible = false;
                        LoadingAnimRunning   = false;
                        LoadingAnimVisible   = false;
                    }
                    orders = _orderCache.GetAll().Select(x => x.Value).ToList();
                    var anyOrders = orders.Any();
                    MainLayoutVisible    = anyOrders;
                    NoOrderLayoutVisible = !anyOrders;
                    var validation = await _validationService.ValidateOrderRequest(user);

                    FreeReportLayoutVisible = validation.State == ValidationState.FreeReportValid;
                    LoginLayoutVisible      = false;
                }
                else
                {
                    FreeReportLayoutVisible = false;
                    MainLayoutVisible       = false;
                    LoginLayoutVisible      = true;
                    NoOrderLayoutVisible    = true;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"Failed to set view state. {ex.Message}", ex);
            }
            finally
            {
                LoadingLayoutVisible = false;
                LoadingAnimRunning   = false;
                LoadingAnimVisible   = false;
            }
            SetListViewSource(orders);
        }
Example #12
0
 private async Task SetInitialState(AccountModel user)
 {
     ToolbarInfoCommand = new Command(() => _navigation.Push(_pageFactory.GetPage(PageType.Instruction, false)));
     LogOutCommand      = new Command(async() =>
     {
         if (_userCache.GetLoggedInAccount() == null)
         {
             _navigation.Push(_pageFactory.GetPage(PageType.Landing));
         }
         else
         {
             _userCache.LogOut();
             SetAccountState(null);
             await SetSubState(null);
         }
     });
     SubscriptionCommand = new Command(async() =>
     {
         if (_userCache.GetLoggedInAccount() == null)
         {
             return;
         }
         var valid = await _orderValidator.ValidateOrderRequest(_userCache.GetLoggedInAccount());
         try
         {
             SubscriptionButtonEnabled = false;
             if (SubscriptionUtility.SubscriptionActive(valid.Subscription))
             {
                 _navigation.Push(_pageFactory.GetPage(PageType.ManageSubscription, valid));
             }
             else
             {
                 _navigation.Push(_pageFactory.GetPage(PageType.PurchaseOptions, valid));
             }
         }
         catch (Exception ex)
         {
             _logger.LogError("Failed to handle subscription click command.", ex);
         }
         finally
         {
             SubscriptionButtonEnabled = true;
         }
     });
     FeedbackCommand = new Command(() =>
     {
         try
         {
             FeedbackButtonEnabled = false;
             _navigation.Push(_pageFactory.GetPage(PageType.Feedback, _navigation));
         }
         catch (Exception ex)
         {
             _logger.LogError("Failed to handle feedback click command.", ex);
         }
         finally
         {
             FeedbackButtonEnabled = true;
         }
     });
     SetAccountState(user);
     await SetSubState(user);
 }