|
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: |
0 commit comments