{
  "name": "screen-deal",
  "type": "registry:page",
  "dependencies": [
    "@lucide/vue",
    "vue-sonner"
  ],
  "registryDependencies": [
    "attachment",
    "avatar",
    "badge",
    "breadcrumb",
    "button",
    "card",
    "checkbox",
    "dropdown-menu",
    "empty",
    "https://ui.dvizh.website/r/screen-shell.json",
    "item",
    "progress",
    "separator",
    "sidebar",
    "sonner",
    "stepper",
    "table",
    "tabs",
    "textarea"
  ],
  "files": [
    {
      "path": "screens/deal/DealScreen.vue",
      "type": "registry:file",
      "target": "screens/deal/DealScreen.vue",
      "content": "<script setup lang=\"ts\">\n/**\n * Карточка сделки в CRM.\n *\n * Сценарий: менеджер открывает сделку перед звонком клиенту. За несколько секунд ему нужно\n * понять четыре вещи — на какой стадии сделка, сколько денег на кону, что обещали в прошлый\n * раз и что уже просрочено. Всё остальное убрано во вкладки и правую колонку.\n *\n * Экран собран только из готовых компонентов библиотеки: ни одного нового в `components/ui`.\n */\nimport { computed, ref } from 'vue'\nimport {\n  BuildingIcon,\n  CalendarIcon,\n  CopyIcon,\n  FileTextIcon,\n  MailIcon,\n  MoreHorizontalIcon,\n  PhoneIcon,\n  PlusIcon,\n  TrashIcon,\n} from '@lucide/vue'\nimport { toast } from 'vue-sonner'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Badge } from '@/components/ui/badge'\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbLink,\n  BreadcrumbList,\n  BreadcrumbPage,\n  BreadcrumbSeparator,\n} from '@/components/ui/breadcrumb'\nimport { Button } from '@/components/ui/button'\nimport {\n  Card,\n  CardAction,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from '@/components/ui/card'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport {\n  Empty,\n  EmptyContent,\n  EmptyDescription,\n  EmptyHeader,\n  EmptyMedia,\n  EmptyTitle,\n} from '@/components/ui/empty'\nimport {\n  Item,\n  ItemActions,\n  ItemContent,\n  ItemDescription,\n  ItemGroup,\n  ItemMedia,\n  ItemTitle,\n} from '@/components/ui/item'\nimport {\n  Attachment,\n  AttachmentContent,\n  AttachmentDescription,\n  AttachmentGroup,\n  AttachmentMedia,\n  AttachmentTitle,\n} from '@/components/ui/attachment'\nimport { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\nimport { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'\nimport {\n  Stepper,\n  StepperDescription,\n  StepperIndicator,\n  StepperItem,\n  StepperSeparator,\n  StepperTitle,\n  StepperTrigger,\n} from '@/components/ui/stepper'\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '@/components/ui/table'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'\nimport { Textarea } from '@/components/ui/textarea'\nimport { Toaster } from '@/components/ui/sonner'\nimport CrmSidebar from '../CrmSidebar.vue'\nimport { contacts, deal, files, history, stages, tasks, terms } from '../data'\n\nconst currentStage = ref(deal.stageIndex)\nconst comment = ref('')\n\n/** Название стадии берётся из воронки: иначе шапка врёт после перевода сделки. */\nconst stageTitle = computed(() => stages[currentStage.value - 1].title)\n\n/** Просроченная задача помечается предупреждением, выполненная — приглушается. */\nconst taskTone = {\n  overdue: 'destructive',\n  today: 'default',\n  planned: 'secondary',\n  done: 'outline',\n} as const\n\nconst taskLabel = {\n  overdue: 'Просрочена',\n  today: 'Сегодня',\n  planned: 'Запланирована',\n  done: 'Выполнена',\n} as const\n\nfunction saveComment(): void {\n  if (!comment.value.trim()) {\n    return\n  }\n  toast.success('Комментарий добавлен в историю сделки')\n  comment.value = ''\n}\n\nfunction moveStage(step: number): void {\n  currentStage.value = step\n  toast(`Стадия изменена: ${stages[step - 1].title}`)\n}\n</script>\n\n<template>\n  <SidebarProvider>\n    <CrmSidebar section=\"Сделки\" />\n    <SidebarInset>\n      <header class=\"flex h-16 shrink-0 items-center gap-2 border-b px-4\">\n        <SidebarTrigger class=\"-ml-1\" />\n        <Separator orientation=\"vertical\" class=\"mr-2 data-[orientation=vertical]:h-4\" />\n        <Breadcrumb>\n          <BreadcrumbList>\n            <BreadcrumbItem class=\"hidden md:block\">\n              <BreadcrumbLink href=\"#\">Сделки</BreadcrumbLink>\n            </BreadcrumbItem>\n            <BreadcrumbSeparator class=\"hidden md:block\" />\n            <BreadcrumbItem>\n              <BreadcrumbPage>{{ deal.title }}</BreadcrumbPage>\n            </BreadcrumbItem>\n          </BreadcrumbList>\n        </Breadcrumb>\n\n        <div class=\"ml-auto flex items-center gap-2\">\n          <Button variant=\"outline\" size=\"sm\">\n            <PlusIcon />\n            Задача\n          </Button>\n          <Button variant=\"outline\" size=\"sm\" class=\"hidden sm:inline-flex\">\n            <MailIcon />\n            Письмо\n          </Button>\n          <DropdownMenu>\n            <DropdownMenuTrigger as-child>\n              <Button variant=\"ghost\" size=\"icon\" aria-label=\"Ещё действия\">\n                <MoreHorizontalIcon />\n              </Button>\n            </DropdownMenuTrigger>\n            <DropdownMenuContent align=\"end\">\n              <DropdownMenuItem>\n                <CopyIcon />\n                Дублировать сделку\n              </DropdownMenuItem>\n              <DropdownMenuItem>\n                <FileTextIcon />\n                Выставить счёт\n              </DropdownMenuItem>\n              <DropdownMenuSeparator />\n              <DropdownMenuItem variant=\"destructive\">\n                <TrashIcon />\n                Удалить\n              </DropdownMenuItem>\n            </DropdownMenuContent>\n          </DropdownMenu>\n        </div>\n      </header>\n\n      <div class=\"flex flex-1 flex-col gap-4 p-4 lg:p-6\">\n        <!-- Шапка сделки: то, ради чего экран открывают. -->\n        <div class=\"flex flex-wrap items-start justify-between gap-4\">\n          <div class=\"space-y-1\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <h1 class=\"font-heading text-2xl font-semibold tracking-tight\">\n                {{ deal.title }}\n              </h1>\n              <Badge>{{ stageTitle }}</Badge>\n            </div>\n            <p class=\"text-muted-foreground text-sm\">\n              {{ deal.company }} · создана {{ deal.createdAt }}\n            </p>\n          </div>\n          <div class=\"text-right\">\n            <p class=\"font-heading text-2xl font-semibold tracking-tight\">{{ deal.amount }}</p>\n            <p class=\"text-muted-foreground text-sm\">\n              закрытие {{ deal.expectedClose }}\n            </p>\n          </div>\n        </div>\n\n        <!-- Воронка: шаг кликабелен, стадия меняется отсюда. -->\n        <Card>\n          <CardContent>\n            <Stepper v-model=\"currentStage\" class=\"w-full overflow-x-auto\">\n              <StepperItem\n                v-for=\"stage in stages\"\n                :key=\"stage.step\"\n                :step=\"stage.step\"\n                class=\"min-w-40\"\n              >\n                <StepperTrigger @click=\"moveStage(stage.step)\">\n                  <StepperIndicator>{{ stage.step }}</StepperIndicator>\n                  <div class=\"flex flex-col text-left\">\n                    <StepperTitle>{{ stage.title }}</StepperTitle>\n                    <StepperDescription>{{ stage.hint }}</StepperDescription>\n                  </div>\n                </StepperTrigger>\n                <StepperSeparator v-if=\"stage.step < stages.length\" />\n              </StepperItem>\n            </Stepper>\n          </CardContent>\n        </Card>\n\n        <div class=\"grid gap-4 xl:grid-cols-[minmax(0,1fr)_20rem]\">\n          <!-- Левая колонка: работа по сделке. -->\n          <Tabs default-value=\"overview\" class=\"min-w-0\">\n            <TabsList>\n              <TabsTrigger value=\"overview\">Обзор</TabsTrigger>\n              <TabsTrigger value=\"tasks\">Задачи</TabsTrigger>\n              <TabsTrigger value=\"history\">История</TabsTrigger>\n              <TabsTrigger value=\"files\">Файлы</TabsTrigger>\n              <TabsTrigger value=\"mail\">Письма</TabsTrigger>\n            </TabsList>\n\n            <TabsContent value=\"overview\" class=\"space-y-4\">\n              <Card>\n                <CardHeader>\n                  <CardTitle>Состав сделки</CardTitle>\n                  <CardDescription>Что входит в коммерческое предложение</CardDescription>\n                </CardHeader>\n                <CardContent>\n                  <Table>\n                    <TableHeader>\n                      <TableRow>\n                        <TableHead>Позиция</TableHead>\n                        <TableHead>Объём</TableHead>\n                        <TableHead class=\"text-right\">Стоимость</TableHead>\n                      </TableRow>\n                    </TableHeader>\n                    <TableBody>\n                      <TableRow v-for=\"row in terms\" :key=\"row.name\">\n                        <TableCell class=\"font-medium\">{{ row.name }}</TableCell>\n                        <TableCell class=\"text-muted-foreground\">{{ row.qty }}</TableCell>\n                        <TableCell class=\"text-right tabular-nums\">{{ row.price }}</TableCell>\n                      </TableRow>\n                      <TableRow>\n                        <TableCell class=\"font-medium\">Итого</TableCell>\n                        <TableCell />\n                        <TableCell class=\"text-right font-semibold tabular-nums\">\n                          {{ deal.amount }}\n                        </TableCell>\n                      </TableRow>\n                    </TableBody>\n                  </Table>\n                </CardContent>\n              </Card>\n\n              <Card>\n                <CardHeader>\n                  <CardTitle>Комментарий</CardTitle>\n                  <CardDescription>Попадёт в историю сделки и в ленту руководителя</CardDescription>\n                </CardHeader>\n                <CardContent class=\"space-y-3\">\n                  <Textarea\n                    v-model=\"comment\"\n                    placeholder=\"Что обсудили и о чём договорились\"\n                    rows=\"3\"\n                  />\n                  <div class=\"flex justify-end\">\n                    <Button :disabled=\"!comment.trim()\" @click=\"saveComment\">Сохранить</Button>\n                  </div>\n                </CardContent>\n              </Card>\n            </TabsContent>\n\n            <TabsContent value=\"tasks\">\n              <Card>\n                <CardHeader>\n                  <CardTitle>Задачи</CardTitle>\n                  <CardDescription>Одна просрочена</CardDescription>\n                  <CardAction>\n                    <Button variant=\"outline\" size=\"sm\">\n                      <PlusIcon />\n                      Добавить\n                    </Button>\n                  </CardAction>\n                </CardHeader>\n                <CardContent>\n                  <ItemGroup>\n                    <Item v-for=\"task in tasks\" :key=\"task.id\" variant=\"outline\" class=\"mb-2\">\n                      <ItemMedia>\n                        <Checkbox :default-value=\"task.state === 'done'\" />\n                      </ItemMedia>\n                      <ItemContent>\n                        <ItemTitle :class=\"task.state === 'done' && 'text-muted-foreground'\">\n                          {{ task.title }}\n                        </ItemTitle>\n                        <ItemDescription>{{ task.due }} · {{ task.owner }}</ItemDescription>\n                      </ItemContent>\n                      <Badge :variant=\"taskTone[task.state]\">{{ taskLabel[task.state] }}</Badge>\n                    </Item>\n                  </ItemGroup>\n                </CardContent>\n              </Card>\n            </TabsContent>\n\n            <TabsContent value=\"history\">\n              <Card>\n                <CardHeader>\n                  <CardTitle>История</CardTitle>\n                  <CardDescription>Что происходило по сделке</CardDescription>\n                </CardHeader>\n                <CardContent>\n                  <ItemGroup>\n                    <Item v-for=\"event in history\" :key=\"event.id\" class=\"items-start\">\n                      <ItemMedia>\n                        <Avatar class=\"size-8\">\n                          <AvatarFallback>{{ event.initials }}</AvatarFallback>\n                        </Avatar>\n                      </ItemMedia>\n                      <ItemContent>\n                        <ItemTitle>{{ event.author }} · {{ event.at }}</ItemTitle>\n                        <ItemDescription>{{ event.text }}</ItemDescription>\n                      </ItemContent>\n                    </Item>\n                  </ItemGroup>\n                </CardContent>\n              </Card>\n            </TabsContent>\n\n            <TabsContent value=\"files\">\n              <Card>\n                <CardHeader>\n                  <CardTitle>Файлы</CardTitle>\n                  <CardDescription>Документы по сделке</CardDescription>\n                </CardHeader>\n                <CardContent>\n                  <AttachmentGroup class=\"flex-col items-stretch gap-2\">\n                    <Attachment v-for=\"file in files\" :key=\"file.name\" class=\"w-full\">\n                      <AttachmentMedia>\n                        <FileTextIcon />\n                      </AttachmentMedia>\n                      <AttachmentContent>\n                        <AttachmentTitle>{{ file.name }}</AttachmentTitle>\n                        <AttachmentDescription>{{ file.meta }}</AttachmentDescription>\n                      </AttachmentContent>\n                    </Attachment>\n                  </AttachmentGroup>\n                </CardContent>\n              </Card>\n            </TabsContent>\n\n            <TabsContent value=\"mail\">\n              <Card>\n                <CardContent>\n                  <!-- Пустое состояние: у сделки ещё нет переписки. -->\n                  <Empty>\n                    <EmptyHeader>\n                      <EmptyMedia variant=\"icon\">\n                        <MailIcon />\n                      </EmptyMedia>\n                      <EmptyTitle>Переписки пока нет</EmptyTitle>\n                      <EmptyDescription>\n                        Письма из почты подтянутся сюда, как только вы отправите первое из\n                        карточки сделки.\n                      </EmptyDescription>\n                    </EmptyHeader>\n                    <EmptyContent>\n                      <Button variant=\"outline\">\n                        <MailIcon />\n                        Написать письмо\n                      </Button>\n                    </EmptyContent>\n                  </Empty>\n                </CardContent>\n              </Card>\n            </TabsContent>\n          </Tabs>\n\n          <!-- Правая колонка: справка, к которой возвращаются во время разговора. -->\n          <div class=\"space-y-4\">\n            <Card>\n              <CardHeader>\n                <CardTitle>Вероятность</CardTitle>\n                <CardDescription>Оценка менеджера</CardDescription>\n              </CardHeader>\n              <CardContent class=\"space-y-2\">\n                <div class=\"flex items-baseline justify-between\">\n                  <span class=\"font-heading text-2xl font-semibold\">{{ deal.probability }} %</span>\n                  <span class=\"text-muted-foreground text-sm\">{{ stageTitle }}</span>\n                </div>\n                <Progress :model-value=\"deal.probability\" />\n              </CardContent>\n            </Card>\n\n            <Card>\n              <CardHeader>\n                <CardTitle>Контакты</CardTitle>\n                <CardDescription>{{ deal.company }}</CardDescription>\n              </CardHeader>\n              <CardContent>\n                <ItemGroup>\n                  <!-- Кнопка идёт в ItemActions: положенная прямо в строку, она растягивает\n                       её и уезжает по вертикали к середине. -->\n                  <Item v-for=\"person in contacts\" :key=\"person.name\" class=\"items-start\">\n                    <ItemMedia>\n                      <Avatar class=\"size-8\">\n                        <AvatarFallback>{{ person.initials }}</AvatarFallback>\n                      </Avatar>\n                    </ItemMedia>\n                    <ItemContent>\n                      <ItemTitle>{{ person.name }}</ItemTitle>\n                      <ItemDescription>{{ person.role }}</ItemDescription>\n                    </ItemContent>\n                    <ItemActions v-if=\"person.main\">\n                      <Button variant=\"ghost\" size=\"icon\" aria-label=\"Позвонить\">\n                        <PhoneIcon />\n                      </Button>\n                    </ItemActions>\n                  </Item>\n                </ItemGroup>\n              </CardContent>\n            </Card>\n\n            <Card>\n              <CardHeader>\n                <CardTitle>О сделке</CardTitle>\n              </CardHeader>\n              <CardContent>\n                <ItemGroup>\n                  <Item size=\"sm\">\n                    <ItemMedia><BuildingIcon /></ItemMedia>\n                    <ItemContent>\n                      <ItemTitle>{{ deal.company }}</ItemTitle>\n                      <ItemDescription>Клиент</ItemDescription>\n                    </ItemContent>\n                  </Item>\n                  <Item size=\"sm\">\n                    <ItemMedia><CalendarIcon /></ItemMedia>\n                    <ItemContent>\n                      <ItemTitle>{{ deal.expectedClose }}</ItemTitle>\n                      <ItemDescription>Ожидаемое закрытие</ItemDescription>\n                    </ItemContent>\n                  </Item>\n                  <Item size=\"sm\">\n                    <ItemMedia>\n                      <Avatar class=\"size-6\">\n                        <AvatarFallback class=\"text-xs\">{{ deal.owner.initials }}</AvatarFallback>\n                      </Avatar>\n                    </ItemMedia>\n                    <ItemContent>\n                      <ItemTitle>{{ deal.owner.name }}</ItemTitle>\n                      <ItemDescription>Ответственный</ItemDescription>\n                    </ItemContent>\n                  </Item>\n                  <Item size=\"sm\">\n                    <ItemMedia><FileTextIcon /></ItemMedia>\n                    <ItemContent>\n                      <ItemTitle>{{ deal.source }}</ItemTitle>\n                      <ItemDescription>Источник</ItemDescription>\n                    </ItemContent>\n                  </Item>\n                </ItemGroup>\n              </CardContent>\n            </Card>\n          </div>\n        </div>\n      </div>\n      <Toaster />\n    </SidebarInset>\n  </SidebarProvider>\n</template>\n"
    }
  ]
}
