Николай ,пиривет!
Да, ровно в этом была проблема. Спасибо!

Запустилось) Разбираюсь дальше)
Дима, привет!

Зайди в настройки репы, может у тебя экшены отключены?
Николай, привет!
Подскажи, пожалуйста, что делать, если в репе нет вкладки Actions (Действия)? Она где-то в настройках включается?
Всем привет!

Сегодня есть отличная новость для тех, кто хочет в обучении больше практики с реальным кодом и реальными проектами, а не только в интерактивных уроках. Сегодня я доработал заготовку @prisma-cms/nexus и теперь при публикации кода в github, автоматически выполняется сборка проекта и публикация его в GitHub Pages. Если кто не знает что такое GitHub Pages - это их встроенный бесплатный хостинг для публикации своих проектов в режиме Headless CMS, то есть без режима реальной работы на сервере.

Зачем это надо и как это нам поможет в обучении?

Плюс здесь в том, что теперь есть возможность не только видеть исходный код проекта, но и сразу увидеть его реальную работу без необходимости скачивать его себе локально, устанавливать зависимости, билдить и т.п.

Пример: вот мы совместно с Олей @angel разработали игру Пятнашки (вики). Сама по себе игра не слошная в реализации, но есть масса тонких и интересных моментов. Ранее я бы просто показал исходный код https://github.com/freecode-academy/dev-project--15-game и предложил всем желающим скачать себе и посмотреть как это работает (выполнив все вышеописанные шаги). Сейчас же я могу просто дать ссылку (которую вы увидите и на странице проекта в самом гитхабе): https://freecode-academy.github.io/dev-project--15-game/
Там же можете и поиграться сразу :)

А вот другой проект:

Исходный проект этой заготовки был любезно предоставлен Олегом @Eo_Narique. Но он был до пошлого ванильный и не использовал ни одной зависимости.


Я не мог с этим мириться, поэтому обложил его гигабайтом нод-модулей и выложил в гитхаб :) https://freecode-academy.github.io/dev-project--car-game/


По мере того, как у меня будут проскакивать интересные наработки, я буду так же их оформлять и выкладывать, чтобы их мог любой поковырять и обсудить здесь. Так что если кому интересно, не стесняйтесь - играйтесь и задавайте вопросы, а так же предлагайте свои идеи.

Как публиковать свои проекты?

Довольно просто всё. Вы можете склонировать себе или вот такие готовые проекты (то есть в которых какая-то логика уже обыграна), или взять исходную заготовку @prisma-cms/nextjs. Код главной страницы находится здесь: src/pages/MainPage/index.tsx. Собственно, сюда можете и писать свой код. После этого коммитите свои изменения и выливаете в свой репозиторий в гитхаб (на счет того как работать с гитхабом в интернете очень много хороших и подробных статей, благо стартовый объем информации в этом небольшой). После того, как выльете, переходите в гитхабе во вкладку Actions (Действия). Дождитесь, пока выполнятся все шаги.
После этого, если вы выполнили все в первый раз, надо настроить публикацию в pages. Для этого перейдите в настройки проекта и укажите для него бранч gh-pages (этот бранч автоматически создастся, если деплой выполнился успешно). Не забудьте сохраниться.
Здесь же указана и ссылка на ваш сайт.


После того, как вы сохранитесь, запустится новая джоба, которая и опубликует ваш сайт.

Артемий, вы правы, здесь есть путаница. Дело в том, что в описании указаны требования к инициализируемым переменным, а в тестах проверка уже конечных значений (после переопределения значений переменных). Дополнил описание. Так должно стать понятней.

В описании задания одни требоваиня, а в тестах - другие.
Всем привет! И отдельный привет неизвестному донатеру! :)


Не хочу, чтобы данный топик выглядел как просьба всем скинуться по копейке (хотя выглядеть он будет именно так). Просто хочу выразить благодарность и немного еще рассказать про финансовую сторону проекта.

Данный проект изначально был некоммерческим и я все буду делать для того, чтобы для учащихся весь функционал был доступен в полной мере и бесплатно. Тем не менее, без финансовых поступлений не может быть активного развития проекта (хотя здесь много чего хочется сделать), просто потому что деньги все-таки зарабатывать приходится, и приходится это делать на сторонних проектах. По этой причине здесь и не заметно особо развития проекта, потому что в свое время я сделал все необходимое, чтобы его запустить, а дальше он в основном работает по инерции. Хотя видно, что пользователи регистрируются регулярно и проходят задачи, а если где вопрос какой задается - я не оставляю его без ответа.

А вот 3 дня назад пришел донат. И это было очень приятно! :) Донаты - это не только деньги, но и как бы "Ты делаешь полезное, спасибо тебе!". И это очень здорово стимулирует! :) Выходные я прозанимался с сайтом.

1. Наконец-то обновил next-js с 10 версии до последней 12. До этого пару раз брался, но даже на 11 не мог перенести. Дело в том, что next-js традиционно не позволяет импортировать зависимости, которые пытаются испортировать css и прочие стилевые файлы. В таких случаях мы получаем ошибку Global CSS cannot be imported from within node_modules. Обсуждение этой темы тянется с 2020 года, и это тот редкий случай, когда мейнтейнеру насовали минусов как следует. Но ответная позиция все такая же: "Это универсальный продукт со своими ограничениями, юзайте как есть".

Раньше помогали модули типа @zeit/next-css, но с 11+ версиями они не совместимы. Из-за этого часть функционала просто ломалась, а проект не собирался. Приходилось откладывать и тянуть легаси.

