From 803122d76e09fecc63ac0cb3a54abe8e87ecbd0f Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Tue, 14 Feb 2023 15:15:34 +0000 Subject: [PATCH 01/12] Update email digest copy --- .../eagle-eye/components/list/eagle-eye-email-digest-card.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue index 7e59452032..9433e830c7 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-email-digest-card.vue @@ -11,8 +11,8 @@
- Receive automatically in your inbox a collection of up - to 10 most relevant results from Eagle Eye. + Receive the 10 most relevant results from Eagle Eye + automatically in your inbox.
Date: Tue, 14 Feb 2023 15:27:07 +0000 Subject: [PATCH 02/12] Add message to bottom of feed --- .../components/list/eagle-eye-list.vue | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue index 7757e0cd1c..810fb7004f 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue @@ -19,6 +19,14 @@ + + +
store.state.eagleEye.list.loading ) +const activeView = computed( + () => store.getters['eagleEye/activeView'] +) const count = computed(() => store.state.eagleEye.count) const pagination = computed( () => store.getters['eagleEye/pagination'] ) const isLoadMoreVisible = computed(() => { + if (activeView.value.id === 'feed') { + return false + } + return ( pagination.value.currentPage * pagination.value.pageSize < @@ -80,4 +95,8 @@ const onLoadMore = () => { pagination.value.currentPage + 1 ) } + +const showBottomFeedMessage = computed(() => { + return activeView.value.id === 'feed' +}) From 728829c99c7a93909d7f377e9c4847fad35e0a03 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Tue, 14 Feb 2023 15:50:02 +0000 Subject: [PATCH 03/12] Add excluded keywords and published date to feed settings --- .../components/list/eagle-eye-settings.vue | 185 +++++++++++------- 1 file changed, 109 insertions(+), 76 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue index 749a514908..c354ff5311 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-settings.vue @@ -7,68 +7,98 @@ various community platforms.
- -
-
- Keywords -
-
-
- {{ keyword }} +
+ +
+
+ Keywords
-
- "{{ exactKeyword }}" +
+
+ {{ keyword }} +
+
+ "{{ exactKeyword }}" +
+
+ + + {{ excludedKeyword }} + + +
-
- -
-
- Platforms + +
+
+ Published date +
+
+ {{ publishedDate }} +
-
-
- - {{ - platformOptions[platform].label - }} + + +
+
+ Platforms +
+
+
+ + {{ + platformOptions[platform].label + }} +
-
- - Feed settings - - - - + + Feed settings + + + + +
@@ -83,37 +113,40 @@ const { currentUser } = mapGetters('auth') const settingsDrawerOpen = ref(false) -const keywords = computed(() => { - const { eagleEyeSettings } = currentUser.value - - if (!eagleEyeSettings?.feed) { - return [] - } - - return eagleEyeSettings.feed.keywords +const eagleEyeFeedSettings = computed(() => { + return currentUser.value.eagleEyeSettings?.feed }) -const exactKeywords = computed(() => { - const { eagleEyeSettings } = currentUser.value +const keywords = computed( + () => eagleEyeFeedSettings.value.keywords +) - if (!eagleEyeSettings?.feed) { - return [] - } +const exactKeywords = computed( + () => eagleEyeFeedSettings.value.exactKeywords +) - return eagleEyeSettings.feed.exactKeywords -}) -const platforms = computed(() => { - const { eagleEyeSettings } = currentUser.value +const excludedKeywords = computed( + () => eagleEyeFeedSettings.value.excludedKeywords +) - if (!eagleEyeSettings?.feed) { - return [] - } +const platforms = computed( + () => eagleEyeFeedSettings.value.platforms +) - return eagleEyeSettings.feed.platforms -}) +const publishedDate = computed( + () => eagleEyeFeedSettings.value.publishedDate +) From 673db78c1d8dbc3821de384cc68530b05c472685 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Tue, 14 Feb 2023 17:02:32 +0000 Subject: [PATCH 04/12] Fix twitter display card --- .../components/list/eagle-eye-result-card.vue | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index caafbc80f1..d638f5781f 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -34,14 +34,25 @@
-
- {{ result.post.title }} -
{{ result.post.description }}
+
+
+ {{ result.post.title }} +
+
+ {{ result.post.description }} +
+
From b7ee96227f44e3e81d7611ee1a58c3994042cb9f Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Tue, 14 Feb 2023 20:03:25 +0000 Subject: [PATCH 05/12] Fix set results in storage --- frontend/src/premium/eagle-eye/store/actions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 4aabde6c87..43349096a2 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -177,7 +177,8 @@ export default { rootGetters['auth/currentTenant'] setResultsInStorage({ - posts: state.list.posts, + storageDate: moment(), + posts: state.views[activeView].list.posts, tenantId: currentTenant.id, userId: currentUser.id }) @@ -219,7 +220,8 @@ export default { rootGetters['auth/currentTenant'] setResultsInStorage({ - posts: state.list.posts, + storageDate: moment(), + posts: state.views[activeView].list.posts, tenantId: currentTenant.id, userId: currentUser.id }) From 51dcacaa7dd4c5d57c182d73e355f149c7e9e874 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Wed, 15 Feb 2023 14:22:33 +0000 Subject: [PATCH 06/12] Fix buttons state --- .../components/list/eagle-eye-result-card.vue | 85 ++++----------- .../src/premium/eagle-eye/store/actions.js | 103 +++++++++++++----- .../src/premium/eagle-eye/store/mutations.js | 44 ++++---- 3 files changed, 122 insertions(+), 110 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index d638f5781f..685817d213 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -62,21 +62,15 @@
- +
- +
@@ -143,8 +130,7 @@ class="h-8 w-8 flex items-center justify-center rounded-full hover:bg-gray-200 group" :class="{ 'bg-blue-100 hover:bg-blue-100': isBookmarked, - 'pointer-events-none bg-transparent': - isBookmarkDisabled + 'pointer-events-none': isBookmarkedByTeam }" @click.stop=" onActionClick({ @@ -157,11 +143,11 @@ class="text-lg text-gray-400 group-hover:text-gray-900" :class="{ 'ri-bookmark-line text-gray-400': - !isBookmarked && !isBookmarkDisabled, + !isBookmarked && !isBookmarkedByTeam, 'ri-bookmark-fill text-blue-600 group-hover:text-blue-600': - isBookmarked && !isBookmarkDisabled, + isBookmarked && !isBookmarkedByTeam, 'ri-bookmark-fill text-blue-300': - isBookmarkDisabled + isBookmarkedByTeam }" />
@@ -197,7 +183,6 @@ const { currentUser } = mapGetters('auth') const { doAddAction, doRemoveAction } = mapActions('eagleEye') -const isLoading = computed(() => props.result.loading) const isBookmarked = computed(() => props.result.actions.some((a) => a.type === 'bookmark') ) @@ -207,19 +192,20 @@ const isRelevant = computed(() => const isNotRelevant = computed(() => props.result.actions.some((a) => a.type === 'thumbs-down') ) -const isBookmarkedByUser = computed( - () => - props.result.actions.find((a) => a.type === 'bookmark') - ?.actionById === currentUser.value.id -) - -const isBookmarkDisabled = computed(() => { +const isBookmarkedByUser = computed(() => { + const bookmarkAction = props.result.actions.find( + (a) => a.type === 'bookmark' + ) return ( - isLoading.value || - (isBookmarked.value && !isBookmarkedByUser.value) + !bookmarkAction?.actionById || + bookmarkAction?.actionById === currentUser.value.id ) }) +const isBookmarkedByTeam = computed(() => { + return isBookmarked.value && !isBookmarkedByUser.value +}) + const bookmarkTooltip = computed(() => { if (isBookmarked.value && !isBookmarkedByUser.value) { return 'Bookmarked by team member' @@ -242,38 +228,11 @@ const onCardClick = async (e) => { }) } -// If opposite thumbs up is set, remove before creating the new action -const onThumbsClick = async ({ actionType, shouldAdd }) => { - if (isLoading.value) { - return - } - - if (actionType === 'thumbs-up' && isNotRelevant.value) { - await onActionClick({ - actionType: 'thumbs-down', - shouldAdd: false - }) - } - - if (actionType === 'thumbs-down' && isRelevant.value) { - await onActionClick({ - actionType: 'thumbs-up', - shouldAdd: false - }) - } - - await onActionClick({ actionType, shouldAdd }) -} - const onActionClick = async ({ actionType, shouldAdd }) => { - if (isLoading.value) { - return - } - if (shouldAdd) { await doAddAction({ post: props.result, - action: actionType, + actionType, index: props.index }) } else { diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index 43349096a2..e6d9737e90 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -8,6 +8,7 @@ import { shouldFetchNewResults, isStorageUpdating } from '@/premium/eagle-eye/eagle-eye-storage' +import Message from '@/shared/message/message' export default { ...sharedActions('eagleEye'), @@ -131,37 +132,76 @@ export default { async doAddAction( { state, commit, getters, rootGetters }, - { post, action, index } + { post, actionType, index } ) { const activeView = getters.activeView.id try { - commit('UPDATE_ACTION_LOADING', { + let updatedPost = JSON.parse(JSON.stringify(post)) + const oppositeActionTypes = { + ['thumbs-up']: 'thumbs-down', + ['thumbs-down']: 'thumbs-up' + } + const actionData = { + type: actionType, + timestamp: moment().utc().format('YYYY-MM-DD') + } + + // Add action to post, update immeadiately in the UI + commit('CREATE_ACTION_SUCCESS', { + action: actionData, index, activeView }) - // Create content in database - const postResponse = - await EagleEyeService.createContent({ - post + const oppositeAction = post.actions.find( + (a) => a.type === oppositeActionTypes[actionType] + ) + + // If action is thumbs up, delete opposite thumbs from post + if ( + oppositeActionTypes[actionType] && + oppositeAction + ) { + // Delete action from post, update immeadiately in the UI + commit('DELETE_ACTION_SUCCESS', { + actionType: oppositeActionTypes[actionType], + index, + activeView }) - commit('CREATE_CONTENT_SUCCESS', { - post: postResponse, - index, - activeView - }) + updatedPost.actions = updatedPost.actions.filter( + (a) => a.type !== oppositeActionTypes[actionType] + ) - // Add action to db content - const actionData = { - type: action, - timestamp: moment().utc().format('YYYY-MM-DD') + await EagleEyeService.deleteAction({ + postId: updatedPost.id, + actionId: oppositeAction.id + }) + } + + // Create content in database if payload does not have any actions yet + if (!updatedPost.actions.length) { + updatedPost = await EagleEyeService.createContent({ + post: { + actions: updatedPost.actions, + platform: updatedPost.platform, + post: updatedPost.post, + postedAt: updatedPost.postedAt, + url: updatedPost.url + } + }) + + commit('CREATE_CONTENT_SUCCESS', { + post: updatedPost, + index, + activeView + }) } const actionResponse = await EagleEyeService.addAction({ - postId: postResponse.id, + postId: updatedPost.id, actionData }) @@ -183,9 +223,14 @@ export default { userId: currentUser.id }) } catch (error) { + Message.error( + 'Something went wrong. Please try again' + ) + commit('UPDATE_ACTION_ERROR', { index, - activeView + activeView, + actions: post.actions }) } }, @@ -195,9 +240,14 @@ export default { { postId, actionId, actionType, index } ) { const activeView = getters.activeView.id + const postActions = + state.views[activeView].list.posts.find( + (p) => p.id === postId + )?.actions || [] try { - commit('UPDATE_ACTION_LOADING', { + commit('DELETE_ACTION_SUCCESS', { + actionType, index, activeView }) @@ -207,13 +257,6 @@ export default { actionId }) - commit('DELETE_ACTION_SUCCESS', { - actionId, - actionType, - index, - activeView - }) - // Update local storage with updated action const currentUser = rootGetters['auth/currentUser'] const currentTenant = @@ -226,7 +269,15 @@ export default { userId: currentUser.id }) } catch (error) { - commit('UPDATE_ACTION_ERROR', { index, activeView }) + Message.error( + 'Something went wrong. Please try again' + ) + + commit('UPDATE_ACTION_ERROR', { + index, + activeView, + actions: postActions + }) } }, diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 2a2552f21f..3fdfdde13a 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -37,17 +37,14 @@ export default { state.views[activeView].count = 0 }, - UPDATE_ACTION_LOADING(state, { index, activeView }) { - state.views[activeView].list.posts[index].loading = true - }, - CREATE_CONTENT_SUCCESS( state, { post, index, activeView } ) { state.views[activeView].list.posts[index] = { - ...state.views[activeView].list.posts[index], - ...post + ...post, + actions: + state.views[activeView].list.posts[index].actions } }, @@ -55,22 +52,25 @@ export default { state, { action, index, activeView } ) { - state.views[activeView].list.posts[ + const indexAction = state.views[activeView].list.posts[ index - ].loading = false - state.views[activeView].list.posts[index].actions.push( - action - ) + ].actions.findIndex((a) => a.type === action.type) + + if (indexAction === -1) { + state.views[activeView].list.posts[ + index + ].actions.push(action) + } else { + state.views[activeView].list.posts[index].actions[ + indexAction + ] = action + } }, DELETE_ACTION_SUCCESS( state, - { actionId, actionType, index, activeView } + { actionType, index, activeView } ) { - state.views[activeView].list.posts[ - index - ].loading = false - // Remove post from bookmarks view if ( actionType === 'bookmark' && @@ -82,7 +82,7 @@ export default { const deleteIndex = state.views[ activeView ].list.posts[index].actions.findIndex( - (a) => a.id === actionId + (a) => a.type === actionType ) state.views[activeView].list.posts[ @@ -91,10 +91,12 @@ export default { } }, - UPDATE_ACTION_ERROR(state, { index, activeView }) { - state.views[activeView].list.posts[ - index - ].loading = false + UPDATE_ACTION_ERROR( + state, + { index, activeView, actions } + ) { + state.views[activeView].list.posts[index].actions = + actions }, SORTER_CHANGED(state, payload) { From 44f018f01a8515fe5a71e12f751ce3e70b8a70de Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Wed, 15 Feb 2023 15:30:04 +0000 Subject: [PATCH 07/12] Fix pagination --- .../components/list/eagle-eye-list.vue | 13 +++++--- .../src/premium/eagle-eye/store/actions.js | 18 +++++++++-- .../src/premium/eagle-eye/store/getters.js | 31 +++++++++++++++++++ .../src/premium/eagle-eye/store/mutations.js | 31 +++++++++++++++++-- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue index 810fb7004f..30cd68c952 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue @@ -60,13 +60,18 @@ const props = defineProps({ }) const store = useStore() -const loading = computed( - () => store.state.eagleEye.list.loading -) const activeView = computed( () => store.getters['eagleEye/activeView'] ) -const count = computed(() => store.state.eagleEye.count) +const loading = computed( + () => + store.state.eagleEye.views[activeView.value.id].list + .loading +) +const count = computed( + () => + store.state.eagleEye.views[activeView.value.id].count +) const pagination = computed( () => store.getters['eagleEye/pagination'] ) diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index e6d9737e90..dbd1401928 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -211,6 +211,13 @@ export default { activeView }) + // Also update action from feed posts + if (activeView === 'bookmarked') { + commit('UPDATE_FEED_POST_SUCCESS', { + postId: post.id + }) + } + // Update local storage with updated action const currentUser = rootGetters['auth/currentUser'] const currentTenant = @@ -218,7 +225,7 @@ export default { setResultsInStorage({ storageDate: moment(), - posts: state.views[activeView].list.posts, + posts: state.views['feed'].list.posts, tenantId: currentTenant.id, userId: currentUser.id }) @@ -257,6 +264,13 @@ export default { actionId }) + // Also remove action from feed posts + if (activeView === 'bookmarked') { + commit('UPDATE_FEED_POST_SUCCESS', { + postId + }) + } + // Update local storage with updated action const currentUser = rootGetters['auth/currentUser'] const currentTenant = @@ -264,7 +278,7 @@ export default { setResultsInStorage({ storageDate: moment(), - posts: state.views[activeView].list.posts, + posts: state.views['feed'].list.posts, tenantId: currentTenant.id, userId: currentUser.id }) diff --git a/frontend/src/premium/eagle-eye/store/getters.js b/frontend/src/premium/eagle-eye/store/getters.js index 2ebedde6fe..b52596f2df 100644 --- a/frontend/src/premium/eagle-eye/store/getters.js +++ b/frontend/src/premium/eagle-eye/store/getters.js @@ -1,4 +1,5 @@ import sharedGetters from '@/shared/store/getters' +import { INITIAL_PAGE_SIZE } from './constants' export default { ...sharedGetters(), @@ -7,5 +8,35 @@ export default { const activeView = sharedGetters().activeView(state) return state.views[activeView.id].list + }, + + pagination: (state, getters) => { + return { + ...getters.activeView.pagination, + total: getters.activeView.count, + showSizeChanger: true + } + }, + + limit: (state, getters) => { + const { pagination } = getters.activeView + + if (!pagination?.pageSize) { + return INITIAL_PAGE_SIZE + } + + return pagination.pageSize + }, + + offset: (state, getters) => { + const { pagination } = getters.activeView + + if (!pagination?.pageSize) { + return 0 + } + + const { currentPage = 1 } = pagination + + return (currentPage - 1) * pagination.pageSize } } diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 3fdfdde13a..4aec55a796 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -24,11 +24,11 @@ export default { ) { state.views[activeView].list.loading = false if (appendToList) { - state.views[activeView].list.posts.concat(list) + state.views[activeView].list.posts.push(...list) } else { state.views[activeView].list.posts = list } - state.count = count + state.views[activeView].count = count }, FETCH_ERROR(state, { activeView }) { @@ -67,15 +67,40 @@ export default { } }, + UPDATE_FEED_POST_SUCCESS(state, { postId }) { + const feedPostIndex = state.views[ + 'feed' + ].list.posts.findIndex((p) => p.id === postId) + + const bookmarkPost = state.views[ + 'bookmarked' + ].list.posts.find((p) => p.id === postId) + + // Update feed with action + if (feedPostIndex && bookmarkPost) { + state.views['feed'].list.posts[feedPostIndex] = + bookmarkPost + // Scenario for bookmarks + } else if (feedPostIndex) { + const actionIndex = state.views['feed'].list.posts[ + feedPostIndex + ].actions.findIndex((a) => a.type === 'bookmark') + + state.views['feed'].list.posts[ + feedPostIndex + ].actions.splice(actionIndex, 1) + } + }, + DELETE_ACTION_SUCCESS( state, { actionType, index, activeView } ) { - // Remove post from bookmarks view if ( actionType === 'bookmark' && activeView === 'bookmarked' ) { + // Remove post from bookmarks view state.views[activeView].list.posts.splice(index, 1) // Remove action from post } else { From 8543cde99db066ee520fc44b5883fd0ee85620d7 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Wed, 15 Feb 2023 17:04:46 +0000 Subject: [PATCH 08/12] Fix eagle eye page grid --- .../components/list/eagle-eye-list.vue | 2 +- .../list/eagle-eye-loading-state.vue | 2 +- .../eagle-eye/pages/eagle-eye-page.vue | 48 ++++++++++++++----- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue index 30cd68c952..99d92683b1 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue @@ -1,6 +1,6 @@ @@ -49,6 +52,15 @@ const store = useStore() const { activeView, activeViewList } = mapGetters('eagleEye') +const cssVars = computed(() => { + const isMenuCollapsed = + store.getters['layout/menuCollapsed'] + const menuWidth = isMenuCollapsed ? '64px' : '260px' + + return { + '--eagle-eye-padding': menuWidth + } +}) const list = computed(() => activeViewList.value.posts) const isLoading = computed(() => { if (activeView.value.id === 'feed') { @@ -86,3 +98,17 @@ onMounted(async () => { } }) + + From 6b37306ef77027eabae0b0146ea4c101ee4c3050 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Thu, 16 Feb 2023 02:59:58 +0000 Subject: [PATCH 09/12] Refactor actions approach for eagle eye --- .../components/list/eagle-eye-result-card.vue | 67 ++-- .../premium/eagle-eye/eagle-eye-service.js | 4 +- .../src/premium/eagle-eye/store/actions.js | 286 +++++++++--------- .../src/premium/eagle-eye/store/mutations.js | 127 ++++---- frontend/src/premium/eagle-eye/store/state.js | 2 + 5 files changed, 262 insertions(+), 224 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index 685817d213..ac8e983784 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -163,10 +163,9 @@ import { computed, defineProps } from 'vue' import platformOptions from '@/premium/eagle-eye/constants/eagle-eye-platforms.json' import { EagleEyeService } from '../../eagle-eye-service' import { withHttp } from '@/utils/string' -import { - mapActions, - mapGetters -} from '@/shared/vuex/vuex.helpers' +import { mapGetters } from '@/shared/vuex/vuex.helpers' +import { useStore } from 'vuex' +import moment from 'moment' const props = defineProps({ result: { @@ -179,18 +178,23 @@ const props = defineProps({ } }) +const store = useStore() const { currentUser } = mapGetters('auth') -const { doAddAction, doRemoveAction } = - mapActions('eagleEye') const isBookmarked = computed(() => - props.result.actions.some((a) => a.type === 'bookmark') + props.result.actions.some( + (a) => a.type === 'bookmark' && !a.toRemove + ) ) const isRelevant = computed(() => - props.result.actions.some((a) => a.type === 'thumbs-up') + props.result.actions.some( + (a) => a.type === 'thumbs-up' && !a.toRemove + ) ) const isNotRelevant = computed(() => - props.result.actions.some((a) => a.type === 'thumbs-down') + props.result.actions.some( + (a) => a.type === 'thumbs-down' && !a.toRemove + ) ) const isBookmarkedByUser = computed(() => { const bookmarkAction = props.result.actions.find( @@ -229,23 +233,34 @@ const onCardClick = async (e) => { } const onActionClick = async ({ actionType, shouldAdd }) => { - if (shouldAdd) { - await doAddAction({ - post: props.result, - actionType, - index: props.index - }) - } else { - const actionId = props.result.actions.find( - (a) => a.type === actionType - ).id - await doRemoveAction({ - postId: props.result.id, - actionId, - actionType, - index: props.index - }) - } + const storeActionType = shouldAdd ? 'add' : 'delete' + const action = shouldAdd + ? { + type: actionType, + timestamp: moment() + } + : props.result.actions.find( + (a) => a.type === actionType + ) + + store.dispatch('eagleEye/doAddTemporaryPostAction', { + index: props.index, + storeActionType, + action + }) + + store.dispatch('eagleEye/doAddActionQueue', { + index: props.index, + storeActionType, + action, + handler: async () => + await store.dispatch('eagleEye/doUpdatePostAction', { + post: props.result, + index: props.index, + storeActionType, + actionType + }) + }) } diff --git a/frontend/src/premium/eagle-eye/eagle-eye-service.js b/frontend/src/premium/eagle-eye/eagle-eye-service.js index bbc15f1f7a..bbc7620013 100644 --- a/frontend/src/premium/eagle-eye/eagle-eye-service.js +++ b/frontend/src/premium/eagle-eye/eagle-eye-service.js @@ -53,12 +53,12 @@ export class EagleEyeService { return response.data } - static async addAction({ postId, actionData }) { + static async addAction({ postId, action }) { const tenantId = AuthCurrentTenant.get() const response = await authAxios.post( `/tenant/${tenantId}/eagleEyeContent/${postId}/action`, - actionData + action ) return response.data diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index dbd1401928..e65e4aa933 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -130,169 +130,183 @@ export default { } }, - async doAddAction( - { state, commit, getters, rootGetters }, - { post, actionType, index } + // Add temporary actions to post so that UI updates immeadiately + async doAddTemporaryPostAction( + { commit, getters }, + { index, storeActionType, action } ) { const activeView = getters.activeView.id - try { - let updatedPost = JSON.parse(JSON.stringify(post)) - const oppositeActionTypes = { - ['thumbs-up']: 'thumbs-down', - ['thumbs-down']: 'thumbs-up' - } - const actionData = { - type: actionType, - timestamp: moment().utc().format('YYYY-MM-DD') - } - - // Add action to post, update immeadiately in the UI - commit('CREATE_ACTION_SUCCESS', { - action: actionData, - index, - activeView + // Add new action + if (storeActionType === 'add') { + commit('CREATE_TEMPORARY_ACTION', { + action, + activeView, + index }) + // Remove action + } else { + commit('REMOVE_TEMPORARY_ACTION', { + action, + activeView, + index + }) + } + }, - const oppositeAction = post.actions.find( - (a) => a.type === oppositeActionTypes[actionType] - ) - - // If action is thumbs up, delete opposite thumbs from post - if ( - oppositeActionTypes[actionType] && - oppositeAction - ) { - // Delete action from post, update immeadiately in the UI - commit('DELETE_ACTION_SUCCESS', { - actionType: oppositeActionTypes[actionType], - index, - activeView - }) - - updatedPost.actions = updatedPost.actions.filter( - (a) => a.type !== oppositeActionTypes[actionType] - ) - - await EagleEyeService.deleteAction({ - postId: updatedPost.id, - actionId: oppositeAction.id - }) - } - - // Create content in database if payload does not have any actions yet - if (!updatedPost.actions.length) { - updatedPost = await EagleEyeService.createContent({ - post: { - actions: updatedPost.actions, - platform: updatedPost.platform, - post: updatedPost.post, - postedAt: updatedPost.postedAt, - url: updatedPost.url - } - }) + // Add or remove actions from the database depending on the action type + async doUpdatePostAction( + { state, dispatch, getters }, + { post, index, storeActionType, actionType } + ) { + const activeView = getters.activeView.id + const action = state.views[activeView].list.posts[ + index + ].actions.find((a) => a.type === actionType) || { + type: actionType, + timestamp: moment() + } + // Add new action + if (storeActionType === 'add') { + await dispatch('doAddAction', { + post, + action, + index + }) + // Remove action + } else { + await dispatch('doRemoveAction', { + postId: post.id, + action, + index + }) + } + }, - commit('CREATE_CONTENT_SUCCESS', { - post: updatedPost, - index, - activeView - }) - } + async doAddAction( + { state, commit, getters, rootGetters }, + { post, action, index } + ) { + const activeView = getters.activeView.id + const oppositeActionTypes = { + ['thumbs-up']: 'thumbs-down', + ['thumbs-down']: 'thumbs-up' + } + const oppositeAction = state.views[ + activeView + ].list.posts[index].actions.find( + (a) => a.type === oppositeActionTypes[action.type] + ) - const actionResponse = - await EagleEyeService.addAction({ - postId: updatedPost.id, - actionData - }) + // If action is thumbs, delete opposite thumbs from post + if ( + oppositeActionTypes[action.type] && + oppositeAction + ) { + commit('REMOVE_TEMPORARY_ACTION', { + action: oppositeAction, + activeView, + index + }) - commit('CREATE_ACTION_SUCCESS', { - action: actionResponse, - index, - activeView + await EagleEyeService.deleteAction({ + postId: post.id, + actionId: oppositeAction.id }) + } - // Also update action from feed posts - if (activeView === 'bookmarked') { - commit('UPDATE_FEED_POST_SUCCESS', { - postId: post.id - }) + const postDb = await EagleEyeService.createContent({ + post: { + actions: [], + platform: post.platform, + post: post.post, + postedAt: post.postedAt, + url: post.url } + }) - // Update local storage with updated action - const currentUser = rootGetters['auth/currentUser'] - const currentTenant = - rootGetters['auth/currentTenant'] + const actionDb = await EagleEyeService.addAction({ + postId: postDb.id, + action + }) - setResultsInStorage({ - storageDate: moment(), - posts: state.views['feed'].list.posts, - tenantId: currentTenant.id, - userId: currentUser.id - }) - } catch (error) { - Message.error( - 'Something went wrong. Please try again' - ) + commit('CREATE_ACTION_SUCCESS', { + post: postDb, + action: actionDb, + index, + activeView + }) - commit('UPDATE_ACTION_ERROR', { - index, - activeView, - actions: post.actions - }) - } + // Update posts with new actions in local storage + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = rootGetters['auth/currentTenant'] + + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) }, async doRemoveAction( { state, commit, getters, rootGetters }, - { postId, actionId, actionType, index } + { postId, action, index } ) { const activeView = getters.activeView.id - const postActions = - state.views[activeView].list.posts.find( - (p) => p.id === postId - )?.actions || [] - try { - commit('DELETE_ACTION_SUCCESS', { - actionType, - index, - activeView - }) + await EagleEyeService.deleteAction({ + postId, + actionId: action.id + }) - await EagleEyeService.deleteAction({ - postId, - actionId - }) + commit('REMOVE_ACTION_SUCCESS', { + action, + index, + activeView + }) - // Also remove action from feed posts - if (activeView === 'bookmarked') { - commit('UPDATE_FEED_POST_SUCCESS', { - postId - }) - } + // Update posts with new actions in local storage + const currentUser = rootGetters['auth/currentUser'] + const currentTenant = rootGetters['auth/currentTenant'] - // Update local storage with updated action - const currentUser = rootGetters['auth/currentUser'] - const currentTenant = - rootGetters['auth/currentTenant'] + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) + }, - setResultsInStorage({ - storageDate: moment(), - posts: state.views['feed'].list.posts, - tenantId: currentTenant.id, - userId: currentUser.id - }) - } catch (error) { - Message.error( - 'Something went wrong. Please try again' - ) + doAddActionQueue({ commit, state, dispatch }, job) { + commit('ADD_PENDING_ACTION', job) - commit('UPDATE_ACTION_ERROR', { - index, - activeView, - actions: postActions - }) + // If there are no actions active, start the next one in the queue + if (Object.keys(state.activeAction).length == 0) { + dispatch('doStartActionQueue') + } + }, + + async doStartActionQueue({ commit, dispatch, state }) { + if (state.pendingActions.length > 0) { + commit('SET_ACTIVE_ACTION', state.pendingActions[0]) + + const pendingAction = { ...state.pendingActions[0] } + + commit('POP_CURRENT_ACTION') + + try { + await pendingAction.handler() + await dispatch('doStartActionQueue') + } catch (error) { + Message.error( + 'Something went wrong. Please try again' + ) + commit('SET_ACTIVE_ACTION', {}) + } } + + commit('SET_ACTIVE_ACTION', {}) }, async doUpdateSettings({ commit, dispatch }, data) { diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 4aec55a796..79723b50a3 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -37,91 +37,86 @@ export default { state.views[activeView].count = 0 }, - CREATE_CONTENT_SUCCESS( - state, - { post, index, activeView } - ) { - state.views[activeView].list.posts[index] = { - ...post, - actions: - state.views[activeView].list.posts[index].actions - } + UPDATE_ACTION_ERROR() { + // state.views[activeView].list.posts[index].actions = + // actions + // TODO }, CREATE_ACTION_SUCCESS( state, - { action, index, activeView } + { post, action, index, activeView } ) { - const indexAction = state.views[activeView].list.posts[ - index - ].actions.findIndex((a) => a.type === action.type) + const { actions } = + state.views[activeView].list.posts[index] + const indexAction = actions.findIndex( + (a) => a.type === action.type + ) - if (indexAction === -1) { - state.views[activeView].list.posts[ - index - ].actions.push(action) - } else { - state.views[activeView].list.posts[index].actions[ - indexAction - ] = action + // Update store post with new one, except for actions + state.views[activeView].list.posts[index] = { + ...post, + actions } - }, - UPDATE_FEED_POST_SUCCESS(state, { postId }) { - const feedPostIndex = state.views[ - 'feed' - ].list.posts.findIndex((p) => p.id === postId) - - const bookmarkPost = state.views[ - 'bookmarked' - ].list.posts.find((p) => p.id === postId) - - // Update feed with action - if (feedPostIndex && bookmarkPost) { - state.views['feed'].list.posts[feedPostIndex] = - bookmarkPost - // Scenario for bookmarks - } else if (feedPostIndex) { - const actionIndex = state.views['feed'].list.posts[ - feedPostIndex - ].actions.findIndex((a) => a.type === 'bookmark') - - state.views['feed'].list.posts[ - feedPostIndex - ].actions.splice(actionIndex, 1) + if (indexAction === -1) { + actions.push(action) + } else { + actions[indexAction] = action } }, - DELETE_ACTION_SUCCESS( + REMOVE_ACTION_SUCCESS( state, - { actionType, index, activeView } + { action, index, activeView } ) { + // Remove post from bookmarks view if ( - actionType === 'bookmark' && + action.type === 'bookmark' && activeView === 'bookmarked' ) { - // Remove post from bookmarks view state.views[activeView].list.posts.splice(index, 1) - // Remove action from post } else { - const deleteIndex = state.views[ - activeView - ].list.posts[index].actions.findIndex( - (a) => a.type === actionType + // Remove action from post + const { actions } = + state.views[activeView].list.posts[index] + const deleteIndex = actions.findIndex( + (a) => a.type === action.type ) - state.views[activeView].list.posts[ - index - ].actions.splice(deleteIndex, 1) + actions.splice(deleteIndex, 1) } }, - UPDATE_ACTION_ERROR( + CREATE_TEMPORARY_ACTION( state, - { index, activeView, actions } + { action, activeView, index } ) { - state.views[activeView].list.posts[index].actions = - actions + const { actions } = + state.views[activeView].list.posts[index] + const indexAction = actions.findIndex( + (a) => a.type === action.type + ) + + if (indexAction === -1) { + actions.push(action) + } else { + actions[indexAction] = action + } + }, + + REMOVE_TEMPORARY_ACTION( + state, + { action, activeView, index } + ) { + // TODO: Handle bookmarks + const { actions } = + state.views[activeView].list.posts[index] + const deleteIndex = actions.findIndex( + (a) => a.type === action.type + ) + + actions[deleteIndex].toRemove = true }, SORTER_CHANGED(state, payload) { @@ -139,5 +134,17 @@ export default { UPDATE_EAGLE_EYE_SETTINGS_ERROR(state) { state.loadingUpdateSettings = false + }, + + ADD_PENDING_ACTION(state, job) { + state.pendingActions.push(job) + }, + + SET_ACTIVE_ACTION(state, job) { + state.activeAction = job + }, + + POP_CURRENT_ACTION(state) { + state.pendingActions.shift() } } diff --git a/frontend/src/premium/eagle-eye/store/state.js b/frontend/src/premium/eagle-eye/store/state.js index 8a37deec75..8e92f374b2 100644 --- a/frontend/src/premium/eagle-eye/store/state.js +++ b/frontend/src/premium/eagle-eye/store/state.js @@ -30,6 +30,8 @@ export default () => { active: false } }, + pendingActions: [], + activeAction: {}, loadingUpdateSettings: false } } From f9d0bb7922c9b7d9d66d20e7f395ca32b1ff0eb1 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Thu, 16 Feb 2023 03:09:28 +0000 Subject: [PATCH 10/12] Add subreddit to reddit posts --- .../components/list/eagle-eye-list.vue | 2 +- .../components/list/eagle-eye-result-card.vue | 28 ++++++++- .../src/premium/eagle-eye/store/actions.js | 61 +++++++++++++++--- .../src/premium/eagle-eye/store/mutations.js | 62 ++++++++++++++++--- 4 files changed, 133 insertions(+), 20 deletions(-) diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue index 99d92683b1..05679794b6 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-list.vue @@ -23,7 +23,7 @@ diff --git a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue index ac8e983784..1deda47ba5 100644 --- a/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue +++ b/frontend/src/premium/eagle-eye/components/list/eagle-eye-result-card.vue @@ -41,6 +41,14 @@ {{ result.post.description }}
+ + {{ subreddit }} +
{ return isBookmarked.value ? 'Unbookmark' : 'Bookmark' }) +const subreddit = computed(() => { + if (props.result.platform !== 'reddit') { + return null + } + + const pattern = + /.*reddit\.com(?\/r\/.[^\\/]*).*/gm + const matches = pattern.exec(props.result.url) + + if (!matches.groups.subreddit) { + return null + } + + return matches.groups.subreddit.slice(1) +}) + // Open post in origin url const onCardClick = async (e) => { if (!props.result.url || e.target.localName === 'a') { @@ -251,8 +275,8 @@ const onActionClick = async ({ actionType, shouldAdd }) => { store.dispatch('eagleEye/doAddActionQueue', { index: props.index, - storeActionType, - action, + id: props.result.id, + post: props.result, handler: async () => await store.dispatch('eagleEye/doUpdatePostAction', { post: props.result, diff --git a/frontend/src/premium/eagle-eye/store/actions.js b/frontend/src/premium/eagle-eye/store/actions.js index e65e4aa933..761500db41 100644 --- a/frontend/src/premium/eagle-eye/store/actions.js +++ b/frontend/src/premium/eagle-eye/store/actions.js @@ -254,17 +254,33 @@ export default { { postId, action, index } ) { const activeView = getters.activeView.id + const actionId = action.id + const deleteImmeadiately = + activeView === 'bookmarked' && + action.type === 'bookmark' + + if (deleteImmeadiately) { + commit('REMOVE_ACTION_SUCCESS', { + postId, + action, + index, + activeView + }) + } await EagleEyeService.deleteAction({ postId, - actionId: action.id + actionId }) - commit('REMOVE_ACTION_SUCCESS', { - action, - index, - activeView - }) + if (!deleteImmeadiately) { + commit('REMOVE_ACTION_SUCCESS', { + postId, + action, + index, + activeView + }) + } // Update posts with new actions in local storage const currentUser = rootGetters['auth/currentUser'] @@ -287,7 +303,13 @@ export default { } }, - async doStartActionQueue({ commit, dispatch, state }) { + async doStartActionQueue({ + commit, + dispatch, + state, + getters, + rootGetters + }) { if (state.pendingActions.length > 0) { commit('SET_ACTIVE_ACTION', state.pendingActions[0]) @@ -299,6 +321,31 @@ export default { await pendingAction.handler() await dispatch('doStartActionQueue') } catch (error) { + // In case of an error, create post again and update it in UI + EagleEyeService.createContent({ + post: pendingAction.post + }).then((response) => { + const activeView = getters.activeView.id + const currentUser = + rootGetters['auth/currentUser'] + const currentTenant = + rootGetters['auth/currentTenant'] + + commit('UPDATE_POST', { + activeView, + index: pendingAction.index, + post: response + }) + + // Update posts with new actions in local storage + setResultsInStorage({ + posts: state.views['feed'].list.posts, + storageDate: moment(), + tenantId: currentTenant.id, + userId: currentUser.id + }) + }) + Message.error( 'Something went wrong. Please try again' ) diff --git a/frontend/src/premium/eagle-eye/store/mutations.js b/frontend/src/premium/eagle-eye/store/mutations.js index 79723b50a3..a1d399bb2a 100644 --- a/frontend/src/premium/eagle-eye/store/mutations.js +++ b/frontend/src/premium/eagle-eye/store/mutations.js @@ -37,16 +37,32 @@ export default { state.views[activeView].count = 0 }, - UPDATE_ACTION_ERROR() { - // state.views[activeView].list.posts[index].actions = - // actions - // TODO - }, - CREATE_ACTION_SUCCESS( state, { post, action, index, activeView } ) { + // Update feed post if bookmark action is updated + if (activeView === 'bookmarked') { + const feedPost = state.views['feed'].list.posts.find( + (p) => p.url === post.url + ) + + if (feedPost) { + const indexAction = feedPost.actions.findIndex( + (a) => a.type === action.type + ) + + if (indexAction === -1) { + feedPost.actions.push(action) + } else { + feedPost.actions[indexAction] = { + ...action, + id: action.id + } + } + } + } + const { actions } = state.views[activeView].list.posts[index] const indexAction = actions.findIndex( @@ -62,14 +78,35 @@ export default { if (indexAction === -1) { actions.push(action) } else { - actions[indexAction] = action + actions[indexAction] = { + ...action, + id: action.id + } } }, REMOVE_ACTION_SUCCESS( state, - { action, index, activeView } + { postId, action, index, activeView } ) { + // Update feed post if bookmark action is updated + if (activeView === 'bookmarked') { + const feedPost = state.views['feed'].list.posts.find( + (p) => p.id === postId + ) + + if (feedPost) { + const deleteIndex = feedPost.actions.findIndex( + (a) => a.type === action.type + ) + + if (deleteIndex !== -1) { + feedPost.actions.splice(deleteIndex, 1) + console.log(feedPost.actions) + } + } + } + // Remove post from bookmarks view if ( action.type === 'bookmark' && @@ -84,7 +121,9 @@ export default { (a) => a.type === action.type ) - actions.splice(deleteIndex, 1) + if (deleteIndex !== -1) { + actions.splice(deleteIndex, 1) + } } }, @@ -109,7 +148,6 @@ export default { state, { action, activeView, index } ) { - // TODO: Handle bookmarks const { actions } = state.views[activeView].list.posts[index] const deleteIndex = actions.findIndex( @@ -119,6 +157,10 @@ export default { actions[deleteIndex].toRemove = true }, + UPDATE_POST(state, { activeView, index, post }) { + state.views[activeView].list.posts[index] = post + }, + SORTER_CHANGED(state, payload) { const { activeView, sorter } = payload state.views[activeView.id].sorter = sorter From a3beae0b83cd1ea5154c3322e5da2a164ebe9c49 Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Thu, 16 Feb 2023 16:26:19 +0000 Subject: [PATCH 11/12] Updage eagle eye page margins --- .../src/premium/eagle-eye/pages/eagle-eye-page.vue | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 0709430afe..70042d05c4 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -2,18 +2,18 @@
@@ -102,13 +102,15 @@ onMounted(async () => { From 6a7e8d4715bfe64ebf992d651d9fab2b55ad120b Mon Sep 17 00:00:00 2001 From: Joana Maia Date: Thu, 16 Feb 2023 16:32:18 +0000 Subject: [PATCH 12/12] Update pixel value --- frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue index 70042d05c4..26243af5ae 100644 --- a/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue +++ b/frontend/src/premium/eagle-eye/pages/eagle-eye-page.vue @@ -2,7 +2,7 @@