Create component to add application

feature/appm-store/pbac
Jayasanka 6 years ago
parent 05d2327205
commit a3a485dd8e

@ -10,12 +10,12 @@ const {Option} = Select;
const {Title, Text} = Typography;
const Search = Input.Search;
// connecting state.apps with the component
const mapStateToProps = state => {
return {apps: state.apps}
};
// const mapStateToProps = state => {
// return {apps: state.apps}
// };
class ConnectedListApps extends React.Component {
class ListApps extends React.Component {
constructor(props) {
super(props);
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;

@ -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;

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

@ -1,14 +1,14 @@
import React from "react";
import {Layout, Menu, Icon} from 'antd';
const {Header, Content, Footer} = Layout;
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 {Redirect} from 'react-router'
import "../../App.css";
const {Header, Content, Footer} = Layout;
const {SubMenu} = Menu;
class Dashboard extends React.Component {
constructor(props) {
super(props);
@ -32,8 +32,18 @@ class Dashboard extends React.Component {
style={{lineHeight: '64px'}}
>
<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
App</Link></Menu.Item>
<SubMenu
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
type="control"/>Manage</Link></Menu.Item>
</Menu>
@ -41,15 +51,13 @@ class Dashboard extends React.Component {
</Layout>
<Layout>
<Content style={{padding: '0 0'}}>
<BrowserRouter>
<Switch>
<Redirect exact from="/publisher" to="/publisher/apps"/>
{this.state.routes.map((route) => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
<Switch>
<Redirect exact from="/publisher" to="/publisher/apps"/>
{this.state.routes.map((route) => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</BrowserRouter>
</Switch>
</Content>
<Footer style={{textAlign: 'center'}}>

@ -19,29 +19,12 @@ import {
Upload,
Divider
} from "antd";
import Step1 from "./Step1";
import Step2 from "./Step2";
import Step3 from "./Step3";
import styles from "./Style.less";
import IconImage from "./IconImg";
import UploadScreenshots from "./UploadScreenshots";
import axios from "axios";
import AddNewAppForm from "../../../components/new-app/AddNewAppForm"
import config from "../../../../public/conf/config.json";
const Paragraph = Typography;
const Dragger = Upload.Dragger;
const routes = [
{
path: 'index',
breadcrumbName: 'publisher',
},
{
path: 'first',
breadcrumbName: 'dashboard',
},
{
path: 'second',
breadcrumbName: 'add new app',
},
];
const props = {
name: 'file',
@ -60,18 +43,17 @@ const props = {
},
};
const Step = Steps.Step;
const steps = [{
title: 'First',
content: Step1
}, {
title: 'Second',
content: Step2,
}, {
title: 'Last',
content: Step3,
}];
//
// const steps = [{
// title: 'First',
// content: Step1
// }, {
// title: 'Second',
// content: Step2,
// }, {
// title: 'Last',
// content: Step3,
// }];
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 {
constructor(props) {
super(props);
this.state = {
current: 0,
categories: []
};
}
tags = [];
addTag(key, value){
this.tags.push(<Option key={key}>{value}</Option>);
componentDidMount() {
// this.getCategories();
}
next() {
@ -188,17 +93,44 @@ class AddNewApp extends React.Component {
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() {
const {current} = this.state;
const Content = steps[current].content;
this.addTag('1','Lorem');
this.addTag('2','Ipsum');
const {categories} = this.state;
return (
<div>
<PageHeader
title="Add New App"
breadcrumb={{routes}}
>
<div className="wrap">
<div className="content">
@ -209,121 +141,7 @@ class AddNewApp extends React.Component {
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<Row>
<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>
<AddNewAppForm/>
</div>
</div>

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

Loading…
Cancel
Save