Move store rest logic to nova:accounts; get rid of AccountsForm component

This commit is contained in:
SachaG 2017-03-23 15:37:39 +09:00
parent f5e4bd5ba1
commit 2f0775a7b8
27 changed files with 75 additions and 147 deletions

View file

@ -43,5 +43,5 @@ accounts-password@1.3.4
############ Your Packages ############
example-movies
# example-movies-full
# example-movies-full
# example-customization

View file

@ -13,7 +13,6 @@ boilerplate-generator@1.0.11
caching-compiler@1.1.9
callback-hook@1.0.10
check@1.2.5
coffeescript@1.11.1_4
ddp@1.2.5
ddp-client@1.3.3
ddp-common@1.2.8
@ -51,6 +50,7 @@ modules@0.7.9
modules-runtime@0.7.9
mongo@1.1.16
mongo-id@1.0.6
nova:accounts@1.2.0
nova:core@1.2.0
nova:forms@1.2.0
nova:i18n-en-us@1.2.0
@ -75,14 +75,12 @@ service-configuration@1.0.11
session@1.1.7
sha@1.0.9
shell-server@0.2.3
softwarerero:accounts-t9n@1.3.9
spacebars@1.0.13
spacebars-compiler@1.0.13
srp@1.0.10
standard-minifier-css@1.3.4
standard-minifier-js@1.2.3
standard-minifiers@1.0.6
std:accounts-ui@1.2.19
tmeasday:check-npm-versions@0.3.1
tracker@1.1.2
ui@1.0.12

View file

