Gibt es eine Möglichkeit, das User-Login-Ereignis über die Theme-Komponente abzurufen?

Hallo zusammen,

ich möchte das Popup-Fenster über die Theme-Komponente anzeigen, wenn sich ein Benutzer zum ersten Mal anmeldet.

1. Ich habe versucht, die Login-Aktion des Login-Controllers mit der Theme-Komponente zu überschreiben, um das Popup-Fenster nach einer erfolgreichen Anmeldung anzuzeigen. In der Login-Aktion habe ich den Code bootbox.alert(“Test Alert”); vor hiddenLoginForm.submit(); eingefügt.

Das Popup wird jedoch erst angezeigt, nachdem hiddenLoginForm abgesendet wurde und die Weiterleitung zur Startseite erfolgt ist.

Mein Ziel ist es, dass das Popup-Fenster erst nach der Weiterleitung zur Startseite nach erfolgreicher Anmeldung angezeigt wird.

2. Um zu prüfen, ob sich ein Benutzer zum ersten Mal anmeldet, habe ich versucht, den Wert der Eigenschaft previous_visit_at des aktuellen Benutzers zu überprüfen. Wenn previous_visit_at = null ist (d. h. der Benutzer meldet sich zum ersten Mal an), sollte dies der Fall sein. Doch auch hier schlägt mein Test fehl: Wenn ich mich ein zweites Mal anmelde, ist der Wert der Eigenschaft previous_visit_at weiterhin null. Ich möchte wissen, wann genau der Wert der Eigenschaft previous_visit_at aktualisiert wird.

Bitte helfen Sie mir, die oben genannten Anforderungen umzusetzen.

Vielen Dank,
Saurabh Khandelwal

Hey @Saurabh_Khandelwal :wave:

Ich würde davon abraten, dies auf diese Weise zu tun; Login ist eine der kritischsten Aktionen, und jegliche Überschreibungen dieser Aktion sind fragil und anfällig für Fehler, falls wir Änderungen im Kernbereich vornehmen.

Wenn du dich erinnerst, hast du beim ersten Registrieren auf dieser Seite etwas wie folgendes gesehen.

Die Bedingungen, die wir verwenden, um dies zu prüfen, sind:

!user.read_first_notification && !user.enforcedSecondFactor

Wenn du also dieselben Bedingungen in einem Initialisierer verwendest, kannst du ein Bootbox beim allerersten Seitenaufruf des Benutzers nach dem Login rendern.

Du kannst etwas Ähnliches in deiner Theme-Komponente ausprobieren:

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);
      }
    });
  }
};

Das wird dir etwas wie folgendes anzeigen:

Du kannst bei Bedarf HTML im Text des Bootbox verwenden. Sobald der Benutzer das Bootbox schließt und auf das eingekreiste Avatar-Bild klickt, wird er das Bootbox nie wieder sehen.

Bitte beachte, dass Bootboxes für einfache Dialoge/Bestätigungen gedacht sind. Wenn du etwas etwas Komplexeres benötigst, ist es wahrscheinlich besser, ein Modal mit showModal() zu verwenden.

Danke, @Johani, für deinen Rat. Ich werde Änderungen in der Login-Aktion vermeiden und versuchen, es wie von dir erwähnt umzusetzen.

.

Hallo, @Johani, ich habe einen einfachen Hyperlink (z. B. “/new-topic”) in das Popup-Fenster eingefügt, der sich in einem neuen Tab öffnet.
Wenn ich auf diesen Link klicke, öffnet er sich zwar in einem neuen Tab, aber es wird erneut ein Popup-Fenster angezeigt, da wir die folgenden Bedingungen geprüft haben:

!user.read_first_notification && !user.enforcedSecondFactor  

In meinem Fall sollte das Popup-Fenster nach dem Besuch des Links nicht erneut angezeigt werden.

Können wir die Werte für diese Eigenschaften aktualisieren, nachdem das Popup-Fenster einmal angezeigt wurde? Wenn ja, wie können wir das umsetzen?

Ich fürchte, das ist nicht möglich.

Diese Eigenschaften haben keine Setter; selbst wenn sie welche hätten, würden Ihre Änderungen nur vorübergehend im ersten Fenster gelten. Sobald der Benutzer den zweiten Tab aufruft, basieren die Daten auf dem, was in der Datenbank gespeichert ist. Themes haben keinen Zugriff auf das Backend; sie können nur das Frontend ändern.

Was Sie tun können, ist, einen Hash zu Ihrem Link hinzuzufügen und diesen wie folgt zu prüfen.

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">Link</a>, consectetur adipiscing elit, sed do eiusmod tempor`;
        bootbox.alert(text);
      }
    });
  }
};

