Files
portal/app/resources/js/api/notifications.ts
T
Дмитрий e746b3c9a4 chore(cleanup): dead code removal + DemoSeeder env-conditional + schema header drift
Closes Audit #3 P2 batch (knip dead exports/components, DemoSeeder
hygiene, schema header drift).

- Remove app/resources/js/views/admin/AdminPlaceholderView.vue
  (unreferenced placeholder view — confirmed via repo-wide grep, only
  doc references remain)
- npm uninstall concurrently (no script invoked it; --legacy-peer-deps
  for Histoire 1.0-beta.1 peerDep quirk)
- 12 unused exports → internal types (remove `export` keyword):
  - api/admin.ts: AdminTenantsStats, ApiTenantMetrics,
    ApiAdminBillingSummary, ApiAdminIncidentsSummary
  - api/notifications.ts: NotificationEvent
  - api/reports.ts: ApiReportType, ApiReportFormat, ApiReportParameters,
    ReportCounts, ReportQuota
  - composables/mockBilling.ts: TxType
  - composables/useStatusPill.ts: StatusPillSlug
  All 12 are used INSIDE their own file (response shapes), just not
  exported externally — converting to internal types satisfies knip
  without losing type-checking inside the file.
- DatabaseSeeder::run() — DemoSeeder runs only in local+testing envs
  (`migrate:fresh --seed` in dev now produces demo tenant + admin@demo.local
  + 3 projects + ~14 demo deals; prod environments skip)
- db/schema.sql header line 4: «62 базовые таблицы» → «63 базовые
  таблицы (61 regular + 2 partitioned parents: deals + supplier_lead_costs)»
  Closes schema header drift finding from Phase 3.

Verification:
- vue-tsc --noEmit: 0 errors
- ESLint on touched files: 0 errors
- Pest --parallel: 742/739/3sk/0 failed (identical to baseline, no regressions)
- 2243 assertions / 34.46s

Plan: docs/superpowers/plans/2026-05-14-audit3-deferred-fixes.md Task 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 08:28:44 +03:00

68 lines
2.0 KiB
TypeScript

import { apiClient, ensureCsrfCookie } from './client';
/**
* In-app уведомления для bell-icon UI (schema v8.10).
*
* Все endpoint'ы под Sanctum SPA auth — для незалогиненных вернётся 401.
* Mutating-вызовы (mark-read/mark-all-read/destroy) делают ensureCsrfCookie().
*/
type NotificationEvent =
| 'new_lead'
| 'reminder'
| 'low_balance'
| 'zero_balance'
| 'topup_success'
| 'invoice_paid'
| 'new_device_login'
| 'marketing';
export interface ApiInAppNotification {
id: number;
event: NotificationEvent;
title: string;
body: string | null;
deal_id: number | null;
payload: Record<string, unknown>;
read_at: string | null;
created_at: string | null;
}
export interface ListNotificationsResponse {
items: ApiInAppNotification[];
unread_count: number;
total: number;
}
export interface ListNotificationsParams {
unreadOnly?: boolean;
limit?: number;
}
export async function listNotifications(params: ListNotificationsParams = {}): Promise<ListNotificationsResponse> {
const { data } = await apiClient.get<ListNotificationsResponse>('/api/notifications', {
params: {
unread_only: params.unreadOnly ? 1 : undefined,
limit: params.limit,
},
});
return data;
}
export async function markNotificationRead(id: number): Promise<{ id: number; read_at: string | null }> {
await ensureCsrfCookie();
const { data } = await apiClient.patch<{ id: number; read_at: string | null }>(`/api/notifications/${id}/read`);
return data;
}
export async function markAllNotificationsRead(): Promise<{ updated: number }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ updated: number }>('/api/notifications/mark-all-read');
return data;
}
export async function deleteNotification(id: number): Promise<void> {
await ensureCsrfCookie();
await apiClient.delete(`/api/notifications/${id}`);
}