@ -3,8 +3,9 @@ import ReactDOM from 'react-dom';
import Tracker from 'tracker-component';
import { Accounts } from 'meteor/accounts-base';
import { KEY_PREFIX } from '../../login_session.js';
import { Components, registerComponent } from 'meteor/nova:core';
import { FormattedMessage, intlShape } from 'react-intl';
import { Components, registerComponent, withCurrentUser } from 'meteor/nova:core';
import { intlShape } from 'react-intl';
import { withApollo } from 'react-apollo';
import {
STATES,
@ -28,19 +29,25 @@ export class AccountsLoginForm extends Tracker.Component {
console.warn('Do not force the state to SIGN_IN on Accounts.ui.LoginForm, it will make it impossible to reset password in your app, this state is also the default state if logged out, so no need to force it.');
}
const user = typeof props.user !== 'undefined'
? props.user : Accounts.user();
const currentUser = props.currentUser;
const resetStoreAndThen = hook => {
return () => {
props.client.resetStore();
hook();
}
}
// Set inital state.
this.state = {
messages: [],
waiting: true,
formState: props.formState ? props.formState : (user ? STATES.PROFILE : STATES.SIGN_IN),
formState: props.formState ? props.formState : (currentUser ? STATES.PROFILE : STATES.SIGN_IN),
onSubmitHook: props.onSubmitHook || Accounts.ui._options.onSubmitHook,
onSignedInHook: props.onSignedInHook || Accounts.ui._options.onSignedInHook,
onSignedOutHook: props.onSignedOutHook || Accounts.ui._options.onSignedOutHook,
onSignedInHook: resetStoreAndThen(props.onSignedInHook || Accounts.ui._options.onSignedInHook),
onSignedOutHook: resetStoreAndThen(props.onSignedOutHook || Accounts.ui._options.onSignedOutHook),
onPreSignUpHook: props.onPreSignUpHook || Accounts.ui._options.onPreSignUpHook,
onPostSignUpHook: props.onPostSignUpHook || Accounts.ui._options.onPostSignUpHook,
onPostSignUpHook: resetStoreAndThen(props.onPostSignUpHook || Accounts.ui._options.onPostSignUpHook),
};
}
@ -79,7 +86,7 @@ export class AccountsLoginForm extends Tracker.Component {
// Add the services list to the user.
this.subscribe('servicesList');
this.setState({
user: Accounts.user(),
currentUser: Accounts.user(),
waiting: !Accounts.loginServicesConfigured()
});
@ -96,17 +103,17 @@ export class AccountsLoginForm extends Tracker.Component {
}
componentDidUpdate(prevProps, prevState) {
if (typeof this.props.user !== 'undefined') {
if (!prevProps.user !== !this.props.user) {
if (typeof this.props.currentUser !== 'undefined') {
if (!prevProps.currentUser !== !this.props.currentUser) {
this.setState({
formState: this.props.user ? STATES.PROFILE : STATES.SIGN_IN
formState: this.props.currentUser ? STATES.PROFILE : STATES.SIGN_IN
});
}
if (this.state.formState == STATES.PROFILE) {
if (!this.props.user && this.state.messages.length === 0) {
if (!this.props.currentUser && this.state.messages.length === 0) {
this.showMessage(loggingInMessage);
} else if (this.props.user &&
} else if (this.props.currentUser &&
this.state.messages.find(({ message }) => message === loggingInMessage)) {
this.clearMessage(loggingInMessage);
}
@ -115,9 +122,9 @@ export class AccountsLoginForm extends Tracker.Component {
this.clearMessage(loggingInMessage);
}
} else {
if (!prevState.user !== !this.state.user) {
if (!prevState.currentUser !== !this.state.currentUser) {
this.setState({
formState: this.state.user ? STATES.PROFILE : STATES.SIGN_IN
formState: this.state.currentUser ? STATES.PROFILE : STATES.SIGN_IN
});
}
}
@ -151,7 +158,7 @@ export class AccountsLoginForm extends Tracker.Component {
hint: this.context.intl.formatMessage({id: 'accounts.enter_username_or_email'}),
label: this.context.intl.formatMessage({id: 'accounts.username_or_email'}),
required: true,
defaultValue: this.state.username || "",
defaultValue: this.state.currentUsername || "",
onChange: this.handleChange.bind(this, 'usernameOrEmail'),
message: this.getMessageForField('usernameOrEmail'),
};
@ -163,7 +170,7 @@ export class AccountsLoginForm extends Tracker.Component {
hint: this.context.intl.formatMessage({id: 'accounts.enter_username'}),
label: this.context.intl.formatMessage({id: 'accounts.username'}),
required: true,
defaultValue: this.state.username || "",
defaultValue: this.state.currentUsername || "",
onChange: this.handleChange.bind(this, 'username'),
message: this.getMessageForField('username'),
};
@ -313,10 +320,10 @@ export class AccountsLoginForm extends Tracker.Component {
} = this.props;
const { formState, waiting } = this.state;
let loginButtons = [];
const user = typeof this.props.user !== 'undefined'
? this.props.user : this.state.user;
const currentUser = typeof this.props.currentUser !== 'undefined'
? this.props.currentUser : this.state.currentUser;
if (user && formState == STATES.PROFILE) {
if (currentUser && formState == STATES.PROFILE) {
loginButtons.push({
id: 'signOut',
label: this.context.intl.formatMessage({id: 'accounts.sign_out'}),
@ -355,9 +362,9 @@ export class AccountsLoginForm extends Tracker.Component {
});
}
if (user
if (currentUser
&& formState == STATES.PROFILE
&& (user.services && 'password' in user.services)) {
&& (currentUser.services && 'password' in currentUser.services)) {
loginButtons.push({
id: 'switchToChangePassword',
label: this.context.intl.formatMessage({id: 'accounts.change_password'}),
@ -651,7 +658,7 @@ export class AccountsLoginForm extends Tracker.Component {
}
oauthSignIn(serviceName) {
const { formState, waiting, user, onSubmitHook } = this.state;
const { formState, waiting, currentUser, onSubmitHook } = this.state;
//Thanks Josh Owens for this one.
function capitalService() {
return serviceName.charAt(0).toUpperCase() + serviceName.slice(1);
@ -751,8 +758,8 @@ export class AccountsLoginForm extends Tracker.Component {
else {
onSubmitHook(null, formState);
this.setState({ formState: STATES.PROFILE, password: null });
let user = Accounts.user();
loginResultCallback(this.state.onPostSignUpHook.bind(this, _options, user));
let currentUser = Accounts.user();
loginResultCallback(this.state.onPostSignUpHook.bind(this, _options, currentUser));
this.clearDefaultFieldValues();
}
@ -924,4 +931,4 @@ AccountsLoginForm.contextTypes = {
intl: intlShape
}
registerComponent('AccountsLoginForm', AccountsLoginForm);
registerComponent('AccountsLoginForm', AccountsLoginForm, withCurrentUser, withApollo);

View file

@ -1,6 +1,6 @@
Package.describe({
name: 'std:accounts-ui',
version: '1.2.19',
name: 'nova:accounts',
version: '1.2.0',
summary: 'Accounts UI for React in Meteor 1.3+',
git: 'https://github.com/studiointeract/accounts-ui',
documentation: 'README.md'

View file

@ -1,60 +0,0 @@
import React, { PropTypes, Component } from 'react';
import { Button, FormControl } from 'react-bootstrap';
import { Accounts } from 'meteor/std:accounts-ui';
import { withApollo } from 'react-apollo';
import { registerComponent, withCurrentUser } from 'meteor/nova:core';
Accounts.ui.config({
passwordSignupFields: 'USERNAME_AND_EMAIL',
});
const AccountsForm = ({client, currentUser}) => {
return (
<div>
<Accounts.ui.LoginForm
user={currentUser}
onPostSignUpHook={() => client.resetStore()}
onSignedInHook={() => client.resetStore()}
onSignedOutHook={() => client.resetStore()}
/>
</div>
)
}
class AccountsButton extends Accounts.ui.Button {
render () {
const {label, href, type, disabled, className, onClick} = this.props;
if (type === 'link') {
return <a href={ href } className={ className } onClick={ onClick }>{ label }</a>;
}
return <Button
bsStyle="primary"
className={ className }
type={ type }
disabled={ disabled }
onClick={ onClick }>{ label }
</Button>;
}
}
class AccountsField extends Accounts.ui.Field {
render() {
const { id, hint, /* label, */ type = 'text', onChange, className = "field", defaultValue = "", message } = this.props;
const { mount = true } = this.state;
return mount ? (
<div className={ className }>
<FormControl id={ id } type={ type } inputRef={ref => { this.input = ref; }} onChange={ onChange } placeholder={ hint } defaultValue={ defaultValue } />
{message && (
<span className={['message', message.type].join(' ').trim()}>
{message.message}</span>
)}
</div>
) : null;
}
}
Accounts.ui.Button = AccountsButton;
Accounts.ui.Field = AccountsField;
registerComponent('AccountsForm', AccountsForm, withCurrentUser, withApollo);

View file

@ -6,7 +6,7 @@ Wrapped with the "withDocument" container.
*/
import React, { PropTypes, Component } from 'react';
import Movies from '../modules/collection.js';
import Movies from '../../modules/movies/collection.js';
import { withDocument, registerComponent } from 'meteor/nova:core';
const MoviesDetails = props => {

View file

@ -7,7 +7,7 @@ Wrapped with the "withDocument" container.
import React, { PropTypes, Component } from 'react';
import { Components, registerComponent, getFragment } from "meteor/nova:core";
import Movies from '../modules/collection.js';
import Movies from '../../modules/movies/collection.js';
const MoviesEditForm = props =>
<Components.SmartForm

View file

@ -8,7 +8,7 @@ Wrapped with the "withCurrentUser" container.
import React, { PropTypes, Component } from 'react';
import { Button } from 'react-bootstrap';
import { Components, registerComponent, ModalTrigger } from 'meteor/nova:core';
import Movies from '../modules/collection.js';
import Movies from '../../modules/movies/collection.js';
class MoviesItem extends Component {

View file

@ -7,7 +7,7 @@ Wrapped with the "withList" and "withCurrentUser" containers.
import React, { PropTypes, Component } from 'react';
import { Button } from 'react-bootstrap';
import Movies from '../modules/collection.js';
import Movies from '../../modules/movies/collection.js';
import { Components, registerComponent, ModalTrigger, withList, withCurrentUser } from 'meteor/nova:core';
const LoadMore = props => <a href="#" className="load-more button button--primary" onClick={e => {e.preventDefault(); props.loadMore();}}>Load More ({props.count}/{props.totalCount})</a>

View file

@ -5,7 +5,7 @@ A component to configure the "new movie" form.
*/
import React, { PropTypes, Component } from 'react';
import Movies from '../modules/collection.js';
import Movies from '../../modules/movies/collection.js';
import { Components, registerComponent, withMessages, getFragment } from 'meteor/nova:core';
const MoviesNewForm = props =>

View file

@ -11,7 +11,7 @@ const MoviesWrapper = () =>
<div className="wrapper framework-demo">
<div className="header">
<Components.AccountsForm />
<Components.AccountsLoginForm />
</div>
<div className="main">

View file

@ -1,7 +1,7 @@
import '../components/AccountsForm.jsx';
import '../components/MoviesDetails.jsx';
import '../components/MoviesEditForm.jsx';
import '../components/MoviesItem.jsx';
import '../components/MoviesList.jsx';
import '../components/MoviesNewForm.jsx';
import '../components/MoviesWrapper.jsx';
import '../components/movies/MoviesDetails.jsx';
import '../components/movies/MoviesEditForm.jsx';
import '../components/movies/MoviesItem.jsx';
import '../components/movies/MoviesList.jsx';
import '../components/movies/MoviesNewForm.jsx';
import '../components/movies/MoviesWrapper.jsx';

View file

@ -1,14 +1,9 @@
// The main Movies collection
import MoviesImport from './collection.js';
import MoviesImport from './movies/collection.js';
// Text strings used in the UI
import './i18n.js';
// Groups & user permissions
import './permissions.js';
// GraphQL fragments used to query for data
import './fragments.js';
// React components
import './components.js';
@ -16,8 +11,5 @@ import './components.js';
// Routes
import './routes.js';
// Sorting & filtering parameters
import './parameters.js';
// Add Movies collection to global Meteor namespace (optional)
Movies = MoviesImport;

View file

@ -9,6 +9,15 @@ import schema from './schema.js';
import resolvers from './resolvers.js';
import mutations from './mutations.js';
// Groups & user permissions
import './permissions.js';
// GraphQL fragments used to query for data
import './fragments.js';
// Sorting & filtering parameters
import './parameters.js';
const Movies = createCollection({
collectionName: 'movies',

View file

@ -1,4 +1,4 @@
import { addRoute, getComponent } from 'meteor/nova:core';
// add new "/movies" route that loads the MoviesWrapper component
addRoute({ name: 'movies', path: 'movies', componentName: 'MoviesWrapper' });
addRoute({ name: 'movies', path: '/', componentName: 'MoviesWrapper' });

View file

@ -4,7 +4,7 @@ Seed the database with some dummy content.
*/
import Movies from '../modules/collection.js';
import Movies from '../modules/movies/collection.js';
import Users from 'meteor/nova:users';
import { newMutation } from 'meteor/nova:core';

View file

@ -1,5 +1,5 @@
Package.describe({
name: 'framework-demo',
name: 'example-movies-full',
});
Package.onUse(function (api) {
@ -9,10 +9,10 @@ Package.onUse(function (api) {
'nova:forms',
'nova:routing',
'std:accounts-ui@1.2.19',
'nova:accounts',
]);
api.addFiles('lib/stylesheets/bootstrap.css', 'client');
api.addFiles('lib/stylesheets/bootstrap.min.css', 'client');
api.mainModule('lib/server/main.js', 'server');
api.mainModule('lib/client/main.js', 'client');

View file

@ -1,22 +0,0 @@
import React, { PropTypes, Component } from 'react';
import { Accounts } from 'meteor/std:accounts-ui';
import { withApollo } from 'react-apollo';
import { Components, registerComponent } from 'meteor/nova:core';
Accounts.ui.config({
passwordSignupFields: 'USERNAME_AND_EMAIL',
});
const AccountsForm = ({client}) => {
return (
<div style={{padding: '20px 0', marginBottom: '20px', borderBottom: '1px solid #ccc'}} >
<Components.AccountsLoginForm
onPostSignUpHook={() => client.resetStore()}
onSignedInHook={() => client.resetStore()}
onSignedOutHook={() => client.resetStore()}
/>
</div>
)
}
export default withApollo(AccountsForm);

View file

@ -6,20 +6,23 @@ Wrapped with the "withList" and "withCurrentUser" containers.
*/
import React, { PropTypes, Component } from 'react';
import { withList, withCurrentUser, Loading } from 'meteor/nova:core';
import { Components, withList, withCurrentUser, Loading } from 'meteor/nova:core';
import Movies from '../../modules/movies/collection.js';
import MoviesItem from './MoviesItem.jsx';
import MoviesNewForm from './MoviesNewForm.jsx';
import AccountsForm from '../AccountsForm.jsx';
const MoviesList = ({results, currentUser, loading, loadMore, count, totalCount}) =>
const MoviesList = ({results = [], currentUser, loading, loadMore, count, totalCount}) =>
<div style={{maxWidth: '500px', margin: 'auto'}}>
{/* user accounts */}
<AccountsForm />
<div style={{padding: '20px 0', marginBottom: '20px', borderBottom: '1px solid #ccc'}}>
<Components.AccountsLoginForm />
</div>
{loading ?
@ -50,6 +53,7 @@ const MoviesList = ({results, currentUser, loading, loadMore, count, totalCount}
const options = {
collection: Movies,
fragmentName: 'MoviesItemFragment',
limit: 5
};
export default withList(options)(withCurrentUser(MoviesList))

View file

@ -2,4 +2,4 @@ import { addRoute } from 'meteor/nova:core';
import MoviesList from '../components/movies/MoviesList.jsx';
addRoute({ name: 'movies', path: 'movies', component: MoviesList });
addRoute({ name: 'movies', path: '/', component: MoviesList });

View file

@ -9,7 +9,7 @@ Package.onUse(function (api) {
'nova:forms',
'nova:routing',
'std:accounts-ui@1.2.19',
'nova:accounts',
]);
api.addFiles('lib/stylesheets/bootstrap.min.css');