12 subscribers
182 photos
3 videos
212 links
Programmer - Курсы программирования. Канал для тех, кто не хочет остаться на задворках цивилизации.
Download Telegram
🚀 Веб-разработка с нуля: Урок 16 - Подключаем Firebase для синхронизации задач

Привет, разработчики! 👨💻👩💻
Сегодня выведем наш To-Do List на новый уровень — добавим облачную синхронизацию между устройствами через Firebase!

🔥 Что нового изучим:
1. Настройку Firebase Realtime Database
2. Работу с аутентификацией
3. Синхронизацию данных в реальном времени

☁️ Почему Firebase?
✓ Бесплатный стартовый тариф
✓ Реальное время обновлений
✓ Простая интеграция

💻 Практика: подключаем облако

1. Регистрируем проект на [firebase.google.com](https://firebase.google.com)
2. Добавляем Firebase в проект:
<!-- В head -->
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-database-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-auth-compat.js"></script>


3. Инициализируем Firebase:
const firebaseConfig = {
apiKey: "ВАШ_API_KEY",
authDomain: "ВАШ_PROJECT.firebaseapp.com",
databaseURL: "https://ВАШ_PROJECT.firebaseio.com",
projectId: "ВАШ_PROJECT",
storageBucket: "ВАШ_PROJECT.appspot.com",
messagingSenderId: "ВАШ_SENDER_ID",
appId: "ВАШ_APP_ID"
};

firebase.initializeApp(firebaseConfig);
const database = firebase.database();


4. Модернизируем логику работы с задачами:
// Авторизация анонимного пользователя
firebase.auth().signInAnonymously()
.then(() => {
console.log('Анонимная авторизация успешна');
initDatabase();
});

function initDatabase() {
const userId = firebase.auth().currentUser.uid;
const tasksRef = database.ref(`users/${userId}/tasks`);

// Синхронизация с сервером
tasksRef.on('value', (snapshot) => {
const data = snapshot.val() || {};
renderTasks(data);
});
}

function saveTaskToCloud(task) {
const userId = firebase.auth().currentUser.uid;
database.ref(`users/${userId}/tasks/${task.id}`).set(task);
}

function deleteTaskFromCloud(taskId) {
const userId = firebase.auth().currentUser.uid;
database.ref(`users/${userId}/tasks/${taskId}`).remove();
}


🔌 Что мы изменили в логике:
1. Заменяем localStorage на Firebase Realtime Database
2. Добавляем анонимную авторизацию
3. Реализуем мгновенную синхронизацию

💡 Профессиональные советы:
1. Для продакшена настройте правила безопасности:
// В Firebase Console -> Rules
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}


2. Добавьте обработку ошибок:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
initDatabase();
} else {
console.error('Ошибка авторизации');
}
});


👉 В следующем уроке:
Добавим уведомления через Firebase Cloud Messaging!

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Как вам работа с Firebase? Делитесь впечатлениями! 💬

#вебразработка #Firebase #RealtimeDatabase #javascript #программирование
🚀 Веб-разработка с нуля: Урок 17 - Добавляем push-уведомления

Привет, разработчики! 👨💻👩💻
Сегодня научим наш To-Do List отправлять push-уведомления через Firebase Cloud Messaging (FCM).

🔥 Что нового:
1. Настройка FCM в Firebase
2. Получение токена устройства
3. Отправка и обработка уведомлений

📲 Как работают push-уведомления:
1. Пользователь разрешает уведомления
2. Браузер получает уникальный токен
3. Сервер отправляет уведомление по токену

💻 Практика: добавляем уведомления

1. Подключаем FCM в проекте Firebase Console
2. Добавляем скрипт в HTML:
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-messaging-compat.js"></script>


3. Инициализируем Messaging:
const messaging = firebase.messaging();

// Запрашиваем разрешение
function requestNotificationPermission() {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Уведомления разрешены');
getToken();
}
});
}

// Получаем токен устройства
function getToken() {
messaging.getToken({vapidKey: "ВАШ_VAPID_KEY"})
.then(token => {
console.log('Токен устройства:', token);
saveToken(token);
});
}

// Сохраняем токен в БД
function saveToken(token) {
const userId = firebase.auth().currentUser.uid;
database.ref(`users/${userId}/fcmToken`).set(token);
}


4. Обрабатываем входящие уведомления:
// Для работающего приложения
messaging.onMessage(payload => {
console.log('Уведомление:', payload);
showNotification(payload.notification);
});

// Для закрытого приложения
messaging.setBackgroundMessageHandler(payload => {
return self.registration.showNotification(
payload.notification.title,
payload.notification
);
});

function showNotification(notification) {
new Notification(notification.title, {
body: notification.body,
icon: '/icon-192.png'
});
}


🔔 Что мы добавили:
Запрос разрешения на уведомления
Сохранение токена устройства
Обработку входящих сообщений
Красивые браузерные уведомления

💡 Профессиональные советы:
1. Добавьте кнопку для управления уведомлениями:
<button id="notifyBtn">Включить уведомления</button>

document.getElementById('notifyBtn').addEventListener('click', requestNotificationPermission);


2. Отправляйте тестовое уведомление через Firebase Console

3. Используйте кастомные иконки:
{
notification: {
title: "Новая задача",
body: "Не забудьте выполнить!",
icon: "/icon-192.png",
click_action: "https://вашсайт.com/tasks"
}
}


👉 В следующем уроке:
Настроим автоматические напоминания о задачах!

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Как вам работа с push-уведомлениями? Пишите в комментариях! 💬

#вебразработка #Firebase #PushУведомления #FCM #javascript
🚀 Веб-разработка с нуля: Урок 18 - Автоматические напоминания

Привет, разработчики! 👨💻👩💻
Сегодня научим наш To-Do List отправлять автоматические напоминания о важных задачах в заданное время.

Что нового:
1. Работа с датами и временем в JavaScript
2. Использование Firebase Cloud Functions
3. Планирование уведомлений

📅 Как это будет работать:
1. Пользователь устанавливает дедлайн для задачи
2. Система запланирует уведомление
3. Firebase отправит напоминание в нужное время

💻 Практика: добавляем дедлайны

1. Добавляем поле для даты в HTML:
<div class="task-form">
<input type="text" id="taskInput" placeholder="Новая задача...">
<input type="datetime-local" id="taskDeadline">
<button id="addButton">Добавить</button>
</div>


2. Модифицируем функцию добавления задачи:
function addTask() {
const taskText = taskInput.value;
const deadline = taskDeadline.value;

if (taskText) {
const task = {
id: Date.now(),
text: taskText,
completed: false,
deadline: deadline || null,
createdAt: firebase.database.ServerValue.TIMESTAMP
};

saveTaskToCloud(task);
if (deadline) scheduleNotification(task);
}
}


3. Создаем Cloud Function для уведомлений:
// В файле functions/index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.scheduleNotification = functions.database
.ref('/users/{userId}/tasks/{taskId}')
.onCreate(async (snapshot, context) => {
const task = snapshot.val();

if (task.deadline) {
const deadline = new Date(task.deadline);
const now = new Date();

if (deadline > now) {
const delay = deadline.getTime() - now.getTime();

await new Promise(resolve => setTimeout(resolve, delay));

const userRef = admin.database().ref(`users/${context.params.userId}`);
const user = (await userRef.once('value')).val();

if (user.fcmToken) {
await admin.messaging().sendToDevice(user.fcmToken, {
notification: {
title: ' Напоминание о задаче',
body: task.text,
clickAction: 'https://вашсайт.com/tasks'
}
});
}
}
}
});


🔔 Что мы улучшили:
Добавили выбор дедлайна для задач
Настроили автоматические напоминания
Использовали Cloud Functions для планирования
Сохранили время создания задачи

💡 Профессиональные советы:
1. Для точного планирования используйте Cloud Tasks API
2. Добавьте повторяющиеся напоминания:
// В объекте задачи
reminder: {
repeat: 'daily',
until: '2023-12-31'
}


3. Валидируйте ввод даты:
if (new Date(deadline) < new Date()) {
alert('Выберите дату в будущем!');
return;
}


👉 В следующем уроке:
Добавим совместную работу над задачами!

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Какие функции хотели бы видеть в следующих уроках? 💬

#вебразработка #Firebase #CloudFunctions #Уведомления #JavaScript
🚀 Веб-разработка с нуля: Урок 19 - Совместная работа над задачами

Привет, разработчики! 👨💻👩💻
Сегодня превратим наш To-Do List в многофункциональный инструмент для командной работы!

🤝 Что нового:
1. Система совместного доступа к задачам
2. Редактирование в реальном времени
3. Индикация активности пользователей

💡 Как это будет работать:
1. Пользователь приглашает участников по email
2. Все изменения синхронизируются мгновенно
3. Каждый видит, кто и что редактирует

💻 Практика: добавляем совместный доступ

1. Добавляем интерфейс для приглашений:
<div class="collaboration-panel">
<input type="email" id="inviteEmail" placeholder="Пригласить по email">
<button id="inviteButton">Пригласить</button>
<div id="collaboratorsList"></div>
</div>


2. Модифицируем структуру данных в Firebase:
function shareTask(taskId, email) {
const userId = firebase.auth().currentUser.uid;
const shareRef = database.ref(`sharedTasks/${taskId}`);

shareRef.push({
userId: userId,
email: email,
accessLevel: 'editor',
sharedAt: firebase.database.ServerValue.TIMESTAMP
});

// Отправляем email-приглашение через Cloud Function
firebase.functions().httpsCallable('sendInvitation')({
taskId: taskId,
email: email
});
}


3. Создаем Cloud Function для приглашений:
exports.sendInvitation = functions.https.onCall((data, context) => {
const taskId = data.taskId;
const email = data.email;

// Отправка email через SendGrid или другой сервис
return sendEmail({
to: email,
subject: 'Приглашение к совместной работе',
html: `Вас пригласили редактировать задачу: <a href="https://вашсайт.com/task/${taskId}">Открыть</a>`
});
});


4. Добавляем индикацию активности:
// Отслеживаем активных пользователей
function trackPresence() {
const userId = firebase.auth().currentUser.uid;
const presenceRef = database.ref(`status/${userId}`);

firebase.database().ref('.info/connected').on('value', snap => {
if (snap.val()) {
presenceRef.onDisconnect().set('offline');
presenceRef.set('online');
}
});
}


👥 Что мы добавили:
Систему приглашений по email
Общий доступ к задачам
Индикацию онлайн-статуса
Безопасный доступ через Firebase Rules

🔒 Настраиваем правила безопасности:
{
"rules": {
"sharedTasks": {
"$taskId": {
".read": "auth != null && root.child('tasks/'+$taskId+'/owner').val() == auth.uid",
".write": "auth != null && root.child('tasks/'+$taskId+'/owner').val() == auth.uid"
}
}
}
}


💡 Профессиональные советы:
1. Добавьте разные уровни доступа (просмотр/редактирование)
2. Реализуйте историю изменений:
function logChange(taskId, change) {
database.ref(`taskHistory/${taskId}`).push({
change: change,
by: firebase.auth().currentUser.uid,
at: firebase.database.ServerValue.TIMESTAMP
});
}


3. Используйте аватары пользователей:
.user-avatar {
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 8px;
}


👉 В следующем уроке:
Добавим чат к задачам для обсуждения!

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Как вам система совместной работы? Пишите идеи! 💬

#вебразработка #Firebase #Collaboration #JavaScript #RealTime
🚀 Веб-разработка с нуля: Урок 20 - Чат к задачам и подведение итогов

Привет, дорогие разработчики! 👨💻👩💻
Мы прошли огромный путь — от простого To-Do List до полноценного collaborative-приложения! Сегодня добавим чат к задачам и подведем итоги нашего 20-дневного марафона.

💬 Что нового:
1. Реализуем чат для обсуждения задач
2. Добавим уведомления о новых сообщениях
3. Подведем итоги всего курса

📌 Как будет работать чат:
• Каждая задача получает свой чат
• Сообщения сохраняются в Firebase
• Участники получают уведомления

💻 Практика: добавляем чат

1. Добавляем HTML-разметку:
<div class="task-chat">
<div id="chatMessages"></div>
<div class="chat-input">
<input type="text" id="chatInput" placeholder="Ваше сообщение...">
<button id="sendMessageBtn">Отправить</button>
</div>
</div>


2. Настраиваем структуру в Firebase:
function sendMessage(taskId, message) {
const userId = firebase.auth().currentUser.uid;
database.ref(`taskChats/${taskId}`).push({
text: message,
sender: userId,
timestamp: firebase.database.ServerValue.TIMESTAMP
});
}

function loadMessages(taskId) {
database.ref(`taskChats/${taskId}`).on('value', snapshot => {
const messages = [];
snapshot.forEach(child => {
messages.push({
id: child.key,
...child.val()
});
});
renderMessages(messages);
});
}


3. Добавляем стили для чата:
.task-chat {
border-top: 1px solid #eee;
margin-top: 20px;
padding-top: 15px;
}

#chatMessages {
max-height: 200px;
overflow-y: auto;
margin-bottom: 10px;
}

.chat-message {
margin-bottom: 8px;
padding: 8px 12px;
background: #f5f5f5;
border-radius: 12px;
display: inline-block;
max-width: 70%;
}

.my-message {
background: #007bff;
color: white;
float: right;
}


🎓 Итоги 20 уроков:
Создали полноценное веб-приложение
Реализовали:
- Работу с DOM
- Адаптивную верстку
- PWA-функционал
- Firebase-интеграцию
- Совместную работу
- Чат к задачам

🚀 Что дальше?
1. Дорабатываем приложение:
- Добавляем теги к задачам
- Реализуем поиск и фильтрацию
- Улучшаем UI/UX

2. Публикуем проект:
- Настраиваем хостинг Firebase
- Регистрируем домен
- Добавляем в App Store/Google Play через PWA

💡 Главные выводы:
1. Современная веб-разработка — это мощно и увлекательно
2. JavaScript + Firebase — отличный стек для старта
3. Лучший способ научиться — делать реальные проекты

📢 Важно:
Весь код доступен в GitHub-репозитории: [ссылка]
Присоединяйтесь к чату участников: [@rm_programmer_chat]

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Делитесь своими реализациями — лучшие проекты мы разберем в канале!

#вебразработка #Итоги #JavaScript #Firebase #PWA
🚀 Веб-разработка с нуля: Урок 21 - Публикуем проект в сети

Привет, выпускники курса! 👨🎓👩🎓
Сегодня завершающий этап — научимся публиковать ваше приложение в интернете и делиться им с миром!

🌐 Что рассмотрим:
1. Хостинг на Firebase
2. Настройку доменного имени
3. Добавление PWA в магазины приложений

🔥 Firebase Hosting за 3 шага:

1. Устанавливаем Firebase CLI:
npm install -g firebase-tools
firebase login


2. Инициализируем проект:
firebase init hosting
# Выбираем ваш проект Firebase
# Указываем папку (public)
# Настраиваем как SPA (все URL → index.html)


3. Делаем деплой:
firebase deploy --only hosting



🔗 Подключаем домен:
1. В Firebase Console → Hosting
2. Добавляем свой домен (можно купить за ~150₽/год)
3. Настраиваем DNS-записи как указано в инструкции

