LB Admin readme

  • NE naručivati (porudžbine) iz aplikacije za korisnike sa admin nalogom. 
  • Za odobravanje novog restorana, ulogujte se na Admin panel i idite na Zahtevi za nove radnje, skrolujte skroz dole, štiklirajte Aktivan checkbox i odredite procenat. 
  • Za pregled zarade idite na Uplate-Zarada, tabela se resetuje na mesečnom nivou. 

  • NE dodavati proizvode, opcije.. itd kao admin, već je to isključivo predvidjeno za managera. 

LB Partner README

  •  Preporučeni proizvodi su oni koji se prikazuju u sekciji “Zaboravljate nesto?” u aplikaciji za korisnike i to neposredno pre potvrde porudžbine. Da bi dodali proizvod tu samo štiklirajte “Preporučeno” prilokom kreiranja proizvoda.



  • Instalacija aplikacije na Android uredjajima je standardna a za iOS postoji jedan ekstra korak. Video uputsvo: https://youtu.be/10PlX-cOssw

  • Da biste primili puš notifikaciju o novoj porudžbini ne zaključavajte telefon/tablet na kome koristite Little Bag Partner aplikaciju i samo minimizirajte aplikaciju tako da ostane aktivna u pozadini. Video uputstvo: https://youtu.be/R00Mi2jpkfM
  • Na kraju radnog vremena (ili u slučaju velike gužve) možete da zatvorite restoran za nove porudžbine tako što ćete ići na tab “Restoran” u aplikaciji i samo prevucite dugme na dnu. Video uputstvo: https://youtu.be/R00Mi2jpkfM


Podrška: support@littlebag.eu

Little Bag Admin panel updates

  1. Remove Part Of City section completely from Admin panel
  2. So when Driver choose City, he should be automatically added to all markets that have selected same City and have Own delivery checkbox set to false.
  3. So here it is order lifecycle for markets that don’t have own delivery:
    1. User place new order
    2. Market owner accept it (order_status_id==2)
    3. Than Push notification is sent to all ACTIVE drivers of that market
    4. First driver that accept it in driver mobile app, only him will be the driver for that order.
    5. When he delivers order than he will update order_status_id to 5 from driver mobile app.
  4. Remove date picker from Drivers section.

3 quick fixes + client request update

  • Make Symbol field in single Currency to be NOT-required, so that it can be empty.
  • Hide social auth (Google and Facebook) buttons and “I forgot my password” from login/register screen.
  • And please bro fix this gallery responsiveness issue, make all images fixed width and fixed height (400×200 for example or sth like that).

CLIENT UPDATE REQUEST:
For phone and mobile phone fields in single Market make it like, international country picker with their numbers, just look at the picture, I think it would be clear what clients wants.

He wants us to hide Address, Latitude and Longitude fields from single Market and add new field which is going to be a search (Google Maps) for places in 5 countries, so its should be same search like this below, just this field. And when user selects place, then fields Address, Latitude and Longtitude fields should be FILLED with values of place that user selected.

And please tell me how much you would charge for this update?

Little Bag final fixes

2. Single Market fixes:

Minimum for delivery” field should not be mandatory (required) and it should have default value of 0 (zero). And if user forgets to enter it and save market, it should have value 0.0 in API.

Put this sound for notification sound!!

5. When you done, I need access to GitHub repository, or you can sent me complete updated project and I will upload on GitHub and also RESET order counters.

Privacy Policy for AppTailor

At AppTailor, accessible from https://apptailor.io, one of our main priorities is the privacy of our visitors. This Privacy Policy document contains types of information that is collected and recorded by AppTailor and how we use it.

If you have additional questions or require more information about our Privacy Policy, do not hesitate to contact us.

This Privacy Policy applies only to our online activities and is valid for visitors to our website with regards to the information that they shared and/or collect in AppTailor. This policy is not applicable to any information collected offline or via channels other than this website.

Consent

By using our website, you hereby consent to our Privacy Policy and agree to its terms.

Information we collect

The personal information that you are asked to provide, and the reasons why you are asked to provide it, will be made clear to you at the point we ask you to provide your personal information.

If you contact us directly, we may receive additional information about you such as your name, email address, phone number, the contents of the message and/or attachments you may send us, and any other information you may choose to provide.

