diff --git a/package.json b/package.json index 9c3b569..4552978 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "react-select": "^5.4.0", "react-simple-maps": "^3.0.0", "react-spinners": "^0.13.6", + "react-step-wizard": "^5.3.11", "react-table": "^7.6.2", "react-timezone-select": "^1.0.7", "react-toastify": "^9.0.8", diff --git a/src/components/Menu/index.jsx b/src/components/Menu/index.jsx index 7143cc7..5cdc6b2 100644 --- a/src/components/Menu/index.jsx +++ b/src/components/Menu/index.jsx @@ -93,12 +93,24 @@ const Menu = observer((props) => { icons_color: '/assets/images/image.png', width: 24, height: 24, - // submenu: [ - // { - // text: "txt_menu_overview", - // link: `/data-${dataStreamActive}/audience/overview`, - // }, - // ], + }, + { + text: 'txt_migrator', + link: `/migrator`, + icons: '/assets/images/image.png', + icons_color: '/assets/images/image.png', + width: 24, + height: 24, + submenu: [ + { + text: 'Joomla', + link: '/migrator/joomla', + }, + { + text: 'Wordpress', + link: '/migrator/wordpress', + }, + ], }, ]; diff --git a/src/components/SbarLeft/index.scss b/src/components/SbarLeft/index.scss index 817df63..e69de29 100644 --- a/src/components/SbarLeft/index.scss +++ b/src/components/SbarLeft/index.scss @@ -1,3 +0,0 @@ -.progress { - height: 4px; -} diff --git a/src/containers/MigratorPage/MigratorForm/JoomlaForm.jsx b/src/containers/MigratorPage/MigratorForm/JoomlaForm.jsx new file mode 100644 index 0000000..4f66434 --- /dev/null +++ b/src/containers/MigratorPage/MigratorForm/JoomlaForm.jsx @@ -0,0 +1,119 @@ +import Input from 'components/Form/Input'; +import { FORM_FIELD_TYPE } from 'constants/FormFieldType'; +import React, { Component } from 'react'; +import { Button, Form } from 'react-bootstrap'; +import SimpleReactValidator from 'simple-react-validator'; +import { observer } from 'mobx-react'; +import { notify } from 'components/Toast'; +import { withMigratorViewModel } from '../MigratorViewModels/MigratorViewModelContextProvider'; +import { JOOMLA_FIELDS } from '../MigratorUtils/joomla'; +import { withTranslation } from 'react-i18next'; +const JoomlaForm = observer( + class JoomlaForm extends Component { + joomlaFormViewmodel = ''; + formPropsData = { + [JOOMLA_FIELDS.URL]: '', + [JOOMLA_FIELDS.TOKEN]: '', + }; + constructor(props) { + super(props); + this.joomlaFormViewmodel = props.viewModel?.getJoomlaFormViewModel(); + this.validator = new SimpleReactValidator({ autoForceUpdate: this }); + this.state = { + loading: false, + }; + } + hanldeClick = () => { + const { nextStep } = this.props; + this.setState({ loading: true }); + if (this.validator.allValid()) { + nextStep(); + } else { + notify('Please input all required fields', 'warn'); + this.validator.showMessages(); + } + this.setState({ loading: false }); + }; + + render() { + const { t } = this.props; + const { loading } = this.state; + return ( + <> +

{t('txt_migrator_joomla')}

+ +
+
+
+ + + Joomla Bearer Token + * + + { + this.joomlaFormViewmodel.formPropsData[JOOMLA_FIELDS.TOKEN] = + e.target.value; + }, + blurred: () => { + this.validator.showMessageFor('Joomla Bearer Token'); + }, + }} + /> + {this.validator.message( + 'Joomla Bearer Token', + this.joomlaFormViewmodel?.formPropsData[JOOMLA_FIELDS.TOKEN], + 'required', + { + className: 'text-danger mt-1', + } + )} + + + + Joomla API URL + * + + { + this.joomlaFormViewmodel.formPropsData[JOOMLA_FIELDS.URL] = e.target.value; + }, + blurred: () => { + this.validator.showMessageFor('Joomla API URL'); + }, + }} + /> + {this.validator.message( + 'Joomla API URL', + this.joomlaFormViewmodel?.formPropsData[JOOMLA_FIELDS.URL], + 'required', + { + className: 'text-danger mt-1', + } + )} + +
+
+ +
+
+
+ + ); + } + } +); +export default withTranslation('common')(withMigratorViewModel(JoomlaForm)); diff --git a/src/containers/MigratorPage/MigratorForm/MergeDataPage.jsx b/src/containers/MigratorPage/MigratorForm/MergeDataPage.jsx new file mode 100644 index 0000000..c223e0a --- /dev/null +++ b/src/containers/MigratorPage/MigratorForm/MergeDataPage.jsx @@ -0,0 +1,73 @@ +import React, { Component } from 'react'; +import { Button } from 'react-bootstrap'; +import ProgressBar from 'react-bootstrap/ProgressBar'; +import { observer } from 'mobx-react'; +import { withTranslation } from 'react-i18next'; + +const MergeDataPage = observer( + class MergeDataPage extends Component { + constructor(props) { + super(props); + this.viewModel = props.viewModel; + this.state = { + isMerging: false, + percent: 0, + }; + } + increasePercentPerSecond = () => { + if (this.state.percent < 99) { + this.setState({ percent: this.state.percent + 3 }); + } + }; + handleClick = async () => { + this.setState({ isMerging: true }); + const increasePercent = setInterval(this.increasePercentPerSecond, 500); + const response = await this.viewModel.migratorData(); + if (response) { + this.setState({ percent: 100 }); + } + clearInterval(increasePercent); + this.setState({ isMerging: false }); + }; + render() { + const { previousStep, t } = this.props; + const { isMerging, percent } = this.state; + return ( + <> +
+
+
+ +
+
+ +
+
+
+ + + ); + } + } +); +export default withTranslation('common')(MergeDataPage); diff --git a/src/containers/MigratorPage/MigratorForm/WordPressForm.jsx b/src/containers/MigratorPage/MigratorForm/WordPressForm.jsx new file mode 100644 index 0000000..46948ae --- /dev/null +++ b/src/containers/MigratorPage/MigratorForm/WordPressForm.jsx @@ -0,0 +1,91 @@ +import Input from 'components/Form/Input'; +import { FORM_FIELD_TYPE } from 'constants/FormFieldType'; +import React, { Component } from 'react'; +import { Button, Form } from 'react-bootstrap'; +import SimpleReactValidator from 'simple-react-validator'; +import { observer } from 'mobx-react'; +import { notify } from 'components/Toast'; +import { withMigratorViewModel } from '../MigratorViewModels/MigratorViewModelContextProvider'; +import { WORDPRESS_FIELDS } from '../MigratorUtils/wordpress'; +import { withTranslation } from 'react-i18next'; +const WordPressForm = observer( + class WordPressForm extends Component { + wordPressFormViewModel = ''; + formPropsData = { + [WORDPRESS_FIELDS.URL]: '', + }; + constructor(props) { + super(props); + this.wordPressFormViewModel = props.viewModel.getWordPressFormViewModel(); + this.validator = new SimpleReactValidator({ autoForceUpdate: this }); + this.state = { + loading: false, + }; + } + hanldeClick = () => { + const { nextStep } = this.props; + this.setState({ loading: true }); + if (this.validator.allValid()) { + nextStep(); + } else { + notify('Please input WordPress API URL fields', 'warn'); + this.validator.showMessages(); + } + this.setState({ loading: false }); + }; + + render() { + const { t } = this.props; + const { loading } = this.state; + return ( + <> +

{t('txt_migrator_wordpress')}

+
+
+
+ + + WordPress API URL + * + + { + this.wordPressFormViewModel.formPropsData[WORDPRESS_FIELDS.URL] = + e.target.value; + }, + blurred: () => { + this.validator.showMessageFor('WordPress API URL'); + }, + }} + /> + {this.validator.message( + 'WordPress API URL', + this.wordPressFormViewModel.formPropsData[WORDPRESS_FIELDS.URL], + 'required', + { + className: 'text-danger mt-1', + } + )} + +
+
+ +
+
+
+ + ); + } + } +); +export default withTranslation('common')(withMigratorViewModel(WordPressForm)); diff --git a/src/containers/MigratorPage/MigratorStore/MigratorStore.js b/src/containers/MigratorPage/MigratorStore/MigratorStore.js new file mode 100644 index 0000000..b0e6849 --- /dev/null +++ b/src/containers/MigratorPage/MigratorStore/MigratorStore.js @@ -0,0 +1,32 @@ +import { AUTHORIZATION_KEY, Storage } from 'aesirx-dma-lib'; +import { AesirX } from '../MigratorUtils/aesirx'; +import { Joomla } from '../MigratorUtils/joomla'; +import { Wordpress } from '../MigratorUtils/wordpress'; + +export default class MigratorStore { + migratorData = async (aesirx_migrate_type, data, callbackSuccess, callbackError) => { + try { + const aesirx_bearer_token = Storage.getItem(AUTHORIZATION_KEY.ACCESS_TOKEN); + const aesirx = new AesirX( + aesirx_bearer_token, + process.env.REACT_APP_ENDPOINT_URL, + aesirx_migrate_type + ); + switch (aesirx_migrate_type) { + case 'WORDPRESS': + await new Wordpress(aesirx, data?.wordpress_api_url).runAll(); + break; + case 'JOOMLA': + default: + await new Joomla(aesirx, data?.joomla_api_url, data?.joomla_bearer_token).runAll(); + break; + } + callbackSuccess(); + return true; + } catch (error) { + console.log(error); + callbackError(); + return false; + } + }; +} diff --git a/src/containers/MigratorPage/MigratorUtils/aesirx.js b/src/containers/MigratorPage/MigratorUtils/aesirx.js new file mode 100644 index 0000000..c52be5b --- /dev/null +++ b/src/containers/MigratorPage/MigratorUtils/aesirx.js @@ -0,0 +1,131 @@ +import axios from 'axios'; + +const Entity = { + Category: 'Category', + Tag: 'Tag', + Item: 'Item', +}; + +class AesirX { + relatedAesirxUrl = + '/index.php?option=reditem&webserviceClient=site&webserviceVersion=1.0.0&api=hal'; + + constructor(aesirx_bearer_token, apiDomain, remotePrefix) { + this.ref = { + Category: {}, + Tag: {}, + Item: {}, + }; + this.entityUrlPart = { + [Entity.Category]: '&view=category_with_org_check_aesirx_categories_69', + [Entity.Tag]: '&view=category_with_org_check_aesirx_tags_70', + [Entity.Item]: '&view=item_with_org_check_aesirx_content_68', + }; + this.aesirx_bearer_token = aesirx_bearer_token; + this.apiDomain = apiDomain; + this.remotePrefix = remotePrefix; + } + setRemoteEntityId(localId, entityName, remoteKey) { + this.ref[entityName][localId] = remoteKey; + } + + async addTag(resource) { + const restTo = await axios.post( + this.apiDomain + this.relatedAesirxUrl + this.entityUrlPart[Entity.Item] + '&task=addTag', + resource, + { + acceptHeader: '*/*', + headers: { + Authorization: 'Bearer ' + this.aesirx_bearer_token, + }, + } + ); + + if (restTo.statusCode != 200 || !restTo.result) { + console.warn('Entity was not created'); + } + } + + async create(entityName, resource) { + try { + resource.id = await this.getRemoteEntityId(resource.remote_key, entityName); + } catch (err) { + console.log(err); + } + + let use = { ...resource }; + use.remote_key = this.remotePrefix + '|' + use.remote_key; + + // Update + if (resource.id) { + const restTo = await axios.put( + this.apiDomain + this.relatedAesirxUrl + this.entityUrlPart[entityName], + use, + { + acceptHeader: '*/*', + headers: { + Authorization: 'Bearer ' + this.aesirx_bearer_token, + }, + } + ); + if (restTo.status != 200 || !restTo.data) { + console.warn('Entity was not created'); + } else { + this.ref[entityName][resource.remote_key] = resource.id; + } + } + + // Create + else { + const restTo = await axios.post( + this.apiDomain + this.relatedAesirxUrl + this.entityUrlPart[entityName], + use, + { + acceptHeader: '*/*', + headers: { + Authorization: 'Bearer ' + this.aesirx_bearer_token, + }, + } + ); + if (restTo.status != 201 || !restTo.data) { + console.warn('Entity was not created'); + } else { + this.ref[entityName][resource.remote_key] = restTo.data.id; + } + } + + return this.ref[entityName][resource.remote_key]; + } + async getRemoteEntityId(localId, entityName) { + if (!(localId in this.ref[entityName])) { + const restRes = await axios.get( + this.apiDomain + + this.relatedAesirxUrl + + this.entityUrlPart[entityName] + + '&filter[remote_key]=' + + this.remotePrefix + + '|' + + localId, + { + acceptHeader: '*/*', + additionalHeaders: { + 'Content-Type': 'application/json; charset=utf-8', + }, + headers: { + Authorization: 'Bearer ' + this.aesirx_bearer_token, + }, + } + ); + + if (restRes.status != 200 || !restRes.data) { + console.warn('Dont have remote entity'); + } else { + this.setRemoteEntityId(localId, entityName, restRes.data._embedded.item[0].id); + } + } + + return this.ref[entityName][localId]; + } +} + +export { AesirX, Entity }; diff --git a/src/containers/MigratorPage/MigratorUtils/joomla.js b/src/containers/MigratorPage/MigratorUtils/joomla.js new file mode 100644 index 0000000..abfffd6 --- /dev/null +++ b/src/containers/MigratorPage/MigratorUtils/joomla.js @@ -0,0 +1,167 @@ +import axios from 'axios'; +import { Entity } from './aesirx'; + +const JOOMLA_FIELDS = { + URL: 'joomla_api_url', + TOKEN: 'joomla_bearer_token', +}; + +class Joomla { + joomla_api_url; + joomla_bearer_token; + limit = 20; + aesirx; + constructor(aesirx, joomla_api_url, joomla_bearer_token, limit = 20) { + this.limit = limit; + this.joomla_bearer_token = joomla_bearer_token; + this.joomla_api_url = joomla_api_url; + this.aesirx = aesirx; + } + async run(url, params, done) { + let offset = 0; + let loop = true; + + while (loop) { + const options = { + acceptHeader: '*/*', + headers: { + Authorization: 'Bearer ' + this.joomla_bearer_token, + }, + additionalHeaders: { + 'Content-Type': 'application/json; charset=utf-8', + }, + params: { + ...{ + 'page[limit]': this.limit, + 'page[offset]': offset, + 'list[ordering]': 'id', + 'list[direction]': 'asc', + }, + ...params, + }, + }; + const restRes = await axios.get(this.joomla_api_url + url, options); + if (restRes.status != 200 || !restRes?.data?.data) { + break; + } + + // Probably less heavier for frontend executions + // https://gist.github.com/joeytwiddle/37d2085425c049629b80956d3c618971#process-each-player-in-serial-using-arrayprototypereduce + await restRes.data.data.reduce(async (prev, item) => { + // Wait for the previous item to finish processing + await prev; + // Process this item + await done(item); + }, Promise.resolve()); + + offset += this.limit; + + if (!restRes?.data?.links?.next) { + break; + } + } + } + async runCategories() { + await this.run( + '/api/index.php/v1/content/categories', + { + 'list[ordering]': 'a.lft', + 'list[direction]': 'asc', + }, + async (item) => { + const resource = { + title: item.attributes.title, + remote_key: item.id, + }; + + if (item.attributes.parent_id != 1) { + resource.parent_id = await this.aesirx.getRemoteEntityId( + item.attributes.parent_id, + Entity.Category + ); + } + await this.aesirx.create(Entity.Category, resource); + } + ); + } + + async runContents() { + const options = { + acceptHeader: '*/*', + headers: { + Authorization: 'Bearer ' + this.joomla_bearer_token, + }, + }; + + await this.run( + '/api/index.php/v1/content/articles', + { + 'list[ordering]': 'a.id', + 'list[direction]': 'asc', + }, + async (item) => { + const resource = { + title: item.attributes.title, + metaverse_content: item.attributes.text, + remote_key: item.id, + + // Empty tags and assign again later + aesirx_tags: [], + }; + + resource.categories = [ + await this.aesirx.getRemoteEntityId(item.relationships.category.data.id, Entity.Category), + ]; + + const restRes = await axios.get( + this.joomla_api_url + '/api/index.php/v1/content/articles/' + item.id, + options + ); + if (restRes.status != 200 || !restRes.data) { + console.log('Joomla dont have contents'); + } else { + const remoteId = await this.aesirx.create(Entity.Item, resource); + + for (const idx in restRes.data.data.attributes.tags) { + await this.aesirx.addTag({ + content_id: remoteId, + tag_id: await this.aesirx.getRemoteEntityId(idx, Entity.Tag), + }); + } + } + } + ); + } + + async runTags() { + await this.run( + '/api/index.php/v1/tags', + { + 'list[ordering]': 'a.lft', + 'list[direction]': 'asc', + }, + async (item) => { + const resource = { + title: item.attributes.title, + description: item.attributes.description, + remote_key: item.id, + }; + + if (item.attributes.parent_id != 1) { + resource.parent_id = await this.aesirx.getRemoteEntityId( + item.attributes.parent_id, + Entity.Tag + ); + } + await this.aesirx.create(Entity.Tag, resource); + } + ); + } + + async runAll() { + await this.runCategories(); + await this.runTags(); + await this.runContents(); + } +} +export { Joomla, JOOMLA_FIELDS }; diff --git a/src/containers/MigratorPage/MigratorUtils/wordpress.js b/src/containers/MigratorPage/MigratorUtils/wordpress.js new file mode 100644 index 0000000..fe4fd42 --- /dev/null +++ b/src/containers/MigratorPage/MigratorUtils/wordpress.js @@ -0,0 +1,159 @@ +import axios from 'axios'; +import { Entity } from './aesirx'; + +const WORDPRESS_FIELDS = { + URL: 'wordpress_api_url', +}; +class Wordpress { + wordpress_api_url; + limit = 20; + aesirx; + + constructor(aesirx, wordpress_api_url, limit = 20) { + this.limit = limit; + this.wordpress_api_url = wordpress_api_url; + this.aesirx = aesirx; + } + + async run(url, params, done) { + let page = 1; + let loop = true; + while (loop) { + const options = { + acceptHeader: '*/*', + additionalHeaders: { + 'Content-Type': 'application/json; charset=utf-8', + }, + params: { + ...{ + per_page: this.limit, + page: page, + order: 'asc', + orderby: 'id', + }, + ...params, + }, + }; + const restRes = await axios.get(this.wordpress_api_url + url, options); + if (restRes.status != 200 || !restRes?.data) { + break; + } + + if (restRes.data.length == 0) { + break; + } + + // Probably less heavier for frontend executions + // https://gist.github.com/joeytwiddle/37d2085425c049629b80956d3c618971#process-each-player-in-serial-using-arrayprototypereduce + await restRes.data.reduce(async (prev, item) => { + // Wait for the previous item to finish processing + await prev; + // Process this item + await done(item); + }, Promise.resolve()); + + if (restRes.data.length < this.limit) { + break; + } + + page += 1; + } + } + + async runCategories() { + let parents = [0]; + let loop = true; + while (loop) { + if (parents.length === 0) { + break; + } + + // @ts-ignore + let parent = parents.pop(); + + await this.run( + '/wp-json/wp/v2/categories', + { + parent: parent, + }, + async (item) => { + const resource = { + title: item.name, + remote_key: item.id, + description: item.description, + }; + + if (item.parent != 0) { + resource.parent_id = await this.aesirx.getRemoteEntityId(item.parent, Entity.Category); + } + + await this.aesirx.create(Entity.Category, resource); + parents.push(item.id); + } + ); + } + } + + async runPosts() { + await this.run('/wp-json/wp/v2/posts', {}, async (item) => { + const resource = { + title: item.title.rendered, + metaverse_content: item.content.rendered, + excerpt: item.excerpt.rendered, + remote_key: item.id, + + // Empty tags and assign again later + aesirx_tags: [], + }; + + if (item.categories.length) { + resource.categories = []; + + for (const id of item.categories) { + resource.categories.push(await this.aesirx.getRemoteEntityId(id, Entity.Category)); + } + } + + const remoteId = await this.aesirx.create(Entity.Item, resource); + + for (const idx of item.tags) { + await this.aesirx.addTag({ + content_id: remoteId, + tag_id: await this.aesirx.getRemoteEntityId(idx, Entity.Tag), + }); + } + }); + } + + async runPages() { + await this.run('/wp-json/wp/v2/pages', {}, async (item) => { + const resource = { + title: item.title.rendered, + metaverse_content: item.content.rendered, + excerpt: item.excerpt.rendered, + remote_key: item.id, + }; + await this.aesirx.create(Entity.Item, resource); + }); + } + + async runTags() { + await this.run('/wp-json/wp/v2/tags', {}, async (item) => { + const resource = { + title: item.name, + description: item.description, + remote_key: item.id, + }; + await this.aesirx.create(Entity.Tag, resource); + }); + } + + async runAll() { + await this.runCategories(); + await this.runTags(); + await this.runPosts(); + await this.runPages(); + } +} + +export { Wordpress, WORDPRESS_FIELDS }; diff --git a/src/containers/MigratorPage/MigratorViewModels/JoomlaFormViewModel.js b/src/containers/MigratorPage/MigratorViewModels/JoomlaFormViewModel.js new file mode 100644 index 0000000..38ea6dc --- /dev/null +++ b/src/containers/MigratorPage/MigratorViewModels/JoomlaFormViewModel.js @@ -0,0 +1,36 @@ +/* + * @copyright Copyright (C) 2022 AesirX. All rights reserved. + * @license GNU General Public License version 3, see LICENSE. + */ + +import { makeAutoObservable } from 'mobx'; +import { notify } from 'components/Toast'; + +class JoomlaFormViewModel { + migratorStore = null; + type = 'JOOMLA'; + formPropsData = {}; + + constructor(migratorStore) { + makeAutoObservable(this); + this.migratorStore = migratorStore; + } + + migratorData = async () => { + return await this.migratorStore.migratorData( + this.type, + this.formPropsData, + this.callbackOnSucessHandler, + this.callbackOnErrorHandler + ); + }; + callbackOnSucessHandler = () => { + this.processPercent == 100; + notify('Migrator data successfully !'); + }; + callbackOnErrorHandler = () => { + notify('Something when wrong !', 'error'); + }; +} + +export default JoomlaFormViewModel; diff --git a/src/containers/MigratorPage/MigratorViewModels/MigratorViewModel.js b/src/containers/MigratorPage/MigratorViewModels/MigratorViewModel.js new file mode 100644 index 0000000..079c239 --- /dev/null +++ b/src/containers/MigratorPage/MigratorViewModels/MigratorViewModel.js @@ -0,0 +1,22 @@ +/* + * @copyright Copyright (C) 2022 AesirX. All rights reserved. + * @license GNU General Public License version 3, see LICENSE. + */ +import JoomlaFormViewModel from './JoomlaFormViewModel'; +import WordPressFormViewModel from './WordPressFormViewModel'; + +class MigratorViewModel { + joomlaFormViewModel = null; + wordpressFormViewModel = null; + + constructor(migratorStore) { + if (migratorStore) { + this.joomlaFormViewModel = new JoomlaFormViewModel(migratorStore); + this.wordpressFormViewModel = new WordPressFormViewModel(migratorStore); + } + } + getJoomlaFormViewModel = () => this.joomlaFormViewModel; + getWordPressFormViewModel = () => this.wordpressFormViewModel; +} + +export default MigratorViewModel; diff --git a/src/containers/MigratorPage/MigratorViewModels/MigratorViewModelContextProvider.js b/src/containers/MigratorPage/MigratorViewModels/MigratorViewModelContextProvider.js new file mode 100644 index 0000000..bfaf3aa --- /dev/null +++ b/src/containers/MigratorPage/MigratorViewModels/MigratorViewModelContextProvider.js @@ -0,0 +1,19 @@ +import React from 'react'; + +const MigratorViewModelContext = React.createContext(); + +export const MigratorViewModelContextProvider = ({ children, viewModel }) => { + return ( + + {children} + + ); +}; + +/* Hook to use store in any functional component */ +export const useMigratorViewModel = () => React.useContext(MigratorViewModelContext); + +/* HOC to inject store to any functional or class component */ +export const withMigratorViewModel = (Component) => (props) => { + return ; +}; diff --git a/src/containers/MigratorPage/MigratorViewModels/WordPressFormViewModel.js b/src/containers/MigratorPage/MigratorViewModels/WordPressFormViewModel.js new file mode 100644 index 0000000..29704a5 --- /dev/null +++ b/src/containers/MigratorPage/MigratorViewModels/WordPressFormViewModel.js @@ -0,0 +1,33 @@ +/* + * @copyright Copyright (C) 2022 AesirX. All rights reserved. + * @license GNU General Public License version 3, see LICENSE. + */ + +import { notify } from 'components/Toast'; +import { makeAutoObservable } from 'mobx'; + +class WordPressFormViewModel { + migratorStore = null; + type = 'WORDPRESS'; + formPropsData = {}; + constructor(migratorStore) { + makeAutoObservable(this); + this.migratorStore = migratorStore; + } + migratorData = async () => { + return await this.migratorStore.migratorData( + this.type, + this.formPropsData, + this.callbackOnSucessHandler, + this.callbackOnErrorHandler + ); + }; + callbackOnSucessHandler = () => { + notify('Migrator data successfully !'); + }; + callbackOnErrorHandler = () => { + notify('Something when wrong !', 'error'); + }; +} + +export default WordPressFormViewModel; diff --git a/src/containers/MigratorPage/index.jsx b/src/containers/MigratorPage/index.jsx new file mode 100644 index 0000000..350e7f3 --- /dev/null +++ b/src/containers/MigratorPage/index.jsx @@ -0,0 +1,61 @@ +import React, { Component } from 'react'; +import { Route } from 'react-router-dom'; +import StepWizard from 'react-step-wizard'; +import JoomlaForm from './MigratorForm/JoomlaForm'; +import WordPressForm from './MigratorForm/WordPressForm'; +import MergeDataPage from './MigratorForm/MergeDataPage'; +import { observer } from 'mobx-react'; + +import MigratorStore from './MigratorStore/MigratorStore'; +import MigratorViewModel from './MigratorViewModels/MigratorViewModel'; +import { MigratorViewModelContextProvider } from './MigratorViewModels/MigratorViewModelContextProvider'; + +const migratorStore = new MigratorStore(); +const migratorViewModel = new MigratorViewModel(migratorStore); +const MigratorPage = observer( + class MigratorPage extends Component { + constructor(props) { + super(props); + this.match = props.match; + } + render() { + return ( + +
+ + + + + + + + + + + + +
+
+ ); + } + } +); +export default MigratorPage; diff --git a/src/routes/routes.js b/src/routes/routes.js index 24ed887..ab61dc8 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -7,6 +7,7 @@ const ItemsPage = lazy(() => import('../containers/ItemsPage')); const ProfilePage = lazy(() => import('../containers/ProfilePage')); const CategoriesPage = lazy(() => import('../containers/Categories')); const DamPage = lazy(() => import('../containers/DamPage')); +const MigratorPage = lazy(() => import('../containers/MigratorPage')); const ContentPage = lazy(() => import('../containers/ContentPage')); const SettingPage = lazy(() => import('../containers/ItemsPage')); const HelpCenterPage = lazy(() => import('../containers/ItemsPage')); @@ -38,6 +39,11 @@ const mainRoutes = [ exact: true, main: ({ match }) => , }, + { + path: ['/migrator/joomla', '/migrator/wordpress'], + exact: true, + main: ({ match }) => , + }, { path: '/categories', exact: true, diff --git a/src/translations/dk/common.json b/src/translations/dk/common.json index 459fb63..833e768 100644 --- a/src/translations/dk/common.json +++ b/src/translations/dk/common.json @@ -105,5 +105,10 @@ "txt_error": "Fejl", "txt_successfuly":"Succesfuldt", "txt_unsuccess": "Forgæves", - "txt_delete_success": "Slet med succes" + "txt_delete_success": "Slet med succes", + "txt_migrator": "Migrator", + "txt_migrator_wordpress": "Migrator WordPress Data", + "txt_migrator_joomla": "Migrator Joomla Data", + "txt_next_step": "Næste skridt", + "txt_previous_step": "Forrige trin" } \ No newline at end of file diff --git a/src/translations/en/common.json b/src/translations/en/common.json index 1b1f495..b839600 100644 --- a/src/translations/en/common.json +++ b/src/translations/en/common.json @@ -105,5 +105,10 @@ "txt_error": "Error", "txt_successfuly":"Successfully", "txt_unsuccess": "Unsuccessfully", - "txt_delete_success": "Delete Successfully" + "txt_delete_success": "Delete Successfully", + "txt_migrator": "Migrator", + "txt_migrator_wordpress": "Migrator WordPress Data", + "txt_migrator_joomla": "Migrator Joomla Data", + "txt_next_step": "Next Step", + "txt_previous_step": "Previous Step" } \ No newline at end of file diff --git a/src/translations/es/common.json b/src/translations/es/common.json index 032a5d7..43b6594 100644 --- a/src/translations/es/common.json +++ b/src/translations/es/common.json @@ -105,5 +105,11 @@ "txt_error": "Error", "txt_successfuly":"ErrorCon éxito", "txt_unsuccess": "sin éxito", - "txt_delete_success": "Eliminar con éxito" + "txt_delete_success": "Eliminar con éxito", + "txt_migrator": "Migrator", + "txt_migrator_wordpress": "Migrator de datos de WordPress", + "txt_migrator_joomla": "Migrator de datos de Joomla", + "txt_next_step": "Próximo paso", + "txt_previous_step": "Paso anterior" + } \ No newline at end of file diff --git a/src/translations/fr/common.json b/src/translations/fr/common.json index 33e15ce..c46cc82 100644 --- a/src/translations/fr/common.json +++ b/src/translations/fr/common.json @@ -105,5 +105,11 @@ "txt_error": "Erreur", "txt_successfuly":"Avec succès", "txt_unsuccess": "Sans succès", - "txt_delete_success": "Supprimer avec succès" + "txt_delete_success": "Supprimer avec succès", + "txt_migrator": "Migrateur", + "txt_migrator_wordpress": "Migrateur de données WordPress", + "txt_migrator_joomla": "Migration de données Joomla", + "txt_next_step": "L'étape suivante", + "txt_previous_step": "Étape précédente" + } \ No newline at end of file diff --git a/src/translations/hr/common.json b/src/translations/hr/common.json index e694685..8d8c3d4 100644 --- a/src/translations/hr/common.json +++ b/src/translations/hr/common.json @@ -105,5 +105,10 @@ "txt_error": "Greška", "txt_successfuly":"Uspješno", "txt_unsuccess": "Neuspješno", - "txt_delete_success": "Uspješno brisanje" + "txt_delete_success": "Uspješno brisanje", + "txt_migrator": "Migrator", + "txt_migrator_wordpress": "Migrator WordPress podataka", + "txt_migrator_joomla": "Migrator Joomla podataka", + "txt_next_step": "Sljedeći korak", + "txt_previous_step": "Prethodni korak" } \ No newline at end of file diff --git a/src/translations/th/common.json b/src/translations/th/common.json index 942c735..0142a61 100644 --- a/src/translations/th/common.json +++ b/src/translations/th/common.json @@ -105,5 +105,10 @@ "txt_error": "ข้อผิดพลาด", "txt_successfuly":"เรียบร้อยแล้ว", "txt_unsuccess": "ไม่สำเร็จ", - "txt_delete_success": "ลบสำเร็จ" + "txt_delete_success": "ลบสำเร็จ", + "txt_migrator": "ผู้อพยพ", + "txt_migrator_wordpress": "การย้ายข้อมูล WordPress", + "txt_migrator_joomla": "การย้ายข้อมูล Joomla", + "txt_next_step": "ขั้นตอนต่อไป", + "txt_previous_step": "ขั้นตอนก่อนหน้า" } \ No newline at end of file diff --git a/src/translations/ua/common.json b/src/translations/ua/common.json index 7d357a6..70f47ab 100644 --- a/src/translations/ua/common.json +++ b/src/translations/ua/common.json @@ -105,5 +105,10 @@ "txt_error": "Помилка", "txt_successfuly":"Успішно", "txt_unsuccess": "Безуспішно", - "txt_delete_success": "Видалити успішно" + "txt_delete_success": "Видалити успішно", + "txt_migrator": "Переселенець", + "txt_migrator_wordpress": "Мігратор даних WordPress", + "txt_migrator_joomla": "Мігратор даних Joomla", + "txt_next_step": "Наступний крок", + "txt_previous_step": "Попередній крок" } \ No newline at end of file diff --git a/src/translations/vi/common.json b/src/translations/vi/common.json index 682a2f3..4f54a30 100644 --- a/src/translations/vi/common.json +++ b/src/translations/vi/common.json @@ -104,5 +104,10 @@ "txt_error": "Lỗi", "txt_successfuly":"Thành công", "txt_unsuccess": "Không thành công", - "txt_delete_success": "Xóa thành công" + "txt_delete_success": "Xóa thành công", + "txt_migrator": "Chuyển đổi", + "txt_migrator_wordpress": "Chuyển đổi dữ liệu WordPress", + "txt_migrator_joomla": "Chuyển đổi dữ liệu Joomla", + "txt_next_step": "Bước tiếp theo", + "txt_previous_step": "Bước trước đó" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 4e741f1..aa86b68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11479,7 +11479,7 @@ react-spinners@^0.13.6: resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.13.8.tgz#5262571be0f745d86bbd49a1e6b49f9f9cb19acc" integrity sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA== -react-step-wizard@^5.3.5: +react-step-wizard@^5.3.11, react-step-wizard@^5.3.5: version "5.3.11" resolved "https://registry.yarnpkg.com/react-step-wizard/-/react-step-wizard-5.3.11.tgz#a52b46db772c0340dd6f45f93716d2afcf2196e2" integrity sha512-TD3ocUdt4XWvisTNEiATh+cFuh1RK0LgvYqOResTIhLtFmdWnXzFVaNIZJ3qzW5Bm6yeotzZ4KAmRjmsqBXnWQ==