epam-ai-conductor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +46 -0
  2. package/bin/workshop.js +6 -0
  3. package/dist/auth-check.d.ts +1 -0
  4. package/dist/auth-check.js +45 -0
  5. package/dist/auth-check.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +156 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/content/content/module-1/task/module-1_home-task_components.md +257 -0
  10. package/dist/content/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  11. package/dist/content/content/module-1/task/module-1_home-task_task.md +253 -0
  12. package/dist/content/content/module-1/tests/Button.test.tsx +22 -0
  13. package/dist/content/content/module-1/tests/CourseCard.test.tsx +64 -0
  14. package/dist/content/content/module-1/tests/CourseInfo.test.tsx +73 -0
  15. package/dist/content/content/module-1/tests/Courses.test.tsx +87 -0
  16. package/dist/content/content/module-1/tests/Header.test.tsx +23 -0
  17. package/dist/content/content/module-1/tests/Input.test.tsx +36 -0
  18. package/dist/content/content/module-1/tests/helpers.test.ts +13 -0
  19. package/dist/content/content/module-1/theory/module-1_elements-render.md +66 -0
  20. package/dist/content/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  21. package/dist/content/content/module-1/theory/module-1_hooks_useState.md +131 -0
  22. package/dist/content/content/module-1/theory/module-1_react.md +64 -0
  23. package/dist/content/content/module-1/theory/module-1_spa.md +74 -0
  24. package/dist/content/content/module-2/task/module-2_home-task_components.md +313 -0
  25. package/dist/content/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  26. package/dist/content/content/module-2/task/module-2_home-task_task.md +210 -0
  27. package/dist/content/content/module-2/tests/App.test.tsx +54 -0
  28. package/dist/content/content/module-2/tests/Login.test.tsx +73 -0
  29. package/dist/content/content/module-2/tests/Registration.test.tsx +70 -0
  30. package/dist/content/content/module-2/tests/SearchBar.test.tsx +39 -0
  31. package/dist/content/content/module-2/theory/module-2_custom-hooks.md +201 -0
  32. package/dist/content/content/module-2/theory/module-2_hooks.md +117 -0
  33. package/dist/content/content/module-2/theory/module-2_react-router.md +328 -0
  34. package/dist/content/content/module-3/task/module-3_home-task_components.md +94 -0
  35. package/dist/content/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  36. package/dist/content/content/module-3/task/module-3_home-task_task.md +170 -0
  37. package/dist/content/content/module-3/tests/App.test.tsx +54 -0
  38. package/dist/content/content/module-3/tests/Courses.test.tsx +87 -0
  39. package/dist/content/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  40. package/dist/content/content/module-3/tests/CreateCourse.test.tsx +122 -0
  41. package/dist/content/content/module-3/theory/module-3_redux-hooks.md +194 -0
  42. package/dist/content/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  43. package/dist/content/content/module-4/task/module-4_home-task_components.md +187 -0
  44. package/dist/content/content/module-4/task/module-4_home-task_task.md +139 -0
  45. package/dist/content/content/module-4/tests/App.test.tsx +54 -0
  46. package/dist/content/content/module-4/tests/Courses.test.tsx +87 -0
  47. package/dist/content/content/module-4/tests/CreateCourse.test.tsx +122 -0
  48. package/dist/content/content/module-4/tests/Login.test.tsx +73 -0
  49. package/dist/content/content/module-4/theory/module-4_async-redux.md +99 -0
  50. package/dist/content/content/module-4/theory/module-4_private-routes.md +55 -0
  51. package/dist/content/content/module-5/task/module-5_home-task_instruction.md +68 -0
  52. package/dist/content/content/module-5/task/module-5_home-task_task.md +154 -0
  53. package/dist/content/content/module-5/tests/App.test.tsx +54 -0
  54. package/dist/content/content/module-5/tests/CourseCard.test.tsx +64 -0
  55. package/dist/content/content/module-5/tests/Courses.test.tsx +87 -0
  56. package/dist/content/content/module-5/tests/Header.test.tsx +23 -0
  57. package/dist/content/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  58. package/dist/content/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  59. package/dist/content/module-1/task/module-1_home-task_components.md +257 -0
  60. package/dist/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  61. package/dist/content/module-1/task/module-1_home-task_task.md +253 -0
  62. package/dist/content/module-1/tests/Button.test.tsx +22 -0
  63. package/dist/content/module-1/tests/CourseCard.test.tsx +64 -0
  64. package/dist/content/module-1/tests/CourseInfo.test.tsx +73 -0
  65. package/dist/content/module-1/tests/Courses.test.tsx +87 -0
  66. package/dist/content/module-1/tests/Header.test.tsx +23 -0
  67. package/dist/content/module-1/tests/Input.test.tsx +36 -0
  68. package/dist/content/module-1/tests/helpers.test.ts +13 -0
  69. package/dist/content/module-1/theory/module-1_elements-render.md +66 -0
  70. package/dist/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  71. package/dist/content/module-1/theory/module-1_hooks_useState.md +131 -0
  72. package/dist/content/module-1/theory/module-1_react.md +64 -0
  73. package/dist/content/module-1/theory/module-1_spa.md +74 -0
  74. package/dist/content/module-2/task/module-2_home-task_components.md +313 -0
  75. package/dist/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  76. package/dist/content/module-2/task/module-2_home-task_task.md +210 -0
  77. package/dist/content/module-2/tests/App.test.tsx +54 -0
  78. package/dist/content/module-2/tests/Login.test.tsx +73 -0
  79. package/dist/content/module-2/tests/Registration.test.tsx +70 -0
  80. package/dist/content/module-2/tests/SearchBar.test.tsx +39 -0
  81. package/dist/content/module-2/theory/module-2_custom-hooks.md +201 -0
  82. package/dist/content/module-2/theory/module-2_hooks.md +117 -0
  83. package/dist/content/module-2/theory/module-2_react-router.md +328 -0
  84. package/dist/content/module-3/task/module-3_home-task_components.md +94 -0
  85. package/dist/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  86. package/dist/content/module-3/task/module-3_home-task_task.md +170 -0
  87. package/dist/content/module-3/tests/App.test.tsx +54 -0
  88. package/dist/content/module-3/tests/Courses.test.tsx +87 -0
  89. package/dist/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  90. package/dist/content/module-3/tests/CreateCourse.test.tsx +122 -0
  91. package/dist/content/module-3/theory/module-3_redux-hooks.md +194 -0
  92. package/dist/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  93. package/dist/content/module-4/task/module-4_home-task_components.md +187 -0
  94. package/dist/content/module-4/task/module-4_home-task_task.md +139 -0
  95. package/dist/content/module-4/tests/App.test.tsx +54 -0
  96. package/dist/content/module-4/tests/Courses.test.tsx +87 -0
  97. package/dist/content/module-4/tests/CreateCourse.test.tsx +122 -0
  98. package/dist/content/module-4/tests/Login.test.tsx +73 -0
  99. package/dist/content/module-4/theory/module-4_async-redux.md +99 -0
  100. package/dist/content/module-4/theory/module-4_private-routes.md +55 -0
  101. package/dist/content/module-5/task/module-5_home-task_instruction.md +68 -0
  102. package/dist/content/module-5/task/module-5_home-task_task.md +154 -0
  103. package/dist/content/module-5/tests/App.test.tsx +54 -0
  104. package/dist/content/module-5/tests/CourseCard.test.tsx +64 -0
  105. package/dist/content/module-5/tests/Courses.test.tsx +87 -0
  106. package/dist/content/module-5/tests/Header.test.tsx +23 -0
  107. package/dist/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  108. package/dist/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  109. package/dist/content-loader.d.ts +7 -0
  110. package/dist/content-loader.js +26 -0
  111. package/dist/content-loader.js.map +1 -0
  112. package/dist/context-builder.d.ts +2 -0
  113. package/dist/context-builder.js +116 -0
  114. package/dist/context-builder.js.map +1 -0
  115. package/package.json +40 -0
