Force footer-nav with cookie

Hello,
I am in the process of creating an app for my forum for iOS devices. Fortunately, there is a project called PWABuilder that provides a ready-made XCode project to package a webapp into an app. This has also worked great with my Discourse forum, however there is no back button or anything like that which would make navigation easier.

iOS App generated with PWABuilder (no navigation footer):

There is a footer bar on the iOS PWA though, where there is a back button. I haven’t found a way to display this outside of the iOS PWA yet though.

iOS PWA has navigation footer but can’t be forced outside it (I didn’t find an easy way):

Now my question is: Could this footer also be displayed inside a WKWebView? I also have an idea how to solve it. Apps generated with PWABuilder have the functionality to set a cookie when used. How about displaying this navigation footer whenever the user has a cookie like “mobile_footer_nav”? Then the problem would be solved.

Settings that can be set within an app generated with PWABuilder (cookie on app use)

I would be very happy if the development team could take a look at this.

(I know there is the DiscourseHub app, but a separate app for a forum is the more elegant option and easier for a user to use and understand.)

1 Like

Discourse renders that footer based on some conditions. The footer is added here.

discourse/application.hbs at a0bbc346cb5d5b89d1a3efdfa89869349a8b067f · discourse/discourse · GitHub

showFooterNav is defined here.

discourse/application.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub

If either of those is true, the nav will be displayed.

isiOSPWA() and isAppWebview() are defined here

discourse/utilities.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub

For example, isAppWebview() looks like this.

discourse/utilities.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub

You can create an additional condition in your theme - in your Discourse site - to check for the cookie, like so

const isWKWebView = () => {
  // check for the cookie and return true if it exists
  // or use any other method to detect if the user is using your application
}

For other Classes, you would normally then be able to modify the showFooterNav() like so

api.modifyClass("controller:application", {
  pluginId: "show-footer-nav",
  @discourseComputed
  showFooterNav() {
    // ...
  }
});

However, this is the application controller, which means that it will be cached before your code gets a chance to execute. In other words, you won’t be able to modify the Class.

That said, you can still change the showFooterNav value with something like this.

<script type="text/discourse-plugin" version="0.8">
  const isWKWebView = () => {
    // check and return your condition
  };

  if (isWKWebView()) {
    const applicationController = api.container.lookup("controller:application");
    applicationController.set("showFooterNav", true);
  }
</script>

in the header tab of your theme or in an initializer if you’re using a remote theme.

5 Likes

Thank you very much for the quick help. Unfortunately I get an error.

I wrote these lines of code in the header of the theme and also added the cookie check ability in isWKWebView(). If I don’t have the cookie nothing happens. This works for now. But if I have the cookie, this bar is unfortunately not displayed and an error is displayed in the console “TypeError: Attempted to assign to readonly property.”

1 Like

I kind of only tried this locally, so maybe that’s why.

Try using

applicationController.set("showFooterNav", true);

instead of

applicationController.showFooterNav = true;

I’ll edit the post with that change.

2 Likes

It works perfectly! Thank you very much :slight_smile:

My final code:

<script type="text/discourse-plugin" version="0.8">
function getCookie(cname) {
  let name = cname + "=";
  let decodedCookie = decodeURIComponent(document.cookie);
  let ca = decodedCookie.split(';');
  for(let i = 0; i <ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

if (getCookie("app-platform") != "") {
    const applicationController = api.container.lookup("controller:application");
    applicationController.set("showFooterNav", true);
}
</script>
2 Likes