C'è un modo per ascoltare l'evento di accesso dell'utente usando il componente Theme

Ciao a tutti,

Voglio visualizzare la finestra di popup utilizzando il componente Theme quando l’utente effettua il login per la prima volta.

1. Ho provato a sovrascrivere l’azione di login del controller di login utilizzando il componente Theme per mostrare il popup dopo che l’utente ha effettuato il login con successo.
Nell’azione di login, ho aggiunto il codice bootbox.alert(“Test Alert”); prima di hiddenLoginForm.submit();.

Tuttavia, il popup viene visualizzato solo dopo che hiddenLoginForm è stato inviato e l’utente viene reindirizzato alla Home page.

Il mio obiettivo è che la finestra di popup venga visualizzata dopo il reindirizzamento alla Home page, a seguito di un login riuscito.

2. Per verificare se l’utente ha effettuato il login per la prima volta, ho provato a controllare il valore della proprietà previous_visit_at dell’utente corrente.
Se previous_visit_at = null (cioè, l’utente sta effettuando il login per la prima volta).
Tuttavia, anche in questo caso il mio test fallisce: quando effettuo il login una seconda volta, il valore della proprietà previous_visit_at risulta ancora null.
Vorrei sapere esattamente quando viene aggiornato il valore della proprietà previous_visit_at.

Potete aiutarmi a soddisfare i requisiti sopra descritti?

Grazie,
Saurabh Khandelwal

Ciao @Saurabh_Khandelwal :wave:

Sconsiglio di procedere in questo modo; il login è una delle azioni più critiche e qualsiasi sovrascrittura di tale azione risulterà fragile e soggetta a errori se apportiamo modifiche in quell’area nel core.

Se ricordi, quando ti sei iscritto per la prima volta a questo sito, hai visto qualcosa di simile.

Le condizioni che utilizziamo per verificare ciò sono

!user.read_first_notification && !user.enforcedSecondFactor

Quindi, se utilizzi le stesse condizioni in un inizializzatore, potrai rendere un Bootbox nella prima visualizzazione della pagina da parte dell’utente dopo il login.

Puoi provare qualcosa di simile nel tuo componente del tema.

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

e otterrai qualcosa di simile

Puoi utilizzare HTML nel testo del bootbox se necessario. Una volta che l’utente chiude il bootbox e clicca sull’avatar cerchiato, non vedrà più il bootbox.

Tieni presente che i bootbox sono pensati per dialoghi o conferme semplici. Se hai bisogno di qualcosa di leggermente più complesso, è probabilmente meglio utilizzare un modal con showModal()

Grazie, @Johani, per il tuo consiglio. Eviterò di apportare modifiche all’azione di login e cercherò di implementare come hai suggerito.

.

Ciao, @Johani, ho aggiunto un semplice hyperlink (ad esempio “/new-topic”) all’interno della finestra popup che si apre in una nuova scheda.
Quando faccio clic su quel link, si apre in una nuova scheda, ma viene visualizzata nuovamente la finestra popup perché abbiamo verificato le seguenti condizioni:

!user.read_first_notification && !user.enforcedSecondFactor

Nel mio caso, la finestra popup non dovrebbe essere visualizzata dopo aver visitato il link.

Possiamo aggiornare i valori di queste proprietà dopo che la finestra popup è stata visualizzata una volta? Se sì, come possiamo farlo?

Temo che non sia possibile.

Queste proprietà non hanno setter; anche se li avessero, le tue modifiche si applicherebbero solo temporaneamente nella prima finestra. Una volta che l’utente visita la seconda scheda, i dati saranno basati su ciò che è memorizzato nel database. I temi non hanno accesso al backend; possono modificare solo il frontend.

Quello che puoi fare è aggiungere un hash al tuo link e controllarlo in questo modo.

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

Non sono sicuro se collegare a “/new-topic” nel tuo post fosse solo un esempio o se fosse ciò che vuoi fare. Se è il risultato desiderato, allora hai un altro problema. Anche se il bootbox non viene visualizzato sulla pagina con l’hash, vedranno comunque questo…

…e il compositore non si aprirà, il che ha senso dato che è molto inaspettato per un utente iniziare a scrivere un argomento sulla sua prima visualizzazione di pagina.

Posso chiederti cosa stai cercando di ottenere qui? Stai cercando di informare l’utente di una cosa o dell’altra?

