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.
- package/README.md +46 -0
- package/bin/workshop.js +6 -0
- package/dist/auth-check.d.ts +1 -0
- package/dist/auth-check.js +45 -0
- package/dist/auth-check.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +156 -0
- package/dist/cli.js.map +1 -0
- package/dist/content/content/module-1/task/module-1_home-task_components.md +257 -0
- package/dist/content/content/module-1/task/module-1_home-task_good_practices.md +69 -0
- package/dist/content/content/module-1/task/module-1_home-task_task.md +253 -0
- package/dist/content/content/module-1/tests/Button.test.tsx +22 -0
- package/dist/content/content/module-1/tests/CourseCard.test.tsx +64 -0
- package/dist/content/content/module-1/tests/CourseInfo.test.tsx +73 -0
- package/dist/content/content/module-1/tests/Courses.test.tsx +87 -0
- package/dist/content/content/module-1/tests/Header.test.tsx +23 -0
- package/dist/content/content/module-1/tests/Input.test.tsx +36 -0
- package/dist/content/content/module-1/tests/helpers.test.ts +13 -0
- package/dist/content/content/module-1/theory/module-1_elements-render.md +66 -0
- package/dist/content/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
- package/dist/content/content/module-1/theory/module-1_hooks_useState.md +131 -0
- package/dist/content/content/module-1/theory/module-1_react.md +64 -0
- package/dist/content/content/module-1/theory/module-1_spa.md +74 -0
- package/dist/content/content/module-2/task/module-2_home-task_components.md +313 -0
- package/dist/content/content/module-2/task/module-2_home-task_good_practices.md +35 -0
- package/dist/content/content/module-2/task/module-2_home-task_task.md +210 -0
- package/dist/content/content/module-2/tests/App.test.tsx +54 -0
- package/dist/content/content/module-2/tests/Login.test.tsx +73 -0
- package/dist/content/content/module-2/tests/Registration.test.tsx +70 -0
- package/dist/content/content/module-2/tests/SearchBar.test.tsx +39 -0
- package/dist/content/content/module-2/theory/module-2_custom-hooks.md +201 -0
- package/dist/content/content/module-2/theory/module-2_hooks.md +117 -0
- package/dist/content/content/module-2/theory/module-2_react-router.md +328 -0
- package/dist/content/content/module-3/task/module-3_home-task_components.md +94 -0
- package/dist/content/content/module-3/task/module-3_home-task_good_practices.md +26 -0
- package/dist/content/content/module-3/task/module-3_home-task_task.md +170 -0
- package/dist/content/content/module-3/tests/App.test.tsx +54 -0
- package/dist/content/content/module-3/tests/Courses.test.tsx +87 -0
- package/dist/content/content/module-3/tests/CreateAuthor.test.tsx +44 -0
- package/dist/content/content/module-3/tests/CreateCourse.test.tsx +122 -0
- package/dist/content/content/module-3/theory/module-3_redux-hooks.md +194 -0
- package/dist/content/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
- package/dist/content/content/module-4/task/module-4_home-task_components.md +187 -0
- package/dist/content/content/module-4/task/module-4_home-task_task.md +139 -0
- package/dist/content/content/module-4/tests/App.test.tsx +54 -0
- package/dist/content/content/module-4/tests/Courses.test.tsx +87 -0
- package/dist/content/content/module-4/tests/CreateCourse.test.tsx +122 -0
- package/dist/content/content/module-4/tests/Login.test.tsx +73 -0
- package/dist/content/content/module-4/theory/module-4_async-redux.md +99 -0
- package/dist/content/content/module-4/theory/module-4_private-routes.md +55 -0
- package/dist/content/content/module-5/task/module-5_home-task_instruction.md +68 -0
- package/dist/content/content/module-5/task/module-5_home-task_task.md +154 -0
- package/dist/content/content/module-5/tests/App.test.tsx +54 -0
- package/dist/content/content/module-5/tests/CourseCard.test.tsx +64 -0
- package/dist/content/content/module-5/tests/Courses.test.tsx +87 -0
- package/dist/content/content/module-5/tests/Header.test.tsx +23 -0
- package/dist/content/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
- package/dist/content/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
- package/dist/content/module-1/task/module-1_home-task_components.md +257 -0
- package/dist/content/module-1/task/module-1_home-task_good_practices.md +69 -0
- package/dist/content/module-1/task/module-1_home-task_task.md +253 -0
- package/dist/content/module-1/tests/Button.test.tsx +22 -0
- package/dist/content/module-1/tests/CourseCard.test.tsx +64 -0
- package/dist/content/module-1/tests/CourseInfo.test.tsx +73 -0
- package/dist/content/module-1/tests/Courses.test.tsx +87 -0
- package/dist/content/module-1/tests/Header.test.tsx +23 -0
- package/dist/content/module-1/tests/Input.test.tsx +36 -0
- package/dist/content/module-1/tests/helpers.test.ts +13 -0
- package/dist/content/module-1/theory/module-1_elements-render.md +66 -0
- package/dist/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
- package/dist/content/module-1/theory/module-1_hooks_useState.md +131 -0
- package/dist/content/module-1/theory/module-1_react.md +64 -0
- package/dist/content/module-1/theory/module-1_spa.md +74 -0
- package/dist/content/module-2/task/module-2_home-task_components.md +313 -0
- package/dist/content/module-2/task/module-2_home-task_good_practices.md +35 -0
- package/dist/content/module-2/task/module-2_home-task_task.md +210 -0
- package/dist/content/module-2/tests/App.test.tsx +54 -0
- package/dist/content/module-2/tests/Login.test.tsx +73 -0
- package/dist/content/module-2/tests/Registration.test.tsx +70 -0
- package/dist/content/module-2/tests/SearchBar.test.tsx +39 -0
- package/dist/content/module-2/theory/module-2_custom-hooks.md +201 -0
- package/dist/content/module-2/theory/module-2_hooks.md +117 -0
- package/dist/content/module-2/theory/module-2_react-router.md +328 -0
- package/dist/content/module-3/task/module-3_home-task_components.md +94 -0
- package/dist/content/module-3/task/module-3_home-task_good_practices.md +26 -0
- package/dist/content/module-3/task/module-3_home-task_task.md +170 -0
- package/dist/content/module-3/tests/App.test.tsx +54 -0
- package/dist/content/module-3/tests/Courses.test.tsx +87 -0
- package/dist/content/module-3/tests/CreateAuthor.test.tsx +44 -0
- package/dist/content/module-3/tests/CreateCourse.test.tsx +122 -0
- package/dist/content/module-3/theory/module-3_redux-hooks.md +194 -0
- package/dist/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
- package/dist/content/module-4/task/module-4_home-task_components.md +187 -0
- package/dist/content/module-4/task/module-4_home-task_task.md +139 -0
- package/dist/content/module-4/tests/App.test.tsx +54 -0
- package/dist/content/module-4/tests/Courses.test.tsx +87 -0
- package/dist/content/module-4/tests/CreateCourse.test.tsx +122 -0
- package/dist/content/module-4/tests/Login.test.tsx +73 -0
- package/dist/content/module-4/theory/module-4_async-redux.md +99 -0
- package/dist/content/module-4/theory/module-4_private-routes.md +55 -0
- package/dist/content/module-5/task/module-5_home-task_instruction.md +68 -0
- package/dist/content/module-5/task/module-5_home-task_task.md +154 -0
- package/dist/content/module-5/tests/App.test.tsx +54 -0
- package/dist/content/module-5/tests/CourseCard.test.tsx +64 -0
- package/dist/content/module-5/tests/Courses.test.tsx +87 -0
- package/dist/content/module-5/tests/Header.test.tsx +23 -0
- package/dist/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
- package/dist/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
- package/dist/content-loader.d.ts +7 -0
- package/dist/content-loader.js +26 -0
- package/dist/content-loader.js.map +1 -0
- package/dist/context-builder.d.ts +2 -0
- package/dist/context-builder.js +116 -0
- package/dist/context-builder.js.map +1 -0
- 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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
@@ -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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+
|