Skip to content

Commit 07bea48

Browse files
authored
Merge pull request #1 from ucfx/pert-chart
Complete PERT Chart with Live Demo
2 parents 3a3812f + 67d7ef9 commit 07bea48

35 files changed

+2290
-20
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches:
66
- main
7+
- beta
78

89
jobs:
910
build:

README.md

Lines changed: 364 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,364 @@
1-
# pert-react
1+
<h1 align="center">react-pert</h1>
2+
3+
## :star2: Overview
4+
5+
This package provides tools to calculate and visualize a PERT (Program Evaluation and Review Technique) diagram. It includes the following components and utilities:
6+
7+
- **`Pert`**: A component to render the PERT diagram.
8+
- **`usePert`**: A custom hook to retrieve PERT results.
9+
- **Chart Interaction**: Allows interaction with the diagram, enabling the selection of tasks and displaying only the path related to the selected task.
10+
11+
### :rocket: Progress
12+
13+
- :white_check_mark: **PERT Calculator**: Fully functional.
14+
- :white_check_mark: **PERT Diagram**: Fully functional.
15+
16+
### :computer: Demo
17+
18+
Check out the live demo [here](https://ucfx.github.io/react-pert/).
19+
20+
---
21+
22+
## :clipboard: Installation
23+
24+
Install the package via npm:
25+
26+
```bash
27+
npm install react-pert
28+
```
29+
30+
---
31+
32+
## :book: Usage
33+
34+
### Using `Pert` Component
35+
36+
```jsx
37+
import { Pert, type TaskInput } from "react-pert";
38+
39+
const App = () => {
40+
const tasks: TaskInput[] = [
41+
{ key: "1", duration: 5, text: "A" },
42+
{ key: "2", duration: 4, text: "B" },
43+
{ key: "3", duration: 2, text: "C", dependsOn: ["1"] },
44+
{ key: "4", duration: 3, text: "D", dependsOn: ["2"] },
45+
//...
46+
];
47+
48+
return <Pert tasks={tasks} />;
49+
};
50+
```
51+
52+
### Using `usePert` Hook
53+
54+
You need to wrap your application with `PertProvider` to use the `usePert` hook. Here is an example of how you can use it:
55+
56+
- **Note**: You should put the `Pert` component and `usePert` hook in the same `PertProvider` to ensure that the PERT data is available to both.
57+
58+
```jsx
59+
import { PertProvider, usePert, type TaskInput } from "react-pert";
60+
61+
const App = () => {
62+
const tasks: TaskInput[] = [
63+
{ key: "1", duration: 5, text: "A" },
64+
{ key: "2", duration: 4, text: "B" },
65+
{ key: "3", duration: 2, text: "C", dependsOn: ["1"] },
66+
{ key: "4", duration: 3, text: "D", dependsOn: ["2"] },
67+
//...
68+
];
69+
return (
70+
<PertProvider>
71+
<Pert tasks={tasks} />
72+
<PertDetails />
73+
</PertProvider>
74+
);
75+
};
76+
```
77+
78+
```jsx
79+
import { usePert } from "react-pert";
80+
81+
const PertDetails = () => {
82+
const { projectDuration, criticalPaths } = usePert();
83+
84+
return (
85+
<div>
86+
<h3>Project Duration : {projectDuration}</h3>
87+
<h3>Critical Paths:</h3>
88+
<div>
89+
{criticalPaths.map((cp, index) => (
90+
<div key={index}>
91+
{cp.map((p, i) => (
92+
<span key={i}>
93+
{p.text}
94+
{i < cp.length - 1 && ""}
95+
</span>
96+
))}
97+
</div>
98+
))}
99+
</div>
100+
</div>
101+
);
102+
};
103+
```
104+
105+
---
106+
107+
## :bulb: Examples
108+
109+
- ### setSelectedTask
110+
111+
You can use the `setSelectedTask` function to select a task in the PERT diagram. This function is available when you import `setSelectedTask` from `react-pert`.
112+
113+
```typescript
114+
setSelectedTask: (taskKey: string | null) => void;
115+
```
116+
117+
```jsx
118+
import { Pert, PertProvider, setSelectedTask } from "react-pert";
119+
120+
const App = () => {
121+
const tasks = [
122+
{ key: "1", duration: 5, text: "A" },
123+
//...
124+
];
125+
126+
const handleClick = () => {
127+
setSelectedTask("1");
128+
};
129+
const handleClear = () => {
130+
setSelectedTask(null);
131+
};
132+
133+
return (
134+
// PertProvider is optional if you are using only setSelectedTask
135+
<PertProvider>
136+
<Pert tasks={tasks} />
137+
<button onClick={handleClick}>Select Task 1</button>
138+
<button onClick={handleClear}>Clear Selection</button>
139+
</PertProvider>
140+
);
141+
};
142+
```
143+
144+
- ### onSelect
145+
146+
You can use the `onSelect` prop to get the selected task when a task is selected in the PERT diagram.
147+
148+
```typescript
149+
onSelect?: (task: Task) => void;
150+
```
151+
152+
```jsx
153+
import { Pert } from "react-pert";
154+
155+
const App = () => {
156+
const tasks = [/*...*/];
157+
const handleSelect = (task) => {
158+
console.log("Selected Task:", task);
159+
};
160+
161+
return <Pert tasks={tasks} onSelect={handleSelect} />;
162+
};
163+
```
164+
165+
- ### `usePert` with `PertOptions`
166+
167+
You can pass options to the `usePert` hook to customize the output data.
168+
169+
```typescript
170+
const results = usePert({ bounds: true });
171+
```
172+
- Default: `true`
173+
174+
The `usePert` hook can be customized using the `bounds` option to include or exclude boundary tasks (Start and Finish) in the returned tasks.
175+
176+
#### Input
177+
178+
```jsx
179+
const input: TaskInput[] = [
180+
{ key: "1", duration: 5, text: "A" },
181+
{ key: "2", duration: 4, text: "B", dependsOn: ["1"] },
182+
{ key: "3", duration: 2, text: "C", dependsOn: ["2"] },
183+
];
184+
```
185+
186+
#### Output with `bounds = true`
187+
188+
When `bounds` is set to `true`, the Start and Finish tasks are included:
189+
190+
```jsx
191+
const output: Task[] = [
192+
{ key: "Start", text: "Start", duration: 0, dependsOn: [] },
193+
{ key: "1", text: "A", duration: 5, dependsOn: ["Start"], ...rest /* other properties */ },
194+
{ key: "2", text: "B", duration: 4, dependsOn: ["1"], ...rest /* other properties */ },
195+
{ key: "3", text: "C", duration: 2, dependsOn: ["2"], ...rest /* other properties */ },
196+
{ key: "Finish", text: "Finish", duration: 0, dependsOn: ["3"] },
197+
];
198+
```
199+
200+
#### Output with `bounds = false`
201+
202+
When `bounds` is set to `false`, the Start and Finish tasks are excluded:
203+
204+
```jsx
205+
const output: Task[] = [
206+
{ key: "1", text: "A", duration: 5, dependsOn: [], ...rest /* other properties */,},
207+
{ key: "2", text: "B", duration: 4, dependsOn: ["1"], ...rest /* other properties */ },
208+
{ key: "3", text: "C", duration: 2, dependsOn: ["2"], ...rest /* other properties */ },
209+
];
210+
```
211+
212+
## :books: API Reference
213+
214+
### `PertProps`
215+
216+
| Attribute | Type | Description |
217+
| ----------- | --------------------------- | --------------------------------------------------------------- |
218+
| `tasks` | [`TaskInput[]`](#taskinput) | Array of tasks to be used for the calculation and PERT diagram. |
219+
| `styles?` | [`PertStyles`](#pertstyles) | Optional styles configuration for the PERT chart. |
220+
| `onSelect?` | `(task: `[`Task`](#task)`) => void` | Optional callback invoked when a task is selected. |
221+
222+
### `Pert`
223+
224+
A visual representation of the PERT diagram (currently in development).
225+
226+
---
227+
228+
### `usePert`
229+
230+
#### Options:
231+
232+
### `PertOptions`
233+
234+
| Attribute | Type | Description |
235+
| --------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
236+
| `bounds` | `boolean` | Determines whether the boundary tasks (Start and Finish) should be included in the returned tasks. Default: `true` |
237+
238+
- If `true`, the Start and Finish tasks will be included.
239+
- If `false`, the Start and Finish tasks will be excluded.
240+
- Default: `true`
241+
242+
#### Returns:
243+
244+
- **`PertDataType`**: Contains all PERT data including tasks, levels, links, critical paths, and project duration.
245+
246+
### `PertDataType`
247+
248+
| Attribute | Type | Description |
249+
| ----------------- | --------------------------------- | ----------------------------------------------------------- |
250+
| `tasks` | [`Task[]`](#task) | Array of tasks with PERT calculation results. |
251+
| `levels` | [`LevelType`](#leveltype) | Mapping of task keys to their respective levels. |
252+
| `links` | [`LinkType[]`](#linktype) | Array of links representing the dependencies between tasks. |
253+
| `criticalPaths` | [`CriticalPath[]`](#criticalpath) | Array of critical paths in the project. |
254+
| `projectDuration` | `number` | Total duration of the project. |
255+
| `error?` | `string \| null` | Current error message, if any. |
256+
257+
### `TaskInput`
258+
259+
Represents a task with input data for PERT calculation.
260+
261+
| Attribute | Type | Description |
262+
| ------------ | ---------- | --------------------------------------------------------------- |
263+
| `key` | `string` | Unique identifier for the task. |
264+
| `text` | `string` | Description or name of the task. |
265+
| `duration` | `number` | Duration of the task in some unit (e.g., days). |
266+
| `dependsOn?` | `string[]` | Array of task keys that the current task depends on (optional). |
267+
268+
### `Task`
269+
270+
Represents a task with PERT calculation results.
271+
272+
| Attribute | Type | Description |
273+
| ------------- | ---------- | -------------------------------------------- |
274+
| `key` | `string` | Unique identifier for the task. |
275+
| `text` | `string` | Description or name of the task. |
276+
| `duration` | `number` | Duration of the task. |
277+
| `dependsOn?` | `string[]` | Array of task keys the task depends on. |
278+
| `earlyStart` | `number` | The earliest start time for the task. |
279+
| `earlyFinish` | `number` | The earliest finish time for the task. |
280+
| `lateStart` | `number` | The latest start time for the task. |
281+
| `lateFinish` | `number` | The latest finish time for the task. |
282+
| `level` | `number` | The level of the task in the PERT diagram. |
283+
| `critical` | `boolean` | Indicates if the task is on a critical path. |
284+
| `freeFloat` | `number` | The free float time of the task. |
285+
| `totalFloat` | `number` | The total float time of the task. |
286+
| `index` | `number` | Index of the task in the sequence. |
287+
288+
### `PertStyles`
289+
290+
Styles configuration for the PERT chart.
291+
292+
| Attribute | Type | Description |
293+
| ---------------------- | ---------------------------- | -------------------------------------------------------- |
294+
| `disableGrid?` | `boolean` | Whether to disable grid lines in the chart. |
295+
| `taskSize?` | `number` | Size of the task node in pixels. |
296+
| `fontFamily?` | `string` | Font family for the text in the task nodes. |
297+
| `fontSize?` | [`FontSize`](#fontsize) | Font size for the text in the task nodes. |
298+
| `textColor?` | `string` | Color of the text inside the task nodes. |
299+
| `chartBackground?` | `string` | Background color of the entire chart. |
300+
| `taskBackground?` | `string` | Background color of the task nodes. |
301+
| `gridColor?` | `string` | Color of the grid lines in the chart. |
302+
| `borderWidth?` | `number` | Width of the border for task nodes. |
303+
| `selectedBorderWidth?` | `number` | Width of the border for selected task nodes. |
304+
| `hoverBorderWidth?` | `number` | Width of the border when hovering over task nodes. |
305+
| `borderColor?` | `string` | Color of the border for task nodes. |
306+
| `selectedBorderColor?` | `string` | Color of the border for selected task nodes. |
307+
| `criticalColor?` | `string` | Color for critical path elements (e.g., tasks or links). |
308+
| `arrowColor?` | `string` | Color of the arrows (links) between task nodes. |
309+
| `arrowWidth?` | `number` | Width of the arrows (links) between task nodes. |
310+
| `gap?` | `{ x?: number; y?: number }` | Gap between task nodes in the chart. |
311+
312+
### `FontSize`
313+
314+
| Type | Description |
315+
| ------------------------------------------------------------------------- | --------------------------------------------- |
316+
| `"sm"`, `"md"`, `"lg"`, `"xl"`, `"2xl"`, `"3xl"`, `string & {}`, `number` | Font size options for text in the task nodes. |
317+
318+
### `LevelType`
319+
320+
Represents a mapping of task keys to their respective levels in the PERT diagram.
321+
322+
| Attribute | Type | Description |
323+
| --------- | ---------- | ----------------------------------------- |
324+
| `key` | `number` | The level number in the PERT diagram. |
325+
| `value` | `string[]` | Array of task keys at the specific level. |
326+
327+
### `LinkType`
328+
329+
Represents a link between two tasks in the PERT diagram.
330+
331+
| Attribute | Type | Description |
332+
| ---------- | --------- | ------------------------------------------------- |
333+
| `from` | `string` | The task key from which the link originates. |
334+
| `to` | `string` | The task key to which the link leads. |
335+
| `critical` | `boolean` | Indicates if the link is part of a critical path. |
336+
337+
### `CriticalPath`
338+
339+
Represents a critical path in the PERT diagram.
340+
341+
| | Type | Description |
342+
| -------------- | -------------------------- | ------------------------------------------------------------------------- |
343+
| `CriticalPath` | [`PathItem[]`](#pathitem) | An array of tasks (`PathItem`) forming the critical path. |
344+
345+
### `PathItem`
346+
347+
| Attribute | Type | Description |
348+
| --------- | -------- | ---------------------------------- |
349+
| `text` | `string` | Description or name of the task. |
350+
| `key` | `string` | Task key identifier. |
351+
352+
---
353+
354+
## :handshake: Contributing
355+
356+
We welcome contributions! If you encounter any bugs or have feature requests, please open an issue or submit a pull request.
357+
358+
---
359+
360+
## :page_with_curl: License
361+
362+
This package is open-source and licensed under the [MIT License](LICENSE.md).
363+
364+
Enjoy building with **PERT Diagram**! :relaxed:

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="UTF-8" />
66
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
77
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8-
<title>pert-react Demo</title>
8+
<title>react-pert Demo</title>
99
</head>
1010

1111
<body>

lib/components/Error.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Error({ error }: { error: string }) {
2+
return (
3+
<div
4+
style={{
5+
display: "flex",
6+
justifyContent: "center",
7+
alignItems: "center",
8+
fontSize: "1.5rem",
9+
padding: "3rem",
10+
}}
11+
>
12+
{error}
13+
</div>
14+
);
15+
}

0 commit comments

Comments
 (0)