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==