Files
autocrm/app/Support/Hints.php
T
Vasyka 06081159b6 feat(hints): contextual help system + FAQ page (MVP)
Infrastructure for a portal-wide in-app help system:

* Users have hints_enabled (default true) and dismissed_hints (JSON
  array) columns. User::shouldSeeHint(key) checks both.
* app/Support/Hints.php — single-source-of-truth registry with 14
  pilot hints across Service (5), CRM (3), Depozit (3), Finanțe (3).
  Each entry has RO/RU/EN title + body + optional next-step + links.
* <x-hint key="wo.dashboard.overview" /> Blade component renders a
  small "?" icon with Alpine.js popover; the popover shows title,
  body, next-step, related links and an "X" button that POSTs to
  /app/hints/{key}/dismiss.
* HintController handles dismiss (per key), toggle (global on/off)
  and reset (clear dismissed + re-enable). Routes are auth:web.
* /app/faq page (Filament Page under Admin group) renders the whole
  registry grouped by area with a live search box and buttons to
  toggle global hints or reset dismissed ones.
* Wired 3 pilot hints into the WO dashboard: title (overview), Docs
  tab PDF preview, and the Chat client card.

Follow-ups: extend registry to cover more pages and add <x-hint>
tags where useful. Filament resource fields can also reuse the same
copy via ->hint()/->helperText().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-09-01 09:46:07 +00:00

