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,328 @@
1
+ ---
2
+ sidebar_position: 1
3
+ sidebar_label: 'What is React Router?'
4
+ title: 'A Simple React Router'
5
+ ---
6
+
7
+ ## What is React Router?
8
+
9
+ React Router is a library for routing in React. It helps users to navigate among views of
10
+ various components in a React Application and allows changing the browser URL. Basically it
11
+ means that user is able to see "different pages" of SPA changing the URL. The main feature of
12
+ React Router is that there is no need to make request to server again, everything happens on
13
+ the client side without page refreshing.
14
+
15
+ ## Installation
16
+
17
+ Run this command to install the React Router:
18
+
19
+ ```http request
20
+ npm install react-router-dom
21
+ ```
22
+
23
+ This command will add React Router to dependencies of your project.
24
+
25
+ :::tip
26
+ To install a certain version of `react-router-dom` you can add "@[version]" to the end.
27
+ For example, to install the 6th version run:
28
+ `npm install react-router-dom@6`
29
+ :::
30
+
31
+ ## Connecting React Router to App
32
+
33
+ When we are done with installation we should connect our app to the browser's URL:
34
+ import
35
+ `BrowserRouter` and wrap `App` component in it.
36
+
37
+ ```javascript
38
+ // src/index.js
39
+ import ReactDOM from 'react-dom';
40
+ import App from './App';
41
+
42
+ // add this import
43
+ import { BrowserRouter } from 'react-router-dom';
44
+
45
+ const root = ReactDOM.createRoot(
46
+ document.getElementById('root')
47
+ );
48
+
49
+ root.render(
50
+ <BrowserRouter>
51
+ <App />
52
+ </BrowserRouter>
53
+ );
54
+ ```
55
+
56
+ Now let's add some links to our application.
57
+
58
+ ## Adding Links
59
+
60
+ As you already know, we are not going to refresh our page when we navigate through pages
61
+ (components) inside our app, that's why we shouldn't use regular tag:
62
+ ```html
63
+ <a href="URL">...</a>
64
+ ```
65
+ instead, we should use special component:
66
+ ```jsx
67
+ <Link to="URL">...</Link>
68
+ ```
69
+ which is provided by `react-router-dom` library, so we can just import it and use, for
70
+ instance, inside our App component.
71
+
72
+ ```jsx
73
+ // src/component/Login/Login.jsx.jsx
74
+
75
+ import { Link } from "react-router-dom";
76
+
77
+ const Login = () => {
78
+ return (
79
+ <div>
80
+ <form>
81
+ // Login form code
82
+ </form>
83
+ <div>
84
+ <Link to="/regiscration">Registration</Link>
85
+ </div>
86
+ </div>
87
+ );
88
+ }
89
+ ```
90
+
91
+ If you click on the link 'Registration' you can see that URL changes and the page does not reload when
92
+ we navigate to the `Registration` component. So now, when we have links, it is time to create our routes
93
+ with components which will be rendered when we follow our links.
94
+
95
+ ## Adding Routes
96
+
97
+ First, let's create two components for **Login** and **Registration** page.
98
+
99
+ * src/components/Login.jsx
100
+ * src/component/Registration.jsx
101
+
102
+ Inside both pages let's add some `jsx` in order to see some difference between them:
103
+ ```jsx
104
+ // src/pages/FirstPage.jsx
105
+
106
+ import { Link } from "react-router-dom";
107
+
108
+ const Login = () => {
109
+ return (
110
+ <>
111
+ <h2>Login</h2>
112
+ <form>
113
+ // Login form code
114
+ </form>
115
+ <p>If you don't have an account you may</p>
116
+ <Link to="/registration">Registration</Link>
117
+ </>
118
+ );
119
+ }
120
+ ```
121
+
122
+ ```jsx
123
+ // src/pages/SecondPage.jsx
124
+
125
+ import { Link } from "react-router-dom";
126
+
127
+ const Registration = () => {
128
+ return (
129
+ <>
130
+ <h2>Registration</h2>
131
+ <form>
132
+ // Registration form code
133
+ </form>
134
+ <p>If you have an account you may </p>
135
+ <Link to="/registration">Login</Link>
136
+ </>
137
+ );
138
+ }
139
+ ```
140
+
141
+ Now we can add our components as Routes of our application.
142
+ For this purpose we should import `Routes` and `Route` components from "react-router-dom" library.
143
+
144
+ ```jsx
145
+ // src/App.js
146
+
147
+ import { Routes, Route } from "react-router-dom";
148
+
149
+ import { Courses } from "./components/Courses.jsx";
150
+ import { Login } from "./component/Login.jsx";
151
+ import { Registration } from "./component/Registration.jsx";
152
+
153
+ const App = () => {
154
+ return (
155
+ <Routes>
156
+ <Route path="/" element={<Courses />}/>
157
+ <Route path="/login" element={<Login />}/>
158
+ <Route path="/registration" element={<Registration />}/>
159
+ </Routes>
160
+ )
161
+ }
162
+ ```
163
+
164
+ Pay attention that **Route** components should be inside **Routes** component.
165
+ For the `element` attribute of **Route** we have to provide a component
166
+ we want to be rendered when our relative path matches with `path` attribute.
167
+
168
+ ### Previous versions of `react-router-dom`
169
+
170
+ Sometimes, on the "old" projects, you may see another version of routing. In our case it
171
+ would look like this:
172
+
173
+ ```jsx
174
+ // src/App.js
175
+
176
+ import { Route, Switch } from "react-router-dom";
177
+
178
+ import { Courses } from "./components/Courses.jsx";
179
+ import { Login } from "./component/Login.jsx";
180
+ import { Registration } from "./component/Registration.jsx";
181
+
182
+ render(
183
+ <Switch>
184
+ <Route exact path="/" children={<Courses />} />
185
+ <Route path="/login" children={<Login />} />
186
+ <Route path="/registration" children={<Registration />} />
187
+ </Switch>
188
+ );
189
+ ```
190
+
191
+ This is the older version of `react-router-dom`.
192
+ **Pay attention that this code will not work with `react-router-dom` v6. **So if you want
193
+ to try this, don't forget to install `react-router-dom` version 5.
194
+ You can find additional information here:
195
+ [Simple React Router v4 Tutorial](https://blog.pshrmn.com/simple-react-router-v4-tutorial/)
196
+
197
+ :::info
198
+ You may also create routes by using the [useRoutes()](./hooks.md#useroutes) hook, which we'll cover in the [React Router Hooks](./hooks.md) section.
199
+ :::
200
+
201
+ ## Path Params
202
+
203
+ Sometimes you need to get information from the URL to render a specific page.
204
+ You can retract the information by using
205
+ `path params`, and pass that information from the URL to the page.
206
+
207
+ To see how it works let's do the following steps:
208
+
209
+ 1. Create new component. In our example it will be `CourseInfo`.
210
+
211
+ ```jsx
212
+ // src/component/CourseInfo.jsx
213
+
214
+ const CourseInfo = () => {
215
+ return <h2>Course id that came from URL is ???</h2>;
216
+ }
217
+ ```
218
+ And we want to show some course id on the page instead of `???`.
219
+
220
+ 2. Now we have to add course item inside `Courses` component.
221
+ ```jsx
222
+ // src/component/Courses.jsx
223
+
224
+ import { Link } from "react-router-dom";
225
+
226
+ const Courses = () => {
227
+ return (
228
+ <>
229
+ <p>React course</p>
230
+ <Link to={`/courses/${id}`}>SHOW COURSE</Link>
231
+ </>
232
+ );
233
+ }
234
+ ```
235
+ You can see that currently we don't have pages for routes `/courses/:courseId`. For this purposes we
236
+ should do this step next.
237
+
238
+ 3. Creating new `Route` with URL param `:courseId`.
239
+
240
+ ```jsx
241
+ // src/App.js
242
+
243
+ import { Routes, Route } from "react-router-dom";
244
+
245
+ import { Courses } from "./components/Courses.jsx";
246
+ import { Login } from "./component/Login.jsx";
247
+ import { Registration } from "./component/Registration.jsx";
248
+ import { CourseInfo } from "./compoments/CourseInfo.jsx";
249
+
250
+ render(
251
+ <Switch>
252
+ <Route exact path="/" children={<Courses />} />
253
+ <Route path="/login" children={<Login />} />
254
+ <Route path="/registration" children={<Registration />} />
255
+ <Route path='/courses/:courseId' element={<CourseInfo/>}/>
256
+ </Switch>
257
+ );
258
+ ```
259
+ This `:courseId` construction means that this URL will match any URL like `courses/id1`, or
260
+ `courses/id2`.
261
+
262
+ 5. And the last step is passing this param to our `CourseInfo`. For this purpose we should import
263
+ `useParams` hook from `react-router-dom` and use it like this:
264
+
265
+ ```jsx
266
+ // src/component/CourseInfo.jsx
267
+
268
+ import { useParams } from "react-router-dom";
269
+
270
+ const CourseInfo = () => {
271
+ const params = useParams();
272
+
273
+ return <h2>Course id that came from URL is {params.courseId}</h2>;
274
+ }
275
+ ```
276
+ :::caution
277
+ **courseId** should be the same key as we're passing `courseId` in our route in the `App` component.
278
+ :::
279
+
280
+ And if we click on `SHOW COURSE`, we can see page with `CourseInfo` component and selected id.
281
+
282
+ ## Redirect
283
+
284
+ Also, there is a possibility to redirect user from some, for instance, non-existing URL. To do that
285
+ we should create such construction.
286
+ ```jsx
287
+ <Route
288
+ path="*"
289
+ element={<Navigate to="/" />}
290
+ />
291
+ ```
292
+ :::caution
293
+ Don't forget to import `Navigate` component from `react-router-dom`.
294
+ :::
295
+
296
+ This will redirect user from all non-existing URLs to the one stated in the element attribute.
297
+ `*` element means that if all routes above didn't match, this path will be used for the address.
298
+ So if we use this construction in our application, all our attempts to visit for instance URL `localhost:3000/hello` will navigate us back to
299
+ `localhost:3000/`:
300
+
301
+ ```jsx
302
+ // src/App.jsx
303
+
304
+ import { Routes, Route, Navigate } from "react-router-dom";
305
+
306
+ import { Courses } from "./components/Courses.jsx";
307
+ import { Login } from "./component/Login.jsx";
308
+ import { Registration } from "./component/Registration.jsx";
309
+ import { CourseInfo } from "./compoments/CourseInfo.jsx";
310
+
311
+ render(
312
+ <Switch>
313
+ <Route exact path="/" children={<Courses />} />
314
+ <Route path="/login" children={<Login />} />
315
+ <Route path="/registration" children={<Registration />} />
316
+ <Route path='/courses/:courseId' element={<CourseInfo/>}/>
317
+ <Route path="*" element={<Navigate to="/" />}/>
318
+ </Switch>
319
+ );
320
+ ```
321
+
322
+ ## Conclusion
323
+ That's it. Congratulations! We have covered all basic topics and successfully implemented navigation
324
+ in our simple React application using `React Router`.
325
+
326
+ ---
327
+ ## Materials
328
+ 1. [Official React Router documentation. Tutorial](https://reactrouter.com/en/6.18.0/start/tutorial)
@@ -0,0 +1,94 @@
1
+ ---
2
+ sidebar_position: 2
3
+ sidebar_label: "COMPONENTS"
4
+ title: Components description for Tasks 3
5
+ ---
6
+
7
+ ## App component
8
+
9
+ 1. Use [configureStore](https://redux-toolkit.js.org/api/configureStore) function to create store.
10
+ 2. Import store to the `index.js`.
11
+ 3. Wrap `App` component in the [Provider](https://react-redux.js.org/tutorials/quick-start#provide-the-redux-store-to-react).
12
+ 4. Pass `store` to the `Provider`.
13
+
14
+ Now all components have access to the store, and you can use `Redux Hooks`.
15
+
16
+ :::tip
17
+ [Reading State from the Store with `useSelector`](https://redux.js.org/tutorials/fundamentals/part-5-ui-react#reading-state-from-the-store-with-useselector)
18
+ [Dispatch actions using `useDispatch`](https://react-redux.js.org/api/hooks#usedispatch)
19
+ :::
20
+
21
+ ---
22
+
23
+ ## Courses component
24
+
25
+ ### Implement new feature for Courses component:
26
+
27
+ - Get courses data from the back-end. See SWAGGER `/courses/all` API.
28
+
29
+ - Get authors data from the back-end. See SWAGGER `/authors/all` API.
30
+
31
+ - Save courses and authors responses' results to the store.
32
+
33
+ - Courses list should be rendered based on the data from the `courses` and `authors` properties in the **store**.
34
+
35
+ :::tip
36
+
37
+ See example [How to create your first reducer](/docs/module-3/state-actions-reducers)
38
+ :::
39
+
40
+ ---
41
+
42
+ ## CourseCard component
43
+
44
+ ![](images/course_card_admin.jpg)
45
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2905-67147&t=2XuYekWUy7fL4Ba9-0)
46
+
47
+ ### Implement new features for CourseCard component:
48
+
49
+ - Update `CourseCard` component by adding two buttons: `Delete` and `Update`.
50
+ (These buttons should be reusable component `Button`).
51
+
52
+ - When user clicks the `Delete` button current course should be removed from the
53
+ store and new courses list should be rendered.
54
+
55
+ - `Update` button has **NO functionality in this module**.
56
+ It will be added in the next module.
57
+
58
+ ---
59
+
60
+ ## Add new course
61
+
62
+ ### Implement new features for CreateCourse component:
63
+
64
+ - When user clicks `Create author` button the new author should be saved to the store.
65
+
66
+ - When user clicks `Create course` button the new course should be saved to the store.
67
+
68
+ ---
69
+
70
+ ## Login component
71
+
72
+ ### Implement new features for Login component:
73
+
74
+ - Save information (name, token, email) from response to the store.
75
+
76
+ - Save token to the `localStorage` after success login.
77
+
78
+ ---
79
+
80
+ :::caution
81
+ If we have a token in the `localStorage` the user should be immediately redirected to the Courses page when opening the application.
82
+ :::
83
+
84
+ ## Header
85
+
86
+ ### Implement new features for Header component:
87
+
88
+ - Take information about user from the store.
89
+
90
+ - When user clicks `LOGOUT` button you should dispatch action to the store.
91
+
92
+ - Delete token from the `localStorage` after logout.
93
+
94
+ ---
@@ -0,0 +1,26 @@
1
+ ---
2
+ sidebar_position: 3
3
+ sidebar_label: 'GOOD PRACTICES'
4
+ title: GOOD PRACTICES
5
+ ---
6
+
7
+ # GOOD PRACTICES THAT YOU CAN APPLY FOR THIS TASK:
8
+ 1. Use `Redux DevTools` extension for Chrome browser to see store changes in the browser.
9
+
10
+
11
+ 2. Use separate `selectors.js` file for `useSelector` callbacks. For example:
12
+ ```js
13
+ // BAD
14
+
15
+ // Courses.jsx
16
+ const courses = useSelector(state => state.courses);
17
+
18
+
19
+ // GOOD
20
+
21
+ // selectors.js
22
+ export const getCourses = state => state.courses;
23
+
24
+ // Courses.jsx
25
+ const courses = useSelector(getCourses);
26
+ ```
@@ -0,0 +1,170 @@
1
+ ---
2
+ sidebar_position: 1
3
+ sidebar_label: 'TASK'
4
+ title: 'Module 3. State Management'
5
+ ---
6
+ This is the third part of the application.
7
+ In this assignment,
8
+ you should continue to work on your project with a slight modification.
9
+ This module is designed to teach how to work with state management in React and what is Redux.
10
+
11
+ ## Prerequisite:
12
+ Firstly, you need to install the [Redux Toolkit](https://redux-toolkit.js.org/introduction/getting-started) and React-redux modules in your project using npm:
13
+
14
+ 1. Go to your project directory
15
+
16
+
17
+ 2. Install redux and react-redux
18
+ ```http request
19
+ npm i @reduxjs/toolkit react-redux --save
20
+ ```
21
+
22
+ 3. Run your project
23
+ ```http request
24
+ npm run start
25
+ ```
26
+
27
+ ## Project structure requirements:
28
+
29
+ 1. Create new folders where put the code for redux `src/store`.
30
+
31
+
32
+ 2. Create new file `services.js / .ts`.
33
+
34
+
35
+ 3. Folder structure `src/store`:
36
+ ```
37
+ src
38
+ |-- store
39
+ | |-- index.js/.ts // Add store creation
40
+ | |
41
+ | |-- rootReducer.js/.ts // combine your reducers here
42
+ | |
43
+ | |
44
+ | |-- user
45
+ | | |-- reducer.js // Code with reducer for user
46
+ | | |-- actions.js // Code with actions
47
+ | | |__ types.js // Code with action types
48
+ | |
49
+ | |-- courses
50
+ | | |-- reducer.js // Code with reducer for courses
51
+ | | |-- actions.js // Code with actions
52
+ | | |__ types.js // Code with action types
53
+ | |
54
+ | |__ authors
55
+ | |-- reducer.js // Code with reducer for user
56
+ | |-- actions.js // Code with actions
57
+ | |__ types.js // Code with action types
58
+ |
59
+ |-- services.js
60
+ |
61
+ |__ ...
62
+ ```
63
+
64
+ 4. Delete `mockedCoursesList` and `mockedAuthorsList`.
65
+
66
+ 5. Store should have model where `user`, `authors` and `courses` should have own reducer:
67
+ ```javascript
68
+ const store = {
69
+ user: {
70
+ isAuth: boolean, // default value - false. After success login - true
71
+ name: string, // default value - empty string. After success login - name of user
72
+ email: string, // default value - empty string. After success login - email of user
73
+ token: string, // default value - empty string or token value from localStorage. After success login - value from API /login response. See Swagger.
74
+ },
75
+ courses: [], // list of courses. Default value - empty array. After success getting courses - value from API /courses/all response. See Swagger.
76
+ authors: [] // list of authors. Default value - empty array. After success getting authors - value from API /authors/all response. See Swagger.
77
+ }
78
+ ```
79
+
80
+ 6. APIs from SWAGGER for Module 3:
81
+ - `courses/all`[GET];
82
+ - `authors/all`[GET].
83
+
84
+ ## Criteria (35 points max)
85
+
86
+ ### APIs
87
+
88
+ * [2 points] - All functionality with back-end should be in `services.js`.
89
+ (Create **api service** for each endpoint that you use and call methods or functions from service into your components)
90
+
91
+
92
+ * [2 points] - Get courses from back-end. See API `/courses/all` in the SWAGGER. Save courses list to the store.
93
+
94
+
95
+ * [2 points] - Get authors from back-end. See API `/authors/all` in the SWAGGER. Save authors list to the store.
96
+
97
+
98
+ ### Store
99
+ * [3 points] - Store should have **User** reducer.
100
+ **User** reducer manage data with user's info and should have next model:
101
+ ```js
102
+ const userInitialState = {
103
+ isAuth: boolean, // default value - false. After success login - true
104
+ name: string, // default value - empty string. After success login - name of user
105
+ email: string, // default value - empty string. After success login - email of user
106
+ token: string, // default value - empty string or token value from localStorage.
107
+ // After success login - value from API /login response. See Swagger.
108
+ };
109
+ ```
110
+ **User** reducer has logic:
111
+ - After success login `isAuth` property has value `true`, save token, email and name.
112
+ - After logout `isAuth` property has value `false`, token, email and name have value as empty string.
113
+
114
+
115
+ * [3 point] - Store should have **Courses** reducer.
116
+ **Courses** reducer manage data with courses list and should have next model:
117
+ ```js
118
+ const coursesInitialState = [] // default value - empty array. After success getting courses from API - array of courses.
119
+ ```
120
+ **Courses** reducer has logic:
121
+ - Get courses. Save courses to the **store** after getting them from API. See Swagger `/courses/all`.
122
+ - Save new course.
123
+ - Delete course.
124
+ - Update course (we will use this action in the next task).
125
+
126
+
127
+ * [3 point] - Store should have **Authors** reducer.
128
+ **Authors** reducer manage data with authors list and should have the next model:
129
+ ```js
130
+ const authorsInitialState = [] // default value - empty array. After success getting authors from API - array of authors.
131
+ ```
132
+ **Authors** reducer has logic:
133
+ - Save a new author.
134
+ - Get authors. Save authors to **store** after getting them from API. See Swagger `/authors/all` .
135
+
136
+
137
+ ### Login Component
138
+ * [2 point] - Save user's info to the store after success login.
139
+
140
+
141
+ ### Header Component
142
+ * [1 point] - Get user's name from the store.
143
+
144
+ * [2 point] - Dispatch REMOVE_USER action by `LOGOUT` button click.
145
+
146
+
147
+ ### Courses Component
148
+ * [3 point] - Get courses from the store and render them into **Courses** component.
149
+
150
+ * [3 points] - If token is present in the localStorage the user should be immediately redirected to the `Courses` page when opening the application.
151
+
152
+ ### CreateCourse Component
153
+ * [2 points] - After saving course in **CreateCourse** component course should be added to **store**.
154
+
155
+ * [2 point] - Get authors from the store.
156
+
157
+ * [1 point] - Save new authors to the store.
158
+
159
+
160
+ ### CourseCard Component
161
+ * [2 point] - Add a new button "Delete course" into CourseCard.
162
+
163
+ * [1 point] - Add a new button "Update course" into CourseCard *(**CourseCard** in COMPONENTS)*.
164
+
165
+ * [1 point] - After clicking on the `Delete course` button a selected course should be deleted from the **store**.
166
+
167
+
168
+ :::info
169
+ Please find detailed description of components and functionality in the [COMPONENTS](components) section.
170
+ :::
@@ -0,0 +1,54 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { MemoryRouter } from "react-router-dom";
4
+ import App from "../App";
5
+
6
+ describe("App", () => {
7
+ test("renders Login component when token is not present", () => {
8
+ localStorage.removeItem("token");
9
+ render(
10
+ <MemoryRouter initialEntries={["/"]}>
11
+ <App />
12
+ </MemoryRouter>
13
+ );
14
+
15
+ expect(
16
+ screen.getByText(/If you don't have an account you can/)
17
+ ).toBeInTheDocument();
18
+ });
19
+
20
+ test("renders Courses component when token is present", () => {
21
+ localStorage.setItem("token", "token");
22
+ render(
23
+ <MemoryRouter initialEntries={["/"]}>
24
+ <App />
25
+ </MemoryRouter>
26
+ );
27
+
28
+ const courseElements = screen.getAllByTestId("courseCard");
29
+
30
+ expect(courseElements[0]).toBeInTheDocument();
31
+ });
32
+
33
+ test("renders Registration component", () => {
34
+ render(
35
+ <MemoryRouter initialEntries={["/registration"]}>
36
+ <App />
37
+ </MemoryRouter>
38
+ );
39
+
40
+ expect(screen.getByLabelText("name")).toBeInTheDocument();
41
+ expect(screen.getByLabelText("email")).toBeInTheDocument();
42
+ expect(screen.getByLabelText("password")).toBeInTheDocument();
43
+ });
44
+
45
+ test("renders course add component", () => {
46
+ render(
47
+ <MemoryRouter initialEntries={["/courses/add"]}>
48
+ <App />
49
+ </MemoryRouter>
50
+ );
51
+
52
+ expect(screen.getByTestId("titleInput")).toBeInTheDocument();
53
+ });
54
+ });