Y a-t-il un moyen d'écouter l'événement de connexion de l'utilisateur en utilisant le composant Theme

Bonjour à tous,

Je souhaite afficher une boîte de dialogue (Popup) en utilisant le composant Theme lors de la première connexion de l’utilisateur.

1. J’ai essayé de remplacer l’action de connexion du contrôleur de connexion en utilisant le composant Theme pour afficher la boîte de dialogue une fois l’utilisateur connecté avec succès. Dans l’action de connexion, j’ai ajouté le code bootbox.alert(“Test Alert”); avant hiddenLoginForm.submit();.

Cependant, la boîte de dialogue s’affiche uniquement après que le formulaire hiddenLoginForm a été soumis et que la redirection vers la page d’accueil a eu lieu.

Ma demande est que la boîte de dialogue s’affiche après la redirection vers la page d’accueil, suite à une connexion réussie.

2. Pour vérifier si l’utilisateur se connecte pour la première fois, j’ai essayé de contrôler la valeur de la propriété previous_visit_at de l’utilisateur actuel. Si previous_visit_at est null (c’est-à-dire que l’utilisateur se connecte pour la première fois).

Mais ici aussi, mon test échoue : lorsque je me connecte une deuxième fois, la valeur de la propriété previous_visit_at est toujours null. Je souhaite savoir exactement à quel moment la valeur de la propriété previous_visit_at est mise à jour.

Pourriez-vous m’aider à réaliser ces exigences ?

Merci,
Saurabh Khandelwal

Salut @Saurabh_Khandelwal :wave:

Je vous déconseille de procéder ainsi ; la connexion est l’une des actions les plus critiques, et toute modification de cette action sera fragile et susceptible de se briser si nous apportons des changements dans cette zone du noyau.

Si vous vous en souvenez, lors de votre première inscription sur ce site, vous avez vu quelque chose comme ceci.

Les conditions que nous utilisons pour vérifier cela sont

!user.read_first_notification && !user.enforcedSecondFactor

Ainsi, si vous utilisez les mêmes conditions dans un initialiseur, vous pourrez afficher une boîte Bootbox lors de la toute première vue de page de l’utilisateur après la connexion.

Vous pouvez essayer quelque chose comme ceci dans votre composant de thème.

import { withPluginApi } from "discourse/lib/plugin-api";
import bootbox from "bootbox";