When you register for an Account, we may ask for your contact information, including items such as name, company name, address, email address, and telephone number.

How we use your information

We use the information we collect in various ways, including to:

  • Provide, operate, and maintain our webste
  • Improve, personalize, and expand our webste
  • Understand and analyze how you use our webste
  • Develop new products, services, features, and functionality
  • Communicate with you, either directly or through one of our partners, including for customer service, to provide you with updates and other information relating to the webste, and for marketing and promotional purposes
  • Send you emails
  • Find and prevent fraud

Log Files

AppTailor follows a standard procedure of using log files. These files log visitors when they visit websites. All hosting companies do this and a part of hosting services’ analytics. The information collected by log files include internet protocol (IP) addresses, browser type, Internet Service Provider (ISP), date and time stamp, referring/exit pages, and possibly the number of clicks. These are not linked to any information that is personally identifiable. The purpose of the information is for analyzing trends, administering the site, tracking users’ movement on the website, and gathering demographic information. Our Privacy Policy was created with the help of the Privacy Policy Generator and the Disclaimer Generator.

Cookies and Web Beacons

Like any other website, AppTailor uses ‘cookies’. These cookies are used to store information including visitors’ preferences, and the pages on the website that the visitor accessed or visited. The information is used to optimize the users’ experience by customizing our web page content based on visitors’ browser type and/or other information.

For more general information on cookies, please read “What Are Cookies”.

Advertising Partners Privacy Policies

You may consult this list to find the Privacy Policy for each of the advertising partners of AppTailor.

Third-party ad servers or ad networks uses technologies like cookies, JavaScript, or Web Beacons that are used in their respective advertisements and links that appear on AppTailor, which are sent directly to users’ browser. They automatically receive your IP address when this occurs. These technologies are used to measure the effectiveness of their advertising campaigns and/or to personalize the advertising content that you see on websites that you visit.

Note that AppTailor has no access to or control over these cookies that are used by third-party advertisers.

Third Party Privacy Policies

AppTailor’s Privacy Policy does not apply to other advertisers or websites. Thus, we are advising you to consult the respective Privacy Policies of these third-party ad servers for more detailed information. It may include their practices and instructions about how to opt-out of certain options.

You can choose to disable cookies through your individual browser options. To know more detailed information about cookie management with specific web browsers, it can be found at the browsers’ respective websites.

CCPA Privacy Rights (Do Not Sell My Personal Information)

Under the CCPA, among other rights, California consumers have the right to:

Request that a business that collects a consumer’s personal data disclose the categories and specific pieces of personal data that a business has collected about consumers.

Request that a business delete any personal data about the consumer that a business has collected.

Request that a business that sells a consumer’s personal data, not sell the consumer’s personal data.

If you make a request, we have one month to respond to you. If you would like to exercise any of these rights, please contact us.

GDPR Data Protection Rights

We would like to make sure you are fully aware of all of your data protection rights. Every user is entitled to the following:

The right to access – You have the right to request copies of your personal data. We may charge you a small fee for this service.

The right to rectification – You have the right to request that we correct any information you believe is inaccurate. You also have the right to request that we complete the information you believe is incomplete.

The right to erasure – You have the right to request that we erase your personal data, under certain conditions.

The right to restrict processing – You have the right to request that we restrict the processing of your personal data, under certain conditions.

The right to object to processing – You have the right to object to our processing of your personal data, under certain conditions.

The right to data portability – You have the right to request that we transfer the data that we have collected to another organization, or directly to you, under certain conditions.

If you make a request, we have one month to respond to you. If you would like to exercise any of these rights, please contact us.

Children’s Information

Another part of our priority is adding protection for children while using the internet. We encourage parents and guardians to observe, participate in, and/or monitor and guide their online activity.

AppTailor does not knowingly collect any Personal Identifiable Information from children under the age of 13. If you think that your child provided this kind of information on our website, we strongly encourage you to contact us immediately and we will do our best efforts to promptly remove such information from our records.

Flutter deep linking

In this tutorial we will go over dynamic link usage in Flutter. We’ll cover what dynamic links are, why you would use them and how to use them in your Flutter code base. This is episode 9 of the Firebase and Flutter series. If you didn’t follow along the series you download the starting code that we’ll use for this tutorial.

What is the problem we’re trying to solve?

Lets say you can share a link to a post of something from your app. You share that link through what’s app (iMessage for my USA friends and WeChat for the Chinese devs). When a user taps on that app wouldn’t it be great if you could customise their experience. For instance:

  1. Tapping the link in Android should open your app, if it’s installed, navigate to that post and show it to the user.
  2. Tapping the link and it’s not installed should take the user to the store. After installing wouldn’t it be great if you can still do 1.
  3. If the user opens the link on Desktop you can open your website for them and take them to the post.

If you’ve implemented this or tried to implement it you know how difficult it is to keep track of something as simple as clicking a promo link, app is not installed so you go to the store, once the user has downloaded the app you need to figure out how to see which link they clicked to perform appropriate action in the app. It’s quite a mission. This is what Dynamic links solve.

Dynamic links is a service provided by firebase that takes care of all of that for you. You can create your links in the console or programatically and share them with other users. They allow you to define the action to take per platform and tailor the experience exactly how you want it to be. Per platform, it also automatically tracks how many people clicked the link, the platform they were on and if they completed the intended action. In short, dynamic links is a smart link. It it handled different on each platform but you can choose how it’s handled.

Implementation

The project we are using already has the firebase project setup for communication for the Android project. No firebase project setup will be done in this tutorial. Episode one covers that if you still have to setup your project. In this tutorial we will cover the following things.

  1. Creating a dynamic link in the console
  2. Handling it in the application
  3. Checking the deeplink url and perform navigations
  4. Create a dynamic link programatically
  5. Debug deeplink and behaviour tips

Lets get started.

Navigate to the Firebase Console, open up your project. In the left navigation bar scroll down to the complete bottom and click on Dynamic links. Click on get started and press next with the default values until you see the following screen.

Empty Dynamic Links UI

You will be given a default prefix or you can enter your own based on your project name. Click on the “New Dynamic Link” button. You will be presented with 5 steps.

  1. Supply your short url: Enter “create-first-post” and check to see your Link preview looks like this https://filledstacks.page.link/create-first-post . With your prefix ofcourse. Go next.
  2. Supply your dynamic link url: This has to be a valid url that the browser can navigate to. It’s also the link that will be retrieved in your app, this is what you’ll use to pass params that you’ll need for deeplinking. I’ll set mine to the following. https://www.compound.com/post?title=This+is+my+first+post .We will extract the title query param in the code to perform our deep link. I’ll set the Dynamic Link Name to “Create First Post”
  3. iOS Behavior: Select “Open deep link Url in Browser”. This is the link from 2.
  4. Android Behaviour: Select “Open the deep link in your Android App”. Select your current firebase app. I’ll select com.filledstacks.compound. THIS HAS TO MATCH YOUR APP ID. This is how we tell firebase which app to link the deeplink info to. 4a. What happens if app is not installed: Select “Google Play page for your app”. If your app is on the store with a matching Id it will open the store for installation. To avoid having to put an app into the store for testing I will skip the testing of this part in this tutorial. There are more advanced settings that you can cover in your own time if you require them.
  5. Campaign tracking: We won’t enter any details here. This is where you’d track which links you’re sending and which campaigns they belong to.

Create the link. When it’s completed you should see something like below when you go to hover over the URL link.

Dynamic Link Copy Action

That is the link that will be used when sharing the link anywhere. On the right side there are three dots that you can press for additional options. You can view the details and edit them, we’ll checkout the link preview later.

Lets move onto the actual implementation. To implement dynamic links in Flutter we’ll make use of the firebase_dynamic_links package. Open your pubspec.yaml file and add it as a dependency.

firebase_dynamic_links: ^0.5.0+11

Under the services folder create a new file called dynamic_link_service.dart. We’ll create a Future called handleDynamicLinks. This is where we’ll check if there’s an initialLink that the app has been opened with and handle it and we’ll register the onLink function with a success and error callback function. These functions will ONLY be fired if the app is opened from the background or suspended state using the deeplink. The register call can be split from the handleDynamicLinks call but for this example I’m leaving it in one function since it’s not that much code.

