Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial state of PermissionsController for geolocation doesn't seem to reflect its real state on pageload #32

Open
TonySpegel opened this issue Jul 24, 2024 · 2 comments

Comments

@TonySpegel
Copy link
Contributor

TonySpegel commented Jul 24, 2024

Hi there!

I was just about to use the PermissionController to be able to work with the geolocations or to display the UI in a slightly different way depending on the state. I'm not sure if I'm doing something wrong or not, but the initial state doesn't seem to correspond to the actual state. I followed the demo in the docs and added some UI with help from lit/task, both in Chrome and Firefox the initial state after I open the page is “prompt” no matter if the permission was granted or denied.

I've got a reproduction repository (you can just run npm run dev) and also a github page with a demo

gps-permission-2024-07-24_22.29.10.mp4

and also my code inline here:

import { html, LitElement, TemplateResult } from 'lit';
import { customElement, state } from 'lit/decorators.js';

import { PermissionsController } from 'relit';
import { Task } from '@lit/task';
import { choose } from 'lit/directives/choose.js';

type coords = Pick<GeolocationCoordinates, 'latitude' | 'longitude'>;

@customElement('app-permission')
export class AppHome extends LitElement {
  @state()
  latitude: number | undefined = 52.522138048058856;

  @state()
  longitude: number | undefined = 13.394977670545542;

  private _geoPermissionController = new PermissionsController(
    this,
    'geolocation'
  );

  private _getGpsPosition(
    options: PositionOptions = { enableHighAccuracy: true }
  ): Promise<coords> {
    return new Promise((resolve, reject) => {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const { latitude, longitude } = position.coords;
          resolve({ latitude, longitude });
        },
        (error) => reject(error),
        options
      );
    });
  }

  private _gpsPositionTask = new Task(this, {
    task: () => this._getGpsPosition(),
    onComplete: (coords) => {
      this.latitude = coords.latitude;
      this.longitude = coords.longitude;
    },
    autoRun: false,
    args: () => [this.latitude, this.longitude] as const,
  });

  private _permissionPending = () => {
    return html`
      <sl-button
        @click=${() => {
          this._gpsPositionTask.run();
        }}
      >
        Ask for location permission
      </sl-button>
    `;
  };

  private _permissionDenied = () => html`
    <sl-button variant="warning">we got a problem</sl-button>
  `;

  private _permissionGranted = () => html`
    <sl-button @click=${() => this._gpsPositionTask.run()} variant="primary">
      Get GPS Position
    </sl-button>
  `;

  private _gpsButtonTemplate = (state: PermissionState) => html`
    ${choose<PermissionState, TemplateResult>(state, [
      ['prompt', () => this._permissionPending()],
      ['granted', () => this._permissionGranted()],
      ['denied', () => this._permissionDenied()],
    ])}
  `;

  render() {
    return html`
      <h2>Permission works</h2>
      <p>${this._geoPermissionController.state}</p>

      ${'geolocation' in navigator
        ? this._gpsButtonTemplate(this._geoPermissionController.state)
        : null}
    `;
  }
}

btw it doesn't seem to matter where or when the state is obtained.

I'm sorry if I misunderstood or misused something, thanks for the help :) and let me know if I can provide more details!

Edit: added a demo

@43081j
Copy link
Owner

43081j commented Jul 25, 2024

i think its a bug and we should explicitly call this.__host.requestUpdate() in the bottom of initialisePermissions

would you be open to contributing it?

should be as simple as this:

    async __initialisePermissions(name) {
        this.__status = await navigator.permissions.query({ name });
        this.__status.addEventListener('change', this.__onPermissionChanged);
        this.__host.requestUpdate(); // <- this line fixes it i think
    }

and adding a test for that (by somehow mocking the query to be granted and ensuring it renders the right value)

@TonySpegel
Copy link
Contributor Author

I'll give it a go :)! Will have a look at it after waking up today ✌️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants