diff --git a/api/BanditAPI.js b/api/BanditAPI.js index ad630b6e5..bf9749676 100644 --- a/api/BanditAPI.js +++ b/api/BanditAPI.js @@ -6,11 +6,11 @@ export default class ChatAPI extends BaseAPI { return ret.variant } - shown({ uid, variant, score }) { - return this.$post('/abtest', { uid, variant, score, shown: true }) + shown({ uid, variant }) { + return this.$post('/abtest', { uid, variant, shown: true }) } - chosen({ uid, variant }) { - return this.$post('/abtest', { uid, variant, action: true }) + chosen({ uid, variant, score }) { + return this.$post('/abtest', { uid, variant, action: true, score }) } } diff --git a/api/ChatAPI.js b/api/ChatAPI.js index a7fe45bbb..c70bf51ff 100644 --- a/api/ChatAPI.js +++ b/api/ChatAPI.js @@ -2,7 +2,9 @@ import BaseAPI from '@/api/BaseAPI' export default class ChatAPI extends BaseAPI { fetch(chatid, { limit, context }) { - return this.$get(`/chat/rooms/${chatid}/messages`, { limit, context }) + return chatid + ? this.$get(`/chat/rooms/${chatid}/messages`, { limit, context }) + : this.$get(`/chatmessages`, { limit, context }) } async listChats(params) { @@ -33,9 +35,9 @@ export default class ChatAPI extends BaseAPI { }) } - nudge(roomid) { + nudge(chatid) { return this.$post('/chatrooms', { - id: roomid, + id: chatid, action: 'Nudge' }) } @@ -52,9 +54,32 @@ export default class ChatAPI extends BaseAPI { return this.$get('/chatrooms', { count: true }) } - rsvp(roomid, id, value) { + hold(msgid) { + return this.$post('/chatmessages', { id: msgid, action: 'Hold' }) + } + + release(msgid) { + return this.$post('/chatmessages', { id: msgid, action: 'Release' }) + } + + reject(msgid) { + return this.$post('/chatmessages', { id: msgid, action: 'Reject' }) + } + + approve(msgid) { + return this.$post('/chatmessages', { id: msgid, action: 'Approve' }) + } + + whitelist(msgid) { + return this.$post('/chatmessages', { + id: msgid, + action: 'ApproveAllFuture' + }) + } + + rsvp(chatid, id, value) { return this.$patch('/chatmessages', { - roomid: roomid, + roomid: chatid, id: id, replyexpected: value }) diff --git a/api/MembershipsAPI.js b/api/MembershipsAPI.js index d29f9cb07..8a85818f7 100644 --- a/api/MembershipsAPI.js +++ b/api/MembershipsAPI.js @@ -12,4 +12,72 @@ export default class MembershipsAPI extends BaseAPI { leaveGroup(data) { return this.$del('/memberships', data) } + + fetch(params, logError = true) { + return this.$get('/memberships', params, logError) + } + + fetchMembers(params) { + return this.$get('/memberships', params) + } + + del(id) { + return this.$del('/memberships', { id }) + } + + put(data) { + return this.$put('/memberships', data) + } + + approve(id, groupid, subject = null, stdmsgid = null, body = null) { + return this.$post('/memberships', { + action: 'Approve', + id: id, + groupid: groupid, + subject: subject, + stdmsgid: stdmsgid, + body: body + }) + } + + reply(id, groupid, subject = null, stdmsgid = null, body = null) { + return this.$post('/memberships', { + action: 'Reply', + id: id, + groupid: groupid, + subject: subject, + stdmsgid: stdmsgid, + body: body + }) + } + + reject(id, groupid, subject = null, stdmsgid = null, body = null) { + return this.$post('/memberships', { + action: 'Reject', + id: id, + groupid: groupid, + subject: subject, + stdmsgid: stdmsgid, + body: body + }) + } + + delete(id, groupid, subject = null, stdmsgid = null, body = null) { + return this.$post('/memberships', { + action: 'Delete', + id: id, + groupid: groupid, + subject: subject, + stdmsgid: stdmsgid, + body: body + }) + } + + spam(id, groupid) { + return this.$post('/memberships', { + action: 'Spam', + id: id, + groupid: groupid + }) + } } diff --git a/api/MessageAPI.js b/api/MessageAPI.js index d4c85659e..2c5018bdb 100644 --- a/api/MessageAPI.js +++ b/api/MessageAPI.js @@ -95,4 +95,26 @@ export default class MessageAPI extends BaseAPI { groupid: groupid }) } + + notspam(id, groupid) { + return this.$post('/message', { + action: 'NotSpam', + id: id, + groupid: groupid + }) + } + + hold(id) { + return this.$post('/message', { + action: 'Hold', + id: id + }) + } + + release(id) { + return this.$post('/message', { + action: 'Release', + id: id + }) + } } diff --git a/components/ChatPane.vue b/components/ChatPane.vue index dcf9205da..17696b83c 100644 --- a/components/ChatPane.vue +++ b/components/ChatPane.vue @@ -138,6 +138,11 @@  Nudge + + +  Info + + Send  @@ -209,6 +214,7 @@ import ChatBlockModal from './ChatBlockModal' import ChatHideModal from './ChatHideModal' import twem from '~/assets/js/twem' import chatCollate from '@/mixins/chatCollate.js' +import WaitForRef from '@/mixins/waitForRef' // Don't use dynamic imports because it stops us being able to scroll to the bottom after render. import ChatMessage from '~/components/ChatMessage.vue' @@ -239,7 +245,7 @@ export default { ChatReportModal, ChatRSVPModal }, - mixins: [chatCollate], + mixins: [chatCollate, WaitForRef], props: { id: { type: Number, @@ -320,18 +326,22 @@ export default { otheruser() { // The user who isn't us. let ret = null + const me = this.$store.getters['auth/user'] - if ( - this.chat && - this.chat.chattype === 'User2User' && - this.chat.user1 && - this.$store.getters['auth/user'] - ) { - ret = + if (this.chat && me) { + if (this.chat.chattype === 'User2User' && this.chat.user1 && me) { + ret = + this.chat.user1 && this.chat.user1.id === me.id + ? this.chat.user2 + : this.chat.user1 + } else if ( + this.chat.chattype === 'User2Mod' && this.chat.user1 && - this.chat.user1.id === this.$store.getters['auth/user'].id - ? this.chat.user2 - : this.chat.user1 + me.id !== this.chat.user1.id + ) { + // We are a mod. + ret = this.chat.user1 + } } return ret @@ -419,7 +429,9 @@ export default { methods: { showInfo() { - this.$refs.profile.show() + this.waitForRef('profile', () => { + this.$refs.profile.show() + }) }, availability() { this.$refs.availabilitymodal.show() diff --git a/components/ChatPopup.vue b/components/ChatPopup.vue index e9beccc93..5b6202931 100644 --- a/components/ChatPopup.vue +++ b/components/ChatPopup.vue @@ -17,102 +17,88 @@ @resizing="onResize" >
- - - - - - - - {{ chat.name }} - - - - {{ chat.name }} - - - - {{ chat.unseen }} - - - - - - - - - - - - - - - - - - - +
+ + + + {{ chat.name }} - -
    -
  • - -
  • -
- - -
- - -

- This person has been reported as a spammer or scammer. Please do not talk to them and under no circumstances - send them any money. -

- + + {{ chat.name }} + + + + {{ chat.unseen }} + + + + + + + + +
+
+ + + + + + + +
    +
  • + - - - - - - - - - - - - - - - - - - - - - - - - - +
  • +
+
+
+

+ This person has been reported as a spammer or scammer. Please do not talk to them and under no circumstances + send them any money. +

+ +
+ + + + + + + + + + + + + + + + + + + +
@@ -215,6 +201,8 @@ const ProfileModal = () => import('./ProfileModal') const AvailabilityModal = () => import('~/components/AvailabilityModal') const AddressModal = () => import('~/components/AddressModal') +const HEIGHT = 400 + export default { components: { InfiniteLoading, @@ -259,7 +247,7 @@ export default { }, minheight() { - return Math.min(this.maxheight, 400) + return Math.min(this.maxheight, HEIGHT) }, maxheight() { @@ -326,7 +314,7 @@ export default { height() { return this.chat && this.chat.remember && this.chat.remember.height ? this.chat.remember.height - : 400 + : HEIGHT }, right() { let right = 0 diff --git a/components/ComposeGroup.vue b/components/ComposeGroup.vue index 9cffd8a51..9563754b4 100644 --- a/components/ComposeGroup.vue +++ b/components/ComposeGroup.vue @@ -29,7 +29,7 @@ export default { if (this.postcode) { for (const group of this.postcode.groupsnear) { - if (group.type === 'Freegle') { + if (group.type === 'Freegle' && group.onhere) { ret.push({ value: group.id, text: group.namedisplay ? group.namedisplay : group.nameshort diff --git a/components/DonationAskModal.vue b/components/DonationAskModal.vue index 7d1486d1e..f18ce8236 100644 --- a/components/DonationAskModal.vue +++ b/components/DonationAskModal.vue @@ -154,7 +154,6 @@ export default { }, score(value) { - console.log('Score', value) this.$api.bandit.chosen({ uid: 'donation', variant: this.variant, diff --git a/components/LoginModal.vue b/components/LoginModal.vue index b739fa52f..2320605b3 100644 --- a/components/LoginModal.vue +++ b/components/LoginModal.vue @@ -346,12 +346,10 @@ export default { console.log('Current path', this.$nuxt, this.$router, this.$route) // Pick up the new user - console.log('Fetch user') await this.$store.dispatch('auth/fetchUser', { components: ['me'], force: true }) - console.log('Fetched') if (this.$route.path === '/' || !this.$route.path) { // We've signed up from the home page. Send them to the explore page to find a group. diff --git a/components/Message.vue b/components/Message.vue index d62e33f0e..df7bb8589 100644 --- a/components/Message.vue +++ b/components/Message.vue @@ -504,11 +504,9 @@ export default { // Have to get the message back, because as a non-member we couldn't see who sent it, and therefore // who to reply to. - console.log('Fetch message back') await this.$store.dispatch('messages/fetch', { id: this.id }) - console.log('Fetched') } // Now create the chat and send the first message. diff --git a/components/MessageUserInfo.vue b/components/MessageUserInfo.vue index 232057c91..1db481a1c 100644 --- a/components/MessageUserInfo.vue +++ b/components/MessageUserInfo.vue @@ -32,7 +32,7 @@
+ {{ user.id }}
@@ -56,7 +56,8 @@ export default { }, message: { type: Object, - required: false + required: false, + default: null }, milesaway: { type: Number, diff --git a/components/ModChatReview.vue b/components/ModChatReview.vue new file mode 100644 index 000000000..f491d8fb7 --- /dev/null +++ b/components/ModChatReview.vue @@ -0,0 +1,121 @@ + + diff --git a/components/ModChatReviewUser.vue b/components/ModChatReviewUser.vue new file mode 100644 index 000000000..552cfbde8 --- /dev/null +++ b/components/ModChatReviewUser.vue @@ -0,0 +1,29 @@ + + diff --git a/components/ModImage.vue b/components/ModImage.vue deleted file mode 100644 index be83e0b93..000000000 --- a/components/ModImage.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/components/ModMember.vue b/components/ModMember.vue new file mode 100644 index 000000000..824058864 --- /dev/null +++ b/components/ModMember.vue @@ -0,0 +1,183 @@ + + diff --git a/components/ModMenuItemLeft.vue b/components/ModMenuItemLeft.vue new file mode 100644 index 000000000..079202397 --- /dev/null +++ b/components/ModMenuItemLeft.vue @@ -0,0 +1,76 @@ + + + diff --git a/components/ModMenuItemNav.vue b/components/ModMenuItemNav.vue new file mode 100644 index 000000000..5648caf5e --- /dev/null +++ b/components/ModMenuItemNav.vue @@ -0,0 +1,76 @@ + + diff --git a/components/ModMessage.vue b/components/ModMessage.vue index d63a66aa9..36ef32cf9 100644 --- a/components/ModMessage.vue +++ b/components/ModMessage.vue @@ -43,12 +43,28 @@ - +
+ + You held this {{ message.heldby.timestamp | timeago }}. Other people will see a warning to check with + you before releasing it. + + + Held by {{ message.heldby.name }} + {{ message.heldby.timestamp | timeago }}. Please check with them before releasing it. + +
This freegler is active on groups {{ message.fromuser.activedistance }} miles apart. + + {{ spamreason }} + + + We think this message might be spam. + +
{{ eBody }}
- +
@@ -130,6 +146,7 @@
+ Purge - @@ -181,17 +197,19 @@ import MessageHistory from './MessageHistory' import MessageUserInfo from './MessageUserInfo' import MessageReplyInfo from './MessageReplyInfo' import SettingsGroup from './SettingsGroup' -import ModImage from './ModImage' +import ModPhoto from './ModPhoto' import NoticeMessage from './NoticeMessage' import ModMessageButtons from './ModMessageButtons' +import ModMessageWorry from './ModMessageWorry' import twem from '~/assets/js/twem' export default { name: 'ModMessage', components: { + ModMessageWorry, ModMessageButtons, NoticeMessage, - ModImage, + ModPhoto, SettingsGroup, MessageReplyInfo, MessageUserInfo, @@ -214,19 +232,19 @@ export default { } }, computed: { + me() { + return this.$store.getters['auth/user'] + }, pending() { - let ret = false - - if (this.message.groups) { - this.message.groups.forEach(group => { - if (group.collection === 'Pending') { - ret = true - } - }) - } - - return ret + return this.hasCollection('Pending') }, + approved() { + return this.hasCollection('Approved') + }, + spam() { + return this.hasCollection('Spam') + }, + typeOptions() { // TODO Per group keywords return [ @@ -290,7 +308,21 @@ export default { return ret } }, - methods: {} + methods: { + hasCollection(coll) { + let ret = false + + if (this.message.groups) { + this.message.groups.forEach(group => { + if (group.collection === coll) { + ret = true + } + }) + } + + return ret + } + } } diff --git a/components/ModStdMessageModal.vue b/components/ModStdMessageModal.vue index c9eacb6e2..9c470872a 100644 --- a/components/ModStdMessageModal.vue +++ b/components/ModStdMessageModal.vue @@ -16,7 +16,10 @@
{{ fromName }}
- {{ message.fromuser.displayname }} <{{ toEmail }}> + {{ message.fromuser.displayname }} + + <{{ toEmail }}> +
@@ -75,7 +78,8 @@ export default { this.message.fromuser.emails.forEach(email => { if ( email.email && - email.email.indexOf('users.ilovefreegle.org') === -1 + email.email.indexOf('users.ilovefreegle.org') === -1 && + (ret === null || email.preferred) ) { ret = email.email } @@ -93,7 +97,6 @@ export default { return ret }, - processLabel() { if (this.stdmsg) { switch (this.stdmsg.action) { @@ -118,10 +121,9 @@ export default { return 'Unknown Action - Bug' } } else { - return null + return 'Send' } }, - modstatus() { if (this.stdmsg) { switch (this.stdmsg.newmodstatus) { @@ -138,7 +140,6 @@ export default { return null }, - emailfrequency() { if (this.stdmsg) { switch (this.stdmsg.newdelstatus) { @@ -155,7 +156,6 @@ export default { return 0 }, - delstatus() { if (this.stdmsg) { switch (this.emailfrequency) { @@ -380,12 +380,6 @@ export default { console.error('Unknown stdmsg action', this.action) } } - - // Ensure the counts are updated. - await this.$store.dispatch('auth/fetchUser', { - components: ['work'], - force: true - }) } } } diff --git a/components/ModUserComment.vue b/components/ModUserComment.vue new file mode 100644 index 000000000..e512f9850 --- /dev/null +++ b/components/ModUserComment.vue @@ -0,0 +1,33 @@ + + diff --git a/components/MyMessage.vue b/components/MyMessage.vue index 4d01d5df7..1a7037f92 100644 --- a/components/MyMessage.vue +++ b/components/MyMessage.vue @@ -416,6 +416,14 @@ export default { type: this.message.type }) + // Set the current location and nearby groups, too, since we're about to use them + const loc = await this.$axios.get(process.env.API + '/locations', { + params: { + typeahead: this.message.location.name + } + }) + await this.$store.dispatch('compose/setPostcode', loc.data.locations[0]) + await this.$store.dispatch('compose/setAttachmentsForMessage', { id: this.message.id, attachments: this.message.attachments diff --git a/components/NewsThread.vue b/components/NewsThread.vue index 5052b44aa..df83b58a1 100644 --- a/components/NewsThread.vue +++ b/components/NewsThread.vue @@ -65,7 +65,7 @@ /> - +
- +
diff --git a/mobile/freegle/android/config.xml b/mobile/freegle/android/config.xml index ddbf66294..184ab4817 100644 --- a/mobile/freegle/android/config.xml +++ b/mobile/freegle/android/config.xml @@ -1,5 +1,5 @@ - + Freegle Offer and request free items on your local Freegle reuse group diff --git a/mobile/freegle/ios/config.xml b/mobile/freegle/ios/config.xml index 4726b88d6..35c8d677e 100644 --- a/mobile/freegle/ios/config.xml +++ b/mobile/freegle/ios/config.xml @@ -1,5 +1,5 @@ - + Freegle Offer and request free items on your local Freegle reuse group diff --git a/nuxt.config.js b/nuxt.config.js index 0b10bd780..133ebeb8b 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -5,7 +5,7 @@ const FACEBOOK_APPID = '134980666550322' const SENTRY_DSN = 'https://4de62393d60a4d2aae4ccc3519e94878@sentry.io/1868170' const YAHOO_CLIENTID = 'dj0yJmk9N245WTRqaDd2dnA4JmQ9WVdrOWIzTlZNMU01TjJjbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmc3Y9MCZ4PWRh' -const MOBILE_VERSION = '2.0.16' +const MOBILE_VERSION = '2.0.17' require('dotenv').config() diff --git a/pages/find/whoami.vue b/pages/find/whoami.vue index 345d62741..4934cbcfd 100644 --- a/pages/find/whoami.vue +++ b/pages/find/whoami.vue @@ -79,7 +79,7 @@ export default { }, mounted() { if (!this.valid) { - this.$router.push('/find/whatisit') + //this.$router.push('/find/whatisit') } }, methods: { diff --git a/pages/give/whoami.vue b/pages/give/whoami.vue index 184a80ab9..a5698db4a 100644 --- a/pages/give/whoami.vue +++ b/pages/give/whoami.vue @@ -78,7 +78,7 @@ export default { }, mounted() { if (!this.valid) { - this.$router.push('/give/whatisit') + //this.$router.push('/give/whatisit') } }, methods: { diff --git a/pages/message/_id.vue b/pages/message/_id.vue index 71170be6d..b11ffeb9e 100644 --- a/pages/message/_id.vue +++ b/pages/message/_id.vue @@ -124,7 +124,7 @@ export default { if (message) { if (message.snippet) { - snip = twem.twem(this.$emoji, message.snippet) + snip = twem.twem(this.$emoji, message.snippet) + '...' } else { snip = 'Click for more details' } diff --git a/pages/modtools/chats/review.vue b/pages/modtools/chats/review.vue new file mode 100644 index 000000000..0cfab89e9 --- /dev/null +++ b/pages/modtools/chats/review.vue @@ -0,0 +1,118 @@ + + + diff --git a/pages/modtools/members/approved/_id.vue b/pages/modtools/members/approved/_id.vue new file mode 100644 index 000000000..d98615ca4 --- /dev/null +++ b/pages/modtools/members/approved/_id.vue @@ -0,0 +1,42 @@ + + diff --git a/pages/modtools/messages/spam/_id.vue b/pages/modtools/messages/spam/_id.vue new file mode 100644 index 000000000..50f5e1322 --- /dev/null +++ b/pages/modtools/messages/spam/_id.vue @@ -0,0 +1,40 @@ + + diff --git a/plugins/filters.js b/plugins/filters.js index a14a3908e..9e59aeeb8 100644 --- a/plugins/filters.js +++ b/plugins/filters.js @@ -4,6 +4,7 @@ import dayjs from 'dayjs' // These are various formatting utilities which we use in templates. Vue.filter('dateonly', val => dayjs(val).format('Do MMMM, YYYY')) Vue.filter('datetime', val => dayjs(val).format('Do MMMM, YYYY HH:mm:ss')) +Vue.filter('datetimeshort', val => dayjs(val).format('Do MMM, YYYY HH:mm')) Vue.filter('dateshort', val => dayjs(val).format('MMM DD, YYYY')) // dayjs pluralises wrongly in some cases - we've seen 1 hours ago. diff --git a/plugins/vue-awesome.js b/plugins/vue-awesome.js index 430a2b378..f35c4d625 100644 --- a/plugins/vue-awesome.js +++ b/plugins/vue-awesome.js @@ -3,6 +3,7 @@ import Icon from 'vue-awesome/components/Icon.vue' // We list the icons we use explicitly because this reduces our bundle size. require('vue-awesome/icons/address-book') +require('vue-awesome/icons/arrow-circle-right') require('vue-awesome/icons/angle-double-right') require('vue-awesome/icons/baby-carriage') require('vue-awesome/icons/balance-scale-left') @@ -58,7 +59,9 @@ require('vue-awesome/icons/meh') require('vue-awesome/icons/map-marker-alt') require('vue-awesome/icons/map-marked-alt') require('vue-awesome/icons/mobile-alt') +require('vue-awesome/icons/pause') require('vue-awesome/icons/pen') +require('vue-awesome/icons/play') require('vue-awesome/icons/plus') require('vue-awesome/icons/print') require('vue-awesome/icons/question-circle') @@ -87,6 +90,7 @@ require('vue-awesome/icons/utensils') require('vue-awesome/icons/window-maximize') require('vue-awesome/icons/window-restore') +require('vue-awesome/icons/brands/discourse') require('vue-awesome/icons/brands/facebook') require('vue-awesome/icons/brands/google-plus') require('vue-awesome/icons/brands/pinterest') diff --git a/store/chatmessages.js b/store/chatmessages.js index 35d2eaf2a..e1865f9da 100644 --- a/store/chatmessages.js +++ b/store/chatmessages.js @@ -13,6 +13,10 @@ export const mutations = { Object.assign(state.messages, {}) }, + clearMessage(state, payload) { + Vue.set(state.messages[payload.chatid], payload.id, null) + }, + mergeMessages(state, payload) { const chatid = payload.id + '' const messages = @@ -102,15 +106,19 @@ export const actions = { } ) - commit('mergeMessages', { - id: chatid, - messages: chatmessages - }) + if (chatmessages) { + commit('mergeMessages', { + id: chatid, + messages: chatmessages + }) + } - commit('mergeUsers', { - id: chatid, - users: chatusers - }) + if (chatusers) { + commit('mergeUsers', { + id: chatid, + users: chatusers + }) + } if (!noContext) { commit('setContext', { @@ -141,5 +149,45 @@ export const actions = { async rsvp({ commit, dispatch }, { id, roomid, value }) { await this.$api.chat.rsvp(roomid, id, value) + }, + + async hold({ commit, dispatch, rootGetters }, { id, chatid }) { + await this.$api.chat.hold(id) + await dispatch('fetch', { + chatid: chatid, + noContext: true + }) + }, + + async release({ commit, dispatch }, { id, chatid }) { + await this.$api.chat.release(id) + await dispatch('fetch', { + chatid: chatid, + noContext: true + }) + }, + + async reject({ commit, dispatch }, { id, chatid }) { + await this.$api.chat.reject(id) + commit('clearMessage', { + id, + chatid + }) + }, + + async approve({ commit, dispatch }, { id, chatid }) { + await this.$api.chat.approve(id) + commit('clearMessage', { + id, + chatid + }) + }, + + async whitelist({ commit, dispatch }, { id, chatid }) { + await this.$api.chat.whitelist(id) + commit('clearMessage', { + id, + chatid + }) } } diff --git a/store/compose.js b/store/compose.js index 462dbf8f4..70f2dd052 100644 --- a/store/compose.js +++ b/store/compose.js @@ -281,24 +281,33 @@ export const actions = { }) }) } else { - // This is one of our messages which we are reposting. We need to edit it (to update it from our client - // copy), convert it back to draft, and then submit. + // This is one of our existing messages which we are reposting. We need to convert it back to a draft, + // edit it (to update it from our client data), and then submit. promise = new Promise(function(resolve, reject) { - dispatch('messages/patch', message, { - root: true - }).then(() => { + dispatch( + 'messages/update', + { + id: message.id, + action: 'RejectToDraft' + }, + { + root: true + } + ).then(() => { commit('incProgress') - dispatch( - 'messages/update', - { - id: message.id, - action: 'RejectToDraft' - }, - { - root: true - } - ).then(() => { + const data = { + id: message.id, + locationid: state.postcode.id, + messagetype: message.type, + item: message.item, + textbody: message.description, + groupid: state.group + } + + dispatch('messages/patch', data, { + root: true + }).then(() => { commit('incProgress') self.$api.message diff --git a/store/members.js b/store/members.js new file mode 100644 index 000000000..35d22ad87 --- /dev/null +++ b/store/members.js @@ -0,0 +1,249 @@ +import Vue from 'vue' +import cloneDeep from 'lodash.clonedeep' + +export const state = () => ({ + // Use array because we need to store them in the order returned by the server. + list: [], + + // The context from the last fetch, used for fetchMore. + context: null +}) + +export const mutations = { + add(state, item) { + // Overwrite any existing entry. + const existing = state.list.findIndex(obj => { + return parseInt(obj.id) === parseInt(item.id) + }) + + if (existing !== -1) { + Vue.set(state.list, existing, item) + } else { + state.list.push(item) + } + }, + addAll(state, items) { + items.forEach(item => { + const existing = state.list.findIndex(obj => { + return parseInt(obj.id) === parseInt(item.id) + }) + + if (existing !== -1) { + Vue.set(state.list, existing, item) + } else { + state.list.push(item) + } + }) + }, + remove(state, item) { + state.list = state.list.filter(obj => { + return parseInt(obj.id) !== parseInt(item.id) + }) + }, + clear(state) { + state.list = [] + }, + setContext(state, ctx) { + state.context = ctx + } +} + +export const getters = { + get: state => id => { + let ret = null + + Object.keys(state.list).forEach(key => { + if (parseInt(state.list[key].id) === parseInt(id)) { + ret = state.list[key] + } + }) + + return ret + }, + getContext: state => { + let ret = null + + if (state.context && state.context.id) { + ret = state.context + } + + return ret + }, + getByGroup: state => groupid => { + const ret = state.list.filter(member => { + return parseInt(member.groupid) === parseInt(groupid) + }) + + return ret + }, + getAll: state => { + return state.list + } +} + +export const actions = { + async fetchMembers({ commit, state }, params) { + if (params.context) { + // Ensure the context is a real object, in case it has been in the store. + const ctx = cloneDeep(params.context) + params.context = ctx + } else if (state.context) { + params.context = state.context + } + + const { members, context } = await this.$api.memberships.fetchMembers( + params + ) + + for (let i = 0; i < members.length; i++) { + // The server doesn't return the collection but this is useful to have in the store. + members[i].collection = params.collection + } + + commit('addAll', members) + commit('setContext', context) + }, + + async fetch({ commit }, params) { + // Don't log errors on fetches of individual members + const { member } = await this.$api.memberships.fetch(params, data => { + return data.ret !== 3 + }) + + commit('add', member) + }, + + async update({ commit, dispatch }, params) { + const data = await this.$api.memberships.update(params) + + if (!data.deleted) { + // Fetch back the updated version. + await dispatch('fetch', { id: params.id }) + } + + return data + }, + + async patch({ commit, dispatch }, params) { + const data = await this.$api.memberships.save(params) + await dispatch('fetch', { id: params.id }) + return data + }, + + async updateChat({ dispatch }, userid) { + // Find the chat to this user and refetch the members, so that if we have a chat window open or other data + // that depends on it, we update that. + const chatid = await dispatch( + 'chats/openChatToUser', + { + userid: userid + }, + { + root: true + } + ) + + await dispatch( + 'chatmembers/clearContext', + { + chatid: chatid + }, + { + root: true + } + ) + + await dispatch( + 'chatmembers/fetch', + { + chatid: chatid + }, + { + root: true + } + ) + }, + + async promise({ dispatch }, params) { + await dispatch( + 'update', + Object.assign(params, { + action: 'Promise' + }) + ) + + await dispatch('updateChat', params.userid) + }, + + async renege({ dispatch }, params) { + await dispatch( + 'update', + Object.assign(params, { + action: 'Renege' + }) + ) + + await dispatch('updateChat', params.userid) + }, + + clear({ commit }) { + commit('clear') + commit('setContext', null) + }, + + async approve({ commit }, params) { + await this.$api.memberships.approve( + params.id, + params.groupid, + params.subject, + params.stdmsgid, + params.body + ) + commit('remove', { + id: params.id + }) + }, + + async spam({ commit }, params) { + await this.$api.memberships.spam(params.id, params.groupid) + commit('remove', { + id: params.id + }) + }, + + async reject({ commit }, params) { + await this.$api.memberships.reject( + params.id, + params.groupid, + params.subject, + params.stdmsgid, + params.body + ) + commit('remove', { + id: params.id + }) + }, + + async reply({ commit }, params) { + await this.$api.memberships.reply( + params.id, + params.groupid, + params.subject, + params.stdmsgid, + params.body + ) + }, + + async delete({ commit }, params) { + await this.$api.memberships.delete( + params.id, + params.groupid, + params.subject, + params.stdmsgid, + params.body + ) + commit('remove', { + id: params.id + }) + } +} diff --git a/store/messages.js b/store/messages.js index 1a77b5c97..c3699401e 100644 --- a/store/messages.js +++ b/store/messages.js @@ -215,7 +215,7 @@ export const actions = { } }, - async approve({ commit }, params) { + async approve({ commit, dispatch }, params) { await this.$api.message.approve( params.id, params.groupid, @@ -223,19 +223,62 @@ export const actions = { params.stdmsgid, params.body ) + commit('remove', { id: params.id }) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) }, - async spam({ commit }, params) { + async spam({ commit, dispatch }, params) { await this.$api.message.spam(params.id, params.groupid) + + commit('remove', { + id: params.id + }) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) + }, + + async notspam({ commit, dispatch }, params) { + await this.$api.message.notspam(params.id, params.groupid) + commit('remove', { id: params.id }) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) }, - async reject({ commit }, params) { + async reject({ commit, dispatch }, params) { await this.$api.message.reject( params.id, params.groupid, @@ -243,12 +286,24 @@ export const actions = { params.stdmsgid, params.body ) + commit('remove', { id: params.id }) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) }, - async reply({ commit }, params) { + async reply({ commit, dispatch }, params) { await this.$api.message.reply( params.id, params.groupid, @@ -256,9 +311,20 @@ export const actions = { params.stdmsgid, params.body ) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) }, - async delete({ commit }, params) { + async delete({ commit, dispatch }, params) { await this.$api.message.delete( params.id, params.groupid, @@ -266,8 +332,38 @@ export const actions = { params.stdmsgid, params.body ) + commit('remove', { id: params.id }) + + dispatch( + 'auth/fetchUser', + { + components: ['work'], + force: true + }, + { + root: true + } + ) + }, + + async hold({ dispatch, commit }, params) { + await this.$api.message.hold(params.id) + const { message } = await this.$api.message.fetch({ + id: params.id, + messagehistory: true + }) + commit('add', message) + }, + + async release({ dispatch, commit }, params) { + await this.$api.message.release(params.id) + const { message } = await this.$api.message.fetch({ + id: params.id, + messagehistory: true + }) + commit('add', message) } } diff --git a/store/stdmsgs.js b/store/stdmsgs.js index a3cace9ad..612758e7d 100644 --- a/store/stdmsgs.js +++ b/store/stdmsgs.js @@ -23,7 +23,6 @@ export const getters = { export const actions = { async fetch({ state, commit }, params) { const { stdmsg } = await this.$api.modconfigs.fetchStdMsg(params.id) - console.log('Fetched', stdmsg) commit('set', stdmsg) return stdmsg }