Create component to add application

4.x.x
Jayasanka 6 years ago
parent 05d2327205
commit a3a485dd8e

@ -10,12 +10,12 @@ const {Option} = Select;
const {Title, Text} = Typography; const {Title, Text} = Typography;
const Search = Input.Search; const Search = Input.Search;
// connecting state.apps with the component // connecting state.apps with the component
const mapStateToProps = state => { // const mapStateToProps = state => {
return {apps: state.apps} // return {apps: state.apps}
}; // };
class ConnectedListApps extends React.Component { class ListApps extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -70,6 +70,6 @@ class ConnectedListApps extends React.Component {
} }
} }
const ListApps = connect(mapStateToProps, {getApps})(ConnectedListApps); // const ListApps = connect(mapStateToProps, {getApps})(ConnectedListApps);
export default ListApps; export default ListApps;

@ -0,0 +1,485 @@
import React from "react";
import "antd/dist/antd.css";
import {
PageHeader,
Typography,
Card,
Steps,
Button,
message,
Row,
Col,
Tag,
Tooltip,
Input,
Icon,
Select,
Switch,
Form,
Upload,
Divider, notification
} from "antd";
import IconImage from "./IconImg";
import UploadScreenshots from "./UploadScreenshots";
import axios from "axios";
import config from "../../../public/conf/config.json";
const Paragraph = Typography;
const Dragger = Upload.Dragger;
const props = {
name: 'file',
multiple: false,
action: '//jsonplaceholder.typicode.com/posts/',
onChange(info) {
const status = info.file.status;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} file uploaded successfully.`);
} else if (status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
};
//
// const steps = [{
// title: 'First',
// content: Step1
// }, {
// title: 'Second',
// content: Step2,
// }, {
// title: 'Last',
// content: Step3,
// }];
const {Option} = Select;
const {TextArea} = Input;
const InputGroup = Input.Group;
const formItemLayout = {
labelCol: {
span: 4,
},
wrapperCol: {
span: 20,
},
};
class AddNewAppFormComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 0,
categories: [],
tags: [],
icons: [],
screenshots: []
};
}
componentDidMount() {
this.getCategories();
this.getTags();
}
getCategories = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/categories",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let categories = JSON.parse(res.data.data);
this.setState({
categories: categories,
loading: false
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
getTags = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/tags",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let tags = JSON.parse(res.data.data);
this.setState({
tags: tags,
loading: false,
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
handleCategoryChange = (value) => {
console.log(`selected ${value}`);
};
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
const {name, description, appCategories, tags, deviceType, price, isSharedWithAllTenants, binaryFile, icon, screenshots} = values;
const payload = {
binaryFile,
icon,
screenshot1: screenshots[0],
screenshot2: screenshots[1],
screenshot3: screenshots[2],
application:{
name,
description,
appCategories,
subType: (price === undefined || parseInt(price) === 0) ? "FREE" : "PAID",
tags,
unrestrictedRoles: [],
deviceType,
applicationReleaseWrappers: {
description,
price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants,
metaData: "string",
supportedOsVersions: "4.0"
}
}
};
axios.post(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/ent-app",
payload,
{
headers: {
'X-Platform': config.serverConfig.platform,
'Content-Type': 'multipart/mixed'
}
}).then(res => {
if (res.status === 201) {
this.setState({
loading: false,
});
notification["success"]({
message: "Done!",
description:
"New app was added successfully",
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
console.log(payload);
}
});
};
normFile = e => {
console.log('Upload event:', e);
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
};
handleIconChange = ({fileList}) => this.setState({icons: fileList});
handleScreenshotChange = ({fileList}) => this.setState({screenshots: fileList});
validateIcon = (rule, value, callback) => {
const {icons} = this.state;
if (icons.length !== 1) {
callback("Please select icon file");
}
callback();
};
render() {
const {categories, tags, icons, screenshots} = this.state;
const {getFieldDecorator} = this.props.form;
return (
<div>
<Row>
<Col span={20} offset={2}>
<Card>
<Form labelAlign="left" layout="horizontal"
hideRequiredMark
onSubmit={this.handleSubmit}>
<Row>
<Col span={12}>
<div>
{/*device type*/}
<Form.Item {...formItemLayout} label="Device Type">
{getFieldDecorator('deviceType', {
rules: [{
required: true,
message: 'Please select device type'
},
{
validator: this.validateIcon
}],
})(
<Select placeholder="select device type">
<Option key="android">Android</Option>
<Option key="ios">iOS</Option>
</Select>
)}
</Form.Item>
{/*app name*/}
<Form.Item {...formItemLayout} label="App Name">
{getFieldDecorator('name', {
rules: [{
required: true,
message: 'Please input a name'
}],
})(
<Input placeholder="ex: Lorem App"/>
)}
</Form.Item>
{/*description*/}
<Form.Item {...formItemLayout} label="Description">
{getFieldDecorator('description', {
rules: [{
required: true,
message: 'Please enter a description'
}],
})(
<TextArea placeholder="Enter the description..." rows={7}/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Categories">
{getFieldDecorator('appCategories', {
rules: [{
required: true,
message: 'Please select categories'
}],
})(
<Select
mode="multiple"
style={{width: '100%'}}
placeholder="Select a Category"
onChange={this.handleCategoryChange}
>
{
categories.map(category => {
return (
<Option
key={category.categoryName}>
{category.categoryName}
</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', {
rules: [{
required: false
}],
})(
<Input prefix="$" placeholder="00.00"/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Is Shared?">
{getFieldDecorator('isSharedWithAllTenants', {
rules: [{
required: true,
message: 'Please select'
}],
})(
<Switch checkedChildren={<Icon type="check"/>}
unCheckedChildren={<Icon type="close"/>} defaultChecked/>
)}
</Form.Item>
<Divider/>
<Form.Item {...formItemLayout} label="Tags">
{getFieldDecorator('tags', {
rules: [{
required: true,
message: 'Please select tags'
}],
})(
<Select
mode="tags"
style={{width: '100%'}}
placeholder="Tags"
>
{
tags.map(tag => {
return (
<Option
key={tag.tagName}>
{tag.tagName}
</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Daa">
<InputGroup>
<Row gutter={8}>
<Col span={10}>
<Input placeholder="Key"/>
</Col>
<Col span={12}>
<Input placeholder="value"/>
</Col>
<Col span={2}>
<Button type="dashed" shape="circle" icon="plus"/>
</Col>
</Row>
</InputGroup>
</Form.Item>
<Form.Item wrapperCol={{span: 12, offset: 5}}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</div>
</Col>
<Col span={12} style={{paddingLeft: 20}}>
<Form.Item label="Application">
<div className="dropbox">
{getFieldDecorator('binaryFile', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
required: true,
message: 'Please select tags'
})(
<Upload.Dragger
name="files"
beforeUpload={() => false}
multiple={false}
>
<p className="ant-upload-drag-icon">
<Icon type="inbox"/>
</p>
<p className="ant-upload-text">Click or drag file to this area
to upload</p>
<p className="ant-upload-hint">Support for a single or bulk
upload.</p>
</Upload.Dragger>,
)}
</div>
</Form.Item>
<Row>
<Col span={12}>
<Form.Item label="Icon">
{getFieldDecorator('icon', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
required: true,
message: 'Please select a icon'
})(
<Upload
name="logo"
onChange={this.handleIconChange}
beforeUpload={() => false}
>
{icons.length !== 1 && (
<Button>
<Icon type="upload"/> Click to upload
</Button>
)}
</Upload>,
)}
</Form.Item>
</Col>
</Row>
<Row style={{marginTop: 40}}>
<Col span={24}>
<Form.Item label="Screenshots">
{getFieldDecorator('screenshots', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
required: true,
message: 'Please select a icon'
})(
<Upload
name="logo"
onChange={this.handleScreenshotChange}
beforeUpload={() => false}
>
{screenshots.length < 3 && (
<Button>
<Icon type="upload"/> Click to upload
</Button>
)}
</Upload>,
)}
</Form.Item>
</Col>
</Row>
</Col>
</Row>
</Form>
</Card>
</Col>
</Row>
</div>
);
}
}
const AddNewAppForm = Form.create({name: 'add-new-app'})(AddNewAppFormComponent);
export default AddNewAppForm;

@ -37,7 +37,7 @@ class IconImage extends React.Component {
loading: false, loading: false,
})); }));
} }
} };
render() { render() {
const uploadButton = ( const uploadButton = (

@ -9,8 +9,6 @@ import Release from "./pages/dashboard/apps/release/Release";
import AddNewApp from "./pages/dashboard/add-new-app/AddNewApp"; import AddNewApp from "./pages/dashboard/add-new-app/AddNewApp";
import Mange from "./pages/dashboard/manage/Manage"; import Mange from "./pages/dashboard/manage/Manage";
import './index.css'; import './index.css';
import store from "./js/store/index";
import {Provider} from "react-redux";
const routes = [ const routes = [
@ -20,7 +18,7 @@ const routes = [
component: Login component: Login
}, },
{ {
path: '/publisher/apps', path: '/publisher/',
exact: false, exact: false,
component: Dashboard, component: Dashboard,
routes: [ routes: [
@ -30,21 +28,25 @@ const routes = [
exact: true exact: true
}, },
{ {
path: '/publisher/apps/new-app', path: '/publisher/apps/releases/:uuid',
exact: true,
component: Release
},
{
path: '/publisher/add-new-app/enterprise',
component: AddNewApp, component: AddNewApp,
exact: true exact: true
}, },
{ {
path: '/publisher/apps/releases/:uuid', path: '/publisher/add-new-app/public',
exact: true, component: AddNewApp,
component: Release exact: true
} },
] {
},{ path: '/publisher/add-new-app/web-clip',
path: '/publisher/manage', component: AddNewApp,
exact: false, exact: true
component: Dashboard, },
routes: [
{ {
path: '/publisher/manage', path: '/publisher/manage',
component: Mange, component: Mange,
@ -56,9 +58,7 @@ const routes = [
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <App routes={routes}/>,
<App routes={routes}/>
</Provider>,
document.getElementById('root')); document.getElementById('root'));
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change

@ -1,14 +1,14 @@
import React from "react"; import React from "react";
import {Layout, Menu, Icon} from 'antd'; import {Layout, Menu, Icon} from 'antd';
const {Header, Content, Footer} = Layout;
import Logo from "../../../public/images/logo.svg"; import Logo from "../../../public/images/logo.svg";
import {BrowserRouter,Switch,Link, NavLink} from "react-router-dom"; import {Switch, Link} from "react-router-dom";
import RouteWithSubRoutes from "../../components/RouteWithSubRoutes" import RouteWithSubRoutes from "../../components/RouteWithSubRoutes"
import {Redirect} from 'react-router' import {Redirect} from 'react-router'
import "../../App.css"; import "../../App.css";
const {Header, Content, Footer} = Layout;
const {SubMenu} = Menu;
class Dashboard extends React.Component { class Dashboard extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -32,8 +32,18 @@ class Dashboard extends React.Component {
style={{lineHeight: '64px'}} style={{lineHeight: '64px'}}
> >
<Menu.Item key="1"><Link to="/publisher/apps"><Icon type="appstore"/>Apps</Link></Menu.Item> <Menu.Item key="1"><Link to="/publisher/apps"><Icon type="appstore"/>Apps</Link></Menu.Item>
<Menu.Item key="3"><Link to="/publisher/apps/new-app"><Icon type="upload"/>Add New <SubMenu
App</Link></Menu.Item> title={
<span className="submenu-title-wrapper">
<Icon type="plus"/>
Add New App
</span>
}
>
<Menu.Item key="setting:1"><Link to="/publisher/add-new-app/public">Public APP</Link></Menu.Item>
<Menu.Item key="setting:2"><Link to="/publisher/add-new-app/enterprise">Enterprise APP</Link></Menu.Item>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web Clip</Link></Menu.Item>
</SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon <Menu.Item key="2"><Link to="/publisher/manage"><Icon
type="control"/>Manage</Link></Menu.Item> type="control"/>Manage</Link></Menu.Item>
</Menu> </Menu>
@ -41,7 +51,6 @@ class Dashboard extends React.Component {
</Layout> </Layout>
<Layout> <Layout>
<Content style={{padding: '0 0'}}> <Content style={{padding: '0 0'}}>
<BrowserRouter>
<Switch> <Switch>
<Redirect exact from="/publisher" to="/publisher/apps"/> <Redirect exact from="/publisher" to="/publisher/apps"/>
{this.state.routes.map((route) => ( {this.state.routes.map((route) => (
@ -49,7 +58,6 @@ class Dashboard extends React.Component {
))} ))}
</Switch> </Switch>
</BrowserRouter>
</Content> </Content>
<Footer style={{textAlign: 'center'}}> <Footer style={{textAlign: 'center'}}>

@ -19,29 +19,12 @@ import {
Upload, Upload,
Divider Divider
} from "antd"; } from "antd";
import Step1 from "./Step1"; import axios from "axios";
import Step2 from "./Step2"; import AddNewAppForm from "../../../components/new-app/AddNewAppForm"
import Step3 from "./Step3"; import config from "../../../../public/conf/config.json";
import styles from "./Style.less";
import IconImage from "./IconImg";
import UploadScreenshots from "./UploadScreenshots";
const Paragraph = Typography; const Paragraph = Typography;
const Dragger = Upload.Dragger; const Dragger = Upload.Dragger;
const routes = [
{
path: 'index',
breadcrumbName: 'publisher',
},
{
path: 'first',
breadcrumbName: 'dashboard',
},
{
path: 'second',
breadcrumbName: 'add new app',
},
];
const props = { const props = {
name: 'file', name: 'file',
@ -60,18 +43,17 @@ const props = {
}, },
}; };
const Step = Steps.Step; //
// const steps = [{
const steps = [{ // title: 'First',
title: 'First', // content: Step1
content: Step1 // }, {
}, { // title: 'Second',
title: 'Second', // content: Step2,
content: Step2, // }, {
}, { // title: 'Last',
title: 'Last', // content: Step3,
content: Step3, // }];
}];
const {Option} = Select; const {Option} = Select;
@ -87,95 +69,18 @@ const formItemLayout = {
}, },
}; };
class EditableTagGroup extends React.Component {
state = {
tags: [],
inputVisible: false,
inputValue: '',
};
handleClose = (removedTag) => {
const tags = this.state.tags.filter(tag => tag !== removedTag);
this.setState({tags});
}
showInput = () => {
this.setState({inputVisible: true}, () => this.input.focus());
}
handleInputChange = (e) => {
this.setState({inputValue: e.target.value});
}
handleInputConfirm = () => {
const {inputValue} = this.state;
let {tags} = this.state;
if (inputValue && tags.indexOf(inputValue) === -1) {
tags = [...tags, inputValue];
}
console.log(tags);
this.setState({
tags,
inputVisible: false,
inputValue: '',
});
}
saveInputRef = input => this.input = input
render() {
const {tags, inputVisible, inputValue} = this.state;
return (
<div>
{tags.map((tag, index) => {
const isLongTag = tag.length > 20;
const tagElem = (
<Tag key={tag} closable={index !== 0} onClose={() => this.handleClose(tag)}>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</Tag>
);
return isLongTag ? <Tooltip title={tag} key={tag}>{tagElem}</Tooltip> : tagElem;
})}
{inputVisible && (
<Input
ref={this.saveInputRef}
type="text"
size="small"
style={{width: 78}}
value={inputValue}
onChange={this.handleInputChange}
onBlur={this.handleInputConfirm}
onPressEnter={this.handleInputConfirm}
/>
)}
{!inputVisible && (
<Tag
onClick={this.showInput}
style={{background: '#fff', borderStyle: 'dashed'}}
>
<Icon type="plus"/> New Tag
</Tag>
)}
</div>
);
}
}
class AddNewApp extends React.Component { class AddNewApp extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
current: 0, current: 0,
categories: []
}; };
} }
tags = []; componentDidMount() {
// this.getCategories();
addTag(key, value){
this.tags.push(<Option key={key}>{value}</Option>);
} }
next() { next() {
@ -188,17 +93,44 @@ class AddNewApp extends React.Component {
this.setState({current}); this.setState({current});
} }
getCategories = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/categories",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let categories = JSON.parse(res.data.data);
this.setState({
categories: categories,
loading: false
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
handleCategoryChange = (value) => {
console.log(`selected ${value}`);
};
render() { render() {
const {current} = this.state; const {categories} = this.state;
const Content = steps[current].content;
this.addTag('1','Lorem');
this.addTag('2','Ipsum');
return ( return (
<div> <div>
<PageHeader <PageHeader
title="Add New App" title="Add New App"
breadcrumb={{routes}}
> >
<div className="wrap"> <div className="wrap">
<div className="content"> <div className="content">
@ -209,121 +141,7 @@ class AddNewApp extends React.Component {
</div> </div>
</PageHeader> </PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<Row> <AddNewAppForm/>
<Col span={20} offset={2}>
<Card>
<Row>
<Col span={12}>
<div>
<Form labelAlign="left" layout="horizontal" className={styles.stepForm}
hideRequiredMark>
<Form.Item {...formItemLayout} label="Platform">
<Select placeholder="ex: android">
<Option value="Android">Android</Option>
<Option value="iOS">iOS</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="Type">
<Select value="Enterprise">
<Option value="Enterprise" selected>Enterprise</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="App Name">
<Input placeholder="ex: Lorem App"/>
</Form.Item>
<Form.Item {...formItemLayout} label="Description">
<TextArea placeholder="Enter the description..." rows={7}/>
</Form.Item>
<Form.Item {...formItemLayout} label="Category">
<Select placeholder="Select a category">
<Option value="travel">Travel</Option>
<Option value="entertainment">Entertainment</Option>
</Select>
</Form.Item>
<Form.Item {...formItemLayout} label="Price">
<Input prefix="$" placeholder="00.00"/>
</Form.Item>
<Form.Item {...formItemLayout} label="Is Sahred?">
<Switch checkedChildren={<Icon type="check" />} unCheckedChildren={<Icon type="close" />} defaultChecked />
</Form.Item>
<Divider/>
<Form.Item {...formItemLayout} label="Tags">
<InputGroup>
<Row gutter={8}>
<Col span={22}>
<Select
mode="multiple"
style={{ width: '100%' }}
placeholder="Tags Mode"
>
{this.tags}
</Select>
</Col>
<Col span={2}>
<Button type="dashed" shape="circle" icon="plus"/>
</Col>
</Row>
</InputGroup>
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Daa">
<InputGroup>
<Row gutter={8}>
<Col span={10}>
<Input placeholder="Key"/>
</Col>
<Col span={12}>
<Input placeholder="value"/>
</Col>
<Col span={2}>
<Button type="dashed" shape="circle" icon="plus"/>
</Col>
</Row>
</InputGroup>
</Form.Item>
</Form>
</div>
</Col>
<Col span={12} style={{paddingTop: 40, paddingLeft: 20}}>
<p>Application</p>
<div style={{height: 170}}>
<Dragger {...props}>
<p className="ant-upload-drag-icon">
<Icon type="inbox"/>
</p>
<p className="ant-upload-text">Click or drag file to this area to
upload</p>
<p className="ant-upload-hint">Support for a single or bulk upload.
Strictly prohibit from uploading company data or other band
files</p>
</Dragger>
</div>
<Row style={{marginTop: 40}}>
<Col span={12}>
<p>Icon</p>
<IconImage/>
</Col>
<Col span={12}>
<p>Banner</p>
<IconImage/>
</Col>
</Row>
<Row style={{marginTop: 40}}>
<Col span={24}>
<p>Screenshots</p>
<UploadScreenshots/>
</Col>
</Row>
</Col>
</Row>
</Card>
</Col>
</Row>
</div> </div>
</div> </div>

@ -33,11 +33,7 @@ class Apps extends React.Component {
render() { render() {
return ( return (
<div> <div>
<PageHeader
breadcrumb={{routes}}
/>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
<ReleaseModal/>
<ListApps/> <ListApps/>
</div> </div>

Loading…
Cancel
Save