Skip to content

Commit 09e6a71

Browse files
committed
Build context added
1 parent 83e2e76 commit 09e6a71

File tree

4 files changed

+172
-36
lines changed

4 files changed

+172
-36
lines changed

src/App.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import Header from "./components/Header";
44
import { AuthProvider } from "./contexts/auth.context";
55
import { ProjectProvider } from "./contexts/project.context";
66
import Router from "./Router";
7+
import { BuildProvider } from "./contexts/build.context";
78

89
function App() {
910
return (
1011
<div className="App">
1112
<AuthProvider>
1213
<ProjectProvider>
13-
<Header />
14-
<Router />
14+
<BuildProvider>
15+
<Header />
16+
<Router />
17+
</BuildProvider>
1518
</ProjectProvider>
1619
</AuthProvider>
1720
</div>

src/components/BuildList.tsx

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@ import {
1111
Chip,
1212
} from "@material-ui/core";
1313
import { Delete } from "@material-ui/icons";
14-
import { Build } from "../types";
15-
import { buildsService } from "../services";
1614
import { useHistory } from "react-router-dom";
17-
18-
interface IBuildList {
19-
builds: Build[];
20-
setBuilds: React.Dispatch<React.SetStateAction<Build[]>>;
21-
selectedBuildId: string | undefined;
22-
}
15+
import {
16+
useBuildState,
17+
useBuildDispatch,
18+
deleteBuild,
19+
} from "../contexts/build.context";
2320

2421
const useStyles = makeStyles((theme: Theme) =>
2522
createStyles({
@@ -34,17 +31,15 @@ const useStyles = makeStyles((theme: Theme) =>
3431
})
3532
);
3633

37-
const BuildList: FunctionComponent<IBuildList> = ({
38-
builds,
39-
setBuilds,
40-
selectedBuildId,
41-
}) => {
34+
const BuildList: FunctionComponent = () => {
4235
const classes = useStyles();
4336
const history = useHistory();
37+
const { buildList, selectedBuildId } = useBuildState();
38+
const buildDispatch = useBuildDispatch();
4439

4540
return (
4641
<List>
47-
{builds.map((build) => (
42+
{buildList.map((build) => (
4843
<ListItem
4944
key={build.id}
5045
selected={selectedBuildId === build.id}
@@ -66,11 +61,7 @@ const BuildList: FunctionComponent<IBuildList> = ({
6661
<ListItemSecondaryAction className={classes.listItemSecondaryAction}>
6762
<IconButton
6863
onClick={() => {
69-
buildsService.remove(build.id).then((isRemoved) => {
70-
if (isRemoved) {
71-
setBuilds(builds.filter((item) => item.id !== build.id));
72-
}
73-
});
64+
deleteBuild(buildDispatch, build.id);
7465
}}
7566
>
7667
<Delete />

src/contexts/build.context.tsx

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import * as React from "react";
2+
import { Build } from "../types";
3+
import { buildsService } from "../services";
4+
5+
interface IRequestAction {
6+
type: "request";
7+
payload?: undefined;
8+
}
9+
10+
interface IGetAction {
11+
type: "get";
12+
payload: Build[];
13+
}
14+
15+
interface ISelectAction {
16+
type: "select";
17+
payload: string;
18+
}
19+
20+
interface IDeleteAction {
21+
type: "delete";
22+
payload: string;
23+
}
24+
25+
type IAction = IRequestAction | IGetAction | IDeleteAction | ISelectAction;
26+
27+
type Dispatch = (action: IAction) => void;
28+
type State = {
29+
selectedBuildId: string | undefined;
30+
buildList: Build[];
31+
};
32+
33+
type BuildProviderProps = { children: React.ReactNode };
34+
35+
const BuildStateContext = React.createContext<State | undefined>(undefined);
36+
const BuildDispatchContext = React.createContext<Dispatch | undefined>(
37+
undefined
38+
);
39+
40+
const initialState: State = {
41+
selectedBuildId: undefined,
42+
buildList: [],
43+
};
44+
45+
function buildReducer(state: State, action: IAction): State {
46+
switch (action.type) {
47+
case "select":
48+
return {
49+
...state,
50+
selectedBuildId: action.payload,
51+
};
52+
case "get":
53+
return {
54+
...state,
55+
buildList: action.payload,
56+
};
57+
case "delete":
58+
return {
59+
...state,
60+
buildList: state.buildList.filter((p) => p.id !== action.payload),
61+
};
62+
default:
63+
return state;
64+
}
65+
}
66+
67+
function BuildProvider({ children }: BuildProviderProps) {
68+
const [state, dispatch] = React.useReducer(buildReducer, initialState);
69+
70+
return (
71+
<BuildStateContext.Provider value={state}>
72+
<BuildDispatchContext.Provider value={dispatch}>
73+
{children}
74+
</BuildDispatchContext.Provider>
75+
</BuildStateContext.Provider>
76+
);
77+
}
78+
79+
function useBuildState() {
80+
const context = React.useContext(BuildStateContext);
81+
if (context === undefined) {
82+
throw new Error("must be used within a BuildProvider");
83+
}
84+
return context;
85+
}
86+
87+
function useBuildDispatch() {
88+
const context = React.useContext(BuildDispatchContext);
89+
if (context === undefined) {
90+
throw new Error("must be used within a BuildProvider");
91+
}
92+
return context;
93+
}
94+
95+
async function getBuildList(dispatch: Dispatch, id: string) {
96+
dispatch({ type: "request" });
97+
98+
buildsService
99+
.getList(id)
100+
.then((items) => {
101+
dispatch({ type: "get", payload: items });
102+
})
103+
.catch((error) => {
104+
console.log(error.toString());
105+
});
106+
}
107+
108+
async function deleteBuild(dispatch: Dispatch, id: string) {
109+
dispatch({ type: "request" });
110+
111+
buildsService
112+
.remove(id)
113+
.then((isDeleted) => {
114+
if (isDeleted) {
115+
dispatch({ type: "delete", payload: id });
116+
}
117+
})
118+
.catch((error) => {
119+
console.log(error.toString());
120+
});
121+
}
122+
123+
async function selectBuild(dispatch: Dispatch, id: string) {
124+
dispatch({ type: "select", payload: id });
125+
}
126+
127+
export {
128+
BuildProvider,
129+
useBuildState,
130+
useBuildDispatch,
131+
getBuildList,
132+
deleteBuild,
133+
selectBuild,
134+
};

src/pages/ProjectPage.tsx

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React, { useEffect, useState } from "react";
22
import { Grid, Dialog, IconButton, Box, Typography } from "@material-ui/core";
33
import { useParams, useLocation, useHistory } from "react-router-dom";
4-
import { Build, TestRun } from "../types";
5-
import { buildsService, testRunService } from "../services";
4+
import { TestRun } from "../types";
5+
import { testRunService } from "../services";
66
import BuildList from "../components/BuildList";
77
import ProjectSelect from "../components/ProjectSelect";
88
import qs from "qs";
@@ -11,6 +11,12 @@ import TestDetailsModal from "../components/TestDetailsModal";
1111
import { NavigateBefore, NavigateNext } from "@material-ui/icons";
1212
import Filters from "../components/Filters";
1313
import { buildTestRunLocation } from "../_helpers/route.helpers";
14+
import {
15+
useBuildState,
16+
useBuildDispatch,
17+
getBuildList,
18+
selectBuild,
19+
} from "../contexts/build.context";
1420

1521
const getQueryParams = (guery: string) => {
1622
const queryParams = qs.parse(guery, { ignoreQueryPrefix: true });
@@ -46,9 +52,9 @@ const ProjectPage = () => {
4652
const { projectId } = useParams();
4753
const location = useLocation();
4854
const history = useHistory();
49-
const [builds, setBuilds] = useState<Build[]>([]);
55+
const { buildList, selectedBuildId } = useBuildState();
56+
const buildDispatch = useBuildDispatch();
5057
const [testRuns, setTestRuns] = useState<TestRun[]>([]);
51-
const [selectedBuildId, setSelectedBuildId] = useState<string>();
5258
const [selectedTestdId, setSelectedTestId] = useState<string>();
5359
const [selectedTestRunIndex, setSelectedTestRunIndex] = useState<number>();
5460

@@ -64,9 +70,9 @@ const ProjectPage = () => {
6470
useEffect(() => {
6571
const queryParams = getQueryParams(location.search);
6672
if (queryParams.buildId) {
67-
setSelectedBuildId(queryParams.buildId);
68-
} else if (builds.length > 0) {
69-
setSelectedBuildId(builds[0].id);
73+
selectBuild(buildDispatch, queryParams.buildId);
74+
} else if (buildList.length > 0) {
75+
selectBuild(buildDispatch, buildList[0].id);
7076
}
7177
if (queryParams.testId) {
7278
setSelectedTestId(queryParams.testId);
@@ -76,13 +82,19 @@ const ProjectPage = () => {
7682
setSelectedTestId(undefined);
7783
setSelectedTestRunIndex(undefined);
7884
}
79-
}, [location.search, builds, testRuns, selectedTestRunIndex]);
85+
}, [
86+
location.search,
87+
buildList,
88+
testRuns,
89+
selectedTestRunIndex,
90+
buildDispatch,
91+
]);
8092

8193
useEffect(() => {
8294
if (projectId) {
83-
buildsService.getList(projectId).then((builds) => setBuilds(builds));
95+
getBuildList(buildDispatch, projectId);
8496
}
85-
}, [projectId]);
97+
}, [projectId, buildDispatch]);
8698

8799
useEffect(() => {
88100
if (selectedBuildId) {
@@ -126,11 +138,7 @@ const ProjectPage = () => {
126138
</Grid>
127139
</Grid>
128140
<Grid item>
129-
<BuildList
130-
builds={builds}
131-
setBuilds={setBuilds}
132-
selectedBuildId={selectedBuildId}
133-
/>
141+
<BuildList />
134142
</Grid>
135143
</Grid>
136144
<Grid item xs={9}>

0 commit comments

Comments
 (0)