├── public
├── robots.txt
├── favicon.ico
├── logo192.png
├── logo512.png
├── assets
│ └── icons
│ │ ├── check2.svg
│ │ ├── x.svg
│ │ ├── clipboard.svg
│ │ ├── trash.svg
│ │ └── pencil-square.svg
├── manifest.json
└── index.html
├── src
├── utils
│ ├── uid.js
│ ├── stringSlice.js
│ └── cookie.js
├── setupTests.js
├── component
│ ├── Popup.js
│ ├── Profile.js
│ ├── Toast.js
│ └── ToastPanel.js
├── index.css
├── reportWebVitals.js
├── mainPage
│ ├── MyPlan.css
│ ├── index.js
│ ├── MyConfig.js
│ ├── PlanDetail
│ │ ├── PlanDetailTokens.js
│ │ ├── PlanDetailConfig.js
│ │ ├── PlanDetailSharedConfig.js
│ │ ├── SelectPanel.js
│ │ ├── PlanDetailSharelinks.js
│ │ └── index.js
│ ├── FavorPlan.js
│ ├── FavorConfig.js
│ ├── MyPlan.js
│ └── ConfigDetail
│ │ └── index.js
├── overall.js
├── loginPage
│ ├── index.js
│ ├── LoginPanel.js
│ └── RegisterPanel.js
├── index.js
├── logo.svg
└── apilib
│ └── apiReq.js
├── .gitignore
├── README.md
└── package.json
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafee98/class-schedule-to-icalendar-webfront/master/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafee98/class-schedule-to-icalendar-webfront/master/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafee98/class-schedule-to-icalendar-webfront/master/public/logo512.png
--------------------------------------------------------------------------------
/src/utils/uid.js:
--------------------------------------------------------------------------------
1 | function genUid() {
2 | if (typeof genUid.__x == 'undefined') {
3 | genUid.__x = 0;
4 | }
5 | return ++genUid.__x;
6 | }
7 |
8 | export default genUid;
9 |
--------------------------------------------------------------------------------
/src/utils/stringSlice.js:
--------------------------------------------------------------------------------
1 | function stringSlice(str, n) {
2 | if (str.length <= n) {
3 | return str;
4 | }
5 |
6 | return str.slice(0, n) + "...";
7 | }
8 |
9 | export default stringSlice;
10 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/public/assets/icons/check2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/x.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/component/Popup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class PopupPanel extends React.Component {
4 | render() {
5 | return (
6 |
35 | {/*
*/}
36 | {localStorage.getItem(overall.storageKey.username)}
37 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default Profile;
48 |
--------------------------------------------------------------------------------
/src/component/Toast.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const bootstrap = require('bootstrap');
4 |
5 | class Toast extends React.Component {
6 | // constructor(props) {
7 | // super(props);
8 | // }
9 |
10 | componentDidMount() {
11 | let e = document.getElementById(`toast-${this.props.uid}`)
12 | e.addEventListener('hidden.bs.toast', () => this.props.onHidden(this.props.uid));
13 |
14 | let t = new bootstrap.Toast(e);
15 | t.show();
16 | }
17 |
18 | render() {
19 | return (
20 |
21 |
23 |
24 |
25 |
31 |
32 | {this.props.head}
33 |
34 |
35 |
36 |
37 |
38 | {this.props.body}
39 |
40 |
41 |
42 |
43 | )
44 | }
45 | }
46 |
47 | export default Toast;
48 |
--------------------------------------------------------------------------------
/src/component/ToastPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 | import overall from '../overall';
4 | import genUid from '../utils/uid';
5 | import Toast from './Toast';
6 |
7 | class ToastPanel extends React.Component {
8 | constructor(props) {
9 | super(props);
10 |
11 | this.addToast = this.addToast.bind(this);
12 | this.handleHidden = this.handleHidden.bind(this);
13 |
14 | this.toasts = [];
15 | }
16 |
17 | __subToken = 0;
18 |
19 | componentDidMount() {
20 | this.__subToken = PubSub.subscribe(overall.topics.toast, (msg, data) => {
21 | this.addToast(data.head, data.body, data.fine);
22 | });
23 | }
24 |
25 | componentWillUnmount() {
26 | PubSub.unsubscribe(this.__subToken);
27 | }
28 |
29 | addToast(head, body, fine=true) {
30 | this.toasts.push({
31 | head: head,
32 | body: body,
33 | fine: fine,
34 | key: genUid()
35 | });
36 | this.forceUpdate();
37 | }
38 |
39 | handleHidden(key) {
40 | let i = this.toasts.map(x => x.key).indexOf(key);
41 | if (i >= 0) {
42 | this.toasts.splice(i, 1);
43 | }
44 | }
45 |
46 | render() {
47 | let t = [];
48 | for (let x of this.toasts) {
49 | t.push(
50 |
52 | );
53 | }
54 |
55 | return (
56 |
57 | {t}
58 |
59 | )
60 | }
61 | }
62 |
63 | export default ToastPanel;
64 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 |
React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/loginPage/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 | import LoginPanel from './LoginPanel';
4 | import RegisterPanel from './RegisterPanel';
5 | import overall from '../overall';
6 |
7 | class LoginPage extends React.Component {
8 | constructor(props) {
9 | super(props);
10 |
11 | this.changeStatus = this.changeStatus.bind(this);
12 |
13 | this.state = {
14 | status: 'l' // l: login, r: register
15 | }
16 | }
17 |
18 | __subToken = "";
19 |
20 | componentDidMount() {
21 | this.__subToken = PubSub.subscribe(overall.topics.loginPage.switch,
22 | (msg, data) => {
23 | switch (data) {
24 | case overall.data.loginPage.switch.login:
25 | this.changeStatus('l');
26 | break;
27 | case overall.data.loginPage.switch.register:
28 | this.changeStatus('r');
29 | break;
30 | default:
31 | break;
32 | }
33 | });
34 | }
35 |
36 | componentWillUnmount() {
37 | PubSub.unsubscribe(this.__subToken);
38 | }
39 |
40 | changeStatus(s) {
41 | this.setState({
42 | status: s
43 | });
44 | }
45 |
46 | render() {
47 | return (
48 |
49 |
50 |
51 | -
52 |
54 |
55 | -
56 |
58 |
59 |
60 |
61 |
62 |
63 | {this.state.status === 'l' ? : }
64 |
65 |
66 | )
67 | }
68 | }
69 |
70 | export default LoginPage;
71 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import PubSub from 'pubsub-js';
4 | import 'bootstrap/dist/css/bootstrap.css';
5 |
6 | import LoginPage from './loginPage';
7 | import MainPage from './mainPage';
8 | import ToastPanel from './component/ToastPanel';
9 | import apiReq from './apilib/apiReq';
10 | import overall from './overall';
11 |
12 | apiReq.networkErrorHandler = () => {
13 | PubSub.publish(overall.topics.toast,
14 | { head: "error", body: "server side error or network error, try to relogin.", fine: false });
15 | };
16 |
17 | apiReq.apiPath = overall.apiPath;
18 |
19 | class Global extends React.Component {
20 | constructor(props) {
21 | super(props);
22 |
23 | this.switchPage = this.switchPage.bind(this);
24 |
25 | let tmpPage = localStorage.getItem("page");
26 | if (tmpPage == null) {
27 | tmpPage = overall.data.switchPage.loginPage;
28 | }
29 |
30 | this.state = {
31 | page: tmpPage
32 | };
33 | }
34 |
35 | __subToken = "";
36 |
37 | componentDidMount() {
38 | this.__subToken = PubSub.subscribe(overall.topics.switchPage, this.switchPage);
39 | }
40 |
41 | componentWillUnmount() {
42 | PubSub.unsubscribe(this.__subToken);
43 | }
44 |
45 | switchPage(topic, data) {
46 | localStorage.setItem(overall.storageKey.page, data);
47 | this.setState({page: data});
48 | }
49 |
50 | render() {
51 | let page = null;
52 | switch (this.state.page) {
53 | case overall.data.switchPage.loginPage:
54 | page =
55 | break;
56 | case overall.data.switchPage.mainPage:
57 | page =
58 | break;
59 |
60 | default:
61 | break;
62 | }
63 |
64 | return (
65 |
66 |
67 |
68 | {page}
69 |
70 |
71 |
72 |
73 | )
74 | }
75 | }
76 |
77 |
78 | ReactDOM.render(
79 |
80 |
81 | ,
82 | document.getElementById('root')
83 | );
84 |
--------------------------------------------------------------------------------
/src/loginPage/LoginPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 | import apiReq from '../apilib/apiReq';
4 | import overall from '../overall';
5 |
6 | class LoginPanel extends React.Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.reqLogin = this.reqLogin.bind(this);
11 | this.handleReqLogin = this.handleReqLogin.bind(this);
12 |
13 | this.state = {
14 | username: "",
15 | password: "",
16 | };
17 | }
18 |
19 | reqLogin(event) {
20 | event.preventDefault();
21 | apiReq.login(
22 | {
23 | username: this.state.username,
24 | password: this.state.password,
25 | tokenDuration: 7,
26 | },
27 | this.handleReqLogin
28 | )
29 | }
30 |
31 | handleReqLogin(j) {
32 | if (j["status"] === "ok") {
33 | PubSub.publish(overall.topics.toast, { head: "login", body: "login success", fine: true });
34 | PubSub.publish(overall.topics.switchPage, overall.data.switchPage.mainPage);
35 |
36 | localStorage.setItem(overall.storageKey.username, this.state.username);
37 | localStorage.setItem(overall.storageKey.userId, j.id);
38 | } else {
39 | PubSub.publish(overall.topics.toast, { head: "login", body: j.data, fine: false });
40 | }
41 | }
42 |
43 | handleChangle(p, v) {
44 | this.setState({[p]: v});
45 | }
46 |
47 | render() {
48 | return (
49 |
70 | )
71 | }
72 |
73 | }
74 |
75 | export default LoginPanel;
76 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/loginPage/RegisterPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PubSub from 'pubsub-js';
3 | import apiReq from '../apilib/apiReq';
4 | import overall from '../overall';
5 |
6 | class RegisterPanel extends React.Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.handleChange = this.handleChange.bind(this);
11 | this.reqRegister = this.reqRegister.bind(this);
12 |
13 | this.state = {
14 | email: "",
15 | username: "",
16 | nickname: "",
17 | password: ""
18 | };
19 | }
20 |
21 | handleChange(key, value) {
22 | this.setState({
23 | [key]: value
24 | });
25 | }
26 |
27 | reqRegister(e) {
28 | e.preventDefault();
29 | apiReq.register(
30 | {
31 | email: this.state.email,
32 | username: this.state.username,
33 | password: this.state.password,
34 | nickname: this.state.nickname
35 | },
36 | (j) => {
37 | if (j.status === "ok") {
38 | PubSub.publish(overall.topics.toast, { head: "register", body: "register success", fine: true })
39 | PubSub.publish(overall.topics.loginPage.switch, overall.data.loginPage.switch.login);
40 | } else {
41 | PubSub.publish(overall.topics.toast, { head: "register", body: j.data, fine: false })
42 | }
43 | }
44 | )
45 | }
46 |
47 | render() {
48 | return (
49 |
77 | )
78 | }
79 | }
80 |
81 | export default RegisterPanel;
82 |
--------------------------------------------------------------------------------
/src/mainPage/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Profile from '../component/Profile';
3 |
4 | import MyPlan from './MyPlan';
5 | import MyConfig from './MyConfig';
6 | import FavorConfig from './FavorConfig';
7 | import FavorPlan from './FavorPlan';
8 |
9 | import cookie from '../utils/cookie';
10 | import overall from '../overall';
11 |
12 | class MainPage extends React.Component {
13 | constructor(props) {
14 | super(props);
15 |
16 | this.subPages = {
17 | myPlan: "myPlan",
18 | favorPlan: "favorPlan",
19 | myConfig: "myConfig",
20 | favorConfig: "favorConfig"
21 | }
22 |
23 | this.state = {
24 | subPage: this.subPages.myPlan
25 | }
26 | }
27 |
28 | switchSubPage(e, p) {
29 | e.preventDefault();
30 | this.setState({ subPage: p });
31 | }
32 |
33 | render() {
34 | let subPage = null;
35 | let subTitle = null;
36 |
37 | switch (this.state.subPage) {
38 | case this.subPages.myPlan:
39 | subPage =
40 | subTitle = "My Plan";
41 | break;
42 |
43 | case this.subPages.favorPlan:
44 | subPage =
;
45 | subTitle = "Favor Plan";
46 | break;
47 |
48 | case this.subPages.myConfig:
49 | subPage =
50 | subTitle = "My Config";
51 | break;
52 |
53 | case this.subPages.favorConfig:
54 | subPage =
55 | subTitle = "Favor Config";
56 | break;
57 |
58 | default:
59 | break;
60 | }
61 |
62 | let profile = null;
63 | if (cookie.get("token") != null || localStorage.getItem(overall.storageKey.userId) !== null)
64 | profile =
;
65 |
66 | return (
67 |
68 |
69 |
70 |
99 |
100 |
101 |
102 | {subPage}
103 |
104 |
105 |
106 | );
107 | }
108 | }
109 |
110 | export default MainPage;
111 |
--------------------------------------------------------------------------------
/src/mainPage/MyConfig.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import ConfigDetail from './ConfigDetail';
5 |
6 | import overall from '../overall';
7 | import apiReq from '../apilib/apiReq';
8 | import stringSlice from '../utils/stringSlice';
9 |
10 | class MyConfig extends React.Component {
11 | constructor(props) {
12 | super(props);
13 | this.state = {
14 | newConfig: false,
15 | offset: 0,
16 | detailId: -1,
17 | configs: []
18 | }
19 | }
20 |
21 | componentDidMount() {
22 | this.reqConfigGetList(this.state.offset);
23 | }
24 |
25 | reqConfigGetList(offset) {
26 | apiReq.configGetList(
27 | { sortBy: "id", offset: offset, count: 30 },
28 | (j) => {
29 | if (j.status === "ok") {
30 | this.setState({ configs: j.data.configs });
31 | } else {
32 | PubSub.publish(overall.topics.toast, { head: "my config", body: "failed to get config: " + j.data, fine: false });
33 | }
34 | }
35 | )
36 | }
37 |
38 | reqConfigRemove(configId) {
39 | apiReq.configRemove(
40 | {id: configId},
41 | (j) => {
42 | if (j.status === "ok") {
43 | PubSub.publish(overall.topics.toast, { head: "my config", body: "success to remove config: " + configId, fine: true });
44 | } else {
45 | PubSub.publish(overall.topics.toast, { head: "my config", body: "failed to remove config: " + j.data, fine: false });
46 | }
47 |
48 | this.reqConfigGetList();
49 | }
50 | );
51 | }
52 |
53 | render() {
54 | let rows = [];
55 |
56 | for (let x of this.state.configs) {
57 | let id = x.id;
58 |
59 | let row = (
60 |
this.setState({detailId: id})}>
62 | | {id} |
63 |
64 | {x.type === 1 && "Global Config"}
65 | {x.type === 1 || "Lesson Config"}
66 | |
67 | {stringSlice(x.name, 24)} |
68 | {stringSlice(x.remark, 24)} |
69 | {x.createTime} |
70 | {x.modifyTime} |
71 |
72 |
75 | |
76 |
77 | )
78 |
79 | rows.push(row);
80 | }
81 |
82 | if (rows.length <= 0) {
83 | rows.push(
84 |
85 | |
86 | Got no config.
87 | |
88 |
89 | )
90 | }
91 |
92 | return (
93 |
94 |
95 |
96 |
97 | |
98 | Config Id
99 | |
100 | Type |
101 | Name |
102 | Remark |
103 | Create Time |
104 | Modify Time |
105 | Operating |
106 |
107 |
108 |
109 | {rows}
110 |
111 |
112 |
113 |
117 |
118 |
119 | {this.state.detailId === -1 ||
120 |
this.reqConfigGetList(this.state.offset)}
122 | onHidden={() => this.setState({detailId: -1})}
123 | newConfig={false} />}
124 | {this.state.newConfig &&
125 | this.reqConfigGetList(this.state.offset)}
127 | onHidden={() => this.setState({newConfig: false})}
128 | newConfig={true} />}
129 |
130 | )
131 | }
132 | }
133 |
134 | export default MyConfig;
135 |
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/PlanDetailTokens.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 | import apiReq from '../../apilib/apiReq';
4 | import overall from '../../overall';
5 |
6 | class PlanDetailTokens extends React.Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.reqAddToken = this.reqAddToken.bind(this);
11 | this.reqPlanGetTokenList = this.reqPlanGetTokenList.bind(this);
12 | this.copyGenerateUrl = this.copyGenerateUrl.bind(this);
13 |
14 | // this.props.planId;
15 | this.state = {
16 | tokens: []
17 | }
18 | }
19 |
20 | componentDidMount() {
21 | this.reqPlanGetTokenList();
22 | }
23 |
24 | reqPlanGetTokenList() {
25 | apiReq.planGetTokenList(
26 | {id: this.props.planId},
27 | (j) => {
28 | if (j.status === "ok") {
29 | this.setState({ tokens: j.data.tokens })
30 | } else {
31 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "failed to get tokens: " + j.data, fine: false });
32 | }
33 | }
34 | )
35 | }
36 |
37 | reqAddToken() {
38 | apiReq.planCreateToken(
39 | { id: this.props.planId },
40 | (j) => {
41 | if (j.status === "ok") {
42 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "success to add token.", fine: true });
43 | } else {
44 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "failed to create token: " + j.data, fine: false });
45 | }
46 |
47 | this.reqPlanGetTokenList();
48 | }
49 | )
50 | }
51 |
52 | reqPlanRevokeToken(token) {
53 | apiReq.planRevokeToken(
54 | { token: token },
55 | (j) => {
56 | if (j.status === "ok") {
57 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "success to revoke token.", fine: true });
58 | } else {
59 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "failed to revoke token: " + j.data, fine: false });
60 | }
61 |
62 | this.reqPlanGetTokenList();
63 | }
64 | )
65 | }
66 |
67 | copyGenerateUrl(token) {
68 | // this only work in HTTPS
69 | const url = window.location.protocol + "//" + window.location.host + overall.apiPath + "/generate-by-plan-token?token=" + token;
70 | if (navigator.clipboard !== undefined) {
71 | navigator.clipboard.writeText(url).then(
72 | () => { PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "success to copy generate url", fine: true }); },
73 | (e) => { PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "failed to copy generate url: " + e, fine: false }); },
74 | )
75 | } else {
76 | PubSub.publish(overall.topics.toast, { head: "plan tokens", body: "the copy action is only available in https environment.", fine: false });
77 | }
78 | }
79 |
80 | render() {
81 | let rows = [];
82 | for (let x of this.state.tokens) {
83 | let tmp = (
84 |
85 | | {x.token} |
86 | {x.createTime} |
87 |
88 |
91 |
94 | |
95 |
96 | );
97 | rows.push(tmp);
98 | }
99 |
100 | if (rows.length === 0) {
101 | rows.push(
102 |
103 | |
104 | No tokens now.
105 | |
106 |
107 | );
108 | }
109 |
110 | return (
111 |
112 |
113 |
114 |
115 | | Token |
116 | Create Time |
117 | Operating |
118 |
119 |
120 |
121 |
122 | {rows}
123 |
124 |
125 |
126 |
127 |
130 |
131 |
132 |
133 | )
134 | }
135 | }
136 |
137 | export default PlanDetailTokens;
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/PlanDetailConfig.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../../apilib/apiReq';
5 | import overall from '../../overall';
6 | import stringSlice from '../../utils/stringSlice';
7 |
8 | class PlanDetailConfig extends React.Component {
9 | constructor(props) {
10 | super(props);
11 |
12 | // this.props.planId;
13 | // this.props.configs;
14 | // this.props.shared
15 | // this.props.onModify;
16 |
17 | this.reqAddConfig = this.reqAddConfig.bind(this);
18 | this.reqPlanRemoveConfig = this.reqPlanRemoveConfig.bind(this);
19 | this.btnAddConfig = this.btnAddConfig.bind(this);
20 | this.planAddConfig = this.planAddConfig.bind(this);
21 | }
22 |
23 | componentDidMount() {
24 | // let eles = document.querySelectorAll(".to-show-tooltip");
25 | // for (let x of eles) {
26 | // new bootstrap.Tooltip(x);
27 | // }
28 | }
29 |
30 | reqAddConfig(configId) {
31 | apiReq.planAddConfig(
32 | { planId: this.props.planId, configId: configId },
33 | (j) => {
34 | if (j.status === "ok") {
35 | PubSub.publish(overall.topics.toast, {head: "plan detail", body: "success to add config to plan", fine: true});
36 | } else {
37 | PubSub.publish(overall.topics.toast, {head: "plan detail", body: "failed to add config: " + j.data, fine: false});
38 | }
39 |
40 | this.props.onModify();
41 | }
42 | )
43 | }
44 |
45 | reqPlanRemoveConfig(planId, configId) {
46 | apiReq.planRemoveConfig(
47 | { planId: planId, configId: configId },
48 | (j) => {
49 | if (j.status === "ok") {
50 | PubSub.publish(overall.topics.toast, { head: "plan detail", body: "removed config: " + configId, fine: true });
51 | } else {
52 | PubSub.publish(overall.topics.toast, { head: "plan detail", body: "failed to remove config: " + j.data, fine: false });
53 | }
54 |
55 | this.props.onModify();
56 | }
57 | );
58 | }
59 |
60 | btnAddConfig() {
61 | PubSub.publishSync(overall.topics.mainPage.myPlan.planDetail.popupHide);
62 | PubSub.publish(overall.topics.mainPage.myPlan.selectPopup.show, { select: "config", onSelect: this.planAddConfig });
63 | }
64 |
65 | planAddConfig(configId) {
66 | PubSub.publish(overall.topics.mainPage.myPlan.planDetail.popupShow);
67 | if (configId >= 0) {
68 | this.reqAddConfig(configId);
69 | }
70 | }
71 |
72 | render() {
73 | let configs = [];
74 | for (let x of this.props.configs) {
75 | let tmp =
76 |
77 | | {x.id} |
78 | {x.type === 1 ? "global" : "lesson"} |
79 | {stringSlice(x.name, 24)} |
80 | {stringSlice(x.content, 24)} |
81 | {stringSlice(x.remark, 24)} |
82 | {x.createTime} |
83 | {x.modifyTime} |
84 |
85 |
88 | |
89 |
90 | configs.push(tmp);
91 | }
92 |
93 | if (configs.length === 0) {
94 | configs.push(
95 |
96 | |
97 | There's no content now.
98 | |
99 |
100 | )
101 | }
102 |
103 | return (
104 |
105 |
106 |
107 |
108 | | id |
109 | type |
110 | name |
111 | content |
112 | remark |
113 | createTime |
114 | modifyTime |
115 | operating |
116 |
117 |
118 |
119 |
120 | {configs}
121 |
122 |
123 |
124 |
125 |
129 |
130 |
131 | )
132 | }
133 | }
134 |
135 | export default PlanDetailConfig;
136 |
--------------------------------------------------------------------------------
/src/mainPage/FavorPlan.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import PlanDetail from './PlanDetail';
5 |
6 | import apiReq from '../apilib/apiReq';
7 | import overall from '../overall';
8 | import stringSlice from '../utils/stringSlice';
9 |
10 | class FavorPlan extends React.Component {
11 | constructor(props) {
12 | super(props);
13 |
14 | this.reqFavorPlanAdd = this.reqFavorPlanAdd.bind(this);
15 | this.reqFavorPlanRemove = this.reqFavorPlanRemove.bind(this);
16 | this.reqFavorPlanGetList = this.reqFavorPlanGetList.bind(this);
17 | this.btnAddShare = this.btnAddShare.bind(this);
18 |
19 | this.state = {
20 | detailId: -1,
21 | directAddShareId: "",
22 | offset: 0,
23 | shares: []
24 | }
25 | }
26 |
27 | componentDidMount() {
28 | this.reqFavorPlanGetList();
29 | }
30 |
31 | reqFavorPlanGetList() {
32 | apiReq.favorPlanGetList(
33 | { offset: this.state.offset, count: 30 },
34 | (j) => {
35 | if (j.status === "ok") {
36 | this.setState({ shares: j.data.plans });
37 | } else {
38 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: "failed to get favor plans: " + j.data, fine: false })
39 | }
40 | }
41 | )
42 | }
43 |
44 | reqFavorPlanAdd(shareId) {
45 | apiReq.favorPlanAdd(
46 | { id: shareId },
47 | (j) => {
48 | if (j.status === "ok") {
49 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: "success to add favor plan.", fine: true });
50 | this.reqFavorPlanGetList();
51 | } else {
52 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: "failed to add favor plan: " + j.data, fine: false });
53 | }
54 | }
55 | )
56 | }
57 |
58 | reqFavorPlanRemove(shareId) {
59 | apiReq.favorPlanRemove(
60 | { id: shareId },
61 | (j) => {
62 | if (j.status === "ok") {
63 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: "success to remove favor plan.", fine: true });
64 | this.reqFavorPlanGetList();
65 | } else {
66 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: "failed to remove favor plan: " + j.data, fine: false });
67 | }
68 | }
69 | )
70 | }
71 |
72 | btnAddShare() {
73 | let shareId = parseInt(this.state.directAddShareId);
74 | if (isNaN(shareId)) {
75 | PubSub.publish(overall.topics.toast, { head: "favor plan", body: this.state.directAddShareId + " is not a valid number.", fine: false });
76 | return;
77 | }
78 |
79 | this.reqFavorPlanAdd(shareId);
80 | }
81 |
82 | render() {
83 | let rows = [];
84 |
85 | for (let x of this.state.shares) {
86 | let id = x.shareId;
87 |
88 | let row = (
89 |
this.setState({ detailId: id })}>
90 | | {id} |
91 |
92 | {x.type === 1 && "Global"}
93 | {x.type === 1 || "Lesson"}
94 | |
95 | {stringSlice(x.name, 24)} |
96 | {stringSlice(x.remark, 24)} |
97 | {x.createTime} |
98 | {x.modifyTime} |
99 |
100 |
103 | |
104 |
105 | )
106 |
107 | rows.push(row);
108 | }
109 |
110 | if (rows.length <= 0) {
111 | rows.push(
112 |
113 | |
114 | Got no config.
115 | |
116 |
117 | )
118 | }
119 | return (
120 |
121 |
122 |
123 |
124 |
125 | | Share Id |
126 | Type |
127 | Name |
128 | Remark |
129 | Create Time |
130 | Modify Time |
131 | Operating |
132 |
133 |
134 |
135 | {rows}
136 |
137 |
138 |
139 |
140 |
141 |
145 | this.setState({ directAddShareId: e.target.value })} />
148 |
149 |
150 |
151 | {this.state.detailId === -1 ||
152 |
this.setState({ detailId: -1 })} />}
156 |
157 | )
158 | }
159 | }
160 |
161 | export default FavorPlan;
162 |
--------------------------------------------------------------------------------
/src/mainPage/FavorConfig.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../apilib/apiReq';
5 | import overall from '../overall';
6 | import stringSlice from '../utils/stringSlice';
7 | import ConfigDetail from './ConfigDetail';
8 |
9 | class FavorConfig extends React.Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.reqFavorConfigAdd = this.reqFavorConfigAdd.bind(this);
14 | this.reqFavorConfigRemove = this.reqFavorConfigRemove.bind(this);
15 | this.reqFavorConfigGetList = this.reqFavorConfigGetList.bind(this);
16 | this.btnAddShare = this.btnAddShare.bind(this);
17 |
18 | this.state = {
19 | detailId: -1,
20 | directAddShareId: "",
21 | offset: 0,
22 | shares: []
23 | }
24 | }
25 |
26 | componentDidMount() {
27 | this.reqFavorConfigGetList();
28 | }
29 |
30 | reqFavorConfigGetList() {
31 | apiReq.favorConfigGetList(
32 | { offset: this.state.offset, count: 30 },
33 | (j) => {
34 | if (j.status === "ok") {
35 | this.setState({ shares: j.data.configs });
36 | } else {
37 | PubSub.publish(overall.topics.toast, { head: "favor config", body: "failed to get favor configs: " + j.data, fine: false })
38 | }
39 | }
40 | )
41 | }
42 |
43 | reqFavorConfigAdd(shareId) {
44 | apiReq.favorConfigAdd(
45 | { id: shareId },
46 | (j) => {
47 | if (j.status === "ok") {
48 | PubSub.publish(overall.topics.toast, { head: "favor config", body: "success to add favor config.", fine: true });
49 | this.reqFavorConfigGetList();
50 | } else {
51 | PubSub.publish(overall.topics.toast, { head: "favor config", body: "failed to add favor config: " + j.data, fine: false });
52 | }
53 | }
54 | )
55 | }
56 |
57 | reqFavorConfigRemove(shareId) {
58 | apiReq.favorConfigRemove(
59 | { id: shareId },
60 | (j) => {
61 | if (j.status === "ok") {
62 | PubSub.publish(overall.topics.toast, { head: "favor config", body: "success to remove favor config.", fine: true });
63 | this.reqFavorConfigGetList();
64 | } else {
65 | PubSub.publish(overall.topics.toast, { head: "favor config", body: "failed to remove favor config: " + j.data, fine: false });
66 | }
67 | }
68 | )
69 | }
70 |
71 | btnAddShare() {
72 | let shareId = parseInt(this.state.directAddShareId);
73 | if (isNaN(shareId)) {
74 | PubSub.publish(overall.topics.toast, { head: "favor config", body: this.state.directAddShareId + " is not a valid number.", fine: false });
75 | return;
76 | }
77 |
78 | this.reqFavorConfigAdd(shareId);
79 | }
80 |
81 | render() {
82 | let rows = [];
83 |
84 | for (let x of this.state.shares) {
85 | let id = x.shareId;
86 |
87 | let row = (
88 |
this.setState({ detailId: id })}>
89 | | {id} |
90 |
91 | {x.type === 1 && "Global"}
92 | {x.type === 1 || "Lesson"}
93 | |
94 | {stringSlice(x.name, 24)} |
95 | {stringSlice(x.remark, 24)} |
96 | {x.createTime} |
97 | {x.modifyTime} |
98 |
99 |
102 | |
103 |
104 | )
105 |
106 | rows.push(row);
107 | }
108 |
109 | if (rows.length <= 0) {
110 | rows.push(
111 |
112 | |
113 | Got no config.
114 | |
115 |
116 | )
117 | }
118 | return (
119 |
120 |
121 |
122 |
123 |
124 | | Share Id |
125 | Type |
126 | Name |
127 | Remark |
128 | Create Time |
129 | Modify Time |
130 | Operating |
131 |
132 |
133 |
134 | {rows}
135 |
136 |
137 |
138 |
139 |
140 |
144 | this.setState({ directAddShareId: e.target.value })} />
147 |
148 |
149 |
150 | {this.state.detailId === -1 ||
151 |
this.setState({ detailId: -1 })}
155 | newConfig={false}
156 | shared={true} />}
157 |
158 | )
159 | }
160 | }
161 |
162 | export default FavorConfig;
163 |
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/PlanDetailSharedConfig.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../../apilib/apiReq';
5 | import overall from '../../overall';
6 | import stringSlice from '../../utils/stringSlice';
7 |
8 | class PlanDetailSharedConfig extends React.Component {
9 | constructor(props) {
10 | super(props);
11 |
12 | this.reqPlanAddShare = this.reqPlanAddShare.bind(this);
13 | this.reqPlanRemoveShare = this.reqPlanRemoveShare.bind(this);
14 | this.btnAddShare = this.btnAddShare.bind(this);
15 | this.btnDirectAddShare = this.btnDirectAddShare.bind(this);
16 |
17 | // this.props.planId;
18 | // this.props.shares;
19 | // this.props.shared;
20 | // this.props.onModify;
21 | this.state = {
22 | directAddShareId: ""
23 | }
24 | }
25 |
26 | reqPlanRemoveShare(shareId) {
27 | apiReq.planRemoveShare(
28 | { planId: this.props.planId, configShareId: shareId },
29 | (j) => {
30 | if (j.status === "ok") {
31 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "success to remove share", fine: true });
32 | this.props.onModify();
33 | } else {
34 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to remove share: " + j.data, fine: false });
35 | }
36 | }
37 | )
38 | }
39 |
40 | reqPlanAddShare(shareId, showPopup=true) {
41 | if (showPopup)
42 | PubSub.publishSync(overall.topics.mainPage.myPlan.planDetail.popupShow);
43 |
44 | if (shareId >= 0) {
45 | apiReq.planAddShare(
46 | { planId: this.props.planId, configShareId: shareId },
47 | (j) => {
48 | if (j.status === "ok") {
49 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "success to add share", fine: true });
50 | this.props.onModify();
51 | } else {
52 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to add share: " + j.data, fine: false });
53 | }
54 | }
55 | )
56 | }
57 | }
58 |
59 | btnAddShare() {
60 | PubSub.publishSync(overall.topics.mainPage.myPlan.planDetail.popupHide);
61 | PubSub.publish(overall.topics.mainPage.myPlan.selectPopup.show, { select: "favorConfig", onSelect: this.reqPlanAddShare })
62 | }
63 |
64 | btnDirectAddShare() {
65 | let shareId = parseInt(this.state.directAddShareId);
66 | if (isNaN(shareId)) {
67 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: this.state.directAddShareId + " is not a valid number.", fine: false });
68 | return;
69 | }
70 |
71 | this.reqPlanAddShare(shareId, false);
72 | }
73 |
74 | render() {
75 | let shares = [];
76 | for (let x of this.props.shares) {
77 | let tmp =
78 |
79 | | {x.id} |
80 | {x.type === 1 && "global"}{x.type === 1 || "lesson"} |
81 | {stringSlice(x.name, 24)} |
82 | {stringSlice(x.content, 24)} |
83 | {stringSlice(x.remark, 24)} |
84 | {x.createTime} |
85 | {x.modifyTime} |
86 |
87 |
90 | |
91 |
92 | shares.push(tmp);
93 | }
94 |
95 | if (shares.length === 0) {
96 | shares.push(
97 |
98 | |
99 | There's no content now.
100 | |
101 |
102 | )
103 | }
104 |
105 | return (
106 |
107 |
108 |
109 |
110 | | Share Id |
111 | Type |
112 | Name |
113 | Content |
114 | Remark |
115 | CreateTime |
116 | ModifyTime |
117 | Operating |
118 |
119 |
120 |
121 |
122 | {shares}
123 |
124 |
125 |
126 |
127 |
128 |
129 |
133 |
134 |
135 |
136 |
140 | this.setState({ directAddShareId: e.target.value })} />
144 |
145 |
146 |
147 |
148 |
149 | )
150 | }
151 | }
152 |
153 | export default PlanDetailSharedConfig;
154 |
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/SelectPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../../apilib/apiReq';
5 | import overall from '../../overall';
6 | import stringSlice from '../../utils/stringSlice';
7 |
8 | const bootstrap = require('bootstrap');
9 |
10 | class SelectPanel extends React.Component {
11 | constructor(props) {
12 | super(props);
13 |
14 | this.reqItems = this.reqItems.bind(this);
15 | this.select = this.select.bind(this);
16 |
17 | // this.props.select == 'config' || 'favorConfig';
18 | // this.props.onSelect == function(configId_or_configShareId);
19 |
20 | this.state = {
21 | param: {
22 | select: "",
23 | onSelect: "",
24 | },
25 | activeId: -1,
26 | offset: 0,
27 | items: []
28 | }
29 | }
30 |
31 | __subToken = "";
32 |
33 | componentDidMount() {
34 | let ele = document.getElementById("select-panel-popup");
35 | this.popup = new bootstrap.Modal(ele, {backdrop: false, keyboard: false});
36 |
37 | this.__subToken = PubSub.subscribe(overall.topics.mainPage.myPlan.selectPopup.show, (topic, param) => {
38 | this.setState({ param: param });
39 | this.popup.show();
40 | this.reqItems();
41 |
42 | console.log(ele);
43 | })
44 | }
45 |
46 | componentWillUnmount() {
47 | PubSub.unsubscribe(this.__subToken);
48 | }
49 |
50 | reqItems(offset = 0) {
51 | switch (this.state.param.select) {
52 | case "config":
53 | apiReq.configGetList(
54 | { sortBy: "id", offset: offset, count: 30 },
55 | (j) => {
56 | if (j.status === "ok") {
57 | this.setState({ items: j.data.configs });
58 | } else {
59 | PubSub.publish(overall.topics.toast, { head: "select panel", body: "failed to get config: " + j.data, fine: false });
60 | }
61 | }
62 | )
63 | break;
64 |
65 | case "favorConfig":
66 | apiReq.favorConfigGetList(
67 | { offset: offset, count: 30 },
68 | (j) => {
69 | if (j.status === "ok") {
70 | this.setState({ items: j.data.configs });
71 | } else {
72 | PubSub.publish(overall.topics.toast, { head: "select panel", body: "failed to get favor configs: " + j.data, fine: false })
73 | }
74 | }
75 | )
76 | break;
77 |
78 | default:
79 | break;
80 | }
81 | }
82 |
83 | select(submit) {
84 | if (submit) {
85 | if (this.state.activeId < 0) {
86 | PubSub.publish(overall.topics.toast, { head: "select panel", body: "please select an item before submit", fine: false });
87 | } else {
88 | this.popup.hide();
89 | this.state.param.onSelect(this.state.activeId);
90 | }
91 | } else {
92 | this.popup.hide();
93 | this.state.param.onSelect(-1);
94 | }
95 | }
96 |
97 | render() {
98 | let rows = [];
99 |
100 | for (let x of this.state.items) {
101 | let id = -1;
102 | switch (this.state.param.select) {
103 | case "config":
104 | id = x.id;
105 | break;
106 | case "favorConfig":
107 | id = x.shareId;
108 | break;
109 | default:
110 | break;
111 | }
112 |
113 | let row = (
114 |
{ this.setState((state, props) => { return { activeId: id === state.activeId ? -1 : id } }) }}>
117 | | {id} |
118 |
119 | {x.type === 1 && "Global"}
120 | {x.type === 1 || "Lesson"}
121 | |
122 | {stringSlice(x.name, 24)} |
123 | {stringSlice(x.remark, 24)} |
124 | {x.createTime} |
125 | {x.modifyTime} |
126 |
127 | )
128 |
129 | rows.push(row);
130 | }
131 |
132 | if (rows.length <= 0) {
133 | rows.push(
134 |
135 | |
136 | Got no config.
137 | |
138 |
139 | )
140 | }
141 |
142 | return (
143 |
180 |
181 | );
182 | }
183 | }
184 |
185 | export default SelectPanel;
186 |
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/PlanDetailSharelinks.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../../apilib/apiReq';
5 | import overall from '../../overall';
6 |
7 | class PlanDetailSharelinks extends React.Component {
8 | constructor(props) {
9 | super(props);
10 |
11 | // this.props.planId;
12 |
13 | this.reqPlanShareGetList = this.reqPlanShareGetList.bind(this);
14 | this.reqPlanShareModify = this.reqPlanShareModify.bind(this);
15 | this.reqPlanShareRevoke = this.reqPlanShareRevoke.bind(this);
16 | this.reqPlanShareCreate = this.reqPlanShareCreate.bind(this);
17 |
18 | this.state = {
19 | newShare: {
20 | exist: false,
21 | remark: ""
22 | },
23 | editShare: {
24 | id: -1,
25 | remark: ""
26 | },
27 | shares: []
28 | };
29 | }
30 |
31 | componentDidMount() {
32 | this.reqPlanShareGetList();
33 | }
34 |
35 | reqPlanShareGetList() {
36 | apiReq.planShareGetList(
37 | { id: this.props.planId },
38 | (j) => {
39 | if (j.status === "ok") {
40 | this.setState({ shares: j.data.shares });
41 | } else {
42 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to get config share links:" + j.data, fine: false });
43 | }
44 | }
45 | )
46 | }
47 |
48 | reqPlanShareModify() {
49 | apiReq.planShareModify(
50 | { id: this.state.editShare.id, remark: this.state.editShare.remark},
51 | (j) => {
52 | if (j.status === "ok") {
53 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "success to modify plan share links.", fine: true });
54 | this.setState({ editShare: { id: -1, remark: "" } });
55 |
56 | this.reqPlanShareGetList(this.props.planId);
57 | } else {
58 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to modify plan share links:" + j.data, fine: false });
59 | }
60 | }
61 | );
62 | }
63 |
64 | reqPlanShareRevoke(shareId) {
65 | apiReq.planShareRevoke(
66 | { id: shareId },
67 | (j) => {
68 | if (j.status === "ok") {
69 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "success to remove share links.", fine: true });
70 |
71 | this.reqPlanShareGetList(this.props.planId);
72 | } else {
73 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to remove share links:" + j.data, fine: false });
74 | }
75 | }
76 | );
77 | }
78 |
79 | reqPlanShareCreate(remark) {
80 | apiReq.planShareCreate(
81 | { id: this.props.planId, remark: remark },
82 | (j) => {
83 | if (j.status === "ok") {
84 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "success to create share links.", fine: true });
85 |
86 | this.reqPlanShareGetList(this.props.planId);
87 | } else {
88 | PubSub.publish(overall.topics.toast, { head: "plan detail share", body: "failed to create share links:" + j.data, fine: false });
89 | }
90 | }
91 | );
92 | }
93 |
94 | render() {
95 | let rows = [];
96 | for (let x of this.state.shares) {
97 | let tmp = (
98 |
99 | | {x.id} |
100 |
101 | {x.id === this.state.editShare.id &&
102 |
103 | | }
106 | {x.id === this.state.editShare.id ||
107 | {x.remark} | }
108 |
109 | {x.createTime} |
110 |
111 | {x.id === this.state.editShare.id &&
112 |
113 |
116 |
119 | |
120 | }
121 | {x.id === this.state.editShare.id ||
122 |
123 |
126 |
127 | | }
128 |
129 | );
130 | rows.push(tmp);
131 | }
132 |
133 | if (rows.length === 0) {
134 | rows.push(
135 |
136 | |
137 | No content now.
138 | |
139 |
140 | )
141 | }
142 |
143 | let newShare = null;
144 | if (this.state.newShare.exist)
145 | newShare = (
146 |
147 | |
148 |
149 | |
152 | |
153 |
154 |
155 |
158 |
161 | |
162 |
163 | )
164 |
165 | return (
166 |
167 |
168 |
169 |
170 | | Share Id |
171 | Remark |
172 | Create Time |
173 | Operating |
174 |
175 |
176 |
177 | {rows}
178 |
179 | {newShare}
180 |
181 |
182 |
183 | {this.state.newShare.exist ||
184 |
185 |
186 |
}
187 |
188 | )
189 | }
190 | }
191 |
192 | export default PlanDetailSharelinks;
193 |
--------------------------------------------------------------------------------
/src/apilib/apiReq.js:
--------------------------------------------------------------------------------
1 | class apiReq {
2 | static __priReq (path, param, successCallback) {
3 | return fetch(this.apiPath + path, {
4 | method: "post",
5 | credentials: "include",
6 | headers: {
7 | 'Content-Type': 'application/json'
8 | },
9 | body: JSON.stringify(param)
10 | }).then((res) => res.json(), this.networkErrorHandler)
11 | .then(successCallback);
12 | }
13 |
14 | static networkErrorHandler = (e) => { console.log(e); };
15 | static apiPath = "/api";
16 |
17 | static __target = {
18 | login: "/login",
19 | register: "/register",
20 | logout: "/logout",
21 |
22 | configCreate: "/config-create",
23 | configRemove: "/config-remove",
24 | configMofidy: "/config-modify",
25 | configGetById: "/config-get-by-id",
26 | configGetByShare: "/config-get-by-share",
27 | configGetList: "/config-get-list",
28 |
29 | configShareCreate: "/config-share-create",
30 | configShareModify: "/config-share-modify",
31 | configShareRevoke: "/config-share-revoke",
32 | configshareGetList: "/config-share-get-list",
33 |
34 | planCreate: "/plan-create",
35 | planRemove: "/plan-remove",
36 |
37 | planModify: "/plan-modify",
38 | planAddConfig: "/plan-add-config",
39 | planRemoveConfig: "/plan-remove-config",
40 | planAddShare: "/plan-add-share",
41 | planRemoveShare: "/plan-remove-share",
42 |
43 | planGetById: "/plan-get-by-id",
44 | planGetByShare: "/plan-get-by-share",
45 | planGetList: "/plan-get-list",
46 |
47 | planCreateToken: "/plan-create-token",
48 | planRevokeToken: "/plan-revoke-token",
49 | planGetTokenList: "/plan-get-token-list",
50 |
51 | planShareCreate: "/plan-share-create",
52 | planShareModify: "/plan-share-modify",
53 | planShareRevoke: "/plan-share-revoke",
54 | planShareGetList: "/plan-share-get-list",
55 |
56 | favorConfigAdd: "/favor-config-add",
57 | favorConfigRemove: "/favor-config-remove",
58 | favorConfigGetList: "/favor-config-get-list",
59 | favorPlanAdd: "/favor-plan-add",
60 | favorPlanRemove: "/favor-plan-remove",
61 | favorPlanGetList: "/favor-plan-get-list",
62 |
63 | generateByPlanToken: "/generate-by-plan-token"
64 | }
65 |
66 | static login(param, successCallback) { return this.__priReq(this.__target.login, param, successCallback); }
67 | static register(param, successCallback) { return this.__priReq(this.__target.register, param, successCallback); }
68 | static logout(param, successCallback) { return this.__priReq(this.__target.logout, param, successCallback); }
69 |
70 | static configCreate(param, successCallback) { return this.__priReq(this.__target.configCreate, param, successCallback); }
71 | static configRemove(param, successCallback) { return this.__priReq(this.__target.configRemove, param, successCallback); }
72 | static configMofidy(param, successCallback) { return this.__priReq(this.__target.configMofidy, param, successCallback); }
73 | static configGetById(param, successCallback) { return this.__priReq(this.__target.configGetById, param, successCallback); }
74 | static configGetByShare(param, successCallback) { return this.__priReq(this.__target.configGetByShare, param, successCallback); }
75 | static configGetList(param, successCallback) { return this.__priReq(this.__target.configGetList, param, successCallback); }
76 |
77 | static configShareCreate(param, successCallback) { return this.__priReq(this.__target.configShareCreate, param, successCallback); }
78 | static configShareModify(param, successCallback) { return this.__priReq(this.__target.configShareModify, param, successCallback); }
79 | static configShareRevoke(param, successCallback) { return this.__priReq(this.__target.configShareRevoke, param, successCallback); }
80 | static configshareGetList(param, successCallback) { return this.__priReq(this.__target.configshareGetList, param, successCallback); }
81 |
82 | static planCreate(param, successCallback) { return this.__priReq(this.__target.planCreate, param, successCallback); }
83 | static planRemove(param, successCallback) { return this.__priReq(this.__target.planRemove, param, successCallback); }
84 |
85 | static planModify(param, successCallback) { return this.__priReq(this.__target.planModify, param, successCallback); }
86 | static planAddConfig(param, successCallback) { return this.__priReq(this.__target.planAddConfig, param, successCallback); }
87 | static planRemoveConfig(param, successCallback) { return this.__priReq(this.__target.planRemoveConfig, param, successCallback); }
88 | static planAddShare(param, successCallback) { return this.__priReq(this.__target.planAddShare, param, successCallback); }
89 | static planRemoveShare(param, successCallback) { return this.__priReq(this.__target.planRemoveShare, param, successCallback); }
90 |
91 | static planGetById(param, successCallback) { return this.__priReq(this.__target.planGetById, param, successCallback); }
92 | static planGetByShare(param, successCallback) { return this.__priReq(this.__target.planGetByShare, param, successCallback); }
93 | static planGetList(param, successCallback) { return this.__priReq(this.__target.planGetList, param, successCallback); }
94 |
95 | static planCreateToken(param, successCallback) { return this.__priReq(this.__target.planCreateToken, param, successCallback); }
96 | static planRevokeToken(param, successCallback) { return this.__priReq(this.__target.planRevokeToken, param, successCallback); }
97 | static planGetTokenList(param, successCallback) { return this.__priReq(this.__target.planGetTokenList, param, successCallback); }
98 |
99 | static planShareCreate(param, successCallback) { return this.__priReq(this.__target.planShareCreate, param, successCallback); }
100 | static planShareModify(param, successCallback) { return this.__priReq(this.__target.planShareModify, param, successCallback); }
101 | static planShareRevoke(param, successCallback) { return this.__priReq(this.__target.planShareRevoke, param, successCallback); }
102 | static planShareGetList(param, successCallback) { return this.__priReq(this.__target.planShareGetList, param, successCallback); }
103 |
104 | static favorConfigAdd(param, successCallback) { return this.__priReq(this.__target.favorConfigAdd, param, successCallback); }
105 | static favorConfigRemove(param, successCallback) { return this.__priReq(this.__target.favorConfigRemove, param, successCallback); }
106 | static favorConfigGetList(param, successCallback) { return this.__priReq(this.__target.favorConfigGetList, param, successCallback); }
107 | static favorPlanAdd(param, successCallback) { return this.__priReq(this.__target.favorPlanAdd, param, successCallback); }
108 | static favorPlanRemove(param, successCallback) { return this.__priReq(this.__target.favorPlanRemove, param, successCallback); }
109 | static favorPlanGetList(param, successCallback) { return this.__priReq(this.__target.favorPlanGetList, param, successCallback); }
110 |
111 | static generateByPlanToken(param, successCallback) { return this.__priReq(this.__target.generateByPlanToken, param, successCallback); }
112 | };
113 |
114 | export default apiReq;
115 |
--------------------------------------------------------------------------------
/src/mainPage/PlanDetail/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import PlanDetailConfig from './PlanDetailConfig';
5 | import PlanDetailTokens from './PlanDetailTokens';
6 |
7 | import apiReq from '../../apilib/apiReq';
8 | import overall from '../../overall';
9 | import PlanDetailSharedConfig from './PlanDetailSharedConfig';
10 | import PlanDetailSharelinks from './PlanDetailSharelinks';
11 |
12 | const bootstrap = require('bootstrap');
13 |
14 | class PlanDetailPopup extends React.Component {
15 | constructor(props) {
16 | super(props);
17 |
18 | // this.props.shared;
19 | // this.props.planId;
20 |
21 | this.reqPlanGetDetail = this.reqPlanGetDetail.bind(this);
22 | this.tabs = {
23 | configs: "configs",
24 | shares: "sharedConfigs",
25 | generatedToken: "generatedToken",
26 | shareLinks: "shareLinks"
27 | }
28 |
29 | this.state = {
30 | tab: this.tabs.configs,
31 | plan: {
32 | name: "",
33 | remark: "",
34 | id: -1,
35 | createTime: "",
36 | modifyTime: "",
37 | configs: [],
38 | shares: [] // share id replace config id
39 | }
40 | }
41 | }
42 |
43 | __subPopupShow = "";
44 | __subPopupHide = "";
45 |
46 | componentDidMount() {
47 | let ele = document.getElementById("plan-detail-popup");
48 |
49 | // ele.addEventListener("hidden.bs.modal", this.props.onClose);
50 |
51 | this.popup = new bootstrap.Modal(ele, { backdrop: false, keyboard: false });
52 | this.popup.show();
53 |
54 | this.reqPlanGetDetail();
55 |
56 | this.__subPopupShow = PubSub.subscribe(overall.topics.mainPage.myPlan.planDetail.popupShow, () => this.popup.show());
57 | this.__subPopupHide = PubSub.subscribe(overall.topics.mainPage.myPlan.planDetail.popupHide, () => this.popup.hide());
58 | }
59 |
60 | componentWillUnmount() {
61 | PubSub.unsubscribe(this.__subPopupShow);
62 | PubSub.unsubscribe(this.__subPopupHide);
63 | }
64 |
65 | reqPlanGetDetail() {
66 | const handleReq = (j) => {
67 | if (j.status === "ok") {
68 | this.setState({ plan: j.data });
69 | } else {
70 | PubSub.publish(overall.topics.toast, { head: "plan detail", body: "failed to get plan detail: " + j.data, fine: false });
71 | }
72 | }
73 |
74 | if (this.props.shared) {
75 | apiReq.planGetByShare(
76 | { id: this.props.planId },
77 | handleReq
78 | )
79 | } else {
80 | apiReq.planGetById(
81 | { id: this.props.planId },
82 | handleReq
83 | )
84 | }
85 | }
86 |
87 | copyGenearteURLFromShare(shareId) {
88 | // this only work in HTTPS
89 | const url = window.location.protocol + "//" + window.location.host + overall.apiPath + "/generate-by-plan-share?shareId=" + shareId;
90 | if (navigator.clipboard !== undefined) {
91 | navigator.clipboard.writeText(url).then(
92 | () => { PubSub.publish(overall.topics.toast, { head: "plan detail", body: "success to copy generate url", fine: true }); },
93 | (e) => { PubSub.publish(overall.topics.toast, { head: "plan detail", body: "failed to copy generate url: " + e, fine: false }); },
94 | )
95 | } else {
96 | PubSub.publish(overall.topics.toast, { head: "plan detail", body: "the copy action is only available in https environment.", fine: false });
97 | }
98 | }
99 |
100 | switchTab(e, tab) {
101 | e.preventDefault();
102 | this.setState({ tab: tab });
103 | }
104 |
105 | render() {
106 | const planSummary =
107 |
108 |
109 |
110 |
111 | Plan Id:
112 |
113 |
114 |
115 | {this.state.plan.id}
116 |
117 |
118 |
119 |
120 | Create Time:
121 |
122 |
123 |
124 | {this.state.plan.createTime}
125 |
126 |
127 |
128 |
129 | Modify Time:
130 |
131 |
132 |
133 | {this.state.plan.modifyTime}
134 |
135 |
136 |
137 |
138 |
139 |
140 | Name:
141 |
142 |
143 |
144 | {this.state.plan.name}
145 |
146 | {this.props.shared &&
147 |
148 |
151 |
}
152 |
153 |
154 |
155 |
156 |
157 | Remark:
158 |
159 |
160 |
161 | {this.state.plan.remark}
162 |
163 |
164 |
165 |
166 |
167 | let tabs = (
168 |
196 | );
197 |
198 | let tabContent = null;
199 | switch (this.state.tab) {
200 | case this.tabs.configs:
201 | tabContent =
206 | break;
207 | case this.tabs.generatedToken:
208 | tabContent =
210 | break;
211 | case this.tabs.shares:
212 | tabContent =
217 | break;
218 | case this.tabs.shareLinks:
219 | tabContent =
221 | break;
222 |
223 | default:
224 | break;
225 | }
226 |
227 |
228 | return (
229 |
230 |
254 |
255 | )
256 | }
257 | }
258 |
259 | export default PlanDetailPopup;
260 |
--------------------------------------------------------------------------------
/src/mainPage/MyPlan.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 | import apiReq from '../apilib/apiReq';
4 | import overall from '../overall';
5 | import './MyPlan.css';
6 | import PlanDetailPopup from './PlanDetail';
7 | import SelectPanel from './PlanDetail/SelectPanel';
8 |
9 | const bootstrap = require('bootstrap');
10 |
11 | class MyPlan extends React.Component {
12 | constructor(props) {
13 | super(props);
14 |
15 | this.reqGetPlanList = this.reqGetPlanList.bind(this);
16 | this.reqPlanCreate = this.reqPlanCreate.bind(this);
17 | this.reqPlanRemove = this.reqPlanRemove.bind(this);
18 |
19 | this.handleReqGetPlanList = this.handleReqGetPlanList.bind(this);
20 | this.handleReqPlanCreate = this.handleReqPlanCreate.bind(this);
21 |
22 | this.handlePlanRemove = this.handlePlanRemove.bind(this);
23 | this.handlePlanRemoveConfirm = this.handlePlanRemoveConfirm.bind(this);
24 |
25 | this.handleAddPlan = this.handleAddPlan.bind(this);
26 | this.handleSaveNewPlan = this.handleSaveNewPlan.bind(this);
27 | this.handleDropNewPlan = this.handleDropNewPlan.bind(this);
28 |
29 | this.handlePlanModify = this.handlePlanModify.bind(this);
30 | this.handlePlanModifySave = this.handlePlanModifySave.bind(this);
31 | this.handlePlanModifyCancel = this.handlePlanModifyCancel.bind(this);
32 |
33 | this.onChange = this.onChange.bind(this);
34 |
35 | this.getPlansTableRows = this.getPlansTableRows.bind(this);
36 |
37 | this.state = {
38 | plans: [],
39 | currentOffset: 0,
40 | addPlan: false,
41 | planRemoveWarningId: -1,
42 | planDetailId: -1,
43 |
44 | editingPlan: {
45 | id: -1,
46 | name: "",
47 | remark: "",
48 | createTime: "",
49 | modifyTime: ""
50 | },
51 | newPlan: {
52 | name: "",
53 | remark: "",
54 | }
55 | };
56 | }
57 |
58 | componentDidMount() {
59 | this.reqGetPlanList(this.state.currentOffset);
60 | }
61 |
62 | reqGetPlanList(offset=0) {
63 | apiReq.planGetList(
64 | {
65 | sortBy: "id",
66 | offset: offset,
67 | count: 30
68 | },
69 | this.handleReqGetPlanList
70 | )
71 | }
72 |
73 | reqPlanCreate() {
74 | apiReq.planCreate(
75 | {
76 | name: this.state.newPlan.name,
77 | remark: this.state.newPlan.remark,
78 | },
79 | this.handleReqPlanCreate
80 | )
81 | }
82 |
83 | reqPlanRemove(planId) {
84 | apiReq.planRemove(
85 | {
86 | id: planId
87 | },
88 | (j) => {
89 | if (j.status === "ok") {
90 | PubSub.publish(overall.topics.toast, { head: "my plan", body: "plan remove successed.", fine: true });
91 | this.reqGetPlanList()
92 | } else {
93 | PubSub.publish(overall.topics.toast, { head: "my plan", body: "plan remove failed: " + j.data, fine: false });
94 | }
95 | }
96 | )
97 | }
98 |
99 | reqPlanModify(plan) {
100 | apiReq.planModify({
101 | id: plan.id,
102 | name: plan.name,
103 | remark: plan.remark
104 | }).then(
105 | (j) => {
106 | if (j.status === "ok") {
107 | PubSub.publish(overall.topics.toast, { head: "my plan", body: "plan modify successed.", fine: true });
108 | this.handlePlanModifyCancel();
109 | this.reqGetPlanList();
110 | } else {
111 | PubSub.publish(overall.topics.toast, { head: "my plan", body: "plan modify failed: " + j.data, fine: false });
112 | }
113 | }
114 | )
115 | }
116 |
117 | handleReqGetPlanList(j) {
118 | if (j.status === "ok") {
119 | this.setState({ plans: j.data.plans });
120 | } else {
121 | PubSub.publish(overall.topics.toast, {head: "my plan", body: "failed to get plans.\n" + j.data, fine: false});
122 | }
123 | }
124 |
125 | handleReqPlanCreate(j) {
126 | if (j.status === "ok") {
127 | this.setState({ addPlan: false, newPlan: { name: "", remark: "" } });
128 | this.reqGetPlanList(this.state.offset);
129 | PubSub.publish(overall.topics.toast, {head: "my plan", body: "create plan success", fine: true});
130 | } else {
131 | PubSub.publish(overall.topics.toast, {head: "my plan", body: "failed to create plan.\n" + j.data, fine: false});
132 | }
133 | }
134 |
135 | handleAddPlan() {
136 | this.setState({ addPlan: true });
137 | }
138 |
139 | handlePlanRemove(planId) {
140 | this.setState({planRemoveWarningId: planId});
141 | let popup = new bootstrap.Modal(document.getElementById("plan-remove-warning-popup"));
142 | popup.show();
143 | }
144 |
145 | handlePlanRemoveConfirm() {
146 | this.reqPlanRemove(this.state.planRemoveWarningId);
147 | }
148 |
149 | handleSaveNewPlan() {
150 | this.reqPlanCreate();
151 | }
152 |
153 | handleDropNewPlan() {
154 | this.setState({
155 | addPlan: false, // remove inputs
156 | newPlan: {
157 | name: "", // reset content in inputs
158 | remark: "",
159 | }
160 | })
161 | }
162 |
163 | handlePlanModify(planId) {
164 | this.setState((state, props) => {
165 | let i = state.plans.map(x => x.id).indexOf(planId);
166 | let p = state.plans[i];
167 | state.editingPlan = p;
168 | return state;
169 | });
170 | }
171 |
172 | handlePlanModifyCancel(e) {
173 | if (e !== undefined)
174 | e.stopPropagation();
175 | this.setState({ editingPlan: { id: -1, name: "", remark: "", createTime: "", modifyTime: "" } });
176 | }
177 |
178 | handlePlanModifySave(e) {
179 | e.stopPropagation();
180 | this.reqPlanModify(this.state.editingPlan);
181 | }
182 |
183 | onChange(subject, p, v) {
184 | this.setState((state, props) => {
185 | switch (subject) {
186 | case "newPlan":
187 | state.newPlan[p] = v;
188 | break;
189 | case "editingPlan":
190 | state.editingPlan[p] = v;
191 | break;
192 | default:
193 | break;
194 | }
195 | return state;
196 | });
197 | }
198 |
199 | getPlansTableRowsNew() {
200 | return (
201 |
202 | |
203 |
205 | |
206 |
207 | |
212 |
213 | |
218 |
219 |
221 | |
222 |
223 |
225 | |
226 |
227 |
230 |
233 | |
234 |
235 | )
236 | }
237 |
238 | getPlansTableRowsEditing(x) {
239 | return (
240 |
241 | |
242 |
244 | |
245 |
246 | |
251 |
252 | |
257 |
258 |
260 | |
261 |
262 |
264 | |
265 |
266 |
269 |
272 | |
273 |
274 | )
275 | }
276 |
277 | getPlansTableRows() {
278 | let planRows = [];
279 | for (let x of this.state.plans) {
280 | let r = null;
281 |
282 | if (this.state.editingPlan.id === x.id) {
283 | r = this.getPlansTableRowsEditing(x);
284 | } else {
285 | r =
286 |
this.setState({planDetailId: x.id})}>
287 | | {x.id} |
288 | {x.name} |
289 | {x.remark} |
290 | {x.createTime} |
291 | {x.modifyTime} |
292 |
293 |
297 |
301 | |
302 |
;
303 | }
304 |
305 | planRows.push(r);
306 | }
307 |
308 | // if adding new plan
309 | if (this.state.addPlan) {
310 | planRows.push(this.getPlansTableRowsNew());
311 | }
312 |
313 | if (planRows.length === 0) {
314 | planRows.push(
315 |
316 | |
317 |
318 |
319 | You have no plans yet...
320 |
321 |
322 | |
323 |
324 | );
325 | }
326 |
327 | return planRows;
328 | }
329 |
330 | getPlanRemoveWarning() {
331 | return (
332 |
348 | )
349 | }
350 |
351 | getPlanDetailPopup(planId) {
352 | return (
353 |
this.setState({ planDetailId: -1 })} />
354 | );
355 | }
356 |
357 | render() {
358 | return (
359 |
360 |
361 |
362 |
363 | | id |
364 | name |
365 | remark |
366 | create time |
367 | modify time |
368 | operating |
369 |
370 |
371 |
372 |
373 | {this.getPlansTableRows()}
374 |
375 |
376 |
377 | { this.state.addPlan ||
378 |
379 |
380 |
}
381 |
382 | {this.getPlanRemoveWarning()}
383 |
384 | {this.state.planDetailId >= 0 && this.getPlanDetailPopup(this.state.planDetailId)}
385 |
386 |
387 |
388 | )
389 | }
390 | }
391 |
392 | export default MyPlan;
393 |
--------------------------------------------------------------------------------
/src/mainPage/ConfigDetail/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PubSub from 'pubsub-js';
3 |
4 | import apiReq from '../../apilib/apiReq';
5 | import overall from '../../overall';
6 |
7 | const bootstrap = require('bootstrap');
8 |
9 | class ConfigDetail extends React.Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | // this.props.onModify;
14 | // this.props.onHidden;
15 | // this.props.configId;
16 | // this.props.shared;
17 | // this.props.newConfig;
18 |
19 | this.reqConfigCreate = this.reqConfigCreate.bind(this);
20 | this.reqConfigModify = this.reqConfigModify.bind(this);
21 | this.reqConfigGetById = this.reqConfigGetById.bind(this);
22 | this.reqConfigShareGetList = this.reqConfigShareGetList.bind(this);
23 | this.reqConfigShareModify = this.reqConfigShareModify.bind(this);
24 | this.reqConfigShareRevoke = this.reqConfigShareRevoke.bind(this);
25 | this.reqConfigShareCreate = this.reqConfigShareCreate.bind(this);
26 | this.hide = this.hide.bind(this);
27 | this.switchTab = this.switchTab.bind(this);
28 | this.getConfigContent = this.getConfigContent.bind(this);
29 | this.getShareLinks = this.getShareLinks.bind(this);
30 |
31 | this.tabs = {
32 | configContent: "configContent",
33 | shareLinks: "shareLinks"
34 | };
35 |
36 | this.state = {
37 | tab: "configContent",
38 | editShare: {
39 | id: -1,
40 | remark: ""
41 | },
42 | newShare: {
43 | exist: false,
44 | remark: ""
45 | },
46 | config: {
47 | id: -1,
48 | type: 2, // default is lesson config
49 | format: 1,
50 | name: "",
51 | content: "",
52 | remark: "",
53 | createTime: "",
54 | modifyTime: ""
55 | },
56 | shares: []
57 | }
58 | }
59 |
60 | componentDidMount() {
61 | let ele = document.getElementById("config-detail-popup");
62 | this.popup = new bootstrap.Modal(ele, {backdrop: false, keyboard: false});
63 | this.popup.show();
64 |
65 | if (this.props.newConfig) {
66 | return;
67 | }
68 |
69 | if (this.props.shared) {
70 | this.reqConfigGetByShare(this.props.configId);
71 | return;
72 | }
73 |
74 | this.reqConfigGetById(this.props.configId);
75 | this.reqConfigShareGetList(this.props.configId);
76 | }
77 |
78 | reqConfigCreate() {
79 | apiReq.configCreate(
80 | {
81 | name: this.state.config.name,
82 | type: this.state.config.type,
83 | format: this.state.config.format,
84 | content: this.state.config.content,
85 | remark: this.state.config.remark,
86 | },
87 | (j) => {
88 | if (j.status === "ok") {
89 | PubSub.publish(overall.topics.toast, { head: "new config", body: "success to create config", fine: true });
90 | } else {
91 | PubSub.publish(overall.topics.toast, { head: "new config", body: "failed to create config:" + j.data, fine: false });
92 | }
93 | }
94 | );
95 | }
96 |
97 | reqConfigModify() {
98 | apiReq.configMofidy(
99 | {
100 | id: this.state.config.id,
101 | name: this.state.config.name,
102 | content: this.state.config.content,
103 | format: this.state.config.format,
104 | remark: this.state.config.remark
105 | },
106 | (j) => {
107 | if (j.status === "ok") {
108 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "success to modify config", fine: true });
109 | } else {
110 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to modify config: " + j.data, fine: false });
111 | }
112 | }
113 | )
114 | }
115 |
116 | reqConfigGetByShare(shareId) {
117 | apiReq.configGetByShare(
118 | { id: shareId },
119 | (j) => {
120 | if (j.status === "ok") {
121 | this.setState({ config: j.data });
122 | } else {
123 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to get config detail from share:" + j.data, fine: false });
124 | }
125 | }
126 | )
127 | }
128 |
129 | reqConfigGetById(configId) {
130 | apiReq.configGetById(
131 | { id: configId },
132 | (j) => {
133 | if (j.status === "ok") {
134 | this.setState({ config: j.data });
135 | } else {
136 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to get config detail:" + j.data, fine: false });
137 | }
138 | }
139 | );
140 | }
141 |
142 | reqConfigShareGetList(configId) {
143 | apiReq.configshareGetList(
144 | { id: configId },
145 | (j) => {
146 | if (j.status === "ok") {
147 | this.setState({ shares: j.data.shares });
148 | } else {
149 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to get config share links:" + j.data, fine: false });
150 | }
151 | }
152 | )
153 | }
154 |
155 | reqConfigShareModify() {
156 | apiReq.configShareModify(
157 | { id: this.state.editShare.id, remark: this.state.editShare.remark},
158 | (j) => {
159 | if (j.status === "ok") {
160 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "success to modify config share links.", fine: true });
161 | this.setState({ editShare: { id: -1, remark: "" } });
162 |
163 | this.reqConfigShareGetList(this.props.configId);
164 | } else {
165 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to modify config share links:" + j.data, fine: false });
166 | }
167 | }
168 | )
169 | }
170 |
171 | reqConfigShareRevoke(shareId) {
172 | apiReq.configShareRevoke(
173 | { id: shareId },
174 | (j) => {
175 | if (j.status === "ok") {
176 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "success to remove share links.", fine: true });
177 |
178 | this.reqConfigShareGetList(this.props.configId);
179 | } else {
180 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to remove share links:" + j.data, fine: false });
181 | }
182 | }
183 | );
184 | }
185 |
186 | reqConfigShareCreate(remark) {
187 | apiReq.configShareCreate(
188 | { id: this.props.configId, remark: remark },
189 | (j) => {
190 | if (j.status === "ok") {
191 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "success to create share links.", fine: true });
192 |
193 | this.reqConfigShareGetList(this.props.configId);
194 | } else {
195 | PubSub.publish(overall.topics.toast, { head: "config detail", body: "failed to create share links:" + j.data, fine: false });
196 | }
197 | }
198 | );
199 | }
200 |
201 | hide(save) {
202 | if (save === true) {
203 | if (this.props.newConfig) {
204 | this.reqConfigCreate();
205 | } else {
206 | this.reqConfigModify();
207 | }
208 | this.popup.hide();
209 | this.props.onModify();
210 | } else {
211 | this.popup.hide();
212 | }
213 | this.props.onHidden();
214 | }
215 |
216 | switchTab(e, tab) {
217 | e.preventDefault();
218 | this.setState({ tab: tab });
219 | }
220 |
221 | getConfigContent() {
222 | return (
223 |
224 |
225 |
226 | {this.props.shared && Share Id: }
227 | {this.props.shared || Id: }
228 |
229 |
{this.state.config.id}
230 |
231 |
Type:
232 |
233 |
239 |
240 |
241 |
Create Time:
242 |
{this.state.config.createTime}
243 |
244 |
Modify Time:
245 |
{this.state.config.modifyTime}
246 |
247 |
248 |
Name:
249 |
250 |
254 |
255 |
256 |
Remark:
257 |
258 |
262 |
263 |
264 |
Content:
265 |
266 |
270 |
271 |
272 | )
273 | }
274 |
275 | getShareLinks() {
276 | let rows = [];
277 | for (let x of this.state.shares) {
278 | let tmp = (
279 |
280 | | {x.id} |
281 |
282 | {x.id === this.state.editShare.id &&
283 |
284 | | }
287 | {x.id === this.state.editShare.id ||
288 | {x.remark} | }
289 |
290 | {x.createTime} |
291 |
292 | {x.id === this.state.editShare.id &&
293 |
294 |
297 |
300 | |
301 | }
302 | {x.id === this.state.editShare.id ||
303 |
304 |
307 |
308 | | }
309 |
310 | );
311 | rows.push(tmp);
312 | }
313 |
314 | if (rows.length === 0) {
315 | rows.push(
316 |
317 | |
318 | No content now.
319 | |
320 |
321 | )
322 | }
323 |
324 | let newShare = null;
325 | if (this.state.newShare.exist)
326 | newShare = (
327 |
328 | |
329 |
330 | |
333 | |
334 |
335 |
336 |
339 |
342 | |
343 |
344 | )
345 |
346 | return (
347 |
348 |
349 |
350 |
351 | | Share Id |
352 | Remark |
353 | Create Time |
354 | Operating |
355 |
356 |
357 |
358 | {rows}
359 |
360 | {newShare}
361 |
362 |
363 |
364 | {this.state.newShare.exist ||
365 |
366 |
367 |
}
368 |
369 | )
370 | }
371 |
372 | render() {
373 | return (
374 |
375 |
422 |
423 | )
424 | }
425 | }
426 |
427 | export default ConfigDetail;
428 |
--------------------------------------------------------------------------------