diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..f6b35a0
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "chrome",
+ "request": "launch",
+ "name": "Launch Chrome against localhost",
+ "url": "http://localhost:3000",
+ "webRoot": "${workspaceFolder}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 523d9c6..385559b 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,10 @@ This is a simple react js hooks starter project that is using Azure AD to authen
```text
// .env.development.local
REACT_APP_ID={Application (client) ID created above}
+ REACT_APP_AUTHORITY=https://login.microsoftonline.com/{Azure tenant id that will match the tenant you created the app registration in}
REACT_APP_REDIRECT_URL=http://localhost:3000
- REACT_APP_API_BASE_URL=https://lws-lagoonapis-fa-sbx.azurewebsites.net/api/
+ REACT_APP_API_BASE_URL=https://jsonplaceholder.typicode.com/
+
```
4. Run the following commands
@@ -26,4 +28,12 @@ This is a simple react js hooks starter project that is using Azure AD to authen
```bash
$npm install
$npm start
- ```
\ No newline at end of file
+ ```
+
+5. Login and start clicking
+
+## Additional Info
+
+This project is using the JSONPlaceHolder API, which can be found here https://jsonplaceholder.typicode.com, to pull in random sample data to play with. A couple of important things to note about this data source:
+ 1. It's read-only. It will provide fakes for inserts and updates, but you aren't really changing the source. For example, if you create a new post and then try to edit that post, it will fail since the post you created was just a fake.
+ 2. Actually there was only one important thing to note about using this data...
\ No newline at end of file
diff --git a/package.json b/package.json
index 04a1678..94eadee 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"reactstrap": "^8.4.1"
},
"scripts": {
- "start": "react-scripts start",
+ "start": "PORT=3000 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
diff --git a/public/index.html b/public/index.html
index 4cdf1e0..964a633 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,7 +2,7 @@
-
+
- Lagoon WES
+ React Azure Starter
diff --git a/src/components/app/app.js b/src/components/app/app.js
index 5e4ca61..47b8568 100644
--- a/src/components/app/app.js
+++ b/src/components/app/app.js
@@ -10,7 +10,6 @@ import { UserAgentApplication } from 'msal';
import { getUserDetails, getUserPhoto, getUserGroups } from '../utils/graph-service';
import Calendar from '../calendar/calendar';
import Posts from '../posts/post';
-import Facility from '../facility/facility';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCheckCircle, faQuestionCircle, faExclamationCircle } from '@fortawesome/free-solid-svg-icons'
@@ -85,7 +84,10 @@ class App extends Component {
}
isUserInAdminRole(userRoles) {
- return userRoles.some(userRole => userRole.id === config.isAdminGroupId);
+ //this is the check for user groups, but it is commented out so we can make the buttons work for this sample, in the event that you use this code,
+ //you will need to create a group for admin access and grant admin consent to the group.read.all scope for the app in azure AD
+ //return userRoles.some(userRole => userRole.id === config.isAdminGroupId);
+ return true;
}
async getUserProfile() {
@@ -150,21 +152,15 @@ class App extends Component {
user={this.state.user}/>
{notify}
-
-
- } />
-
-
- } />
- } />
- } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
diff --git a/src/components/facility/facility-upsert.js b/src/components/facility/facility-upsert.js
deleted file mode 100644
index 4187dff..0000000
--- a/src/components/facility/facility-upsert.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import React, {useState} from 'react';
-import {Button,Form,FormGroup,Label,Input,FormFeedback} from 'reactstrap';
-import NotifyUser from '../packages/notify-user';
-import { upsertFacilities } from '../utils/api-service';
-
-const UpsertFacility = (props) => {
- const [error,setError] = useState(null);
- const [facility, setFacility] = useState(props.facility);
- const [validFields, setValidFields] = useState({facilityName:true,operator:true});
-
- const onChange = (event) => {
- const value = event.target.type === "checkbox" ? event.target.checked : event.target.value;
- const name = event.target.name;
- const optionSelectText = event.target.type === "select-one" ? event.target.options[event.target.selectedIndex].text : '';
-
- //special logic for system object
- if (name === "system") {
- var systemObj = {systemId: value, systemName: optionSelectText};
- setFacility({...facility, system: systemObj});
- } else {
- setFacility({...facility, [name]: value});
- }
- checkInputValidity(name,value);
- }
-
- const callUpsertFacilitiesApi = async() => {
- try {
- if (props.isAuthenticated) {
- var facilities = [facility];
- var results = await upsertFacilities(facilities);
-
- //check results and close modal
- if (results.HasErrors) {
- setError({message: JSON.stringify(results.Message)});
- return false;
- } else {
- //if edit
- if (props.editFacility) {
- props.editFacility(facility);
- }
- //if new
- if (props.addFacility) {
- props.addFacility(facility);
- }
- props.showNotify('success', facility.facilityName + ' successfully updated', JSON.stringify(results.Messages));
- return true;
- }
- } else {
- setError({message: 'User not Authenticated. Please sign in to view this page'});
- }
- } catch (e) {
- console.log('callUpsertFacilities',e);
- setError({message: 'ERROR Occurred: ', debug: JSON.stringify(e).length === 0 ? e : JSON.stringify(e)});
- return false;
- }
- }
-
- const submitForm = async(item) => {
- var isUpdateSuccessful = await callUpsertFacilitiesApi();
- if (isUpdateSuccessful) {
- props.toggleModal();
- }
- }
-
- const checkInputValidity = (inputName, value) => {
- switch(inputName) {
- case 'facilityName':
- value.trim().length === 0 ? setValidFields({...validFields, facilityName:false}) : setValidFields({...validFields, facilityName:true});
- break;
- case 'operator':
- value.trim().length === 0 ? setValidFields({...validFields, operator:false}) : setValidFields({...validFields, operator:true});
- break;
- default:
- break
- }
- }
-
- const checkIsFormValid = () => {
- var validFieldsPropertyArray = Object.keys(validFields);
- return !validFieldsPropertyArray.every((item) => {return validFields[item] === true});
- }
-
- let errorElement = null;
- if (error) {
- errorElement = ;
- }
-
- const systemOptions = props.systems.map(system => {
- return (
-
- );
- });
-
- return (
-
- {errorElement}
-
-
- )
-};
-
-export default UpsertFacility;
\ No newline at end of file
diff --git a/src/components/facility/facility.js b/src/components/facility/facility.js
deleted file mode 100644
index 272e142..0000000
--- a/src/components/facility/facility.js
+++ /dev/null
@@ -1,124 +0,0 @@
-import React, {useState, useEffect} from 'react'
-import {Table,
- ButtonGroup,
- Container } from 'reactstrap';
-import moment from 'moment';
-import { getFacilities, getPipelineSystems } from '../utils/api-service';
-import Loader from '../packages/loader';
-import ModalForm from '../packages/modal-form';
-import UpsertFacility from './facility-upsert';
-
-//Helper function to format Graph date/time
-function formatDateTime(dateTime) {
- return moment.utc(dateTime).local().format('M/D/YY h:mm A');
-}
-
-const Facility = (props) => {
- const [facilities, setFacilities] = useState([]);
- const [systems, setSystems] = useState([]);
- const [isLoading, setIsLoading] = useState(true);
-
- useEffect(() => {
- const fetchData = async () => {
- try {
- if (props.isAuthenticated) {
- //Get the user's events
- var [facilities, systems] = await Promise.all([ getFacilities(), getPipelineSystems() ]);
- //Update the array of events in state
- setFacilities(facilities);
- setSystems(systems);
- setIsLoading(false);
- } else {
- props.showNotify('danger', 'User not Authenticated', 'Please sign in to view this page')
- }
- }
- catch (err) {
- props.showNotify('danger', 'ERROR', JSON.stringify(err));
- }
- }
- fetchData();
- }, []);
-
- const editFacility = (facility) => {
- setIsLoading(true);
- setFacilities(facilities.map(item => (item.facilityId === facility.facilityId ? facility : item)));
- setIsLoading(false);
- }
-
- const addFacility = (facility) => {
- setIsLoading(true);
- setFacilities(prevArray => [...prevArray, facility]);
- setIsLoading(false);
- }
-
- if (props.isAuthenticated) {
-
- if (isLoading) {
- return (
-
- );
- }
-
- const facilitiesRender = facilities.map(facility => {
- return (
-
+ )
+}
+
+export default ModalFromButton;
\ No newline at end of file
diff --git a/src/components/packages/navbar.js b/src/components/packages/navbar.js
index 52e7fbd..592fb4e 100644
--- a/src/components/packages/navbar.js
+++ b/src/components/packages/navbar.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState} from 'react';
import { NavLink as RouterNavLink } from 'react-router-dom';
import {
Collapse,
@@ -16,7 +16,7 @@ import {
Button } from 'reactstrap';
import '@fortawesome/fontawesome-free/css/all.css';
-function UserAvatar(props) {
+const UserAvatar = (props) => {
// If a user avatar is available, return an img tag with the pic
if (props.user.avatar) {
return ;
}
-function AuthNavItem(props) {
+const AuthNavItem = (props) => {
// If authenticated, return a dropdown with the user's info and a
// sign out button
if (props.isAuthenticated) {
@@ -63,76 +63,55 @@ function AuthNavItem(props) {
);
}
-export default class NavBar extends React.Component {
- constructor(props) {
- super(props);
+const NavBar = (props) => {
- this.toggle = this.toggle.bind(this);
- this.state = {
- isOpen: false
- };
- }
+ const [isOpen, setIsOpen] = useState(false);
- toggle() {
- this.setState({
- isOpen: !this.state.isOpen
- });
+ const toggle = () => {
+ setIsOpen({isOpen: !isOpen});
}
- render() {
- // Only following nav item if logged in
- let calendarLink = null;
- let postsLink = null;
- let facilityLink = null;
- if (this.props.isAuthenticated) {
- calendarLink = (
-
- Calendar
-
- );
- postsLink = (
-
- Postss
-
- );
- facilityLink = (
-
- Facilities
-
- )
- }
-
- return (
-
-
-
- Well Management System
-
-
-
-
-
-
-
-
+ // Only following nav item if logged in
+ let calendarLink = null;
+ let postsLink = null;
+ if (props.isAuthenticated) {
+ calendarLink = (
+
+ Calendar
+
+ );
+ postsLink = (
+
+ Posts
+
);
}
-}
\ No newline at end of file
+
+ return (
+
+
+
+ React Azure Starter
+
+
+
+
+
+
+
+
+ );
+}
+
+export default NavBar;
\ No newline at end of file
diff --git a/src/components/pipeline-system/index.js b/src/components/pipeline-system/index.js
deleted file mode 100644
index 9702300..0000000
--- a/src/components/pipeline-system/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export {default} from './pipeline-system';
\ No newline at end of file
diff --git a/src/components/pipeline-system/pipeline-system-upsert.js b/src/components/pipeline-system/pipeline-system-upsert.js
deleted file mode 100644
index 9ad8ad7..0000000
--- a/src/components/pipeline-system/pipeline-system-upsert.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import React, {useState} from 'react'
-import {Button,Form,FormGroup,Label,Input,FormFeedback} from 'reactstrap';
-import NotifyUser from '../packages/notify-user';
-import { upsertPipelineSystem } from '../utils/api-service';
-
-const UpsertPipelineSystem = (props) => {
- const [error, setError] = useState(null);
- const [system, setSystem] = useState(props.system);
- const [validFields, setValidFields] = useState({systemName:true});
-
- const onChange = (event) => {
- const value = event.target.type === "checkbox" ? event.target.checked : event.target.value;
- const name = event.target.name;
-
- setSystem({...system, [name]: value});
- checkInputValidity(name,value);
- }
-
- const callUpsertSystemsApi = async() => {
- try {
- if (props.isAuthenticated) {
- var systems = [system];
- var results = await upsertPipelineSystem(systems);
-
- //check results and close modal
- if (results.HasErrors) {
- setError({message: JSON.stringify(results.Message)});
- return false;
- } else {
- //if edit
- if (props.editSystem) {
- props.editSystem(system);
- }
- //if new
- if (props.addSystem) {
- props.addSystem(system);
- }
- props.showNotify('success', system.systemName + ' successfully updated', JSON.stringify(results.Messages));
- return true;
- }
- } else {
- setError({message: 'User not Authenticated. Please sign in to view this page'});
- }
- } catch (e) {
- console.log('callUpsertSystemsApi',e);
- setError({message: 'ERROR Occurred: ', debug: JSON.stringify(e).length === 0 ? e : JSON.stringify(e)});
- return false;
- }
- }
-
- const submitForm = async(item) => {
- var isUpdateSuccessful = await callUpsertSystemsApi();
- if (isUpdateSuccessful) {
- //props.toggleModal();
- }
- }
-
- const checkInputValidity = (inputName, value) => {
- switch(inputName) {
- case 'systemName':
- value.trim().length === 0 ? setValidFields({...validFields, systemName:false}) : setValidFields({...validFields, systemName:true});
- break;
- default:
- break
- }
- }
-
- const checkIsFormValid = () => {
- var validFieldsPropertyArray = Object.keys(validFields);
- return !validFieldsPropertyArray.every((item) => {return validFields[item] === true});
- }
-
- let errorElement = null;
- if (error) {
- errorElement = ;
- }
-
- return (
-
- {errorElement}
-
-
- )
-}
-
-export default UpsertPipelineSystem;
\ No newline at end of file
diff --git a/src/components/pipeline-system/pipeline-system.js b/src/components/pipeline-system/pipeline-system.js
deleted file mode 100644
index 49dd143..0000000
--- a/src/components/pipeline-system/pipeline-system.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import React, {useState, useEffect} from 'react';
-import {Table,
- ButtonGroup,
- Container } from 'reactstrap';
-import moment from 'moment';
-import { getPipelineSystems } from '../utils/api-service';
-import Loader from '../packages/loader';
-import ModalForm from '../packages/modal-form';
-import UpsertPipelineSystem from './pipeline-system-upsert';
-
-//Helper function to format Graph date/time
-function formatDateTime(dateTime) {
- return moment.utc(dateTime).local().format('M/D/YY h:mm A');
-}
-
-const PipelineSystem = (props) => {
- const [systems,setSystems] = useState([]);
- const [isLoading,setIsLoading] = useState(true);
-
- useEffect(() => {
- const fetchData = async () => {
- try {
- if (props.isAuthenticated) {
- //Get the user's events
- var [systems] = await Promise.all([ getPipelineSystems() ]);
- //Update the array of events in state
- setSystems(systems);
- setIsLoading(false);
- } else {
- props.showNotify('danger', 'User not Authenticated', 'Please sign in to view this page')
- }
- }
- catch (err) {
- props.showNotify('danger', 'ERROR', JSON.stringify(err));
- }
- }
- fetchData();
- }, []);
-
- const editSystem = (system) => {
- setIsLoading(true);
- setSystems(systems.map(item => (item.systemId === system.systemId ? system : item)));
- setIsLoading(false);
- }
-
- const addSystem = (system) => {
- setIsLoading(true);
- setSystems(prevArray => [...prevArray, system]);
- setIsLoading(false);
- }
-
- if (props.isAuthenticated) {
-
- if (isLoading) {
- return (
-
- );
- }
-
- const pipelineSystems = systems.map(system => {
- return (
-
diff --git a/src/components/utils/api-service.js b/src/components/utils/api-service.js
index 0d90022..975148e 100644
--- a/src/components/utils/api-service.js
+++ b/src/components/utils/api-service.js
@@ -1,39 +1,28 @@
import config from './config';
-export async function getPipelineSystems() {
- var systems = [];
- var url = config.lagoonApiUrl + 'enterprise/pipelinesystem?code=' + config.lagoonApiCode;
- var resp = await fetch(url);
- systems = await resp.json();
- return systems;
-}
-
-export async function getFacilities() {
- var facilities = [];
- var url = config.lagoonApiUrl + 'enterprise/facility?code=' + config.lagoonApiCode;
- var resp = await fetch(url);
- facilities = await resp.json();
- return facilities;
-}
-
export async function getPosts() {
var posts = [];
- console.log('url',config);
- var url = config.jsonApiUrl + '/posts';
+ var url = config.jsonApiUrl + 'posts';
var resp = await fetch(url);
- console.log('getPosts',resp);
posts = await resp.json();
- console.log('getPosts',posts);
return posts;
}
-export async function upsertPipelineSystem(system) {
+export async function getUsers() {
+ var users = [];
+ var url = config.jsonApiUrl + 'users';
+ var resp = await fetch(url);
+ users = await resp.json();
+ return users;
+}
+
+export async function createPost(post) {
const requestOptions = {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(system)
+ headers: { 'Content-Type': 'application/json; charset=UTF-8' },
+ body: JSON.stringify(post)
};
- var url = config.lagoonApiUrl + 'enterprise/pipelinesystem?code=' + config.lagoonApiCode;
+ var url = config.jsonApiUrl + 'posts';
return fetch(url, requestOptions)
.then(async response => {
if (response.ok) {
@@ -51,13 +40,13 @@ export async function upsertPipelineSystem(system) {
});
}
-export async function upsertFacilities(facilities) {
+export async function updatePost(post) {
const requestOptions = {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(facilities)
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json; charset=UTF-8' },
+ body: JSON.stringify(post)
};
- var url = config.lagoonApiUrl + 'enterprise/facility?code=' + config.lagoonApiCode;
+ var url = config.jsonApiUrl + 'posts/' + post.id;
return fetch(url, requestOptions)
.then(async response => {
if (response.ok) {
diff --git a/src/components/utils/utils.js b/src/components/utils/utils.js
new file mode 100644
index 0000000..f982828
--- /dev/null
+++ b/src/components/utils/utils.js
@@ -0,0 +1,11 @@
+export function sortArrayByProperty(array, propName) {
+ return array.sort((obj1, obj2) => {
+ if (obj1[propName] < obj2[propName]) {
+ return -1;
+ }
+ if (obj1[propName] > obj2[propName]) {
+ return 1;
+ }
+ return 0;
+ });
+}
\ No newline at end of file
diff --git a/src/components/welcome/welcome.js b/src/components/welcome/welcome.js
index b40ff87..c0cc278 100644
--- a/src/components/welcome/welcome.js
+++ b/src/components/welcome/welcome.js
@@ -22,9 +22,9 @@ export default class Welcome extends React.Component {
render() {
return (
-
Well Management System
+
React Azure Started
- This app allows you to manage the well/pad/facility/system information in the Lagoon environment
+ This app is a quickstart to get a react app pointed to Azure AD and a CRUD screen pointing to JSONPLaceholder API, https://jsonplaceholder.typicode.com/