ДЗ 1:

0) забрать код по ссылке выше; √

используя store.subscribe и вашу функцию-подписчика:

1) забрать rootCats (store.getState().rootCats.payload.data.CategoryFind) 
при его наличии. Используйте ?. вместо . чтобы не получать ошибки Cannot read 
properties of undefined. √ 

2) проитерировать rootCats, создать для каждой категории ссылку (тэг a) 
с текстом-названием категории вида #/category/АЙДИШНИК КАТЕГОРИИ. 
Отобразите ссылке в блоке aside √

3) пока промис в статусе PENDING используйте какой-то прелоадер (анимированную 
картинку загрузки) вместо меню. Картинку нагуглите). Для симуляции тормозного 
интернета используйте Network -> Throttling в Developer Tools √

gql:

- сделать функцию getGQL, которая возвращает функцию, похожую на текущую gql, 
однако замыкает url (getGQL принимает url как параметр; gql же более не будет 
требовать этого параметра) √
- сделать параметр по умолчанию для variables - пустой объект; √
- сделать reject возвращаемого промиса, если с бэкэнда не вернулся JSON с data, 
зато в JSON есть errors. ошибка с бэка должна попасть error промиса; √
- сделать так, что бы промис-результат gql был без лишних оберток типа 
data.CategoryFind, data.GoodFindOne и т.п. Пусть результат gql содержит только 
полезную информацию. Для этого из data извлеките значение первого ключа, как бы он 
не назывался; √
- если в localStorage есть authToken - добавить заголовок Authorization 
со значением "Bearer ТОКЕН_ИЗ_ЛОКАЛСТОРЕЙДЖА" √

-------------------------------------------------------------------------------------

ДЗ 2:

1. доделать страницу категории:
    1.1 сделать нормальные карточки товаров с ценой и картинкой. Для картинки используйте 
    ссылку http://shop-roles.node.ed.asmer.org.ua/ + url картинки; √
    1.2 вверху над товарами сделать вывод ссылок на подкатегории (по аналогии с aside 
    слева)

2. Сделать страницу товара. Пусть там выводятся все картинки (можно сделать какой-то 
слайдер, переключающий картинки по клику) + описание. Добавьте ссылку на 
категорию(-и) в которых находится товар. 

3. создать actionFullLogin, который thunk (возвращает функцию с параметром dispatch. 
Thunk должен вначале диспатчить actionLogin (который промис login), получать его 
результат (let result = await dispatch(actionLogin....., и если там не null, то 
диспатчить actionAuthLogin с полученным токеном; 
(http://doc.a-level.com.ua/javascript-redux-thunk#h3-8)

4. создать actionFullRegister, который так же thunk:
    4.1 диспатчит actionRegister (аналог actionLogin, создает юзера на бэке)
    4.2 в случае успеха диспатчит actionFullLogin, для автоматического логина после 
    реги. (http://doc.a-level.com.ua/javascript-redux-thunk#h3-9)

5. добавить в window.onhashchange роуты #/login и #/register, которые используют 
ваши конструкторы LoginForm для отрисовки формы. По событию формы логина onlogin 
делайте store.dispatch(actionFullLogin(.....)) и 
store.dispatch(actionFullRegister(.....)) соответственно;

6. добавьте где-то вверху страницы имя пользователя когда пользователь залогинен.