From a77318f03bccbb42616d66a26190db2e42d809d5 Mon Sep 17 00:00:00 2001 From: Collin Schlager Date: Thu, 18 Feb 2021 19:03:40 -0800 Subject: [PATCH 01/25] Beging work hacking patient registration. --- ReactJS-Project-CardinalKit/src/App.tsx | 10 +- .../src/api/getAllUsers.ts | 45 +++++--- .../src/api/registerUser.ts | 55 +++++++++ ReactJS-Project-CardinalKit/src/api/user.ts | 4 +- .../src/components/Firebase/firebase.js | 34 ++++-- .../src/components/RegisterForm.js | 93 +++++++++++++++ .../src/components/RegisterPage.tsx | 91 +++++++++++++++ .../src/components/TimeInfoBubble.tsx | 108 ++++++++++-------- .../src/components/UserCard.tsx | 20 +++- .../src/components/UserDetailHeader.tsx | 4 +- .../src/components/UserList.tsx | 4 + .../src/components/UserPage.tsx | 2 +- .../src/components/UsersPage.tsx | 16 +++ .../src/constants/usersConstants.ts | 2 + .../src/sagas/usersSaga.ts | 13 +-- 15 files changed, 408 insertions(+), 93 deletions(-) create mode 100644 ReactJS-Project-CardinalKit/src/api/registerUser.ts create mode 100644 ReactJS-Project-CardinalKit/src/components/RegisterForm.js create mode 100644 ReactJS-Project-CardinalKit/src/components/RegisterPage.tsx diff --git a/ReactJS-Project-CardinalKit/src/App.tsx b/ReactJS-Project-CardinalKit/src/App.tsx index 1abb9aa..5fb6bf4 100644 --- a/ReactJS-Project-CardinalKit/src/App.tsx +++ b/ReactJS-Project-CardinalKit/src/App.tsx @@ -9,8 +9,9 @@ import { isAuthenticated } from './selectors/loginSelectors'; import Header from './components/Header'; import LoginPage from './components/LoginPage'; import NotFoundPage from './components/NotFoundPage'; -import UsersPage from './components/UsersPage'; +import RegisterPage from './components/RegisterPage'; import UserPage from './components/UserPage'; +import UsersPage from './components/UsersPage'; interface AppProps { isAuth: boolean; @@ -27,7 +28,12 @@ class App extends React.Component { - } /> + } + /> + diff --git a/ReactJS-Project-CardinalKit/src/api/getAllUsers.ts b/ReactJS-Project-CardinalKit/src/api/getAllUsers.ts index 5b23e2b..ca0e6ac 100644 --- a/ReactJS-Project-CardinalKit/src/api/getAllUsers.ts +++ b/ReactJS-Project-CardinalKit/src/api/getAllUsers.ts @@ -1,37 +1,54 @@ -import Firebase from '../components/Firebase'; import app from 'firebase/app'; +import Firebase from '../components/Firebase'; export function getAllFirebaseUsers(): Promise { const firebase = new Firebase(); - return firebase.users().get().then(function(doc) { + return firebase + .users() + .get() + .then(function(doc) { return doc; - }).catch(function(error) { - console.log("Error getting document:", error); + }) + .catch(function(error) { + console.log('Error getting document:', error); return error; - }); + }); + // return firebase.users().get().then(function(doc) { + // return doc; + // }).catch(function(error) { + // console.log("Error getting document:", error); + // return error; + // }); } export function getFirebaseUser(uid: String): Promise { const firebase = new Firebase(); - return firebase.user(uid).get().then(function(doc) { + return firebase + .user(uid) + .get() + .then(function(doc) { return doc; - }).catch(function(error) { - console.log("Error getting document:", error); + }) + .catch(function(error) { + console.log('Error getting document:', error); return error; - }); + }); } export function getSurveys(uid: String): Promise { const firebase = new Firebase(); - return firebase.surveys(uid).get().then(function(doc) { + return firebase + .surveys(uid) + .get() + .then(function(doc) { return doc; - }).catch(function(error) { - console.log("Error getting document:", error); + }) + .catch(function(error) { + console.log('Error getting document:', error); return error; - }); + }); } - /* import { UserDetails } from './user'; diff --git a/ReactJS-Project-CardinalKit/src/api/registerUser.ts b/ReactJS-Project-CardinalKit/src/api/registerUser.ts new file mode 100644 index 0000000..412c3d6 --- /dev/null +++ b/ReactJS-Project-CardinalKit/src/api/registerUser.ts @@ -0,0 +1,55 @@ +import app from 'firebase/app'; +import Firebase from '../components/Firebase'; + +let actionCodeSettings = { + // URL you want to redirect back to. The domain (www.example.com) for this + // URL must be in the authorized domains list in the Firebase Console. + // url: 'https://www.example.com/finishSignUp?cartId=1234', + url: 'cs342-alpha-9bb64.firebaseapp.com', + // This must be true. + handleCodeInApp: true, + // iOS: { + // bundleId: 'com.example.ios' + // }, + // android: { + // packageName: 'com.example.android', + // installApp: true, + // minimumVersion: '12' + // }, + dynamicLinkDomain: 'cs342-alpha-9bb64.firebaseapp.com', +}; + +export function registerNewUser(user: any): Promise { + const firebase = new Firebase(); + console.log('Registering a new user!'); + let userRef = firebase.db + .collection(`registered-patients`) + .add(user) + .then((docRef: any) => { + console.log('Document written with ID: ', docRef.id); + return docRef; + }) + .catch((error: any) => { + console.error('Error adding document: ', error); + return error; + }); + + firebase.auth + .sendSignInLinkToEmail(user.email, actionCodeSettings) + .then(() => { + // The link was successfully sent. Inform the user. + // Save the email locally so you don't need to ask the user for it again + // if they open the link on the same device. + console.log('email sent!'); + window.localStorage.setItem('emailForSignIn', user.email); + // ... + }) + .catch(error => { + let errorCode = error.code; + let errorMessage = error.message; + console.log('email failed!', errorCode, errorMessage); + // ... + }); + + return userRef; +} diff --git a/ReactJS-Project-CardinalKit/src/api/user.ts b/ReactJS-Project-CardinalKit/src/api/user.ts index f6daa91..cd9b925 100644 --- a/ReactJS-Project-CardinalKit/src/api/user.ts +++ b/ReactJS-Project-CardinalKit/src/api/user.ts @@ -5,7 +5,9 @@ export interface UserDetails { eID: string; userID: string; email: string; + firstName: string; + lastName: string; createdAt?: Date; surveyList?: Survey[]; - lastActive: Date; + lastActive: number; } diff --git a/ReactJS-Project-CardinalKit/src/components/Firebase/firebase.js b/ReactJS-Project-CardinalKit/src/components/Firebase/firebase.js index c97c188..c10c755 100644 --- a/ReactJS-Project-CardinalKit/src/components/Firebase/firebase.js +++ b/ReactJS-Project-CardinalKit/src/components/Firebase/firebase.js @@ -3,16 +3,26 @@ import 'firebase/auth'; import 'firebase/firestore'; const config = { - apiKey: process.env.REACT_APP_API_KEY || 'AIzaSyCVzML6v4C16HNjUZN_xnEX5RWJmDq3YUU', - authDomain: process.env.REACT_APP_AUTH_DOMAIN || 'cs342-master-sample.firebaseapp.com', - databaseURL: process.env.REACT_APP_DATABASE_URL || 'https://cs342-master-sample.firebaseio.com', - projectId: process.env.REACT_APP_PROJECT_ID || 'cs342-master-sample', - storageBucket: process.env.REACT_APP_STORAGE_BUCKET || 'cs342-master-sample.appspot.com', - messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID || '267563013930', - appId: process.env.REACT_APP_ID || '1:267563013930:web:99eeeff653b0f07accb053', - iOSAppBundleId: process.env.IOS_APP_ID || 'edu.stanford.cardinalkit', // as setup on your iOS project + apiKey: 'AIzaSyBYlt95-E4qI7yOdkChGIdq1tkjVC6I68U', + authDomain: 'cs342-alpha-9bb64.firebaseapp.com', + projectId: 'cs342-alpha-9bb64', + storageBucket: 'cs342-alpha-9bb64.appspot.com', + messagingSenderId: '47235957743', + appId: '1:47235957743:web:30ad97b3d66cfb239f2c1a', + iOSAppBundleId: 'edu.stanford.cs342-alpha-cardiology', }; +// const config = { +// apiKey: process.env.REACT_APP_API_KEY || 'AIzaSyCVzML6v4C16HNjUZN_xnEX5RWJmDq3YUU', +// authDomain: process.env.REACT_APP_AUTH_DOMAIN || 'cs342-master-sample.firebaseapp.com', +// databaseURL: process.env.REACT_APP_DATABASE_URL || 'https://cs342-master-sample.firebaseio.com', +// projectId: process.env.REACT_APP_PROJECT_ID || 'cs342-master-sample', +// storageBucket: process.env.REACT_APP_STORAGE_BUCKET || 'cs342-master-sample.appspot.com', +// messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID || '267563013930', +// appId: process.env.REACT_APP_ID || '1:267563013930:web:99eeeff653b0f07accb053', +// iOSAppBundleId: process.env.IOS_APP_ID || 'edu.stanford.cardinalkit', // as setup on your iOS project +// }; + class Firebase { constructor() { if (!app.apps.length) { @@ -94,9 +104,13 @@ class Firebase { // *** User API *** - user = uid => this.db.collection(`studies/${config.iOSAppBundleId}/users`).doc(`${uid}`); + // user = uid => this.db.collection(`studies/${config.iOSAppBundleId}/users`).doc(`${uid}`); + + // users = () => this.db.collection(`studies/${config.iOSAppBundleId}/users/`); + + user = uid => this.db.collection(`registered-patients`).doc(`${uid}`); - users = () => this.db.collection(`studies/${config.iOSAppBundleId}/users/`); + users = () => this.db.collection(`registered-patients`); // *** Surveys API *** diff --git a/ReactJS-Project-CardinalKit/src/components/RegisterForm.js b/ReactJS-Project-CardinalKit/src/components/RegisterForm.js new file mode 100644 index 0000000..e67d1fc --- /dev/null +++ b/ReactJS-Project-CardinalKit/src/components/RegisterForm.js @@ -0,0 +1,93 @@ +import { thisExpression, throwStatement } from '@babel/types'; +import * as React from 'react'; +import { useHistory } from 'react-router-dom'; +import { registerNewUser } from '../api/registerUser.ts'; + +class RegisterForm extends React.Component { + constructor(props) { + super(props); + + this.initialState = { + first_name: '', + last_name: '', + email: '', + }; + + this.state = this.initialState; + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + handleChange(event) { + this.setState({ [event.target.name]: event.target.value }); + } + + handleSubmit(event) { + alert('Patient Registered'); + const new_user = { + firstName: this.state.first_name, + lastName: this.state.last_name, + email: this.state.email, + lastActive: 0, + userID: this.state.first_name + this.state.last_name, + }; + registerNewUser(new_user); + event.preventDefault(); + + // reset form + this.setState(this.initialState); + } + + render() { + return ( +
+
+
+
+

Register a New Patient:

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ ); + } +} + +export { RegisterForm }; diff --git a/ReactJS-Project-CardinalKit/src/components/RegisterPage.tsx b/ReactJS-Project-CardinalKit/src/components/RegisterPage.tsx new file mode 100644 index 0000000..31b2681 --- /dev/null +++ b/ReactJS-Project-CardinalKit/src/components/RegisterPage.tsx @@ -0,0 +1,91 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { defineMessages, FormattedMessage } from 'react-intl'; + +import { fetchUserDetails } from '../actions/usersActions'; +import { Store } from '../reducers/rootReducer'; +import { selectUserDetails } from '../selectors/usersSelectors'; + +import { UserDetails } from '../api/user'; + +import { Card } from '../ui/Card'; + +import { TimeInfoBubble, TimeType } from './TimeInfoBubble'; + +import { RegisterForm } from './RegisterForm'; + +const messages = defineMessages({ + userEmailHeader: { + id: 'app.containers.UserDetailHeader.userid', + defaultMessage: 'Email:', + }, + userIdHeader: { + id: 'app.containers.UserDetailHeader.id', + defaultMessage: 'User ID:', + }, +}); + +class UserDetailHeader extends React.Component { + componentDidMount() { + this.props.loadUserDetails(); + } + + render() { + const { userDetails } = this.props; + + return ( +
+ + + +
+ ); + } +} + +interface UserDetailHeaderStateProps { + userDetails: UserDetails | undefined; +} +interface UserDetailHeaderDispatchProps { + loadUserDetails: () => void; +} + +interface UserDetailHeaderContainerProps { + userID: string; +} + +type UserDetailHeaderProps = UserDetailHeaderStateProps & + UserDetailHeaderDispatchProps & + UserDetailHeaderContainerProps; + +function mapStateToProps( + state: Store, + props: UserDetailHeaderContainerProps +): UserDetailHeaderStateProps { + return { + userDetails: selectUserDetails(state, props), + }; +} + +function mapDispatchToProps( + dispatch: Dispatch, + props: UserDetailHeaderContainerProps +): UserDetailHeaderDispatchProps { + return { + loadUserDetails: () => { + dispatch(fetchUserDetails(props.userID)); + }, + }; +} + +export default connect< + UserDetailHeaderStateProps, + UserDetailHeaderDispatchProps, + UserDetailHeaderContainerProps, + Store +>( + mapStateToProps, + mapDispatchToProps +)(UserDetailHeader); diff --git a/ReactJS-Project-CardinalKit/src/components/TimeInfoBubble.tsx b/ReactJS-Project-CardinalKit/src/components/TimeInfoBubble.tsx index b0ad92b..453f004 100644 --- a/ReactJS-Project-CardinalKit/src/components/TimeInfoBubble.tsx +++ b/ReactJS-Project-CardinalKit/src/components/TimeInfoBubble.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; -//import { selectUnit } from '@formatjs/intl-utils'; -import { FormattedDate/*, defineMessages, FormattedMessage, FormattedRelativeTime*/ } from 'react-intl'; +// import { selectUnit } from '@formatjs/intl-utils'; +import { + FormattedDate /*, defineMessages, FormattedMessage, FormattedRelativeTime*/, +} from 'react-intl'; import { BubbleColor, InfoBubble } from '../ui/InfoBubble'; @@ -45,60 +47,74 @@ const assignBubbleBreakpoints = (time: Date, colors: BubbleColor[], msBreakpoint const HOUR_MS = 3600000; -//const DAY_MS = 86400000; +// const DAY_MS = 86400000; const GREEN_ORANGE_RED = [BubbleColor.Green, BubbleColor.Orange, BubbleColor.Red]; -const assignBubbleColor = (time: Date, type: TimeType) => { +const assignBubbleColor = (time: number, type: TimeType) => { + if (time == 0) { + return GREEN_ORANGE_RED[2]; + } + + let date_time: Date = new Date(time); switch (type) { case TimeType.Active: - return assignBubbleBreakpoints(time, GREEN_ORANGE_RED, [24 * HOUR_MS, 72 * HOUR_MS]); + return assignBubbleBreakpoints(date_time, GREEN_ORANGE_RED, [24 * HOUR_MS, 72 * HOUR_MS]); default: - return assignBubbleBreakpoints(time, GREEN_ORANGE_RED, [24 * HOUR_MS, 72 * HOUR_MS]); + return assignBubbleBreakpoints(date_time, GREEN_ORANGE_RED, [24 * HOUR_MS, 72 * HOUR_MS]); } }; interface TimeInfoBubbleProps { timeType: TimeType; - time: Date; + time: number; } -export const TimeInfoBubble: React.StatelessComponent = ( - props: TimeInfoBubbleProps -) => { - - //const targetDate : any = props.time.getTime(); - //const { value, unit } = selectUnit(Date.now() - targetDate); - - return ( - -
- -
Last active
- {/*, - }} - />*/} -
-
-
- -
-
- ); -}; +class TimeInfoBubble extends React.Component { + constructor(props: TimeInfoBubbleProps) { + super(props); + } + + // const targetDate : any = props.time.getTime(); + // const { value, unit } = selectUnit(Date.now() - targetDate); + + render() { + return ( + +
+ +
Last active
+ {/*, + }} + />*/} +
+
+
+ {this.props.time ? ( + + ) : ( + 'Never (has not registered)' + )} +
+
+ ); + } +} + +export { TimeInfoBubble }; diff --git a/ReactJS-Project-CardinalKit/src/components/UserCard.tsx b/ReactJS-Project-CardinalKit/src/components/UserCard.tsx index 3cb1b70..5f60cb3 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserCard.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserCard.tsx @@ -11,6 +11,10 @@ import { defineMessages, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; const messages = defineMessages({ + userNameHeader: { + id: 'app.containers.UserCard.name', + defaultMessage: 'Patient Name', + }, userIdHeader: { id: 'app.containers.UserCard.userid', defaultMessage: 'ID', @@ -31,13 +35,18 @@ interface UserCardProps { class UserCard extends React.Component { render() { - const { userID, lastActive, email } = this.props.user; - const lastActiveTake = new Date(lastActive); + const { userID, lastActive, email, lastName, firstName } = this.props.user; return (
+

+ +

+

+ {lastName}, {firstName} +

@@ -45,16 +54,15 @@ class UserCard extends React.Component { {email}

-

+ {/*

{userID} -

+

*/}
- {lastActiveTake && } - {/*lastActive && */} + {}
diff --git a/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx b/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx index eb822f4..e65db5f 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx @@ -41,8 +41,6 @@ class UserDetailHeader extends React.Component { ); } - const lastActiveTake = new Date(userDetails.lastActive); - return (
@@ -65,7 +63,7 @@ class UserDetailHeader extends React.Component {

- {lastActiveTake && } + {}
diff --git a/ReactJS-Project-CardinalKit/src/components/UserList.tsx b/ReactJS-Project-CardinalKit/src/components/UserList.tsx index f720c93..a0e4ffd 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserList.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserList.tsx @@ -46,6 +46,10 @@ const messages = defineMessages({ id: 'app.UserList.eid', defaultMessage: 'Email', }, + lastName: { + id: 'app.UserList.lastname', + defaultMessage: 'Name', + }, eidTypeFormat: { id: 'app.UserList.eidTypeFormat', defaultMessage: '{eidType}', diff --git a/ReactJS-Project-CardinalKit/src/components/UserPage.tsx b/ReactJS-Project-CardinalKit/src/components/UserPage.tsx index 0ad42d4..f94b1a4 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserPage.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserPage.tsx @@ -18,7 +18,7 @@ export default class UserPage extends React.PureComponent { return (
- + {/* */}
); } diff --git a/ReactJS-Project-CardinalKit/src/components/UsersPage.tsx b/ReactJS-Project-CardinalKit/src/components/UsersPage.tsx index 9705605..548fc6a 100644 --- a/ReactJS-Project-CardinalKit/src/components/UsersPage.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UsersPage.tsx @@ -3,11 +3,18 @@ import { defineMessages, FormattedMessage } from 'react-intl'; import UserList from './UserList'; +import { Link } from 'react-router-dom'; +import { Card } from '../ui/Card'; + const messages = defineMessages({ header: { id: 'app.containers.UserPage.header', defaultMessage: 'Users', }, + addUserButton: { + id: 'app.UserList.addUserButton', + defaultMessage: 'Register a New Patient', + }, }); export default class UsersPage extends React.PureComponent { @@ -21,6 +28,15 @@ export default class UsersPage extends React.PureComponent {
+
+ +
+ + + +
+ +
); diff --git a/ReactJS-Project-CardinalKit/src/constants/usersConstants.ts b/ReactJS-Project-CardinalKit/src/constants/usersConstants.ts index dd06ed4..40cb81c 100644 --- a/ReactJS-Project-CardinalKit/src/constants/usersConstants.ts +++ b/ReactJS-Project-CardinalKit/src/constants/usersConstants.ts @@ -3,6 +3,8 @@ export enum UsersSortField { LastActive = 'LAST_ACTIVE', UserID = 'USER_ID', UserEID = 'USER_EID', + UserFirstName = 'USER_FIRST_NAME', + UserLastName = 'USER_LAST_NAME', } export enum UsersSortOrder { diff --git a/ReactJS-Project-CardinalKit/src/sagas/usersSaga.ts b/ReactJS-Project-CardinalKit/src/sagas/usersSaga.ts index 1b3398a..1804993 100644 --- a/ReactJS-Project-CardinalKit/src/sagas/usersSaga.ts +++ b/ReactJS-Project-CardinalKit/src/sagas/usersSaga.ts @@ -3,12 +3,12 @@ import { call, put, takeLatest } from 'redux-saga/effects'; import { getAllFirebaseUsers, getFirebaseUser, getSurveys } from '../api/getAllUsers'; import { - FetchUsersAction, FetchUserDetailsAction, + fetchUserDetailsFailure, + fetchUserDetailsSuccess, + FetchUsersAction, fetchUsersFailure, fetchUsersSuccess, - fetchUserDetailsSuccess, - fetchUserDetailsFailure } from '../actions/usersActions'; import { UsersActionType } from '../constants/usersConstants'; @@ -17,12 +17,6 @@ import app from 'firebase/app'; export function* fetchUserSummaries(action: FetchUsersAction) { try { const users = yield call(getAllFirebaseUsers); - - /*users.docs.forEach(function(doc: app.firestore.QueryDocumentSnapshot) { - // doc.data() is never undefined for query doc snapshots - console.log(doc.id, " => ", doc.data()); - });*/ - const userList = users.docs.map((i: app.firestore.QueryDocumentSnapshot) => i.data()); yield put(fetchUsersSuccess(userList)); @@ -32,7 +26,6 @@ export function* fetchUserSummaries(action: FetchUsersAction) { } export function* fetchUserDetails(action: FetchUserDetailsAction) { - try { const user = yield call(getFirebaseUser, action.userID); From cceb08deb642dcbe200fdefbb526e43f3e240381 Mon Sep 17 00:00:00 2001 From: Collin Schlager Date: Sat, 27 Feb 2021 16:18:23 -0800 Subject: [PATCH 02/25] Add user registration. --- ReactJS-Project-CardinalKit/src/api/registerUser.ts | 12 ++++++------ ReactJS-Project-CardinalKit/src/api/user.ts | 1 + .../src/components/RegisterForm.js | 12 ++++++++++++ .../src/components/TimeInfoBubble.tsx | 2 +- .../src/components/UserDetailHeader.tsx | 6 ++++++ 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/ReactJS-Project-CardinalKit/src/api/registerUser.ts b/ReactJS-Project-CardinalKit/src/api/registerUser.ts index 412c3d6..3ad066c 100644 --- a/ReactJS-Project-CardinalKit/src/api/registerUser.ts +++ b/ReactJS-Project-CardinalKit/src/api/registerUser.ts @@ -1,11 +1,11 @@ import app from 'firebase/app'; import Firebase from '../components/Firebase'; -let actionCodeSettings = { +const actionCodeSettings = { // URL you want to redirect back to. The domain (www.example.com) for this // URL must be in the authorized domains list in the Firebase Console. // url: 'https://www.example.com/finishSignUp?cartId=1234', - url: 'cs342-alpha-9bb64.firebaseapp.com', + url: 'https://cs342-alpha-9bb64.web.app', // This must be true. handleCodeInApp: true, // iOS: { @@ -16,13 +16,13 @@ let actionCodeSettings = { // installApp: true, // minimumVersion: '12' // }, - dynamicLinkDomain: 'cs342-alpha-9bb64.firebaseapp.com', + dynamicLinkDomain: 'cs342alpha.page.link', }; export function registerNewUser(user: any): Promise { const firebase = new Firebase(); console.log('Registering a new user!'); - let userRef = firebase.db + const userRef = firebase.db .collection(`registered-patients`) .add(user) .then((docRef: any) => { @@ -45,8 +45,8 @@ export function registerNewUser(user: any): Promise // ... }) .catch(error => { - let errorCode = error.code; - let errorMessage = error.message; + const errorCode = error.code; + const errorMessage = error.message; console.log('email failed!', errorCode, errorMessage); // ... }); diff --git a/ReactJS-Project-CardinalKit/src/api/user.ts b/ReactJS-Project-CardinalKit/src/api/user.ts index cd9b925..8176d1e 100644 --- a/ReactJS-Project-CardinalKit/src/api/user.ts +++ b/ReactJS-Project-CardinalKit/src/api/user.ts @@ -10,4 +10,5 @@ export interface UserDetails { createdAt?: Date; surveyList?: Survey[]; lastActive: number; + medications: string; } diff --git a/ReactJS-Project-CardinalKit/src/components/RegisterForm.js b/ReactJS-Project-CardinalKit/src/components/RegisterForm.js index e67d1fc..97b55fa 100644 --- a/ReactJS-Project-CardinalKit/src/components/RegisterForm.js +++ b/ReactJS-Project-CardinalKit/src/components/RegisterForm.js @@ -11,6 +11,7 @@ class RegisterForm extends React.Component { first_name: '', last_name: '', email: '', + medication: '', }; this.state = this.initialState; @@ -29,6 +30,7 @@ class RegisterForm extends React.Component { firstName: this.state.first_name, lastName: this.state.last_name, email: this.state.email, + medications: this.state.medication, lastActive: 0, userID: this.state.first_name + this.state.last_name, }; @@ -77,6 +79,16 @@ class RegisterForm extends React.Component { onChange={this.handleChange} /> +
+ + +
- {/*
-

- -

-
- {eidTypes.map((eidType: string, index: number) => ( - - ))} -
-
*/}
{userList.map(user => { From a9b64704940b4532ab526ce33e944367d0da869e Mon Sep 17 00:00:00 2001 From: Collin Schlager Date: Tue, 2 Mar 2021 15:49:33 -0800 Subject: [PATCH 05/25] Update user card style. --- .../src/components/UserCard.tsx | 7 ------- .../src/components/UserDetailHeader.tsx | 15 +++++++-------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/ReactJS-Project-CardinalKit/src/components/UserCard.tsx b/ReactJS-Project-CardinalKit/src/components/UserCard.tsx index 5f60cb3..697adb1 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserCard.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserCard.tsx @@ -53,13 +53,6 @@ class UserCard extends React.Component {

{email}

- - {/*

- -

-

- {userID} -

*/}
{} diff --git a/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx b/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx index 4c85826..dfd8229 100644 --- a/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx +++ b/ReactJS-Project-CardinalKit/src/components/UserDetailHeader.tsx @@ -44,29 +44,28 @@ class UserDetailHeader extends React.Component { return (
-
+
+ {}
-
+

-

+

{userDetails.email}

-
+

-

+

{userDetails.userID}

- {} - {/*

Medications:

*/}
-

+

{userDetails.medications}

From 993563dc6699e1533c2c21d477b009d5600ed1bb Mon Sep 17 00:00:00 2001 From: Collin Schlager Date: Tue, 2 Mar 2021 15:50:53 -0800 Subject: [PATCH 06/25] Add simple provider check to sign in. --- ReactJS-Project-CardinalKit/src/api/admin.ts | 16 ++++++++++++++++ .../src/api/registerUser.ts | 8 +++----- .../src/components/LoginPage.jsx | 4 +++- .../src/sagas/loginSaga.ts | 5 ++++- 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 ReactJS-Project-CardinalKit/src/api/admin.ts diff --git a/ReactJS-Project-CardinalKit/src/api/admin.ts b/ReactJS-Project-CardinalKit/src/api/admin.ts new file mode 100644 index 0000000..aa8ac74 --- /dev/null +++ b/ReactJS-Project-CardinalKit/src/api/admin.ts @@ -0,0 +1,16 @@ +import app from 'firebase/app'; +import Firebase from '../components/Firebase'; + +export function isAdmin(userEmail: string): Promise { + const firebase = new Firebase(); + var adminBool = firebase.db.collection('providers').doc('providers').get() + .then(function(doc) { + var data = doc.data(); + return (data && data["providers"].includes(userEmail)); + }) + .catch(function(error) { + console.log('Error getting document:', error); + return false; + }); + return adminBool; +} \ No newline at end of file diff --git a/ReactJS-Project-CardinalKit/src/api/registerUser.ts b/ReactJS-Project-CardinalKit/src/api/registerUser.ts index 19a6e51..f12d0aa 100644 --- a/ReactJS-Project-CardinalKit/src/api/registerUser.ts +++ b/ReactJS-Project-CardinalKit/src/api/registerUser.ts @@ -1,15 +1,13 @@ import app from 'firebase/app'; import Firebase from '../components/Firebase'; - export function registerNewUser(user: any): Promise { - - var actionCodeSettings = { - // include email in link so it can be passed to iOS + let actionCodeSettings = { + // include email in link so it can be passed to iOS url: 'https://cs342-alpha-9bb64.web.app/?email=' + user.email, handleCodeInApp: true, iOS: { - bundleId: 'https://cs342-alpha-9bb64.web.app' + bundleId: 'https://cs342-alpha-9bb64.web.app', }, dynamicLinkDomain: 'cs342alpha.page.link', }; diff --git a/ReactJS-Project-CardinalKit/src/components/LoginPage.jsx b/ReactJS-Project-CardinalKit/src/components/LoginPage.jsx index d3d1971..d73353c 100644 --- a/ReactJS-Project-CardinalKit/src/components/LoginPage.jsx +++ b/ReactJS-Project-CardinalKit/src/components/LoginPage.jsx @@ -43,7 +43,9 @@ export class LoginPage extends React.Component { VascTrac
- {error &&

Unable to login. Please make sure you are using a valid @stanford.edu account.

} + {error &&

+ Unable to login. This portal is only for registered providers. +

}
+ {(isModified) && + + } + {(isModified) && + + } +
+
+
+ + ); + } +} + +export { MedicationForm }; diff --git a/ReactJS-Project-CardinalKit/src/components/MedicationPage.tsx b/ReactJS-Project-CardinalKit/src/components/MedicationPage.tsx new file mode 100644 index 0000000..1940ce7 --- /dev/null +++ b/ReactJS-Project-CardinalKit/src/components/MedicationPage.tsx @@ -0,0 +1,95 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { defineMessages, FormattedMessage } from 'react-intl'; + +import { fetchUserDetails } from '../actions/usersActions'; +import { Store } from '../reducers/rootReducer'; +import { selectUserDetails } from '../selectors/usersSelectors'; + +import { UserDetails } from '../api/user'; + +import { Card } from '../ui/Card'; + +import { TimeInfoBubble, TimeType } from './TimeInfoBubble'; + +import { MedicationForm } from './MedicationForm'; + +const messages = defineMessages({ + userEmailHeader: { + id: 'app.containers.UserDetailHeader.userid', + defaultMessage: 'Email:', + }, + userIdHeader: { + id: 'app.containers.UserDetailHeader.id', + defaultMessage: 'User ID:', + }, +}); + +interface MedicationPageProps { + match: { + params: { + userID: string; + }; + }; +} + +class MedicationPage extends React.Component { + render() { + let userID = this.props.match.params.userID; + + return ( +
+ + + +
+ ); + } +} + +interface UserDetailHeaderStateProps { + userDetails: UserDetails | undefined; +} +interface UserDetailHeaderDispatchProps { + loadUserDetails: () => void; +} + +interface UserDetailHeaderContainerProps { + userID: string; +} + +type UserDetailHeaderProps = UserDetailHeaderStateProps & + UserDetailHeaderDispatchProps & + UserDetailHeaderContainerProps; + +function mapStateToProps( + state: Store, + props: UserDetailHeaderContainerProps +): UserDetailHeaderStateProps { + return { + userDetails: selectUserDetails(state, props), + }; +} + +function mapDispatchToProps( + dispatch: Dispatch, + props: UserDetailHeaderContainerProps +): UserDetailHeaderDispatchProps { + return { + loadUserDetails: () => { + dispatch(fetchUserDetails(props.userID)); + }, + }; +} + +export default connect< + UserDetailHeaderStateProps, + UserDetailHeaderDispatchProps, + UserDetailHeaderContainerProps, + Store +>( + mapStateToProps, + mapDispatchToProps +)(MedicationPage); From 1f75886ca52a4ec921c82cb419f06c9d7f54cc54 Mon Sep 17 00:00:00 2001 From: Collin Schlager Date: Sun, 14 Mar 2021 19:05:22 -0700 Subject: [PATCH 22/25] Add styling --- ReactJS-Project-CardinalKit/package-lock.json | 5 +++++ ReactJS-Project-CardinalKit/package.json | 1 + .../src/components/MedicationCard.js | 4 +++- .../src/components/MedicationForm.js | 9 ++++++--- .../src/components/RegisterForm.js | 6 +++--- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ReactJS-Project-CardinalKit/package-lock.json b/ReactJS-Project-CardinalKit/package-lock.json index 6cef83e..a2f8288 100644 --- a/ReactJS-Project-CardinalKit/package-lock.json +++ b/ReactJS-Project-CardinalKit/package-lock.json @@ -21640,6 +21640,11 @@ "resolved": "https://registry.npmjs.org/react-feather/-/react-feather-1.1.6.tgz", "integrity": "sha512-iCofWhTjX+vQwvDmg7o6vg0XrUg1c41yBDZG+l83nz1FiCsleJoUgd3O+kHpOeWMXuPrRIFfCixvcqyOLGOgIg==" }, + "react-icons": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.2.0.tgz", + "integrity": "sha512-rmzEDFt+AVXRzD7zDE21gcxyBizD/3NqjbX6cmViAgdqfJ2UiLer8927/QhhrXQV7dEj/1EGuOTPp7JnLYVJKQ==" + }, "react-input-autosize": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.2.tgz", diff --git a/ReactJS-Project-CardinalKit/package.json b/ReactJS-Project-CardinalKit/package.json index a1bdb82..5d4f572 100644 --- a/ReactJS-Project-CardinalKit/package.json +++ b/ReactJS-Project-CardinalKit/package.json @@ -23,6 +23,7 @@ "react-day-picker": "^7.2.4", "react-dom": "^16.10.2", "react-feather": "^1.1.4", + "react-icons": "^4.2.0", "react-intl": "3.2.1", "react-redux": "^7.1.1", "react-router": "5.1.2", diff --git a/ReactJS-Project-CardinalKit/src/components/MedicationCard.js b/ReactJS-Project-CardinalKit/src/components/MedicationCard.js index 610db1c..e19ade8 100644 --- a/ReactJS-Project-CardinalKit/src/components/MedicationCard.js +++ b/ReactJS-Project-CardinalKit/src/components/MedicationCard.js @@ -9,6 +9,8 @@ import { defineMessages, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import MedicationPage from './MedicationPage'; +import { BsUnlock, BsLock } from 'react-icons/bs'; + const messages = defineMessages({ medicineName: { id: 'app.containers.UserCard.name', @@ -94,7 +96,7 @@ class MedicationCard extends React.Component {
this.toggleEdit()} className="bg-blue hover:bg-blue-dark border border-blue rounded mx-2 px-2 py-1 my-1 flex justify-center"> - {(!this.state.editing) ? "Unlock" : "Lock"} + {(!this.state.editing) ? : }
this.deleteRow()} className="bg-red hover:bg-red-dark border border-red rounded mx-1 px-2 py-1 my-1 flex justify-center" diff --git a/ReactJS-Project-CardinalKit/src/components/MedicationForm.js b/ReactJS-Project-CardinalKit/src/components/MedicationForm.js index 795f5a9..aeac53c 100644 --- a/ReactJS-Project-CardinalKit/src/components/MedicationForm.js +++ b/ReactJS-Project-CardinalKit/src/components/MedicationForm.js @@ -78,10 +78,13 @@ class MedicationForm extends React.Component {
-

Medications for {this.state.firstName + " " + this.state.lastName}

-

Email: {this.state.email}

-
+

Medications for {this.state.lastName + ", " + this.state.firstName}

+

Email: {this.state.email}

+

UserID: {this.props.userID}

+ {(Object.entries(medications).length === 0) && +

No medications registered.

+ } {Object.keys(medications).sort().map(function(medication) { const interval = medications[medication]; return
-
+ {/*
-
+
*/}