هل هناك أي طريقة للاستماع إلى حدث تسجيل دخول المستخدم باستخدام مكون Theme

مرحباً بالجميع،

أود عرض نافذة منبثقة باستخدام مكون Theme عندما يسجل المستخدم دخوله لأول مرة.

1. لقد حاولت تجاوز إجراء تسجيل الدخول في وحدة تحكم تسجيل الدخول باستخدام مكون Theme لعرض النافذة المنبثقة بعد تسجيل الدخول بنجاح.
في إجراء تسجيل الدخول، أضفت كود bootbox.alert(“Test Alert”); قبل hiddenLoginForm.submit();.

لكن النافذة المنبثقة تظهر فقط بعد تقديم hiddenLoginForm ثم إعادة التوجيه إلى الصفحة الرئيسية.

متطلباتي هي أن تظهر النافذة المنبثقة بعد إعادة التوجيه إلى الصفحة الرئيسية بعد تسجيل الدخول بنجاح.

2. للتحقق مما إذا كان المستخدم يسجل دخوله لأول مرة، حاولت فحص قيمة خاصية previous_visit_at للمستخدم الحالي.
إذا كانت previous_visit_at = null (أي أن المستخدم يسجل دخوله لأول مرة).
لكن هنا أيضاً يفشل اختباري، حيث أنني عند تسجيل الدخول للمرة الثانية كانت قيمة خاصية previous_visit_at هي null.
أود معرفة متى يتم تحديث قيمة خاصية previous_visit_at بالضبط.

يرجى مساعدتي في تحقيق المتطلبات المذكورة أعلاه

شكراً لكم،
سورabh خاندوال

مرحبًا @Saurabh_Khandelwal :wave:

أنصحك بعدم القيام بذلك بهذه الطريقة؛ فإجراء تسجيل الدخول هو أحد الإجراءات الأكثر أهمية، وأي تجاوزات لهذا الإجراء ستكون هشة وعرضة للكسر إذا قمنا بأي تغييرات في هذا المجال في النواة.

إذا كنت تتذكر، عندما سجلت أول مرة في هذا الموقع، رأيت شيئًا مثل هذا.

الشروط التي نستخدمها للتحقق من ذلك هي

!user.read_first_notification && !user.enforcedSecondFactor

لذلك، إذا استخدمت نفس الشروط في مُهيئ (initializer)، فستتمكن من عرض نافذة Bootbox عند أول عرض للصفحة للمستخدم بعد تسجيل الدخول.

يمكنك تجربة شيء مثل هذا في مكون السمة الخاص بك.

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

وسيعطيك ذلك شيئًا مثل هذا

يمكنك استخدام HTML في نص نافذة Bootbox إذا لزم الأمر. بمجرد أن يغلق المستخدم نافذة Bootbox وينقر على الصورة الرمزية الدائرية، فلن يرى نافذة Bootbox مرة أخرى.

يرجى ملاحظة أن نوافذ Bootbox مخصصة للحوارات أو التأكيدات البسيطة. إذا كنت بحاجة إلى شيء أكثر تعقيدًا قليلاً من ذلك، فمن الأفضل استخدام نافذة منبثقة (modal) باستخدام showModal()

شكرًا لك، @Johani، على نصيحتك. سأتجنب إجراء تعديلات في إجراء تسجيل الدخول وسأحاول التنفيذ كما ذكرت.

.

مرحبًا، @Johani، لقد أضفت رابطًا بسيطًا (مثل “/new-topic”) داخل نافذة منبثقة تفتح في علامة تبويب جديدة.
عند النقر على هذا الرابط، يفتح في علامة تبويب جديدة، لكنه يعرض مرة أخرى النافذة المنبثقة لأننا تحققنا من الشروط التالية:

!user.read_first_notification && !user.enforcedSecondFactor

في حالتي، لا ينبغي عرض النافذة المنبثقة بعد زيارة الرابط.

هل يمكننا تحديث قيم هذه الخصائص بعد عرض النافذة المنبثقة مرة واحدة؟ إذا كان الأمر كذلك، فكيف يمكننا القيام بذلك؟

أخشى أن هذا غير ممكن.

هذه الخصائص لا تحتوي على دوال تعيين (setters)؛ وحتى لو كانت تحتوي عليها، فإن تغييراتك ستُطبَّق مؤقتًا فقط في النافذة الأولى. بمجرد زيارة المستخدم للعلامة التبويب الثانية، ستُستند البيانات إلى ما هو مخزن في قاعدة البيانات. لا تملك السمات (Themes) وصولًا إلى الخلفية؛ فهي تستطيع تغيير الواجهة الأمامية فقط.

ما يمكنك فعله هو إضافة تجزئة (hash) إلى رابطك والتحقق منها كما يلي:

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

لست متأكدًا مما إذا كان ربط "
/new-topic" في منشورك مجرد مثال أم أنه ما تريد فعله. إذا كان هذا هو النتيجة المرجوة، فإن لديك مشكلة أخرى. حتى لو لم يتم عرض نافذة Bootbox في الصفحة التي تحتوي على التجزئة، فسيظل المستخدم يرى هذا…

… ولن يفتح المُنشئ (composer)، وهو أمر منطقي لأن من غير المتوقع أن يبدأ المستخدم بكتابة موضوع في أول صفحة يزورها مباشرةً.

هل لي أن أسأل ما الذي تحاول تحقيقه هنا؟ هل تحاول إبلاغ المستخدم بشيء معين أم بأشياء أخرى؟

الطريقة التي رأيتها تُطبَّق في مواقع أخرى هي تعديل رسالة الترحيب، ولكن إذا كانت هذه الخيار متاحًا، فهناك بدائل.

إليك ما أقترحه:

  1. أنشئ موضوعًا وأضف جميع المعلومات التي تريدها هناك.
  2. انشر هذا الموضوع.
  3. اربط بهذا الموضوع داخل نافذة Bootbox وافتح هذا الرابط في علامة تبويب جديدة.

بهذه الطريقة، عندما ينقر المستخدم على الرابط، سيرى شيئًا مثل هذا (بدون الطبقة العلوية):

بمجرد انتهائه من تلك الصفحة، يمكنه العودة إلى العلامة التبويب الأولى، إغلاق نافذة Bootbox، قراءة الإشعار الأول، ثم مواصلة استخدام الموقع.

بهذه الطريقة، لن تحتاج حتى إلى إضافة أو التحقق من وجود تجزئة. إليك مثالًا على مقتطف الكود:

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

أحاول تضمين بعض الروابط مثل “/new-topic” و “/my/preferences” داخل النافذة المنبثقة.

بخلاف ذلك، كنت أفكر في عرض النافذة المنبثقة فقط لصفحة الرئيسية عن طريق التحقق من عنوان URL الحالي.
لذلك، عند زيارة صفحات أخرى، لن يتم عرض النافذة المنبثقة.

حتى لو قمت بالتحقق من عنوان URL للصفحة الرئيسية بعد النقر على رابط “/new-topic”، ستظهر المشكلة المذكورة أعلاه.

مرحبًا سورهيش،
نعم، أعتقد أن التحقق من عنوان URL الحالي وإظهار النافذة المنبثقة فقط على الصفحة الرئيسية يجب أن ينجح.

يمكننا عرض مقدمة المستخدم الجديد من Discobot بعد مرور بعض الوقت، مثل دقيقتين:

مرحبًا، @Johani

هل يمكننا إنشاء أداة (widget) كما هو موضح أدناه واستدعاء bootbox() داخلها؟
وبعد استدعاء bootbox، هل يمكننا استدعاء دالة “skipNewUserTips()”؟ وهي الدالة التي تستخدمها Discourse أيضًا في أداة إشعارات الرأس (header-notifications widget).

