{
  "name": "screen-deals",
  "type": "registry:page",
  "dependencies": [
    "@lucide/vue"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "breadcrumb",
    "button",
    "card",
    "checkbox",
    "empty",
    "https://ui.dvizh.website/r/screen-shell.json",
    "input-group",
    "native-select",
    "separator",
    "sidebar",
    "table",
    "tooltip"
  ],
  "files": [
    {
      "path": "screens/deals/DealsScreen.vue",
      "type": "registry:file",
      "target": "screens/deals/DealsScreen.vue",
      "content": "<script setup lang=\"ts\">\n/**\n * Список сделок.\n *\n * Сценарий: утро понедельника, руководитель отдела ищет, где воронка встала. Ему нужно\n * отфильтровать сделки по менеджеру и стадии, увидеть сумму отобранного и провалиться в\n * карточку. Поэтому фильтры и итог по выборке стоят выше таблицы, а не под ней.\n */\nimport { computed, ref } from 'vue'\nimport { ArrowUpDownIcon, DownloadIcon, PlusIcon, SearchIcon, TriangleAlertIcon } from '@lucide/vue'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Badge } from '@/components/ui/badge'\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbList,\n  BreadcrumbPage,\n} from '@/components/ui/breadcrumb'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport {\n  Empty,\n  EmptyDescription,\n  EmptyHeader,\n  EmptyMedia,\n  EmptyTitle,\n} from '@/components/ui/empty'\nimport { InputGroup, InputGroupAddon, InputGroupInput } from '@/components/ui/input-group'\nimport { NativeSelect, NativeSelectOption } from '@/components/ui/native-select'\nimport { Separator } from '@/components/ui/separator'\nimport { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '@/components/ui/table'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'\nimport CrmSidebar from '../CrmSidebar.vue'\nimport { dealRows, managers, stageNames } from '../data'\n\nconst query = ref('')\nconst manager = ref('Все менеджеры')\nconst stage = ref('Все стадии')\nconst sortDesc = ref(true)\nconst selected = ref<number[]>([])\n\nconst riskHint = {\n  overdue: 'Просроченная задача',\n  stuck: 'Пятый день без движения',\n  none: '',\n}\n\nconst visible = computed(() => {\n  const needle = query.value.trim().toLowerCase()\n  const rows = dealRows.filter((row) => {\n    const byText =\n      !needle ||\n      row.title.toLowerCase().includes(needle) ||\n      row.company.toLowerCase().includes(needle)\n    const byManager = manager.value === 'Все менеджеры' || row.owner === manager.value\n    const byStage = stage.value === 'Все стадии' || row.stage === stage.value\n    return byText && byManager && byStage\n  })\n  return [...rows].sort((a, b) => (sortDesc.value ? b.amount - a.amount : a.amount - b.amount))\n})\n\nconst total = computed(() => visible.value.reduce((sum, row) => sum + row.amount, 0))\n\nconst money = new Intl.NumberFormat('ru-RU')\n\nfunction toggle(id: number): void {\n  selected.value = selected.value.includes(id)\n    ? selected.value.filter((item) => item !== id)\n    : [...selected.value, id]\n}\n\nfunction toggleAll(): void {\n  selected.value = selected.value.length === visible.value.length\n    ? []\n    : visible.value.map((row) => row.id)\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><BreadcrumbPage>Сделки</BreadcrumbPage></BreadcrumbItem>\n          </BreadcrumbList>\n        </Breadcrumb>\n        <div class=\"ml-auto flex items-center gap-2\">\n          <Button variant=\"outline\" size=\"sm\">\n            <DownloadIcon />\n            Выгрузить\n          </Button>\n          <Button size=\"sm\">\n            <PlusIcon />\n            Сделка\n          </Button>\n        </div>\n      </header>\n\n      <div class=\"flex flex-1 flex-col gap-4 p-4 lg:p-6\">\n        <Card>\n          <CardHeader>\n            <CardTitle>Воронка на сегодня</CardTitle>\n            <CardDescription>\n              {{ visible.length }} сделок на {{ money.format(total) }} ₽\n              <template v-if=\"selected.length\"> · выбрано {{ selected.length }}</template>\n            </CardDescription>\n          </CardHeader>\n          <CardContent class=\"space-y-4\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <InputGroup class=\"w-full sm:w-72\">\n                <InputGroupAddon><SearchIcon /></InputGroupAddon>\n                <InputGroupInput v-model=\"query\" placeholder=\"Сделка или компания\" />\n              </InputGroup>\n              <NativeSelect v-model=\"manager\" size=\"sm\" class=\"w-48\" aria-label=\"Менеджер\">\n                <NativeSelectOption v-for=\"name in managers\" :key=\"name\" :value=\"name\">\n                  {{ name }}\n                </NativeSelectOption>\n              </NativeSelect>\n              <NativeSelect v-model=\"stage\" size=\"sm\" class=\"w-44\" aria-label=\"Стадия\">\n                <NativeSelectOption value=\"Все стадии\">Все стадии</NativeSelectOption>\n                <NativeSelectOption v-for=\"name in stageNames\" :key=\"name\" :value=\"name\">\n                  {{ name }}\n                </NativeSelectOption>\n              </NativeSelect>\n            </div>\n\n            <Table v-if=\"visible.length\">\n              <TableHeader>\n                <TableRow>\n                  <TableHead class=\"w-10\">\n                    <Checkbox\n                      :model-value=\"\n                        selected.length > 0 && selected.length === visible.length\n                      \"\n                      aria-label=\"Выбрать все\"\n                      @update:model-value=\"toggleAll\"\n                    />\n                  </TableHead>\n                  <TableHead>Сделка</TableHead>\n                  <TableHead class=\"hidden md:table-cell\">Стадия</TableHead>\n                  <TableHead class=\"hidden lg:table-cell\">Менеджер</TableHead>\n                  <TableHead class=\"hidden lg:table-cell\">Изменена</TableHead>\n                  <TableHead class=\"text-right\">\n                    <button\n                      type=\"button\"\n                      class=\"ml-auto inline-flex items-center gap-1\"\n                      @click=\"sortDesc = !sortDesc\"\n                    >\n                      Сумма\n                      <ArrowUpDownIcon class=\"size-3.5\" />\n                    </button>\n                  </TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                <TableRow\n                  v-for=\"row in visible\"\n                  :key=\"row.id\"\n                  :data-state=\"selected.includes(row.id) ? 'selected' : undefined\"\n                >\n                  <TableCell>\n                    <Checkbox\n                      :model-value=\"selected.includes(row.id)\"\n                      :aria-label=\"row.title\"\n                      @update:model-value=\"toggle(row.id)\"\n                    />\n                  </TableCell>\n                  <TableCell>\n                    <div class=\"flex items-center gap-2\">\n                      <RouterLink to=\"/screens/deal\" class=\"font-medium hover:underline\">\n                        {{ row.title }}\n                      </RouterLink>\n                      <Tooltip v-if=\"row.risk !== 'none'\">\n                        <TooltipTrigger as-child>\n                          <TriangleAlertIcon class=\"text-destructive size-4\" />\n                        </TooltipTrigger>\n                        <TooltipContent>{{ riskHint[row.risk] }}</TooltipContent>\n                      </Tooltip>\n                    </div>\n                    <p class=\"text-muted-foreground text-sm\">{{ row.company }}</p>\n                  </TableCell>\n                  <TableCell class=\"hidden md:table-cell\">\n                    <Badge variant=\"secondary\">{{ row.stage }}</Badge>\n                  </TableCell>\n                  <TableCell class=\"hidden lg:table-cell\">\n                    <div class=\"flex items-center gap-2\">\n                      <Avatar class=\"size-6\">\n                        <AvatarFallback class=\"text-xs\">{{ row.initials }}</AvatarFallback>\n                      </Avatar>\n                      <span class=\"text-sm\">{{ row.owner }}</span>\n                    </div>\n                  </TableCell>\n                  <TableCell class=\"text-muted-foreground hidden text-sm lg:table-cell\">\n                    {{ row.updated }}\n                  </TableCell>\n                  <TableCell class=\"text-right font-medium tabular-nums\">\n                    {{ money.format(row.amount) }} ₽\n                  </TableCell>\n                </TableRow>\n              </TableBody>\n            </Table>\n\n            <!-- Пусто после фильтров: подсказываем, что именно снять. -->\n            <Empty v-else>\n              <EmptyHeader>\n                <EmptyMedia variant=\"icon\"><SearchIcon /></EmptyMedia>\n                <EmptyTitle>Под фильтры ничего не попало</EmptyTitle>\n                <EmptyDescription>\n                  Снимите условия по менеджеру или стадии — в воронке есть\n                  {{ dealRows.length }} сделок.\n                </EmptyDescription>\n              </EmptyHeader>\n            </Empty>\n          </CardContent>\n        </Card>\n      </div>\n    </SidebarInset>\n  </SidebarProvider>\n</template>\n"
    }
  ]
}