@@ -0,0 +1,445 @@
1
+ ---
2
+ sidebar_position: 2
3
+ sidebar_label: "State, Actions and Reducers"
4
+ title: "State, Actions and Reducers"
5
+ ---
6
+
7
+ The next step to manage a work with the store is to create `Reducer` with `State`.
8
+
9
+ The easiest way to understand how it works is to consider it as an example.
10
+ Let's create a store for our 'Courses' application.
11
+
12
+ **Files structure**:
13
+
14
+ ```
15
+ store
16
+ |-- courses
17
+ | |-- reducer.js
18
+ | |-- actions.js
19
+ | |__ types.js
20
+ |
21
+ |-- rootReducer.js
22
+ |
23
+ |-- index.js
24
+ ```
25
+
26
+ ## Initial state
27
+
28
+ One of the core principles of React and Redux is that **your UI should be based on your state**.
29
+ One strategy for designing an application involves initially considering all the state required to describe its functionality.
30
+ It is also beneficial to aim for describing your UI using as few values in the state as possible,
31
+ which results in less data to monitor and update.
32
+
33
+ \*Conceptually, the primary aspect of this application is the actual list of current course items.
34
+
35
+ In our case, since we don't have any courses for the initial state, we should obtain them through an API request.
36
+
37
+ ```jsx
38
+ const initialCoursesState = [];
39
+ ```
40
+
41
+ ## Actions
42
+
43
+ **Actions are plain JavaScript objects that have a `type` field.**
44
+
45
+ ```js
46
+ const ACTION = {type: string, payload?: any};
47
+ ```
48
+
49
+ _Similar to designing the state structure based on the app's requirements, we should be able to generate a list of
50
+ actions that describe the events occurring in the app:_
51
+
52
+ 1. _Save courses from the response to the store_
53
+ 2. _Add a new course entry based on the data the user entered._
54
+ 3. _Delete a course._
55
+
56
+ Typically, any additional data needed to describe an event is placed in the `action.payload` field. This data could be a number, a string, or an object with multiple fields.
57
+
58
+ `action.type` is simply a string, and you can create any type you prefer. The Redux store is not concerned with the actual text of the `action.type` field. It's recommended to select action types that are easily understandable and accurately describe the event.
59
+ This way, it will be much more straightforward to realize the actions when reviewing them later.
60
+
61
+ _For our COURSES application, let's create the action types in a `types.js` file._
62
+
63
+ ```js
64
+ //types.js
65
+
66
+ export const SAVE_COURSES = "SAVE_COURSES";
67
+ export const DELETE_COURSE = "DELETE_COURSE";
68
+ export const ADD_COURSE = "ADD_COURSE";
69
+ ```
70
+
71
+ _The next step is to create action creators for these types in an `actions.js` file._
72
+
73
+ ```js
74
+ // actions.js
75
+
76
+ import { SAVE_COURSES, DELETE_COURSE, ADD_COURSE } from './types.js'
77
+
78
+ const addCourseAction = (payload) => ({ type: ADD_COURSE, payload });
79
+ const deleteCourseAction = (payload) => ({ type: DELETE_COURSE, payload });
80
+ const saveCoursesAction = (payload) => ({ type: SAVE_COURSES, payload });
81
+
82
+ ```
83
+
84
+ ## Reducers
85
+
86
+ With the knowledge of our state structure and the actions, we can now proceed to write our first reducer.
87
+
88
+ **Reducers are functions that take the current `state` and an `action` as arguments, and return a new `state` result.**
89
+
90
+ ```js
91
+ const reducer = (state, action) => newState;
92
+ ```
93
+
94
+ ### Creating the Reducer
95
+
96
+ A Redux app essentially has a single reducer function: the "root reducer" function that
97
+ will be passed to `configureStore` at a later stage.<br/>
98
+
99
+ _(In some example code, you may see createStore instead, but it is now deprecated. <br />
100
+ IAlthough it still works and is mentioned in the Redux documentation for "plain" Redux,
101
+ using Redux Toolkit is the recommended approach.<br />
102
+ Please use `configureStore`. See more [here](https://stackoverflow.com/a/71947129/12236670).)_
103
+
104
+ The single root reducer function is responsible for handling all dispatched actions and
105
+ determining the entire new state result each time an action occurs.
106
+
107
+ Let's start by creating a `coursesReducer` in `reducer.js` file for our application.
108
+
109
+ Every reducer requires an initial state.
110
+ After defining the initial state, we can draft a framework for the logic inside the reducer function:
111
+
112
+ ```js
113
+ import { SAVE_COURSES, DELETE_COURSE, ADD_COURSE } from './types.js'
114
+
115
+ export const coursesInitialState = [];
116
+ // Use the initialState as a default value
117
+ export const coursesReducer = (state = coursesInitialState, action) => {
118
+ // The reducer normally looks at the action type field to decide what happens
119
+ switch (action.type) {
120
+ // Do something here based on the different types of actions
121
+ default:
122
+ // If this reducer doesn't recognize the action type, or doesn't
123
+ // care about this specific action, return the existing state unchanged
124
+ return state
125
+ }
126
+ }
127
+ ```
128
+
129
+ Following that, let's implement the logic to handle the `SAVE_COURSES` and `ADD_COURSE` actions.
130
+
131
+ ```js
132
+ export const coursesReducer = (state = coursesInitialState, action) => {
133
+ switch (action.type) {
134
+ // in this case we need to return
135
+ case SAVE_COURSES:
136
+ return action.payload;
137
+
138
+ case ADD_COURSE:
139
+ return [...state, action.payload];
140
+
141
+ default:
142
+ return state;
143
+ }
144
+ };
145
+ ```
146
+
147
+ Continue implementing the logic for each action as needed.
148
+
149
+ ### Creating the Root Reducer
150
+
151
+ You might have numerous reducers, but it's necessary to create a single root reducer to combine all of them.
152
+
153
+ **Create the root reducer using `combineReducers`.**
154
+
155
+ ```js
156
+ import { combineReducers, configureStore } from "@reduxjs/toolkit";
157
+
158
+ import { coursesReducer } from "./courses/reducer.js"; // reducer that we already have
159
+
160
+ const rootReducer = combineReducers({
161
+ courses: coursesReducer,
162
+ //could be extended by another slice of reducer that respond for other part of your app
163
+ });
164
+
165
+ export const store = configureStore({ reducer: rootReducer });
166
+ ```
167
+
168
+ **Create root reducer without `combineReducers`.**
169
+
170
+ ```js
171
+ import { combineReducers } from "@reduxjs/toolkit";
172
+ import { coursesReducer } from "./courses/reducer.js"; // reducer that we already have
173
+
174
+ export const store = configureStore({
175
+ reducer: {
176
+ courses: coursesReducer,
177
+ //could be extended by another slice of reducer that respond for other part of your app
178
+ },
179
+ });
180
+ ```
181
+
182
+ :::info
183
+ **`reducer`**
184
+ If there is single function, it can be directly employed as the root reducer for the store.
185
+
186
+ If it is an object of slice reducers, like `{courses : coursesReducer, user : userReducer}`,
187
+ `configureStore` will automatically create the root reducer by passing this object to the
188
+ [Redux combineReducers utility](https://redux.js.org/api/combinereducers).
189
+ :::
190
+
191
+ ### Rules of Reducers
192
+
193
+ **Reducers must always follow some special rules:**
194
+
195
+ &#9989; They should only calculate the new `state` value based on the state and action arguments.
196
+
197
+ &#10062; They are not allowed to modify the existing `state`.
198
+
199
+ Instead, reducers must perform immutable updates by copying the existing state and applying changes to the copied values.
200
+
201
+ &#10060; Reducers must not implement any asynchronous logic or other ["side effects"](https://dev.to/vonheikemen/dealing-with-side-effects-and-pure-functions-in-javascript-16mg)
202
+
203
+ A function that adheres to these rules is also referred to as a ["pure" function](get-started#three-redux-fundamental-principles), even if it's not specifically written as a reducer function.
204
+
205
+ ### &#10071; Courses reducer with TypeScript
206
+
207
+ Let's add type checking with TS to our example.
208
+
209
+ 1. Describe the course entity type
210
+
211
+ ```ts
212
+ type CourseType = {
213
+ id: string;
214
+ title: string;
215
+ description: string;
216
+ creationDate: string;
217
+ duration: number;
218
+ authors: string[];
219
+ };
220
+ ```
221
+
222
+ 2. Create `enum` for possible courses' action types
223
+
224
+ ```ts
225
+ const enum CoursesActionTypes {
226
+ SAVE_COURSES = "SAVE_COURSES",
227
+ ADD_COURSE = "ADD_COURSE",
228
+ DELETE_COURSE = "DELETE_COURSES",
229
+ }
230
+ ```
231
+
232
+ With the use of an enum, there is no need to describe the action in an `actions.ts` file.
233
+ Enum serves as a self-descriptive representation of the action types.
234
+
235
+ 3. Once we have actions, we need to create action creators. As an example let's create action creator for ADD_COURSE action.
236
+
237
+ ```ts
238
+ type AddNewCourseAction = {
239
+ type: CoursesActionTypes.ADD_COURSE;
240
+ payload: CourseValues;
241
+ };
242
+
243
+ export const addNewCourseAction = (
244
+ courseData: CourseType,
245
+ ): AddNewCourseAction => ({
246
+ type: CoursesActionTypes.ADD_COURSE,
247
+ payload: courseData,
248
+ });
249
+ ```
250
+
251
+ 4. Create `interface` for each action and type for courses actions
252
+
253
+ ```ts
254
+ interface SaveCourses {
255
+ type: CoursesActionTypes.SAVE_COURSES;
256
+ payload: CourseType[];
257
+ }
258
+
259
+ interface AddCourse {
260
+ type: CoursesActionTypes.ADD_COURSE;
261
+ payload: CourseType;
262
+ }
263
+
264
+ interface DeleteCourse {
265
+ type: CoursesActionTypes.DELETE_COURSE;
266
+ payload: string;
267
+ }
268
+
269
+ type CoursesAction = SaveCourses | AddCourse | DeleteCourse;
270
+ ```
271
+
272
+ 5. It's time to write the reducer:
273
+
274
+ ```ts
275
+ const initCoursesState = [] as CourseType[];
276
+
277
+ export function coursesReducer(
278
+ state = initCoursesState,
279
+ action: CoursesAction,
280
+ ) {
281
+ switch (action.type) {
282
+ case CoursesActionTypes.SAVE_COURSES:
283
+ return action.payload;
284
+ case CoursesActionTypes.ADD_COURSE:
285
+ return [...state, action.payload];
286
+
287
+ default:
288
+ return state;
289
+ }
290
+ }
291
+ ```
292
+
293
+ ## Store
294
+
295
+ ### Function `createStore`
296
+
297
+ Now let's create store for COURSES application.
298
+
299
+ ```jsx
300
+ // store/index.js
301
+
302
+ import { createStore } from "redux";
303
+
304
+ import rootReducer from "./rootReducer";
305
+ import { coursesInitialState } from "./courses/reducer.js";
306
+
307
+ const appInitialState = {
308
+ courses: coursesInitialState,
309
+ };
310
+ const store = createStore(rootReducer, appInitialState);
311
+
312
+ export default store;
313
+ ```
314
+
315
+ The `createStore` function accept 3 arguments:
316
+
317
+ 1. `rootReducer` (we have created it early).
318
+
319
+ 2. `initialState (optional)` - Represents the initial structure of your app's state.
320
+ If you created a `rootReducer` using `combineReducers`, this must be a plain object with the same shape
321
+ as the keys passed to it. Otherwise, you are free to pass any data type that your reducer can process.
322
+
323
+ 3. The store enhancer (optional) - You have the option to specify a store enhancer to augment the store with
324
+ third-party features such as middleware, time travel, persistence, and more.
325
+ The only store enhancer that ships with Redux is [`applyMiddleware()`](https://redux.js.org/api/applymiddleware)(this function is described in the [next module](/docs/module-4/redux-thunk#how-to-add-and-configure-thunk)).
326
+
327
+ Add store to the entire COURSES application:
328
+
329
+ 1. Wrap `App` into the `Provider`
330
+ 2. Pass our store to the `Provider`
331
+
332
+ ```jsx
333
+ // src/index.js
334
+ import ReactDOM from "react-dom";
335
+
336
+ import { Provider } from "react-redux";
337
+ import store from "./store";
338
+ import App from "./App";
339
+
340
+ import "./index.css";
341
+
342
+ const root = ReactDOM.createRoot(document.getElementById("root"));
343
+
344
+ root.render(
345
+ <Provider store={store}>
346
+ <React.StrictMode>
347
+ <App />
348
+ </React.StrictMode>
349
+ </Provider>,
350
+ );
351
+ ```
352
+
353
+ ### Function `configureStore`
354
+
355
+ `configureStore` is the recommended way to create store. It is an abstraction under `createStore` function.
356
+
357
+ It helps to simplify store setup by:
358
+
359
+ 1. Utilizing an options object with "named" parameters can enhance readability and make it easier to understand when working with function arguments.
360
+ 2. By allowing you to supply arrays of middleware and enhancers to be added to the store, Redux handles the calls to `applyMiddleware` and `compose` automatically, streamlining the store configuration process.
361
+ 3. Enables the Redux DevTools Extension automatically, making it easier to debug your application's state and actions.
362
+ In addition, `configureStore` adds some middleware by default, each with a specific goal:
363
+ 4. [**Redux-thunk**](https://github.com/reduxjs/redux-thunk) is the most commonly used middleware for handling both synchronous and asynchronous logic outside of components.
364
+ 5. In development, middleware checks for common mistakes, such as state mutation or the use of non-serializable values.
365
+ This results in shorter and more readable store setup code and provides good default behavior right out of the box.
366
+ The simplest way to utilize it is by passing the root reducer function as a parameter named reducer:
367
+
368
+ ```js
369
+ import { configureStore } from "@reduxjs/toolkit";
370
+ import rootReducer from "./rootReducer";
371
+
372
+ const store = configureStore({
373
+ reducer: rootReducer,
374
+ });
375
+
376
+ export default store;
377
+ ```
378
+
379
+ ### Redux DevTools
380
+
381
+ :::info
382
+ Redux DevTools is enabled by default in case of using `configureStore` (redux/toolkit).
383
+ This upcoming section is for when using reac-redux without toolkit.
384
+ :::
385
+
386
+ ```npm
387
+ npm i redux-devtools-extension
388
+ ```
389
+
390
+ Let's look at the store with DevTools applied example.
391
+
392
+ ```jsx
393
+ // store/index.js
394
+
395
+ import { composeWithDevTools } from "redux-devtools-extension"; // import DevTools
396
+ import { createStore } from "redux";
397
+ import rootReducer from "./rootReducer";
398
+ import { coursesInitialState } from "./courses/reducer.js";
399
+
400
+ const appInitialState = {
401
+ courses: coursesInitialState,
402
+ };
403
+
404
+ const store = createStore(
405
+ rootReducer,
406
+ appInitialState,
407
+ composeWithDevTools(), //apply React DevTools enhancer
408
+ );
409
+
410
+ export default store;
411
+ ```
412
+
413
+ After this, React DevTools will have access to you web application.
414
+ Go to the Chrome DevTools and find the tab `Redux`.
415
+ ![](images/redux-dev-tools.jpg)
416
+
417
+ [Link to the Chrome Store](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd)
418
+
419
+ ## Data Flow
420
+
421
+ - Initial setup:
422
+ - A Redux store is created by using a root reducer function.
423
+ - The store invokes the root reducer once and stores the returned value as its initial state.
424
+ - When the UI is initially rendered, UI components access the current state of the Redux store and utilize that data to determine what to render on the screen. Additionally, UI components subscribe to future store updates, allowing them to detect any changes in the state and respond accordingly.
425
+ - Updates:
426
+ - Something happens in the app, such as a user add new course.
427
+ - The app code dispatches an `action` to the Redux store, like:
428
+ ```jsx
429
+ onClick((event) => dispatch(addCoursesAction(newCourse)));
430
+ ```
431
+
432
+ - The store executes the reducer function again, passing the previous `state` and the current action. It then saves the returned value as the new `state`.
433
+ - The store informs all subscribed UI components that an update has taken place in the store's state.
434
+ - Each UI component that relies on data from the store verifies if the state parts they require have undergone changes.
435
+ - Any component that detects changes in its data triggers a re-render using the new data, updating the content displayed on the screen accordingly.
436
+
437
+ Here's what that data flow looks like visually:
438
+ ![Redux data flow](./images/data-flow2.gif)
439
+
440
+ ## Materials
441
+
442
+ 1. [Redux Fundamentals: State, Actions, and Reducers.](https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers#designing-the-state-structure)
443
+ 2. [What is Redux Toolkit?](https://redux.js.org/redux-toolkit/overview)
444
+ 3. [Modern Redux with Redux Toolkit.](https://redux.js.org/tutorials/fundamentals/part-8-modern-redux)
445
+ 4. [Redux Data Flow.](https://redux.js.org/tutorials/essentials/part-3-data-flow)
@@ -0,0 +1,187 @@
1
+ ---
2
+ sidebar_position: 2
3
+ sidebar_label: 'COMPONENTS'
4
+ title: 'Components description for Tasks 4'
5
+ ---
6
+
7
+ ## App
8
+ - Use the Redux Thunk for `courses/all` and `authors/all` GET requests.
9
+ ---
10
+
11
+
12
+ ## Store
13
+ - Add a new value `role` to the initial state of user
14
+ ```js
15
+ const userInitialState = {
16
+ isAuth: '',
17
+ name: '',
18
+ email: '',
19
+ token: '',
20
+ role: '', // new value
21
+ };
22
+ ```
23
+ ---
24
+ ## Courses component
25
+ - Make a request to get current user `/users/me`. Now you have `name`, `email` and `role` values.
26
+ Save this data to the store. Use **Thunk** for it.
27
+ If you have user's data you should redirect him to the `\courses`.
28
+
29
+ :::tip
30
+ Don't forget to add header `Authorization: token`.
31
+ :::
32
+
33
+ - Button `Add new course` and route `/courses/add` **should be available only for ADMIN role**.
34
+
35
+ ---
36
+ ## Private route (new component)
37
+ ### Create [`PrivateRoute` component](/docs/module-4/private-routes).
38
+ - This component should render any component as a children.
39
+
40
+
41
+ - This component checks user's role and if it is **ADMIN** `PrivateRoute` returns
42
+ component as children otherwise redirects to `/courses`.
43
+
44
+ ---
45
+ ## Header
46
+ ### Add new functionality for the `logout` button
47
+ - When user clicks `logout` button you should make a request to logout.
48
+ ```
49
+ Swagger:
50
+ url: "/logout",
51
+ method: "DELETE".
52
+ ```
53
+
54
+ ---
55
+ ## `EmptyCourseList` component
56
+ ### Implement a new feature for `EmptyCourseList` component:
57
+ FOR ADMIN USER:
58
+ - By clicking 'ADD NEW COURSE' button user should be navigated to the route `courses/add`.
59
+
60
+ FOR NON-ADMINS (REGULAR USERS):
61
+ - Message "You don't have permissions to create a course. Please log in as ADMIN" is displayed instead of 'ADD NEW COURSE' button.
62
+ ___
63
+
64
+ ## CourseCard component
65
+ :::caution
66
+ This components has different functionality for users with different roles.
67
+ :::
68
+
69
+ *CourseCard component without ADMIN role:*
70
+ ![](images/course_card.jpg)
71
+
72
+
73
+ *CourseCard component with ADMIN role:*
74
+ ![](images/course_card_admin.jpg)
75
+
76
+ ## Course card with ADMIN role
77
+
78
+ When user has a role **ADMIN** `CourseCard` two new buttons should be displayed:
79
+ 1. `Delete course` button:
80
+ When user clicks this button - course should be deleted from back-end.
81
+ Delete this course from store after success response. Use Thunk for it.
82
+ ```
83
+ Swagger:
84
+ url: "/courses/:id",
85
+ method: "DELETE".
86
+ ```
87
+
88
+ 2. `Update course` button:
89
+ When user clicks this button **Update course** form is opened by the route `/courses/update/:courseId`.
90
+
91
+ ---
92
+ ## Add new course
93
+ ### Implement new features for CourseForm component:
94
+
95
+ - `CourseForm` should be displayed only for user with a role **ADMIN**.
96
+
97
+
98
+ - Use `PrivateRoure` for `/courses/add` route.
99
+
100
+
101
+ - When user clicks the `Create course` button:
102
+ - New course should be sent to back-end.
103
+ ```
104
+ Swagger:
105
+ url: "/courses/add",
106
+ method: "POST".
107
+ ```
108
+ - Save the response course result to the **store**.
109
+
110
+ - Navigate to the `Courses` component.
111
+
112
+ - New course should be in the courses list.
113
+
114
+
115
+ - When user clicks the `Create author` button:
116
+ - New author should be sent to back-end.
117
+ ```
118
+ Swagger:
119
+ url: "/authors/add",
120
+ method: "POST".
121
+ ```
122
+ - Save the response author result to the **store**.
123
+
124
+ - New author should be in the all authors list.
125
+
126
+
127
+ :::info
128
+ Now you do not have to generate **id** for new course and author and **creation date**.
129
+ API generates id for new course and author automatically.
130
+ :::
131
+
132
+ Models of course and author info must be as bellow:
133
+ ```js
134
+ // Course
135
+ {
136
+ title: string
137
+ description: string
138
+ duration: number
139
+ authors: [authorId]
140
+ }
141
+
142
+ // Author
143
+ {
144
+ name: string
145
+ }
146
+ ```
147
+ ---
148
+
149
+ ## Update course
150
+
151
+ ### Now you should use `CourseFrom` (old `CreateCourse`) for course creation and course updating.
152
+ When user clicks `Update` button on the `CourseCard`:
153
+
154
+ - `CourseForm` is rendered instead of the Courses component by route `/courses/update/:courseId`
155
+ (`courseId` - id of the course that should be updated).
156
+ (Use `useParams` hook to get courseId).
157
+
158
+
159
+
160
+ - All fields on the `CourseForm` page have prefilled data from opened course.
161
+
162
+
163
+ - Route `/courses/update/:courseId` should be accessible only for a role **ADMIN**.
164
+ (Use **Private route** component).
165
+
166
+
167
+ - After clicking on the `Update course` button, the course should be updated on API.
168
+ ```
169
+ Swagger:
170
+ url: "/courses/:id",
171
+ method: "PUT".
172
+ ```
173
+ A returned from API course should be added to **store** as updated course.
174
+
175
+
176
+ - When user clicks the `Create author` button:
177
+ - New author should be sent to the back-end.
178
+ ```
179
+ Swagger:
180
+ url: "/authors/add",
181
+ method: "POST".
182
+ ```
183
+ - Save the response author result to the **store**.
184
+
185
+ - New author should be in the all authors list.
186
+ ___
187
+