@greatapps/common 1.1.396 → 1.1.398
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/modals/PaidPlanRequiredModal.mjs +1 -1
- package/dist/components/modals/PaidPlanRequiredModal.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs +44 -51
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/navigation/ProjectSelectorPopover.tsx +1 -15
- package/src/modules/plans/hooks/use-has-plan-addon.hook.ts +2 -5
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
DialogHeader,
|
|
10
10
|
DialogTitle
|
|
11
11
|
} from "../ui/overlay/Dialog";
|
|
12
|
-
import { useWhitelabelUrls } from "../../
|
|
12
|
+
import { useWhitelabelUrls } from "../../providers/whitelabel.provider";
|
|
13
13
|
import { useModalManager } from "../../store/useModalManager";
|
|
14
14
|
function PaidPlanRequiredModal() {
|
|
15
15
|
const { activeModal, modalData, closeModal } = useModalManager();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/modals/PaidPlanRequiredModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { IconLock } from '@tabler/icons-react';\nimport { Button } from '../ui/buttons/Button';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../ui/overlay/Dialog';\nimport { useWhitelabelUrls } from '../../
|
|
1
|
+
{"version":3,"sources":["../../../src/components/modals/PaidPlanRequiredModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { IconLock } from '@tabler/icons-react';\nimport { Button } from '../ui/buttons/Button';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../ui/overlay/Dialog';\nimport { useWhitelabelUrls } from '../../providers/whitelabel.provider';\nimport { useModalManager } from '../../store/useModalManager';\nimport type { ModalData } from '../../store/useModalManager';\n\nexport default function PaidPlanRequiredModal() {\n const { activeModal, modalData, closeModal } = useModalManager();\n const isOpen = activeModal === 'paidPlanRequiredModal';\n const data = modalData as ModalData & { title?: string; description?: string };\n const { accountsUrl } = useWhitelabelUrls();\n\n const title = (data.title as string) ?? \"Recurso disponível em planos pagos\";\n const description = (data.description as string) ?? \"Para acessar este recurso, faça upgrade para um plano pago\";\n\n const handleKnowPlans = () => {\n closeModal();\n window.open(`${accountsUrl}/signature?tab=plans`, '_blank');\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={() => closeModal()}>\n <DialogContent className=\"flex flex-col p-0 gap-0 w-full md:w-[410px] lg:w-[410px]\">\n <DialogHeader className=\"gap-3 text-left p-5\">\n <div className=\"flex items-center justify-center w-10 h-10 bg-zinc-50 rounded-lg\">\n <IconLock size={24} className=\"text-zinc-950\" />\n </div>\n <div className=\"flex flex-col gap-2\">\n <DialogTitle className=\"paragraph-medium-semibold text-zinc-950\">\n {title}\n </DialogTitle>\n <DialogDescription className=\"paragraph-small-regular text-zinc-600\">\n {description}\n </DialogDescription>\n </div>\n </DialogHeader>\n <div className=\"flex items-center gap-2 p-5 border-t border-zinc-200\">\n <Button\n className=\"w-fit h-10!\"\n onClick={handleKnowPlans}\n >\n Conhecer planos\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AAkCwB,cAEJ,YAFI;AAhCxB,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAGjB,SAAR,wBAAyC;AAC5C,QAAM,EAAE,aAAa,WAAW,WAAW,IAAI,gBAAgB;AAC/D,QAAM,SAAS,gBAAgB;AAC/B,QAAM,OAAO;AACb,QAAM,EAAE,YAAY,IAAI,kBAAkB;AAE1C,QAAM,QAAS,KAAK,SAAoB;AACxC,QAAM,cAAe,KAAK,eAA0B;AAEpD,QAAM,kBAAkB,MAAM;AAC1B,eAAW;AACX,WAAO,KAAK,GAAG,WAAW,wBAAwB,QAAQ;AAAA,EAC9D;AAEA,SACI,oBAAC,UAAO,MAAM,QAAQ,cAAc,MAAM,WAAW,GACjD,+BAAC,iBAAc,WAAU,4DACrB;AAAA,yBAAC,gBAAa,WAAU,uBACpB;AAAA,0BAAC,SAAI,WAAU,oEACX,8BAAC,YAAS,MAAM,IAAI,WAAU,iBAAgB,GAClD;AAAA,MACA,qBAAC,SAAI,WAAU,uBACX;AAAA,4BAAC,eAAY,WAAU,2CAClB,iBACL;AAAA,QACA,oBAAC,qBAAkB,WAAU,yCACxB,uBACL;AAAA,SACJ;AAAA,OACJ;AAAA,IACA,oBAAC,SAAI,WAAU,wDACX;AAAA,MAAC;AAAA;AAAA,QACG,WAAU;AAAA,QACV,SAAS;AAAA,QACZ;AAAA;AAAA,IAED,GACJ;AAAA,KACJ,GACJ;AAER;","names":[]}
|
|
@@ -6,7 +6,6 @@ import { useHasPlanAddon } from "../../../modules/plans/hooks/use-has-plan-addon
|
|
|
6
6
|
import { useMobileNavbarSheet } from "../../../store/useMobileNavbarSheet";
|
|
7
7
|
import { useAppNavigationContext } from "../AppNavigationContext";
|
|
8
8
|
import { ProjectSelectorPopover } from "../ProjectSelectorPopover";
|
|
9
|
-
import { UsersSelectorPopover } from "../../layouts/UsersSelectorPopover";
|
|
10
9
|
import { Button, Command, CommandEmpty, CommandInput, CommandItem, CommandList, UserAvatar } from "../../../index";
|
|
11
10
|
import { IconChevronDown, IconPlus, IconSettings } from "@tabler/icons-react";
|
|
12
11
|
function ProjectItemSkeleton() {
|
|
@@ -39,58 +38,52 @@ function ProjectSelector({
|
|
|
39
38
|
}
|
|
40
39
|
}, [openProjectList, breakpoint, clearProjectList]);
|
|
41
40
|
if (breakpoint === "desktop" || breakpoint === "md") {
|
|
42
|
-
return /* @__PURE__ */
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
),
|
|
70
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(UsersSelectorPopover, { projectId: selectedProject?.id }) })
|
|
71
|
-
] });
|
|
41
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx(
|
|
42
|
+
ProjectSelectorPopover,
|
|
43
|
+
{
|
|
44
|
+
open: isPopoverOpen,
|
|
45
|
+
setOpen: setIsPopoverOpen,
|
|
46
|
+
titleRef,
|
|
47
|
+
projects,
|
|
48
|
+
selectedProject,
|
|
49
|
+
isLoading,
|
|
50
|
+
isFetchingNextPage,
|
|
51
|
+
hasNextPage,
|
|
52
|
+
onLoadMore,
|
|
53
|
+
onSelectProject,
|
|
54
|
+
onAddProject,
|
|
55
|
+
onManageProjects,
|
|
56
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate select-none cursor-pointer", ref: titleRef, children: [
|
|
57
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "skeleton h-4 w-32 rounded" }) : /* @__PURE__ */ jsx("span", { className: "paragraph-medium-semibold text-gray-600 truncate max-w-[120px] inline-block", children: selectedProject?.title }),
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
IconChevronDown,
|
|
60
|
+
{
|
|
61
|
+
size: 20,
|
|
62
|
+
className: `transition-transform duration-200 ${isPopoverOpen ? "rotate-180 text-gray-950" : "text-gray-400"}`
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
] })
|
|
66
|
+
}
|
|
67
|
+
) });
|
|
72
68
|
}
|
|
73
69
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5", children: [
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
children:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
),
|
|
92
|
-
/* @__PURE__ */ jsx(UsersSelectorPopover, { projectId: selectedProject?.id })
|
|
93
|
-
] }),
|
|
70
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs(
|
|
71
|
+
"div",
|
|
72
|
+
{
|
|
73
|
+
className: "flex items-center gap-1 cursor-pointer",
|
|
74
|
+
onClick: () => setActiveSection(activeSection === "projects" ? null : "projects"),
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-medium-semibold text-gray-600", children: selectedProject?.title }),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
IconChevronDown,
|
|
79
|
+
{
|
|
80
|
+
size: 20,
|
|
81
|
+
className: `transition-transform duration-200 ${activeSection === "projects" ? "rotate-180 text-gray-950" : "text-gray-400"}`
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
) }),
|
|
94
87
|
activeSection === "projects" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col p-3 gap-2 border border-gray-200 rounded-lg animate-in fade-in duration-400", children: [
|
|
95
88
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
96
89
|
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold", children: "Projetos" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/navigation/subcomponents/ProjectSelector.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useRef, useEffect, RefObject } from 'react';\nimport { ADDON_IDS } from '../../../modules/subscriptions/constants/addons.constants';\nimport { useHasPlanAddon } from '../../../modules/plans/hooks/use-has-plan-addon.hook';\nimport { useMobileNavbarSheet } from '../../../store/useMobileNavbarSheet';\nimport { useAppNavigationContext } from '../AppNavigationContext';\nimport { ProjectSelectorPopover } from '../ProjectSelectorPopover';\nimport { UsersSelectorPopover } from '../../layouts/UsersSelectorPopover';\nimport { Button, Command, CommandEmpty, CommandInput, CommandItem, CommandList, UserAvatar } from '../../../index';\nimport { IconChevronDown, IconPlus, IconSettings } from '@tabler/icons-react';\nimport type { NavigationProject } from '../types';\n\nexport interface ProjectSelectorProps {\n projects: NavigationProject[];\n selectedProject: NavigationProject | null;\n isLoading?: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void | Promise<unknown>;\n onSelectProject: (project: NavigationProject) => void;\n onAddProject?: () => void;\n onManageProjects?: () => void;\n}\n\nfunction ProjectItemSkeleton() {\n return (\n <div className=\"flex items-center gap-2 p-[8.8px]\">\n <div className=\"skeleton size-9 rounded-lg shrink-0\" />\n <div className=\"skeleton h-4 w-36 rounded\" />\n </div>\n );\n}\n\nexport function ProjectSelector({\n projects,\n selectedProject,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n onSelectProject,\n onAddProject,\n onManageProjects,\n}: ProjectSelectorProps) {\n const { breakpoint } = useAppNavigationContext();\n const { hasAddon: canAddProject } = useHasPlanAddon(ADDON_IDS.PROJECTS);\n const [isPopoverOpen, setIsPopoverOpen] = useState(false);\n const [activeSection, setActiveSection] = useState<'projects' | null>(null);\n const titleRef = useRef<HTMLDivElement>(null);\n const { openProjectList, clearProjectList } = useMobileNavbarSheet();\n\n useEffect(() => {\n if (openProjectList && breakpoint === 'mobile') {\n setActiveSection('projects');\n clearProjectList();\n }\n }, [openProjectList, breakpoint, clearProjectList]);\n\n // Desktop and md: title + popover + users selector (same visual as current gpages sidebars)\n if (breakpoint === 'desktop' || breakpoint === 'md') {\n return (\n <div className=\"flex items-center justify-between\">\n <ProjectSelectorPopover\n open={isPopoverOpen}\n setOpen={setIsPopoverOpen}\n titleRef={titleRef as unknown as RefObject<HTMLSpanElement | null>}\n projects={projects}\n selectedProject={selectedProject}\n isLoading={isLoading}\n isFetchingNextPage={isFetchingNextPage}\n hasNextPage={hasNextPage}\n onLoadMore={onLoadMore}\n onSelectProject={onSelectProject}\n onAddProject={onAddProject}\n onManageProjects={onManageProjects}\n >\n <div className=\"flex items-center gap-2 truncate select-none cursor-pointer\" ref={titleRef}>\n {isLoading ? (\n <div className=\"skeleton h-4 w-32 rounded\" />\n ) : (\n <span className=\"paragraph-medium-semibold text-gray-600 truncate max-w-[120px] inline-block\">\n {selectedProject?.title}\n </span>\n )}\n <IconChevronDown\n size={20}\n className={`transition-transform duration-200 ${isPopoverOpen ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}\n />\n </div>\n </ProjectSelectorPopover>\n <div className=\"flex items-center gap-2\">\n <UsersSelectorPopover projectId={selectedProject?.id} />\n </div>\n </div>\n );\n }\n\n // Mobile: inline collapsible accordion\n return (\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-center justify-between\">\n <div\n className=\"flex items-center gap-1 cursor-pointer\"\n onClick={() => setActiveSection(activeSection === 'projects' ? null : 'projects')}\n >\n <span className=\"paragraph-medium-semibold text-gray-600\">{selectedProject?.title}</span>\n <IconChevronDown\n size={20}\n className={`transition-transform duration-200 ${\n activeSection === 'projects' ? 'rotate-180 text-gray-950' : 'text-gray-400'\n }`}\n />\n </div>\n <UsersSelectorPopover projectId={selectedProject?.id} />\n </div>\n {activeSection === 'projects' && (\n <div className=\"flex flex-col p-3 gap-2 border border-gray-200 rounded-lg animate-in fade-in duration-400\">\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-semibold\">Projetos</span>\n {(onAddProject || onManageProjects) && (\n <div className=\"flex items-center gap-1.5\">\n {canAddProject && onAddProject && (\n <Button variant=\"secondary\" className=\"h-8! paragraph-small-semibold text-gray-950\" onClick={onAddProject}>\n <IconPlus size={16} />\n Adicionar\n </Button>\n )}\n {onManageProjects && (\n <Button variant=\"secondary\" className=\"p-0 size-8\" onClick={onManageProjects}>\n <IconSettings size={18} />\n </Button>\n )}\n </div>\n )}\n </div>\n <Command className=\"gap-2\">\n <CommandInput placeholder=\"Busque aqui\" />\n <CommandList\n className=\"custom-scrollbar paragraph-small-medium text-gray-600 h-[227px]\"\n onScroll={(event) => {\n if (!hasNextPage || isFetchingNextPage || !onLoadMore) return;\n\n const target = event.currentTarget;\n const distanceToBottom = target.scrollHeight - target.scrollTop - target.clientHeight;\n\n if (distanceToBottom <= 80) {\n onLoadMore();\n }\n }}\n >\n <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>\n {isLoading ? (\n <>\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n </>\n ) : (\n projects.map((project) => (\n <CommandItem\n key={project.id}\n value={`${project.title}-${project.id}`}\n keywords={[project.title]}\n className={selectedProject?.id === project.id ? 'bg-gray-50 min-h-[39px]' : 'min-h-[39px]'}\n onSelect={() => { onSelectProject(project); setActiveSection(null); }}\n >\n <UserAvatar\n photo={project.photo}\n name={project.title}\n size={36}\n />\n {project.title}\n </CommandItem>\n ))\n )}\n {isFetchingNextPage && (\n <>\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n </>\n )}\n </CommandList>\n </Command>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/navigation/subcomponents/ProjectSelector.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useRef, useEffect, RefObject } from 'react';\nimport { ADDON_IDS } from '../../../modules/subscriptions/constants/addons.constants';\nimport { useHasPlanAddon } from '../../../modules/plans/hooks/use-has-plan-addon.hook';\nimport { useMobileNavbarSheet } from '../../../store/useMobileNavbarSheet';\nimport { useAppNavigationContext } from '../AppNavigationContext';\nimport { ProjectSelectorPopover } from '../ProjectSelectorPopover';\nimport { Button, Command, CommandEmpty, CommandInput, CommandItem, CommandList, UserAvatar } from '../../../index';\nimport { IconChevronDown, IconPlus, IconSettings } from '@tabler/icons-react';\nimport type { NavigationProject } from '../types';\n\nexport interface ProjectSelectorProps {\n projects: NavigationProject[];\n selectedProject: NavigationProject | null;\n isLoading?: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n onLoadMore?: () => void | Promise<unknown>;\n onSelectProject: (project: NavigationProject) => void;\n onAddProject?: () => void;\n onManageProjects?: () => void;\n}\n\nfunction ProjectItemSkeleton() {\n return (\n <div className=\"flex items-center gap-2 p-[8.8px]\">\n <div className=\"skeleton size-9 rounded-lg shrink-0\" />\n <div className=\"skeleton h-4 w-36 rounded\" />\n </div>\n );\n}\n\nexport function ProjectSelector({\n projects,\n selectedProject,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n onLoadMore,\n onSelectProject,\n onAddProject,\n onManageProjects,\n}: ProjectSelectorProps) {\n const { breakpoint } = useAppNavigationContext();\n const { hasAddon: canAddProject } = useHasPlanAddon(ADDON_IDS.PROJECTS);\n const [isPopoverOpen, setIsPopoverOpen] = useState(false);\n const [activeSection, setActiveSection] = useState<'projects' | null>(null);\n const titleRef = useRef<HTMLDivElement>(null);\n const { openProjectList, clearProjectList } = useMobileNavbarSheet();\n\n useEffect(() => {\n if (openProjectList && breakpoint === 'mobile') {\n setActiveSection('projects');\n clearProjectList();\n }\n }, [openProjectList, breakpoint, clearProjectList]);\n\n // Desktop and md: title + popover + users selector (same visual as current gpages sidebars)\n if (breakpoint === 'desktop' || breakpoint === 'md') {\n return (\n <div className=\"flex items-center justify-between\">\n <ProjectSelectorPopover\n open={isPopoverOpen}\n setOpen={setIsPopoverOpen}\n titleRef={titleRef as unknown as RefObject<HTMLSpanElement | null>}\n projects={projects}\n selectedProject={selectedProject}\n isLoading={isLoading}\n isFetchingNextPage={isFetchingNextPage}\n hasNextPage={hasNextPage}\n onLoadMore={onLoadMore}\n onSelectProject={onSelectProject}\n onAddProject={onAddProject}\n onManageProjects={onManageProjects}\n >\n <div className=\"flex items-center gap-2 truncate select-none cursor-pointer\" ref={titleRef}>\n {isLoading ? (\n <div className=\"skeleton h-4 w-32 rounded\" />\n ) : (\n <span className=\"paragraph-medium-semibold text-gray-600 truncate max-w-[120px] inline-block\">\n {selectedProject?.title}\n </span>\n )}\n <IconChevronDown\n size={20}\n className={`transition-transform duration-200 ${isPopoverOpen ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}\n />\n </div>\n </ProjectSelectorPopover>\n </div>\n );\n }\n\n // Mobile: inline collapsible accordion\n return (\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-center justify-between\">\n <div\n className=\"flex items-center gap-1 cursor-pointer\"\n onClick={() => setActiveSection(activeSection === 'projects' ? null : 'projects')}\n >\n <span className=\"paragraph-medium-semibold text-gray-600\">{selectedProject?.title}</span>\n <IconChevronDown\n size={20}\n className={`transition-transform duration-200 ${\n activeSection === 'projects' ? 'rotate-180 text-gray-950' : 'text-gray-400'\n }`}\n />\n </div>\n </div>\n {activeSection === 'projects' && (\n <div className=\"flex flex-col p-3 gap-2 border border-gray-200 rounded-lg animate-in fade-in duration-400\">\n <div className=\"flex items-center justify-between\">\n <span className=\"paragraph-small-semibold\">Projetos</span>\n {(onAddProject || onManageProjects) && (\n <div className=\"flex items-center gap-1.5\">\n {canAddProject && onAddProject && (\n <Button variant=\"secondary\" className=\"h-8! paragraph-small-semibold text-gray-950\" onClick={onAddProject}>\n <IconPlus size={16} />\n Adicionar\n </Button>\n )}\n {onManageProjects && (\n <Button variant=\"secondary\" className=\"p-0 size-8\" onClick={onManageProjects}>\n <IconSettings size={18} />\n </Button>\n )}\n </div>\n )}\n </div>\n <Command className=\"gap-2\">\n <CommandInput placeholder=\"Busque aqui\" />\n <CommandList\n className=\"custom-scrollbar paragraph-small-medium text-gray-600 h-[227px]\"\n onScroll={(event) => {\n if (!hasNextPage || isFetchingNextPage || !onLoadMore) return;\n\n const target = event.currentTarget;\n const distanceToBottom = target.scrollHeight - target.scrollTop - target.clientHeight;\n\n if (distanceToBottom <= 80) {\n onLoadMore();\n }\n }}\n >\n <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>\n {isLoading ? (\n <>\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n </>\n ) : (\n projects.map((project) => (\n <CommandItem\n key={project.id}\n value={`${project.title}-${project.id}`}\n keywords={[project.title]}\n className={selectedProject?.id === project.id ? 'bg-gray-50 min-h-[39px]' : 'min-h-[39px]'}\n onSelect={() => { onSelectProject(project); setActiveSection(null); }}\n >\n <UserAvatar\n photo={project.photo}\n name={project.title}\n size={36}\n />\n {project.title}\n </CommandItem>\n ))\n )}\n {isFetchingNextPage && (\n <>\n <ProjectItemSkeleton />\n <ProjectItemSkeleton />\n </>\n )}\n </CommandList>\n </Command>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
PopoverTrigger,
|
|
14
14
|
UserAvatar,
|
|
15
15
|
} from '../../index';
|
|
16
|
-
import { IconCheck, IconChevronDown, IconFolderOpen
|
|
16
|
+
import { IconCheck, IconChevronDown, IconFolderOpen } from '@tabler/icons-react';
|
|
17
17
|
import type { NavigationProject } from './types';
|
|
18
18
|
|
|
19
19
|
interface ProjectSelectorPopoverProps {
|
|
@@ -96,20 +96,6 @@ export function ProjectSelectorPopover({
|
|
|
96
96
|
<div className="flex flex-col p-3 gap-2">
|
|
97
97
|
<div className="flex items-center justify-between">
|
|
98
98
|
<span className="paragraph-small-semibold">Projetos</span>
|
|
99
|
-
{(onAddProject || onManageProjects) && (
|
|
100
|
-
<div className="flex items-center gap-1.5">
|
|
101
|
-
{onAddProject && (
|
|
102
|
-
<Button
|
|
103
|
-
variant="secondary"
|
|
104
|
-
className="h-8! paragraph-small-semibold text-gray-950"
|
|
105
|
-
onClick={onAddProject}
|
|
106
|
-
>
|
|
107
|
-
<IconPlus size={16} />
|
|
108
|
-
Adicionar
|
|
109
|
-
</Button>
|
|
110
|
-
)}
|
|
111
|
-
</div>
|
|
112
|
-
)}
|
|
113
99
|
</div>
|
|
114
100
|
<Command className="gap-2">
|
|
115
101
|
<CommandInput placeholder="Busque aqui" />
|
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import type { AddonKindEnum } from '../../subscriptions/constants/addons.constants';
|
|
4
4
|
import { useActiveSubscription } from '../../subscriptions/hooks/find-active-subscription.hook';
|
|
5
|
-
import { usePlanById } from './use-plan-by-id.hook';
|
|
6
5
|
|
|
7
6
|
export function useHasPlanAddon(addonId: AddonKindEnum) {
|
|
8
7
|
const { data: subscriptionData, isLoading: isLoadingSubscription } = useActiveSubscription();
|
|
9
8
|
const activeSubscription = subscriptionData?.data?.[0] ?? null;
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const hasAddon = !!planData?.data?.items?.some((i) => i.id_addon === addonId);
|
|
14
|
-
const isLoading = isLoadingSubscription || isLoadingPlan;
|
|
10
|
+
const hasAddon = !!activeSubscription?.items?.find((i) => i.id_addon === addonId);
|
|
11
|
+
const isLoading = isLoadingSubscription;
|
|
15
12
|
|
|
16
13
|
return { hasAddon, isLoading };
|
|
17
14
|
}
|