А в этот раз я решил пойти до конца. В итоге вот такой большой коммит получился: https://github.com/freecode-academy/freecode.academy/commit/f6d70658b0f30b2b0da16afadf51b61e11e2585b.
Правда совсем без потерь не обошлось: отвалился @fullcalendar/reactОфисе был вывод задач в календаре), но этим функционалом вряд ли кто-то кроме меня пользовался, так что можно проигнорировать. В целом же все работает.

2. Наконец-то в уроках сделал кнопочку "Следующее задание". Многие просили. Это чтобы после успешного выполнения задания не приходилось возвращаться в список заданий, а просто перейти к следующему.


Кстати, здесь пришлось решать несколько нетривиальную задачу: надо было получить в текущем разделе задание, следующее за выполненным. Если пытаться это сделать обычным методом, используя offset, то надо знать какой порядковый номер у записи текущего задания. Плюс к этому, может оказаться, что с момента, как мы получили эту информацию на клиент, в базу данных могли добавиться новые записи, и наш индекс окажется неактуальным. Нам же надо выполнить SQL-запрос буквально следующего содержания "Получить задание после задания с id таким-то". И я был приятно удивлен, что prisma-2 дает необходимый для этого функционал, а именно курсоры. Посмотрите на итоговый запрос в секции variables:
const response = useCodeChallengesQuery({ variables: { cursor: { id: challenge.id, }, orderBy: { rank: SortOrder.ASC, }, where: { Block: { equals: challenge.Block, }, }, skip: 1, take: 1, }, skip: !challenge.Block, })
Кажется, все четко и понятно: курсор на текущее задание, сортировка по ранку, условие по блоку задач, пропускаем 1 запись (потому что курсор так же попадает в выборку) и берем одну нужную нам запись. Очень удобно.


Хотя TS ругается, что пока еще рано, но все же работает, так что пусть будет. А сделано это ради всего одного метода - Array.prototype.at().

Зачем он нужен, этот метод? В целом, он возвращает элемент массива по его индексу так же, как если бы бы просто в скобочной нотации элемент запросили. Но проблема в тайпскрипте, который много лет уже не может поправить возвращаемый тип при получении по индексу. Вот одно из обсуждений: https://github.com/microsoft/TypeScript/issues/13778

Чтобы было понятней, посмотрите вот такой пример:
const array = ["a", "b", "c"] const str = array[99999]; // string const firstLetter = str.charAt(0); // Cannot read properties of undefined (reading 'charAt')
Вот здесь TS считает, что str имеет тип string, то есть однозначно будет строка. Но мы-то видим, что в массиве всего 3 элемента, и там точно нет 99999 + 1 элементов, то есть у нас str точно будет undefined, так что мы логично получаем ошибку Cannot read properties of undefined (reading 'charAt') при попытке выполнить метод на несуществующем объекте.

А вот метод Array.prototype.at() не имеет такой болячки и корректно возвращает type | undefined.
const array = ["a", "b", "c"] const str2 = array.at(99999); // string | undefined const firstLetter2 = str2.charAt(0); // Expected error

Здесь нам TS четко пишет:
const str2: string | undefined Object is possibly 'undefined'.(2532)

Поиграться с примером можно здесь.

Таким образом использование метода .at() больше защищает от логических ошибок.

4. Поправил сохранение комментариев. Точнее они-то сохранялись, но не обновлялся запрос и не выполнялся ререндер, из-за чего новый комментарий как бы пропадал при сохранении и появлялся после обновления страницы. К слову, есть еще места, где подобное может проявляться, буду фиксить.

5. Сделал отдельную страницу для Донатов. :)
Главная задача - чтобы ничей вклад в развитие проекта не был забыт. Поэтому, неизвестный донатер, обозначься, кто ты, чтобы я добавил информацию :)
Позже я доработаю, чтобы донаты были по API и связка на пользователя автоматически проставлялась, если пользователь авторизован. Но в любом случае, когда шлете донаты, пишите мне, от кого они, а главное - чего хотелось бы нового полезного видеть на сайте (или исправление чего).

P.S. вообще форма доната давно висит и я ранее про нее не говорил, так что вряд ли прям все ее видели. Мне было интересно, будет ли хоть один донат, если о нем не просить специально. Вот, свершилось :)

Артем, все верно: реакт не выводит undefined. Так же он не выводит null, false, true. Можете сами попробовать вставить в любом месте шаблоа {false}, к примеру.
Николай, спасибо за ответ. Вероятно я полагал что пытаясь получить элемент массива не по индексу, а по пустой строке мы должны получить ошибку. Сейчас проверил вот такой код - const digits = ['a', 'b' , 'c']; console.log(digits['']); В итоге мы получаем undefind. Получается что если {answer} undefind, то реакт просто не выводит undefind в html.
Артем, в данном случае код компонента не совсем корректен. Если бы у нас тут был TypeScript, то мы точно получили бы ошибку. Дело в том, что элементы из массива мы получаем по числовому индексу, то есть в нашем случае randomIndex должен быть именно числом, а у нас в стейте по-умолчанию да, задается пустая строка. Сделано это, вероятнее всего, чтобы точно не получить ни одного элемента. То есть possibleAnswers[""] в нашем случае ничего не вернет. Здесь, конечно же, логичней было бы по-умолчанию задать что-то типа -1.
В остальном все работает как обычно: при попытке получения из массива элемента по указанному индексу мы его или получаем (если он есть) или нет. В нашем случае до клика мы его не получаем, потом и ничего в ответ не выводится. А по клику задается существующий индекс, выполняется ререндеринг компонента, получаем элемент массива и выводим его.