<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">أنت عضو. أهلاً بك على متنها!</div>`;
          const body = `<div class="first-login-bootbox-body">الآن يمكنك: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">اطرح سؤالاً أو ابدأ نقاشًا</a></li> <li><a href="/my/preferences/tags" target="_blank">قم بإعداد إعدادات الإشعارات الخاصة بك</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 الخاص بأداة إشعارات الرأس:
https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/widgets/header.js#L101

هل سيؤدي ذلك إلى أي مشاكل؟

هذا يتجاوز هذه الطبقة التراكبية تمامًا لـ جميع المستخدمين الجدد. لذا لن يروها أبدًا.

إذا كان ذلك مقبولاً بالنسبة لك، نعم، يجب أن يعمل.

تحتاج إلى تغيير استدعاء bootbox. وإلا، ستحصل على هذا.

بدلاً من القيام بذلك

يجب عليك تمرير حجة واحدة فقط.

تمت إضافة هذه الخيارات إلى إصدارات أحدث من Bootbox ولن تعمل مع الإصدار الذي نستخدمه حاليًا في Discourse (نحن نناقش هذا داخليًا، ولكن حتى الآن، لا يمكنك استخدامها)

أيضًا، بما أنك تنشئ طلب PUT، فيمكنك أيضًا تخطي هذا.

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

لذا، ربما شيء مثل هذا.

  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">أنت عضو. أهلاً بك على متنها!</h2>
                      <hr>
                      <div class="first-login-bootbox-body">
                        الآن يمكنك:
                        <br>
                        <ol class="user-suggestions">
                          <li>
                            <a href="/new-topic" target="_blank"
                              >اطرح سؤالاً أو ابدأ نقاشًا</a
                            >
                          </li>
                          <li>
                            <a href="/my/preferences/tags" target="_blank"
                              >قم بإعداد إعدادات الإشعارات الخاصة بك</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
        }
      });
    }
  });

مرحبًا @Johani،

بما أننا قمنا بتعيين skip_new_user_tips إلى true، فإن إشعار تحية Discobot يتم تجاوزه أيضًا. لا بأس إذا لم يتم عرض قناع الطبقة الأولى للإشعار، لكننا نرغب في ظهور إشعار تحية Discobot.

إشعار Discobot:

لحل هذه المشكلة، قمنا بتعديل الكود بحيث يتم تحميل إشعار تحية Discobot لجميع المستخدمين الجدد.
الآن، أضفنا طريقة جديدة إلى أداة الرأس (header widget) باسم “closeFirstNotificationMask()”، حيث قمنا بتعيين “ringBackdrop” إلى false و"userVisible" إلى قيمتها العكسية. ثم قمنا باستدعاء هذه الطريقة بعد استدعاء طريقة bootbox في أداة welcome-popup.

لقد استندنا في ذلك إلى طريقة “toggleUserMenu” في أداة الرأس، والتي يتم استدعاؤها عند النقر على أيقونة المستخدم.

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

/* إضافة طريقة جديدة إلى أداة الرأس سيتم استدعاؤها بعد عرض welcome-popup */
api.reopenWidget("header",{
    closeFirstNotificationMask() {
        this.state.ringBackdrop = false;
        this.state.userVisible = !this.state.userVisible;
        this.toggleBodyScrolling(this.state.userVisible);
    }
});

/* إنشاء أداة جديدة "welcome-popup"، سيتم عرضها فقط عند تسجيل دخول المستخدم لأول مرة */
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">أنت عضو. مرحبًا بك!</div>`;
          const body = `<div class="first-login-bootbox-body">الآن يمكنك: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">اطرح سؤالًا أو ابدأ نقاشًا</a></li> <li><a href="/my/preferences/tags" target="_blank">قم بإعداد إعدادات الإشعارات</a></li></ol></div>`;
          
          bootbox.alert({
                        title: title,
                        message: body
                    });
            // استدعاء طريقة closeFirstNotificationMask في أداة الرأس
            this.sendWidgetAction("closeFirstNotificationMask", this.attrs);
        }
      return null;
  },
  
});

