diff --git a/imports/client/components/validationMethods.js b/imports/client/components/validationMethods.js index 4695f7f..dae3c25 100644 --- a/imports/client/components/validationMethods.js +++ b/imports/client/components/validationMethods.js @@ -42,7 +42,6 @@ export default class Validation{ isValidACN(str){ str = String(str); - console.log(str); if(/^\d+$/.test(str) && str.length ==9){ return true; } else{ diff --git a/imports/client/layouts/OrgApp.js b/imports/client/layouts/OrgApp.js index e465a04..2974b4d 100644 --- a/imports/client/layouts/OrgApp.js +++ b/imports/client/layouts/OrgApp.js @@ -1,6 +1,6 @@ import React from 'react'; import { Grid } from 'react-bootstrap'; -import AppNavigation from '/imports/client/views/org/module/navigation/AppNavigation'; +import AppNavigation from '/imports/client/views/org/app/module/navigation/AppNavigation'; const App = ({ children }) => (
diff --git a/imports/client/views/nonOrg/enter/SignupView.js b/imports/client/views/nonOrg/enter/SignupView.js index bec41b1..1504022 100644 --- a/imports/client/views/nonOrg/enter/SignupView.js +++ b/imports/client/views/nonOrg/enter/SignupView.js @@ -27,7 +27,6 @@ export default class Signup extends React.Component { event.preventDefault(); } checkExistingOrgSlug() { - console.log(this.state.orgSlug); if(this.state.orgSlug==""){return null} searchOrg = Orgs.find({slug:this.state.orgSlug}).fetch(); if(searchOrg.length>0){ @@ -55,7 +54,7 @@ export default class Signup extends React.Component { type ="text" ref ="orgSlug" name ="orgSlug" - placeholder ="School Name" + placeholder ="School URL" onChange = {(e) => this.handleChange(e)} /> @yd.com @@ -63,6 +62,19 @@ export default class Signup extends React.Component { + + + + First Name + + + + diff --git a/imports/client/views/nonOrg/enter/signup.js b/imports/client/views/nonOrg/enter/signup.js index de9c35c..890f3da 100644 --- a/imports/client/views/nonOrg/enter/signup.js +++ b/imports/client/views/nonOrg/enter/signup.js @@ -12,6 +12,8 @@ let component; const getUserData = () => ({ email: document.querySelector('[name="emailAddress"]').value, password: document.querySelector('[name="password"]').value, + orgSlug: document.querySelector('[name="orgSlug"]').value, + orgName: document.querySelector('[name="orgName"]').value, profile: { name: { first: document.querySelector('[name="firstName"]').value, @@ -36,7 +38,6 @@ $.validator.addMethod( "uniqueSlug", function(value, element) { slug = Orgs.find({slug:value}).fetch(); - console.log(slug); if(slug.length>0){ return false; }else{ diff --git a/imports/client/views/org/app/module/AppLayout.js b/imports/client/views/org/app/module/AppLayout.js new file mode 100644 index 0000000..fcaa68d --- /dev/null +++ b/imports/client/views/org/app/module/AppLayout.js @@ -0,0 +1,44 @@ +import _ from 'lodash'; +import { Meteor } from 'meteor/meteor'; +import React, { Component } from 'react'; +import { Link } from 'react-router'; +import { Avatar } from '/imports/client/components/Avatar'; +import { Icon } from '/imports/client/components/Icon'; +import classNames from 'classnames'; + + +export class AppLayout extends Component { + + + + + + + render() { + const {user} = this.props.data; + + if(!user) { + return ( +
+ ); + } + return ( +
+ +
+
+
+ +
+
+
+ { this.props.children } +
+
+
+
+
+ ); + }; + +}; diff --git a/imports/client/views/org/app/module/Index.js b/imports/client/views/org/app/module/Index.js new file mode 100644 index 0000000..8ae05c8 --- /dev/null +++ b/imports/client/views/org/app/module/Index.js @@ -0,0 +1,46 @@ +// import { AppModule } from '/imports/client/views/app/module/index' +import { + composeWithTracker, + compose, + composeAll + } from 'react-komposer'; +import { AppLayout } from './AppLayout'; +import { Loading } from '/imports/client/components/Loading'; + +import { Users } from '/imports/collections/users/index'; +import { Orgs } from '/imports/collections/orgs/index'; + + +const meteorTick = (props, onData) => { + + const handles = [ + Meteor.subscribe('users.current'), + ]; + + if(_.every(handles, (handle) => (handle.ready()) )) { + const user = Users.current(); + onData(null, { + data: { + user: user, + }, + }); + } + + return () => { + _.each(handles, (handle) => handle.stop() ); + }; +}; + + +const reduxTick = (props, onData) => { + onData(null, { + location: props.location, + data: {} + }); +}; + + +export const AppModule = composeAll( + composeWithTracker(meteorTick, Loading), + compose(reduxTick, Loading), +)(AppLayout); diff --git a/imports/client/views/org/app/module/navigation/AppNavigation.js b/imports/client/views/org/app/module/navigation/AppNavigation.js new file mode 100644 index 0000000..ff33f9a --- /dev/null +++ b/imports/client/views/org/app/module/navigation/AppNavigation.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Navbar } from 'react-bootstrap'; +import { Link } from 'react-router'; +import PublicNavigation from './PublicNavigation.js'; +import AuthenticatedNavigation from './AuthenticatedNavigation.js'; +import '/imports/client/assets/css/icons/icomoon/styles.css'; +import '/imports/client/assets/css/bootstrap.css'; +import '/imports/client/assets/css/core.css'; +import '/imports/client/assets/css/components.css'; +import '/imports/client/assets/css/colors.css'; +const renderNavigation = hasUser => (hasUser ? : ); +const AppNavigation = ({ hasUser }) => ( + + + + Home + + + + + { renderNavigation(hasUser) } + + +); + +AppNavigation.propTypes = { + hasUser: React.PropTypes.object, +}; + +export default AppNavigation; diff --git a/imports/client/views/org/app/module/navigation/AuthenticatedNavigation.js b/imports/client/views/org/app/module/navigation/AuthenticatedNavigation.js new file mode 100644 index 0000000..87a0c38 --- /dev/null +++ b/imports/client/views/org/app/module/navigation/AuthenticatedNavigation.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { browserHistory } from 'react-router'; +import { LinkContainer } from 'react-router-bootstrap'; +import { Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; +import { Meteor } from 'meteor/meteor'; + +const handleLogout = () => Meteor.logout(() => browserHistory.push('/login')); + +const userName = () => { + const user = Meteor.user(); + const name = user && user.profile ? user.profile.name : ''; + return user ? `${name.first} ${name.last}` : ''; +}; + +const AuthenticatedNavigation = () => ( +
+ + +
+); + +export default AuthenticatedNavigation; diff --git a/imports/client/views/org/app/module/navigation/Loading.js b/imports/client/views/org/app/module/navigation/Loading.js new file mode 100644 index 0000000..c97a7eb --- /dev/null +++ b/imports/client/views/org/app/module/navigation/Loading.js @@ -0,0 +1,30 @@ +import React from 'react'; + +const Loading = () => ( + + + + + +); + +export default Loading; diff --git a/imports/client/views/org/app/module/navigation/PublicNavigation.js b/imports/client/views/org/app/module/navigation/PublicNavigation.js new file mode 100644 index 0000000..d04fc80 --- /dev/null +++ b/imports/client/views/org/app/module/navigation/PublicNavigation.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { LinkContainer } from 'react-router-bootstrap'; +import { Nav, NavItem } from 'react-bootstrap'; + +const PublicNavigation = () => ( + +); + +export default PublicNavigation; diff --git a/imports/client/views/org/app/module/navigation/index.js b/imports/client/views/org/app/module/navigation/index.js new file mode 100644 index 0000000..65f743d --- /dev/null +++ b/imports/client/views/org/app/module/navigation/index.js @@ -0,0 +1,7 @@ +import { composeWithTracker } from 'react-komposer'; +import { Meteor } from 'meteor/meteor'; +import AppNavigation from '../components/AppNavigation.js'; + +const composer = (props, onData) => onData(null, { hasUser: Meteor.user() }); + +export default composeWithTracker(composer, {}, {}, { pure: false })(AppNavigation); diff --git a/imports/client/views/org/enter/login/LoginView.js b/imports/client/views/org/enter/login/LoginView.js index ee5204a..31f67bf 100644 --- a/imports/client/views/org/enter/login/LoginView.js +++ b/imports/client/views/org/enter/login/LoginView.js @@ -7,7 +7,6 @@ import handleLogin from './login'; export class LoginView extends React.Component { componentDidMount() { - console.log(this); handleLogin({ component: this }); } diff --git a/imports/client/views/org/module/Index.js b/imports/client/views/org/module/Index.js deleted file mode 100644 index 5da010c..0000000 --- a/imports/client/views/org/module/Index.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { Jumbotron } from 'react-bootstrap'; - -const Index = () => ( -
- -

Base

-

A starting point for Meteor applications.

-

Read the Documentation

-

Currently at v4.11.1

-
-
-); - -export default Index; diff --git a/imports/client/views/org/module/navigation/AppNavigation.js b/imports/client/views/org/module/navigation/AppNavigation.js deleted file mode 100644 index a30288a..0000000 --- a/imports/client/views/org/module/navigation/AppNavigation.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { Navbar } from 'react-bootstrap'; -import { Link } from 'react-router'; -import PublicNavigation from './PublicNavigation.js'; -import AuthenticatedNavigation from './AuthenticatedNavigation.js'; -import '/imports/client/assets/css/icons/icomoon/styles.css'; -import '/imports/client/assets/css/bootstrap.css'; -import '/imports/client/assets/css/core.css'; -import '/imports/client/assets/css/components.css'; -import '/imports/client/assets/css/colors.css'; -const renderNavigation = hasUser => (hasUser ? : ); -console.log(React.PropTypes); -const AppNavigation = ({ hasUser }) => ( - - - - Home - - - - - { renderNavigation(hasUser) } - - -); - -AppNavigation.propTypes = { - hasUser: React.PropTypes.object, -}; - -export default AppNavigation; diff --git a/imports/client/views/org/module/navigation/AuthenticatedNavigation.js b/imports/client/views/org/module/navigation/AuthenticatedNavigation.js deleted file mode 100644 index 87a0c38..0000000 --- a/imports/client/views/org/module/navigation/AuthenticatedNavigation.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { browserHistory } from 'react-router'; -import { LinkContainer } from 'react-router-bootstrap'; -import { Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; -import { Meteor } from 'meteor/meteor'; - -const handleLogout = () => Meteor.logout(() => browserHistory.push('/login')); - -const userName = () => { - const user = Meteor.user(); - const name = user && user.profile ? user.profile.name : ''; - return user ? `${name.first} ${name.last}` : ''; -}; - -const AuthenticatedNavigation = () => ( -
- - -
-); - -export default AuthenticatedNavigation; diff --git a/imports/client/views/org/module/navigation/Loading.js b/imports/client/views/org/module/navigation/Loading.js deleted file mode 100644 index c97a7eb..0000000 --- a/imports/client/views/org/module/navigation/Loading.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; - -const Loading = () => ( - - - - - -); - -export default Loading; diff --git a/imports/client/views/org/module/navigation/PublicNavigation.js b/imports/client/views/org/module/navigation/PublicNavigation.js deleted file mode 100644 index d04fc80..0000000 --- a/imports/client/views/org/module/navigation/PublicNavigation.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { LinkContainer } from 'react-router-bootstrap'; -import { Nav, NavItem } from 'react-bootstrap'; - -const PublicNavigation = () => ( - -); - -export default PublicNavigation; diff --git a/imports/client/views/org/module/navigation/index.js b/imports/client/views/org/module/navigation/index.js deleted file mode 100644 index 65f743d..0000000 --- a/imports/client/views/org/module/navigation/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { composeWithTracker } from 'react-komposer'; -import { Meteor } from 'meteor/meteor'; -import AppNavigation from '../components/AppNavigation.js'; - -const composer = (props, onData) => onData(null, { hasUser: Meteor.user() }); - -export default composeWithTracker(composer, {}, {}, { pure: false })(AppNavigation); diff --git a/imports/collections/orgs/index.js b/imports/collections/orgs/index.js index 7f1ae83..9f269eb 100644 --- a/imports/collections/orgs/index.js +++ b/imports/collections/orgs/index.js @@ -87,8 +87,8 @@ Orgs.deny({ Orgs.schema = new SimpleSchema({ - name: { type: String, }, - slug: { type: String, optional: true}, + name: { type: String }, + slug: { type: String }, address: { type: String, optional: true}, users: { type: [new SimpleSchema({ diff --git a/imports/collections/students/index.js b/imports/collections/students/index.js new file mode 100644 index 0000000..545a927 --- /dev/null +++ b/imports/collections/students/index.js @@ -0,0 +1,207 @@ +// import { Users } from '/imports/collections/users/index'; +// import { Users } from '/imports/collections/users/index'; + +import _ from 'lodash'; +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +import { Orgs } from '/imports/collections/orgs/index'; + +class User { + + constructor(doc) { + _.assign(this, doc); + }; + + isEmailVerified() { + return !! _.find(this.emails, x => x.verified); + }; + + isPhoneVerified() { + return !! _.find(this.phones, x => x.verified); + }; + + isIdentityVerified() { + return !! _.find(this.identities, x => x.verified); + }; + + getRole() { + const org = Orgs.findOne({_id: this.orgId}); + if(!org) return null; + const connection = _.find(org.users, {userId: this._id}); + if(!connection) return null; + return connection.role; + }; + + getFullName() { + return `${this.firstName} ${this.lastName}`; + }; + getFirstName() { + return `${this.firstName}`; + }; + getLastName() { + return `${this.lastName}`; + }; + getEmail() { + return `${this.emails[0].address}`; + }; + getOrganization(){ + return `${this.orgId}`; + }; + + getNameByUserId(userId){ + var user = Users.findOne({"_id":userId}); + return user.firstName + " " + user.lastName; + } + getAvatarUrl() { + let random = parseInt(this._id.substr(0, 4), 36); + random = '' + (random % 32); + while(random.length < 3) random = '0' + random; + return `/files/random/random${ random }.png`; + }; +}; + +export { User }; + + +const transform = function(doc) { + return new User(doc); +}; + +export const Users = { + + current: function() { + return Meteor.users.findOne({_id: Meteor.userId()}, _.extend({transform: transform})); + }, + + find: function(selector, options) { + return Meteor.users.find(selector || {}, _.extend({transform: transform}, options)); + }, + + findOne: function(selector, options) { + return Meteor.users.findOne(selector || {}, _.extend({transform: transform}, options)); + }, + + insert: _.bind(Meteor.users.insert, Meteor.users), + update: _.bind(Meteor.users.update, Meteor.users), + remove: _.bind(Meteor.users.remove, Meteor.users), + allow: _.bind(Meteor.users.allow, Meteor.users), + deny: _.bind(Meteor.users.deny, Meteor.users), + attachSchema: _.bind(Meteor.users.attachSchema, Meteor.users), + +}; + + +Users.deny({ + insert() { return true; }, + update() { return true; }, + remove() { return true; }, +}); + +Users.roles = { + 'STUDENT': 'STUDENT', + 'TEACHER': 'TEACHER', + 'ADMIN': 'ADMIN', + 'PARENT': 'PARENT' +}; + + +Users.schema = new SimpleSchema({ + roles: { type: String }, + orgId: { type: String }, + admissionId: { type: String, optional: true }, + enrollmentDate: { type: String, optional: true }, + address: { type: String, optional: true }, + prefix: { type: String, optional: true }, + firstName: { type: String, optional: true }, + middlename: { type: String, optional: true }, + lastName: { type: String, optional: true }, + gender: { type: String, optional: true }, + dob: { type: String, optional: true }, + rollNo: { type: String, optional: true }, + class: { type: String, optional: true }, + section: { type: String, optional: true }, + bloodGroup: { type: String, optional: true }, + community: { type: String, optional: true }, + nationality: { type: String, optional: true }, + motherTongue: { type: String, optional: true }, + motherTongue: { type: String, optional: true }, + religion: { type: String, optional: true }, + permanentAddress: { + type: new SimpleSchema({ + home: { type: String, optional: true }, + street: { type: String, optional: true }, + town: { type: String, optional: true }, + city: { type: String, optional: true }, + state: { type: String, optional: true }, + zip: { type: String, optional: true }, + }), + }, + parent: { + type: [new SimpleSchema({ + id: { type: String, }, + relatinship: { type: Boolean, }, + })], + minCount: 1, + }, + emails: { + type: [new SimpleSchema({ + address: { type: String, }, + verified: { type: Boolean, }, + })], + }, + prevInstitute: { + type: [new SimpleSchema({ + name: { type: String, }, + fromYear: { type: Boolean, }, + toYear: { type: Boolean, }, + ydId: { type: Boolean, }, + })], + optional: true + }, + + phones: { + type: [new SimpleSchema({ + country: { type: String, }, + prefix: { type: String, }, + number: { type: String, }, + verified: { type: Boolean, }, + })], + optional: true + }, + + services: { + type: Object, + optional: true, + blackbox: true, + }, + + isMetaUser: { type: Boolean, optional: true }, + + createdAt: { type: Date, autoValue: function(){return new Date();}} + +}); + +Users.attachSchema(Users.schema); + +Users.privateFields = { + orgId: 1, + address: 1, + + firstName: 1, + lastName: 1, + emails: 1, + phones: 1, + + isMetaUser: 1, + createdAt: 1, +}; + +Users.publicFields = { + firstName: 1, + lastName: 1, + emails: 1, + + createdAt: 1, +}; diff --git a/imports/collections/users/index.js b/imports/collections/users/index.js index de8165a..aadd8c9 100644 --- a/imports/collections/users/index.js +++ b/imports/collections/users/index.js @@ -108,59 +108,20 @@ Users.roles = { Users.schema = new SimpleSchema({ - roles: { type: String }, + role: { type: String }, orgId: { type: String }, - admissionId: { type: String }, - enrollmentDate: { type: String, optional: true }, - address: { type: String, optional: true }, prefix: { type: String, optional: true }, firstName: { type: String, optional: true }, middlename: { type: String, optional: true }, lastName: { type: String, optional: true }, gender: { type: String, optional: true }, dob: { type: String, optional: true }, - rollNo: { type: String, optional: true }, - class: { type: String, optional: true }, - section: { type: String, optional: true }, - bloodGroup: { type: String, optional: true }, - community: { type: String, optional: true }, - nationality: { type: String, optional: true }, - motherTongue: { type: String, optional: true }, - motherTongue: { type: String, optional: true }, - religion: { type: String, optional: true }, - permanentAddress: { - type: new SimpleSchema({ - home: { type: String, optional: true }, - street: { type: String, optional: true }, - town: { type: String, optional: true }, - city: { type: String, optional: true }, - state: { type: String, optional: true }, - zip: { type: String, optional: true }, - }), - }, - parent: { - type: [new SimpleSchema({ - id: { type: String, }, - relatinship: { type: Boolean, }, - })], - minCount: 1, - }, emails: { type: [new SimpleSchema({ address: { type: String, }, verified: { type: Boolean, }, })], }, - prevInstitute: { - type: [new SimpleSchema({ - name: { type: String, }, - fromYear: { type: Boolean, }, - toYear: { type: Boolean, }, - ydId: { type: Boolean, }, - })], - optional: true - }, - phones: { type: [new SimpleSchema({ country: { type: String, }, diff --git a/imports/collections/users/publications.js b/imports/collections/users/publications.js new file mode 100644 index 0000000..42beeda --- /dev/null +++ b/imports/collections/users/publications.js @@ -0,0 +1,14 @@ +import { Meteor } from 'meteor/meteor'; +import { check, Match } from 'meteor/check' +import { Users } from '/imports/collections/users/index'; +import { Orgs } from '/imports/collections/orgs/index'; + + + +Meteor.publish('users.current', function() { + return Users.find({ + _id: this.userId, + }, { + fields: Users.privateFields, + }); +}); diff --git a/imports/server/accounts/creation.js b/imports/server/accounts/creation.js index 83eed16..8e1bb79 100644 --- a/imports/server/accounts/creation.js +++ b/imports/server/accounts/creation.js @@ -12,7 +12,6 @@ Accounts.validateNewUser((user) => { }); Accounts.onCreateUser((options, user) => { - console.log(options); _.assign(user, { firstName: options.profile.firstName, lastName: options.profile.lastName, diff --git a/imports/startup/client/routes.js b/imports/startup/client/routes.js index 509b68c..1dfcb3e 100644 --- a/imports/startup/client/routes.js +++ b/imports/startup/client/routes.js @@ -16,12 +16,12 @@ import Index from '/imports/client/views/app/modu */ import App from '/imports/client/layouts/OrgApp'; -import OrgIndex from '/imports/client/views/org/module/Index'; +import { AppModule } from '/imports/client/views/org/app/module/Index'; import { orgLoginController } from '/imports/client/views/org/enter/login/index'; -import NotFound from '/imports/client/views/org/NotFound'; import RecoverPassword from '/imports/client/views/org/enter/RecoverPassword'; import ResetPassword from '/imports/client/views/org/enter/ResetPassword'; import { Orgs } from '/imports/collections/orgs/index'; +import NotFound from '/imports/client/views/org/NotFound'; /** * NonOrg Components @@ -50,7 +50,6 @@ const detectOrg = () => { } if(orgSlug!=""){ Meteor.call('checkExistingOrg', {slug:orgSlug}, function(err, res) { - console.log(res); if(res){ Session.set('orgId', res._id._str); render(getOrgRoutes(),document.getElementById('app')); @@ -75,7 +74,7 @@ There are three types of routes const getOrgRoutes = () => ( - + @@ -97,7 +96,7 @@ const getInvalidOrgRoute = () => ( const getNonOrgRoutes = () => ( - + diff --git a/imports/startup/server/accounts/creation.js b/imports/startup/server/accounts/creation.js index fd17c40..6feb688 100644 --- a/imports/startup/server/accounts/creation.js +++ b/imports/startup/server/accounts/creation.js @@ -3,6 +3,8 @@ import { Accounts } from 'meteor/accounts-base'; import { SimpleSchema } from 'meteor/aldeed:simple-schema'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import { Orgs } from '/imports/collections/orgs/index'; +import { Users } from '/imports/collections/users/index'; Accounts.validateNewUser((user) => { @@ -11,4 +13,23 @@ Accounts.validateNewUser((user) => { Accounts.onCreateUser((options, user) => { console.log(options); + if(options.orgSlug){ + orgId = Orgs.insert({ + slug: options.orgSlug, + name: options.orgName, + setup: 1, + users: [{ + userId: user._id, + role: Users.roles.ADMIN, + }], + }); + } + console.log(user); + _.assign(user, { + role: Users.roles.ADMIN, + orgId: orgId, + firstName: options.profile.firstName, + lastName: options.profile.lastName, + }); + return user; }); diff --git a/imports/startup/server/api.js b/imports/startup/server/api.js index a5e8d21..29b5eb6 100644 --- a/imports/startup/server/api.js +++ b/imports/startup/server/api.js @@ -3,3 +3,5 @@ import '../../api/documents/server/publications.js'; import '/imports/collections/orgs/publications' import '/imports/collections/orgs/methods'; + +import '/imports/collections/users/publications'; diff --git a/package.json b/package.json index 140497a..607925b 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,8 @@ "react-bootstrap": "^0.30.5", "react-dom": "^15.3.2", "react-komposer": "^1.13.1", - "react-router": "^3.0.0", - "react-router-bootstrap": "^0.23.1" + "react-router": "^2.6.1", + "react-router-bootstrap": "^0.23.1", + "react-svg": "^2.1.19" } }