Il modo in cui ho visto questo fatto su altri siti è modificare il messaggio di benvenuto, ma se è un’opzione, ci sono alternative.

Ecco cosa suggerisco:

  1. crea un argomento e aggiungi tutte le informazioni che desideri lì
  2. pubblica quell’argomento
  3. collega quell’argomento nel bootbox e apri quel link in una nuova scheda.

In questo modo, quando l’utente clicca sul link, vedranno qualcosa di simile a questo (senza l’overlay)

Una volta finito con quella pagina, possono tornare alla prima scheda, chiudere il bootbox, leggere la prima notifica e poi continuare a usare il sito.

In questo modo, non hai nemmeno bisogno di aggiungere/controllare un hash. Ecco un esempio di 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">Link</a>, consectetur adipiscing elit, sed do eiusmod tempor`;
        bootbox.alert(text);
      }
    });
  }
};

Sto cercando di inserire dei link come “/new-topic” e “/my/preferences” all’interno del Popup.

In alternativa, stavo pensando di mostrare il Popup solo per la home page, controllando l’URL corrente.
Quindi, quando si visitano altre pagine, il Popup non verrà mostrato.

Anche se controllo l’URL della home page dopo aver fatto clic sul collegamento “/new-topic”, si verificherà il problema sopra descritto.

Ciao Saurabh,
Sì, penso che controllare l’URL corrente e mostrare il popup solo nella home page dovrebbe funzionare..

Possiamo mostrare l’introduzione per i nuovi utenti di Discobot dopo un certo periodo, ad esempio 2 minuti:

Ciao, @Johani

Possiamo creare un widget come mostrato di seguito e chiamare bootbox() al suo interno?
E dopo aver chiamato bootbox, possiamo chiamare il metodo “skipNewUserTips()”. Questo metodo è utilizzato anche da Discourse nel 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">Sei un membro. Benvenuto a bordo!</div>`;
          const body = `<div class="first-login-bootbox-body">Ora puoi: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Fai una domanda o inizia una discussione</a></li> <li><a href="/my/preferences/tags" target="_blank">Configura le tue impostazioni di notifica</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> 

Codice di Discourse per il widget header-notifications:
https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/widgets/header.js#L101

Questo creerà qualche problema?

Ciò ignora completamente questo overlay per tutti i nuovi utenti. Quindi non lo vedranno mai.

Se per te va bene, sì, dovrebbe funzionare.

Devi comunque modificare la chiamata a Bootbox. Altrimenti, otterrai questo.

invece di fare questo

Dovresti passare solo un singolo argomento.

Queste opzioni sono state aggiunte nelle versioni più recenti di Bootbox e non funzionano con la versione che stiamo attualmente utilizzando in Discourse (ne stiamo discutendo internamente, ma per ora non puoi usarle)

Inoltre, dato che stai creando una richiesta PUT, puoi anche saltare questo passaggio.

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

Quindi, forse qualcosa del genere.

  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">Sei un membro. Benvenuto a bordo!</h2>
                      <hr>
                      <div class="first-login-bootbox-body">
                        Ora puoi:
                        <br>
                        <ol class="user-suggestions">
                          <li>
                            <a href="/new-topic" target="_blank"
                              >Fai una domanda o inizia una discussione</a
                            >
                          </li>
                          <li>
                            <a href="/my/preferences/tags" target="_blank"
                              >Configura le tue impostazioni di notifica</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
        }
      });
    }
  });

Ciao @Johani,

Poiché abbiamo impostato skip_new_user_tips su true, anche la notifica di benvenuto di Discobot viene saltata. Va bene che la maschera di sovrapposizione della prima notifica non venga visualizzata, ma vogliamo mantenere la notifica di benvenuto di Discobot.

Notifica di Discobot:

Per risolvere questo problema, abbiamo modificato il codice in modo che la notifica di benvenuto di Discobot venga caricata per tutti i nuovi utenti.
Ora abbiamo aggiunto un nuovo metodo al widget dell’intestazione chiamato “closeFirstNotificationMask()”, in cui impostiamo “ringBackdrop” su false e “userVisible” sul suo opposto. Questo metodo viene chiamato dopo l’esecuzione del metodo bootbox nel widget welcome-popup.

Abbiamo preso come riferimento il metodo “toggleUserMenu” del widget dell’intestazione, che viene chiamato quando si fa clic sull’icona dell’utente.

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

/* Aggiunta un nuovo metodo al widget dell'intestazione da chiamare dopo la visualizzazione del popup di benvenuto */
api.reopenWidget("header",{
    closeFirstNotificationMask() {
        this.state.ringBackdrop = false;
        this.state.userVisible = !this.state.userVisible;
        this.toggleBodyScrolling(this.state.userVisible);
    }
});

/* Creazione del nuovo widget "welcome-popup", che verrà renderizzato solo al primo accesso dell'utente */
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">Sei un membro. Benvenuto a bordo!</div>`;
          const body = `<div class="first-login-bootbox-body">Ora puoi: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Fai una domanda o inizia una discussione</a></li> <li><a href="/my/preferences/tags" target="_blank">Configura le tue impostazioni di notifica</a></li></ol></div>`;
          
          bootbox.alert({
                        title: title,
                        message: body
                    });
            // Chiamata al metodo closeFirstNotificationMask del widget dell'intestazione
            this.sendWidgetAction("closeFirstNotificationMask", this.attrs);
        }
      return null;
  },
  
});