/* الكود أدناه سيقوم بعرض أداة "welcome-popup" بعد عرض أداة "header-notifications" عند تسجيل دخول المستخدم لأول مرة */
api.decorateWidget("header-notifications:after", helper => { 
    if(!helper.attrs.active && helper.attrs.ringBackdrop){
        return helper.attach("welcome-popup", helper.attrs);     
    }else{
        return null;    
    }
});
</script>

شيء آخر، نحن نستخدم إصدار Bootbox 5.4.1 من خلال تضمين السكربت أدناه في مكون الثيم الخاص بنا، حيث أن Discourse لا يدعم حاليًا طريقة bootbox متعددة المعلمات. هل هذا مقبول؟

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

نرجو منكم إبداء رأيكم، شكرًا لكم!

هذا يبدو جيدًا :+1:

لقد جربته محليًا ولم ألاحظ أي مشاكل. قمت بإجراء بعض التغييرات الطفيفة.

<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">أنت عضو. مرحبًا بك على متنها!</div>`;
  const bootboxBody = `<div class="first-login-bootbox-body">الآن يمكنك: </br> <ol class="user-suggestions"><li><a href="/new-topic" target="_blank">اطرح سؤالًا أو ابدأ نقاشًا</a></li> <li><a href="/my/preferences/tags" target="_blank">قم بإعداد إعدادات الإشعارات</a></li></ol></div>`;

  /* إضافة طريقة جديدة إلى مكون الرأس (header Widget) والتي سيتم استدعاؤها بعد عرض نافذة الترحيب */
  api.reopenWidget("header", {
    closeFirstNotificationMask() {
      this.state.ringBackdrop = false;
      this.state.userVisible = !this.state.userVisible;
    }
  });

  /* إنشاء مكون جديد "welcome-popup"، سيتم عرض هذا المكون فقط عند تسجيل دخول المستخدم لأول مرة */
  api.createWidget("welcome-popup", {
    tagName: "div.welcome-popup",
    html(attrs) {
      // استدعاء طريقة الإجراء closeFirstNotificationMask الخاصة بمكون الرأس
      this.sendWidgetAction("closeFirstNotificationMask", attrs);

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

  /* الكود أدناه سيعرض مكون "welcome-popup" بعد عرض مكون "header-notifications" عند تسجيل دخول المستخدم لأول مرة */
  api.decorateWidget("header-notifications:before", helper => {
    if (!helper.attrs.active && helper.attrs.ringBackdrop) {
      return helper.attach("welcome-popup", helper.attrs);
    }
  });
</script>

نعم، هذا مقبول. يقوم Discourse بتحميل إصدار Bootbox الذي نستخدمه كـ (shim)، لذا فإن تحميل إصدار مختلف في مكون الثيم الخاص بك لن يغير أي شيء في النواة. سيتم استخدام الإصدار الجديد فقط في مكون الثيم الخاص بك. العيب الوحيد هو أنه يضيف طلبًا إضافيًا وحجمًا إضافيًا يبلغ حوالي 4 كيلوبايت إلى تحميل الصفحة الأولي.

مرحبًا @Johani، بما أنك قمت بتحميل عنصر واجهة welcome-popup قبل عنصر واجهة header-notifications، يبدو أن إشعار Discobot لم يتم تحميله. كما أن النقر على الروابط داخل welcome-popup يعرض مرة أخرى عنصر welcome-popup للمستخدم.
لقد اختبرت ذلك بتحميل عنصر واجهة welcome-popup بعد عنصر واجهة header-notifications، وقد عمل ذلك بشكل صحيح. لذا، هل يمكنني تغييره إلى “header-notifications:after”؟

هذا غريب :thinking:

لقد جربت نفس الكود مرة أخرى مع 3 مستخدمين جدد مختلفين، وحصلت على النتيجة المتوقعة في كل مرة. أرى النافذة المنبثقة في أول عرض للصفحة، ويتم إرسال رسالة ترحيب من Discobot. لا تظهر النافذة المنبثقة في عروض الصفحة اللاحقة.

بالتأكيد، إذا كان يعمل معك، فلا يجب أن يكون لموقع المزخرف أي أهمية.

شكرًا لك @Johani، سنستخدم الزخرفة بعد.