1. 사용자가 성공적으로 로그인할 때 팝업 상자를 표시하기 위해 Theme 컴포넌트를 사용하여 로그인 컨트롤러의 로그인 액션을 오버라이드해 보았습니다.
여기서 로그인 액션 내에서 hiddenLoginForm.submit(); 코드 앞에 bootbox.alert(“Test Alert”); 코드를 추가했습니다.
하지만 팝업은 hiddenLoginForm이 제출되어 홈 페이지로 리디렉션될 때까지 표시되고, 이후 사라집니다.
제 요구사항은 성공적인 로그인 후 홈 페이지로 리디렉션된 후에 팝업 상자가 표시되도록 하는 것입니다.
2. 사용자가 처음 로그인하는지 확인하기 위해 현재 사용자의 previous_visit_at 속성의 값을 확인해 보았습니다.
만약 previous_visit_at = null 이면 (즉, 사용자가 처음 로그인하는 경우)
하지만 여기에서도 테스트가 실패합니다. 두 번째로 로그인했을 때 previous_visit_at 속성의 값이 여전히 null이었기 때문입니다. previous_visit_at 속성의 값이 정확히 언제 업데이트되는지 알고 싶습니다.
따라서 이니셜라이저에서 동일한 조건을 사용하면, 로그인 후 사용자의 첫 페이지 뷰에서 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);
}
});
}
};
해당 속성들은 세터(setter)가 없습니다. 설령 세터가 있다고 하더라도, 사용자의 변경 사항은 첫 번째 탭에서만 일시적으로 적용됩니다. 사용자가 두 번째 탭을 방문하면 데이터는 데이터베이스에 저장된 내용을 기반으로 하게 됩니다. 테마는 백엔드에 접근할 수 없으며, 프론트엔드만 변경할 수 있습니다.
할 수 있는 것은 링크에 해시(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)가 표시되지 않더라도, 사용자는 여전히 이것을 보게 됩니다…
아래와 같이 위젯을 생성하고 그 안에서 bootbox()를 호출할 수 있을까요?
그리고 bootbox를 호출한 후 "skipNewUserTips()" 메서드를 호출할 수 있을까요? 이 메서드는 header-notifications 위젯에서도 Discourse가 사용 중인 메서드입니다.
<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>
이를 위해 모든 신규 사용자에게 Discobot 인사 알림이 로드되도록 코드를 수정했습니다.
이제 헤더 위젯에 "closeFirstNotificationMask()"라는 새 메서드를 추가하여 "ringBackdrop"을 false로, "userVisible"을 그 반대값으로 설정하도록 했습니다. 그리고 welcome-popup 위젯에서 bootbox 메서드를 호출한 후에 이 메서드를 호출합니다.
이는 헤더 위젯의 “toggeleUserMenu” 메서드를 참고하여 구현했으며, 이 메서드는 사용자 아이콘이 클릭될 때 호출됩니다.
<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;
/* 환영 팝업 표시 후에 호출될 헤더 위젯의 새 메서드 추가 */
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">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
});
// 헤더 위젯의 closeFirstNotificationMask 액션 메서드 호출
this.sendWidgetAction("closeFirstNotificationMask", this.attrs);
}
return null;
},
});
/* 아래 코드는 사용자가 처음 로그인할 때 "header-notifications" 위젯 렌더링 후 "welcome-popup" 위젯을 렌더링합니다 */
api.decorateWidget("header-notifications:after", helper => {
if(!helper.attrs.active && helper.attrs.ringBackdrop){
return helper.attach("welcome-popup", helper.attrs);
}else{
return null;
}
});
</script>
한 가지 더, 현재 Discourse가 다중 매개변수 bootbox 메서드를 지원하지 않기 때문에 테마 구성 요소에 아래 스크립트를 포함하여 Bootbox 5.4.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>`;
/* Welcome-popup 표시 후 호출될 header 위젯의 새로운 메서드 추가 */
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) {
// header 위젯의 closeFirstNotificationMask 액션 메서드 호출
this.sendWidgetAction("closeFirstNotificationMask", attrs);
bootbox.alert({
title: bootboxTitle,
message: bootboxBody
});
}
});
/* 아래 코드는 사용자가 처음 로그인할 때 "header-notifications" 위젯 렌더링 후 "welcome-popup" 위젯을 렌더링합니다 */
api.decorateWidget("header-notifications:before", helper => {
if (!helper.attrs.active && helper.attrs.ringBackdrop) {
return helper.attach("welcome-popup", helper.attrs);
}
});
</script>
네, 괜찮습니다. Discourse는 우리가 사용하는 bootbox 버전을 shim으로 로드하므로, 테마 컴포넌트에서 다른 버전을 로드해도 코어에 아무런 변경이 일어나지 않습니다. 새 버전은 오직 테마 컴포넌트 내에서만 사용됩니다. 유일한 단점은 초기 페이지 로드 시 요청이 하나 추가되고 약 4kb의 용량이 증가한다는 것입니다.
@Johani님, 안녕하세요. welcome-popup 위젯을 header-notifications 위젯보다 먼저 로드하셨기 때문에 Discobot 알림이 로드되지 않는 것으로 보입니다. 또한 welcome-popup 내부의 링크를 클릭한 후에도 다시 welcome-popup이 사용자에게 표시되는 문제가 있습니다.
저는 header-notifications 위젯 이후에 welcome-popup 위젯을 로드하도록 테스트해 보았을 때 정상적으로 작동하는 것을 확인했습니다. 따라서 이를 "header-notifications:after"로 변경해도 될까요?