class DynamicLinkService {
    Future handleDynamicLinks() async {
    // 1. Get the initial dynamic link if the app is opened with a dynamic link
    final PendingDynamicLinkData data =
        await FirebaseDynamicLinks.instance.getInitialLink();

    // 2. handle link that has been retrieved
    _handleDeepLink(data);

    // 3. Register a link callback to fire if the app is opened up from the background
    // using a dynamic link.
    FirebaseDynamicLinks.instance.onLink(
        onSuccess: (PendingDynamicLinkData dynamicLink) async {
      // 3a. handle link that has been retrieved
      _handleDeepLink(dynamicLink);
    }, onError: (OnLinkErrorException e) async {
      print('Link Failed: ${e.message}');
    });
  }

  void _handleDeepLink(PendingDynamicLinkData data) {
    final Uri deepLink = data?.link;
    if (deepLink != null) {

      print('_handleDeepLink | deeplink: $deepLink');
    }
  }
}

Then we’ll register the DynamicLinkService. Go to the locator.dart file and register the service as a singleton instance.

locator.registerLazySingleton(() => DynamicLinkService());

And the last step for the setup is to go to the StartupViewModel and call the handleDynamicLinks function.

class StartUpViewModel extends BaseModel {
  ...
  // get the dynamic link service
  final DynamicLinkService _dynamicLinkService = locator<DynamicLinkService>();

  Future handleStartUpLogic() async {
    // call handle dynamic links
    await _dynamicLinkService.handleDynamicLinks();
    await _pushNotificationService.initialise();
    ...
  }
}

At this point you can run the app. Once the app has installed and opened up you can click on My Firebase dynamic link on the same device you installed the app. It will open the webview for a second or two, then close it down and open your app. When the app is opened and you’re still connected to the debug logs you’ll see the message below.

_handleDeepLink | deeplink: https://www.compound.com/post?title=This+is+my+first+post

This means everything is working fine and we’re ready to perform a deeplink operation.

Now we can add the functionality to the _handleDeepLink function to perform the actions we want to in the app. We want the app to navigate to the CreatePostView and fill in the title we added into the link. To do that we’ll have to get the NavigationService from the locator and then do some basic url string checks.

class DynamicLinkService {
  final NavigationService _navigationService = locator<NavigationService>();

  ...

  void _handleDeepLink(PendingDynamicLinkData data) {
    final Uri deepLink = data?.link;
    if (deepLink != null) {
      print('_handleDeepLink | deeplink: $deepLink');

      // Check if we want to make a post
      var isPost = deepLink.pathSegments.contains('post');

      if (isPost) {
        // get the title of the post
        var title = deepLink.queryParameters['title'];

        if (title != null) {
          // if we have a post navigate to the CreatePostViewRoute and pass in the title as the arguments.
          _navigationService.navigateTo(CreatePostViewRoute, arguments: title);
        }
      }
    }
  }
}

That’s all there is for the service. The way you’ll handle more going forward is simply by adding more checks. To close down this implementation you could establish a convention and allow the links to navigate to any of your views in the app without you having the change the code. If you pass a route query parameter you can do something like below.

void _handleDeepLink(PendingDynamicLinkData data) {
  final Uri deepLink = data?.link;
  if (deepLink != null) {
    print('_handleDeepLink | deeplink: $deepLink');

    var navigationRoute = deepLink.queryParameters['route'];

    var params = deepLink.queryParameters['params'];
    if (params != null) {
      _navigationService.navigateTo(navigationRoute, arguments: params);
    }
  }
}

Once you and your team establish a convention for the links and what data you’d expect to pass in then you can set it up so you never touch this service again. The last past of this implementation is to make the CreatePostView aware that we’ll be sending it a title to show. Open up the router.dart file and update the CreatePostViewRoute case to the following.

 case CreatePostViewRoute:
    String postTitle;
    Post postToEdit;

    // if it's a string we set postTitle
    if (settings.arguments is String) {
      postTitle = settings.arguments;
    }
    // if it's a post we set post to edit
    else if (settings.arguments is Post) {
      postToEdit = settings.arguments as Post;
    }

    return _getPageRoute(
      routeName: settings.name,
      viewToShow: CreatePostView(
        edittingPost: postToEdit,
        postTitle: postTitle,
      ),
    );

