From 226ec676b23aa1e6040776462ca09404027c2c7c Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 18 Sep 2021 14:49:57 +0300 Subject: [PATCH 1/8] Move related-media-store to 'store' --- src/store/index.js | 4 -- .../related.js} | 44 ++++++++++--------- .../specs/store/related-media-store.spec.js | 33 ++++++-------- 3 files changed, 37 insertions(+), 44 deletions(-) rename src/{store-modules/related-media-store.js => store/related.js} (64%) diff --git a/src/store/index.js b/src/store/index.js index 4735e0d6071..c87c6dc6ea9 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -14,7 +14,6 @@ import UserStore from '~/store-modules/user-store' import UsageDataStore from '~/store-modules/usage-data-store' import FilterStore from '~/store-modules/filter-store' import ReportContentStore from '~/store-modules/report-content-store' -import RelatedMediaStore from '~/store-modules/related-media-store' import NotificationStore from '~/store-modules/notification-store' import NavStore from '~/store-modules/nav-store' import ActiveMediaStore from '~/store-modules/active-media-store' @@ -35,7 +34,6 @@ export const actions = Object.assign( SocialMediaStore.actions(GoogleAnalytics), ABTestStore.actions, ReportContentStore.actions(ReportService), - RelatedMediaStore.actions(AudioService, ImageService), NotificationStore.actions, { async nuxtServerInit({ dispatch }) { @@ -59,7 +57,6 @@ export const state = () => ABTestStore.state, UserStore.state, ReportContentStore.state, - RelatedMediaStore.state, NotificationStore.state, NavStore.state, ActiveMediaStore.state @@ -74,7 +71,6 @@ export const mutations = Object.assign( BugReportStore.mutations, ABTestStore.mutations, ReportContentStore.mutations, - RelatedMediaStore.mutations, NotificationStore.mutations, NavStore.mutations, ActiveMediaStore.mutations diff --git a/src/store-modules/related-media-store.js b/src/store/related.js similarity index 64% rename from src/store-modules/related-media-store.js rename to src/store/related.js index bc2bb1c6102..33a3bc09e52 100644 --- a/src/store-modules/related-media-store.js +++ b/src/store/related.js @@ -2,35 +2,30 @@ import { FETCH_END_MEDIA, FETCH_START_MEDIA, SET_RELATED_MEDIA, -} from '../constants/mutation-types' +} from '~/constants/mutation-types' import { FETCH_RELATED_MEDIA, HANDLE_NO_MEDIA, HANDLE_MEDIA_ERROR, -} from '../constants/action-types' -import { AUDIO, IMAGE } from '~/constants/media' +} from '~/constants/action-types' +import AudioService from '~/data/audio-service' +import ImageService from '~/data/image-service' -const initialState = { - related: { - images: [], - audios: [], - }, -} +export const state = () => ({ + images: [], + audios: [], +}) -const actions = (AudioService, ImageService) => ({ +export const actionsCreator = (services) => ({ [FETCH_RELATED_MEDIA]({ commit, dispatch }, params) { const { mediaType } = params commit(FETCH_START_MEDIA, { mediaType }) - let service - if (mediaType === AUDIO) { - service = AudioService - } else if (mediaType === IMAGE) { - service = ImageService - } else { + if (!Object.keys(services).includes(mediaType)) { throw new Error( `Unsupported media type ${mediaType} for related media fetching` ) } + const service = services[mediaType] return service .getRelatedMedia(params) .then(({ data }) => { @@ -46,26 +41,33 @@ const actions = (AudioService, ImageService) => ({ }) .catch((error) => { dispatch(HANDLE_MEDIA_ERROR, { - mediaType: IMAGE, + mediaType, error, }) }) }, }) -const mutations = { +const services = { + AUDIO: AudioService, + IMAGE: ImageService, +} + +export const actions = actionsCreator(services) + +export const mutations = { /** * @param _state * @param {'image'|'audio'} mediaType * @param {Array} relatedMedia */ [SET_RELATED_MEDIA](_state, { mediaType, relatedMedia }) { - _state.related[`${mediaType}s`] = relatedMedia + _state[`${mediaType}s`] = relatedMedia }, } export default { - state: initialState, - actions, + state, mutations, + actions, } diff --git a/test/unit/specs/store/related-media-store.spec.js b/test/unit/specs/store/related-media-store.spec.js index fad31dec7cd..aab8bb06c31 100644 --- a/test/unit/specs/store/related-media-store.spec.js +++ b/test/unit/specs/store/related-media-store.spec.js @@ -1,4 +1,4 @@ -import store from '~/store-modules/related-media-store' +import store, { actionsCreator } from '~/store/related' import { FETCH_END_MEDIA, FETCH_START_MEDIA, @@ -10,9 +10,9 @@ import { IMAGE } from '~/constants/media' describe('Related Images Store', () => { describe('state', () => { it('exports default state', () => { - const state = store.state - expect(state.related.audios).toHaveLength(0) - expect(state.related.images).toHaveLength(0) + const state = store.state() + expect(state.audios).toHaveLength(0) + expect(state.images).toHaveLength(0) }) }) @@ -21,7 +21,7 @@ describe('Related Images Store', () => { const mutations = store.mutations beforeEach(() => { - state = { related: { images: [], audios: [] } } + state = { images: [], audios: [] } }) it('SET_RELATED_MEDIA updates state', () => { @@ -30,21 +30,17 @@ describe('Related Images Store', () => { relatedMedia: ['foo'], } mutations[SET_RELATED_MEDIA](state, params) - expect(state.relatedImages).toBe(params.relatedImages) + expect(state.images).toBe(params.relatedMedia) }) }) describe('actions', () => { const searchData = { results: ['foo'], result_count: 1 } - let audioServiceMock = null let imageServiceMock = null let commit = null let dispatch = null beforeEach(() => { - audioServiceMock = { - getRelatedMedia: jest.fn(() => Promise.resolve({ data: searchData })), - } imageServiceMock = { getRelatedMedia: jest.fn(() => Promise.resolve({ data: searchData })), } @@ -54,9 +50,10 @@ describe('Related Images Store', () => { it('FETCH_RELATED_MEDIA on success', (done) => { const params = { id: 'foo', mediaType: IMAGE } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_RELATED_MEDIA - ] + const actions = actionsCreator({ + [IMAGE]: imageServiceMock, + }) + const action = actions[FETCH_RELATED_MEDIA] action({ commit, dispatch }, params).then(() => { expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) expect(commit).toBeCalledWith(FETCH_END_MEDIA, { mediaType: IMAGE }) @@ -72,16 +69,14 @@ describe('Related Images Store', () => { }) it('FETCH_RELATED_IMAGES on error', (done) => { - const audioServiceMock = { - getRelatedMedia: jest.fn(() => Promise.reject('error')), - } const imageServiceMock = { getRelatedMedia: jest.fn(() => Promise.reject('error')), } const params = { id: 'foo', mediaType: IMAGE } - const action = store.actions(audioServiceMock, imageServiceMock)[ - FETCH_RELATED_MEDIA - ] + const actions = actionsCreator({ + [IMAGE]: imageServiceMock, + }) + const action = actions[FETCH_RELATED_MEDIA] action({ commit, dispatch }, params).catch((error) => { expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) expect(dispatch).toBeCalledWith('HANDLE_IMAGE_ERROR', error) From 8631b4afb97821f29135ce4a46dfed56df1d514e Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 18 Sep 2021 15:16:41 +0300 Subject: [PATCH 2/8] Use namespaced 'related' store module --- src/constants/store-modules.js | 1 + src/pages/photos/_id.vue | 13 ++++---- src/pages/search.vue | 2 +- src/store/related.js | 33 ++++++++++++------- .../specs/store/related-media-store.spec.js | 12 +++++-- 5 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 src/constants/store-modules.js diff --git a/src/constants/store-modules.js b/src/constants/store-modules.js new file mode 100644 index 00000000000..d0b21c6ec7b --- /dev/null +++ b/src/constants/store-modules.js @@ -0,0 +1 @@ +export const RELATED = 'related' diff --git a/src/pages/photos/_id.vue b/src/pages/photos/_id.vue index 5278fb72b86..dd4285e530f 100644 --- a/src/pages/photos/_id.vue +++ b/src/pages/photos/_id.vue @@ -32,6 +32,7 @@ import featureFlags from '~/feature-flags' import { FETCH_IMAGE, FETCH_RELATED_MEDIA } from '~/constants/action-types' import { SET_IMAGE, SET_RELATED_MEDIA } from '~/constants/mutation-types' import { IMAGE } from '~/constants/media' +import { RELATED } from '~/constants/store-modules' const PhotoDetailPage = { name: 'PhotoDetailPage', @@ -66,7 +67,7 @@ const PhotoDetailPage = { tags: (state) => state.image.tags, image: (state) => state.image, }), - ...mapState({ + ...mapState(RELATED, { relatedImagesCount: (state) => state.images.length, relatedImages: (state) => state.images, }), @@ -82,7 +83,7 @@ const PhotoDetailPage = { async fetch({ store, route, error, app }) { // Clear related images if present if (store.state.related.images && store.state.related.images.length > 0) { - await store.dispatch(SET_RELATED_MEDIA, { + await store.dispatch(`${RELATED}/${SET_RELATED_MEDIA}`, { mediaType: IMAGE, relatedMedia: [], }) @@ -90,8 +91,8 @@ const PhotoDetailPage = { try { // Load the image + related images in parallel await Promise.all([ - store.dispatch(FETCH_IMAGE, { id: route.params.id }), - store.dispatch(FETCH_RELATED_MEDIA, { + store.dispatch(`${FETCH_IMAGE}`, { id: route.params.id }), + store.dispatch(`${RELATED}/${FETCH_RELATED_MEDIA}`, { mediaType: IMAGE, id: route.params.id, }), @@ -112,7 +113,7 @@ const PhotoDetailPage = { }) }, methods: { - ...mapActions([FETCH_RELATED_MEDIA]), + ...mapActions({ fetchRelatedMedia: `${RELATED}/${FETCH_RELATED_MEDIA}` }), ...mapActions([FETCH_IMAGE]), ...mapMutations([SET_IMAGE]), onImageLoaded(event) { @@ -125,7 +126,7 @@ const PhotoDetailPage = { }, getRelatedImages() { if (this.image && this.image.id) { - this[FETCH_RELATED_MEDIA]({ mediaType: IMAGE, id: this.image.id }) + this.fetchRelatedMedia({ mediaType: IMAGE, id: this.image.id }) } }, }, diff --git a/src/pages/search.vue b/src/pages/search.vue index afafdaf88d3..0720f8dc042 100644 --- a/src/pages/search.vue +++ b/src/pages/search.vue @@ -80,11 +80,11 @@ const BrowsePage = { ...mapActions({ fetchMedia: `${FETCH_MEDIA}`, setSearchTypeFromUrl: `${SET_SEARCH_TYPE_FROM_URL}`, - setFiltersFromUrl: `${SET_FILTERS_FROM_URL}`, }), ...mapMutations({ setQuery: `${SET_QUERY}`, setFilterVisibility: `${SET_FILTER_IS_VISIBLE}`, + setFiltersFromUrl: `${SET_FILTERS_FROM_URL}`, }), getMediaItems(params, mediaType) { this.fetchMedia({ ...params, mediaType }) diff --git a/src/store/related.js b/src/store/related.js index 33a3bc09e52..1cf64921125 100644 --- a/src/store/related.js +++ b/src/store/related.js @@ -10,6 +10,7 @@ import { } from '~/constants/action-types' import AudioService from '~/data/audio-service' import ImageService from '~/data/image-service' +import { AUDIO, IMAGE } from '~/constants/media' export const state = () => ({ images: [], @@ -19,7 +20,7 @@ export const state = () => ({ export const actionsCreator = (services) => ({ [FETCH_RELATED_MEDIA]({ commit, dispatch }, params) { const { mediaType } = params - commit(FETCH_START_MEDIA, { mediaType }) + commit(FETCH_START_MEDIA, { mediaType }, { root: true }) if (!Object.keys(services).includes(mediaType)) { throw new Error( `Unsupported media type ${mediaType} for related media fetching` @@ -29,28 +30,36 @@ export const actionsCreator = (services) => ({ return service .getRelatedMedia(params) .then(({ data }) => { - commit(FETCH_END_MEDIA, { mediaType }) + commit(FETCH_END_MEDIA, { mediaType }, { root: true }) commit(SET_RELATED_MEDIA, { mediaType, relatedMedia: data.results, }) - dispatch(HANDLE_NO_MEDIA, { - mediaCount: data.results.length, - mediaType, - }) + dispatch( + HANDLE_NO_MEDIA, + { + mediaCount: data.results.length, + mediaType, + }, + { root: true } + ) }) .catch((error) => { - dispatch(HANDLE_MEDIA_ERROR, { - mediaType, - error, - }) + dispatch( + HANDLE_MEDIA_ERROR, + { + mediaType, + error, + }, + { root: true } + ) }) }, }) const services = { - AUDIO: AudioService, - IMAGE: ImageService, + [AUDIO]: AudioService, + [IMAGE]: ImageService, } export const actions = actionsCreator(services) diff --git a/test/unit/specs/store/related-media-store.spec.js b/test/unit/specs/store/related-media-store.spec.js index aab8bb06c31..9f6ccccc15f 100644 --- a/test/unit/specs/store/related-media-store.spec.js +++ b/test/unit/specs/store/related-media-store.spec.js @@ -55,8 +55,16 @@ describe('Related Images Store', () => { }) const action = actions[FETCH_RELATED_MEDIA] action({ commit, dispatch }, params).then(() => { - expect(commit).toBeCalledWith(FETCH_START_MEDIA, { mediaType: IMAGE }) - expect(commit).toBeCalledWith(FETCH_END_MEDIA, { mediaType: IMAGE }) + expect(commit).toBeCalledWith( + FETCH_START_MEDIA, + { mediaType: IMAGE }, + { root: true } + ) + expect(commit).toBeCalledWith( + FETCH_END_MEDIA, + { mediaType: IMAGE }, + { root: true } + ) expect(commit).toBeCalledWith(SET_RELATED_MEDIA, { mediaType: IMAGE, From c0ff2fb50d009809bbb60e304872203ae3a936fd Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sat, 18 Sep 2021 16:11:30 +0300 Subject: [PATCH 3/8] Make 'abtest' module namespaced --- src/ab-tests/index.js | 3 ++- src/constants/store-modules.js | 1 + .../abtest-store.js => store/abtest.js} | 12 ++++++------ src/store/index.js | 4 ---- src/store/related.js | 4 ++-- test/unit/specs/ab-tests.spec.js | 5 ++++- test/unit/specs/store/related-media-store.spec.js | 6 +++--- 7 files changed, 18 insertions(+), 17 deletions(-) rename src/{store-modules/abtest-store.js => store/abtest.js} (75%) diff --git a/src/ab-tests/index.js b/src/ab-tests/index.js index a585edcf4e4..b2a94a17a69 100644 --- a/src/ab-tests/index.js +++ b/src/ab-tests/index.js @@ -1,5 +1,6 @@ import { JOINED_AB_TEST_EXPERIMENT } from '~/constants/mutation-types' import { participate } from '~/utils/sixpack' +import { ABTEST } from '~/constants/store-modules' export const activeExperiments = [] @@ -28,7 +29,7 @@ const abTests = async (store, activeExperiments) => { // commit each experiment to Vuex const commitExperiments = (experiments) => { experiments.map((experiment) => { - store.commit(JOINED_AB_TEST_EXPERIMENT, { + store.commit(`${ABTEST}/${JOINED_AB_TEST_EXPERIMENT}`, { name: experiment.name, case: experiment.case, session: experiment.session, diff --git a/src/constants/store-modules.js b/src/constants/store-modules.js index d0b21c6ec7b..f60c7d98af6 100644 --- a/src/constants/store-modules.js +++ b/src/constants/store-modules.js @@ -1 +1,2 @@ export const RELATED = 'related' +export const ABTEST = 'abtest' diff --git a/src/store-modules/abtest-store.js b/src/store/abtest.js similarity index 75% rename from src/store-modules/abtest-store.js rename to src/store/abtest.js index 1ddcb8e77a5..70888388172 100644 --- a/src/store-modules/abtest-store.js +++ b/src/store/abtest.js @@ -1,12 +1,12 @@ -import { JOINED_AB_TEST_EXPERIMENT } from '../constants/mutation-types' -import { CONVERT_AB_TEST_EXPERIMENT } from '../constants/action-types' +import { JOINED_AB_TEST_EXPERIMENT } from '~/constants/mutation-types' +import { CONVERT_AB_TEST_EXPERIMENT } from '~/constants/action-types' import { convert } from '~/utils/sixpack' -const state = { +export const state = () => ({ experiments: [], -} +}) -const actions = { +export const actions = { [CONVERT_AB_TEST_EXPERIMENT](context, params) { const experiment = context.state.experiments.find( ({ name }) => name === params.name @@ -25,7 +25,7 @@ const actions = { }, } -const mutations = { +export const mutations = { [JOINED_AB_TEST_EXPERIMENT](_state, params) { _state.experiments = [{ ...params }, ..._state.experiments] }, diff --git a/src/store/index.js b/src/store/index.js index c87c6dc6ea9..8cc9c6f5cd7 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -9,7 +9,6 @@ import MediaProviderStore from '~/store-modules/media-provider-store' import AttributionStore from '~/store-modules/attribution-store' import BugReportStore from '~/store-modules/bug-report-store' import SocialMediaStore from '~/store-modules/social-store' -import ABTestStore from '~/store-modules/abtest-store' import UserStore from '~/store-modules/user-store' import UsageDataStore from '~/store-modules/usage-data-store' import FilterStore from '~/store-modules/filter-store' @@ -32,7 +31,6 @@ export const actions = Object.assign( AttributionStore.actions(GoogleAnalytics), BugReportStore.actions(BugReportService), SocialMediaStore.actions(GoogleAnalytics), - ABTestStore.actions, ReportContentStore.actions(ReportService), NotificationStore.actions, { @@ -54,7 +52,6 @@ export const state = () => FilterStore.state, MediaProviderStore.state, BugReportStore.state, - ABTestStore.state, UserStore.state, ReportContentStore.state, NotificationStore.state, @@ -69,7 +66,6 @@ export const mutations = Object.assign( FilterStore.mutations, MediaProviderStore.mutations, BugReportStore.mutations, - ABTestStore.mutations, ReportContentStore.mutations, NotificationStore.mutations, NavStore.mutations, diff --git a/src/store/related.js b/src/store/related.js index 1cf64921125..86ceeac32c1 100644 --- a/src/store/related.js +++ b/src/store/related.js @@ -17,7 +17,7 @@ export const state = () => ({ audios: [], }) -export const actionsCreator = (services) => ({ +export const createActions = (services) => ({ [FETCH_RELATED_MEDIA]({ commit, dispatch }, params) { const { mediaType } = params commit(FETCH_START_MEDIA, { mediaType }, { root: true }) @@ -62,7 +62,7 @@ const services = { [IMAGE]: ImageService, } -export const actions = actionsCreator(services) +export const actions = createActions(services) export const mutations = { /** diff --git a/test/unit/specs/ab-tests.spec.js b/test/unit/specs/ab-tests.spec.js index 54282662c5b..ad5a0f0d6ff 100644 --- a/test/unit/specs/ab-tests.spec.js +++ b/test/unit/specs/ab-tests.spec.js @@ -1,6 +1,7 @@ import abTests from '~/ab-tests' import { JOINED_AB_TEST_EXPERIMENT } from '~/constants/mutation-types' import donationLanguage from '~/ab-tests/experiments/donation-language' +import { ABTEST } from '~/constants/store-modules' process.env.API_URL = 'http://api.cc.org/v1/' @@ -19,7 +20,9 @@ describe('AB Tests', () => { it('sets up experiments', (done) => { const result = abTests(store, [donationLanguage]) result.then(() => { - expect(store.commit.mock.calls[0][0]).toBe(JOINED_AB_TEST_EXPERIMENT) + expect(store.commit.mock.calls[0][0]).toBe( + `${ABTEST}/${JOINED_AB_TEST_EXPERIMENT}` + ) done() }) }) diff --git a/test/unit/specs/store/related-media-store.spec.js b/test/unit/specs/store/related-media-store.spec.js index 9f6ccccc15f..03215d88e18 100644 --- a/test/unit/specs/store/related-media-store.spec.js +++ b/test/unit/specs/store/related-media-store.spec.js @@ -1,4 +1,4 @@ -import store, { actionsCreator } from '~/store/related' +import store, { createActions } from '~/store/related' import { FETCH_END_MEDIA, FETCH_START_MEDIA, @@ -50,7 +50,7 @@ describe('Related Images Store', () => { it('FETCH_RELATED_MEDIA on success', (done) => { const params = { id: 'foo', mediaType: IMAGE } - const actions = actionsCreator({ + const actions = createActions({ [IMAGE]: imageServiceMock, }) const action = actions[FETCH_RELATED_MEDIA] @@ -81,7 +81,7 @@ describe('Related Images Store', () => { getRelatedMedia: jest.fn(() => Promise.reject('error')), } const params = { id: 'foo', mediaType: IMAGE } - const actions = actionsCreator({ + const actions = createActions({ [IMAGE]: imageServiceMock, }) const action = actions[FETCH_RELATED_MEDIA] From 89100e331392c5ebc9edc4c15991bc3a3ef2e136 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sun, 19 Sep 2021 05:30:39 +0300 Subject: [PATCH 4/8] Make 'active-media' and 'attribution' modules namespaced --- src/components/AudioTrack/AudioController.vue | 6 +++--- src/components/MediaInfo/CopyLicense.vue | 6 +++++- src/constants/store-modules.js | 1 + src/store-modules/attribution-store.js | 11 ---------- src/store-modules/search-store.js | 4 ++-- .../active-media.js} | 20 +++++++++---------- src/store/attribution.js | 12 +++++++++++ src/store/index.js | 9 ++------- src/{store-modules => store}/types.d.ts | 4 ++-- .../ImageDetails/copy-license.spec.js | 12 +++++++---- .../specs/store/attribution-store.spec.js | 7 +++++-- 11 files changed, 50 insertions(+), 42 deletions(-) delete mode 100644 src/store-modules/attribution-store.js rename src/{store-modules/active-media-store.js => store/active-media.js} (70%) create mode 100644 src/store/attribution.js rename src/{store-modules => store}/types.d.ts (93%) diff --git a/src/components/AudioTrack/AudioController.vue b/src/components/AudioTrack/AudioController.vue index 1fc5b23746e..0faad283bb3 100644 --- a/src/components/AudioTrack/AudioController.vue +++ b/src/components/AudioTrack/AudioController.vue @@ -78,8 +78,8 @@ export default { const isActiveTrack = computed( () => - store.state.activeMediaType === 'audio' && - store.state.activeMediaId === props.audio.id + store.state['active-media'].type === 'audio' && + store.state['active-media'].id === props.audio.id ) // Sync status from parent to player and store watch( @@ -107,7 +107,7 @@ export default { ) // Sync status from store to parent watch( - () => [store.state.activeMediaType, store.state.activeMediaId], + () => [store.state['active-media'].type, store.state['active-media'].id], () => { const status = isActiveTrack.value ? 'playing' : 'paused' emit('change', status) diff --git a/src/components/MediaInfo/CopyLicense.vue b/src/components/MediaInfo/CopyLicense.vue index 557d1498a34..064c6f363a7 100644 --- a/src/components/MediaInfo/CopyLicense.vue +++ b/src/components/MediaInfo/CopyLicense.vue @@ -178,6 +178,7 @@ import { DETAIL_PAGE_EVENTS, } from '~/store-modules/usage-data-analytics-types' import { isPublicDomain } from '~/utils/license' +import { ATTRIBUTION } from '~/constants/store-modules' export default { name: 'CopyLicense', @@ -225,7 +226,10 @@ export default { }) }, onCopyAttribution(type, event) { - this.$store.dispatch(COPY_ATTRIBUTION, { type, content: event.content }) + this.$store.dispatch(`${ATTRIBUTION}/${COPY_ATTRIBUTION}`, { + type, + content: event.content, + }) this.sendDetailPageEvent(DETAIL_PAGE_EVENTS.ATTRIBUTION_CLICKED) }, onPhotoSourceLinkClicked() { diff --git a/src/constants/store-modules.js b/src/constants/store-modules.js index f60c7d98af6..44b0456939e 100644 --- a/src/constants/store-modules.js +++ b/src/constants/store-modules.js @@ -1,2 +1,3 @@ export const RELATED = 'related' export const ABTEST = 'abtest' +export const ATTRIBUTION = 'attribution' diff --git a/src/store-modules/attribution-store.js b/src/store-modules/attribution-store.js deleted file mode 100644 index 166f51b1392..00000000000 --- a/src/store-modules/attribution-store.js +++ /dev/null @@ -1,11 +0,0 @@ -import { CopyAttribution } from '~/analytics/events' -import { COPY_ATTRIBUTION } from '../constants/action-types' - -const actions = (GoogleAnalytics) => ({ - [COPY_ATTRIBUTION](_, params) { - const event = CopyAttribution(params.type, params.content) - GoogleAnalytics().sendEvent(event) - }, -}) - -export default { actions } diff --git a/src/store-modules/search-store.js b/src/store-modules/search-store.js index a8c2bf5404f..176087968c1 100644 --- a/src/store-modules/search-store.js +++ b/src/store-modules/search-store.js @@ -84,7 +84,7 @@ const fetchCollectionImages = (commit, params, imageService) => { * and handle possible errors * @param {import('vuex').Commit} commit * @param {import('vuex').Dispatch} dispatch - * @param {import('./types').MediaResult} data + * @param {import('../store/types').MediaResult} data * @param {Object} params * @param {'image'|'audio'} params.mediaType * @param {boolean} params.shouldPersistMedia @@ -109,7 +109,7 @@ const handleSearchResponse = async ( } /** - * @type {{ audios: import('./types').AudioDetail[], + * @type {{ audios: import('../store/types').AudioDetail[], * audiosCount: number, audioPage:number, * images: import('./types').ImageDetail[], * imagePage: number, imagesCount: number, query: {}, diff --git a/src/store-modules/active-media-store.js b/src/store/active-media.js similarity index 70% rename from src/store-modules/active-media-store.js rename to src/store/active-media.js index 48ec6863565..128e8551103 100644 --- a/src/store-modules/active-media-store.js +++ b/src/store/active-media.js @@ -1,16 +1,16 @@ import { SET_ACTIVE_MEDIA_ITEM, UNSET_ACTIVE_MEDIA_ITEM, -} from '../constants/mutation-types' +} from '~/constants/mutation-types' /** * Stores information about the active media item. - * @type {import('./types').ActiveMediaState} + * @return {import('./types').ActiveMediaState} */ -const state = { - activeMediaType: null, - activeMediaId: null, -} +const state = () => ({ + type: null, + id: null, +}) const mutations = { /** @@ -21,16 +21,16 @@ const mutations = { * @param {string} payload.id - the ID of the active media item */ [SET_ACTIVE_MEDIA_ITEM](_state, { type, id }) { - _state.activeMediaType = type - _state.activeMediaId = id + _state.type = type + _state.id = id }, /** * Clear the active media item. * @param {import('./types').ActiveMediaState} _state */ [UNSET_ACTIVE_MEDIA_ITEM](_state) { - _state.activeMediaType = null - _state.activeMediaId = null + _state.type = null + _state.id = null }, } diff --git a/src/store/attribution.js b/src/store/attribution.js new file mode 100644 index 00000000000..0180aa70c4f --- /dev/null +++ b/src/store/attribution.js @@ -0,0 +1,12 @@ +import GoogleAnalytics from '~/analytics/google-analytics' +import { CopyAttribution } from '~/analytics/events' +import { COPY_ATTRIBUTION } from '~/constants/action-types' + +export const createActions = (googleAnalytics) => ({ + [COPY_ATTRIBUTION](_, params) { + const event = CopyAttribution(params.type, params.content) + googleAnalytics().sendEvent(event) + }, +}) + +export const actions = createActions(GoogleAnalytics) diff --git a/src/store/index.js b/src/store/index.js index 8cc9c6f5cd7..1f08f046201 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -6,7 +6,6 @@ import UsageDataService from '~/data/usage-data-service' import ReportService from '~/data/report-service' import SearchStore from '~/store-modules/search-store' import MediaProviderStore from '~/store-modules/media-provider-store' -import AttributionStore from '~/store-modules/attribution-store' import BugReportStore from '~/store-modules/bug-report-store' import SocialMediaStore from '~/store-modules/social-store' import UserStore from '~/store-modules/user-store' @@ -15,7 +14,6 @@ import FilterStore from '~/store-modules/filter-store' import ReportContentStore from '~/store-modules/report-content-store' import NotificationStore from '~/store-modules/notification-store' import NavStore from '~/store-modules/nav-store' -import ActiveMediaStore from '~/store-modules/active-media-store' import { FETCH_MEDIA_PROVIDERS } from '~/constants/action-types' import GoogleAnalytics from '~/analytics/google-analytics' import { AUDIO, IMAGE } from '~/constants/media' @@ -28,7 +26,6 @@ export const actions = Object.assign( SearchStore.actions(AudioService, ImageService), FilterStore.actions, MediaProviderStore.actions(AudioProviderService, ImageProviderService), - AttributionStore.actions(GoogleAnalytics), BugReportStore.actions(BugReportService), SocialMediaStore.actions(GoogleAnalytics), ReportContentStore.actions(ReportService), @@ -55,8 +52,7 @@ export const state = () => UserStore.state, ReportContentStore.state, NotificationStore.state, - NavStore.state, - ActiveMediaStore.state + NavStore.state ) export const getters = Object.assign(FilterStore.getters) @@ -68,6 +64,5 @@ export const mutations = Object.assign( BugReportStore.mutations, ReportContentStore.mutations, NotificationStore.mutations, - NavStore.mutations, - ActiveMediaStore.mutations + NavStore.mutations ) diff --git a/src/store-modules/types.d.ts b/src/store/types.d.ts similarity index 93% rename from src/store-modules/types.d.ts rename to src/store/types.d.ts index d9826128c1b..f894fc6d5c2 100644 --- a/src/store-modules/types.d.ts +++ b/src/store/types.d.ts @@ -57,6 +57,6 @@ export type ImageDetail = { } export interface ActiveMediaState { - activeMediaType: 'image' | 'audio' | null - activeMediaId: string | null + type: 'image' | 'audio' | null + id: string | null } diff --git a/test/unit/specs/components/ImageDetails/copy-license.spec.js b/test/unit/specs/components/ImageDetails/copy-license.spec.js index 3e4e4fda6b6..f49b4811d8b 100644 --- a/test/unit/specs/components/ImageDetails/copy-license.spec.js +++ b/test/unit/specs/components/ImageDetails/copy-license.spec.js @@ -7,6 +7,7 @@ import { import render from '../../../test-utils/render' import i18n from '../../../test-utils/i18n' +import { ATTRIBUTION } from '~/constants/store-modules' describe('CopyLicense', () => { let options = null @@ -59,10 +60,13 @@ describe('CopyLicense', () => { it('should dispatch COPY_ATTRIBUTION', () => { const wrapper = render(CopyLicense, options) wrapper.vm.onCopyAttribution(copyData.type, copyData.event) - expect(dispatchMock).toHaveBeenCalledWith(COPY_ATTRIBUTION, { - type: copyData.type, - content: copyData.event.content, - }) + expect(dispatchMock).toHaveBeenCalledWith( + `${ATTRIBUTION}/${COPY_ATTRIBUTION}`, + { + type: copyData.type, + content: copyData.event.content, + } + ) }) it('should dispatch SEND_DETAIL_PAGE_EVENT on copy attribution', () => { diff --git a/test/unit/specs/store/attribution-store.spec.js b/test/unit/specs/store/attribution-store.spec.js index 7b17ec8111b..4837e3d7f5b 100644 --- a/test/unit/specs/store/attribution-store.spec.js +++ b/test/unit/specs/store/attribution-store.spec.js @@ -1,14 +1,17 @@ -import store from '~/store-modules/attribution-store' +import { createActions } from '~/store/attribution' import { CopyAttribution } from '~/analytics/events' +import { COPY_ATTRIBUTION } from '~/constants/action-types' describe('Attribution Store', () => { describe('actions', () => { let gaInstance = null let googleAnalyticsMock = null + let actions = null beforeEach(() => { gaInstance = { sendEvent: jest.fn() } googleAnalyticsMock = jest.fn(() => gaInstance) + actions = createActions(googleAnalyticsMock) }) it('COPY_ATTRIBUTION sends copy event', () => { @@ -16,7 +19,7 @@ describe('Attribution Store', () => { type: 'HTML Whatever', content: '
foo
', } - store.actions(googleAnalyticsMock).COPY_ATTRIBUTION({}, data) + actions[COPY_ATTRIBUTION]({}, data) expect(googleAnalyticsMock().sendEvent).toHaveBeenCalledWith( new CopyAttribution(data.type, data.content) From 5b17365f7218f5e16de567fd7f8a568fdc441ac3 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sun, 19 Sep 2021 05:50:35 +0300 Subject: [PATCH 5/8] Make 'bug-report' and 'provider' modules namespaced --- src/constants/store-modules.js | 1 + .../bug-report.js} | 20 +++++---- src/store/index.js | 14 ------ .../provider.js} | 43 ++++++++++++------- ...tion-store.spec.js => attribution.spec.js} | 0 ...eport-store.spec.js => bug-report.spec.js} | 31 +++++++++---- ...rovider-store.spec.js => provider.spec.js} | 43 +++++++++++-------- test/unit/test-utils/sample-store.js | 2 +- 8 files changed, 88 insertions(+), 66 deletions(-) rename src/{store-modules/bug-report-store.js => store/bug-report.js} (70%) rename src/{store-modules/media-provider-store.js => store/provider.js} (81%) rename test/unit/specs/store/{attribution-store.spec.js => attribution.spec.js} (100%) rename test/unit/specs/store/{bug-report-store.spec.js => bug-report.spec.js} (72%) rename test/unit/specs/store/{image-provider-store.spec.js => provider.spec.js} (64%) diff --git a/src/constants/store-modules.js b/src/constants/store-modules.js index 44b0456939e..0624b21d876 100644 --- a/src/constants/store-modules.js +++ b/src/constants/store-modules.js @@ -1,3 +1,4 @@ export const RELATED = 'related' export const ABTEST = 'abtest' export const ATTRIBUTION = 'attribution' +export const PROVIDER = 'provider' diff --git a/src/store-modules/bug-report-store.js b/src/store/bug-report.js similarity index 70% rename from src/store-modules/bug-report-store.js rename to src/store/bug-report.js index 71424a4f802..4b85d60779c 100644 --- a/src/store-modules/bug-report-store.js +++ b/src/store/bug-report.js @@ -1,13 +1,13 @@ -import { REPORT_BUG } from '../constants/action-types' +import BugReportService from '~/data/bug-report-service' +import { REPORT_BUG } from '~/constants/action-types' import { REPORT_BUG_START, REPORT_BUG_END, REPORT_BUG_FAILED, -} from '../constants/mutation-types' +} from '~/constants/mutation-types' -const actions = (bugReportService) => ({ - // eslint-disable-next-line no-unused-vars +export const createActions = (bugReportService) => ({ [REPORT_BUG]({ commit }, params) { commit(REPORT_BUG_START) bugReportService @@ -17,14 +17,16 @@ const actions = (bugReportService) => ({ }, }) -const state = { +export const actions = createActions(BugReportService) + +export const state = () => ({ isReportingBug: false, bugReported: false, bugReportFailed: false, -} +}) /* eslint no-param-reassign: ["error", { "props": false }] */ -const mutations = { +export const mutations = { [REPORT_BUG_START](_state) { _state.isReportingBug = true }, @@ -39,7 +41,7 @@ const mutations = { } export default { - actions, - mutations, state, + mutations, + actions, } diff --git a/src/store/index.js b/src/store/index.js index 1f08f046201..3b7d8ba5f69 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,12 +1,8 @@ -import MediaProviderService from '~/data/media-provider-service' import AudioService from '~/data/audio-service' import ImageService from '~/data/image-service' -import BugReportService from '~/data/bug-report-service' import UsageDataService from '~/data/usage-data-service' import ReportService from '~/data/report-service' import SearchStore from '~/store-modules/search-store' -import MediaProviderStore from '~/store-modules/media-provider-store' -import BugReportStore from '~/store-modules/bug-report-store' import SocialMediaStore from '~/store-modules/social-store' import UserStore from '~/store-modules/user-store' import UsageDataStore from '~/store-modules/usage-data-store' @@ -16,17 +12,11 @@ import NotificationStore from '~/store-modules/notification-store' import NavStore from '~/store-modules/nav-store' import { FETCH_MEDIA_PROVIDERS } from '~/constants/action-types' import GoogleAnalytics from '~/analytics/google-analytics' -import { AUDIO, IMAGE } from '~/constants/media' - -const AudioProviderService = MediaProviderService(AUDIO) -const ImageProviderService = MediaProviderService(IMAGE) export const actions = Object.assign( UsageDataStore.actions(UsageDataService), SearchStore.actions(AudioService, ImageService), FilterStore.actions, - MediaProviderStore.actions(AudioProviderService, ImageProviderService), - BugReportStore.actions(BugReportService), SocialMediaStore.actions(GoogleAnalytics), ReportContentStore.actions(ReportService), NotificationStore.actions, @@ -47,8 +37,6 @@ export const state = () => Object.assign( SearchStore.state, FilterStore.state, - MediaProviderStore.state, - BugReportStore.state, UserStore.state, ReportContentStore.state, NotificationStore.state, @@ -60,8 +48,6 @@ export const getters = Object.assign(FilterStore.getters) export const mutations = Object.assign( SearchStore.mutations, FilterStore.mutations, - MediaProviderStore.mutations, - BugReportStore.mutations, ReportContentStore.mutations, NotificationStore.mutations, NavStore.mutations diff --git a/src/store-modules/media-provider-store.js b/src/store/provider.js similarity index 81% rename from src/store-modules/media-provider-store.js rename to src/store/provider.js index b1dc9ca04d1..fb50e311670 100644 --- a/src/store-modules/media-provider-store.js +++ b/src/store/provider.js @@ -1,7 +1,11 @@ +import MediaProviderService from '~/data/media-provider-service' +import previousImageProviders from '../data/existing-image-providers' +import previousAudioProviders from '../data/existing-audio-providers' +import { AUDIO, IMAGE } from '~/constants/media' import { FETCH_MEDIA_TYPE_PROVIDERS, FETCH_MEDIA_PROVIDERS, -} from '../constants/action-types' +} from '~/constants/action-types' import { SET_PROVIDER_FETCH_ERROR, @@ -9,11 +13,10 @@ import { FETCH_MEDIA_PROVIDERS_START, SET_MEDIA_PROVIDERS, SET_PROVIDERS_FILTERS, -} from '../constants/mutation-types' +} from '~/constants/mutation-types' -import previousImageProviders from '../data/existing-image-providers' -import previousAudioProviders from '../data/existing-audio-providers' -import { AUDIO, IMAGE } from '~/constants/media' +const AudioProviderService = MediaProviderService(AUDIO) +const ImageProviderService = MediaProviderService(IMAGE) const existingProviders = { [AUDIO]: previousAudioProviders, @@ -28,16 +31,16 @@ const sortProviders = (data) => { }) } -const state = { +export const state = () => ({ audioProviders: [], imageProviders: [], isFetchingAudioProvidersError: false, isFetchingImageProvidersError: false, isFetchingAudioProviders: false, isFetchingImageProviders: false, -} +}) -const actions = (AudioProviderService, ImageProviderService) => ({ +export const createActions = (services) => ({ async [FETCH_MEDIA_PROVIDERS]({ dispatch }, params) { return Promise.all([ dispatch(FETCH_MEDIA_TYPE_PROVIDERS, { ...params, mediaType: AUDIO }), @@ -48,8 +51,7 @@ const actions = (AudioProviderService, ImageProviderService) => ({ const { mediaType } = params commit(SET_PROVIDER_FETCH_ERROR, { mediaType, error: false }) commit(FETCH_MEDIA_PROVIDERS_START, { mediaType }) - const providerService = - mediaType === AUDIO ? AudioProviderService : ImageProviderService + const providerService = services[mediaType] let sortedProviders return providerService .getProviderStats() @@ -69,16 +71,25 @@ const actions = (AudioProviderService, ImageProviderService) => ({ mediaType, providers: sortedProviders, }) - commit(SET_PROVIDERS_FILTERS, { - mediaType, - providers: sortedProviders, - }) + commit( + `${SET_PROVIDERS_FILTERS}`, + { + mediaType, + providers: sortedProviders, + }, + { root: true } + ) }) }, }) +export const actions = createActions({ + [IMAGE]: ImageProviderService, + [AUDIO]: AudioProviderService, +}) + /* eslint no-param-reassign: ["error", { "props": false }] */ -const mutations = { +export const mutations = { [FETCH_MEDIA_PROVIDERS_START](_state, { mediaType }) { if (mediaType === AUDIO) { _state.isFetchingAudioProviders = true @@ -107,6 +118,6 @@ const mutations = { export default { state, - actions, mutations, + actions, } diff --git a/test/unit/specs/store/attribution-store.spec.js b/test/unit/specs/store/attribution.spec.js similarity index 100% rename from test/unit/specs/store/attribution-store.spec.js rename to test/unit/specs/store/attribution.spec.js diff --git a/test/unit/specs/store/bug-report-store.spec.js b/test/unit/specs/store/bug-report.spec.js similarity index 72% rename from test/unit/specs/store/bug-report-store.spec.js rename to test/unit/specs/store/bug-report.spec.js index d3b25d96493..ae082ef0ee9 100644 --- a/test/unit/specs/store/bug-report-store.spec.js +++ b/test/unit/specs/store/bug-report.spec.js @@ -1,14 +1,21 @@ -import store from '~/store-modules/bug-report-store' +import { + state, + mutations as BugReportMutations, + createActions, +} from '~/store/bug-report' import { REPORT_BUG_START, REPORT_BUG_END, REPORT_BUG_FAILED, } from '~/constants/mutation-types' +import { REPORT_BUG } from '~/constants/action-types' describe('Attribution Store', () => { describe('actions', () => { let serviceMock = null let commitMock = null + let store = {} + const data = { name: 'Foo', email: 'foo@bar.com', @@ -24,22 +31,27 @@ describe('Attribution Store', () => { commit: jest.fn(), } serviceMock.reportBug.mockResolvedValue(1) + store = { + state: state(), + mutations: BugReportMutations, + actions: createActions(serviceMock), + } }) it('calls reportBug service', () => { - store.actions(serviceMock).REPORT_BUG(commitMock, data) + store.actions[REPORT_BUG](commitMock, data) expect(serviceMock.reportBug).toHaveBeenCalledWith(data) }) it('commits REPORT_BUG_START', () => { - store.actions(serviceMock).REPORT_BUG(commitMock, data) + store.actions.REPORT_BUG(commitMock, data) expect(commitMock.commit).toHaveBeenCalledWith(REPORT_BUG_START) }) it('commits REPORT_BUG_END', (done) => { - store.actions(serviceMock).REPORT_BUG(commitMock, data) + store.actions.REPORT_BUG(commitMock, data) setTimeout(() => { expect(commitMock.commit).toHaveBeenCalledWith(REPORT_BUG_END) @@ -51,8 +63,9 @@ describe('Attribution Store', () => { const failedServiceMock = { reportBug: jest.fn(), } + store.actions = createActions(failedServiceMock) failedServiceMock.reportBug.mockRejectedValue(1) - store.actions(failedServiceMock).REPORT_BUG(commitMock, data) + store.actions.REPORT_BUG(commitMock, data) setTimeout(() => { expect(commitMock.commit).toHaveBeenCalledWith(REPORT_BUG_FAILED) @@ -63,26 +76,28 @@ describe('Attribution Store', () => { describe('mutations', () => { let state = null + let mutations = null beforeEach(() => { state = {} + mutations = BugReportMutations }) it('REPORT_BUG_START sets isReportingBug to true', () => { - store.mutations.REPORT_BUG_START(state) + mutations.REPORT_BUG_START(state) expect(state.isReportingBug).toBeTruthy() }) it('REPORT_BUG_END sets bugReported to true and isReportingBug to false', () => { - store.mutations.REPORT_BUG_END(state) + mutations.REPORT_BUG_END(state) expect(state.bugReported).toBeTruthy() expect(state.isReportingBug).toBeFalsy() }) it('REPORT_BUG_FAILED sets bugReportFailed to true and isReportingBug to false', () => { - store.mutations.REPORT_BUG_FAILED(state) + mutations.REPORT_BUG_FAILED(state) expect(state.bugReportFailed).toBeTruthy() expect(state.isReportingBug).toBeFalsy() diff --git a/test/unit/specs/store/image-provider-store.spec.js b/test/unit/specs/store/provider.spec.js similarity index 64% rename from test/unit/specs/store/image-provider-store.spec.js rename to test/unit/specs/store/provider.spec.js index 5ba1bcc4b73..d4efef57865 100644 --- a/test/unit/specs/store/image-provider-store.spec.js +++ b/test/unit/specs/store/provider.spec.js @@ -1,4 +1,4 @@ -import store from '~/store-modules/media-provider-store' +import { state, mutations, createActions } from '~/store/provider' import { FETCH_MEDIA_PROVIDERS_END, FETCH_MEDIA_PROVIDERS_START, @@ -6,35 +6,44 @@ import { SET_PROVIDER_FETCH_ERROR, } from '~/constants/mutation-types' import { FETCH_MEDIA_TYPE_PROVIDERS } from '~/constants/action-types' +import { IMAGE } from '~/constants/media' describe('Image Provider Store', () => { describe('state', () => { it('exports default state', () => { - expect(store.state.imageProviders).toHaveLength(0) - expect(store.state.isFetchingImageProvidersError).toBeFalsy() - expect(store.state.isFetchingImageProviders).toBeFalsy() + expect(state().imageProviders).toHaveLength(0) + expect(state().isFetchingImageProvidersError).toBeFalsy() + expect(state().isFetchingImageProviders).toBeFalsy() }) }) describe('mutations', () => { - let state = null + let store = {} + let serviceMock = null beforeEach(() => { - state = {} + serviceMock = jest.fn() + store = { + state: state(), + mutations: mutations, + actions: createActions(serviceMock), + } }) it('FETCH_MEDIA_PROVIDERS_START sets isFetchingImageProviders to true', () => { - store.mutations[FETCH_MEDIA_PROVIDERS_START](state, { + store.mutations[FETCH_MEDIA_PROVIDERS_START](store.state, { mediaType: 'image', }) - expect(state.isFetchingImageProviders).toBeTruthy() + expect(store.state.isFetchingImageProviders).toBeTruthy() }) it('FETCH_MEDIA_PROVIDERS_END sets isFetchingImageProviders to false', () => { - store.mutations[FETCH_MEDIA_PROVIDERS_END](state, { mediaType: 'image' }) + store.mutations[FETCH_MEDIA_PROVIDERS_END](store.state, { + mediaType: 'image', + }) - expect(state.isFetchingImageProviders).toBeFalsy() + expect(store.state.isFetchingImageProviders).toBeFalsy() }) it('SET_PROVIDER_FETCH_ERROR sets isFetchingImageProvidersError', () => { @@ -42,9 +51,9 @@ describe('Image Provider Store', () => { mediaType: 'image', error: true, } - store.mutations[SET_PROVIDER_FETCH_ERROR](state, params) + store.mutations[SET_PROVIDER_FETCH_ERROR](store.state, params) - expect(state.isFetchingImageProvidersError).toBe(params.error) + expect(store.state.isFetchingImageProvidersError).toBe(params.error) }) it('SET_IMAGE_PROVIDERS sets imageProviders', () => { @@ -52,9 +61,9 @@ describe('Image Provider Store', () => { mediaType: 'image', providers: [{ name: 'testProvider' }], } - store.mutations[SET_MEDIA_PROVIDERS](state, params) + store.mutations[SET_MEDIA_PROVIDERS](store.state, params) - expect(state.imageProviders).toBe(params.providers) + expect(store.state.imageProviders).toBe(params.providers) }) }) @@ -63,13 +72,11 @@ describe('Image Provider Store', () => { const imageProviderServiceMock = { getProviderStats: jest.fn(() => Promise.resolve({ data })), } + const services = { [IMAGE]: imageProviderServiceMock } const commit = jest.fn() const dispatch = jest.fn() it('FETCH_MEDIA_TYPE_PROVIDERS on success', (done) => { - const action = store.actions( - imageProviderServiceMock, - imageProviderServiceMock - )[FETCH_MEDIA_TYPE_PROVIDERS] + const action = createActions(services)[FETCH_MEDIA_TYPE_PROVIDERS] action({ commit, dispatch }, { mediaType: 'image' }).then(() => { expect(commit).toBeCalledWith(SET_PROVIDER_FETCH_ERROR, { error: false, diff --git a/test/unit/test-utils/sample-store.js b/test/unit/test-utils/sample-store.js index eddf879cc48..4f48eb05cd1 100644 --- a/test/unit/test-utils/sample-store.js +++ b/test/unit/test-utils/sample-store.js @@ -1,5 +1,5 @@ import SearchStore from '~/store-modules/search-store' -import MediaProviderStore from '~/store-modules/media-provider-store' +import MediaProviderStore from '~/store/provider' const store = { state: Object.assign(SearchStore.state, MediaProviderStore.state), From 9aa833dcd611e26e4e323a4cc9340bf98d1fd601 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sun, 19 Sep 2021 06:10:00 +0300 Subject: [PATCH 6/8] Make 'nav' module namespaced --- src/components/HeaderSection.vue | 2 +- src/components/HeroSection.vue | 2 +- src/constants/store-modules.js | 1 + src/layouts/embedded-with-nav-search.vue | 4 +++- src/layouts/embedded.vue | 4 +++- src/middleware/middleware.js | 7 ++++--- src/mixins/iframe-height.js | 2 +- src/pages/about.vue | 4 ++-- src/pages/extension.vue | 4 ++-- src/pages/feedback.vue | 18 +++++++----------- src/pages/index.vue | 2 +- src/pages/meta-search.vue | 2 +- src/pages/photos/_id.vue | 2 +- src/pages/search-help.vue | 2 +- src/pages/search.vue | 2 +- src/pages/sources.vue | 7 +++++-- src/plugins/migration-notice.js | 3 ++- src/plugins/url-change.js | 2 +- src/store/index.js | 10 ++++------ .../nav-store.js => store/nav.js} | 7 +++---- .../specs/components/header-section.spec.js | 2 +- 21 files changed, 46 insertions(+), 43 deletions(-) rename src/{store-modules/nav-store.js => store/nav.js} (82%) diff --git a/src/components/HeaderSection.vue b/src/components/HeaderSection.vue index f84f2477dcb..46264c0491c 100644 --- a/src/components/HeaderSection.vue +++ b/src/components/HeaderSection.vue @@ -21,7 +21,7 @@ export default { computed: { ...mapState({ showNotification: (state) => state.showNotification, - isEmbedded: (state) => state.isEmbedded, + isEmbedded: (state) => state.nav.isEmbedded, }), }, } diff --git a/src/components/HeroSection.vue b/src/components/HeroSection.vue index 30a1ad07e6b..2e038b98085 100644 --- a/src/components/HeroSection.vue +++ b/src/components/HeroSection.vue @@ -68,7 +68,7 @@ export default { name: 'HeroSection', data: () => ({ form: { searchTerm: '' } }), computed: { - ...mapState({ isEmbedded: (state) => state.isEmbedded }), + ...mapState({ isEmbedded: (state) => state.nav.isEmbedded }), }, mounted() { if (document.querySelector('#searchTerm')) { diff --git a/src/constants/store-modules.js b/src/constants/store-modules.js index 0624b21d876..a8cbab00708 100644 --- a/src/constants/store-modules.js +++ b/src/constants/store-modules.js @@ -2,3 +2,4 @@ export const RELATED = 'related' export const ABTEST = 'abtest' export const ATTRIBUTION = 'attribution' export const PROVIDER = 'provider' +export const NAV = 'nav' diff --git a/src/layouts/embedded-with-nav-search.vue b/src/layouts/embedded-with-nav-search.vue index 30e2b4cecfc..3607ee942ba 100644 --- a/src/layouts/embedded-with-nav-search.vue +++ b/src/layouts/embedded-with-nav-search.vue @@ -19,7 +19,9 @@ const embeddedWithNavSearch = { head() { return this.$nuxtI18nHead({ addSeoAttributes: true }) }, - computed: mapState(['isReferredFromCc']), + computed: mapState({ + isReferredFromCc: (state) => state.nav.isReferredFromCc, + }), } export default embeddedWithNavSearch diff --git a/src/layouts/embedded.vue b/src/layouts/embedded.vue index 3d3a3b2409b..b67e06c7b58 100644 --- a/src/layouts/embedded.vue +++ b/src/layouts/embedded.vue @@ -19,7 +19,9 @@ const embeddedPage = { head() { return this.$nuxtI18nHead({ addSeoAttributes: true }) }, - computed: mapState(['isReferredFromCc']), + computed: mapState({ + isReferredFromCc: (state) => state.nav.isReferredFromCc, + }), } export default embeddedPage diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 9ad0b1280a5..b79525544b4 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -1,6 +1,7 @@ import { SET_EMBEDDED, SET_REFERRED } from '~/constants/mutation-types' import { sendWindowMessage } from '~/utils/send-message' import config from '../../nuxt.config.js' +import { NAV } from '~/constants/store-modules' /** * In embedded mode, the app sends its size and url @@ -19,7 +20,7 @@ import config from '../../nuxt.config.js' export default function ({ store, query, route }) { if ('embedded' in query) { const isEmbedded = query.embedded === 'true' - store.commit(SET_EMBEDDED, { isEmbedded }) + store.commit(`${NAV}/${SET_EMBEDDED}`, { isEmbedded }) } if (process.client) { sendWindowMessage({ @@ -29,7 +30,7 @@ export default function ({ store, query, route }) { }) } - if (store.state.isReferredFromCc) { - store.commit(SET_REFERRED, { isReferredFromCc: false }) + if (store.state.nav.isReferredFromCc) { + store.commit(`${NAV}/${SET_REFERRED}`, { isReferredFromCc: false }) } } diff --git a/src/mixins/iframe-height.js b/src/mixins/iframe-height.js index b9a6bb6bc57..1d3b83f4db1 100644 --- a/src/mixins/iframe-height.js +++ b/src/mixins/iframe-height.js @@ -10,7 +10,7 @@ import config from '../../nuxt.config.js' export default { data: () => ({ height: 0, observer: null }), mounted() { - if (this.$store.state.isEmbedded) { + if (this.$store.state.nav.isEmbedded) { this.notifyOuterWindow(document.documentElement.scrollHeight) this.observer = this.createResizeObserver() this.observer.observe(document.documentElement) diff --git a/src/pages/about.vue b/src/pages/about.vue index 4064e57331f..1e8afd88ac3 100644 --- a/src/pages/about.vue +++ b/src/pages/about.vue @@ -101,12 +101,12 @@ import { mapState } from 'vuex' const AboutPage = { name: 'about-page', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, computed: { - ...mapState(['isEmbedded']), + ...mapState({ isEmbedded: (state) => state.nav.isEmbedded }), }, } diff --git a/src/pages/extension.vue b/src/pages/extension.vue index fb37e073c9a..d1135edf480 100644 --- a/src/pages/extension.vue +++ b/src/pages/extension.vue @@ -82,7 +82,7 @@ const AboutPage = { name: 'about-page', components: { ExtensionBrowsers }, layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, @@ -98,7 +98,7 @@ const AboutPage = { } }, computed: { - ...mapState(['isEmbedded']), + ...mapState({ isEmbedded: (state) => state.nav.isEmbedded }), }, methods: { togglePlay() { diff --git a/src/pages/feedback.vue b/src/pages/feedback.vue index 88d3e4665ae..6434b278890 100644 --- a/src/pages/feedback.vue +++ b/src/pages/feedback.vue @@ -71,7 +71,7 @@ const suggestionForm = export const FeedbackPage = { name: 'feedback-page', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, @@ -97,16 +97,12 @@ export const FeedbackPage = { }, }, computed: { - ...mapState(['isEmbedded']), - isReportingBug() { - return this.$store.state.isReportingBug - }, - bugReported() { - return this.$store.state.bugReported - }, - bugReportFailed() { - return this.$store.state.bugReportFailed - }, + ...mapState({ + isEmbedded: (state) => state.nav.isEmbedded, + isReportingBug: (state) => state['bug-report'].isReportingBug, + bugReported: (state) => state['bug-report'].bugReported, + bugReportFailed: (state) => state['bug-report'].bugReportFailed, + }), }, } diff --git a/src/pages/index.vue b/src/pages/index.vue index 2e2e26edaaa..7424b876e95 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -8,7 +8,7 @@ import { CLEAR_FILTERS } from '~/constants/mutation-types' const HomePage = { name: 'home-page', layout({ store }) { - return store.state.isEmbedded ? 'embedded' : 'default' + return store.state.nav.isEmbedded ? 'embedded' : 'default' }, beforeMount() { this.$store.commit(`${CLEAR_FILTERS}`) diff --git a/src/pages/meta-search.vue b/src/pages/meta-search.vue index 7fe45365198..7fe6841d7ca 100644 --- a/src/pages/meta-search.vue +++ b/src/pages/meta-search.vue @@ -110,7 +110,7 @@ import { mapState } from 'vuex' export default { name: 'MetaSearchPage', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, diff --git a/src/pages/photos/_id.vue b/src/pages/photos/_id.vue index dd4285e530f..68b8ae0add8 100644 --- a/src/pages/photos/_id.vue +++ b/src/pages/photos/_id.vue @@ -37,7 +37,7 @@ import { RELATED } from '~/constants/store-modules' const PhotoDetailPage = { name: 'PhotoDetailPage', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, diff --git a/src/pages/search-help.vue b/src/pages/search-help.vue index e7f0fe58023..1cf4d901566 100644 --- a/src/pages/search-help.vue +++ b/src/pages/search-help.vue @@ -260,7 +260,7 @@ import { mapState } from 'vuex' const SearchHelpPage = { name: 'search-help-page', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, diff --git a/src/pages/search.vue b/src/pages/search.vue index 0720f8dc042..435c2e88480 100644 --- a/src/pages/search.vue +++ b/src/pages/search.vue @@ -37,7 +37,7 @@ import { mapActions, mapMutations } from 'vuex' const BrowsePage = { name: 'browse-page', layout({ store }) { - return store.state.isEmbedded ? 'embedded' : 'default' + return store.state.nav.isEmbedded ? 'embedded' : 'default' }, scrollToTop: false, async fetch() { diff --git a/src/pages/sources.vue b/src/pages/sources.vue index c7055375bcc..40253ad9862 100644 --- a/src/pages/sources.vue +++ b/src/pages/sources.vue @@ -140,7 +140,7 @@ import { mapState } from 'vuex' const SourcePage = { name: 'source-page', layout({ store }) { - return store.state.isEmbedded + return store.state.nav.isEmbedded ? 'embedded-with-nav-search' : 'with-nav-search' }, @@ -153,7 +153,10 @@ const SourcePage = { } }, computed: { - ...mapState(['imageProviders', 'isEmbedded']), + ...mapState({ + imageProviders: (state) => state.provider.imageProviders, + isEmbedded: (state) => state.nav.isEmbedded, + }), sortedProviders() { const sorted = sortBy(this.imageProviders, [this.sort.field]) return this.sort.direction === 'asc' ? sorted : sorted.reverse() diff --git a/src/plugins/migration-notice.js b/src/plugins/migration-notice.js index 5fc6506a6c0..eb79ffbd348 100644 --- a/src/plugins/migration-notice.js +++ b/src/plugins/migration-notice.js @@ -1,4 +1,5 @@ import { SET_REFERRED } from '~/constants/mutation-types.js' +import { NAV } from '~/constants/store-modules' /** * If the URL contains a referral parameter pointing containing @@ -8,6 +9,6 @@ import { SET_REFERRED } from '~/constants/mutation-types.js' export default function ({ query, store }) { if (query.referrer) { const isReferredFromCc = query.referrer.includes('creativecommons.org') - store.commit(SET_REFERRED, { isReferredFromCc }) + store.commit(`${NAV}/${SET_REFERRED}`, { isReferredFromCc }) } } diff --git a/src/plugins/url-change.js b/src/plugins/url-change.js index d562969ddc9..f560772248f 100644 --- a/src/plugins/url-change.js +++ b/src/plugins/url-change.js @@ -8,7 +8,7 @@ import config from '../../nuxt.config.js' */ export default function ({ app, store }) { app.router.onReady(() => { - if (process.client && store.state.isEmbedded) { + if (process.client && store.state.nav.isEmbedded) { sendWindowMessage({ debug: config.dev, type: 'urlChange', diff --git a/src/store/index.js b/src/store/index.js index 3b7d8ba5f69..156c3976c78 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -9,9 +9,9 @@ import UsageDataStore from '~/store-modules/usage-data-store' import FilterStore from '~/store-modules/filter-store' import ReportContentStore from '~/store-modules/report-content-store' import NotificationStore from '~/store-modules/notification-store' -import NavStore from '~/store-modules/nav-store' import { FETCH_MEDIA_PROVIDERS } from '~/constants/action-types' import GoogleAnalytics from '~/analytics/google-analytics' +import { PROVIDER } from '~/constants/store-modules' export const actions = Object.assign( UsageDataStore.actions(UsageDataService), @@ -23,7 +23,7 @@ export const actions = Object.assign( { async nuxtServerInit({ dispatch }) { try { - await dispatch(FETCH_MEDIA_PROVIDERS) + await dispatch(`${PROVIDER}/${FETCH_MEDIA_PROVIDERS}`) } catch (error) { // TODO: What happens if we do not have image providers? // How do we show the error to the user? @@ -39,8 +39,7 @@ export const state = () => FilterStore.state, UserStore.state, ReportContentStore.state, - NotificationStore.state, - NavStore.state + NotificationStore.state ) export const getters = Object.assign(FilterStore.getters) @@ -49,6 +48,5 @@ export const mutations = Object.assign( SearchStore.mutations, FilterStore.mutations, ReportContentStore.mutations, - NotificationStore.mutations, - NavStore.mutations + NotificationStore.mutations ) diff --git a/src/store-modules/nav-store.js b/src/store/nav.js similarity index 82% rename from src/store-modules/nav-store.js rename to src/store/nav.js index fc182cef1ba..d417c1e96c6 100644 --- a/src/store-modules/nav-store.js +++ b/src/store/nav.js @@ -1,11 +1,10 @@ import { SET_EMBEDDED, SET_REFERRED } from '~/constants/mutation-types' -const state = { +export const state = () => ({ isEmbedded: true, - isReferredFromCc: false, -} +}) -const mutations = { +export const mutations = { [SET_EMBEDDED](_state, params) { _state.isEmbedded = params.isEmbedded }, diff --git a/test/unit/specs/components/header-section.spec.js b/test/unit/specs/components/header-section.spec.js index 154ecadc136..c1358fde87b 100644 --- a/test/unit/specs/components/header-section.spec.js +++ b/test/unit/specs/components/header-section.spec.js @@ -6,7 +6,7 @@ describe('HeaderSection', () => { const wrapper = render(HeaderSection, { mocks: { $store: { - state: { abSessionId: '' }, + state: { abSessionId: '', nav: { isEmbedded: true } }, }, $route: { path: '', From 5b90ff78a14cf3c4d8139a27a346976e55114d56 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Sun, 19 Sep 2021 06:21:06 +0300 Subject: [PATCH 7/8] Make 'notification' and 'report-content' modules namespaced --- src/components/NotificationBanner.vue | 13 +++++++------ src/constants/action-types.js | 1 + src/constants/store-modules.js | 2 ++ src/store/index.js | 17 ++--------------- .../notification.js} | 18 +++++++----------- .../report-content.js} | 19 +++++++++++-------- .../specs/store/report-content-store.spec.js | 8 ++++---- 7 files changed, 34 insertions(+), 44 deletions(-) rename src/{store-modules/notification-store.js => store/notification.js} (82%) rename src/{store-modules/report-content-store.js => store/report-content.js} (71%) diff --git a/src/components/NotificationBanner.vue b/src/components/NotificationBanner.vue index c178d570687..83f0c53c1d6 100644 --- a/src/components/NotificationBanner.vue +++ b/src/components/NotificationBanner.vue @@ -36,25 +36,26 @@