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,257 @@
1
+ ---
2
+ sidebar_position: 2
3
+ sidebar_label: "COMPONENTS"
4
+ title: Components description for Tasks 1
5
+ ---
6
+
7
+ :::tip
8
+ **You need just follow from one step to another.**
9
+ The description was created in such a way
10
+ that you do not need to navigate through the document at random.
11
+ :::
12
+
13
+ :::info
14
+ You can watch [this (link)](https://www.youtube.com/watch?v=Cla1WwguArA) 7 minutes tutorial video about components creation 😉
15
+ :::
16
+
17
+ ## Header
18
+
19
+ ![](images/header.png)
20
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2905-67147&t=2XuYekWUy7fL4Ba9-0)
21
+
22
+ ### Create `Logo` component.
23
+
24
+ Logo component contains only logo picture (you can use any picture, you like).
25
+
26
+ :::info
27
+ Logo component is just a function component which returns `img` tag.
28
+ :::
29
+
30
+ :::tip
31
+ If you use TypeScript and have this error
32
+ ![](images/ts_images_errorjpg.jpg)
33
+ Try to find solution [here](https://stackoverflow.com/questions/52759220/importing-images-in-typescript-react-cannot-find-module)
34
+ :::
35
+
36
+ ### Create `Button` component.
37
+
38
+ Button component is a function component which returns `button` tag.
39
+
40
+ :::tip
41
+ You will use Button component in several places through your app,
42
+ so you should use `props` for this component such as `buttonText` and `onClick`
43
+ (and any props, that you want).
44
+
45
+ If you want to repeat how to work with `props` you can:
46
+ ⭐ read theoretical material again [(link)](/docs/module-1/components-and-props);
47
+ ⭐ watch this tutorial [(link)](https://www.youtube.com/watch?v=m7OWXtbiXX8&list=RDCMUC80PWRj_ZU8Zu0HSMNVwKWw&index=3).
48
+ :::
49
+
50
+ ### Create `Header` component.
51
+
52
+ Header should be in `App` component.
53
+
54
+ `Header` component should include:
55
+
56
+ - `Logo` component;
57
+
58
+ - Logout button (`Button` component **WITHOUT** any functionality for the current task).
59
+
60
+ [Small demo](../components-and-props#how-to-create-a-simple-function-component)
61
+
62
+ ---
63
+
64
+ ## Courses
65
+
66
+ ### Create `CourseCard` component.
67
+
68
+ ![](images/course_card.jpg)
69
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2905-67147&t=GislgRTjkGsyZ4Xy-0)
70
+
71
+ This component contains all info about the course.
72
+
73
+ For the current task you should use `mockedCoursesList` array for courses info.
74
+
75
+ `CourseCard` components should be rendered in `Courses` component (you will create it in the next step).
76
+
77
+ `CourseCard` component should contain the following information:
78
+
79
+ 1. Title (Course name);
80
+
81
+ 2. Duration (format: hh:mm + 'hours'). In the `mockedCoursesList` duration is specified in minutes;
82
+
83
+ :::info
84
+ If `hh` < 10 (0,1,2,3,4,5,6,7,8,9) => '0' + h:mm + 'hours' (02:20 hours)
85
+ If `mm` < 10 (0,1,2,3,4,5,6,7,8,9) => hh:'0' + m + 'hours' (10:06 hours)
86
+ If `hh` = 1 => hh:mm + 'hour' (01:30 hour)
87
+ :::
88
+
89
+ 3. Creation date (format: dd.mm.yyyy);
90
+
91
+ 4. Description;
92
+
93
+ 5. `Show course` button.
94
+ When user clicks `Show course` button `CourseInfo` component with current course info should replace `Courses` component.
95
+ (You will create it after `Courses` component).
96
+
97
+ 6. `Authors` list:
98
+ - the authors' names should be displayed on the one line;
99
+
100
+ - if all authors' names do not fit on one line,
101
+ then the extra text should be cut off and '...' should be added at the end of line.
102
+
103
+ :::caution
104
+ In `mockedCoursesList` each course has only authors' `ids`.
105
+ To define authors' names you should find them in `mockedAuthorsList` by id.
106
+ :::
107
+
108
+ ### Mocked courses and authors data.
109
+
110
+ Save these data as constants and use in your App:
111
+
112
+ ```js
113
+ export const mockedCoursesList = [
114
+ {
115
+ id: "de5aaa59-90f5-4dbc-b8a9-aaf205c551ba",
116
+ title: "JavaScript",
117
+ description: `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
118
+ has been the industry's standard dummy text ever since the 1500s, when an unknown
119
+ printer took a galley of type and scrambled it to make a type specimen book. It has survived
120
+ not only five centuries, but also the leap into electronic typesetting, remaining essentially u
121
+ nchanged.`,
122
+ creationDate: "08/03/2021",
123
+ duration: 160,
124
+ authors: [
125
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
126
+ "f762978b-61eb-4096-812b-ebde22838167",
127
+ ],
128
+ },
129
+ {
130
+ id: "b5630fdd-7bf7-4d39-b75a-2b5906fd0916",
131
+ title: "Angular",
132
+ description: `Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
133
+ has been the industry's standard dummy text ever since the 1500s, when an unknown
134
+ printer took a galley of type and scrambled it to make a type specimen book.`,
135
+ creationDate: "10/11/2020",
136
+ duration: 210,
137
+ authors: [
138
+ "df32994e-b23d-497c-9e4d-84e4dc02882f",
139
+ "095a1817-d45b-4ed7-9cf7-b2417bcbf748",
140
+ ],
141
+ },
142
+ ];
143
+
144
+ export const mockedAuthorsList = [
145
+ {
146
+ id: "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
147
+ name: "Vasiliy Dobkin",
148
+ },
149
+ {
150
+ id: "f762978b-61eb-4096-812b-ebde22838167",
151
+ name: "Nicolas Kim",
152
+ },
153
+ {
154
+ id: "df32994e-b23d-497c-9e4d-84e4dc02882f",
155
+ name: "Anna Sidorenko",
156
+ },
157
+ {
158
+ id: "095a1817-d45b-4ed7-9cf7-b2417bcbf748",
159
+ name: "Valentina Larina",
160
+ },
161
+ ];
162
+ ```
163
+
164
+ ### `EmptyCourseList` component
165
+
166
+ ![](images/emptyCourseList.jpg)
167
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2906-66989&t=GislgRTjkGsyZ4Xy-0)
168
+
169
+ `EmptyCourseList` component should be rendered instead of `Courses` components when
170
+ we do not have any course.
171
+
172
+ `EmptyCourseList` component should include:
173
+
174
+ - Title with text: 'Course List is Empty'.
175
+
176
+ - Subtitle text: 'Please use "Add New Course" button to add your first course'.
177
+
178
+ - `Add New Course` button **WITHOUT** functionality for current task. (Reuse `Button` Component).
179
+
180
+ ### Create `Courses` component.
181
+
182
+ ![](images/courses_component.jpg)
183
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2907-67422&t=2XuYekWUy7fL4Ba9-0)
184
+
185
+ `Courses` component should be rendered in `App` component.
186
+
187
+ `Courses` component should include:
188
+
189
+ - `SearchBar` component (optional extra task).
190
+
191
+ - `CourseCard` component.
192
+
193
+ - `Add new course` button WITHOUT any functionality. (Reuse `Button` component).
194
+
195
+ :::tip
196
+ You should import `mockedCoursesList` and `mockedAuthorsList` to the `App` component and pass it to the `Courses` component as a prop.
197
+ Use loop for `CourseCard` rendering.
198
+ Please, follow [this link](https://react.dev/learn/rendering-lists#rendering-data-from-arrays) to the **"Embedding map() in JSX"** topic to see the example.
199
+ :::
200
+
201
+ ---
202
+
203
+ ## Course info
204
+
205
+ ![](images/course_info.jpg)
206
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=6130-322&t=2XuYekWUy7fL4Ba9-0)
207
+
208
+ - This component shows information about the course.
209
+
210
+ - This component contains:
211
+ - ID of course;
212
+ - Title;
213
+ - Description;
214
+ - Duration;
215
+ - List of authors;
216
+ - Creation date;
217
+ - `Back to courses` button.
218
+
219
+ - This component should be rendered instead of `Courses` component.
220
+
221
+ - Pass course information to the `CourseInfo` component using `props`.
222
+
223
+ - By clicking `Back` button `CourseInfo` component should be replaced by `Courses` component.
224
+
225
+ ---
226
+
227
+ ## Search. Extra Task
228
+
229
+ ![](images/search_field.jpg)
230
+ [Figma link](https://www.figma.com/design/9MsU97rn21GuQIT01xwLuc/React-Fundamentals-Course?node-id=2905-67147&t=2XuYekWUy7fL4Ba9-0)
231
+
232
+ ### Create `SearchBar` component.
233
+
234
+ `SearchBar` should be in Courses component (above the list of courses).
235
+
236
+ `SearchBar` component should include:
237
+
238
+ - `Input` component;
239
+
240
+ - `Button` component.
241
+
242
+ #### Add functionality for searching courses:
243
+
244
+ - User should have ability to search course by **title** and **id**;
245
+
246
+ - The search is performed by the occurrence of characters in the string,
247
+ and **not just by a match at the beginning of the string**;
248
+
249
+ - **Case-insensitive** search;
250
+
251
+ - When user clicks on `Search` button it displays all courses that match the search query;
252
+
253
+ - All courses are displayed when user cleans search field.
254
+
255
+ <sub>(Search by title example)</sub>
256
+
257
+ ![](images/course_search.jpg)
@@ -0,0 +1,69 @@
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. Place `css` files in the folder with the component.
9
+
10
+ Example:
11
+ ```
12
+ src
13
+ |
14
+ |- components
15
+ |
16
+ |-Header
17
+ |-Header.jsx //component
18
+ |-header.css //styles for this component
19
+
20
+ ```
21
+ 2. Use `label` tag for input. [Link to the W3C.](https://www.w3schools.com/tags/tag_label.asp)
22
+
23
+
24
+ 3. Use `key` attribute for list rendering. [Link to the documentation.](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key)
25
+
26
+
27
+ 4. Use constants to avoid a hardcode. *For example, when passing string properties to a component:*
28
+ ```js
29
+ // BAD
30
+ <Button text='Search' />
31
+
32
+
33
+ // GOOD
34
+ //constants.js
35
+ const BUTTON_TEXT = 'Search';
36
+
37
+ //Button.jsx
38
+ import {BUTTON_TEXT} from './constants.js';
39
+
40
+ <Button text={BUTTON_TEXT} />
41
+ ```
42
+
43
+ 5. Add empty string between import groups. *Example:*
44
+ ```js
45
+ import from '[node_modules]'
46
+
47
+ import from '[own_components]'
48
+ import from '[constants]'
49
+
50
+ import from '[styles]'
51
+ ```
52
+
53
+ 6. Use common `index.js` file for components and helpers. [Link to the article](https://www.digitalocean.com/community/tutorials/react-index-js-public-interfaces).
54
+
55
+
56
+ 7. If component does not have any logic you can return the markup immediately. *Examples:*
57
+ ```js
58
+ import logo from '../../assets/logo.jpg';
59
+
60
+ export const Logo = () => <img src={logo} />;
61
+ ```
62
+
63
+ or
64
+
65
+ ```js
66
+ export const Button = ({ text, onClick }) => (
67
+ <button onClick={onClick}>{text}</button>
68
+ );
69
+ ```
@@ -0,0 +1,253 @@
1
+ ---
2
+ sidebar_position: 1
3
+ sidebar_label: 'TASK'
4
+ title: 'Module 1. React Components'
5
+ ---
6
+
7
+ Hello friend!
8
+ Let me say a few words what we are going to do with you.
9
+ We will write a small React application that allows users to manage a list of courses
10
+ with features like creating, deleting, and viewing course information.
11
+ Additionally, the application will have authorization functionality to ensure
12
+ secure access to the application's features.
13
+
14
+ The main goal of this task is to create app skeleton - set of
15
+ some simple components for the app.
16
+
17
+ Please, follow next steps:
18
+
19
+ ## Steps:
20
+
21
+ 1. Generate a new project:
22
+
23
+ ```http request
24
+ npx create-react-app courses-app
25
+ ```
26
+
27
+ :::note
28
+ You can use `git bash` to run the command.
29
+
30
+
31
+ `courses-app` is a name of the project. You can give any name you want.
32
+ :::
33
+
34
+ 2. Open you new project via code editor.
35
+
36
+
37
+ 3. Configure `eslint` and `prettier`.
38
+ See instruction in the [ESLINT instruction](eslint).
39
+
40
+
41
+ 4. Configure `pre-commit hook`.
42
+ See instruction in the [PRE COMMIT instruction](pre_commit).
43
+
44
+
45
+ 5. Run your project.
46
+ ```http request
47
+ npm run start
48
+ ```
49
+
50
+ Result in the browser:
51
+ ![](images/initial_react_view.jpg)
52
+
53
+ :::tip
54
+ Now it's good time to push your INITIAL COMMIT to the repo and create a new branch for the first module.
55
+ :::
56
+
57
+
58
+ ## Project structure requirements
59
+
60
+ 1. You should use **function** components for your app.
61
+
62
+
63
+ 2. Rename `App.js` to `App.jsx` / `App.tsx`. `App` - main app file.
64
+
65
+
66
+ 3. Delete unnecessary files:
67
+ - `src/App.test.js`
68
+ - `src/logo.svg`
69
+ - `src/reportWebVitals.js`
70
+ - all files in the `public` folder EXCEPT `public/index.html` and `manifest.json`
71
+
72
+ 4. Delete default code in files:
73
+
74
+ - `scr/App`
75
+ - `src/App.css`
76
+
77
+ You can do like this:
78
+ ```js
79
+ function App() {
80
+ return <div>React</div>;
81
+ }
82
+
83
+ export default App;
84
+ ```
85
+
86
+ Delete unnecessary import and function call in the `index.js` file
87
+ ```js
88
+ import reportWebVitals from './reportWebVitals';
89
+ ...
90
+ reportWebVitals();
91
+ ```
92
+
93
+ Result in the browser:
94
+ ![](images/initial_view_localhost.jpg)
95
+
96
+ :::tip
97
+ If you use `App.tsx` you need to fix its import in the `index.js` file
98
+ ```js
99
+ import App from './App.tsx';
100
+ ```
101
+ :::
102
+
103
+ 5. Create folders and files for each component. Follow the architecture below:
104
+
105
+ ```
106
+ src
107
+ |-- common
108
+ | |--Button
109
+ | | |__ Button.jsx/.tsx
110
+ | |
111
+ | |__Input
112
+ | | |__ Input.jsx/.tsx
113
+ | | |
114
+ | |__ //any common components you want to add
115
+ |
116
+ |-- components
117
+ | |-- CourseInfo
118
+ | | |__ CourseInfo.jsx/.tsx
119
+ | |
120
+ | |-- Courses
121
+ | | |__ components
122
+ | | |__ CourseCard
123
+ | | |__ CourseCard.jsx/.tsx
124
+ | | |__ SearchBar (extra task)
125
+ | | | |__ SearchBar.jsx/.tsx
126
+ | | |__ Courses.jsx/.tsx
127
+ | |
128
+ | |__ // any components you want to add
129
+ | |
130
+ | |-- EmptyCourseList
131
+ | | |__ EmptyCourseList.jsx/.tsx
132
+ | |
133
+ | |-- Header
134
+ | | |__ Header.jsx/.tsx
135
+ | | |__ components
136
+ | | |__ Logo
137
+ | | |__ Logo.jsx/.tsx
138
+ |
139
+ |-- helpers
140
+ | |
141
+ | |--getCourseDuration.js/.ts // a helper to format course duration
142
+ | |
143
+ | |--formatCreationDate.js/.ts // to format date that we will receive from server
144
+ | |
145
+ | |__ // any helpers you want to add
146
+ |
147
+ |-- constants.js/.ts // file with mocked data
148
+ |
149
+ |-- App.jsx/.tsx
150
+ |-- App.css
151
+ |-- index.js
152
+ |_ ...
153
+
154
+ ```
155
+
156
+ :::caution
157
+ The presented architecture is required for use, BUT you can add files and folders at your discretion.
158
+ :::
159
+
160
+ 7. You can use any way to add styles to components (styled components, Bootstrap, CSS modules etc). Also, you can use preprocessors like SASS [instruction.](https://create-react-app.dev/docs/adding-a-sass-stylesheet/)
161
+
162
+ :::tip
163
+ It's recommended to keep each component's style file in their appropriate folders.
164
+ :::
165
+
166
+ 8. You can choose the design at your discretion.
167
+ **It is important to keep the layout** (the arrangement of elements on the page).
168
+
169
+
170
+ ![](images/initial_view.jpg)
171
+ **App initial view**
172
+
173
+ ## Final preparations:
174
+ 1. Support browsers: Google Chrome.
175
+ 2. Type checking: you can use TypeScript (it's not required but recommended).
176
+
177
+ Please, read requirements for the first task. To find the full description of each criteria please go to
178
+ the [COMPONENTS page.](components)
179
+
180
+ ## Criteria (30 points max)
181
+
182
+ ### Common
183
+
184
+ * [1 point] - The architecture of the application **should be** the same as presented above.
185
+
186
+
187
+ * [1 point] - Components are presented as [**function components**](https://react.dev/reference/react/Component) (not class components).
188
+
189
+
190
+ * [1 point] - Use `.jsx` extensions for files with [`jsx` syntax](https://react.dev/learn/writing-markup-with-jsx).
191
+
192
+
193
+ * [1 point] - All inputs and buttons should be reusable components.
194
+
195
+
196
+ * [2 points] - `eslint`, `prettier` and `pre-commit hook` work correctly.
197
+
198
+ ### [Header component](/docs/module-1/home-task/components#header)
199
+ * [3 points] - Should display `Header` component with:
200
+ * `Logo` (any appropriate image)
201
+ * `Logout` button (without functionality)
202
+
203
+ ### [CourseCard component](/docs/module-1/home-task/components#create-coursecard-component)
204
+ * [5 points] - Should display `CourseCard` component with:
205
+ * course title;
206
+ * course description;
207
+ * authors list;
208
+ * course duration;
209
+ * creation date;
210
+ * `Show course` button.
211
+
212
+ * [2 point] Show `CourseInfo` component with current course information by clicking `Show course` button.
213
+
214
+ ### [EmptyCourseList component](/docs/module-1/home-task/components#emptycourselist-component)
215
+
216
+ * [2 points] - Show `EmptyCourseList` component when no courses.
217
+
218
+ * [2 point] - Component Should contain:
219
+ * title 'Your List Is Empty';
220
+ * subtitle 'Please use "Add New Course" button to add your first course'.
221
+ * `Add New Course` button (without functionality for current task).
222
+
223
+ ### [Courses component](/docs/module-1/home-task/components#courses)
224
+ * [2 points] - Show list of courses (use [mocked course list](/docs/module-1/home-task/components#mocked-courses-and-authors-data) for this task).
225
+
226
+ * [1 point] - Show `Add new course` button (without functionality for current task).
227
+
228
+
229
+ ### [CourseInfo Component](/docs/module-1/home-task/components#course-info)
230
+
231
+ * [5 points] - Create component that contains:
232
+ * course title
233
+ * course description
234
+ * course ID
235
+ * course duration
236
+ * creation date
237
+ * course authors
238
+ * `Back` button
239
+
240
+ * [2 point] - By clicking `Back` button `CourseInfo` component should be replaced by `Courses` component.
241
+
242
+ ## Extra Task
243
+ ### [Searching](/docs/module-1/home-task/components#search-extra-task)
244
+ * Implement searching functionality by title. Reset search result when searchbar is empty.
245
+
246
+
247
+ * Implement searching functionality by id. Reset search result when searchbar is empty.
248
+
249
+ [Full description](/docs/module-1/home-task/components#search-extra-task)
250
+
251
+ :::info
252
+ Please find a detailed description of components and functionality in the [COMPONENTS](components) section.
253
+ :::
@@ -0,0 +1,22 @@
1
+ import '@testing-library/jest-dom'
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { Button } from "../common/Button/Button";
4
+
5
+ describe('Button component', () => {
6
+ test("Should render button with provided label", () => {
7
+ const handleClickMock = jest.fn();
8
+ render(<Button buttonText='Hello' handleClick={handleClickMock}/>);
9
+ const buttonElement = screen.getByText("Hello");
10
+
11
+ expect(buttonElement).toBeInTheDocument();
12
+ });
13
+
14
+ test("Should call provided callback", () => {
15
+ const handleClickMock = jest.fn();
16
+ render(<Button handleClick={handleClickMock} buttonText='Click me'/>);
17
+ const buttonElement = screen.getByText("Click me");
18
+
19
+ fireEvent.click(buttonElement);
20
+ expect(handleClickMock).toHaveBeenCalledTimes(1);
21
+ });
22
+ })
@@ -0,0 +1,64 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { CourseCard } from "../components/Courses/components/CourseCard/CourseCard";
4
+
5
+ describe('CourseCard component', () => {
6
+ const course = {
7
+ id: "1",
8
+ title: "Course Title",
9
+ description: "Course Description",
10
+ creationDate: "08/03/2021",
11
+ duration: 60,
12
+ authors: [
13
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
14
+ "f762978b-61eb-4096-812b-ebde22838167",
15
+ ],
16
+ };
17
+
18
+ test("Should contain title", () => {
19
+ render(<CourseCard course={course} />);
20
+
21
+ const titleElement = screen.getByText("Course Title");
22
+
23
+ expect(titleElement).toBeInTheDocument();
24
+ });
25
+
26
+ test("Should contain description", () => {
27
+ render(<CourseCard course={course} />);
28
+ const descriptionElement = screen.getByText("Course Description");
29
+ expect(descriptionElement).toBeInTheDocument();
30
+ });
31
+
32
+ test("Should contain duration", () => {
33
+ render(<CourseCard course={course} />);
34
+
35
+ const durationElement = screen.getByText(/01:00 hour/);
36
+
37
+ expect(durationElement).toBeInTheDocument();
38
+ });
39
+
40
+ test("Should contain date", () => {
41
+ render(<CourseCard course={course} />);
42
+
43
+ const creationDateElement = screen.getByText(/08.03.2021/);
44
+
45
+ expect(creationDateElement).toBeInTheDocument();
46
+ });
47
+
48
+ test("Should contain authors list", () => {
49
+ render(<CourseCard course={course} />);
50
+
51
+ const creationDateElement = screen.getByText(/Vasiliy Dobkin, Nicolas Kim/);
52
+
53
+ expect(creationDateElement).toBeInTheDocument();
54
+ });
55
+
56
+ test("Should contain authors list", () => {
57
+ render(<CourseCard course={course} />);
58
+
59
+ const creationDateElement = screen.getByText(/Show course/);
60
+
61
+ expect(creationDateElement).toBeInTheDocument();
62
+ });
63
+ })
64
+