/* Il codice sottostante renderizzerà il widget "welcome-popup" dopo il rendering del widget "header-notifications" al primo accesso dell'utente */
api.decorateWidget("header-notifications:after", helper => { 
    if(!helper.attrs.active && helper.attrs.ringBackdrop){
        return helper.attach("welcome-popup", helper.attrs);     
    }else{
        return null;    
    }
});
</script>

Un’altra cosa: stiamo utilizzando la versione 5.4.1 di Bootbox includendo lo script sottostante nel nostro componente del tema, poiché attualmente Discourse non supporta il metodo bootbox con più parametri. Va bene?

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

Ti chiediamo il tuo parere, grazie!

Sembra tutto a posto :+1:

L’ho provato in locale e non ho riscontrato problemi. Ho apportato alcune piccole modifiche.

<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">Sei un membro. Benvenuto a bordo!</div>`;
  const bootboxBody = `<div class="first-login-bootbox-body">Ora puoi: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">Fai una domanda o inizia una discussione</a></li> <li><a href="/my/preferences/tags" target="_blank">Configura le impostazioni delle notifiche</a></li></ol></div>`;

  /* Aggiunta un nuovo metodo al widget header che verrà chiamato dopo la visualizzazione del popup di benvenuto */
  api.reopenWidget("header", {
    closeFirstNotificationMask() {
      this.state.ringBackdrop = false;
      this.state.userVisible = !this.state.userVisible;
    }
  });

  /* Creato un nuovo widget "welcome-popup", questo widget verrà renderizzato solo quando l'utente effettua il login per la prima volta */
  api.createWidget("welcome-popup", {
    tagName: "div.welcome-popup",
    html(attrs) {
      /* Chiamata al metodo closeFirstNotificationMask del widget header */
      this.sendWidgetAction("closeFirstNotificationMask", attrs);

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

  /* Il codice sottostante renderizzerà il widget "welcome-popup" dopo il rendering del widget "header-notifications" quando l'utente effettua il login per la prima volta */
  api.decorateWidget("header-notifications:before", helper => {
    if (!helper.attrs.active && helper.attrs.ringBackdrop) {
      return helper.attach("welcome-popup", helper.attrs);
    }
  });
</script>

Sì, va bene. Discourse carica la versione di bootbox che utilizziamo come shim, quindi caricare una versione diversa nel tuo componente del tema non cambierà nulla nel core. La nuova versione verrà utilizzata solo nel tuo componente del tema. L’unico svantaggio è che aggiunge una richiesta in più e circa 4kb al caricamento iniziale della pagina.

Ciao @Johani, dato che hai caricato il widget welcome-popup prima del widget header-notifications, sembra che la notifica di Discobot non venga caricata. Inoltre, dopo aver cliccato sui link all’interno di welcome-popup, il widget welcome-popup viene nuovamente visualizzato all’utente.

Ho testato caricando il widget welcome-popup dopo il widget header-notifications e funziona correttamente. Posso quindi modificarlo in “header-notifications:after”?

Che strano :thinking:

Ho appena provato lo stesso codice di nuovo con 3 nuovi utenti diversi e ottengo il risultato previsto ogni volta. Vedo il popup alla prima visualizzazione della pagina e viene inviata la messaggio di saluto di Discobot. Le visualizzazioni successive della pagina non mostrano il popup.

Certo, se funziona per te, allora la posizione del decoratore non dovrebbe avere importanza.

Grazie @Johani, useremo il decoratore after.