react-cms
Version:
For personal use. Not production.
937 lines (628 loc) • 16.9 kB
JavaScript
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
buildSchema,
graphql,
GraphQLSchema,
} from 'graphql';
export default class App extends Component{
static propTypes = {
defaultQuery: PropTypes.string.isRequired,
rootResolver: PropTypes.func.isRequired,
RootType: PropTypes.object.isRequired,
Mutation: PropTypes.object,
rootDirectives: PropTypes.array,
};
static contextTypes = {
};
constructor(props){
super(props);
// const orm = new ORM();
// const schema = this.getSchema();
this.state = {
// schema,
developMode: false,
};
Object.assign(this.state, this.createStores());
this.loadApiData = ::this.loadApiData;
this.saveItem = ::this.saveItem;
this.saveCommentItem = ::this.saveCommentItem;
}
static childContextTypes = {
inited: PropTypes.bool,
document: PropTypes.object,
user: PropTypes.object,
schema: PropTypes.object,
defaultQuery: PropTypes.string,
localQuery: PropTypes.func,
remoteQuery: PropTypes.func,
request: PropTypes.func,
apiRequest: PropTypes.func,
updateItem: PropTypes.func,
saveItem: PropTypes.func,
connector_url: PropTypes.string,
userActions: PropTypes.object,
documentActions: PropTypes.object,
};
getChildContext() {
let {
document,
user,
connector_url,
userActions,
documentActions,
defaultQuery,
} = this.props;
let {
inited,
schema,
} = this.state;
let context = {
inited,
document,
user,
schema,
defaultQuery,
connector_url,
userActions,
documentActions,
localQuery: ::this.localQuery,
remoteQuery: ::this.remoteQuery,
request: ::this.request,
apiRequest: ::this.apiRequest,
updateItem: ::this.updateItem,
saveItem: ::this.saveItem,
};
return context;
}
componentWillMount(){
this.rootResolver = this.getRootResolver();
const schema = this.getSchema();
Object.assign(this.state, {
schema,
});
this.loadApiData();
super.componentWillMount && super.componentWillMount();
}
getRootResolver(){
const {
rootResolver,
} = this.props;
return rootResolver;
}
getSchema(){
const {
RootType,
Mutation,
rootDirectives,
} = this.props;
return new GraphQLSchema({
query: RootType,
mutation: Mutation,
directives: rootDirectives,
});
}
createStores(){
}
async loadApiData(){
//
const {
developMode,
} = this.state;
const {
document,
} = this.props;
let {
apiData,
// citiesData,
resourceState,
} = document;
const {
state: initialState,
} = resourceState || {};
const {
cities,
} = initialState || {};
if(typeof window !== "undefined" && developMode){
await this.remoteQuery({
operationName: "apiData",
variables: {
limit: 0,
apiDataGetCurrentUser: true,
},
})
.then(r => {
// document.apiData = apiData = r && r.object || null;
apiData = r && r.data || null;
});
}
// if(!apiData){
// return;
// }
apiData = apiData || {};
Object.assign(apiData, {
cities,
});
this.initData(apiData);
let user;
let {
user: currentUser,
} = apiData || {};
if(currentUser){
this.props.userActions.GetOwnDataSuccess(currentUser);
user = currentUser;
}
this.initUser(user);
return;
}
updateItem(item, data, store, silent){
if(!item){
console.error("Не указан объект");
return false;
}
// if(!store){
// console.error("Не указано хранилище");
// return false;
// }
let newState = {};
Object.assign(newState, data);
if(!silent){
let _isDirty = {};
item._isDirty && Object.assign(_isDirty, item._isDirty);
Object.assign(_isDirty, newState);
newState._isDirty = _isDirty;
}
if(store){
store.getDispatcher().dispatch(store.actions['UPDATE'], item, newState);
}
else{
Object.assign(item, newState);
}
return item;
}
saveItem = async (store, item, connector_path, callback) => {
let {
connector_url,
documentActions: {
addInformerMessage,
},
} = this.props;
//
// if(!store){
// console.error("Не было получено хранилище");
// return;
// }
if(
!item
|| item._sending === true
){
return;
}
let {
id,
_isDirty,
} = item;
if(!_isDirty){
addInformerMessage({
text: "Нечего сохранять",
autohide: 4000,
});
return;
}
item._sending = true;
var action = id && id > 0 ? 'update' : 'create';
var options = options || {};
var body = {};
body['id'] = id;;
for(var i in _isDirty){
var value = _isDirty[i];
if(value === undefined){
continue;
}
// Пропускаем свойства-объекты
// if(
// typeof value === "object"
// && !Array.isArray(value)
// && value !== null
// ){
// continue;
// }
// Пропускаем временные свойства
if(/^\_/.test(i)){
continue;
}
//
body[i] = value;
};
let result = await this.request(connector_path, false, `${connector_path}${action}`, body, {
callback: (data, errors) => {
//
// self.setState({items: data.object});
let newObject = data.object || {};
var errors = {};
if(data.success === true){
Object.assign(newObject, {
_isDirty: undefined,
});
addInformerMessage({
type: "success",
text: data.message || "Объект успешно сохранен",
autohide: 4000,
});
}
else{
if(data.data && data.data.length){
data.data.map(function(error){
var value = error.msg;
if(value && value != ''){
errors[error.id] = value;
}
});
}
errors.error_message = data.message;
// addInformerMessage &&
// addInformerMessage({
// text: data.message || "Ошибка выполнения запроса",
// autohide: 4000,
// });
// this.forceUpdate();
}
// newState.errors = this.state.errors || {};
// newState.errors[item.id || 0] = errors;
// item._errors = errors;
callback && callback(data, errors);
// if(callback){
// }
// this.forceUpdate();
// item._sending = false;
//
// this.forceUpdate();
// TODO store.commit
Object.assign(newObject, {
_errors: errors,
_sending: false,
});
if(store){
let dispatcher = store.getDispatcher();
dispatcher.dispatch(store.actions["SAVE"], item, newObject);
}
else{
Object.assign(item, newObject);
}
this.forceUpdate();
}
})
.then(r => {
return r;
})
.catch(e => {
item._sending = false;
throw(e);
});
// return;
// fetch(this.props.connector_url + '?pub_action='+ connector_path + action,{
// credentials: 'same-origin',
// method: options.method || "POST",
// body: body,
// })
// .then(function (response) {
// return response.json()
// })
// .then((data) => {
// })
// .catch((error) => {
// console.error('Request failed', error, this);
// item && (item._sending = false);
// addInformerMessage && addInformerMessage({
// text: "Ошибка выполнения запроса",
// autohide: 4000,
// });
// }
// );
this.forceUpdate();
return result;
}
async saveCommentItem (item) {
//
// let {
// CommentsStore: store,
// } = this.state;
// item = item && store.getState().find(n => n.id === item.id);
if(!item){
throw(new Error("Не был получен объект комментария"));
}
// let {
// id: itemId,
// } = item;
// const callback = (data, errors) => {
// if(data.success && data.object){
// // const {
// // id,
// // uri,
// // } = data.object;
// // if(id !== itemId){
// // // const uri = `/topics/${id}/`;
// // browserHistory.replace(uri);
// // }
// this.reloadApiData();
// return;
// }
// }
let result = await this.saveItem(null, item, 'comment/');
await this.reloadApiData();
return result;
}
updateCurrentUser = (item, data, silent) => {
// item = item && UsersStore.getState().find(n => n.id === item.id);
// let {
// user: {
// user: item,
// },
// } = this.props;
const currentUser = this.getCurrentUser();
if(!currentUser){
throw(new Error("Не был получен объект пользователя 2"));
}
return this.updateItem(currentUser, data, null, silent);
}
getCurrentUser = () => {
let {
user: {
user: currentUser,
},
} = this.props;
return currentUser;
}
saveCurrentUser = (item) => {
//
// let {
// user: {
// user: item,
// },
// } = this.props;
// let {
// UsersStore,
// } = this.state;
// item = item && UsersStore.getState().find(n => n.id === item.id);
const currentUser = this.getCurrentUser();
if(!currentUser){
throw(new Error("Не был получен объект пользователя"));
}
// let {
// id: itemId,
// } = item;
// const callback = (data, errors) => {
// if(data.success && data.object){
// // const {
// // id,
// // uri,
// // } = data.object;
// // if(id !== itemId){
// // // const uri = `/topics/${id}/`;
// // browserHistory.replace(uri);
// // }
// this.reloadApiData();
// return;
// }
// }
return this.saveItem(null, currentUser, 'user/own_profile/');
}
localQuery = (graphQLParams) => {
const {
schema,
} = this.state;
const {
defaultQuery,
} = this.props;
// var schema = this._getSchema();
const rootResolver = this.getRootResolver();
const {
query,
operationName,
variables,
} = graphQLParams;
// return new Promise(resolve => resolve([{}]));
return new Promise((resolve, reject) => {
// class user {
// constructor(props){
// Object.assign(this, props);
// }
// }
const {
ContactsStore,
PlacesStore,
PlaceContactsStore,
} = this.state;
graphql({
schema,
operationName,
source: query || defaultQuery,
// rootValue: {
// contacts: ContactsStore.getState(),
// places: PlacesStore.getState(),
// contact_places: PlaceContactsStore.getState(),
// },
variableValues: variables || undefined,
// contextValue: this.getChildContext(),
contextValue: this,
fieldResolver: rootResolver,
}).then((result) => {
let {
errors,
} = result;
if(errors && errors.length){
reject(result);
// let {
// message,
// ...other
// } = errors[0];
// console.error("localQuery error", result);
// return reject(message, {...other});
}
resolve(result);
})
.catch(e => {
// console.error(e);
reject(e);
});
});
}
remoteQuery = (graphQLParams) => {
if(typeof graphQLParams !== 'object'){
graphQLParams = {
query: graphQLParams,
};
}
const {
query,
operationName,
variables,
} = graphQLParams;
return new Promise((resolve, reject) => {
this.apiRequest(null, true, 'graphql', {
query,
operationName,
variables,
},{
callback: (data, errors) => {
if(data.success){
return resolve(data);
}
else{
return reject(data);
}
},
});
});
}
request = (context, allowMultiRequest, connector_path, params, options) => {
if(allowMultiRequest === undefined){
allowMultiRequest = false;
}
if(this.state[context] === undefined){
this.state[context] = {};
}
if(!allowMultiRequest && this.state[context].inRequest === true){
return;
}
let {
connector_url: default_connector_url,
user,
} = this.props;
params = params || {}
Object.assign(params, {
token: user.token,
});
var newState = {};
newState[context] = this.state[context];
newState[context].inRequest = true;
this.setState(newState);
options = options || {};
let {
connector_url,
callback: callback2,
} = options;
connector_url = connector_url || default_connector_url;
let callback = (data, errors) => {
var newState = {};
newState[context] = this.state[context];
newState[context].inRequest = false;
newState[context].errors = errors;
this.setState(newState, () => {
callback2 && callback2(data, errors);
});
}
options.callback = callback;
return this._request(connector_url, connector_path, params, options);
}
_request = (connector_url, connector_path, params, options) => {
let defaultOptions = {
showErrorMessage: true,
callback: null,
method: 'POST',
};
const {
documentActions,
} = this.props;
options = options || {};
options = Object.assign(defaultOptions, options);
let showErrorMessage = options.showErrorMessage;
let callback = options.callback;
let method = options.method;
var data = {
};
if(params){
Object.assign(data, params);
}
return new Promise((resolve, reject) => {
const request = fetch(connector_url +'?pub_action=' + connector_path,{
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: method,
// body: body,
body: JSON.stringify(data),
})
.then(function (response) {
return response.json()
})
.then( (data) => {
let message;
let errors = {};
if(data.success){
}
else{
// console.error('Request result', data);
if(data.data && data.data.length){
data.data.map(function(error){
if(error.msg != ''){
errors[error.id] = error.msg;
}
}, this);
}
message = data.message || "Ошибка выполнения запроса";
showErrorMessage && documentActions.addInformerMessage({
text: message,
autohide: 4000,
});
}
if(callback){
callback(data, errors);
}
this.forceUpdate();
if(data.success){
resolve(data);
}
else{
reject({
message,
data,
errors,
});
}
return;
})
.catch((error) => {
console.error('Request failed', error);
showErrorMessage && documentActions.addInformerMessage({
text: "Ошибка выполнения запроса",
autohide: 4000,
});
if(callback){
callback(data, {});
}
reject(error);
}
);
this.forceUpdate();
});
}
apiRequest = (context, allowMultiRequest, connector_path, params, options) => {
options = Object.assign({
connector_url: '/api/',
}, options || {});
return this.request(context, allowMultiRequest, connector_path, params, options);
}
}