Skip to content

Commit ae57e90

Browse files
set up and move state into mobx stores
1 parent b923913 commit ae57e90

File tree

12 files changed

+220
-137
lines changed

12 files changed

+220
-137
lines changed

API/reactivities.db

0 Bytes
Binary file not shown.

client-app/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client-app/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"@types/react": "^17.0.11",
1212
"@types/react-dom": "^17.0.7",
1313
"axios": "^0.21.1",
14+
"mobx": "^6.3.2",
15+
"mobx-react-lite": "^3.2.0",
1416
"react": "^17.0.2",
1517
"react-dom": "^17.0.2",
1618
"react-scripts": "4.0.3",

client-app/src/app/layout/App.tsx

Lines changed: 12 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,42 @@
11
import { useEffect, useState } from "react";
22
import { ActivityDashboard } from "../../features/activities/dashboard/ActivityDashboard";
33
import { v4 as uuidv4 } from "uuid";
4-
5-
64
import { Container } from "semantic-ui-react";
75
import { NavBar } from "./NavBar";
86
import { Activity } from "../models/activities";
97
import agent from "../api/agent";
108
import LoadingComponents from "./LoadingComponents";
9+
import { useStore } from "../stores/store";
10+
import { observer } from "mobx-react-lite";
1111

1212
function App() {
13-
const [activities, setActivities] = useState<Activity[]>([]);
14-
const [selectedActivity, setSelectedActivity] =
15-
useState<Activity | undefined>(undefined);
16-
const [editMode, setEditMode] = useState(false);
17-
const [loading, setLoading] = useState(true);
18-
const [submitting, setSubmitting] = useState(false)
13+
const {activityStore} = useStore();
1914

20-
useEffect(() => {
21-
agent.Activities.list()
22-
.then(response => {
23-
response.forEach( res => {
24-
//modify date string to include only date portion -- 2 ways to do it
25-
//can also create a new wmply array of type activities and push each modified activity into the array, then set state with newly formed array
26-
res.date = res.date.substr(0, res.date.indexOf('T'));
27-
//res.date = res.date.split('T')[0];
28-
})
29-
setActivities(response);
30-
setLoading(false);
31-
});
32-
}, []);
3315

34-
const handleSelectActivity = (id: string) => {
35-
setSelectedActivity(activities.find((x) => x.id === id));
36-
};
37-
const handleCancelSelection = () => {
38-
setSelectedActivity(undefined);
39-
};
4016

41-
const handleFormOpen = (id?: string) => {
42-
id ? handleSelectActivity(id) : handleCancelSelection();
43-
setEditMode(true);
44-
};
45-
const handleFormClose = () => {
46-
setEditMode(false);
47-
};
4817

49-
const handleCreateOrEditActivity = (activity: Activity) => {
50-
setSubmitting(true)
51-
if(activity.id){
52-
agent.Activities.update(activity).then (() => {
53-
setActivities([
54-
...activities.filter((x) => x.id !== activity.id),
55-
activity,
56-
]);
57-
setEditMode(false);
58-
setSelectedActivity(activity);
59-
setSubmitting(false);
60-
})
18+
useEffect(() => {
19+
//actSttore will be populated with the data when called
20+
activityStore.loadActivites()
21+
}, [activityStore]);
22+
6123

62-
63-
}else {
64-
activity.id = uuidv4();
65-
agent.Activities.create(activity).then( () => {
66-
setActivities([...activities, activity]);
67-
setEditMode(false);
68-
setSelectedActivity(activity);
69-
setSubmitting(false);
70-
}).catch((err) => {
71-
console.log(err);
72-
})
73-
74-
}
7524

76-
};
7725

78-
const handleDeleteActivity = (id: string) => {
79-
setSubmitting(true);
80-
agent.Activities.delete(id).then(()=> {
81-
setActivities([...activities.filter((x) => x.id !== id)]);
82-
setSubmitting(false);
83-
})
8426

8527

86-
};
87-
if(loading) return <LoadingComponents inverted={true} content='Lodading app...'/>
28+
if(activityStore.loadingInitial) return <LoadingComponents inverted={true} content='Lodading app...'/>
8829
return (
8930
<>
90-
<NavBar formOpen={handleFormOpen}></NavBar>
31+
<NavBar ></NavBar>
9132

9233
<Container style={{ marginTop: "7em" }}>
9334
<ActivityDashboard
94-
activities={activities}
95-
selectedActivity={selectedActivity}
96-
selectActivity={handleSelectActivity}
97-
cancelSelection={handleCancelSelection}
98-
formOpen={handleFormOpen}
99-
formClose={handleFormClose}
100-
editMode={editMode}
101-
submitForm={handleCreateOrEditActivity}
102-
deleteActivity={handleDeleteActivity}
103-
submitting={submitting}
35+
10436
></ActivityDashboard>
10537
</Container>
10638
</>
10739
);
10840
}
10941

