Commit 878ca8a152800bbb889f6aa5a106a87f8867cf95
1 parent
a8c5a7fb6d
Exists in
master
added signup form on index route for main site
Showing
12 changed files
with
345 additions
and
34 deletions
Show diff stats
imports/client/app/routes.js
1 | /* eslint-disable max-len */ | 1 | /* eslint-disable max-len */ |
2 | 2 | ||
3 | import React from 'react'; | 3 | import React from 'react'; |
4 | import { render } from 'react-dom'; | 4 | import { render } from 'react-dom'; |
5 | import { Router, Route, | 5 | import { Router, Route, |
6 | IndexRoute, browserHistory } from 'react-router'; | 6 | IndexRoute, browserHistory } from 'react-router'; |
7 | import { Meteor } from 'meteor/meteor'; | 7 | import { Meteor } from 'meteor/meteor'; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * General Components | 10 | * General Components |
11 | */ | 11 | */ |
12 | import Index from '/imports/client/views/app/module/Index'; | 12 | import Index from '/imports/client/views/app/module/Index'; |
13 | import NotFound from '/imports/client/views/org/NotFound'; | 13 | import NotFound from '/imports/client/views/org/NotFound'; |
14 | 14 | ||
15 | /** | 15 | /** |
16 | * Org Components | 16 | * Org Components |
17 | */ | 17 | */ |
18 | 18 | ||
19 | import { App } from '/imports/client/layouts/OrgApp'; | 19 | import { App } from '/imports/client/layouts/OrgApp'; |
20 | import { AppModule } from '/imports/client/views/org/app/module/Index'; | 20 | import { AppModule } from '/imports/client/views/org/app/module/Index'; |
21 | import { Orgs } from '/imports/collections/orgs/index'; | 21 | import { Orgs } from '/imports/collections/orgs/index'; |
22 | import { importCsvController } from '/imports/client/views/org/importCsv/index' | 22 | import { importCsvController } from '/imports/client/views/org/importCsv/index' |
23 | 23 | ||
24 | //admin | 24 | //admin |
25 | import { StudentDataController } from '/imports/client/views/org/admin/students/index' | 25 | import { StudentDataController } from '/imports/client/views/org/admin/students/index' |
26 | import { teachersViewController } from '/imports/client/views/org/admin/teachers/index' | 26 | import { teachersViewController } from '/imports/client/views/org/admin/teachers/index' |
27 | //students | 27 | //students |
28 | 28 | ||
29 | //teachers | 29 | //teachers |
30 | 30 | ||
31 | //parents | 31 | //parents |
32 | 32 | ||
33 | 33 | ||
34 | 34 | ||
35 | /** | 35 | /** |
36 | * NonOrg Components | 36 | * NonOrg Components |
37 | */ | 37 | */ |
38 | import Signup from '/imports/client/views/nonOrg/enter/SignupView'; | 38 | import Signup from '/imports/client/views/nonOrg/enter/SignupView'; |
39 | import { NonOrgApp } from '/imports/client/layouts/NonOrgApp'; | 39 | import { NonOrgApp } from '/imports/client/layouts/NonOrgApp'; |
40 | import {NonOrgAppModule} from '/imports/client/views/nonOrg/app/module/Index'; | ||
40 | 41 | ||
41 | /** | 42 | /** |
42 | * Invalid Org Components | 43 | * Invalid Org Components |
43 | */ | 44 | */ |
44 | 45 | ||
45 | /** | 46 | /** |
46 | There are three types of routes | 47 | There are three types of routes |
47 | 1)getOrgRoutes: all the routes that should be present for a registered org | 48 | 1)getOrgRoutes: all the routes that should be present for a registered org |
48 | 2)getInvalidOrgRoute: all the routes where someone tries to enter a subdomain which hasn't been registered yet (404 mostly :D) | 49 | 2)getInvalidOrgRoute: all the routes where someone tries to enter a subdomain which hasn't been registered yet (404 mostly :D) |
49 | 3)getNonOrgRoutes: all routes linked to normal site, ie signing up a new org. CHeking out demo and everything internal | 50 | 3)getNonOrgRoutes: all routes linked to normal site, ie signing up a new org. CHeking out demo and everything internal |
50 | **/ | 51 | **/ |
51 | const getOrgRoutes = () => ( | 52 | const getOrgRoutes = () => ( |
52 | <Router history={ browserHistory }> | 53 | <Router history={ browserHistory }> |
53 | <Route path="/" component={ App }> | 54 | <Route path="/" component={ App }> |
54 | <IndexRoute name="index" component={ AppModule } /> | 55 | <IndexRoute name="index" component={ AppModule } /> |
55 | <Route name="import" path="/import" component={ importCsvController } /> | 56 | <Route name="import" path="/import" component={ importCsvController } /> |
56 | <Route name="student" path="/students" component={ StudentDataController } /> | 57 | <Route name="student" path="/students" component={ StudentDataController } /> |
57 | <Route name="teachers" path="/teachers" component={ teachersViewController } /> | 58 | <Route name="teachers" path="/teachers" component={ teachersViewController } /> |
58 | <Route path="*" component={ NotFound } /> | 59 | <Route path="*" component={ NotFound } /> |
59 | </Route> | 60 | </Route> |
60 | </Router> | 61 | </Router> |
61 | ) | 62 | ) |
62 | 63 | ||
63 | 64 | ||
64 | const getInvalidOrgRoute = () => ( | 65 | const getInvalidOrgRoute = () => ( |
65 | <Router history={ browserHistory }> | 66 | <Router history={ browserHistory }> |
66 | <Route path="/" component={ App }> | 67 | <Route path="/" component={ App }> |
67 | <IndexRoute name="index" component={ NotFound } /> | 68 | <IndexRoute name="index" component={ NotFound } /> |
68 | <Route path="*" component={ NotFound } /> | 69 | <Route path="*" component={ NotFound } /> |
69 | </Route> | 70 | </Route> |
70 | </Router> | 71 | </Router> |
71 | ) | 72 | ) |
72 | 73 | ||
73 | const getNonOrgRoutes = () => ( | 74 | const getNonOrgRoutes = () => ( |
74 | <Router history={ browserHistory }> | 75 | <Router history={ browserHistory }> |
75 | <Route path="/" component={ NonOrgApp }> | 76 | <Route path="/" component={ NonOrgApp }> |
76 | <IndexRoute name="index" component={ Index } /> | 77 | <IndexRoute name="index" component={ NonOrgAppModule } /> |
77 | <Route name="signup" path="/signup" component={ Signup } /> | 78 | <Route name="signup" path="/signup" component={ Signup } /> |
78 | <Route path="*" component={ NotFound } /> | 79 | <Route path="*" component={ NotFound } /> |
79 | </Route> | 80 | </Route> |
80 | </Router> | 81 | </Router> |
81 | ) | 82 | ) |
82 | 83 | ||
83 | //Authenticate function to give access to users only | 84 | //Authenticate function to give access to users only |
84 | const authenticate = (nextState, replace) => { | 85 | const authenticate = (nextState, replace) => { |
85 | if (!Meteor.loggingIn() && !Meteor.userId()) { | 86 | if (!Meteor.loggingIn() && !Meteor.userId()) { |
86 | replace({ | 87 | replace({ |
87 | pathname: '/login', | 88 | pathname: '/login', |
88 | state: { nextPathname: nextState.location.pathname }, | 89 | state: { nextPathname: nextState.location.pathname }, |
89 | }); | 90 | }); |
90 | } | 91 | } |
91 | }; | 92 | }; |
92 | 93 | ||
93 | 94 | ||
94 | /** | 95 | /** |
95 | 96 | ||
96 | **/ | 97 | **/ |
97 | const detectOrg = () => { | 98 | const detectOrg = () => { |
98 | orgSlug = ""; | 99 | orgSlug = ""; |
99 | var hostnameArray = document.location.hostname.split( "." ); | 100 | var hostnameArray = document.location.hostname.split( "." ); |
100 | if(hostnameArray[1]=='localhost'){ | 101 | if(hostnameArray[1]=='localhost'){ |
101 | orgSlug = hostnameArray[0]; | 102 | orgSlug = hostnameArray[0]; |
102 | } | 103 | } |
103 | if(orgSlug!=""){ | 104 | if(orgSlug!=""){ |
104 | Meteor.call('checkExistingOrg', {slug:orgSlug}, function(err, res) { | 105 | Meteor.call('checkExistingOrg', {slug:orgSlug}, function(err, res) { |
105 | if(res){ | 106 | if(res){ |
106 | Session.set('orgId', res._id); | 107 | Session.set('orgId', res._id); |
107 | Session.set('orgSlug', orgSlug); | 108 | Session.set('orgSlug', orgSlug); |
108 | render(getOrgRoutes(),document.getElementById('app')); | 109 | render(getOrgRoutes(),document.getElementById('app')); |
109 | }else{ | 110 | }else{ |
110 | render(getInvalidOrgRoute(),document.getElementById('app')); | 111 | render(getInvalidOrgRoute(),document.getElementById('app')); |
111 | } | 112 | } |
112 | }); | 113 | }); |
113 | }else{ | 114 | }else{ |
114 | render(getNonOrgRoutes(),document.getElementById('app')); | 115 | render(getNonOrgRoutes(),document.getElementById('app')); |
115 | } | 116 | } |
116 | } | 117 | } |
117 | const checkSlug = (nextState, replace) => { | 118 | const checkSlug = (nextState, replace) => { |
118 | orgId = Session.get('orgId'); | 119 | orgId = Session.get('orgId'); |
119 | } | 120 | } |
120 | 121 | ||
121 | 122 | ||
122 | Meteor.startup(() => { | 123 | Meteor.startup(() => { |
123 | detectOrg(); | 124 | detectOrg(); |
124 | }); | 125 | }); |
125 | 126 |
imports/client/layouts/NonOrgApp.js
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import { Grid } from 'react-bootstrap'; | 2 | import { Grid } from 'react-bootstrap'; |
3 | import {AppNavigationController} from '/imports/client/views/nonOrg/app/module/navigation/index'; | ||
4 | /** | 3 | /** |
5 | * user based redirection will take place here | 4 | * user based redirection will take place here |
6 | */ | 5 | */ |
7 | export class App extends Component { | 6 | export class NonOrgApp extends Component { |
8 | constructor(props) { | 7 | constructor(props) { |
9 | super(props); | 8 | super(props); |
10 | this.state = { | 9 | this.state = { |
11 | 10 | ||
12 | }; | 11 | }; |
13 | }; | 12 | }; |
14 | render(){ | 13 | render(){ |
15 | return ( | 14 | return ( |
16 | <div> | 15 | <div> |
17 | <AppNavigationController /> | ||
18 | <Grid> | 16 | <Grid> |
19 | { this.props.children } | 17 | { this.props.children } |
20 | </Grid> | 18 | </Grid> |
21 | </div> | 19 | </div> |
22 | ) | 20 | ) |
23 | } | 21 | } |
24 | } | 22 | } |
25 | 23 |
imports/client/views/nonOrg/app/module/AppLayout.js
File was created | 1 | import _ from 'lodash'; | |
2 | import { Meteor } from 'meteor/meteor'; | ||
3 | import React, { Component } from 'react'; | ||
4 | import { Link } from 'react-router'; | ||
5 | import { Avatar } from '/imports/client/components/Avatar'; | ||
6 | import { Icon } from '/imports/client/components/Icon'; | ||
7 | import classNames from 'classnames'; | ||
8 | |||
9 | import { logout } from '/imports/client/app/utils/loginMethods'; | ||
10 | |||
11 | import Signup from '/imports/client/views/nonOrg/enter/SignupView'; | ||
12 | import { VerifyModule } from '/imports/client/views/verify/module/index'; | ||
13 | import ReactSVG from 'react-svg' | ||
14 | |||
15 | export class AppLayout extends Component { | ||
16 | render() { | ||
17 | const {user, org} = this.props.data; | ||
18 | console.log(user); | ||
19 | if(!user) { | ||
20 | return ( | ||
21 | <Signup | ||
22 | /> | ||
23 | ); | ||
24 | } | ||
25 | |||
26 | if(!user.isEmailVerified()) { | ||
27 | return ( | ||
28 | <VerifyModule | ||
29 | pane = {this.props.location.query.verify} | ||
30 | location = {this.props.location} | ||
31 | /> | ||
32 | ); | ||
33 | } | ||
34 | |||
35 | |||
36 | return ( | ||
37 | <div className = "appLayout-box"> | ||
38 | <div className = "appLayout-wrapOuter"> | ||
39 | <div className = "appLayout-wrapInner"> | ||
40 | <div className = "appLayout-menuWrap"> | ||
41 | </div> | ||
42 | <div className = "appLayout-contentWrap"> | ||
43 | <div className = "appLayout-content"> | ||
44 | |||
45 | </div> | ||
46 | </div> | ||
47 | </div> | ||
48 | </div> | ||
49 | </div> | ||
50 | ); | ||
51 | }; | ||
52 | |||
53 | }; | ||
54 |
imports/client/views/nonOrg/app/module/Index.js
1 | import React from 'react'; | 1 | // import { AppModule } from '/imports/client/views/app/module/index' |
2 | import { Jumbotron } from 'react-bootstrap'; | 2 | import { |
3 | 3 | composeWithTracker, | |
4 | const Index = () => ( | 4 | compose, |
5 | <div className="Index"> | 5 | composeAll |
6 | <Jumbotron className="text-center"> | 6 | } from 'react-komposer'; |
7 | <h2>Base</h2> | 7 | import { AppLayout } from './AppLayout'; |
8 | <p>A starting point for Meteor applications.</p> | 8 | import { Loading } from '/imports/client/components/Loading'; |
9 | <p><a className="btn btn-success" href="https://themeteorchef.com/base" role="button">Read the Documentation</a></p> | 9 | |
10 | <p style={ { fontSize: '16px', color: '#aaa' } }>Currently at v4.11.1</p> | 10 | import { Users } from '/imports/collections/users/index'; |
11 | </Jumbotron> | 11 | import { Orgs } from '/imports/collections/orgs/index'; |
12 | </div> | 12 | |
13 | ); | 13 | |
14 | 14 | const meteorTick = (props, onData) => { | |
15 | export default Index; | 15 | |
16 | const handles = [ | ||
17 | Meteor.subscribe('users.current'), | ||
18 | Meteor.subscribe('orgs.current'), | ||
19 | ]; | ||
20 | |||
21 | if(_.every(handles, (handle) => (handle.ready()) )) { | ||
22 | const user = Users.current(); | ||
23 | console.log(user); | ||
24 | onData(null, { | ||
25 | data: { | ||
26 | user: user, | ||
27 | org: Orgs.current(), | ||
28 | }, | ||
29 | }); | ||
30 | } | ||
31 | |||
32 | return () => { | ||
33 | _.each(handles, (handle) => handle.stop() ); | ||
34 | }; | ||
35 | }; | ||
36 | |||
37 | |||
38 | const reduxTick = (props, onData) => { | ||
39 | onData(null, { | ||
40 | location: props.location, | ||
41 | data: {} | ||
42 | }); | ||
43 | }; | ||
44 | |||
45 | |||
46 | export const NonOrgAppModule = composeAll( | ||
47 | composeWithTracker(meteorTick, Loading), | ||
48 | compose(reduxTick, Loading), | ||
49 | )(AppLayout); | ||
16 | 50 |
imports/client/views/nonOrg/app/module/navigation/AppNavigation.js
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import { Navbar } from 'react-bootstrap'; | 2 | import { Navbar } from 'react-bootstrap'; |
3 | import { Link } from 'react-router'; | 3 | import { Link } from 'react-router'; |
4 | import {PublicNavigation} from './PublicNavigation.js'; | 4 | import {PublicNavigation} from './PublicNavigation.js'; |
5 | import {AuthenticatedNavigation} from './AuthenticatedNavigation.js'; | 5 | import {AuthenticatedNavigation} from './AuthenticatedNavigation.js'; |
6 | // import '/imports/client/assets/css/icons/icomoon/styles.css'; | 6 | // import '/imports/client/assets/css/icons/icomoon/styles.css'; |
7 | // import '/imports/client/assets/css/bootstrap.css'; | 7 | // import '/imports/client/assets/css/bootstrap.css'; |
8 | // import '/imports/client/assets/css/core.css'; | 8 | // import '/imports/client/assets/css/core.css'; |
9 | // import '/imports/client/assets/css/components.css'; | 9 | // import '/imports/client/assets/css/components.css'; |
10 | // import '/imports/client/assets/css/colors.css'; | 10 | // import '/imports/client/assets/css/colors.css'; |
11 | // import '/imports/client/assets/css/colors.css'; | 11 | // import '/imports/client/assets/css/colors.css'; |
12 | export class AppNavigation extends Component { | 12 | export class AppNavigation extends Component { |
13 | 13 | ||
14 | constructor(props) { | 14 | constructor(props) { |
15 | super(props); | 15 | super(props); |
16 | this.state = { | 16 | this.state = { |
17 | 17 | ||
18 | }; | 18 | }; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | onUpdate(key, value) { | 21 | onUpdate(key, value) { |
22 | this.setState({[key]: value}); | 22 | this.setState({[key]: value}); |
23 | }; | 23 | }; |
24 | render() { | 24 | render() { |
25 | const {user} = this.props.data; | 25 | const {user} = this.props.data; |
26 | console.log(user); | ||
26 | if(user){ | 27 | if(user){ |
27 | return( | 28 | return( |
28 | <AuthenticatedNavigation | 29 | <AuthenticatedNavigation |
29 | data = {this.props.data} | 30 | data = {this.props.data} |
30 | /> | 31 | /> |
31 | ) | 32 | ) |
32 | }else{ | 33 | }else{ |
33 | return( | 34 | return( |
34 | <Navbar> | 35 | <Navbar> |
35 | <Navbar.Header> | 36 | <Navbar.Header> |
36 | <Navbar.Brand> | 37 | <Navbar.Brand> |
37 | <Link to="/">Application Name</Link> | 38 | <Link to="/">Application Name</Link> |
38 | </Navbar.Brand> | 39 | </Navbar.Brand> |
39 | <Navbar.Toggle /> | 40 | <Navbar.Toggle /> |
40 | </Navbar.Header> | 41 | </Navbar.Header> |
41 | <Navbar.Collapse> | 42 | <Navbar.Collapse> |
42 | <PublicNavigation /> | 43 | <PublicNavigation /> |
43 | </Navbar.Collapse> | 44 | </Navbar.Collapse> |
44 | </Navbar> | 45 | </Navbar> |
45 | 46 | ||
46 | ) | 47 | ) |
47 | } | 48 | } |
48 | 49 | ||
49 | return ( | 50 | return ( |
50 | <div></div> | 51 | <div></div> |
51 | ); | 52 | ); |
52 | }; | 53 | }; |
53 | 54 | ||
54 | }; | 55 | }; |
55 | 56 |
imports/client/views/nonOrg/app/module/navigation/AuthenticatedNavigation.js
1 | import React from 'react'; | 1 | import React from 'react'; |
2 | import { browserHistory } from 'react-router'; | 2 | import { browserHistory } from 'react-router'; |
3 | import { LinkContainer } from 'react-router-bootstrap'; | 3 | import { LinkContainer } from 'react-router-bootstrap'; |
4 | import { Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; | 4 | import { Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; |
5 | import { Meteor } from 'meteor/meteor'; | 5 | import { Meteor } from 'meteor/meteor'; |
6 | 6 | ||
7 | const handleLogout = () => Meteor.logout(() => browserHistory.push('/login')); | 7 | const handleLogout = () => Meteor.logout(() => browserHistory.push('/login')); |
8 | 8 | ||
9 | const userName = () => { | 9 | const userName = () => { |
10 | const user = Meteor.user(); | 10 | const user = Meteor.user(); |
11 | const name = user && user.profile ? user.profile.name : ''; | 11 | const name = user && user.profile ? user.profile.name : ''; |
12 | return user ? `${name.first} ${name.last}` : ''; | 12 | return user ? `${name.first} ${name.last}` : ''; |
13 | }; | 13 | }; |
14 | 14 | ||
15 | const AuthenticatedNavigation = () => ( | 15 | const AuthenticatedNavigation = () => ( |
16 | <div> | 16 | <div> |
17 | <Nav> | 17 | <Nav> |
18 | <LinkContainer to="/documents"> | 18 | <LinkContainer to="/documents"> |
19 | <NavItem eventKey={ 2 } href="/documents">Documents</NavItem> | 19 | <NavItem eventKey={ 2 } href="/documents">Documents</NavItem> |
20 | </LinkContainer> | 20 | </LinkContainer> |
21 | </Nav> | 21 | </Nav> |
22 | <Nav pullRight> | ||
23 | <NavDropdown eventKey={ 3 } title={ userName() } id="basic-nav-dropdown"> | ||
24 | <MenuItem eventKey={ 3.1 } onClick={ handleLogout }>Logout</MenuItem> | ||
25 | </NavDropdown> | ||
26 | </Nav> | ||
27 | </div> | 22 | </div> |
28 | ); | 23 | ); |
29 | 24 | ||
30 | export default AuthenticatedNavigation; | 25 | export default AuthenticatedNavigation; |
31 | 26 |
imports/client/views/nonOrg/app/module/navigation/index.js
1 | // import { AppNavigation } from '/imports/client/views/nonOrg/app/module/navigation/index' | 1 | // import { AppNavigation } from '/imports/client/views/nonOrg/app/module/navigation/index' |
2 | import _ from 'lodash'; | 2 | import _ from 'lodash'; |
3 | import { | 3 | import { |
4 | composeWithTracker, | 4 | composeWithTracker, |
5 | compose, | 5 | compose, |
6 | composeAll | 6 | composeAll |
7 | } from 'react-komposer'; | 7 | } from 'react-komposer'; |
8 | import { Loading } from '/imports/client/components/Loading'; | 8 | import { Loading } from '/imports/client/components/Loading'; |
9 | 9 | ||
10 | import { Orgs } from '/imports/collections/orgs/index'; | 10 | import { Orgs } from '/imports/collections/orgs/index'; |
11 | import { Users } from '/imports/collections/users/index'; | 11 | import { Users } from '/imports/collections/users/index'; |
12 | 12 | ||
13 | import { AppNavigation } from './AppNavigation'; | 13 | import { AppNavigation } from './AppNavigation'; |
14 | 14 | ||
15 | const meteorTick = (props, onData) => { | 15 | const meteorTick = (props, onData) => { |
16 | 16 | ||
17 | const handles = [ | 17 | const handles = [ |
18 | Meteor.subscribe('users.current'), | 18 | Meteor.subscribe('users.current'), |
19 | Meteor.subscribe('orgs.current') | 19 | Meteor.subscribe('orgs.current') |
20 | ]; | 20 | ]; |
21 | 21 | ||
22 | if(_.every(handles, (handle) => (handle.ready()) )) { | 22 | if(_.every(handles, (handle) => (handle.ready()) )) { |
23 | const user = Users.current(); | 23 | const user = Users.current(); |
24 | const org = Orgs.current(); | 24 | const org = Orgs.current(); |
25 | console.log(user); | ||
25 | onData(null, { | 26 | onData(null, { |
26 | data: { | 27 | data: { |
27 | user: user, | 28 | user: user, |
28 | org: org | 29 | org: org |
29 | }, | 30 | }, |
30 | }); | 31 | }); |
31 | } | 32 | } |
32 | 33 | ||
33 | return () => { | 34 | return () => { |
34 | _.each(handles, (handle) => handle.stop() ); | 35 | _.each(handles, (handle) => handle.stop() ); |
35 | }; | 36 | }; |
36 | }; | 37 | }; |
37 | 38 | ||
38 | 39 | ||
39 | const reduxTick = (props, onData) => { | 40 | const reduxTick = (props, onData) => { |
40 | onData(null, { | 41 | onData(null, { |
41 | data: {} | 42 | data: {} |
42 | }); | 43 | }); |
43 | }; | 44 | }; |
44 | 45 | ||
45 | 46 | ||
46 | export const AppNavigationController = composeAll( | 47 | export const AppNavigationController = composeAll( |
47 | composeWithTracker(meteorTick, Loading), | 48 | composeWithTracker(meteorTick, Loading), |
48 | compose(reduxTick, Loading), | 49 | compose(reduxTick, Loading), |
49 | )(AppNavigation); | 50 | )(AppNavigation); |
50 | 51 |
imports/client/views/verify/EmailPane.js
File was created | 1 | import React from 'react'; | |
2 | import { Link } from 'react-router'; | ||
3 | import { If, Case } from '/imports/client/components/Logic'; | ||
4 | import { Bert } from 'meteor/themeteorchef:bert'; | ||
5 | |||
6 | import { Row, Col, Alert,ControlLabel, | ||
7 | FormGroup, FormControl, Button } from 'react-bootstrap'; | ||
8 | |||
9 | |||
10 | export class EmailPane extends React.Component { | ||
11 | |||
12 | constructor(props) { | ||
13 | super(props); | ||
14 | |||
15 | this.state = { | ||
16 | email: props.user.emails[0].address, | ||
17 | form: false, | ||
18 | }; | ||
19 | }; | ||
20 | |||
21 | onUpdate(key, val) { | ||
22 | this.setState({[key]: val}); | ||
23 | }; | ||
24 | |||
25 | onSetEmail() { | ||
26 | startEmailVerification.call({email: this.state.email}, (err, res)=>{ | ||
27 | Bert.alert('New verification email sent!', 'success'); | ||
28 | |||
29 | }); | ||
30 | this.setState({form: false}); | ||
31 | }; | ||
32 | |||
33 | onShowForm() { | ||
34 | this.setState({form: true}); | ||
35 | }; | ||
36 | |||
37 | renderForm() { | ||
38 | const {user} = this.props; | ||
39 | |||
40 | return ( | ||
41 | <div className = "wizardPane-box"> | ||
42 | <div className = "wizardPane-section"> | ||
43 | <div className="icon-circle icon-lg"> | ||
44 | <i className="icon icon-simple icon-envelope"></i> | ||
45 | </div> | ||
46 | <div className = "wizardPane-title"> | ||
47 | Set your email address | ||
48 | </div> | ||
49 | <div className = "col-xs-8 horizontalform verifyEmail wizardPane-text"> | ||
50 | <div className="form-row"> | ||
51 | <Col sm={4}> | ||
52 | Enter email | ||
53 | </Col> | ||
54 | <Col sm={8}> | ||
55 | <input | ||
56 | type = "text" | ||
57 | value = {this.state.email} | ||
58 | onChange = {(evt) => this.onUpdate('email', evt.currentTarget.value)} | ||
59 | placeholder = "Email" | ||
60 | /> | ||
61 | </Col> | ||
62 | </div> | ||
63 | |||
64 | </div> | ||
65 | </div> | ||
66 | <div className = "wizardPane-section wizardPane-footer"> | ||
67 | <div | ||
68 | className = "wizardPane-button btn btn-blue" | ||
69 | onClick = {() => this.onSetEmail()} | ||
70 | > | ||
71 | Send verification email | ||
72 | </div> | ||
73 | </div> | ||
74 | </div> | ||
75 | ); | ||
76 | }; | ||
77 | |||
78 | renderMessage() { | ||
79 | const {user} = this.props; | ||
80 | |||
81 | return ( | ||
82 | <div className = "wizardPane-box"> | ||
83 | <div className = "wizardPane-section"> | ||
84 | |||
85 | <div className = "wizardPane-title"> | ||
86 | <i className="icon-envelope icon"></i> | ||
87 | <h3>Verify your email</h3> | ||
88 | </div> | ||
89 | <div className = "wizardPane-text"> | ||
90 | Check your email โย we sent a verification link to<br/> | ||
91 | {user.emails[0].address} | ||
92 | </div> | ||
93 | </div> | ||
94 | <div className = "wizardPane-section wizardPane-footer"> | ||
95 | <div className="btn" | ||
96 | className = "wizardPane-link" | ||
97 | onClick = {() => this.onShowForm()} | ||
98 | > | ||
99 | Email did not arrive or want to use a different email? | ||
100 | </div> | ||
101 | </div> | ||
102 | </div> | ||
103 | ); | ||
104 | }; | ||
105 | |||
106 | render() { | ||
107 | return this.state.form ? this.renderForm() : this.renderMessage(); | ||
108 | }; | ||
109 | |||
110 | }; | ||
111 |
imports/client/views/verify/module/VerifyLayout.js
File was created | 1 | import _ from 'lodash'; | |
2 | import { Meteor } from 'meteor/meteor'; | ||
3 | |||
4 | import React, { Component } from 'react'; | ||
5 | import { Link } from 'react-router'; | ||
6 | import { If, Case } from '/imports/client/components/Logic'; | ||
7 | import { Avatar } from '/imports/client/components/Avatar'; | ||
8 | |||
9 | import { logout } from '/imports/client/app/utils/loginMethods'; | ||
10 | |||
11 | import { EmailPane } from '/imports/client/views/verify/EmailPane'; | ||
12 | import ReactSVG from 'react-svg' | ||
13 | |||
14 | |||
15 | export class VerifyLayout extends Component { | ||
16 | |||
17 | render() { | ||
18 | const user = this.props.data.user; | ||
19 | |||
20 | return ( | ||
21 | <div className = "wizardLayout-box"> | ||
22 | <div className = "wizardLayout-top"> | ||
23 | <div className="container"> | ||
24 | <div className = "wizardLayout-topSpace logo-space-0"> | ||
25 | <ReactSVG | ||
26 | path="/files/images/svg/logo--white.svg" | ||
27 | className="enterPane__logo" | ||
28 | /> | ||
29 | </div> | ||
30 | <div className = "wizardLayout-topGroup"> | ||
31 | <div className = "wizardLayout-topItem"> | ||
32 | <Avatar | ||
33 | user = {user} | ||
34 | size = {20} | ||
35 | small = {true} | ||
36 | /> | ||
37 | | ||
38 | {user.getFullName()} | ||
39 | </div> | ||
40 | <div | ||
41 | className = "wizardLayout-topItem" | ||
42 | onClick = {() => logout()} | ||
43 | > | ||
44 | <i className="icon icon-simple icon-power"></i> | ||
45 | </div> | ||
46 | </div> | ||
47 | </div> | ||
48 | </div> | ||
49 | |||
50 | <div className = "wizardLayout-wrap"> | ||
51 | <div className = "wizardLayout-content"> | ||
52 | |||
53 | <EmailPane | ||
54 | user = {user} | ||
55 | /> | ||
56 | |||
57 | </div> | ||
58 | </div> | ||
59 | </div> | ||
60 | ); | ||
61 | }; | ||
62 | |||
63 | }; | ||
64 | |||
65 | |||
66 |
imports/client/views/verify/module/index.js
File was created | 1 | // import { VerifyModule } from '/imports/client/views/verify/module/index' | |
2 | import { | ||
3 | composeWithTracker, | ||
4 | compose, | ||
5 | composeAll | ||
6 | } from 'react-komposer'; | ||
7 | import { VerifyLayout } from './VerifyLayout'; | ||
8 | import { Loading } from '/imports/client/components/Loading'; | ||
9 | |||
10 | import { Users } from '/imports/collections/users/index'; | ||
11 | |||
12 | |||
13 | const meteorTick = (props, onData) => { | ||
14 | |||
15 | const handles = [ | ||
16 | Meteor.subscribe('users.current'), | ||
17 | ]; | ||
18 | |||
19 | if(_.every(handles, (handle) => (handle.ready()) )) { | ||
20 | const user = Users.current(); | ||
21 | onData(null, { | ||
22 | data: { | ||
23 | user: user, | ||
24 | }, | ||
25 | }); | ||
26 | } | ||
27 | |||
28 | return () => { | ||
29 | _.each(handles, (handle) => handle.stop() ); | ||
30 | }; | ||
31 | }; | ||
32 | |||
33 | |||
34 | const reduxTick = (props, onData) => { | ||
35 | onData(null, { | ||
36 | data: {} | ||
37 | }); | ||
38 | }; | ||
39 | |||
40 | |||
41 | export const VerifyModule = composeAll( | ||
42 | composeWithTracker(meteorTick, Loading), | ||
43 | compose(reduxTick, Loading), | ||
44 | )(VerifyLayout); | ||
45 | |||
46 | |||
47 | |||
48 | |||
49 | |||
50 | |||
51 |
imports/server/accounts/creation.js
1 | import _ from 'lodash'; | 1 | import _ from 'lodash'; |
2 | import { Accounts } from 'meteor/accounts-base'; | 2 | import { Accounts } from 'meteor/accounts-base'; |
3 | import { SimpleSchema } from 'meteor/aldeed:simple-schema'; | 3 | import { SimpleSchema } from 'meteor/aldeed:simple-schema'; |
4 | import { ValidatedMethod } from 'meteor/mdg:validated-method'; | 4 | import { ValidatedMethod } from 'meteor/mdg:validated-method'; |
5 | 5 | ||
6 | import { Orgs } from '/imports/collections/orgs/index'; | 6 | import { Orgs } from '/imports/collections/orgs/index'; |
7 | import { Users } from '/imports/collections/users/index'; | 7 | import { Users } from '/imports/collections/users/index'; |
8 | 8 | ||
9 | 9 | ||
10 | Accounts.validateNewUser((user) => { | 10 | Accounts.validateNewUser((user) => { |
11 | return !!user; | 11 | return !!user; |
12 | }); | 12 | }); |
13 | 13 | ||
14 | Accounts.onCreateUser((options, user) => { | 14 | Accounts.onCreateUser((options, user) => { |
15 | |||
15 | if(options.orgSlug){ | 16 | if(options.orgSlug){ |
16 | orgId = Orgs.insert({ | 17 | orgId = Orgs.insert({ |
17 | slug: options.orgSlug, | 18 | slug: options.orgSlug, |
18 | name: options.orgName, | 19 | name: options.orgName, |
19 | setup: 1, | 20 | setup: 1, |
20 | users: [{ | 21 | users: [{ |
21 | userId: user._id, | 22 | userId: user._id, |
22 | role: Users.roles.ADMIN, | 23 | role: Users.roles.ADMIN, |
23 | }], | 24 | }], |
24 | }); | 25 | }); |
25 | } | 26 | } |
27 | console.log("options"); | ||
28 | console.log(options); | ||
29 | console.log("user"); | ||
30 | console.log(user); | ||
26 | _.assign(user, { | 31 | _.assign(user, { |
27 | role: Users.roles.ADMIN, | 32 | role: Users.roles.ADMIN, |
28 | orgId: orgId, | 33 | orgId: orgId, |
29 | firstName: options.profile.firstName, | 34 | firstName: options.profile.name.first, |
30 | lastName: options.profile.lastName, | 35 | lastName: options.profile.name.last, |
31 | }); | 36 | }); |
37 | console.log(user); | ||
32 | return user; | 38 | return user; |
33 | }); | 39 | }); |
34 | 40 |
imports/server/emails/verifyEmail.js
1 | import _ from 'lodash'; | 1 | import _ from 'lodash'; |
2 | import { Accounts } from 'meteor/accounts-base'; | 2 | import { Accounts } from 'meteor/accounts-base'; |
3 | import { Orgs } from '/imports/collections/orgs/index'; | ||
3 | 4 | ||
4 | Accounts.config({ | 5 | Accounts.config({ |
5 | sendVerificationEmail: true | 6 | sendVerificationEmail: true |
6 | }); | 7 | }); |
7 | 8 | ||
8 | Accounts.emailTemplates.verifyEmail = { | 9 | Accounts.emailTemplates.verifyEmail = { |
9 | subject() { | 10 | subject() { |
10 | return '[YoungDesk] Verify Your Email Address'; | 11 | return '[YoungDesk] Verify Your Email Address'; |
11 | }, | 12 | }, |
12 | text(user, url) { | 13 | text(user, url) { |
13 | console.log(user); | ||
14 | if(user.firstName){ | ||
15 | const name = user.firstName; | ||
16 | }else{ | ||
17 | const name = user.profile.firstName; | ||
18 | } | ||
19 | const theUrl = Meteor.absoluteUrl(`back/verifyEmail/${_.last(url.split('/'))}`); | 14 | const theUrl = Meteor.absoluteUrl(`back/verifyEmail/${_.last(url.split('/'))}`); |
15 | org = Orgs.findOne({"_id":user.orgId}); | ||
20 | 16 | ||
17 | OrgUrl = theUrl.replace("http://","http://"+org.slug+"."); | ||
21 | return ( | 18 | return ( |
22 | ` | 19 | ` |
23 | Hello, ${name}! | 20 | Hello, ${user.firstName}! |
24 | 21 | ||
25 | 22 | ||
26 | To verify your email address, visit the following link: | 23 | To verify your email address, visit the following link: |
27 | 24 | ||
28 | ${theUrl} | 25 | ${OrgUrl} |
29 | 26 | ||
30 | If you did not request this verification, please ignore this email. | 27 | If you did not request this verification, please ignore this email. |
31 | 28 | ||
32 | ` | 29 | ` |
33 | ); | 30 | ); |