From ecb99e0e8ca94b0e29a7041f3ed13ce7b6e6e05e Mon Sep 17 00:00:00 2001 From: Pranav Date: Sun, 12 Jan 2025 12:03:22 -0800 Subject: [PATCH] Migrate widgetPortalArticlesToPinia --- app/javascript/entrypoints/widget.js | 3 + app/javascript/widget/api/article.js | 7 -- app/javascript/widget/api/endPoints.js | 10 -- .../Home/Article/ArticleContainer.vue | 74 ++++++++++++ app/javascript/widget/store/index.js | 2 - .../widget/store/modules/articles.js | 55 --------- .../widget/stores/api/articleAPI.js | 13 +++ app/javascript/widget/stores/articleStore.js | 6 + .../widget/stores/piniaStoreFactory.js | 105 ++++++++++++++++++ app/javascript/widget/views/Home.vue | 77 +------------ package.json | 1 + pnpm-lock.yaml | 18 +-- 12 files changed, 216 insertions(+), 155 deletions(-) delete mode 100644 app/javascript/widget/api/article.js create mode 100644 app/javascript/widget/components/pageComponents/Home/Article/ArticleContainer.vue delete mode 100644 app/javascript/widget/store/modules/articles.js create mode 100644 app/javascript/widget/stores/api/articleAPI.js create mode 100644 app/javascript/widget/stores/articleStore.js create mode 100644 app/javascript/widget/stores/piniaStoreFactory.js diff --git a/app/javascript/entrypoints/widget.js b/app/javascript/entrypoints/widget.js index 5c1fac7a9..8ef1cdddf 100644 --- a/app/javascript/entrypoints/widget.js +++ b/app/javascript/entrypoints/widget.js @@ -10,6 +10,7 @@ import router from '../widget/router'; import { directive as onClickaway } from 'vue3-click-away'; import { domPurifyConfig } from '../shared/helpers/HTMLSanitizer'; import { plugin, defaultConfig } from '@formkit/vue'; +import { createPinia } from 'pinia'; import { startsWithPlus, @@ -21,9 +22,11 @@ const i18n = createI18n({ locale: 'en', messages: i18nMessages, }); +const pinia = createPinia(); const app = createApp(App); app.use(i18n); +app.use(pinia); app.use(store); app.use(router); app.use(VueDOMPurifyHTML, domPurifyConfig); diff --git a/app/javascript/widget/api/article.js b/app/javascript/widget/api/article.js deleted file mode 100644 index 0c9d6675a..000000000 --- a/app/javascript/widget/api/article.js +++ /dev/null @@ -1,7 +0,0 @@ -import endPoints from 'widget/api/endPoints'; -import { API } from 'widget/helpers/axios'; - -export const getMostReadArticles = async (slug, locale) => { - const urlData = endPoints.getMostReadArticles(slug, locale); - return API.get(urlData.url, { params: urlData.params }); -}; diff --git a/app/javascript/widget/api/endPoints.js b/app/javascript/widget/api/endPoints.js index e6ada5914..17e315800 100755 --- a/app/javascript/widget/api/endPoints.js +++ b/app/javascript/widget/api/endPoints.js @@ -97,15 +97,6 @@ const triggerCampaign = ({ websiteToken, campaignId, customAttributes }) => ({ }, }); -const getMostReadArticles = (slug, locale) => ({ - url: `/hc/${slug}/${locale}/articles.json`, - params: { - page: 1, - sort: 'views', - status: 1, - }, -}); - export default { createConversation, sendMessage, @@ -115,5 +106,4 @@ export default { getAvailableAgents, getCampaigns, triggerCampaign, - getMostReadArticles, }; diff --git a/app/javascript/widget/components/pageComponents/Home/Article/ArticleContainer.vue b/app/javascript/widget/components/pageComponents/Home/Article/ArticleContainer.vue new file mode 100644 index 000000000..135a82b2d --- /dev/null +++ b/app/javascript/widget/components/pageComponents/Home/Article/ArticleContainer.vue @@ -0,0 +1,74 @@ + + + diff --git a/app/javascript/widget/store/index.js b/app/javascript/widget/store/index.js index 22115d5b1..a63696bb6 100755 --- a/app/javascript/widget/store/index.js +++ b/app/javascript/widget/store/index.js @@ -10,7 +10,6 @@ import events from 'widget/store/modules/events'; import globalConfig from 'shared/store/globalConfig'; import message from 'widget/store/modules/message'; import campaign from 'widget/store/modules/campaign'; -import article from 'widget/store/modules/articles'; export default createStore({ modules: { @@ -24,6 +23,5 @@ export default createStore({ globalConfig, message, campaign, - article, }, }); diff --git a/app/javascript/widget/store/modules/articles.js b/app/javascript/widget/store/modules/articles.js deleted file mode 100644 index 0f858012b..000000000 --- a/app/javascript/widget/store/modules/articles.js +++ /dev/null @@ -1,55 +0,0 @@ -import { getMostReadArticles } from 'widget/api/article'; - -const state = { - records: [], - uiFlags: { - isError: false, - hasFetched: false, - isFetching: false, - }, -}; - -export const getters = { - uiFlags: $state => $state.uiFlags, - popularArticles: $state => $state.records, -}; - -export const actions = { - fetch: async ({ commit }, { slug, locale }) => { - commit('setIsFetching', true); - commit('setError', false); - - try { - const { data } = await getMostReadArticles(slug, locale); - const { payload = [] } = data; - - if (payload.length) { - commit('setArticles', payload); - } - } catch (error) { - commit('setError', true); - } finally { - commit('setIsFetching', false); - } - }, -}; - -export const mutations = { - setArticles($state, data) { - $state.records = data; - }, - setError($state, value) { - $state.uiFlags.isError = value; - }, - setIsFetching($state, value) { - $state.uiFlags.isFetching = value; - }, -}; - -export default { - namespaced: true, - state, - getters, - actions, - mutations, -}; diff --git a/app/javascript/widget/stores/api/articleAPI.js b/app/javascript/widget/stores/api/articleAPI.js new file mode 100644 index 000000000..597d0785a --- /dev/null +++ b/app/javascript/widget/stores/api/articleAPI.js @@ -0,0 +1,13 @@ +import { API } from 'widget/helpers/axios'; + +export default { + index: params => { + const url = `/hc/${params.slug}/${params.locale}/articles.json`; + const urlParams = { + page: 1, + sort: 'views', + status: 1, + }; + return API.get(url, { params: urlParams }); + }, +}; diff --git a/app/javascript/widget/stores/articleStore.js b/app/javascript/widget/stores/articleStore.js new file mode 100644 index 000000000..3c4ea63d6 --- /dev/null +++ b/app/javascript/widget/stores/articleStore.js @@ -0,0 +1,6 @@ +import articleAPI from './api/articleAPI'; +import { createResourceStore } from './piniaStoreFactory'; + +export const useArticleStore = createResourceStore('articles', { + api: articleAPI, +}); diff --git a/app/javascript/widget/stores/piniaStoreFactory.js b/app/javascript/widget/stores/piniaStoreFactory.js new file mode 100644 index 000000000..d93ab00d7 --- /dev/null +++ b/app/javascript/widget/stores/piniaStoreFactory.js @@ -0,0 +1,105 @@ +import { defineStore } from 'pinia'; + +export const createResourceStore = ( + storeName, + { api, customGetters = {}, customActions = {} } +) => { + return defineStore(storeName, { + state: () => ({ + records: [], + uiFlags: { + isFetching: false, + isCreating: false, + isUpdating: false, + isDeleting: false, + }, + error: null, + }), + + getters: { + getRecords: state => state.records, + getUIFlags: state => state.uiFlags, + getError: state => state.error, + ...customGetters, + }, + + actions: { + async index(params = {}) { + this.uiFlags.isFetching = true; + this.error = null; + + try { + const { + data: { payload = [] }, + } = await api.index(params); + this.records = [...payload]; + } catch (error) { + this.error = error; + throw error; + } finally { + this.uiFlags.isFetching = false; + } + }, + + async create(payload) { + this.uiFlags.isCreating = true; + this.error = null; + + try { + const { data } = await api.post(payload); + this.records.push(data.payload); + return data.payload; + } catch (error) { + this.error = error; + throw error; + } finally { + this.uiFlags.isCreating = false; + } + }, + + async update(id, payload) { + this.uiFlags.isUpdating = true; + this.error = null; + + try { + const { data } = await api.put(id, payload); + const index = this.records.findIndex(record => record.id === id); + if (index !== -1) { + this.records[index] = data.payload; + } + return data.payload; + } catch (error) { + this.error = error; + throw error; + } finally { + this.uiFlags.isUpdating = false; + } + }, + + async delete(id) { + this.uiFlags.isDeleting = true; + this.error = null; + + try { + await api.delete(id); + this.records = this.records.filter(record => record.id !== id); + } catch (error) { + this.error = error; + throw error; + } finally { + this.uiFlags.isDeleting = false; + } + }, + + reset() { + this.records = []; + this.error = null; + Object.keys(this.uiFlags).forEach(key => { + this.uiFlags[key] = false; + }); + }, + + ...customActions, + }, + }); +}; diff --git a/app/javascript/widget/views/Home.vue b/app/javascript/widget/views/Home.vue index d02e3f8d3..ff0703a2a 100755 --- a/app/javascript/widget/views/Home.vue +++ b/app/javascript/widget/views/Home.vue @@ -1,62 +1,26 @@ @@ -95,21 +41,6 @@ export default { @start-conversation="startConversation" /> -
- - -
+ diff --git a/package.json b/package.json index 10ee2a88a..63dcb3423 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "md5": "^2.3.0", "mitt": "^3.0.1", "opus-recorder": "^8.0.5", + "pinia": "^2.3.0", "semver": "7.6.3", "snakecase-keys": "^8.0.1", "timezone-phone-codes": "^0.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d2059e42..6e868b601 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -157,6 +157,9 @@ importers: opus-recorder: specifier: ^8.0.5 version: 8.0.5 + pinia: + specifier: ^2.3.0 + version: 2.3.0(typescript@5.6.2)(vue@3.5.12(typescript@5.6.2)) semver: specifier: 7.6.3 version: 7.6.3 @@ -3927,15 +3930,12 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pinia@2.2.6: - resolution: {integrity: sha512-vIsR8JkDN5Ga2vAxqOE2cJj4VtsHnzpR1Fz30kClxlh0yCHfec6uoMeM3e/ddqmwFUejK3NlrcQa/shnpyT4hA==} + pinia@2.3.0: + resolution: {integrity: sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==} peerDependencies: - '@vue/composition-api': ^1.4.0 typescript: '>=4.4.4' - vue: ^2.6.14 || ^3.5.11 + vue: ^2.7.0 || ^3.5.11 peerDependenciesMeta: - '@vue/composition-api': - optional: true typescript: optional: true @@ -5262,7 +5262,7 @@ snapshots: clsx: 2.1.1 date-fns: 3.6.0 lucide-vue-next: 0.394.0(vue@3.5.12(typescript@5.6.2)) - pinia: 2.2.6(typescript@5.6.2)(vue@3.5.12(typescript@5.6.2)) + pinia: 2.3.0(typescript@5.6.2)(vue@3.5.12(typescript@5.6.2)) radix-vue: 1.9.9(vue@3.5.12(typescript@5.6.2)) secure-ls: 2.0.0 tailwind-merge: 2.5.4 @@ -9317,13 +9317,15 @@ snapshots: pify@2.3.0: {} - pinia@2.2.6(typescript@5.6.2)(vue@3.5.12(typescript@5.6.2)): + pinia@2.3.0(typescript@5.6.2)(vue@3.5.12(typescript@5.6.2)): dependencies: '@vue/devtools-api': 6.6.4 vue: 3.5.12(typescript@5.6.2) vue-demi: 0.14.10(vue@3.5.12(typescript@5.6.2)) optionalDependencies: typescript: 5.6.2 + transitivePeerDependencies: + - '@vue/composition-api' pirates@4.0.6: {}