110-
export default App;
42+
export default observer(App);

client-app/src/app/layout/NavBar.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React from 'react'
22
import { Menu, Container, Button } from 'semantic-ui-react'
3+
import { useStore } from '../stores/store';
4+
35

4-
interface Props {
5-
formOpen: () =>void;
6-
}
76

8-
export const NavBar = ({formOpen}: Props) => {
7+
export const NavBar = () => {
8+
const {activityStore} = useStore();
9+
const {formOpen} = activityStore;
910
return (
1011
<>
1112
<Menu inverted fixed='top' >
@@ -16,7 +17,7 @@ export const NavBar = ({formOpen}: Props) => {
1617
</Menu.Item>
1718
<Menu.Item name="Activities"></Menu.Item>
1819
<Menu.Item>
19-
<Button onClick={formOpen} positive content='Create Activity'></Button>
20+
<Button onClick={() => formOpen()} positive content='Create Activity'></Button>
2021
</Menu.Item>
2122
</Container>
2223

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { action, makeAutoObservable } from "mobx";
2+
3+
import agent from "../api/agent";
4+
import { Activity } from "../models/activities";
5+
import {v4 as uuid} from 'uuid';
6+
7+
8+
export default class ActivityStore {
9+
activities: Activity[] = [];
10+
selectedActivity: Activity | undefined = undefined;
11+
editMode = false;
12+
loading = false;
13+
loadingInitial = false;
14+
15+
constructor() {
16+
makeAutoObservable(this);
17+
}
18+
19+
loadActivites = async () => {
20+
this.setLoadingInitial(true);
21+
//async code goes in the try catch
22+
try {
23+
const activities = await agent.Activities.list();
24+
25+
activities.forEach((res => {
26+
res.date = res.date.split('T')[0];
27+
this.activities.push(res);
28+
29+
}))
30+
this.setLoadingInitial(false);
31+
} catch (error) {
32+
console.log(error);
33+
this.setLoadingInitial(false);
34+
}
35+
};
36+
37+
setLoadingInitial = (state: boolean) => {
38+
this.loadingInitial = state;
39+
};
40+
41+
selectActivity = (id: string) => {
42+
this.selectedActivity = this.activities.find((x) => x.id === id);
43+
console.log(this.selectedActivity);
44+
};
45+
cancelSelection = () => {
46+
this.selectedActivity = undefined;
47+
};
48+
49+
formOpen = (id?: string) => {
50+
id ? this.selectActivity(id) : this.cancelSelection();
51+
this.setEditMode(true);
52+
};
53+
formClose = () => {
54+
this.setEditMode(false);
55+
};
56+
57+
58+
//USING ASYNC PROMISES, THEN FUNCTIONS MUST CALL OTHER IMPLEMENTED ACTION METHODS (AS IN 'IF' BLOCK) OR BE WRAPPED IN ACTION() OR RUNINACTION() (AS IN 'ELSE' BLOCK)
59+
createOrEditActivity = (activity:Activity) => {
60+
this.setLoading(true);
61+
if(activity.id) {
62+
agent.Activities.update(activity).then(()=>{
63+
this.updateActivity(activity);
64+
this.selectActivity(activity.id);
65+
this.setLoading(false);
66+
}).catch((error)=>{
67+
console.log(error)
68+
})
69+
}else {
70+
activity.id = uuid();
71+
agent.Activities.create(activity).then(() => {
72+
action( (() => {
73+
this.activities = [...this.activities, activity];
74+
this.updateActivity(activity);
75+
this.selectActivity(activity.id);
76+
this.setLoading(false);
77+
})
78+
)
79+
}).catch((error)=>{
80+
console.log(error)
81+
})
82+
}
83+
84+
85+
86+
};
87+
88+
updateActivity = (activity:Activity) => {
89+
this.activities = [...this.activities.filter(x=> x.id !== activity.id),activity];
90+
}
91+
92+
deleteActivity = (id:string) => {
93+
this.setLoading(true);
94+
agent.Activities.delete(id).then( ()=> {
95+
this.activities = [...this.activities.filter(x=> x.id !== id)]
96+
}).catch((error) =>{
97+
console.log(error);
98+
});
99+
if(this.selectedActivity?.id === id) this.cancelSelection();
100+
this.setLoading(false);
101+
};
102+
setLoading = (state: boolean) => {
103+
this.loading = state;
104+
}
105+
106+
setEditMode = (state: boolean) => {
107+
this.editMode = state;
108+
}
109+
}
110+
111+
112+
113+
114+

client-app/src/app/stores/store.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useContext, createContext } from "react";
2+
import ActivityStore from "./activityStore";
3+
4+
//defines the Store TYPE
5+
interface Store {
6+
activityStore : ActivityStore
7+
}
8+
9+
//impliments an instance of the store type
10+
export const store: Store = {
11+
activityStore: new ActivityStore()
12+
}
13+
14+
//makes the store into a context object called StoreContext which is accessed when using useStore; will be used as a component.provider to wrap app and provide this conext to all children
15+
export const StoreContext = createContext(store);
16+
17+
18+
//adds a wrapper to better read which context is being used via a custom hook
19+
//used as the consumer and added to all children to access the elements in the StoreContext
20+
export function useStore() {
21+
return useContext(StoreContext);
22+
}
23+
24+
25+
26+
27+
28+
29+
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
11
import React from "react";
22
import { GridColumn, Grid } from "semantic-ui-react";
33
import { Activity } from "../../../app/models/activities";
4+
import { useStore } from "../../../app/stores/store";
45
import ActivityDetails from "../details/ActivityDetails";
56
import ActivityForm from "../form/ActivityForm";
67
import ActivityList from "./ActivityList";
8+
import { observer } from "mobx-react-lite";
79

8-
interface Props {
9-
activities: Activity[];
10-
selectedActivity: Activity | undefined;
11-
editMode: boolean;
12-
submitting: boolean;
13-
selectActivity: (id: string) => void;
14-
cancelSelection: () => void;
15-
formOpen: (id? : string) => void;
16-
formClose: () => void;
17-
submitForm: (activity:Activity) => void;
18-
deleteActivity: (id: string) => void;
1910

20-
}
21-
export const ActivityDashboard = ({ activities, selectedActivity, selectActivity, cancelSelection, formOpen, formClose, editMode, submitting,submitForm, deleteActivity}: Props) => {
11+
12+
export const ActivityDashboard = observer( () => {
13+
const {activityStore} = useStore();
14+
const {selectedActivity, editMode} = activityStore;
15+
2216
return (
2317
<>
2418
<Grid>
2519
<Grid.Column width="10">
26-
<ActivityList activities={activities} selectActivity={selectActivity} deleteActivity={deleteActivity} editMode={editMode} submitting={submitting} ></ActivityList>
20+
<ActivityList ></ActivityList>
2721
</Grid.Column>
2822
<GridColumn width="6">
2923
{selectedActivity && !editMode && (
30-
<ActivityDetails activity={selectedActivity} cancelSelection={cancelSelection} formOpen={formOpen} ></ActivityDetails>
24+
<ActivityDetails ></ActivityDetails>
3125
)}
3226
{editMode &&
33-
<ActivityForm selectedActivity={selectedActivity} formClose={formClose} submitForm={submitForm} submitting={submitting}></ActivityForm>}
27+
<ActivityForm ></ActivityForm>}
3428
</GridColumn>
3529
</Grid>
3630
</>
3731
);
38-
};
32+
});

0 commit comments

Comments
 (0)