From 016e9b09aeebf27eaa38d5ff528895bef7261ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sun, 17 May 2026 15:40:27 +0300 Subject: [PATCH] refactor(deals): extract DealDetailBody; DealDetailDrawer = overlay/inline wrapper --- .../js/components/deals/DealDetailBody.vue | 340 +++++++++++++++ .../js/components/deals/DealDetailDrawer.vue | 398 ++---------------- app/tests/Frontend/DealDetailDrawer.spec.ts | 111 ++--- .../Frontend/DealDetailDrawerApi.spec.ts | 30 +- 4 files changed, 422 insertions(+), 457 deletions(-) create mode 100644 app/resources/js/components/deals/DealDetailBody.vue diff --git a/app/resources/js/components/deals/DealDetailBody.vue b/app/resources/js/components/deals/DealDetailBody.vue new file mode 100644 index 00000000..373e828f --- /dev/null +++ b/app/resources/js/components/deals/DealDetailBody.vue @@ -0,0 +1,340 @@ + + + + + diff --git a/app/resources/js/components/deals/DealDetailDrawer.vue b/app/resources/js/components/deals/DealDetailDrawer.vue index 2fdf53b4..4796958e 100644 --- a/app/resources/js/components/deals/DealDetailDrawer.vue +++ b/app/resources/js/components/deals/DealDetailDrawer.vue @@ -1,43 +1,23 @@ @@ -312,75 +51,16 @@ defineExpose({ .deal-drawer { background: #fff; } - -.drawer-content { - display: flex; - flex-direction: column; -} - -.section-title { - font-weight: 600; - color: #081319; -} - -.params { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px 12px; - margin: 0; -} -.param dt { - font-size: 11px; - margin-bottom: 2px; -} -.param dd { - margin: 0; - color: #081319; -} -.param .link { - color: #0f6e56; - cursor: pointer; -} -.param .link:hover { - text-decoration: underline; -} - -.num { - font-family: 'JetBrains Mono', ui-monospace, monospace; - font-feature-settings: 'tnum'; -} - -.reminders-list { - list-style: none; - padding: 0; - margin: 0; - display: flex; - flex-direction: column; - gap: 6px; -} - -.reminder-row { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 8px; +.deal-detail-inline { + flex: 0 0 400px; + width: 400px; + background: #fff; border: 1px solid #e8e3d6; - border-radius: 6px; - background: #fdfaf3; -} - -.reminder-body { - flex: 1; - min-width: 0; -} - -.reminder-text { - font-size: 13px; - line-height: 1.4; - color: #081319; -} - -.reminder-meta { - margin-top: 2px; + border-radius: 8px; + overflow-y: auto; + align-self: flex-start; + max-height: calc(100vh - 160px); + position: sticky; + top: 16px; } diff --git a/app/tests/Frontend/DealDetailDrawer.spec.ts b/app/tests/Frontend/DealDetailDrawer.spec.ts index 9cbf043d..a51d8e6c 100644 --- a/app/tests/Frontend/DealDetailDrawer.spec.ts +++ b/app/tests/Frontend/DealDetailDrawer.spec.ts @@ -1,95 +1,46 @@ -import { describe, it, expect, beforeEach } from 'vitest'; +import { describe, it, expect } from 'vitest'; import { mount } from '@vue/test-utils'; import { createVuetify } from 'vuetify'; import { createPinia, setActivePinia } from 'pinia'; import DealDetailDrawer from '../../resources/js/components/deals/DealDetailDrawer.vue'; -import { MOCK_DEALS } from '../../resources/js/composables/mockDeals'; +import type { MockDeal } from '../../resources/js/composables/mockDeals'; -beforeEach(() => { +const vuetify = createVuetify(); +const deal: MockDeal = { + id: 1, name: '+7 999', phone: '+7 999', statusSlug: 'new', project: 'Окна', + manager: { initials: 'AD', name: 'Admin' }, cost: 0, receivedMinutesAgo: 5, +}; + +function mountDrawer(props: Record) { setActivePinia(createPinia()); -}); - -// DealDetailDrawer использует v-navigation-drawer, который требует layout- -// контекст от v-app/v-layout. В Vitest auto-import недоступен — stub'им -// v-navigation-drawer как passthrough div чтобы slot-content рендерился -// и был доступен для assertion. - -describe('DealDetailDrawer.vue', () => { - const factory = (props: { open: boolean; deal: (typeof MOCK_DEALS)[number] | null }) => - mount(DealDetailDrawer, { - props, - global: { - plugins: [createVuetify()], - stubs: { - VNavigationDrawer: { - template: '
', - props: ['modelValue'], - }, + return mount(DealDetailDrawer, { + props: { open: true, deal, ...props }, + global: { + plugins: [vuetify, createPinia()], + stubs: { + DealDetailBody: true, + VNavigationDrawer: { + template: '
', + props: ['modelValue'], }, }, - }); + }, + }); +} - const sampleDeal = MOCK_DEALS[0]; // Анна Соколова - - it('не рендерит контент когда open=false', () => { - const wrapper = factory({ open: false, deal: sampleDeal }); - expect(wrapper.find('.drawer-stub').exists()).toBe(false); +describe('DealDetailDrawer wrapper', () => { + it('inline=true рендерит