Ich bin mir nicht sicher, ob der Link zu „/new-topic

Ich möchte Links wie “/new-topic” und “/my/preferences” innerhalb eines Popups anzeigen.

Ansonsten habe ich überlegt, das Popup nur auf der Startseite anzuzeigen, indem ich die aktuelle URL überprüfe.
Beim Besuch anderer Seiten wird das Popup also nicht angezeigt.

[quote=“Johani, Beitrag:6, Thema:170976”]
Ich bin mir nicht sicher, ob der Link zu „/new-topic

Hallo Saurabh,
ja, ich denke, dass das Überprüfen der aktuellen URL und das Anzeigen des Pop-ups nur auf der Startseite funktionieren sollte.

Wir können die neue Benutzereinführung von Discobot nach einiger Zeit, z. B. nach 2 Minuten, anzeigen:

Hallo @Johani,

Können wir ein Widget wie unten gezeigt erstellen und darin bootbox() aufrufen?
Und können wir nach dem Aufruf von bootbox die Methode “skipNewUserTips()” aufrufen, die auch von Discourse im header-notifications-Widget verwendet wird.

<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">You're a member. Welcome aboard!</div>`;
          const body = `<div class="first-login-bootbox-body">Now you can: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank" >Ask a question or start a discussion</a></li> <li><a href="/my/preferences/tags" target="_blank">Set up your notification settings</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> 

Discourse-Code für das header-notifications-Widget:
https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/widgets/header.js#L101

Wird dies Probleme verursachen?

Dies überspringt dieses Overlay vollständig für alle neuen Benutzer. Sie werden es also nie sehen.

Wenn das für dich in Ordnung ist, dann ja, es sollte funktionieren.

Du musst jedoch den Bootbox-Aufruf ändern. Andernfalls erhältst du dies:

anstatt dies:

Du solltest nur ein einzelnes Argument übergeben.

Diese Optionen wurden zu neueren Versionen von Bootbox hinzugefügt und funktionieren nicht mit der Version, die wir derzeit in Discourse verwenden (wir diskutieren dies intern, aber vorerst kannst du sie nicht verwenden).

Da du außerdem eine PUT-Anfrage erstellst, kannst du dies ebenfalls überspringen.

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

Also vielleicht so etwas wie das hier.

  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">Du bist ein Mitglied. Willkommen an Bord!</h2>
                      <hr>
                      <div class="first-login-bootbox-body">
                        Jetzt kannst du:
                        <br>
                        <ol class="user-suggestions">
                          <li>
                            <a href="/new-topic" target="_blank"
                              >Eine Frage stellen oder eine Diskussion starten</a
                            >
                          </li>
                          <li>
                            <a href="/my/preferences/tags" target="_blank"
                              >Deine Benachrichtigungseinstellungen einrichten</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
        }
      });
    }
  });

Hallo @Johani,

Da wir skip_new_user_tips auf true gesetzt haben, wird auch die Discobot-Gruß-Benachrichtigung übersprungen. Es ist in Ordnung, wenn die erste Benachrichtigungs-Overlay-Maske nicht angezeigt wird, aber wir möchten die Discobot-Gruß-Benachrichtigung.

Discobot-Benachrichtigung:

Deshalb haben wir den Code so geändert, dass die Discobot-Gruß-Benachrichtigung für alle neuen Benutzer geladen wird.
Jetzt haben wir eine neue Methode zum Header-Widget hinzugefügt: “closeFirstNotificationMask()”, bei der wir “ringBackdrop” auf false und “userVisible” auf das Gegenteil davon setzen. Diese Methode rufen wir auf, nachdem wir die bootbox-Methode im welcome-popup-Widget aufgerufen haben.

Wir haben uns dabei an der “toggleUserMenu”-Methode des Header-Widgets orientiert, die aufgerufen wird, wenn auf das Benutzer-Symbol geklickt wird.

<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;

/* Neue Methode zum Header-Widget hinzufügen, die nach der Anzeige des Welcome-Popups aufgerufen wird */
api.reopenWidget("header",{
    closeFirstNotificationMask() {
        this.state.ringBackdrop = false;
        this.state.userVisible = !this.state.userVisible;
        this.toggleBodyScrolling(this.state.userVisible);
    }
});

/* Neues Widget "welcome-popup" erstellen; dieses Widget wird nur gerendert, wenn der Benutzer sich zum ersten Mal anmeldet */
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">Sie sind jetzt Mitglied. Herzlich willkommen!</div>`;
          const body = `<div class="first-login-bootbox-body">Jetzt können Sie: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Eine Frage stellen oder eine Diskussion starten</a></li> <li><a href="/my/preferences/tags" target="_blank">Ihre Benachrichtigungseinstellungen konfigurieren</a></li></ol></div>`;
          
          bootbox.alert({
                        title: title,
                        message: body
                    });
            // Aufruf der closeFirstNotificationMask-Aktionsmethode des Header-Widgets
            this.sendWidgetAction("closeFirstNotificationMask", this.attrs);
        }
      return null;
  },
  
});

