Commit cfc0aea5 authored by ddcat1115's avatar ddcat1115 Committed by GitHub

Dva@2 (#13)

* temp save

* upgrade to dva@2

* update

* fix ci

* remove useless Link & add missing `to` prop setting
parent 9e5bbe7a
...@@ -113,6 +113,8 @@ export const getNotice = [ ...@@ -113,6 +113,8 @@ export const getNotice = [
description: '那是一种内在的东西, 他们到达不了,也无法触及的', description: '那是一种内在的东西, 他们到达不了,也无法触及的',
updatedAt: new Date(), updatedAt: new Date(),
member: '科学搬砖组', member: '科学搬砖组',
href: '',
memberLink: '',
}, },
{ {
id: 'xxx2', id: 'xxx2',
...@@ -121,6 +123,8 @@ export const getNotice = [ ...@@ -121,6 +123,8 @@ export const getNotice = [
description: '希望是一个好东西,也许是最好的,好东西是不会消亡的', description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
updatedAt: new Date('2017-07-24 11:00:00'), updatedAt: new Date('2017-07-24 11:00:00'),
member: '全组都是吴彦祖', member: '全组都是吴彦祖',
href: '',
memberLink: '',
}, },
{ {
id: 'xxx3', id: 'xxx3',
...@@ -129,6 +133,8 @@ export const getNotice = [ ...@@ -129,6 +133,8 @@ export const getNotice = [
description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
updatedAt: new Date(), updatedAt: new Date(),
member: '中二少女团', member: '中二少女团',
href: '',
memberLink: '',
}, },
{ {
id: 'xxx4', id: 'xxx4',
...@@ -137,6 +143,8 @@ export const getNotice = [ ...@@ -137,6 +143,8 @@ export const getNotice = [
description: '那时候我只会想自己想要什么,从不想自己拥有什么', description: '那时候我只会想自己想要什么,从不想自己拥有什么',
updatedAt: new Date('2017-07-23 06:23:00'), updatedAt: new Date('2017-07-23 06:23:00'),
member: '程序员日常', member: '程序员日常',
href: '',
memberLink: '',
}, },
{ {
id: 'xxx5', id: 'xxx5',
...@@ -145,6 +153,8 @@ export const getNotice = [ ...@@ -145,6 +153,8 @@ export const getNotice = [
description: '凛冬将至', description: '凛冬将至',
updatedAt: new Date('2017-07-23 06:23:00'), updatedAt: new Date('2017-07-23 06:23:00'),
member: '高逼格设计天团', member: '高逼格设计天团',
href: '',
memberLink: '',
}, },
{ {
id: 'xxx6', id: 'xxx6',
...@@ -153,6 +163,8 @@ export const getNotice = [ ...@@ -153,6 +163,8 @@ export const getNotice = [
description: '生命就像一盒巧克力,结果往往出人意料', description: '生命就像一盒巧克力,结果往往出人意料',
updatedAt: new Date('2017-07-23 06:23:00'), updatedAt: new Date('2017-07-23 06:23:00'),
member: '骗你来学计算机', member: '骗你来学计算机',
href: '',
memberLink: '',
}, },
]; ];
......
...@@ -17,15 +17,16 @@ ...@@ -17,15 +17,16 @@
}, },
"dependencies": { "dependencies": {
"antd": "next", "antd": "next",
"dva": "^2.0.3",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"dva": "^1.2.1",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"qs": "^6.5.0", "qs": "^6.5.0",
"react": "^15.6.2", "react": "^15.6.2",
"react-document-title": "^2.0.3", "react-document-title": "^2.0.3",
"react-dom": "^15.6.2" "react-dom": "^15.6.2",
"lodash.clonedeep": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^8.0.1", "babel-eslint": "^8.0.1",
...@@ -56,7 +57,7 @@ ...@@ -56,7 +57,7 @@
"nightmare": "^2.10.0", "nightmare": "^2.10.0",
"react-test-renderer": "^15.6.2", "react-test-renderer": "^15.6.2",
"redbox-react": "^1.3.2", "redbox-react": "^1.3.2",
"roadhog": "^1.0.2", "roadhog": "^1.2.1",
"roadhog-api-doc": "^0.1.8", "roadhog-api-doc": "^0.1.8",
"stylelint": "^8.1.0", "stylelint": "^8.1.0",
"stylelint-config-standard": "^17.0.0" "stylelint-config-standard": "^17.0.0"
......
...@@ -34,6 +34,7 @@ import RegisterResult from '../routes/User/RegisterResult'; ...@@ -34,6 +34,7 @@ import RegisterResult from '../routes/User/RegisterResult';
const data = [{ const data = [{
component: BasicLayout, component: BasicLayout,
layout: 'BasicLayout',
name: '首页', // for breadcrumb name: '首页', // for breadcrumb
path: '', path: '',
children: [{ children: [{
...@@ -152,6 +153,7 @@ const data = [{ ...@@ -152,6 +153,7 @@ const data = [{
}], }],
}, { }, {
component: UserLayout, component: UserLayout,
layout: 'UserLayout',
children: [{ children: [{
name: '帐户', name: '帐户',
icon: 'user', icon: 'user',
......
...@@ -18,6 +18,8 @@ export default class PageHeader extends PureComponent { ...@@ -18,6 +18,8 @@ export default class PageHeader extends PureComponent {
static contextTypes = { static contextTypes = {
routes: PropTypes.array, routes: PropTypes.array,
params: PropTypes.object, params: PropTypes.object,
location: PropTypes.object,
breadcrumbNameMap: PropTypes.object,
}; };
onChange = (key) => { onChange = (key) => {
if (this.props.onTabChange) { if (this.props.onTabChange) {
...@@ -28,10 +30,12 @@ export default class PageHeader extends PureComponent { ...@@ -28,10 +30,12 @@ export default class PageHeader extends PureComponent {
return { return {
routes: this.props.routes || this.context.routes, routes: this.props.routes || this.context.routes,
params: this.props.params || this.context.params, params: this.props.params || this.context.params,
location: this.props.location || this.context.location,
breadcrumbNameMap: this.props.breadcrumbNameMap || this.context.breadcrumbNameMap,
}; };
}; };
render() { render() {
const { routes, params } = this.getBreadcrumbProps(); const { routes, params, location, breadcrumbNameMap } = this.getBreadcrumbProps();
const { title, logo, action, content, extraContent, const { title, logo, action, content, extraContent,
breadcrumbList, tabList, className } = this.props; breadcrumbList, tabList, className } = this.props;
const clsString = classNames(styles.pageHeader, className); const clsString = classNames(styles.pageHeader, className);
...@@ -45,6 +49,28 @@ export default class PageHeader extends PureComponent { ...@@ -45,6 +49,28 @@ export default class PageHeader extends PureComponent {
itemRender={itemRender} itemRender={itemRender}
/> />
); );
} else if (location && location.pathname) {
const pathSnippets = location.pathname.split('/').filter(i => i);
const extraBreadcrumbItems = pathSnippets.map((_, index) => {
const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
return (
<Breadcrumb.Item key={url}>
<Link to={url}>
{breadcrumbNameMap[url] || breadcrumbNameMap[url.replace('/', '')] || url}
</Link>
</Breadcrumb.Item>
);
});
const breadcrumbItems = [(
<Breadcrumb.Item key="home">
<Link to="/">Home</Link>
</Breadcrumb.Item>
)].concat(extraBreadcrumbItems);
breadcrumb = (
<Breadcrumb className={styles.breadcrumb}>
{breadcrumbItems}
</Breadcrumb>
);
} else if (breadcrumbList && breadcrumbList.length) { } else if (breadcrumbList && breadcrumbList.length) {
breadcrumb = ( breadcrumb = (
<Breadcrumb className={styles.breadcrumb}> <Breadcrumb className={styles.breadcrumb}>
......
import dva from 'dva'; import dva from 'dva';
import G2 from 'g2'; import G2 from 'g2';
// import { browserHistory } from 'dva/router';
import 'moment/locale/zh-cn'; import 'moment/locale/zh-cn';
import models from './models'; import models from './models';
// import { browserHistory } from 'dva/router';
import './index.less'; import './index.less';
G2.track(false); G2.track(false);
...@@ -16,7 +15,7 @@ const app = dva({ ...@@ -16,7 +15,7 @@ const app = dva({
// 2. Plugins // 2. Plugins
// app.use({}); // app.use({});
// 3. Model // 3. Model move to router
models.forEach((m) => { models.forEach((m) => {
app.model(m); app.model(m);
}); });
......
...@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; ...@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Layout, Menu, Icon, Avatar, Dropdown, Tag, message, Spin } from 'antd'; import { Layout, Menu, Icon, Avatar, Dropdown, Tag, message, Spin } from 'antd';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import { connect } from 'dva'; import { connect } from 'dva';
import { Link, routerRedux } from 'dva/router'; import { Link, routerRedux, Route, Redirect, Switch } from 'dva/router';
import moment from 'moment'; import moment from 'moment';
import groupBy from 'lodash/groupBy'; import groupBy from 'lodash/groupBy';
import styles from './BasicLayout.less'; import styles from './BasicLayout.less';
...@@ -11,14 +11,15 @@ import HeaderSearch from '../components/HeaderSearch'; ...@@ -11,14 +11,15 @@ import HeaderSearch from '../components/HeaderSearch';
import NoticeIcon from '../components/NoticeIcon'; import NoticeIcon from '../components/NoticeIcon';
import GlobalFooter from '../components/GlobalFooter'; import GlobalFooter from '../components/GlobalFooter';
import { getNavData } from '../common/nav'; import { getNavData } from '../common/nav';
import { getRouteData } from '../utils/utils';
const { Header, Sider, Content } = Layout; const { Header, Sider, Content } = Layout;
const { SubMenu } = Menu; const { SubMenu } = Menu;
class BasicLayout extends React.PureComponent { class BasicLayout extends React.PureComponent {
static childContextTypes = { static childContextTypes = {
routes: PropTypes.array, location: PropTypes.object,
params: PropTypes.object, breadcrumbNameMap: PropTypes.object,
} }
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -29,8 +30,14 @@ class BasicLayout extends React.PureComponent { ...@@ -29,8 +30,14 @@ class BasicLayout extends React.PureComponent {
}; };
} }
getChildContext() { getChildContext() {
const { routes, params } = this.props; const { location } = this.props;
return { routes, params }; const routeData = getRouteData('BasicLayout');
const menuData = getNavData().reduce((arr, current) => arr.concat(current.children), []);
const breadcrumbNameMap = {};
routeData.concat(menuData).forEach((item) => {
breadcrumbNameMap[item.path] = item.name;
});
return { location, breadcrumbNameMap };
} }
componentDidMount() { componentDidMount() {
this.props.dispatch({ this.props.dispatch({
...@@ -98,13 +105,15 @@ class BasicLayout extends React.PureComponent { ...@@ -98,13 +105,15 @@ class BasicLayout extends React.PureComponent {
}); });
} }
getPageTitle() { getPageTitle() {
const { routes } = this.props; const { location } = this.props;
for (let i = routes.length - 1; i >= 0; i -= 1) { const { pathname } = location;
if (routes[i].breadcrumbName) { let title = 'Ant Design Pro';
return `${routes[i].breadcrumbName} - Ant Design Pro`; getRouteData('UserLayout').forEach((item) => {
if (item.path === pathname) {
title = `${item.name} - Ant Design Pro`;
} }
} });
return 'Ant Design Pro'; return title;
} }
getNoticeData() { getNoticeData() {
const { notices = [] } = this.props; const { notices = [] } = this.props;
...@@ -161,7 +170,7 @@ class BasicLayout extends React.PureComponent { ...@@ -161,7 +170,7 @@ class BasicLayout extends React.PureComponent {
} }
} }
render() { render() {
const { children, currentUser, collapsed, fetchingNotices } = this.props; const { currentUser, collapsed, fetchingNotices } = this.props;
const menu = ( const menu = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}> <Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
...@@ -171,7 +180,6 @@ class BasicLayout extends React.PureComponent { ...@@ -171,7 +180,6 @@ class BasicLayout extends React.PureComponent {
<Menu.Item key="logout"><Icon type="logout" />退出登录</Menu.Item> <Menu.Item key="logout"><Icon type="logout" />退出登录</Menu.Item>
</Menu> </Menu>
); );
const noticeData = this.getNoticeData(); const noticeData = this.getNoticeData();
// Don't show popup menu when it is been collapsed // Don't show popup menu when it is been collapsed
...@@ -270,7 +278,21 @@ class BasicLayout extends React.PureComponent { ...@@ -270,7 +278,21 @@ class BasicLayout extends React.PureComponent {
</div> </div>
</Header> </Header>
<Content style={{ margin: '24px 24px 0', height: '100%' }}> <Content style={{ margin: '24px 24px 0', height: '100%' }}>
{children} <Switch>
{
getRouteData('BasicLayout').map(item =>
(
<Route
exact={item.exact}
key={item.path}
path={item.path}
component={item.component}
/>
)
)
}
<Redirect to="/dashboard/analysis" />
</Switch>
<GlobalFooter <GlobalFooter
links={[{ links={[{
title: '帮助', title: '帮助',
......
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Link } from 'dva/router'; import { Link, Route } from 'dva/router';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import { Icon } from 'antd'; import { Icon } from 'antd';
import GlobalFooter from '../components/GlobalFooter'; import GlobalFooter from '../components/GlobalFooter';
import styles from './UserLayout.less'; import styles from './UserLayout.less';
import { getRouteData } from '../utils/utils';
const links = [{ const links = [{
title: '帮助', title: '帮助',
...@@ -21,25 +22,24 @@ const copyright = <div>Copyright <Icon type="copyright" /> 2017 蚂蚁金服体 ...@@ -21,25 +22,24 @@ const copyright = <div>Copyright <Icon type="copyright" /> 2017 蚂蚁金服体
class UserLayout extends React.PureComponent { class UserLayout extends React.PureComponent {
static childContextTypes = { static childContextTypes = {
routes: PropTypes.array, location: PropTypes.object,
params: PropTypes.object,
} }
getChildContext() { getChildContext() {
const { routes, params } = this.props; const { location } = this.props;
return { routes, params }; return { location };
} }
getPageTitle() { getPageTitle() {
const { routes } = this.props; const { location } = this.props;
for (let i = routes.length - 1; i >= 0; i -= 1) { const { pathname } = location;
if (routes[i].breadcrumbName) { let title = 'Ant Design Pro';
return `${routes[i].breadcrumbName} - Ant Design Pro`; getRouteData('UserLayout').forEach((item) => {
if (item.path === pathname) {
title = `${item.name} - Ant Design Pro`;
} }
} });
return 'Ant Design Pro'; return title;
} }
render() { render() {
const { children } = this.props;
return ( return (
<DocumentTitle title={this.getPageTitle()}> <DocumentTitle title={this.getPageTitle()}>
<div className={styles.container}> <div className={styles.container}>
...@@ -52,7 +52,18 @@ class UserLayout extends React.PureComponent { ...@@ -52,7 +52,18 @@ class UserLayout extends React.PureComponent {
</div> </div>
<p className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</p> <p className={styles.desc}>Ant Design 是西湖区最具影响力的 Web 设计规范</p>
</div> </div>
{children} {
getRouteData('UserLayout').map(item =>
(
<Route
exact={item.exact}
key={item.path}
path={item.path}
component={item.component}
/>
)
)
}
<GlobalFooter className={styles.footer} links={links} copyright={copyright} /> <GlobalFooter className={styles.footer} links={links} copyright={copyright} />
</div> </div>
</DocumentTitle> </DocumentTitle>
......
import React from 'react'; import React from 'react';
import { Router, Route, Redirect } from 'dva/router'; import { Router, Route, Switch, Redirect } from 'dva/router';
import { LocaleProvider } from 'antd'; import { LocaleProvider } from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN'; import zhCN from 'antd/lib/locale-provider/zh_CN';
import navData from './common/nav'; import BasicLayout from './layouts/BasicLayout';
import UserLayout from './layouts/UserLayout';
function getRoutes(data, level = 0) {
return data.map((item, i) => {
let children;
if (item.children) {
children = getRoutes(item.children, level + 1);
}
let homePageRedirect;
if (level === 1 && i === 0) {
let indexPath;
// First children router
if (item.children && item.children[0]) {
indexPath = `/${item.path}/${item.children[0].path}`;
} else {
indexPath = item.path;
}
homePageRedirect = <Redirect from="/" to={indexPath} />;
}
if (item.noRoute) {
return null;
}
return (
<Route
key={item.key || item.path || ''}
path={item.path}
breadcrumbName={item.name}
component={item.component}
>
{homePageRedirect}
{children}
</Route>
);
});
}
function RouterConfig({ history }) { function RouterConfig({ history }) {
return ( return (
<LocaleProvider locale={zhCN}> <LocaleProvider locale={zhCN}>
<Router history={history}> <Router history={history}>
{getRoutes(navData)} <Switch>
<Route path="/user" component={UserLayout} />
<Route path="/" component={BasicLayout} />
<Redirect to="/" />
</Switch>
</Router> </Router>
</LocaleProvider> </LocaleProvider>
); );
......
import React, { cloneElement, PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'dva'; import { connect } from 'dva';
import { Card, Steps, Form } from 'antd'; import { Card, Steps, Form } from 'antd';
import PageHeaderLayout from '../../../layouts/PageHeaderLayout'; import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
import Step1 from './Step1'; import Step1 from './Step1';
import Step2 from './Step2';
import Step3 from './Step3';
import styles from '../style.less'; import styles from '../style.less';
const { Step } = Steps; const { Step } = Steps;
...@@ -10,16 +12,26 @@ const { Step } = Steps; ...@@ -10,16 +12,26 @@ const { Step } = Steps;
@Form.create() @Form.create()
class StepForm extends PureComponent { class StepForm extends PureComponent {
getCurrentStep() { getCurrentStep() {
const { routes } = this.props; const { location } = this.props;
switch (routes[routes.length - 1].path) { const { pathname } = location;
const pathList = pathname.split('/');
switch (pathList[pathList.length - 1]) {
case 'step-form': return 0; case 'step-form': return 0;
case 'confirm': return 1; case 'confirm': return 1;
case 'result': return 2; case 'result': return 2;
default: return 0; default: return 0;
} }
} }
getCurrentComponent() {
const componentMap = {
0: Step1,
1: Step2,
2: Step3,
};
return componentMap[this.getCurrentStep()];
}
render() { render() {
const { form, stepFormData, submitting, dispatch, children } = this.props; const { form, stepFormData, submitting, dispatch } = this.props;
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
span: 5, span: 5,
...@@ -28,6 +40,7 @@ class StepForm extends PureComponent { ...@@ -28,6 +40,7 @@ class StepForm extends PureComponent {
span: 19, span: 19,
}, },
}; };
const CurrentComponent = this.getCurrentComponent();
return ( return (
<PageHeaderLayout title="分步表单" content="将表单内容进行分步可以提高用户处理的专注度,降低页面复杂性。"> <PageHeaderLayout title="分步表单" content="将表单内容进行分步可以提高用户处理的专注度,降低页面复杂性。">
<Card bordered={false}> <Card bordered={false}>
...@@ -37,19 +50,13 @@ class StepForm extends PureComponent { ...@@ -37,19 +50,13 @@ class StepForm extends PureComponent {
<Step title="确认转账信息" /> <Step title="确认转账信息" />
<Step title="完成" /> <Step title="完成" />
</Steps> </Steps>
{children ? cloneElement(children, { <CurrentComponent
form, formItemLayout={formItemLayout}
formItemLayout, form={form}
data: stepFormData, dispatch={dispatch}
submitting, data={stepFormData}
dispatch, submitting={submitting}
}) : ( />
<Step1
formItemLayout={formItemLayout}
form={form}
dispatch={dispatch}
/>
)}
</div> </div>
</Card> </Card>
</PageHeaderLayout> </PageHeaderLayout>
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import moment from 'moment'; import moment from 'moment';
import { connect } from 'dva'; import { connect } from 'dva';
import { Link, routerRedux } from 'dva/router'; import { routerRedux } from 'dva/router';
import { Row, Col, Form, Card, Select, List, Input } from 'antd'; import { Row, Col, Form, Card, Select, List, Input } from 'antd';
import PageHeaderLayout from '../../layouts/PageHeaderLayout'; import PageHeaderLayout from '../../layouts/PageHeaderLayout';
...@@ -78,33 +78,31 @@ export default class CoverCardList extends PureComponent { ...@@ -78,33 +78,31 @@ export default class CoverCardList extends PureComponent {
dataSource={list} dataSource={list}
renderItem={item => ( renderItem={item => (
<List.Item> <List.Item>
<Link> <Card
<Card hoverable
hoverable cover={<img alt={item.title} src={item.cover} />}
cover={<img alt={item.title} src={item.cover} />} >
> <Card.Meta
<Card.Meta title={item.title}
title={item.title} description={item.subDescription}
description={item.subDescription} />
/> <div className={styles.cardItemContent}>
<div className={styles.cardItemContent}> <span>{moment(item.updatedAt).fromNow()}</span>
<span>{moment(item.updatedAt).fromNow()}</span> <div className={styles.avatarList}>
<div className={styles.avatarList}> <AvatarList size="mini">
<AvatarList size="mini"> {
{ item.members.map((member, i) => (
item.members.map((member, i) => ( <AvatarList.Item
<AvatarList.Item key={`${item.id}-avatar-${i}`}
key={`${item.id}-avatar-${i}`} src={member.avatar}
src={member.avatar} tips={member.name}
tips={member.name} />
/> ))
)) }
} </AvatarList>
</AvatarList>
</div>
</div> </div>
</Card> </div>
</Link> </Card>
</List.Item> </List.Item>
)} )}
/> />
......
import moment from 'moment'; import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import navData from '../common/nav';
export function fixedZero(val) { export function fixedZero(val) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
...@@ -48,3 +51,31 @@ export function getTimeDistance(type) { ...@@ -48,3 +51,31 @@ export function getTimeDistance(type) {
return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)]; return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
} }
} }
function getPlainNode(nodeList, parentPath = '') {
const arr = [];
nodeList.forEach((node) => {
const item = node;
item.path = `${parentPath}/${item.path || ''}`.replace(/\/+/g, '/');
item.exact = true;
if (item.children && !item.component) {
arr.push(...getPlainNode(item.children, item.path));
} else {
if (item.children && item.component) {
item.exact = false;
}
arr.push(item);
}
});
return arr;
}
export function getRouteData(path) {
if (!navData.some(item => item.layout === path) ||
!(navData.filter(item => item.layout === path)[0].children)) {
return null;
}
const dataList = cloneDeep(navData.filter(item => item.layout === path)[0]);
const nodeList = getPlainNode(dataList.children);
return nodeList;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment