🔧 fix(src/hh/scraper.ts): исправляет сообщения о пропущенных вакансиях с более информативным текстом
All checks were successful
Deploy / deploy (push) Successful in 7m44s

🎨 style(src/hh/ui.ts): обновляет клавиатуру настроек, добавляет отображение режима поиска

🔧 fix(src/hh/handlers/settings.ts): заменяет клавиатуру настроек на клавиатуру фильтров в обработчике переключения режима поиска
This commit is contained in:
Oscar
2026-06-22 19:15:03 +03:00
parent 9603aed259
commit aa01aa142b
3 changed files with 10 additions and 9 deletions

View File

@@ -2,7 +2,7 @@ import bot from '@bot'
import prisma from '@prisma' import prisma from '@prisma'
import cron from 'node-cron' import cron from 'node-cron'
import { clearVacancyCache } from '../scraper.js' import { clearVacancyCache } from '../scraper.js'
import { buildSettingsKeyboard, escapeHtml } from '../ui.js' import { buildFiltersKeyboard, buildSettingsKeyboard, escapeHtml } from '../ui.js'
import { getState } from '../state.js' import { getState } from '../state.js'
export async function handleSearchModeToggle(chatId: number): Promise<void> { export async function handleSearchModeToggle(chatId: number): Promise<void> {
@@ -15,7 +15,7 @@ export async function handleSearchModeToggle(chatId: number): Promise<void> {
const text = next === 'resume' const text = next === 'resume'
? `✅ <b>Поиск по резюме включён</b>\n\n• Есть ключевые слова → <code>?text=...&resume=...</code>\n• Ключевые слова пусты → только <code>?resume=...</code>` ? `✅ <b>Поиск по резюме включён</b>\n\n• Есть ключевые слова → <code>?text=...&resume=...</code>\n• Ключевые слова пусты → только <code>?resume=...</code>`
: `⛔ <b>Поиск по резюме выключен</b>\n\n• Всегда ищет по ключевым словам → <code>?text=...</code>` : `⛔ <b>Поиск по резюме выключен</b>\n\n• Всегда ищет по ключевым словам → <code>?text=...</code>`
await bot.sendMessage(chatId, text, { parse_mode: 'HTML', reply_markup: await buildSettingsKeyboard(chatId) }) await bot.sendMessage(chatId, text, { parse_mode: 'HTML', reply_markup: await buildFiltersKeyboard(chatId) })
} }
export async function handleQuery(chatId: number): Promise<void> { export async function handleQuery(chatId: number): Promise<void> {

View File

@@ -100,15 +100,14 @@ async function skipIfQuestionnaire(
vacancy: { title: string, href: string }, vacancy: { title: string, href: string },
ref: VacancyRef, ref: VacancyRef,
chatId: number, chatId: number,
status: (msg: string) => Promise<void>, keep: (msg: string) => Promise<void>,
results: ApplyResult, results: ApplyResult,
): Promise<boolean> { ): Promise<boolean> {
await page.waitForSelector(APPLY_OUTCOME_SELECTOR, { timeout: 5000 }).catch(() => {}) await page.waitForSelector(APPLY_OUTCOME_SELECTOR, { timeout: 5000 }).catch(() => {})
const hasQuestionnaire = await page.$('[data-qa="employer-asking-for-test"], [data-qa="task-body"]') const hasQuestionnaire = await page.$('[data-qa="employer-asking-for-test"], [data-qa="task-body"]')
if (!hasQuestionnaire) if (!hasQuestionnaire)
return false return false
const { keep } = createStatusReporter(chatId) await keep(`⏭ Пропущена: <b>требует заполнения анкеты/теста</b>\n${escapeHtml(vacancy.title)}`)
await keep(`Пропущена вакансия: ${vacancy.title}`)
log.warn(`[x] ${vacancy.title} hasQuestionnaire`) log.warn(`[x] ${vacancy.title} hasQuestionnaire`)
await prisma.skippedVacancy.upsert({ await prisma.skippedVacancy.upsert({
where: { telegramId_href: { telegramId: chatId, href: vacancy.href } }, where: { telegramId_href: { telegramId: chatId, href: vacancy.href } },
@@ -431,6 +430,7 @@ export async function applyToJobs(
.catch(() => '') .catch(() => '')
if (!description) { if (!description) {
await keep(`⏭ Пропущена: <b>описание недоступно</b>\n${escapeHtml(vacancy.title)}`)
results.skipped.push(ref) results.skipped.push(ref)
consecutiveSkips++ consecutiveSkips++
continue continue
@@ -438,6 +438,7 @@ export async function applyToJobs(
const applyBtn = await page.$('[data-qa="vacancy-response-link-top"]') const applyBtn = await page.$('[data-qa="vacancy-response-link-top"]')
if (!applyBtn) { if (!applyBtn) {
await keep(`⏭ Пропущена: <b>уже откликались или кнопка не найдена</b>\n${escapeHtml(vacancy.title)}`)
results.skipped.push(vacancy) results.skipped.push(vacancy)
consecutiveSkips++ consecutiveSkips++
continue continue
@@ -451,7 +452,7 @@ export async function applyToJobs(
if (relocationConfirm) if (relocationConfirm)
await relocationConfirm.click() await relocationConfirm.click()
if (await skipIfQuestionnaire(page, vacancy, ref, chatId, status, results)) { if (await skipIfQuestionnaire(page, vacancy, ref, chatId, keep, results)) {
consecutiveSkips++ consecutiveSkips++
continue continue
} }

View File

@@ -38,13 +38,11 @@ export const MAIN_REPLY_KEYBOARD = {
} }
export async function buildSettingsKeyboard(chatId: number) { export async function buildSettingsKeyboard(chatId: number) {
const settings = await prisma.settings.findUnique({ where: { telegramId: chatId } })
const modeLabel = settings?.searchMode === 'resume' ? 'резюме' : 'текст'
return { return {
keyboard: [ keyboard: [
[{ text: BTN.MAX }, { text: BTN.AUTO_TOGGLE }], [{ text: BTN.MAX }, { text: BTN.AUTO_TOGGLE }],
[{ text: BTN.RESUME_LIST }, { text: BTN.PROMPT }], [{ text: BTN.RESUME_LIST }, { text: BTN.PROMPT }],
[{ text: `${BTN.SEARCH_MODE_TOGGLE}: ${modeLabel}` }, { text: BTN.LOGIN }], [{ text: BTN.LOGIN }],
[{ text: BTN.BACK }], [{ text: BTN.BACK }],
], ],
resize_keyboard: true, resize_keyboard: true,
@@ -54,12 +52,14 @@ export async function buildSettingsKeyboard(chatId: number) {
export async function buildFiltersKeyboard(chatId: number) { export async function buildFiltersKeyboard(chatId: number) {
const settings = await prisma.settings.findUnique({ where: { telegramId: chatId } }) const settings = await prisma.settings.findUnique({ where: { telegramId: chatId } })
const modeLabel = settings?.searchMode === 'resume' ? 'резюме' : 'текст'
const fullLabel = areaLabel(settings?.area) const fullLabel = areaLabel(settings?.area)
const regionShort = fullLabel.split(' ').slice(1).join(' ') const regionShort = fullLabel.split(' ').slice(1).join(' ')
return { return {
keyboard: [ keyboard: [
[{ text: BTN.QUERY }], [{ text: BTN.QUERY }],
[{ text: BTN.EXCLUSIONS }, { text: `${BTN.REGION}: ${regionShort}` }], [{ text: BTN.EXCLUSIONS }, { text: `${BTN.REGION}: ${regionShort}` }],
[{ text: `${BTN.SEARCH_MODE_TOGGLE}: ${modeLabel}` }],
[{ text: BTN.BACK }], [{ text: BTN.BACK }],
], ],
resize_keyboard: true, resize_keyboard: true,