We check what type the arguments are and then set those values. We pass both to the CreatePostView through the constructor. Open up the CreatePostView class. We’ll update the constructor to take in a new String postTitle. We’ll

class CreatePostView extends StatelessWidget {
  ...
  final Post edittingPost;
  final String postTitle;
  CreatePostView({
    Key key,
    this.edittingPost,
    this.postTitle,
  }) : super(key: key);


  @override
  Widget build(BuildContext context) {
    return ViewModelProvider<CreatePostViewModel>.withConsumer(
      viewModel: CreatePostViewModel(),
      onModelReady: (model) {
        // If we have a post to edit, run edit logic
        if (edittingPost != null) {
          titleController.text = edittingPost?.title ?? '';

          model.setEdittingPost(edittingPost);
        }
        // if we have a title then set the title equal to the value passed in
        else if (postTitle != null) {
          titleController.text = postTitle;
        }
      },
    ...);
  }
}

And that’s it. If you run the app now, close the app and open the dynamic link you’ll navigate straight to the CreatePostView with the link title entered.

This is also quite a straight forward task. Remember those 5 things you had to to when creating a dynamic link in the console, you do that but in code. In the DynamicLinkService create a new function that returns a future called createFirstPostLink that takes in a String title to share. In this function we will define all the dynamic link parameters and return the Uri.toString() as the result to the caller

Future<String> createFirstPostLink(String title) async {
    final DynamicLinkParameters parameters = DynamicLinkParameters(
      uriPrefix: 'https://filledstacks.page.link',
      link: Uri.parse('https://www.compound.com/post?title=$title'),
      androidParameters: AndroidParameters(
        packageName: 'com.filledstacks.compound',
      ),
      // NOT ALL ARE REQUIRED ===== HERE AS AN EXAMPLE =====
      iosParameters: IosParameters(
        bundleId: 'com.example.ios',
        minimumVersion: '1.0.1',
        appStoreId: '123456789',
      ),
      googleAnalyticsParameters: GoogleAnalyticsParameters(
        campaign: 'example-promo',
        medium: 'social',
        source: 'orkut',
      ),
      itunesConnectAnalyticsParameters: ItunesConnectAnalyticsParameters(
        providerToken: '123456',
        campaignToken: 'example-promo',
      ),
      socialMetaTagParameters: SocialMetaTagParameters(
        title: 'Example of a Dynamic Link',
        description: 'This link works whether app is installed or not!',
      ),
    );

    final Uri dynamicUrl = await parameters.buildUrl();

    return dynamicUrl.toString();
}

That’s about it. When you want to add a feature where you can share it with a friend for them to make a first post you can add UI to type a title and then share the link with them with a title that you put in for the post.

If you’re having trouble figuring out what your dynamic link will be doing in certain scenarios you can open up the firebase console, go to the link. On the far right side there’s 3 dots where you can get a context menu and click on “Link Preview Debug”. This will show you a visual of how your link will behave per platform like below.

Firebase Dynamic Link Preview

Here you can see what it’s doing. You’ll also have warnings at the top of your link that will give tips for production use and pointers as to what features might be disabled based on your configuration. It will also provide you with clickable links at the end of each navigation path that you can checkout before launching the dynamic link into the wild.

That’s basically it. Using the deep link technique you can get to anywhere in your app with the correct parameters and provide the user with the best experience possible when they click your links.

Big Data Tools, & Frameworks

We were Inpulse and these were the ideals that we strived to uphold. In the end, it was the talented people and the unmatched work they did that mattered the most…
Legwork lives on in the things we created, our memories, shared experiences and, so we don’t forget, here for good measure. It has truly been an amazing decade–goodbye.

Augmented Reality Platform

We were Inpulse and these were the ideals that we strived to uphold. In the end, it was the talented people and the unmatched work they did that mattered the most…
Legwork lives on in the things we created, our memories, shared experiences and, so we don’t forget, here for good measure. It has truly been an amazing decade–goodbye.

Art Conference Events

We were Inpulse and these were the ideals that we strived to uphold. In the end, it was the talented people and the unmatched work they did that mattered the most…
Legwork lives on in the things we created, our memories, shared experiences and, so we don’t forget, here for good measure. It has truly been an amazing decade–goodbye.