Commit 89912a28 by zhanghaozhe

Merge branch 'formik' into dev

parents 0cb27bb9 4d4316e7
......@@ -15,4 +15,11 @@
border: 0;
outline: 0;
-webkit-appearance: none;
}
.screen {
position: relative;
width: 375px;
height: 667px;
background: #fff;
}
\ No newline at end of file
......@@ -4,25 +4,25 @@
"private": true,
"dependencies": {
"@babel/core": "7.9.0",
"@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/runtime": "^7.7.7",
"@loadable/component": "^5.10.1",
"@babel/plugin-proposal-decorators": "^7.10.5",
"@loadable/component": "^5.13.1",
"@svgr/webpack": "4.3.3",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/classnames": "^2.2.10",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.53",
"@types/node": "^12.12.54",
"@types/qs": "^6.9.4",
"@types/react": "^16.9.43",
"@types/react": "^16.9.44",
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.5",
"@types/redux-logger": "^3.0.8",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"antd-mobile": "^2.3.1",
"autoprefixer": "^9.6.0",
"antd-mobile": "^2.3.3",
"autoprefixer": "^9.8.6",
"axios": "^0.19.2",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.1.0",
......@@ -34,9 +34,9 @@
"callapp-lib": "^2.1.8",
"camelcase": "^5.3.1",
"case-sensitive-paths-webpack-plugin": "2.3.0",
"crypto-js": "^3.1.9-1",
"crypto-js": "^3.3.0",
"css-loader": "3.4.2",
"date-fns": "^2.14.0",
"date-fns": "^2.15.0",
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0",
"eslint": "^6.6.0",
......@@ -48,21 +48,21 @@
"eslint-plugin-react": "7.19.0",
"eslint-plugin-react-hooks": "^1.6.1",
"file-loader": "4.3.0",
"formik": "^1.5.8",
"formik": "^2.1.5",
"fs-extra": "^8.1.0",
"html-webpack-plugin": "4.0.0-beta.11",
"html2canvas": "^1.0.0-rc.5",
"http-proxy-middleware": "^0.19.1",
"http-proxy-middleware": "^0.19.2",
"identity-obj-proxy": "3.0.0",
"jest": "24.9.0",
"jest-environment-jsdom-fourteen": "1.0.1",
"jest-pnp-resolver": "1.0.2",
"jest-resolve": "24.9.0",
"jest-watch-typeahead": "0.4.2",
"js-base64": "^2.5.1",
"js-cookie": "^2.2.0",
"js-base64": "^2.6.4",
"js-cookie": "^2.2.1",
"json-stringify-safe": "^5.0.1",
"less": "^3.9.0",
"less": "^3.12.2",
"less-loader": "^4.1.0",
"lodash": "^4.17.19",
"mini-css-extract-plugin": "0.9.0",
......@@ -76,21 +76,21 @@
"postcss-safe-parser": "4.0.1",
"prop-types": "^15.7.2",
"qrcode": "^1.4.4",
"qs": "^6.7.0",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-ace": "^8.0.0",
"react-ace": "^8.1.0",
"react-app-polyfill": "^1.0.6",
"react-copy-to-clipboard": "^5.0.1",
"react-copy-to-clipboard": "^5.0.2",
"react-dev-utils": "^10.2.1",
"react-dom": "^16.13.1",
"react-infinite-scroller": "^1.2.4",
"react-lazy-load": "^3.0.13",
"react-lazy-load": "^3.1.13",
"react-mobile-swiper": "^1.1.4",
"react-redux": "^7.0.2",
"react-redux": "^7.2.1",
"react-router-dom": "^5.2.0",
"react-spinners": "^0.5.4",
"react-spinners": "^0.9.0",
"react-sticky": "^6.0.3",
"redux": "^4.0.1",
"redux": "^4.0.5",
"redux-immutable": "^4.0.0",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
......@@ -98,7 +98,7 @@
"resolve-url-loader": "3.1.1",
"sass-loader": "8.0.2",
"semver": "6.3.0",
"socket.io": "^2.2.0",
"socket.io": "^2.3.0",
"store2": "^2.11.2",
"style-loader": "0.23.1",
"swiper": "^4.5.1",
......@@ -106,8 +106,8 @@
"ts-pnp": "1.1.6",
"typescript": "^3.7.5",
"url-loader": "2.3.0",
"video.js": "^7.6.5",
"web-launch-app": "^2.1.9",
"video.js": "^7.8.4",
"web-launch-app": "^2.2.4",
"webpack": "4.42.0",
"webpack-dev-server": "^3.11.0",
"webpack-manifest-plugin": "2.2.0",
......@@ -123,27 +123,37 @@
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"resolver": "jest-pnp-resolver",
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx,ts,tsx}"
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"testURL": "http://localhost",
"testEnvironment": "jest-environment-jsdom-fourteen",
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
......@@ -153,6 +163,7 @@
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
......@@ -170,8 +181,8 @@
"node"
],
"watchPlugins": [
"/Users/baiguangyao/project/my-julyedu/node_modules/jest-watch-typeahead/filename.js",
"/Users/baiguangyao/project/my-julyedu/node_modules/jest-watch-typeahead/testname.js"
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
]
},
"babel": {
......@@ -195,20 +206,20 @@
]
},
"devDependencies": {
"@babel/runtime": "^7.7.2",
"@babel/runtime": "^7.11.2",
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/addon-links": "^5.3.19",
"@storybook/addons": "^5.3.19",
"@storybook/preset-typescript": "^3.0.0",
"@storybook/react": "^5.3.19",
"babel-plugin-import": "^1.11.0",
"browserslist": "^4.6.6",
"caniuse-lite": "^1.0.30000989",
"babel-plugin-import": "^1.13.0",
"browserslist": "^4.14.0",
"caniuse-lite": "^1.0.30001112",
"classnames": "^2.2.6",
"fork-ts-checker-webpack-plugin": "^5.0.14",
"mockjs": "^1.0.1-beta3",
"postcss-px-to-viewport": "^1.1.0",
"mockjs": "^1.1.0",
"postcss-px-to-viewport": "^1.1.1",
"ts-loader": "^8.0.2"
},
"theme": "./src/assets/theme/config.js"
......
......@@ -50,7 +50,8 @@ class App extends Component {
firstLoad = true
componentWillMount() {
componentDidMount() {
let url = window.location.href
if (url.indexOf('ccode') > -1) {
if (!getParam('ccode').includes('%')) {
......@@ -61,9 +62,8 @@ class App extends Component {
})
}
}
}
componentDidMount() {
//是否显示宝箱全局入口
this.isShowGlobalEntryInTime()
......
import React, {Component} from 'react'
import './index.scss'
import MaskCover from "../cover";
interface PersonalInfo {
name: string
phone: string
address: string
}
interface Props extends PersonalInfo {
subtitle: string
title?: string
onSubmit?: () => PersonalInfo
}
class Address extends Component<Props> {
render() {
return <MaskCover>
<div className="address-container">
<div className="title"></div>
<div className="subtitle"></div>
</div>
</MaskCover>
}
}
export default Address
......@@ -23,7 +23,7 @@ class AddressPopup extends Component {
// 获取收货信息
fetchUserAddress = () => {
const { addressInfo } = this.state;
const {addressInfo} = this.state;
http.get(`${API.home}/sys/user_address_info`).then(res => {
const {code, data, msg} = res.data;
if (code === 200) {
......@@ -40,10 +40,10 @@ class AddressPopup extends Component {
}
handleToSubmit = (params = {}) => {
const { successBindAddress } = this.props;
const {successBindAddress} = this.props;
http.post(`${API.home}/sys/update_address`, {
act_type: 'treasure',
...params
...params,
}).then(res => {
const {code, msg} = res.data;
if (code === 200) {
......@@ -55,15 +55,15 @@ class AddressPopup extends Component {
}
render() {
const { isLoading, addressInfo } = this.state;
const {isLoading, addressInfo} = this.state;
const {tip, prize, skip = 'default'} = this.props;
return (
<>
{
isLoading &&
<Formik
initialValues={{
...addressInfo
initialValues={{
...addressInfo,
}}
validate={({name, phone, address}) => {
const errors = {};
......@@ -71,7 +71,7 @@ class AddressPopup extends Component {
if (!name) {
errors.name = '请输入收件人';
}
if(!/^1[3-9]\d{9}$/.test(phone)) {
if (!/^1[3-9]\d{9}$/.test(phone)) {
errors.phone = '请填写正确格式的手机号';
}
if (!address) {
......@@ -85,79 +85,84 @@ class AddressPopup extends Component {
onSubmit={(values) => {
this.handleToSubmit(values);
}}
render={({errors}) => (
<Form className="address-form" data-skip={skip}>
<h2 className="address-form__title">收货信息</h2>
{
prize ? (
<p className='address__prize'>
您抽中了
<span style={{'color': '#FF4000'}}>{prize}</span>
</p>
) : (null)
}
{
tip ? (<div className="address-form__subtitle">{tip}</div>) : (<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
}
<Field
name="name"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收件人"
/>
{
errors.name &&
<p className="address-form__tip">{errors.name}</p>
}
</div>
)}
/>
<Field
name="phone"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="联系方式"
/>
{
errors.phone &&
<p className="address-form__tip">{errors.phone}</p>
}
</div>
)}
/>
<Field
name="address"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收货地址"
/>
{
errors.address &&
<p className="address-form__tip">{errors.address}</p>
}
</div>
)}
/>
<button
className="address-form__submit"
data-status="do"
type="submit"
>提交</button>
</Form>
)}
/>
>
{
({errors}) => (
<Form className="address-form" data-skip={skip}>
<h2 className="address-form__title">收货信息</h2>
{
prize ? (
<p className='address__prize'>
您抽中了
<span style={{'color': '#FF4000'}}>{prize}</span>
</p>
) : (null)
}
{
tip ? (<div className="address-form__subtitle">{tip}</div>) : (
<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
}
<Field
name="name"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收件人"
/>
{
errors.name &&
<p className="address-form__tip">{errors.name}</p>
}
</div>
)}
/>
<Field
name="phone"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="联系方式"
/>
{
errors.phone &&
<p className="address-form__tip">{errors.phone}</p>
}
</div>
)}
/>
<Field
name="address"
render={({field}) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收货地址"
/>
{
errors.address &&
<p className="address-form__tip">{errors.address}</p>
}
</div>
)}
/>
<button
className="address-form__submit"
data-status="do"
type="submit"
>提交
</button>
</Form>
)
}
</Formik>
}
</>
);
......
......@@ -177,69 +177,72 @@ class BindPhone extends Component {
});
this.toBindPhone();
}}
render={({values: {tel, code}, errors}) => (
<Form className="popup-form" data-skip={skip}>
<h2 className="popup-form__title">绑定手机号</h2>
{
desc &&
<div className="poup-form__desc">{desc}</div>
}
<div className="popup-form__item">
<a className="popup-form__button--num" onClick={this.toFetchCountryNum}>
+{country.num}
<i className="iconfont iconiconfront-69"/>
</a>
<Field
name="tel"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt"
data-type="tel"
type="text"
placeholder="请填写手机号"
/>
);
}}
/>
</div>
<CaptchaAli getInstance={this.getCaptchaInstance} onVerify={this.onVerify} mb={15}/>
<div className="popup-form__item">
<Field
name="code"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt popup-form__ipt--left"
type="text"
placeholder="输入验证码"
/>
);
}}
/>
>
{
({values: {tel, code}, errors}) => (
<Form className="popup-form" data-skip={skip}>
<h2 className="popup-form__title">绑定手机号</h2>
{
desc &&
<div className="poup-form__desc">{desc}</div>
}
<div className="popup-form__item">
<a className="popup-form__button--num" onClick={this.toFetchCountryNum}>
+{country.num}
<i className="iconfont iconiconfront-69"/>
</a>
<Field
name="tel"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt"
data-type="tel"
type="text"
placeholder="请填写手机号"
/>
);
}}
/>
</div>
<CaptchaAli getInstance={this.getCaptchaInstance} onVerify={this.onVerify} mb={15}/>
<div className="popup-form__item">
<Field
name="code"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt popup-form__ipt--left"
type="text"
placeholder="输入验证码"
/>
);
}}
/>
<button
className="popup-form__button--code"
data-status={(validate && !isTimer) ? 'do' : ''}
type="button"
onClick={() => this.handleToSend({tel, code})}
>
{
isTimer ? `重新发送${seconds}s` : '发送验证码'
}
</button>
</div>
<button
className="popup-form__button--code"
data-status={(validate && !isTimer) ? 'do' : ''}
type="button"
onClick={() => this.handleToSend({tel, code})}
className="popup-form__button--bundle"
data-status={(tel && code && isEmpty(errors)) ? 'do' : 'done'}
type="submit"
>
{
isTimer ? `重新发送${seconds}s` : '发送验证码'
}
完成绑定
</button>
</div>
<button
className="popup-form__button--bundle"
data-status={(tel && code && isEmpty(errors)) ? 'do' : 'done'}
type="submit"
>
完成绑定
</button>
</Form>
)}
/>
</Form>
)
}
</Formik>
)
}
}
......
......@@ -5,79 +5,90 @@ import classnames from 'classnames'
const re = /(https?|ftp):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/
function ClosablePopup({
title,
content,
className,
closable = true,
close = function () {
},
clickMaskClose = true,
closeIcon = 'iconiconfront-2',
afterClose = function () {
},
remove = function () {
}
} = {}) {
interface Props {
title: string
content: React.ReactNode
className?: string
closable?: boolean
clickMaskClose?: boolean
close?: () => void | Promise<void>
closeIcon?: string
remove?: () => void
afterClose?: () => void
}
function ClosablePopup({
title,
content,
className,
closable = true,
close = function () {
},
clickMaskClose = true,
closeIcon = 'iconiconfront-2',
afterClose = function () {
},
remove = function () {
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
div.parentNode.removeChild(div)
}
}
}: Props) {
function _close() {
let _c = close()
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
afterClose()
})
} else {
unmountComponent()
afterClose()
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
div.parentNode.removeChild(div)
}
}
}
function clickMask() {
if (closable) {
return
function _close() {
let _c = close()
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
afterClose()
})
} else {
unmountComponent()
afterClose()
}
}
if (!clickMaskClose) {
return
function clickMask() {
if (closable) {
return
}
if (!clickMaskClose) {
return
}
_close()
}
_close()
}
const closablePopup = (
<div className={'closable-popup-mask'} onClick={clickMask}>
<div className={classnames(['popup-container', className])}>
<div className="title">{title}</div>
<div className="content">
{content}
const closablePopup = (
<div className={'closable-popup-mask'} onClick={clickMask}>
<div className={classnames(['popup-container', className])}>
<div className="title">{title}</div>
<div className="content">
{content}
</div>
{
closable &&
(re.test(closeIcon)
? <img src={closeIcon} alt="" className={'close-icon'} onClick={_close} />
: <i className={`close iconfont ${closeIcon}`} onClick={_close} />)
}
</div>
</div>
{
closable &&
(re.test(closeIcon)
? <img src={closeIcon} alt="" className={'close-icon'} onClick={_close}/>
: <i className={`close iconfont ${closeIcon}`} onClick={_close}/>)
}
</div>
</div>
)
const div = document.createElement('div')
document.body.appendChild(div)
)
const div = document.createElement('div')
document.body.appendChild(div)
ReactDOM.render(closablePopup, div)
ReactDOM.render(closablePopup, div)
return {
close: _close,
remove: unmountComponent
}
return {
close: _close,
remove: unmountComponent
}
}
export default ClosablePopup
export default ClosablePopup
\ No newline at end of file
.mask-cover {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, .6);
z-index: 999;
}
\ No newline at end of file
import React from 'react';
import './index.scss'
const MaskCover:React.FC = ({children}) => {
return (
<div className={'mask-cover'}>
{children}
</div>
);
};
export default MaskCover;
\ No newline at end of file
......@@ -24,7 +24,7 @@ class AddressPopup extends Component {
// 获取收货信息
fetchUserAddress = () => {
const { addressInfo } = this.state;
const {addressInfo} = this.state;
http.get(`${API.home}/sys/user_address_info`).then(res => {
const {code, data, msg} = res.data;
if (code === 200) {
......@@ -41,7 +41,7 @@ class AddressPopup extends Component {
}
handleToSubmit = (params = {}) => {
const { handleToHide } = this.props;
const {handleToHide} = this.props;
http.post(`${API.home}/sys/collect_info`, params).then(res => {
const {code, msg} = res.data;
if (code === 200) {
......@@ -53,15 +53,15 @@ class AddressPopup extends Component {
}
render() {
const { isLoading, addressInfo } = this.state;
const {isLoading, addressInfo} = this.state;
const {tip, prize} = this.props;
return (
<>
{
isLoading &&
<Formik
initialValues={{
...addressInfo
initialValues={{
...addressInfo,
}}
validate={({name, phone, address}) => {
const errors = {};
......@@ -69,7 +69,7 @@ class AddressPopup extends Component {
if (!name) {
errors.name = '请输入收件人';
}
if(!/^1[3-9]\d{9}$/.test(phone)) {
if (!/^1[3-9]\d{9}$/.test(phone)) {
errors.phone = '请填写正确格式的手机号';
}
if (!address) {
......@@ -83,7 +83,8 @@ class AddressPopup extends Component {
onSubmit={(values) => {
this.handleToSubmit(values);
}}
render={({errors}) => (
>
{({errors}) => (
<Form className="address-form">
{
prize ? (
......@@ -91,11 +92,13 @@ class AddressPopup extends Component {
) : (null)
}
{
tip ? (<p className="address-form__desc">{tip}</p>) : (<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
tip ? (<p className="address-form__desc">{tip}</p>) : (
<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
}
<Field
<Field
name="name"
render={({ field }) => (
>
{({field}) => (
<div className="address-form__item">
<input
{...field}
......@@ -109,10 +112,11 @@ class AddressPopup extends Component {
}
</div>
)}
/>
<Field
</Field>
<Field
name="phone"
render={({ field }) => (
>
{({field}) => (
<div className="address-form__item">
<input
{...field}
......@@ -126,10 +130,11 @@ class AddressPopup extends Component {
}
</div>
)}
/>
<Field
</Field>
<Field
name="address"
render={({ field }) => (
>
{({field}) => (
<div className="address-form__item">
<input
{...field}
......@@ -143,15 +148,16 @@ class AddressPopup extends Component {
}
</div>
)}
/>
<button
className="address-form__submit"
</Field>
<button
className="address-form__submit"
data-status="do"
type="submit"
>提交</button>
>提交
</button>
</Form>
)}
/>
</Formik>
}
</>
);
......
......@@ -20,11 +20,11 @@ class BargainBindPhone extends Component {
}
// 获取短信验证码
handleToSendCode = ({ mobile }) => {
const { country: { num = 86 } } = this.props;
let { isTimer, seconds } = this.state;
if(!isTimer) {
if(!/^\d+$/.test(mobile)){
handleToSendCode = ({mobile}) => {
const {country: {num = 86}} = this.props;
let {isTimer, seconds} = this.state;
if (!isTimer) {
if (!/^\d+$/.test(mobile)) {
Toast.info('请输入正确的手机号');
return;
}
......@@ -34,29 +34,29 @@ class BargainBindPhone extends Component {
`${API['passport-api']}/m/personal/bindPhoneSendCode`,
{
area_code: `00${num}`,
phone_num: mobile
}
phone_num: mobile,
},
).then(res => {
const { errno, msg } = res.data;
if(errno === 200) {
const {errno, msg} = res.data;
if (errno === 200) {
Toast.info('验证码发送成功', 2, null, false);
// 倒计时
this.timer = window.setInterval(() => {
if (seconds <= 0) {
window.clearInterval(this.timer);
this.setState({
isTimer: false,
seconds: 60
seconds: 60,
});
}else {
} else {
this.setState({
isTimer: true,
seconds: --seconds
seconds: --seconds,
});
}
}, 1000);
}else {
} else {
Toast.info(msg);
}
});
......@@ -65,7 +65,7 @@ class BargainBindPhone extends Component {
// 绑定手机号
handleToBindPhone = ({code, mobile}) => {
const { country: { num = 86}, handleToBargain, confirmBindPhone } = this.props;
const {country: {num = 86}, handleToBargain, confirmBindPhone} = this.props;
if (!mobile) {
Toast.info('请填手机号码');
return;
......@@ -87,34 +87,34 @@ class BargainBindPhone extends Component {
{
...params,
type: 1,
is_valid: 1
}
is_valid: 1,
},
).then(res => {
const { errno, data, msg } = res.data;
if(errno === 200) {
if(data.tip_info) {
const {errno, data, msg} = res.data;
if (errno === 200) {
if (data.tip_info) {
confirmBindPhone(params, data.tip_info);
}else {
} else {
handleToBargain();
}
}else {
} else {
Toast.info(msg);
}
});
}
render() {
const { country: { num = '86' } } = this.props;
const { isTimer, seconds } = this.state;
const {country: {num = '86'}} = this.props;
const {isTimer, seconds} = this.state;
return (
<Formik
initialValues={{
mobile: '',
code: ''
code: '',
}}
validate={({mobile, code}) => {
const errors = {};
if(!/^\d+$/.test(mobile)) {
if (!/^\d+$/.test(mobile)) {
errors.mobile = '请填写正确格式的手机号';
}
if (!/[0-9]{6}/.test(code)) {
......@@ -122,10 +122,11 @@ class BargainBindPhone extends Component {
}
return errors;
}}
onSubmit={(values, { setStatus, setSubmitting }) => {
onSubmit={(values, {setStatus, setSubmitting}) => {
this.handleToBindPhone(values);
}}
render={({values: {mobile, code}, errors}) => (
>
{({values: {mobile, code}, errors}) => (
<Form className="bargain-bind-phone">
<h2 className="bargain-bind-phone__title">绑定手机,先砍一刀</h2>
<div className="bargain-bind-phone__item">
......@@ -138,52 +139,53 @@ class BargainBindPhone extends Component {
</Link>
<Field
name="mobile"
render={({field}) => (
<input
>
{({field}) => (
<input
{...field}
className="bargain-bind-phone__ipt"
type="tel"
placeholder='手机号'
placeholder='手机号'
maxLength={11}
/>
)}
/>
</Field>
</div>
<div className="bargain-bind-phone__item">
<Field
name="code"
render={({field}) => (
<input
<Field name="code">
{({field}) => (
<input
{...field}
type="tel"
placeholder='验证码'
maxLength={6}
/>
)}
/>
</Field>
{errors.mobile}
<button
<button
type="button"
className={classnames(
'bargain-bind-phone__button--send',
{
'active': mobile && errors.mobile === undefined
}
'active': mobile && errors.mobile === undefined,
},
)}
disabled={!(mobile && errors.mobile === undefined)}
onClick={() => this.handleToSendCode({mobile})}
>
{isTimer? `重新发送${seconds}s` : '发送验证码'}
{isTimer ? `重新发送${seconds}s` : '发送验证码'}
</button>
</div>
<button
<button
type="submit"
className="bargain-bind-phone__button--bargain"
disabled={!(mobile && code && JSON.stringify(errors) === '{}')}
>先砍一刀</button>
>先砍一刀
</button>
</Form>
)}
/>
</Formik>
)
}
}
......
import React, { Component } from 'react';
import { Flex, NavBar, List, InputItem, Button, WhiteSpace, WingBlank, Toast } from 'antd-mobile';
import { Formik, Field, Form, withFormik } from 'formik';
import { InputItem, Button, WingBlank, Toast } from 'antd-mobile';
import { withFormik } from 'formik';
import {HeaderBar} from '../../common';
import { http } from "src/utils";
const InnerForm = ({
values,
errors,
touched,
setFieldValue,
handleBlur,
handleSubmit,
isSubmitting,
}) => (
<form>
<InputItem
......
......@@ -27,9 +27,8 @@ class AccountLogin extends PureComponent {
<HeaderBar arrow={true} title={'登录'}/>
<Header/>
<Form className="login-info">
<FastField
name='account'
render={({field}) => (
<FastField name='account'>
{({field}) => (
<Input
{...field}
type={'text'}
......@@ -42,10 +41,9 @@ class AccountLogin extends PureComponent {
}
/>
)}
/>
<FastField
name='password'
render={({field}) => (
</FastField>
<FastField name='password'>
{({field}) => (
<PasswordInput
{...field}
autoComplete={'on'}
......@@ -55,7 +53,7 @@ class AccountLogin extends PureComponent {
}
/>
)}
/>
</FastField>
<LoginButton active={values.account && values.password && isEmpty(errors)}/>
<Link className={'forgot-password-btn'} to='/passport/forgot-password'>忘记密码</Link>
</Form>
......
......@@ -47,7 +47,8 @@ class BindingTel extends Component {
<Form>
<Field
name='tel'
render={({field, form}) => {
>
{({field, form}) => {
return (
<ClearableInput
{...field}
......@@ -59,10 +60,11 @@ class BindingTel extends Component {
)
}}
/>
</Field>
<Field
name='veriCode'
render={({field}) => {
>
{({field}) => {
return (
<VeriCodeInput
{...field}
......@@ -81,7 +83,7 @@ class BindingTel extends Component {
)
}}
/>
</Field>
<CaptchaAli onVerify={this.onVerify} getInstance={this.getCaptchaInstance} mb={0}/>
<Button className={'complete-btn'}
active={values.tel && values.veriCode && isEmpty(errors)}>完成</Button>
......
......@@ -52,7 +52,8 @@ class ForgotPassword extends Component {
<Form className='forgot-password-form'>
<Field
name={'tel'}
render={({field, form}) => {
>
{({field, form}) => {
return (
<ClearableInput
{...field}
......@@ -63,12 +64,13 @@ class ForgotPassword extends Component {
country={country}
/>)
}}
/>
</Field>
{
this.state.validate &&
<Field
name='veriCode'
render={({field}) => {
>
{({field}) => {
return (
<VeriCodeInput
{...field}
......@@ -86,7 +88,7 @@ class ForgotPassword extends Component {
/>
)
}}
/>
</Field>
}
<OnSubmissionError callback={this.onSubmissionError}/>
<CaptchaAli getInstance={this.getCaptchaInstance} onVerify={this.onVerify}/>
......
......@@ -18,7 +18,7 @@ class Login extends Component {
state = {
validate: null,
captchaInstance: null,
validationData: null
validationData: null,
}
loginWaysClick = method => {
......@@ -29,7 +29,7 @@ class Login extends Component {
let from = location.state && location.state.from || {
pathname: '/',
search: window.location.search,
hash: ''
hash: '',
};
const referrer = document.referrer
const redirectURI = (!/^https?:\/\/m.julyedu.com\/?$/.test(referrer) && referrer) ? referrer : window.location.origin + from.pathname + from.search + from.hash;
......@@ -52,14 +52,14 @@ class Login extends Component {
getCaptchaInstance = instance => {
this.setState({
captchaInstance: instance
captchaInstance: instance,
})
}
onVerify = (data) => {
this.setState({
validationData: data,
validate: true
validate: true,
})
}
......@@ -86,16 +86,15 @@ class Login extends Component {
loginWays,
errors,
values,
country
country,
} = this.props
return (
<div className='login'>
<HeaderBar title={'登录'} arrow={true}/>
<Header/>
<Form className="login-info">
<Field
name='tel'
render={({field}) => (
<Field name='tel'>
{({field}) => (
<Input
{...field}
type={'tel'}
......@@ -105,14 +104,14 @@ class Login extends Component {
id={'tel'}
/>
)}
>
</Field>
{
this.state.validate &&
<Field
type='number'
name='veriCode'
render={({field}) => (
>
{({field}) => (
<VeriCodeInput
{...field}
className={'verification'}
......@@ -127,7 +126,7 @@ class Login extends Component {
country={country}
/>
)}
/>
</Field>
}
<CaptchaAli onVerify={this.onVerify} getInstance={this.getCaptchaInstance}/>
......@@ -147,7 +146,7 @@ class Login extends Component {
const FormikConfig = {
mapPropsToValues: () => ({
tel: '',
veriCode: ''
veriCode: '',
}),
handleSubmit(values, {props}) {
const from = props.location.state && props.location.state.from
......@@ -155,7 +154,7 @@ const FormikConfig = {
phone_num: values.tel,
phone_code: values.veriCode,
area_code: '00' + props.country.num,
redirect: from && encodeURIComponent(window.location.origin + from.pathname + from.search + from.hash)
redirect: from && encodeURIComponent(window.location.origin + from.pathname + from.search + from.hash),
}).then(res => {
if (res.hasError) {
Toast.info(res.msg);
......@@ -176,13 +175,13 @@ const FormikConfig = {
errors.veriCode = '请输入验证码'
}
return errors
}
},
}
export default compose(
connect(
state => ({country: state.country}),
{quickLogin}
{quickLogin},
),
withFormik(FormikConfig),
)(Login)
......@@ -9,7 +9,6 @@ import { HeaderBar } from "src/common"
import { http } from "src/utils"
import { Toast } from "antd-mobile"
import { encrypt } from "src/components/passport/encryption"
import { Link } from "react-router-dom"
import { isEmpty } from "lodash"
import { connect } from "react-redux"
import { setCurrentUser } from 'src/store/userAction'
......@@ -20,30 +19,9 @@ class SetPassword extends Component {
let historyUrl = window.localStorage.getItem('HistoryUrl')
const {history} = this.props
history.push(historyUrl)
// window.localStorage.removeItem('HistoryUrl')
return
}
//
// componentDidMount() {
// const {location} = this.props
// const {action} = this.props.history
// let pathname = location.state && location.state.from && location.state.from.pathname
// let search = location.state && location.state.from && location.state.from.search
//
// console.log(location);
// console.log(location.state);
// console.log(action,pathname,search);
//
// // if(action !== 'PUSH'){
// // let historyUrl = `${pathname}${search}`
// // window.localStorage.setItem('HistoryUrl',historyUrl)
// // }
//
// }
render() {
let {values, errors, location} = this.props
let {from} = location.state || {from: {pathname: '/'}}
......@@ -55,7 +33,8 @@ class SetPassword extends Component {
<Form>
<Field
name='password'
render={({field}) => {
>
{({field}) => {
return (
<PasswordInput
autoComplete={'on'}
......@@ -65,7 +44,7 @@ class SetPassword extends Component {
/>
)
}}
/>
</Field>
<Button className={'btn-active'}
active={values.password && values.agreement && isEmpty(errors)}>完成</Button>
<label htmlFor="agreement" className='user-agreement'>
......
......@@ -171,9 +171,8 @@ class StudentRoot extends PureComponent {
const isSubmit = Object.values(props.values).join('') !== '' && props.errors.tip === undefined;
return (
<Form className="student-form">
<Field
name='tel'
render={({field}) => (
<Field name='tel'>
{({field}) => (
<Input
{...field}
type={'tel'}
......@@ -182,7 +181,7 @@ class StudentRoot extends PureComponent {
country={country}
/>
)}
/>
</Field>
<div className="student-form__item">
<Field
className="student-form__input"
......@@ -199,7 +198,8 @@ class StudentRoot extends PureComponent {
<Field
type='number'
name='code'
render={({field}) => (
>
{({field}) => (
<VeriCodeInput
{...field}
className={'student-form__code'}
......@@ -212,7 +212,7 @@ class StudentRoot extends PureComponent {
country={country}
/>
)}
/>
</Field>
}
<div className="student-form__item">
<label className="student-form__label">学校</label>
......
import React, {Component} from 'react';
import {V} from 'src/common/course-card'
import React, {Component, useState, useEffect, useLayoutEffect, useRef} from 'react';
import {withRouter, RouteComponentProps} from 'react-router-dom'
class TSTest extends Component<RouteComponentProps> {
componentDidMount() {
const TSTest: React.FC = () => {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert('You clicked on: ' + count);
}, 3000);
}
render() {
return (
<div className={'ts-test'}>
TS
<V title={'a'} status={2} courseId={2}
history={this.props.history}
image={'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/20a86c1353.jpg'}></V>
</div>
);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={handleAlertClick}>
Show alert
</button>
</div>
);
}
function Message({text}: { text: string }) {
const [message, setMessage] = useState<string | null>(null)
useEffect(() => {
setMessage(text)
})
return <span>{message}</span>
}
export default withRouter(TSTest);
\ No newline at end of file
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