📱 Публикуем PWA в магазинах:
1. Генерируем APK/IPA через:
- [PWABuilder](https://www.pwabuilder.com/)
- [Bubblewrap](https://github.com/GoogleChromeLabs/bubblewrap)

2. Загружаем в:
- Google Play Console (~2000₽ разовый взнос)
- App Store Connect ($99/год)

💼 Портфолио-советы:
1. Создайте README.md с:
- Скриншотами
- Описанием технологий
- Ссылкой на живое демо

2. Выложите код на GitHub:
git init
git add .
git commit -m "Мой To-Do List проект"
git remote add origin [ваш-репозиторий]
git push -u origin main



🎁 Бонус: бесплатные ресурсы
1. Домены: [Freenom](https://www.freenom.com/) (бесплатные .tk/.ml)
2. Хостинг: [Vercel](https://vercel.com/), [Netlify](https://www.netlify.com/)
3. Иконки: [Font Awesome](https://fontawesome.com/)

💡 Финал — это только начало!
Ваш путь в веб-разработке продолжается:
➜ Осваиваем React/Vue
➜ Изучаем серверный Node.js
➜ Пробуем TypeScript

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Делитесь ссылками на ваши проекты — лучшие опубликуем в канале! 🚀

#вебразработка #Firebase #Хостинг #Портфолио #PWA
🚀 Веб-разработка с нуля: Урок 22 - Оптимизация и продвижение вашего приложения

Привет, веб-разработчики! 👨💻👩💻
Теперь, когда ваше приложение опубликовано, научимся его оптимизировать и привлекать первых пользователей!

⚡️ 5 ключевых направлений оптимизации:

1. Производительность
- Сжимаем изображения через Squoosh
- Включаем кэширование в Service Worker
- Используем lazy loading для контента

// service-worker.js
const CACHE_NAME = 'cache-v2';
const ASSETS = [
'/',
'/styles.min.css',
'/script.min.js',
'/icon-192.min.png'
];


2. SEO-продвижение
- Добавляем мета-теги
- Настраиваем manifest.json
- Создаем sitemap.xml

<meta name="description" content="Менеджер задач с синхронизацией">
<meta property="og:image" content="/social-preview.png">


3. Аналитика
- Подключаем Google Analytics
- Добавляем heatmap-отслеживание
- Собираем feedback от пользователей

// Подключаем Google Analytics
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');


4. Маркетинг
- Создаем landing page
- Запускаем рекламу в соцсетях
- Пишем полезный контент о приложении

5. Мониторинг
- Настраиваем Sentry для ошибок
- Мониторим скорость загрузки
- Анализируем поведение пользователей

📈 3 способа привлечь первых пользователей:

1. Бесплатные каналы:
- Посты в соцсетях
- Гостевые публикации
- Участие в форумах

2. Платные инструменты:
- Таргетированная реклама ($5-10 в день)
- Продвижение в каталогах PWA
- Email-рассылка

3. Партнерские программы:
- Реферальные ссылки
- Программа лояльности
- Совместные промо с блогерами

💡 Советы по удержанию пользователей:
- Добавьте onboarding-тур
- Внедрите систему достижений
- Регулярно выпускайте обновления

🚀 Дополнительные ресурсы:
1. [Web.dev](https://web.dev/) - тесты производительности
2. [Google Search Console](https://search.google.com/) - SEO-аналитика
3. [Hotjar](https://www.hotjar.com/) - анализ поведения

👉 В следующих выпусках:
Разберем реальные кейсы успешных PWA-приложений!

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
Делитесь вашими успехами в комментариях!

#вебразработка #Оптимизация #Маркетинг #PWA #SEO
🚀 Веб-разработка с нуля: Урок 23 — Переходим на TypeScript

Привет, разработчики! 👨💻👩💻
Сегодня сделаем важный шаг в профессиональной разработке — переведём наш To-Do List на TypeScript!

### 🔥 Зачем TypeScript?
Чёткая типизация — меньше ошибок
Лучшая поддержка кода
Удобный рефакторинг
Популярен в крупных проектах

### 🛠 Настройка TypeScript
1. Устанавливаем зависимости:
npm install typescript @types/node --save-dev



2. Инициализируем конфиг:
npx tsc --init



3. Настраиваем tsconfig.json:
{
"compilerOptions": {
"target": "ES6",
"module": "ESNext",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
}
}



### 💡 Переписываем код на TypeScript
1. Раньше (JavaScript):
function addTask(text) {
tasks.push({ text, completed: false });
}



2. Теперь (TypeScript):
interface Task {
text: string;
completed: boolean;
id?: number;
}

const tasks: Task[] = [];

function addTask(text: string): void {
tasks.push({ text, completed: false });
}



### 🚀 Преимущества TypeScript в нашем проекте
🔹 Автодополнение в IDE (VSCode, WebStorm)
🔹 Ошибки на этапе компиляции, а не в браузере
🔹 Читаемость кода — сразу видно, какие данные ожидаются

### 📌 Практическое задание
1. Переведите на TypeScript хотя бы один модуль (например, task-manager.ts)
2. Убедитесь, что сборка работает:
npx tsc



### 👉 Что дальше?
В следующем уроке подключим React и сделаем наш To-Do List ещё круче!

💬 Пишите в комментариях — как вам TypeScript?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)

#TypeScript #ВебРазработка #Программирование #УрокиTS
🚀 Веб-разработка с нуля: Урок 24 — Подключаем React к проекту

Привет, разработчики! 👨💻👩💻
Сегодня совершим революцию в нашем To-Do List — переведём его на React + TypeScript!

### 🌟 Почему React?
• Компонентный подход
• Виртуальный DOM для производительности
• Огромное сообщество и экосистема

### 🛠 Настройка проекта за 3 шага

1️⃣ Создаем React-приложение с TypeScript:
npx create-react-app todo-react --template typescript
cd todo-react



2️⃣ Переносим логику:
Создаем src/components/TaskList.tsx:
interface Task {
id: number;
text: string;
completed: boolean;
}

export const TaskList = () => {
const [tasks, setTasks] = useState<Task[]>([]);

const addTask = (text: string) => {
setTasks([...tasks, { id: Date.now(), text, completed: false }]);
};

return (
<div className="task-manager">
<TaskInput onAdd={addTask} />
<ul className="task-list">
{tasks.map(task => (
<TaskItem key={task.id} task={task} />
))}
</ul>
</div>
);
};



3️⃣ Запускаем проект:
npm start



### 🔥 Что изменилось в архитектуре?
| Было (Vanilla JS) | Стало (React) |
|-----------------------|-------------------------|
| Ручное управление DOM | Декларативный рендеринг |
| Глобальные переменные | Локальный стейт |
| Один большой файл | Компонентная система |

### 💡 5 преимуществ нового подхода
1. Переиспользуемые компоненты (TaskItem, TaskInput)
2. Предиктивный рендеринг — только измененные части
3. Простая интеграция с Firebase (хуки useEffect)
4. Готовые UI-библиотеки (Material UI, Ant Design)
5. Лёгкий переход на React Native для мобилок

### 🚀 Практическое задание
1. Реализуйте компонент TaskInput с формой добавления
2. Добавьте переключение статуса задачи
3. Подключите Firebase (используйте useEffect)

👉 В следующем уроке:
Подключим Redux для управления состоянием!

💬 Пишите в комментариях — какие компоненты уже сделали?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)

#React #TypeScript #Фронтенд #ВебРазработка
🚀 Веб-разработка с нуля: Урок 25 — State-менеджмент с Redux Toolkit

Привет, React-разработчики! 👨💻👩💻
Сегодня выведем управление состоянием на профессиональный уровень — внедрим Redux Toolkit в наше To-Do приложение!

### 🔥 Зачем Redux Toolkit?
- Упрощенная настройка хранилища
- Встроенная иммутабельность
- DevTools для отладки
- Оптимизированные перерисовки

### 🛠 Настройка за 4 шага

1️⃣ Устанавливаем зависимости:
npm install @reduxjs/toolkit react-redux



2️⃣ Создаем слайс задач (features/tasks/tasksSlice.ts):
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface Task {
id: string;
text: string;
completed: boolean;
}

const initialState: Task[] = [];

export const tasksSlice = createSlice({
name: 'tasks',
initialState,
reducers: {
addTask: (state, action: PayloadAction<string>) => {
state.push({
id: Date.now().toString(),
text: action.payload,
completed: false
});
},
toggleTask: (state, action: PayloadAction<string>) => {
const task = state.find(t => t.id === action.payload);
if (task) task.completed = !task.completed;
}
}
});

export const { addTask, toggleTask } = tasksSlice.actions;
export default tasksSlice.reducer;



3️⃣ Настраиваем хранилище (app/store.ts):
import { configureStore } from '@reduxjs/toolkit';
import tasksReducer from '../features/tasks/tasksSlice';

export const store = configureStore({
reducer: {
tasks: tasksReducer
}
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;



4️⃣ Подключаем к React (main.tsx):
import { Provider } from 'react-redux';
import { store } from './app/store';

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);



### 💡 Используем в компонентах
import { useAppDispatch, useAppSelector } from '../app/hooks';
import { addTask, toggleTask } from './tasksSlice';

export const TaskList = () => {
const tasks = useAppSelector(state => state.tasks);
const dispatch = useAppDispatch();

const handleAdd = (text: string) => dispatch(addTask(text));
const handleToggle = (id: string) => dispatch(toggleTask(id));

return (
/* JSX с использованием tasks и handlers */
);
};



### 🚀 Что это даёт?
- Централизованное управление состоянием
- Предсказуемость изменений
- Лёгкую масштабируемость
- Возможность time-travel дебаггинга

### 📌 Практическое задание
1. Реализуйте удаление задач
2. Добавьте фильтрацию (все/активные/выполненные)
3. Подключите сохранение в localStorage

👉 В следующем уроке:
Асинхронные действия с Redux Thunk!

💬 Какие state-менеджеры пробовали до этого?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #React #TypeScript #ВебРазработка
🚀 Веб-разработка с нуля: Урок 26 — Асинхронные действия с Redux Thunk

Привет, покорители state-менеджмента! 👨💻👩💻
Сегодня научим наш To-Do List работать с API и асинхронными операциями через Redux Thunk!

### 🔥 Зачем нужен Thunk?
• Обработка асинхронных запросов
• Инкапсуляция бизнес-логики
• Работа с побочными эффектами

### 🛠 Настройка асинхронного слайса

1️⃣ Добавляем API-слой (features/tasks/tasksAPI.ts):
import { Task } from './tasksSlice';

const API_URL = 'https://your-api.com/tasks';

export const fetchTasks = async (): Promise<Task[]> => {
const response = await fetch(API_URL);
return await response.json();
};

export const saveTask = async (task: Task): Promise<Task> => {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(task)
});
return await response.json();
};



2️⃣ Модернизируем слайс (tasksSlice.ts):
import { createAsyncThunk } from '@reduxjs/toolkit';
import { fetchTasks, saveTask } from './tasksAPI';

export const loadTasks = createAsyncThunk('tasks/load', async () => {
return await fetchTasks();
});

export const addTaskAsync = createAsyncThunk(
'tasks/add',
async (text: string) => {
const newTask = { text, completed: false };
return await saveTask(newTask);
}
);

const tasksSlice = createSlice({
// ...существующие reducers
extraReducers: (builder) => {
builder
.addCase(loadTasks.fulfilled, (state, action) => {
return action.payload;
})
.addCase(addTaskAsync.fulfilled, (state, action) => {
state.push(action.payload);
});
}
});



### 💡 Использование в компонентах
import { loadTasks, addTaskAsync } from './tasksSlice';

export const TaskList = () => {
const dispatch = useAppDispatch();
const { loading, error } = useAppSelector(state => state.tasks.meta);

useEffect(() => {
dispatch(loadTasks());
}, []);

const handleAdd = (text: string) => {
dispatch(addTaskAsync(text));
};

if (loading) return <Spinner />;
if (error) return <ErrorAlert message={error} />;

return ( /* ... */ );
};



### 🚀 5 преимуществ подхода
1. Разделение ответственности (UI ≠ бизнес-логика)
2. Автоматические состояния загрузки/ошибок
3. Кеширование данных
4. Оптимистичные обновления UI
5. Легкое тестирование

### 📌 Практическое задание
1. Реализуйте удаление задач через API
2. Добавьте обработку ошибок
3. Внедрите оптимистичное обновление для toggle

👉 В следующем уроке:
Тестирование Redux-приложения с Jest!

💬 Какую логику вы вынесли бы в thunks?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Redux #Thunk #React #Асинхронность
🚀 Веб-разработка с нуля: Урок 27 — Тестирование Redux с Jest

Привет, будущие эксперты качества кода! 👨💻👩💻
Сегодня научимся писать тесты для Redux-приложения, чтобы ловить баги до того, как их увидят пользователи!

### 🔥 Зачем тестировать Redux?
• Проверка корректности редьюсеров
• Контроль бизнес-логики
• Предотвращение регрессий

### 🛠 Настраиваем тестовое окружение

1️⃣ Устанавливаем зависимости:
npm install jest @types/jest @testing-library/react redux-mock-store --save-dev



2️⃣ Конфиг jest.config.js:
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect']
};



### 💡 Тестируем редьюсер (tasksSlice.test.ts)
import tasksReducer, { addTask, toggleTask } from './tasksSlice';

describe('tasks reducer', () => {
it('should handle initial state', () => {
expect(tasksReducer(undefined, { type: 'unknown' })).toEqual([]);
});

it('should handle addTask', () => {
const actual = tasksReducer([], addTask('New task'));
expect(actual[0].text).toEqual('New task');
expect(actual[0].completed).toBe(false);
});

it('should handle toggleTask', () => {
const initialState = [{ id: '1', text: 'Test', completed: false }];
const actual = tasksReducer(initialState, toggleTask('1'));
expect(actual[0].completed).toBe(true);
});
});



### 🧪 Тестируем асинхронные thunks
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { loadTasks } from './tasksSlice';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

describe('async thunks', () => {
it('dispatches fulfilled when loadTasks succeeds', async () => {
const store = mockStore({});
await store.dispatch(loadTasks() as any);
const actions = store.getActions();

expect(actions[0].type).toEqual('tasks/load/pending');
expect(actions[1].type).toEqual('tasks/load/fulfilled');
});
});



### 🚀 Тестируем компоненты (TaskList.test.tsx)
import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from '../../app/store';
import TaskList from './TaskList';

test('renders empty task list', () => {
render(
<Provider store={store}>
<TaskList />
</Provider>
);

expect(screen.getByText(/нет задач/i)).toBeInTheDocument();
});



### 📌 Практическое задание
1. Напишите тест для неудачного сценария загрузки задач
2. Протестируйте компонент с заполненным списком
3. Добавьте snapshot-тест для редьюсера

👉 В следующем уроке:
CI/CD — Настраиваем автоматические тесты!

💬 Какие части вашего приложения нужно покрыть тестами в первую очередь?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#Jest #Testing #Redux #React #QualityAssurance
Forwarded from rm -r
Дорогие читатели, уверен, что многие из Вас слышали про язык C++. А многие знают, насколько он востребован в мире.

Почему именно он? Да всё просто. Это, с одной стороны, объектно-ориентированный язык, а потому на нём можно создавать очень чистый код и грамотную архитектуру. С другой стороны, в отличие от Java или C#, он обладает очень высокой скоростью выполнения. Поэтому там, где требуется высокая скорость и ООП (а это очень и очень частая ситуация, хотя бы те же игры) прибегают к C++. Дополнительно, C++ обладает отличными возможностями по прямому управлению памятью, а отсюда и его востребованность при системном программировании (создании ОС, драйверов и т.п.).

Но C++ очень сложный и возникает вопрос. Как его выучить в кратчайшие сроки и с максимальным КПД? При этом чтобы материал был не устаревший, чтобы преподавал его практик, чтобы были упражнения и так далее?

И тут я хочу представить Вам бесплатный курс Михаила Русакова "Программирование на C++ для начинающих": https://Hottab.programsite.ru/freecpp

Данный курс полностью удовлетворяет всем этим критериям, поэтому я его однозначно могу рекомендовать: https://Hottab.programsite.ru/freecpp

В данном курсе Вы получите, во-первых, всю необходимую базу, первый практический опыт написания программ на C++ благодаря упражнениям (!!!), поддержку от автора. И самое главное... Это всё бесплатно!

Получить этот курс можно здесь: https://Hottab.programsite.ru/freecpp. Торопитесь, пока такой подробный, структурированный курс, с поддержкой от автора, да ещё и с упражнениями находится в свободном доступе: https://Hottab.programsite.ru/freecpp
🚀 Веб-разработка с нуля: Урок 28 — Настраиваем CI/CD для автоматического тестирования

Привет, инженеры DevOps-культуры! 👨💻👩💻
Сегодня автоматизируем процесс проверки кода — настроим Continuous Integration для нашего To-Do List!

### 🔥 Что такое CI/CD?
CI (Continuous Integration) — автоматический запуск тестов при каждом коммите
CD (Continuous Deployment) — автоматический деплой на сервер

### 🛠 Настройка GitHub Actions

1️⃣ Создаем файл .github/workflows/tests.yml:
name: Run Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '16'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test -- --coverage

- name: Upload coverage
uses: codecov/codecov-action@v1



2️⃣ Добавляем скрипты в package.json:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
}



### 💡 Что мы автоматизировали?
Запуск тестов при каждом push/pr
Проверку на разных ОС
Генерацию отчета о покрытии кода
Интеграцию с Codecov

### 🚀 Деплой на Vercel/Netlify
Добавляем в tests.yml:
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm run build

- name: Deploy to Vercel
uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}



### 📌 Практическое задание
1. Создайте workflow для деплоя на Firebase Hosting
2. Настройте автоматический запуск linting (ESLint)
3. Добавьте проверку типов TypeScript

👉 В следующем уроке:
Мониторинг ошибок в продакшене!

💬 Какие CI-системы вы уже пробовали?

Подписывайтесь: [t.me/rm_programmer](https://t.me/rm_programmer)
#CICD #GitHubActions #DevOps #Автоматизация
Forwarded from rm -r
🔤БЕСПЛАТНО🔤

⭕️❗️Многие наши читатели увлекаются разработкой игр на Unreal Engine. И многие уже поднадоел Blueprint из-за множества ограничений с ним, неудобства использования при работе в команде, низкой производительности. И они хотят освоить C++ в Unreal Engine. Однако, они сталкиваются с проблемой фактически полного отсутствия курсов по этой теме, по крайней мере, на русском языке.

К счастью, теперь это уже не проблема, так как недавно Михаил Русаков выпустил свой видеокурс по C++ в Unreal Engine 5: https://Hottab.programsite.ru/freecppue5

Автора зовут Михаил Русаков, и он преподаёт аж с 2010-го года! Поэтому опыт он имеет очень большой, и в его компетенции можно быть уверены. В самом курсе разбирается и теория, и практика. Более того, курс содержит ещё и упражнения: https://Hottab.programsite.ru/freecppue5

Но самое приятное здесь то, что курс абсолютно бесплатен (по крайней мере, пока)! И получить его прямо сейчас можно здесь: https://Hottab.programsite.ru/freecppue5
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from rm -r
⭕️❗️Дорогие читатели, уверен, что многие из Вас слышали про бум языка Python за последние годы. И это всё неспроста. Дело в том, что у Python есть много преимуществ, но есть 2 таких, совокупность которых отсутствует у других языков программирования. Во-первых, это простота. Python осваивают даже дети (и даже далеко не старшеклассники). Во-вторых, он обладает огромными возможностями для решения практически любых задач, благодаря колоссальному количеству готовых модулей.

Кто бы мог подумать, что для определения возраста человека по его фотографии (а это безумно сложная задача когда-то была), необходимо всего лишь установить модуль парой кликой мышью, написать несколько строчек кода и готово!

Есть другой пример. Нужно Вам скачать видео в 4K с YouTube. Новички идут покупать программы (бесплатно в таком разрешении скачать затруднительно, по крайней мере, я не нашёл без появляющихся водяных знаков). А программисты на Python могут уже написать простенькую программу на 20-30 строчек кода, которая скачает видео в 4K и бесплатно!

Эти 2 примера подчёркивают и простоту языка, и колоссальные возможности, а потому неудивительно, что Python всё чаще и чаще используется для автоматизации всякой рутины. Но, безусловно, нужно научиться писать такие программы. Как?

И тут я хочу представить Вам курс Михаила Русакова "Написание лайфхаков на Python для начинающих": https://Hottab.programsite.ru/freepythonlife

Этот курс содержит несколько различных примеров автоматизации рутинных задач на Python из самых разных областей: работа с файлами, mp3-теги, отправка e-mail.

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

А крайне приятным бонусом идёт то, что курс абсолютно 🔤бесплатный! 🔤Поэтому торопитесь его забрать, пока он ещё в открытом доступе: https://Hottab.programsite.ru/freepythonlife
Please open Telegram to view this post
VIEW IN TELEGRAM