/* Der folgende Code rendert das "welcome-popup"-Widget nach dem Rendern des "header-notifications"-Widgets, wenn sich der Benutzer zum ersten Mal anmeldet */
api.decorateWidget("header-notifications:after", helper => { 
    if(!helper.attrs.active && helper.attrs.ringBackdrop){
        return helper.attach("welcome-popup", helper.attrs);     
    }else{
        return null;    
    }
});
</script>

Noch eine Sache: Wir verwenden die Bootbox-Version 5.4.1, indem wir das folgende Skript in unsere Theme-Komponente einbinden, da Discourse derzeit die bootbox-Methode mit mehreren Parametern nicht unterstützt. Ist das in Ordnung?

<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>

Bitte teilen Sie uns Ihre Meinung mit. Vielen Dank!

Das sieht gut aus :+1:

Ich habe es lokal getestet und keine Probleme festgestellt. Ich habe ein paar kleinere Änderungen vorgenommen.

<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">Du bist jetzt dabei. Willkommen an Bord!</div>`;
  const bootboxBody = `<div class="first-login-bootbox-body">Jetzt kannst du: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank ">Eine Frage stellen oder eine Diskussion starten</a></li> <li><a href="/my/preferences/tags" target="_blank">Deine Benachrichtigungseinstellungen konfigurieren</a></li></ol></div>`;

  /* Neue Methode zum Header-Widget hinzufügen, die nach Anzeige des Willkommens-Popups aufgerufen wird */
  api.reopenWidget("header", {
    closeFirstNotificationMask() {
      this.state.ringBackdrop = false;
      this.state.userVisible = !this.state.userVisible;
    }
  });

  /* Neues Widget "welcome-popup" erstellt. Dieses Widget wird nur gerendert, wenn sich der Benutzer zum ersten Mal anmeldet */
  api.createWidget("welcome-popup", {
    tagName: "div.welcome-popup",
    html(attrs) {
      // Aufruf der closeFirstNotificationMask-Aktionsmethode des Header-Widgets
      this.sendWidgetAction("closeFirstNotificationMask", attrs);

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

  /* Der folgende Code rendert das "welcome-popup"-Widget nach dem Rendern des "header-notifications"-Widgets, wenn sich der Benutzer zum ersten Mal anmeldet */
  api.decorateWidget("header-notifications:before", helper => {
    if (!helper.attrs.active && helper.attrs.ringBackdrop) {
      return helper.attach("welcome-popup", helper.attrs);
    }
  });
</script>

Ja, das ist in Ordnung. Discourse lädt die von uns verwendete Bootbox-Version als Shim, sodass das Laden einer anderen Version in deiner Theme-Komponente nichts am Kern ändert. Die neue Version wird nur in deiner Theme-Komponente verwendet. Der einzige Nachteil ist, dass dies eine zusätzliche Anfrage hinzufügt und etwa 4 KB zur initialen Seitenladung beiträgt.

Hallo @Johani, da du das Widget welcome-popup vor dem Widget header-notifications geladen hast, scheint es, dass die Discobot-Benachrichtigung nicht geladen wird. Zudem wird nach dem Klicken auf die Links innerhalb von welcome-popup erneut das welcome-popup für den Benutzer angezeigt.
Ich habe es getestet, indem ich das Widget welcome-popup nach dem Widget header-notifications geladen habe; das funktioniert einwandfrei. Kann ich es also in “header-notifications:after” ändern?

Das ist seltsam :thinking:

Ich habe den gleichen Code gerade erneut mit drei verschiedenen neuen Benutzern ausprobiert und jedes Mal das erwartete Ergebnis erhalten. Ich sehe das Popup beim ersten Seitenaufruf, und die Discobot-Begrüßungsnachricht wird gesendet. Bei nachfolgenden Seitenaufrufen erscheint das Popup nicht.

Klar, wenn es bei dir funktioniert, sollte der Dekorationsort keine Rolle spielen.

Danke @Johani, wir werden den after-Decorator verwenden.