From c8463e0258bbcd63acbc7bb09d059bd57c5baf6f Mon Sep 17 00:00:00 2001 From: distalx Date: Mon, 12 Nov 2018 10:00:10 +0530 Subject: [PATCH] Feat inbox (#1076) * resolve merge conflit * feat(inbox): user can send direct messages to other users. * feat(email-notifications): email notifications for `new messages`. user will receive email notification for unread messages * refactor(user-settings): update user email setting preference. * small proofreading edits * fix(conversation): now, user can create multiple conversations * style(conversations): remove typo --- client/css/_buttons.scss | 1 + client/css/_colors.scss | 1 + client/css/_inbox.scss | 27 +++ client/css/style.scss | 1 + client/layouts/layout.js | 13 +- .../admin/notification/all_notifications.html | 3 + client/templates/comments/comment_box.js | 10 +- .../templates/discussion/discussion_card.js | 19 +-- .../templates/discussion/discussion_item.js | 19 +-- .../discussion/discussion_response_card.js | 19 +-- client/templates/hangout/hangout-clone.js | 22 +-- client/templates/hangout/hangout-edit.js | 11 +- client/templates/hangout/hangout-frame.js | 20 +-- client/templates/hangout/hangout-modal.js | 24 +-- client/templates/hangout/hangout.js | 4 +- .../templates/hangout/hangout_action_bar.js | 51 ++---- .../hangout/hangout_action_buttons.js | 101 +++-------- client/templates/inbox/conversation.html | 53 ++++++ client/templates/inbox/conversation.js | 124 ++++++++++++++ .../templates/inbox/conversations_list.html | 24 +++ client/templates/inbox/conversations_list.js | 15 ++ client/templates/inbox/inbox.html | 16 ++ client/templates/inbox/message_bubble.html | 10 ++ client/templates/inbox/message_bubble.js | 5 + .../templates/inbox/report_message_modal.html | 51 ++++++ .../templates/inbox/report_message_modal.js | 20 +++ client/templates/main.js | 36 ++-- client/templates/members/member-status.js | 5 +- client/templates/nav/header.html | 1 + client/templates/nav/header.js | 60 ++++--- .../profile/profile-edit/profile-edit.js | 4 +- client/templates/profile/profile.html | 9 + client/templates/profile/profile.js | 13 ++ .../settings/delete_my_account_modal.js | 9 +- .../unsubscribe_from_mailing_list.html | 14 ++ .../settings/unsubscribe_from_mailing_list.js | 15 +- .../settings/user_account_settings.html | 14 ++ client/templates/status/learning-item.js | 17 +- client/templates/status/status-list.js | 31 ++-- client/templates/status/update-status.js | 3 +- .../study_groups/all_study_groups.js | 16 +- .../study_groups/study_group_discussion.js | 31 +--- .../study_groups/study_group_settings.js | 57 ++----- i18n/en.i18n.json | 7 +- imports/api/unsubscribe_links/methods.js | 5 +- imports/data/contributors.json | 69 +++----- imports/data/discussion_tags.js | 4 +- imports/data/slack_channels.js | 4 +- imports/libs/server/cron/helpers.js | 54 ++++-- .../cron/initial_email_notifications.js | 135 ++++++++++----- imports/libs/server/user/welcome_email.js | 5 +- .../ui/pages/users/basic_user_information.js | 62 ++----- lib/collections.js | 2 + lib/routes.js | 38 +++++ package.json | 2 +- .../templates/email/new_direct_message.html | 158 ++++++++++++++++++ server/conversations/methods.js | 78 +++++++++ server/conversations/publications.js | 6 + server/cron_job/methods.js | 115 ++++++------- server/discussions/methods.js | 15 +- server/hangouts/helpers.js | 42 +---- server/hangouts/methods.js | 76 ++------- server/main.js | 6 +- server/messages/methods.js | 104 ++++++++++++ server/messages/publications.js | 8 + server/study_groups/methods.js | 66 ++------ server/twitter/methods.js | 18 +- server/users/methods.js | 63 ++----- 68 files changed, 1242 insertions(+), 899 deletions(-) create mode 100644 client/css/_inbox.scss create mode 100644 client/templates/inbox/conversation.html create mode 100644 client/templates/inbox/conversation.js create mode 100644 client/templates/inbox/conversations_list.html create mode 100644 client/templates/inbox/conversations_list.js create mode 100644 client/templates/inbox/inbox.html create mode 100644 client/templates/inbox/message_bubble.html create mode 100644 client/templates/inbox/message_bubble.js create mode 100644 client/templates/inbox/report_message_modal.html create mode 100644 client/templates/inbox/report_message_modal.js create mode 100644 private/templates/email/new_direct_message.html create mode 100644 server/conversations/methods.js create mode 100644 server/conversations/publications.js create mode 100644 server/messages/methods.js create mode 100644 server/messages/publications.js diff --git a/client/css/_buttons.scss b/client/css/_buttons.scss index 665c1920..64e9bf4a 100644 --- a/client/css/_buttons.scss +++ b/client/css/_buttons.scss @@ -61,6 +61,7 @@ &:hover { background: $white; color: $cta-blue; + cursor: pointer; } } diff --git a/client/css/_colors.scss b/client/css/_colors.scss index ff5a39e4..a5fe4f8b 100644 --- a/client/css/_colors.scss +++ b/client/css/_colors.scss @@ -29,6 +29,7 @@ $warning-orange: #f0ad4e; $danger-red: #d9534f; $well: #f5f5f5; $end-hangout-color: #AD4545; +$light-grey: #D3D3D3; $github: #333; $slack: #3AAF85; diff --git a/client/css/_inbox.scss b/client/css/_inbox.scss new file mode 100644 index 00000000..c23ef6d2 --- /dev/null +++ b/client/css/_inbox.scss @@ -0,0 +1,27 @@ +.conversation-unread { + background: $light-grey; +} + +// chat bubble + +.ib-clear {clear: both} +.ib-from-me { + position:relative; + padding:15px; + margin-bottom: 4px; + color: black; + border: 1px solid $light-grey; + border-radius:25px; + float: right; +} +.ib-from-them { + position:relative; + padding:10px 20px; + margin-bottom: 4px; + // background:#E5E5EA; + border: 1px solid $light-grey; + border-radius:25px; + color: black; + float: left; + cursor: pointer; +} diff --git a/client/css/style.scss b/client/css/style.scss index fe54ab2c..e7ef364c 100644 --- a/client/css/style.scss +++ b/client/css/style.scss @@ -29,6 +29,7 @@ @import 'study_groups'; @import 'discussion'; @import 'slack'; +@import 'inbox'; @import 'sections'; @import 'tips_lists'; diff --git a/client/layouts/layout.js b/client/layouts/layout.js index 4752c421..4ba8d547 100644 --- a/client/layouts/layout.js +++ b/client/layouts/layout.js @@ -28,18 +28,9 @@ Template.layout.events({ } }); } else if (result.dismiss === "esc" || result.dismiss === "overlay") { - swal( - "No worries!", - "Sign up or sign in with Slack or Github at any time.", - "info" - ); + swal("No worries!", "Sign up or sign in with Slack or Github at any time.", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); } diff --git a/client/templates/admin/notification/all_notifications.html b/client/templates/admin/notification/all_notifications.html index f22918f0..cb491eb7 100644 --- a/client/templates/admin/notification/all_notifications.html +++ b/client/templates/admin/notification/all_notifications.html @@ -19,6 +19,9 @@

Notifications

{{#if equals type 'reported discussion'}}

{{#if isActorAdmin actor.id}} {{actor.username}} {{else}} {{actor.username}} {{/if}} {{action}} {{subject.username}}'s discussion {{discussion.topic}}    {{matter}}{{dispDate createdAt}}

{{/if}} + {{#if equals type 'reported message'}} +

{{#if isActorAdmin actor.id}} {{actor.username}} {{else}} {{actor.username}} {{/if}} {{action}} {{subject.username}}'s message {{message.body}}    {{matter}}{{dispDate createdAt}}

+ {{/if}} {{#if equals type 'hangout edit'}}

{{#if isActorAdmin actorId}} {{actorUsername}} {{else}} {{actorUsername}} {{/if}} {{action}} {{subjectUsername}}'s hangout . {{dispDate createdAt}}

{{/if}} diff --git a/client/templates/comments/comment_box.js b/client/templates/comments/comment_box.js index e63cfad3..418942e5 100644 --- a/client/templates/comments/comment_box.js +++ b/client/templates/comments/comment_box.js @@ -115,10 +115,7 @@ Template.commentBox.events({ if (userId && !_.includes(this.upvotes, userId)) { //checking if user has already voted for other category if true then switching if (userId && _.includes(this.downvotes, userId)) { - Meteor.call("voteSwitching", commentId, "downvote-to-upvote", function( - error, - result - ) { + Meteor.call("voteSwitching", commentId, "downvote-to-upvote", function(error, result) { if (error) { console.log("error", error); } @@ -147,10 +144,7 @@ Template.commentBox.events({ if (userId && !_.includes(this.downvotes, userId)) { //checking if user has already voted for other category if true then switching if (userId && _.includes(this.upvotes, userId)) { - Meteor.call("voteSwitching", commentId, "upvote-to-downvote", function( - error, - result - ) { + Meteor.call("voteSwitching", commentId, "upvote-to-downvote", function(error, result) { if (error) { console.log("error", error); } diff --git a/client/templates/discussion/discussion_card.js b/client/templates/discussion/discussion_card.js index 28dbe88b..278d63e5 100644 --- a/client/templates/discussion/discussion_card.js +++ b/client/templates/discussion/discussion_card.js @@ -19,25 +19,12 @@ Template.discussionCard.events({ swal.disableButtons(); if (result.value) { Meteor.call("discussions.remove", data, function(error) { - swal( - "Poof!", - "Your Discussion has been successfully deleted!", - "success" - ); + swal("Poof!", "Your Discussion has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); }, diff --git a/client/templates/discussion/discussion_item.js b/client/templates/discussion/discussion_item.js index a9f518be..6b4e7fa9 100644 --- a/client/templates/discussion/discussion_item.js +++ b/client/templates/discussion/discussion_item.js @@ -19,25 +19,12 @@ Template.discussionItem.events({ swal.disableButtons(); if (result.value) { Meteor.call("discussions.remove", data, function(error) { - swal( - "Poof!", - "Your Discussion has been successfully deleted!", - "success" - ); + swal("Poof!", "Your Discussion has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); // sweetAlert2 }, diff --git a/client/templates/discussion/discussion_response_card.js b/client/templates/discussion/discussion_response_card.js index f0c1a1fb..b6ff8737 100644 --- a/client/templates/discussion/discussion_response_card.js +++ b/client/templates/discussion/discussion_response_card.js @@ -20,25 +20,12 @@ Template.discussionResponseCard.events({ swal.disableButtons(); if (result.value) { Meteor.call("discussionResponses.remove", data, function(error) { - swal( - "Poof!", - "Your Discussion has been successfully deleted!", - "success" - ); + swal("Poof!", "Your Discussion has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); }, diff --git a/client/templates/hangout/hangout-clone.js b/client/templates/hangout/hangout-clone.js index dc3c58d5..51fcb284 100644 --- a/client/templates/hangout/hangout-clone.js +++ b/client/templates/hangout/hangout-clone.js @@ -14,8 +14,7 @@ Template.cloneHangoutModal.onRendered(function() { }); templateInstance.editor.setContents( - templateInstance.data.hangout.data.description_in_quill_delta || - templateInstance.data.hangout.data.description + templateInstance.data.hangout.data.description_in_quill_delta || templateInstance.data.hangout.data.description ); //instructions for start date time picker @@ -39,18 +38,11 @@ Template.cloneHangoutModal.onRendered(function() { let studyGroupsKeys = []; Object.entries(roles).forEach(([key, value]) => { - if ( - value.includes("owner") || - value.includes("admin") || - (value.includes("moderator") && key !== "CB") - ) { + if (value.includes("owner") || value.includes("admin") || (value.includes("moderator") && key !== "CB")) { studyGroupsKeys.push(key); } else if (value.includes("member") && key !== "CB") { // check for exempt_from_default_permission - if ( - StudyGroups.findOne({ _id: key }) && - StudyGroups.findOne({ _id: key }).exempt_from_default_permission - ) { + if (StudyGroups.findOne({ _id: key }) && StudyGroups.findOne({ _id: key }).exempt_from_default_permission) { studyGroupsKeys.push(key); } } @@ -86,9 +78,7 @@ Template.cloneHangoutModal.events({ var templateInstance = Template.instance(); const topic = $("#topic").val(); - const description = QuillEditor.generatePlainTextFromDeltas( - templateInstance.editor.getContents() - ); + const description = QuillEditor.generatePlainTextFromDeltas(templateInstance.editor.getContents()); const description_in_quill_delta = templateInstance.editor.getContents(); const start = $("#start-date-time").val(); const startDate = new Date(start); @@ -97,9 +87,7 @@ Template.cloneHangoutModal.events({ const end = new Date(startDate.getTime() + 1000 * 60 * duration); const type = $('input[name="hangout-type"]:checked').val(); const groupId = $(".study-group-single").val(); - const externalCheckbox = $('input[name="externalCheckbox"]').prop( - "checked" - ); + const externalCheckbox = $('input[name="externalCheckbox"]').prop("checked"); const externalButtonText = $('input[name="externalButtonText"]').val(); const externalURL = $('input[name="externalURL"]').val(); diff --git a/client/templates/hangout/hangout-edit.js b/client/templates/hangout/hangout-edit.js index be84104a..7328dd54 100644 --- a/client/templates/hangout/hangout-edit.js +++ b/client/templates/hangout/hangout-edit.js @@ -11,8 +11,7 @@ Template.editHangoutModal.rendered = function() { }); templateInstance.editor.setContents( - templateInstance.data.hangout.data.description_in_quill_delta || - templateInstance.data.hangout.data.description + templateInstance.data.hangout.data.description_in_quill_delta || templateInstance.data.hangout.data.description ); //instructions for start date time picker @@ -36,9 +35,7 @@ Template.editHangoutModal.events({ "click #edit-hangout": function() { var templateInstance = Template.instance(); const topic = $("#topic").val(); - const description = QuillEditor.generatePlainTextFromDeltas( - templateInstance.editor.getContents() - ); + const description = QuillEditor.generatePlainTextFromDeltas(templateInstance.editor.getContents()); const description_in_quill_delta = templateInstance.editor.getContents(); const start = $("#start-date-time").val(); const startDate = new Date(start); @@ -46,9 +43,7 @@ Template.editHangoutModal.events({ const duration = Number($("#end-date-time").val()) || 1440; const end = new Date(startDate.getTime() + 1000 * 60 * duration); const type = $('input[name="hangout-type"]:checked').val(); - const externalCheckbox = $('input[name="externalCheckbox"]').prop( - "checked" - ); + const externalCheckbox = $('input[name="externalCheckbox"]').prop("checked"); const externalButtonText = $('input[name="externalButtonText"]').val(); const externalURL = $('input[name="externalURL"]').val(); diff --git a/client/templates/hangout/hangout-frame.js b/client/templates/hangout/hangout-frame.js index 38b92c44..2caae1f0 100644 --- a/client/templates/hangout/hangout-frame.js +++ b/client/templates/hangout/hangout-frame.js @@ -1,8 +1,6 @@ Template.hangoutFrame.onCreated(function() { let instance = this; - instance.room = new ReactiveVar( - `cb${instance.data._id || instance.data.hroom}` - ); + instance.room = new ReactiveVar(`cb${instance.data._id || instance.data.hroom}`); instance.autorun(() => { instance.subscribe("hangoutParticipants", instance.room.get()); @@ -43,9 +41,7 @@ Template.hangoutFrame.onCreated(function() { $("[id^=" + "jitsiConference" + "]").css("width", "100%"); //only show the launch hangout button if Jitsi is not loaded - $("[id^=" + "jitsiConference" + "]").length == 1 - ? $(".load-hangout").hide() - : $("#load-hangout").show(); + $("[id^=" + "jitsiConference" + "]").length == 1 ? $(".load-hangout").hide() : $("#load-hangout").show(); instance.api.on("readyToClose", () => { Bert.alert({ @@ -80,10 +76,7 @@ Template.hangoutFrame.onRendered(function() { * Chrome or Firefox */ - if ( - (!!window.chrome && !!window.chrome.webstore) || - typeof InstallTrigger !== "undefined" - ) { + if ((!!window.chrome && !!window.chrome.webstore) || typeof InstallTrigger !== "undefined") { //console.log('using firefox or chrome') $("p.chrome-firefox-warning").hide(); } else { @@ -92,17 +85,14 @@ Template.hangoutFrame.onRendered(function() { } //Google Hangout support - $("head").append( - '' - ); + $("head").append(''); }); Template.hangoutFrame.events({ "click .load-hangout": function(event, template) { const data = { room: this._id || template.data.hroom, - username: - (Meteor.user() && Meteor.user().username) || template.data.huser, + username: (Meteor.user() && Meteor.user().username) || template.data.huser, type: template.data.htype || this.type, avatar: template.data.havatar || Meteor.user().profile.avatar.default }; diff --git a/client/templates/hangout/hangout-modal.js b/client/templates/hangout/hangout-modal.js index f4b2a2cf..f2ae1446 100644 --- a/client/templates/hangout/hangout-modal.js +++ b/client/templates/hangout/hangout-modal.js @@ -55,18 +55,11 @@ Template.createHangoutModal.onRendered(function() { let studyGroupsKeys = []; Object.entries(roles).forEach(([key, value]) => { - if ( - value.includes("owner") || - value.includes("admin") || - (value.includes("moderator") && key !== "CB") - ) { + if (value.includes("owner") || value.includes("admin") || (value.includes("moderator") && key !== "CB")) { studyGroupsKeys.push(key); } else if (value.includes("member") && key !== "CB") { // check for exempt_from_default_permission - if ( - StudyGroups.findOne({ _id: key }) && - StudyGroups.findOne({ _id: key }).exempt_from_default_permission - ) { + if (StudyGroups.findOne({ _id: key }) && StudyGroups.findOne({ _id: key }).exempt_from_default_permission) { studyGroupsKeys.push(key); } } @@ -83,10 +76,7 @@ Template.createHangoutModal.onRendered(function() { data: studyGroups }); - if ( - typeof instance.studyGroupId !== "undefined" && - instance.studyGroupId !== "" - ) { + if (typeof instance.studyGroupId !== "undefined" && instance.studyGroupId !== "") { instance .$(".study-group-single") .val(instance.studyGroupId) @@ -103,9 +93,7 @@ Template.createHangoutModal.events({ "click #create-hangout": function(e, template) { const templateInstance = template; const topic = $("#topic").val(); - const description = QuillEditor.generatePlainTextFromDeltas( - templateInstance.editor.getContents() - ); + const description = QuillEditor.generatePlainTextFromDeltas(templateInstance.editor.getContents()); const description_in_quill_delta = templateInstance.editor.getContents(); const start = $("#start-date-time").val(); const startDate = new Date(start); @@ -113,9 +101,7 @@ Template.createHangoutModal.events({ const duration = Number($("#end-date-time").val()) || 1440; const end = new Date(startDate.getTime() + 1000 * 60 * duration); const groupId = $(".study-group-single").val(); - const externalCheckbox = $('input[name="externalCheckbox"]').prop( - "checked" - ); + const externalCheckbox = $('input[name="externalCheckbox"]').prop("checked"); const externalButtonText = $('input[name="externalButtonText"]').val(); const externalURL = $('input[name="externalURL"]').val(); diff --git a/client/templates/hangout/hangout.js b/client/templates/hangout/hangout.js index 69c7d2ad..f055ea39 100644 --- a/client/templates/hangout/hangout.js +++ b/client/templates/hangout/hangout.js @@ -1,9 +1,7 @@ import QuillEditor from "../../libs/QuillEditor"; Meteor.startup(function() { - $("head").append( - '' - ); + $("head").append(''); //$('head').append(''); }); diff --git a/client/templates/hangout/hangout_action_bar.js b/client/templates/hangout/hangout_action_bar.js index 01a295b8..8c078617 100644 --- a/client/templates/hangout/hangout_action_bar.js +++ b/client/templates/hangout/hangout_action_bar.js @@ -14,27 +14,17 @@ Template.hangoutActionBar.events({ // console.log(hangout.data._id + ' this is a cloned hangout id'); Session.set("hangoutId", hangout.data._id); Modal.show("cloneHangoutModal", { hangout }); - $("#clone-hangout-modal input#external-checkbox").prop( - "checked", - hangout.data.externalCheckbox - ); - $("#clone-hangout-modal #externalButtonText").val( - hangout.data.externalButtonText - ); + $("#clone-hangout-modal input#external-checkbox").prop("checked", hangout.data.externalCheckbox); + $("#clone-hangout-modal #externalButtonText").val(hangout.data.externalButtonText); $("#clone-hangout-modal #externalURL").val(hangout.data.externalURL); $("#clone-hangout-modal #topic").val(hangout.data.topic); - $("#clone-hangout-modal input[value=" + hangout.data.type + "]").prop( - "checked", - true - ); + $("#clone-hangout-modal input[value=" + hangout.data.type + "]").prop("checked", true); } }, "click .edit-hangout": function(e, hangout) { //console.log(hangout.data.topic); //pass in the right times like 03/09/2016 2:03 AM - var start_time_reverted = moment(hangout.data.start).format( - "MM/DD/YYYY h:mm A" - ); + var start_time_reverted = moment(hangout.data.start).format("MM/DD/YYYY h:mm A"); var hangoutDuration = hangout.data.duration; //var end_time_reverted = moment(hangout.data.end).format('MM/DD/YYYY h:mm A'); @@ -54,21 +44,13 @@ Template.hangoutActionBar.events({ //console.log(editor_content.html()); Modal.show("editHangoutModal", { hangout }); - $("#edit-hangout-modal input#external-checkbox").prop( - "checked", - hangout.data.externalCheckbox - ); - $("#edit-hangout-modal #externalButtonText").val( - hangout.data.externalButtonText - ); + $("#edit-hangout-modal input#external-checkbox").prop("checked", hangout.data.externalCheckbox); + $("#edit-hangout-modal #externalButtonText").val(hangout.data.externalButtonText); $("#edit-hangout-modal #externalURL").val(hangout.data.externalURL); $("#edit-hangout-modal #topic").val(hangout.data.topic); // $('#edit-hangout-modal #description').val(hangout.data.description); // templateInstance.editor.setContents(hangout.data.description); - $("#edit-hangout-modal input[value=" + hangout.data.type + "]").prop( - "checked", - true - ); + $("#edit-hangout-modal input[value=" + hangout.data.type + "]").prop("checked", true); $("#edit-hangout-modal #start-date-time").val(start_time_reverted); $("#edit-hangout-modal #end-date-time").val(hangoutDuration); $("#edit-hangout-modal #group").val(hangout.data.group.title); @@ -95,25 +77,12 @@ Template.hangoutActionBar.events({ swal.disableButtons(); if (result.value) { Meteor.call("deleteHangout", data, function(error) { - swal( - "Poof!", - "Your hangout has been successfully deleted!", - "success" - ); + swal("Poof!", "Your hangout has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); //sweetAlert 2 } diff --git a/client/templates/hangout/hangout_action_buttons.js b/client/templates/hangout/hangout_action_buttons.js index c587f8bd..741667e6 100644 --- a/client/templates/hangout/hangout_action_buttons.js +++ b/client/templates/hangout/hangout_action_buttons.js @@ -3,29 +3,16 @@ import QuillEditor from "../../libs/QuillEditor"; Template.hangoutActionButtons.helpers({ icsDownloadLink: function(hangout) { const nowDate = new Date(); - const startDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate( - hangout.start - ); - const startTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime( - hangout.start - ); - const endDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate( - hangout.end - ); - const endTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime( - hangout.end - ); - const currentDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate( - nowDate - ); - const currentTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime( - nowDate - ); + const startDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate(hangout.start); + const startTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime(hangout.start); + const endDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate(hangout.end); + const endTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime(hangout.end); + const currentDate = Blaze._globalHelpers.getHangoutGoogleCalendarDate(nowDate); + const currentTime = Blaze._globalHelpers.getHangoutGoogleCalendarTime(nowDate); const start = `${startDate}T${startTime}`; const end = `${endDate}T${endTime}`; const current = `${currentDate}T${currentTime}`; - const SEPARATOR = - navigator.appVersion.indexOf("Win") !== -1 ? "\r\n" : "\n"; + const SEPARATOR = navigator.appVersion.indexOf("Win") !== -1 ? "\r\n" : "\n"; let topic = hangout.topic; const group = (hangout && hangout.group) || null; @@ -49,9 +36,7 @@ Template.hangoutActionButtons.helpers({ "END:VEVENT" ].join(SEPARATOR); const calendarEvent = `BEGIN:VCALENDAR${SEPARATOR}PRODID:Calendar${SEPARATOR}VERSION:2.0${SEPARATOR}${calendarDetails}${SEPARATOR}END:VCALENDAR`; - return `data:text/calendar;charset=utf8,${encodeURIComponent( - calendarEvent - )}`; + return `data:text/calendar;charset=utf8,${encodeURIComponent(calendarEvent)}`; }, googleCalendarUrl: function(hangout) { const { _id: id, topic, description, group, start, end } = hangout; @@ -75,27 +60,17 @@ Template.hangoutActionButtons.events({ // console.log(hangout.data._id + ' this is a cloned hangout id'); Session.set("hangoutId", hangout.data._id); Modal.show("cloneHangoutModal", { hangout }); - $("#clone-hangout-modal input#external-checkbox").prop( - "checked", - hangout.data.externalCheckbox - ); - $("#clone-hangout-modal #externalButtonText").val( - hangout.data.externalButtonText - ); + $("#clone-hangout-modal input#external-checkbox").prop("checked", hangout.data.externalCheckbox); + $("#clone-hangout-modal #externalButtonText").val(hangout.data.externalButtonText); $("#clone-hangout-modal #externalURL").val(hangout.data.externalURL); $("#clone-hangout-modal #topic").val(hangout.data.topic); - $("#clone-hangout-modal input[value=" + hangout.data.type + "]").prop( - "checked", - true - ); + $("#clone-hangout-modal input[value=" + hangout.data.type + "]").prop("checked", true); } }, "click .edit-hangout": function(e, hangout) { //console.log(hangout.data.topic); //pass in the right times like 03/09/2016 2:03 AM - var start_time_reverted = moment(hangout.data.start).format( - "MM/DD/YYYY h:mm A" - ); + var start_time_reverted = moment(hangout.data.start).format("MM/DD/YYYY h:mm A"); var hangoutDuration = hangout.data.duration; //var end_time_reverted = moment(hangout.data.end).format('MM/DD/YYYY h:mm A'); @@ -118,17 +93,9 @@ Template.hangoutActionButtons.events({ $("#edit-hangout-modal #topic").val(hangout.data.topic); // $('#edit-hangout-modal #description').val(hangout.data.description); // templateInstance.editor.setContents(hangout.data.description); - $("#edit-hangout-modal input[value=" + hangout.data.type + "]").prop( - "checked", - true - ); - $("#edit-hangout-modal input#external-checkbox").prop( - "checked", - hangout.data.externalCheckbox - ); - $("#edit-hangout-modal #externalButtonText").val( - hangout.data.externalButtonText - ); + $("#edit-hangout-modal input[value=" + hangout.data.type + "]").prop("checked", true); + $("#edit-hangout-modal input#external-checkbox").prop("checked", hangout.data.externalCheckbox); + $("#edit-hangout-modal #externalButtonText").val(hangout.data.externalButtonText); $("#edit-hangout-modal #externalURL").val(hangout.data.externalURL); $("#edit-hangout-modal #start-date-time").val(start_time_reverted); $("#edit-hangout-modal #end-date-time").val(hangoutDuration); @@ -157,25 +124,12 @@ Template.hangoutActionButtons.events({ if (result.value) { Meteor.call("deleteHangout", data, function(error) { - swal( - "Poof!", - "Your hangout has been successfully deleted!", - "success" - ); + swal("Poof!", "Your hangout has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); //sweetAlert }, @@ -199,25 +153,12 @@ Template.hangoutActionButtons.events({ swal.disableButtons(); if (result.value) { Meteor.call("endHangout", data, function(error) { - swal( - "Poof!", - "Your hangout has been successfully deleted!", - "success" - ); + swal("Poof!", "Your hangout has been successfully deleted!", "success"); }); - } else if ( - result.dismiss === "cancel" || - result.dismiss === "esc" || - result.dismiss === "overlay" - ) { + } else if (result.dismiss === "cancel" || result.dismiss === "esc" || result.dismiss === "overlay") { swal("Phew!", "No changes made", "info"); } else { - swal( - "Oops! Something went wrong", - error.error, - +"\n Try again", - "error" - ); + swal("Oops! Something went wrong", error.error, +"\n Try again", "error"); } }); //sweetAlert 2 } diff --git a/client/templates/inbox/conversation.html b/client/templates/inbox/conversation.html new file mode 100644 index 00000000..33bef851 --- /dev/null +++ b/client/templates/inbox/conversation.html @@ -0,0 +1,53 @@ + diff --git a/client/templates/inbox/conversation.js b/client/templates/inbox/conversation.js new file mode 100644 index 00000000..a7724ead --- /dev/null +++ b/client/templates/inbox/conversation.js @@ -0,0 +1,124 @@ +import moment from "moment"; +import _ from "lodash"; +Template.conversation.onCreated(function() { + let instance = this; + const title = "CodeBuddies | conversation"; + instance.limit = new ReactiveVar(12); + instance.flag = new ReactiveVar(false); + DocHead.setTitle(title); + + instance.autorun(function() { + const limit = instance.limit.get(); + instance.subscribe("messagesByConvoId", FlowRouter.getParam("conversationId"), limit); + }); +}); + +Template.conversation.onRendered(function() { + const instance = this; + Meteor.setTimeout(function() { + instance.$("#chatbox").scrollTop($("#chatbox")[0].scrollHeight); + Meteor.call("conversation.markAsRead", FlowRouter.getParam("conversationId")); + }, 900); + + $("#chatbox").bind("scroll", function() { + // add more message + if ($("#chatbox").scrollTop() < 100) { + console.log("load more message"); + const limit = instance.limit.get() + 10; + instance.limit.set(limit); + } + }); + + const conversationId = FlowRouter.getParam("conversationId"); + // this is for preventing auto-scrolling. + const cursor = Messages.find({ conversation_id: conversationId }, { sort: { sent: 1 } }); + cursor.observe({ + addedAt(document, atIndex, before) { + if (atIndex == instance.limit.get() - 1) { + $("#chatbox").scrollTop($("#chatbox")[0].scrollHeight); + console.log("if ", atIndex, " ", instance.limit.get()); + } else { + console.log("else ", atIndex, " ", instance.limit.get()); + } + } + }); +}); +Template.conversation.helpers({ + messages() { + //"round" all the createdAt dates to the minute (using _.map) + //group all messages by createdAt (using _.groupBy) + //remove the createdAt property for all but the first item (using _.each on the list of groups, then _.map again on the grouped-together messages, the latter removing the property when the index > 0) + //then flatten that out into an array again (using _.values, then _.flatten) + //return it as the model for the template to work on + + const messages = _.chain( + Messages.find({ conversation_id: FlowRouter.getParam("conversationId") }, { sort: { sent: 1 } }).fetch() + ) + .map(m => { + m.from_now = moment(m.sent) + .startOf("minute") + .fromNow(); + return m; + }) + .groupBy("from_now") + .forEach((i, key) => { + return _.map(i, (m, key) => { + if (key > 0) { + delete m["sent"]; + } + return m; + }); + }) + .values() + .flatten() + .value(); + + console.log(messages); + + return messages; + // return Messages.find({conversation_id: FlowRouter.getParam('conversationId')}, {sort: {sent: 1}}); + }, + conversation() { + return Conversations.findOne({ _id: FlowRouter.getParam("conversationId") }); + } +}); + +Template.conversation.events({ + "keypress form.sendMessage"(event, template) { + if ( + event.which === 13 && + !event.shiftKey && + $("#messge-body") + .val() + .trim() != "" + ) { + event.preventDefault(); + const target = event.currentTarget; + $(event.target).submit(); + } + }, + "submit .sendMessage"(event, template) { + event.preventDefault(); + const body = $("#messge-body").val(); + const body_delta = $("#messge-body") + .val() + .replace(/\r?\n/g, "
"); + const data = { + conversationId: FlowRouter.getParam("conversationId"), + body: body, + body_delta: body_delta + }; + + Meteor.call("message.add", data, function(error, result) { + if (error) { + console.log("error", error); + } + if (result) { + Meteor.setTimeout(function() { + $("#chatbox").scrollTop($("#chatbox")[0].scrollHeight); + }, 200); + $("#messge-body").val(""); + } + }); + } +}); diff --git a/client/templates/inbox/conversations_list.html b/client/templates/inbox/conversations_list.html new file mode 100644 index 00000000..3ce587b5 --- /dev/null +++ b/client/templates/inbox/conversations_list.html @@ -0,0 +1,24 @@ + diff --git a/client/templates/inbox/conversations_list.js b/client/templates/inbox/conversations_list.js new file mode 100644 index 00000000..9a0b4d26 --- /dev/null +++ b/client/templates/inbox/conversations_list.js @@ -0,0 +1,15 @@ +Template.conversations_list.onCreated(function() { + let instance = this; + const title = "CodeBuddies | conversation"; + DocHead.setTitle(title); + + instance.autorun(function() { + instance.subscribe("conversationsForCurrentUser"); + }); +}); + +Template.conversations_list.helpers({ + conversations() { + return Conversations.find({}, { sort: { sent: -1 } }); + } +}); diff --git a/client/templates/inbox/inbox.html b/client/templates/inbox/inbox.html new file mode 100644 index 00000000..514eefa0 --- /dev/null +++ b/client/templates/inbox/inbox.html @@ -0,0 +1,16 @@ + diff --git a/client/templates/inbox/message_bubble.html b/client/templates/inbox/message_bubble.html new file mode 100644 index 00000000..ac984b39 --- /dev/null +++ b/client/templates/inbox/message_bubble.html @@ -0,0 +1,10 @@ + diff --git a/client/templates/inbox/message_bubble.js b/client/templates/inbox/message_bubble.js new file mode 100644 index 00000000..3b1a25cf --- /dev/null +++ b/client/templates/inbox/message_bubble.js @@ -0,0 +1,5 @@ +Template.message_bubble.events({ + "click .ib-from-them": function(event, template) { + Modal.show("report_message_modal", this); + } +}); diff --git a/client/templates/inbox/report_message_modal.html b/client/templates/inbox/report_message_modal.html new file mode 100644 index 00000000..3cd044d8 --- /dev/null +++ b/client/templates/inbox/report_message_modal.html @@ -0,0 +1,51 @@ + diff --git a/client/templates/inbox/report_message_modal.js b/client/templates/inbox/report_message_modal.js new file mode 100644 index 00000000..4dd37134 --- /dev/null +++ b/client/templates/inbox/report_message_modal.js @@ -0,0 +1,20 @@ +Template.report_message_modal.events({ + "click #report-message": function(event, template) { + const data = { + messageId: this._id, + category: $('input[name="report-category"]:checked').val() + }; + Meteor.call("messages.report", data, function(error, result) { + if (result) { + Modal.hide(); + sweetAlert({ + title: TAPi18n.__("discussion_has_been_reported"), + text: TAPi18n.__("discussion_reported_message"), + confirmButtonText: TAPi18n.__("ok"), + type: "success", + closeOnConfirm: true + }); + } + }); + } +}); diff --git a/client/templates/main.js b/client/templates/main.js index ec4b330c..101ae133 100644 --- a/client/templates/main.js +++ b/client/templates/main.js @@ -1,8 +1,6 @@ if (Meteor.isClient) { Meteor.startup(function() { - $("head").append( - '' - ); + $("head").append(''); if (!Meteor.settings.public.isModeDebug) { console = console || {}; @@ -11,16 +9,10 @@ if (Meteor.isClient) { const defaultLang = "en"; const localStorageLang = localStorage.getItem("languageCode"); - const browserLang = ( - window.navigator.userLanguage || - window.navigator.language || - "" - ).slice(0, 2); + const browserLang = (window.navigator.userLanguage || window.navigator.language || "").slice(0, 2); TAPi18n.setLanguage(localStorageLang || browserLang || defaultLang) .fail(console.log) - .always(() => - localStorage.setItem("languageCode", TAPi18n.getLanguage()) - ); + .always(() => localStorage.setItem("languageCode", TAPi18n.getLanguage())); }); } @@ -135,17 +127,10 @@ Template.registerHelper("isHangoutEndTimeTBA", function(start, end) { Template.registerHelper("isOwnerOfTheGroup", function(userId, groupId) { const loggedInUserId = Meteor.userId(); - return loggedInUserId !== userId && - Roles.userIsInRole(loggedInUserId, ["owner"], groupId) - ? true - : false; + return loggedInUserId !== userId && Roles.userIsInRole(loggedInUserId, ["owner"], groupId) ? true : false; }); -Template.registerHelper("canUpdateUserRoleForGroup", function( - subjectId, - groupId, - subjectRole -) { +Template.registerHelper("canUpdateUserRoleForGroup", function(subjectId, groupId, subjectRole) { const loggedInUserId = Meteor.userId(); return loggedInUserId !== subjectId && @@ -212,3 +197,14 @@ Template.registerHelper("truncateIt", function(text, length) { Template.registerHelper("instance", function() { return Template.instance(); }); + +Template.registerHelper("relativeTimeInMinute", function(date) { + return moment(date) + .startOf("minute") + .fromNow(); +}); + +Template.registerHelper("exceptMe", function(id) { + // return _.reject(items, { 'id': Meteor.userId() }); + return id != Meteor.userId() ? true : false; +}); diff --git a/client/templates/members/member-status.js b/client/templates/members/member-status.js index 939dd670..913fab10 100644 --- a/client/templates/members/member-status.js +++ b/client/templates/members/member-status.js @@ -38,10 +38,7 @@ Template.memberStatus.events({ study_group_id: FlowRouter.getParam("studyGroupId") }; - Meteor.call("updateUserStatusForStudyGroup", data, function( - error, - result - ) { + Meteor.call("updateUserStatusForStudyGroup", data, function(error, result) { if (error) { console.log(error); return Bert.alert(error.reason, "danger", "growl-top-right"); diff --git a/client/templates/nav/header.html b/client/templates/nav/header.html index 56348bcd..de697293 100644 --- a/client/templates/nav/header.html +++ b/client/templates/nav/header.html @@ -89,6 +89,7 @@ {{#unless isInRole 'admin' 'CB'}}
  • {{#if userNotificationCount}}{{userNotificationCount}}{{/if}}
  • +
  • {{#if unreadConversationCount}}{{unreadConversationCount}}{{/if}}