export default {
  name: "first-login-bootbox",
  initialize() {
    withPluginApi("0.8", api => {
      const user = api.getCurrentUser();
      if (!user) return;

      if (!user.read_first_notification && !user.enforcedSecondFactor) {
        const text = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor`;
        bootbox.alert(text);
      }
    });
  }
};

Cela vous donnera quelque chose comme ceci

Vous pouvez utiliser du HTML dans le texte de la boîte Bootbox si nécessaire. Une fois que l’utilisateur ferme la boîte Bootbox et clique sur l’avatar entouré, il ne verra plus jamais la boîte Bootbox.

Veuillez noter que les boîtes Bootbox sont destinées à des dialogues ou confirmations simples. Si vous avez besoin de quelque chose de légèrement plus complexe, il est probablement préférable d’utiliser une fenêtre modale avec showModal().

Merci, @Johani, pour vos conseils. Je vais éviter de modifier l’action de connexion et essayer de mettre en œuvre ce que vous mentionnez.

.

Bonjour, @Johani, j’ai ajouté un simple lien hypertexte (par exemple “/new-topic”) dans la fenêtre contextuelle, qui s’ouvre dans un nouvel onglet.

Lorsque je clique sur ce lien, il s’ouvre bien dans un nouvel onglet, mais la fenêtre contextuelle s’affiche à nouveau car nous vérifions les conditions suivantes :

!user.read_first_notification && !user.enforcedSecondFactor

Dans mon cas, la fenêtre contextuelle ne devrait pas s’afficher après avoir visité le lien.

Pouvons-nous mettre à jour les valeurs de ces propriétés une fois la fenêtre contextuelle affichée pour la première fois ? Si oui, comment pouvons-nous procéder ?

Je crains que cela ne soit pas possible.

Ces propriétés n’ont pas de setters ; même si elles en avaient, vos modifications ne s’appliqueraient que temporairement dans la première fenêtre. Une fois que l’utilisateur visite le deuxième onglet, les données seront basées sur ce qui est stocké dans la base de données. Les thèmes n’ont pas accès au backend ; ils ne peuvent modifier que le frontend.

Ce que vous pouvez faire, c’est ajouter un hachage à votre lien et le vérifier comme ceci.

import { withPluginApi } from "discourse/lib/plugin-api";
import bootbox from "bootbox";

export default {
  name: "first-login-bootbox",
  initialize() {
    withPluginApi("0.8", api => {
      const user = api.getCurrentUser();
      if (!user) return;

      if (
        !user.read_first_notification &&
        !user.enforcedSecondFactor &&
        !window.location.hash
      ) {
        const text = `Lorem ipsum dolor sit amet <a href="http://localhost:3000/new-topic#some-hash" target="_blank">Lien</a>, consectetur adipiscing elit, sed do eiusmod tempor`;
        bootbox.alert(text);
      }
    });
  }
};

Je ne sais pas si le lien vers “/new-topic” dans votre message était juste un exemple ou si c’est ce que vous souhaitez faire. Si c’est le résultat souhaité, alors vous avez un autre problème. Même si la boîte bootbox n’est pas affichée sur la page avec le hachage, ils verront toujours ceci…

…et le compositeur ne s’ouvrira pas, ce qui est logique car il est très inattendu pour un utilisateur de commencer à rédiger un sujet dès sa toute première vue de page.

Pourrais-je savoir ce que vous essayez d’accomplir ici ? Cherchez-vous à informer l’utilisateur d’une chose ou d’une autre ?

La manière dont j’ai vu cela être fait sur d’autres sites consiste à modifier le message de bienvenue, mais si c’est une option, il existe des alternatives.

Voici ce que je suggère :

  1. Créez un sujet et ajoutez-y toutes les informations que vous souhaitez.
  2. Publiez ce sujet.
  3. Liez ce sujet dans la boîte bootbox et ouvrez ce lien dans un nouvel onglet.

De cette façon, lorsque l’utilisateur cliquera sur le lien, il verra quelque chose comme ceci (sans la superposition)

Une fois qu’il aura terminé sur cette page, il pourra revenir au premier onglet, fermer la boîte bootbox, lire la première notification, puis continuer à utiliser le site.

De cette manière, vous n’avez même pas besoin d’ajouter ou de vérifier un hachage. Voici un exemple de snippet :

import { withPluginApi } from "discourse/lib/plugin-api";
import bootbox from "bootbox";

export default {
  name: "first-login-bootbox",
  initialize() {
    withPluginApi("0.8", api => {
      const user = api.getCurrentUser();
      if (!user) return;

      if (!user.read_first_notification && !user.enforcedSecondFactor) {
        const text = `Lorem ipsum dolor sit amet <a href="http://my.site.com/pub/bentley-flying-spur-s-production-milestone" target="_blank">Lien</a>, consectetur adipiscing elit, sed do eiusmod tempor`;
        bootbox.alert(text);
      }
    });
  }
};

Je souhaite inclure des liens tels que “/new-topic” et “/my/preferences” dans la fenêtre contextuelle.

Sinon, je pensais afficher la fenêtre contextuelle uniquement sur la page d’accueil en vérifiant l’URL actuelle.
Ainsi, lors de la visite d’autres pages, la fenêtre contextuelle ne sera pas affichée.

Même si je vérifie l’URL de la page d’accueil après avoir cliqué sur le lien « /new-topic », le problème ci-dessus se produira.

Bonjour Saurabh,
Oui, je pense que vérifier l’URL actuelle et afficher la fenêtre contextuelle uniquement sur la page d’accueil devrait fonctionner..

Nous pouvons afficher la présentation aux nouveaux utilisateurs de Discobot après un certain temps, par exemple 2 minutes :

Bonjour, @Johani

Pouvons-nous créer un widget comme illustré ci-dessous et appeler bootbox() à l’intérieur ?
Et après avoir appelé bootbox, pouvons-nous appeler la méthode “skipNewUserTips()”. Elle est également utilisée par Discourse dans le widget header-notifications.

<script type="text/discourse-plugin" version="0.8">
 const { h } = require('virtual-dom');
 const { ajax } = require("discourse/lib/ajax").default;
 const DiscourseURL =  require("discourse/lib/url");
 const { userPath } = require("discourse/lib/url");

api.createWidget("welcome-popup", {
  tagName: "div.welcome-popup",
  html(attrs) {
      let user = this.currentUser;
      if (!user) return;
      if (
        !user.get("read_first_notification") &&
        !user.get("enforcedSecondFactor")
      ) {
          const title = `<div class="first-login-bootbox-title">Vous êtes membre. Bienvenue à bord !</div>`;
          const body = `<div class="first-login-bootbox-body">Maintenant, vous pouvez : </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Poser une question ou lancer une discussion</a></li> <li><a href="/my/preferences/tags" target="_blank">Configurer vos paramètres de notification</a></li></ol></div>`;
          bootbox.alert({
                        title: title,
                        message: body
                    });
            this.skipNewUserTips();        
      }
      return null;
  },

  skipNewUserTips() {

    ajax(userPath(this.currentUser.username_lower), {
      type: "PUT",
      data: {
        skip_new_user_tips: true,
      },
    }).then(() => {
      this.currentUser.set("skip_new_user_tips", true);
    });
  },
});
</script>

<script
  type="text/x-handlebars"
  data-template-name="/connectors/below-site-header/welcome-popup"
>
  {{mount-widget widget="welcome-popup"}}
</script> 

Code Discourse pour le widget header-notifications :
https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/widgets/header.js#L101

Cela posera-t-il un problème ?

Cela ignore complètement cette superposition pour tous les nouveaux utilisateurs. Ils ne la verront donc jamais.

Si cela vous convient, alors oui, cela devrait fonctionner.

Vous devez toutefois modifier l’appel à bootbox. Sinon, vous obtiendrez ceci :

au lieu de faire ceci

Vous ne devez passer qu’un seul argument.

Ces options ont été ajoutées dans des versions plus récentes de Bootbox et ne fonctionneront pas avec la version que nous utilisons actuellement dans Discourse (nous en discutons en interne, mais pour l’instant, vous ne pouvez pas les utiliser).

De plus, puisque vous créez une requête PUT, vous pouvez également ignorer ceci.

this.currentUser.set("skip_new_user_tips", true);

Donc, peut-être quelque chose comme ceci.

  api.createWidget("welcome-popup", {
    tagName: "div.welcome-popup",
    html(attrs) {
      let user = this.currentUser;
      if (!user) return;
      if (
        !user.get("read_first_notification") &&
        !user.get("enforcedSecondFactor")
      ) {
        const body = `<h2 class="first-login-bootbox-title">Vous êtes membre. Bienvenue à bord !</h2>
                      <hr>
                      <div class="first-login-bootbox-body">
                        Vous pouvez maintenant :
                        <br>
                        <ol class="user-suggestions">
                          <li>
                            <a href="/new-topic" target="_blank"
                              >Poser une question ou lancer une discussion</a
                            >
                          </li>
                          <li>
                            <a href="/my/preferences/tags" target="_blank"
                              >Configurer vos paramètres de notification</a
                            >
                          </li>
                        </ol>
                      </div>`;
        bootbox.alert(body);
        this.skipNewUserTips();
      }
      return null;
    },

    skipNewUserTips() {
      ajax(userPath(this.currentUser.username_lower), {
        type: "PUT",
        data: {
          skip_new_user_tips: true
        }
      });
    }
  });

Bonjour @Johani,

Comme nous avons défini skip_new_user_tips à true, la notification de bienvenue de Discobot est également ignorée. Il est acceptable que le masque de superposition de la première notification ne soit pas affiché, mais nous souhaitons conserver la notification de bienvenue de Discobot.

Notification Discobot :

Pour cela, nous avons modifié le code afin que la notification de bienvenue de Discobot soit chargée pour tous les nouveaux utilisateurs.
Nous avons ajouté une nouvelle méthode au widget d’en-tête nommée “closeFirstNotificationMask()” où nous définissons “ringBackdrop” à false et “userVisible” à son inverse. Nous appelons ensuite cette méthode après l’appel de la méthode bootbox dans le widget welcome-popup.

Nous nous sommes inspirés de la méthode “toggleUserMenu” du widget d’en-tête, qui est appelée lorsque l’icône Utilisateur est cliquée.

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.1/bootbox.min.js" integrity="sha512-eoo3vw71DUo5NRvDXP/26LFXjSFE1n5GQ+jZJhHz+oOTR4Bwt7QBCjsgGvuVMQUMMMqeEvKrQrNEI4xQMXp3uA==" crossorigin="anonymous"></script>

<script type="text/discourse-plugin" version="0.8">
 const { h } = require('virtual-dom');
 const { ajax } = require("discourse/lib/ajax").default;

/* Ajout d'une nouvelle méthode au widget d'en-tête qui sera appelée après l'affichage de la fenêtre Welcome-popup */
api.reopenWidget("header",{
    closeFirstNotificationMask() {
        this.state.ringBackdrop = false;
        this.state.userVisible = !this.state.userVisible;
        this.toggleBodyScrolling(this.state.userVisible);
    }
});

/* Création d'un nouveau widget "welcome-popup", ce widget ne sera rendu que lors de la première connexion de l'utilisateur */
api.createWidget("welcome-popup", {
  tagName: "div.welcome-popup",
  html(attrs) {
      let user = this.currentUser;
      if (!user) return;
      if ( !user.get("read_first_notification") && !user.get("enforcedSecondFactor") ) {
          const title = `<div class="first-login-bootbox-title">Vous êtes membre. Bienvenue à bord !</div>`;
          const body = `<div class="first-login-bootbox-body">Maintenant, vous pouvez : </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Poser une question ou lancer une discussion</a></li> <li><a href="/my/preferences/tags" target="_blank">Configurer vos paramètres de notification</a></li></ol></div>`;
          
          bootbox.alert({
                        title: title,
                        message: body
                    });
            // Appel de la méthode d'action closeFirstNotificationMask du widget d'en-tête
            this.sendWidgetAction("closeFirstNotificationMask", this.attrs);
        }
      return null;
  },
  
});

/* Le code ci-dessous rendra le widget "welcome-popup" après le rendu du widget "header-notifications" lors de la première connexion de l'utilisateur */
api.decorateWidget("header-notifications:after", helper => { 
    if(!helper.attrs.active && helper.attrs.ringBackdrop){
        return helper.attach("welcome-popup", helper.attrs);     
    }else{
        return null;    
    }
});
</script>

Une dernière chose : nous utilisons la version 5.4.1 de Bootbox en incluant le script ci-dessous dans notre composant de thème, car Discourse ne prend pas encore en charge la méthode bootbox multi-paramètres. Est-ce acceptable ?

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.1/bootbox.min.js" integrity="sha512-eoo3vw71DUo5NRvDXP/26LFXjSFE1n5GQ+jZJhHz+oOTR4Bwt7QBCjsgGvuVMQUMMMqeEvKrQrNEI4xQMXp3uA==" crossorigin="anonymous"></script>

Merci de nous donner votre avis, merci !

Cela semble bon :+1:

Je l’ai testé localement et je n’ai relevé aucun problème. J’ai apporté quelques modifications mineures.

<script
  src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.1/bootbox.min.js"
  integrity="sha512-eoo3vw71DUo5NRvDXP/26LFXjSFE1n5GQ+jZJhHz+oOTR4Bwt7QBCjsgGvuVMQUMMMqeEvKrQrNEI4xQMXp3uA=="
  crossorigin="anonymous"
></script>

<script type="text/discourse-plugin" version="0.8">
  const user = api.getCurrentUser();
  if (!user || user.read_first_notification || user.enforcedSecondFactor) {
    return;
  }

  const bootboxTitle = `<div class="first-login-bootbox-title">Vous êtes membre. Bienvenue à bord !</div>`;
  const bootboxBody = `<div class="first-login-bootbox-body">Désormais, vous pouvez : </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Poser une question ou lancer une discussion</a></li> <li><a href="/my/preferences/tags" target="_blank">Configurer vos paramètres de notification</a></li></ol></div>`;

  /* Ajout d'une nouvelle méthode au widget en-tête qui sera appelée après l'affichage de la fenêtre contextuelle de bienvenue */
  api.reopenWidget("header", {
    closeFirstNotificationMask() {
      this.state.ringBackdrop = false;
      this.state.userVisible = !this.state.userVisible;
    }
  });

  /* Création d'un nouveau widget "welcome-popup", ce widget ne sera rendu que lors de la première connexion de l'utilisateur */
  api.createWidget("welcome-popup", {
    tagName: "div.welcome-popup",
    html(attrs) {
      // Appel de la méthode d'action closeFirstNotificationMask du widget en-tête
      this.sendWidgetAction("closeFirstNotificationMask", attrs);

      bootbox.alert({
        title: bootboxTitle,
        message: bootboxBody
      });
    }
  });

  /* Le code ci-dessous rendra le widget "welcome-popup" après le rendu du widget "header-notifications" lors de la première connexion de l'utilisateur */
  api.decorateWidget("header-notifications:before", helper => {
    if (!helper.attrs.active && helper.attrs.ringBackdrop) {
      return helper.attach("welcome-popup", helper.attrs);
    }
  });
</script>

Oui, c’est acceptable. Discourse charge la version de bootbox que nous utilisons comme un shim, de sorte que charger une version différente dans votre composant de thème n’affectera rien au cœur du système. La nouvelle version ne sera utilisée que dans votre composant de thème. Le seul inconvénient est qu’elle ajoute une requête supplémentaire et environ 4 ko au chargement initial de la page.

Bonjour @Johani, comme vous avez chargé le widget welcome-popup avant le widget header-notifications, il semble que la notification de Discobot ne soit pas chargée. De plus, après avoir cliqué sur les liens dans welcome-popup, ce dernier s’affiche à nouveau à l’utilisateur.

Je l’ai testé en chargeant le widget welcome-popup après le widget header-notifications, et cela fonctionne correctement. Puis-je donc le modifier en “header-notifications:after” ?

C’est étrange :thinking:

Je viens de retenter le même code avec 3 nouveaux utilisateurs différents, et j’obtiens le résultat attendu à chaque fois. La popup apparaît lors de la première visite de la page, et le message de bienvenue du Discobot est envoyé. Les visites suivantes ne montrent plus la popup.

Bien sûr, si cela fonctionne pour vous, l’emplacement du décorateur ne devrait pas avoir d’importance.

Merci @Johani, nous utiliserons le décorateur after.