272 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Support;
/**
* Centralized registry of in-app hints and the FAQ they generate.
*
* Each hint has:
* key — stable identifier used for dismiss + Blade component reference
* area — grouping bucket ("service", "crm", "depozit", "finante")
* title — short title (all 3 languages)
* body — 1-3 sentence explanation (all 3 languages)
* links — optional related pages (label + url in current locale)
* next — optional "what to do next" label (current locale)
*
* The FAQ page renders every entry grouped by area with a search box.
* The <x-hint> Blade component renders a single entry as a "?" popover.
*
* Add hints incrementally — this file is the single source of truth.
*/
class Hints
{
public const AREAS = [
'service' => ['label' => ['ro' => 'Fișe lucru', 'ru' => 'Заказ-наряды', 'en' => 'Work orders'], 'icon' => '🔧'],
'crm' => ['label' => ['ro' => 'CRM & Clienți', 'ru' => 'CRM и клиенты', 'en' => 'CRM & Customers'], 'icon' => '👥'],
'depozit' => ['label' => ['ro' => 'Depozit & Piese', 'ru' => 'Склад и запчасти', 'en' => 'Warehouse & Parts'], 'icon' => '📦'],
'finante' => ['label' => ['ro' => 'Finanțe', 'ru' => 'Финансы', 'en' => 'Finance'], 'icon' => '💰'],
];
/** @return array<string, array{area:string,title:array,body:array,links?:array,next?:array}> */
public static function all(): array
{
return [
// ─── Service / Work orders ────────────────────────────────
'wo.list.overview' => [
'area' => 'service',
'title' => [
'ro' => 'Lista fișelor de lucru',
'ru' => 'Список заказ-нарядов',
'en' => 'Work orders list',
],
'body' => [
'ro' => 'Aici vezi toate fișele active. Click pe un rând deschide dashboard-ul fișei (Mitchell1-style). Butonul „+ Fișă nouă" creează una nouă și te duce direct pe dashboard. Filtrele de sus permit selectare pe status, plată, maistru.',
'ru' => 'Здесь все активные заказы. Клик по строке открывает дашборд заказа. Кнопка «+ Новый заказ» создаёт и сразу открывает дашборд. Фильтры вверху — статус, оплата, мастер.',
'en' => 'All active work orders. Row click opens the Mitchell1-style dashboard. "+ New" creates and lands on the dashboard. Top filters: status, payment, master.',
],
'links' => [
['label_ro' => 'Deschide un dashboard', 'label_ru' => 'Открыть дашборд', 'label_en' => 'Open a dashboard', 'url' => '/app/work-orders'],
],
'next' => [
'ro' => 'Click pe orice rând sau „+ Fișă nouă"',
'ru' => 'Клик по строке или «+ Новый заказ»',
'en' => 'Click any row or "+ New"',
],
],
'wo.dashboard.overview' => [
'area' => 'service',
'title' => [
'ro' => 'Dashboard fișă (hub central)',
'ru' => 'Дашборд заказа (центр управления)',
'en' => 'Work order dashboard (hub)',
],
'body' => [
'ro' => 'Toate acțiunile legate de această fișă într-un singur ecran: stânga = client & mașină & istoric reparații, mijloc = lucrări/piese/diagnostic/foto/documente/note (taburi), dreapta = finanțe & timeline & chat client. Jos: navigare între fișe, comandă repetată, închide fișă.',
'ru' => 'Все действия по заказу в одном экране: слева — клиент, авто, история; в центре — работы/запчасти/диагностика/фото/документы/заметки (табы); справа — финансы, лента, чат с клиентом. Внизу: навигация, повтор заказа, закрытие.',
'en' => 'Everything for this WO on one screen: left = client + vehicle + repair history; middle = tabs (works/parts/diag/photos/docs/notes); right = finance + timeline + chat. Bottom bar: prev/next, repeat, close WO.',
],
'next' => [
'ro' => 'Explorează taburile din mijloc: Lucrări, Piese, Foto etc.',
'ru' => 'Проверьте табы в центре: Работы, Запчасти, Фото и т.д.',
'en' => 'Try the middle tabs: Works, Parts, Photos, etc.',
],
],
'wo.dashboard.pdf' => [
'area' => 'service',
'title' => [
'ro' => 'Vizualizare & descărcare PDF',
'ru' => 'Просмотр и скачивание PDF',
'en' => 'PDF preview & download',
],
'body' => [
'ro' => 'Butonul „Vizualizare PDF" deschide factura într-un modal cu preview embedded. Din modal poți printa (via viewer-ul browserului) sau descărca (link „Descarcă"). Nu forțează descărcare implicit.',
'ru' => 'Кнопка «Просмотр PDF» открывает счёт в модалке с превью. Оттуда можно печатать (через просмотрщик браузера) или скачать. По умолчанию не скачивается.',
'en' => 'The "View PDF" button opens the invoice in a modal preview. You can print (via the browser PDF viewer) or download from there. It doesn\'t force download by default.',
],
],
'wo.dashboard.tracking' => [
'area' => 'service',
'title' => [
'ro' => 'Link tracking pentru client',
'ru' => 'Ссылка отслеживания для клиента',
'en' => 'Client tracking link',
],
'body' => [
'ro' => 'Fiecare fișă are un token public unic. Butonul „Link tracking" deschide pagina publică pe care o poți trimite clientului prin SMS/WhatsApp/Telegram — vede statusul lucrării, ETA-ul și fotografiile.',
'ru' => 'У каждого заказа есть публичный токен. Кнопка «Ссылка отслеживания» открывает публичную страницу, которую можно отправить клиенту — он видит статус, ETA, фотографии.',
'en' => 'Each WO has a unique public token. "Tracking link" opens the customer-facing page you can send via SMS/WhatsApp/Telegram — status, ETA, photos.',
],
],
'wo.dashboard.chat' => [
'area' => 'service',
'title' => [
'ro' => 'Chat cu clientul (Telegram/WhatsApp)',
'ru' => 'Чат с клиентом (Telegram/WhatsApp)',
'en' => 'Client chat (Telegram/WhatsApp)',
],
'body' => [
'ro' => 'Trimite mesaje direct din dashboard dacă ai configurat integrarea Telegram sau WhatsApp în Setări → Integrări. Dacă vezi „Mesageria nu este configurată" — mergi la Integrări și completează token-ul.',
'ru' => 'Отправляйте сообщения из дашборда, если настроен Telegram или WhatsApp в Настройки → Интеграции. Если написано «Мессенджер не настроен» — заполните токен.',
'en' => 'Send messages from the dashboard when Telegram/WhatsApp is configured under Settings → Integrations. If it says "Messaging not configured" — go set the token.',
],
'links' => [
['label_ro' => 'Setări integrări', 'label_ru' => 'Настроить интеграции', 'label_en' => 'Configure integrations', 'url' => '/app/integrations'],
],
],
// ─── CRM ──────────────────────────────────────────────────
'crm.pipeline.overview' => [
'area' => 'crm',
'title' => [
'ro' => 'Pipeline — de la lead la fișă',
'ru' => 'Pipeline — от лида до заказа',
'en' => 'Pipeline — from lead to WO',
],
'body' => [
'ro' => 'Fiecare deal trece prin coloane (New → Contactat → Diagnostic → Confirmat → Fișă creată → Închis/Pierdut). Trage-și cardurile între coloane. Când ajunge la „Fișă creată" se generează automat un WO legat de client + mașină.',
'ru' => 'Каждый deal проходит через колонки (New → Контакт → Диагностика → Подтверждён → Заказ создан → Закрыт/Проигран). Перетаскивайте карточки. На «Заказ создан» автоматически генерируется WO.',
'en' => 'Each deal moves across columns (New → Contacted → Diagnosed → Confirmed → WO created → Closed/Lost). Drag cards between columns. Reaching "WO created" auto-generates a work order.',
],
'next' => [
'ro' => 'Trage un card la stânga/dreapta',
'ru' => 'Перетащите карточку',
'en' => 'Drag a card left/right',
],
],
'crm.leads.overview' => [
'area' => 'crm',
'title' => [
'ro' => 'Cereri (leaduri) — intrare centralizată',
'ru' => 'Заявки (лиды) — единая точка входа',
'en' => 'Leads — single inbox',
],
'body' => [
'ro' => 'Aici ajung toate cererile: formularul de pe site, telefoane, mesaje Telegram, campanii Google/Facebook (dacă e configurat). Convertește-le în client + deal cu un click. Statusul „nou" apare cu galben pe dashboard.',
'ru' => 'Все входящие заявки: сайт, звонки, Telegram, Google/Facebook кампании. Одним кликом превращаешь в клиента + deal. Статус «новый» подсвечивается жёлтым на дашборде.',
'en' => 'All incoming requests: website form, calls, Telegram, Google/Facebook (if configured). Convert to client + deal in one click. "New" status shows amber on the dashboard.',
],
],
'crm.calendar.overview' => [
'area' => 'crm',
'title' => [
'ro' => 'Calendar programări (5 vederi)',
'ru' => 'Календарь записей (5 видов)',
'en' => 'Appointments calendar (5 views)',
],
'body' => [
'ro' => 'Zi / Săptămână / Lună / Custom / Listă — comută cu butoanele de sus. Grupare pe post de lucru sau pe maistru. Trage evenimentele pentru re-programare. Butonul „🖨 PDF programări" exportă perioada curentă.',
'ru' => 'День / Неделя / Месяц / Свой / Список — кнопки сверху. Группировка по посту или мастеру. Перетаскивайте события. «🖨 PDF записей» экспортирует текущий период.',
'en' => 'Day / Week / Month / Custom / List — top buttons. Group by post or master. Drag events to reschedule. "🖨 PDF" exports the current period.',
],
],
// ─── Depozit ──────────────────────────────────────────────
'depozit.parts.overview' => [
'area' => 'depozit',
'title' => [
'ro' => 'Piese — catalog + stoc',
'ru' => 'Запчасти — каталог и остатки',
'en' => 'Parts — catalog + stock',
],
'body' => [
'ro' => 'Fiecare piesă are cod, preț cost/vânzare, stoc curent, stoc minim și furnizor preferat. Când stocul scade sub minim, apare în widget-ul „Stoc minim atins" pe dashboard. Adaugă la o fișă din tab-ul „Piese" al fișei.',
'ru' => 'У каждой запчасти: код, цена (закупка/продажа), остаток, минимум, поставщик. Когда остаток ниже минимума — попадает в виджет «Минимальный остаток». Добавляй в заказ через таб «Запчасти».',
'en' => 'Each part has SKU, cost/sell price, current + min stock, preferred supplier. When stock drops below min, it shows up in the "Low stock" widget. Add to a WO via the WO\'s "Parts" tab.',
],
],
'depozit.excel.import' => [
'area' => 'depozit',
'title' => [
'ro' => 'Import factură Excel',
'ru' => 'Импорт счёта из Excel',
'en' => 'Excel invoice import',
],
'body' => [
'ro' => 'Încarcă factura de la furnizor în Excel/CSV. Wizard-ul mapează coloanele (cod, denumire, preț, cant.) și le arată în preview. Piese noi se creează automat, cele existente se actualizează. Maparea coloanelor se salvează per furnizor.',
'ru' => 'Загрузите счёт поставщика в Excel/CSV. Мастер сопоставит колонки (код, название, цена, кол-во) и покажет превью. Новые запчасти создаются, существующие обновляются. Соответствие колонок сохраняется на поставщика.',
'en' => 'Upload the supplier invoice in Excel/CSV. The wizard maps columns (SKU, name, price, qty) and shows a preview. New parts are created, existing ones updated. Column mapping is remembered per supplier.',
],
],
'depozit.scanner.usage' => [
'area' => 'depozit',
'title' => [
'ro' => 'Scaner barcode',
'ru' => 'Сканер штрихкодов',
'en' => 'Barcode scanner',
],
'body' => [
'ro' => 'Scanează codul de bare al piesei cu telefonul (camera browser) sau cu un scanner USB. Sistemul găsește piesa în catalog și te lasă să o adaugi rapid la o fișă activă sau să ajustezi stocul.',
'ru' => 'Сканируй штрихкод телефоном (камерой) или USB-сканером. Система найдёт запчасть в каталоге — можно добавить в заказ или изменить остаток.',
'en' => 'Scan the part barcode with your phone camera or a USB scanner. The system finds it in the catalog — add to an active WO or adjust stock.',
],
],
// ─── Finanțe ──────────────────────────────────────────────
'finante.payments.overview' => [
'area' => 'finante',
'title' => [
'ro' => 'Plăți — încasările tale',
'ru' => 'Оплаты — приход',
'en' => 'Payments — cash in',
],
'body' => [
'ro' => 'Fiecare plată se leagă de o fișă (WO), o metodă (cash, card, transfer) și un user care a primit-o. Suma totală apare pe dashboard-ul principal la „Încasări (luna)" și pe dashboard-ul fișei la „Plătit".',
'ru' => 'Каждая оплата привязана к заказу, способу (наличные/карта/перевод) и пользователю. Общая сумма — на главном дашборде «Приход (месяц)» и на дашборде заказа «Оплачено».',
'en' => 'Each payment ties to a WO, a method (cash/card/transfer) and the user who took it. The total shows on the main dashboard ("Cash in / month") and on the WO dashboard ("Paid").',
],
],
'finante.salaries.overview' => [
'area' => 'finante',
'title' => [
'ro' => 'Salarii — calcul automat per mecanic',
'ru' => 'Зарплаты — авторасчёт по механику',
'en' => 'Salaries — auto per mechanic',
],
'body' => [
'ro' => 'La sfârșit de perioadă (săptămână/lună), rulează „Închide perioada" în Salarii. Sistemul calculează pentru fiecare mecanic: manoperele făcute × marja internă + bonusuri avansuri = net de plată. Toate valorile pot fi ajustate manual înainte de export.',
'ru' => 'В конце периода (неделя/месяц) нажми «Закрыть период» в Зарплатах. Система посчитает по каждому механику: работы × внутренняя маржа + бонусы − авансы = к выплате. Значения можно поправить вручную.',
'en' => 'At period end (week/month), hit "Close period" in Salaries. The system computes per mechanic: labor × internal margin + bonuses advances = net pay. All values are editable before export.',
],
'links' => [
['label_ro' => 'Bonusuri & avansuri', 'label_ru' => 'Бонусы и авансы', 'label_en' => 'Bonuses & advances', 'url' => '/app/payroll-adjustments'],
],
],
'finante.reports.overview' => [
'area' => 'finante',
'title' => [
'ro' => 'Rapoarte financiare',
'ru' => 'Финансовые отчёты',
'en' => 'Financial reports',
],
'body' => [
'ro' => 'Vezi aici P&L pe perioadă selectabilă: încasări, cheltuieli, salarii, profit brut, top clienți, top piese vândute, comparație lună-lună. Export CSV pentru contabilitate.',
'ru' => 'P&L за выбранный период: приход, расход, зарплаты, валовая прибыль, топ клиентов, топ запчастей, сравнение месяцев. Экспорт CSV.',
'en' => 'P&L for a selectable period: income, expenses, salaries, gross profit, top clients, top parts, month-over-month comparison. CSV export for accounting.',
],
],
];
}
public static function get(string $key): ?array
{
return static::all()[$key] ?? null;
}
/** Group all hints by area, preserving insertion order. */
public static function byArea(): array
{
$out = [];
foreach (static::all() as $key => $h) {
$out[$h['area']] ??= [];
$out[$h['area']][$key] = $h;
}
return $out;
}
public static function locale(): string
{
$l = app()->getLocale();
return in_array($l, ['ro', 'ru', 'en'], true) ? $l : 'ro';
}
}