@greatapps/common 1.1.5 → 1.1.7

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.
Files changed (40) hide show
  1. package/dist/components/layouts/ProfilePopover.mjs +18 -10
  2. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  3. package/dist/components/ui/data-display/UserAvatar.mjs +3 -3
  4. package/dist/components/ui/data-display/UserAvatar.mjs.map +1 -1
  5. package/dist/index.mjs +4 -0
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/modules/auth/utils/get-user-context.mjs +24 -0
  8. package/dist/modules/auth/utils/get-user-context.mjs.map +1 -0
  9. package/dist/modules/ia-credits/actions/list-ia-credits.action.mjs +9 -0
  10. package/dist/modules/ia-credits/actions/list-ia-credits.action.mjs.map +1 -0
  11. package/dist/modules/ia-credits/hooks/ia-credits.hook.mjs +75 -0
  12. package/dist/modules/ia-credits/hooks/ia-credits.hook.mjs.map +1 -0
  13. package/dist/modules/ia-credits/services/ia-credits.service.mjs +31 -0
  14. package/dist/modules/ia-credits/services/ia-credits.service.mjs.map +1 -0
  15. package/dist/modules/ia-credits/types.mjs +25 -0
  16. package/dist/modules/ia-credits/types.mjs.map +1 -0
  17. package/dist/modules/subscriptions/actions/list-subscriptions.action.mjs +9 -0
  18. package/dist/modules/subscriptions/actions/list-subscriptions.action.mjs.map +1 -0
  19. package/dist/modules/subscriptions/hooks/list-subscriptions.hook.mjs +14 -0
  20. package/dist/modules/subscriptions/hooks/list-subscriptions.hook.mjs.map +1 -0
  21. package/dist/modules/subscriptions/services/subscriptions.service.mjs +32 -0
  22. package/dist/modules/subscriptions/services/subscriptions.service.mjs.map +1 -0
  23. package/dist/modules/subscriptions/types.mjs +12 -0
  24. package/dist/modules/subscriptions/types.mjs.map +1 -0
  25. package/dist/server.mjs +10 -0
  26. package/dist/server.mjs.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/layouts/ProfilePopover.tsx +23 -11
  29. package/src/components/ui/data-display/UserAvatar.tsx +3 -3
  30. package/src/index.ts +4 -0
  31. package/src/modules/auth/utils/get-user-context.ts +29 -0
  32. package/src/modules/ia-credits/actions/list-ia-credits.action.ts +11 -0
  33. package/src/modules/ia-credits/hooks/ia-credits.hook.ts +96 -0
  34. package/src/modules/ia-credits/services/ia-credits.service.ts +37 -0
  35. package/src/modules/ia-credits/types.ts +33 -0
  36. package/src/modules/subscriptions/actions/list-subscriptions.action.ts +11 -0
  37. package/src/modules/subscriptions/hooks/list-subscriptions.hook.ts +14 -0
  38. package/src/modules/subscriptions/services/subscriptions.service.ts +38 -0
  39. package/src/modules/subscriptions/types.ts +17 -0
  40. package/src/server.ts +5 -0
@@ -11,21 +11,21 @@ import { NavBarItem } from "./NavBarItem";
11
11
  import { UserAvatar } from "../ui/data-display/UserAvatar";
12
12
  import { useAuth } from "../../providers/auth.provider";
13
13
  import { cn } from "../../infra/utils/clsx";
14
+ import { useIaCredits } from "../../modules/ia-credits/hooks/ia-credits.hook";
14
15
  function ProfilePopover({
15
16
  side = "top",
16
17
  align = "start",
17
18
  contentClassName = "absolute bottom-2 left-[26px]",
18
19
  onEditProfile,
19
- credits,
20
20
  onCreditsClick,
21
21
  menuItems = [],
22
22
  logoutRedirect = "/login",
23
- storageUrl,
24
23
  logoutOverlay
25
24
  }) {
26
25
  const router = useRouter();
27
26
  const { user, logout } = useAuth();
28
27
  const [isLoggingOut, setIsLoggingOut] = useState(false);
28
+ const { summary, subscription, isSubscriptionLoading, isCreditsLoading } = useIaCredits();
29
29
  const handleLogout = async () => {
30
30
  try {
31
31
  setIsLoggingOut(true);
@@ -37,7 +37,10 @@ function ProfilePopover({
37
37
  setIsLoggingOut(false);
38
38
  }
39
39
  };
40
- const creditsPercentage = credits && credits.total > 0 ? credits.used / credits.total * 100 : 0;
40
+ const hasSubscription = !isSubscriptionLoading && subscription !== null;
41
+ const showCreditsSkeleton = hasSubscription && isCreditsLoading;
42
+ const showCredits = hasSubscription && !isCreditsLoading && summary.totalCredits > 0;
43
+ const creditsPercentage = showCredits && summary.totalCredits > 0 ? summary.usedCredits / summary.totalCredits * 100 : 0;
41
44
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42
45
  isLoggingOut && logoutOverlay,
43
46
  /* @__PURE__ */ jsxs(Popover, { children: [
@@ -46,8 +49,7 @@ function ProfilePopover({
46
49
  {
47
50
  photo: user.photo,
48
51
  name: user.name,
49
- size: 40,
50
- storageUrl
52
+ size: 40
51
53
  },
52
54
  user.id
53
55
  ) }),
@@ -68,8 +70,7 @@ function ProfilePopover({
68
70
  {
69
71
  photo: user.photo,
70
72
  name: user.name,
71
- size: 32,
72
- storageUrl
73
+ size: 32
73
74
  },
74
75
  user.id
75
76
  ),
@@ -88,7 +89,14 @@ function ProfilePopover({
88
89
  )
89
90
  ] }),
90
91
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5", children: [
91
- credits && /* @__PURE__ */ jsxs(
92
+ showCreditsSkeleton && /* @__PURE__ */ jsxs("div", { className: "flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4", children: [
93
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
94
+ /* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-semibold text-white truncate", children: "Cr\xE9ditos usados" }),
95
+ /* @__PURE__ */ jsx("div", { className: "h-3.5 w-16 rounded bg-white/20 animate-pulse" })
96
+ ] }),
97
+ /* @__PURE__ */ jsx("div", { className: "h-1.5 w-full rounded-full bg-white/20 animate-pulse" })
98
+ ] }),
99
+ showCredits && /* @__PURE__ */ jsxs(
92
100
  "div",
93
101
  {
94
102
  className: cn(
@@ -100,9 +108,9 @@ function ProfilePopover({
100
108
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
101
109
  /* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-semibold text-white truncate", children: "Cr\xE9ditos usados" }),
102
110
  /* @__PURE__ */ jsxs("span", { className: "paragraph-xsmall-medium text-white/50", children: [
103
- credits.used.toLocaleString("pt-BR"),
111
+ summary.usedCredits.toLocaleString("pt-BR"),
104
112
  "/",
105
- credits.total.toLocaleString("pt-BR")
113
+ summary.totalCredits.toLocaleString("pt-BR")
106
114
  ] })
107
115
  ] }),
108
116
  /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/layouts/ProfilePopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\r\nimport { Popover } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Progress } from '../ui/feedback/Progress';\r\nimport { Separator } from '../ui/data-display/Separator';\r\nimport { NavBarItem } from './NavBarItem';\r\nimport { UserAvatar } from '../ui/data-display/UserAvatar';\r\nimport { useAuth } from '../../providers/auth.provider';\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\nexport interface ProfileMenuItem {\r\n icon?: React.ReactNode;\r\n label: string;\r\n onClick: () => void;\r\n}\r\n\r\nexport interface ProfilePopoverProps {\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n onEditProfile?: () => void;\r\n credits?: { used: number; total: number };\r\n onCreditsClick?: () => void;\r\n menuItems?: ProfileMenuItem[];\r\n logoutRedirect?: string;\r\n storageUrl?: string;\r\n logoutOverlay?: React.ReactNode;\r\n}\r\n\r\nfunction ProfilePopover({\r\n side = 'top',\r\n align = 'start',\r\n contentClassName = 'absolute bottom-2 left-[26px]',\r\n onEditProfile,\r\n credits,\r\n onCreditsClick,\r\n menuItems = [],\r\n logoutRedirect = '/login',\r\n storageUrl,\r\n logoutOverlay,\r\n}: ProfilePopoverProps) {\r\n const router = useRouter();\r\n const { user, logout } = useAuth();\r\n const [isLoggingOut, setIsLoggingOut] = useState(false);\r\n\r\n const handleLogout = async () => {\r\n try {\r\n setIsLoggingOut(true);\r\n await logout();\r\n router.push(logoutRedirect);\r\n } catch (error) {\r\n console.error('Erro ao fazer logout:', error);\r\n } finally {\r\n setIsLoggingOut(false);\r\n }\r\n };\r\n\r\n const creditsPercentage =\r\n credits && credits.total > 0\r\n ? (credits.used / credits.total) * 100\r\n : 0;\r\n\r\n return (\r\n <>\r\n {isLoggingOut && logoutOverlay}\r\n <Popover>\r\n <PopoverPrimitive.Trigger className=\"cursor-pointer\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={40}\r\n storageUrl={storageUrl}\r\n />\r\n )}\r\n </PopoverPrimitive.Trigger>\r\n\r\n <PopoverPrimitive.Portal>\r\n <PopoverPrimitive.Content\r\n className={cn(\r\n 'w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={32}\r\n storageUrl={storageUrl}\r\n />\r\n )}\r\n\r\n <div className=\"flex flex-col gap-0.5 min-w-0\">\r\n <span className=\"paragraph-small-semibold text-gray-950 truncate\">\r\n {user?.name || ''}\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-gray-500 truncate\">\r\n {user?.email || ''}\r\n </span>\r\n </div>\r\n\r\n {onEditProfile && (\r\n <Button\r\n variant=\"secondary\"\r\n className=\"paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit\"\r\n onClick={onEditProfile}\r\n >\r\n Editar Perfil\r\n </Button>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5\">\r\n {credits && (\r\n <div\r\n className={cn(\r\n 'flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors',\r\n onCreditsClick && 'cursor-pointer hover:bg-gray-900'\r\n )}\r\n onClick={onCreditsClick}\r\n >\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-white/50\">\r\n {credits.used.toLocaleString('pt-BR')}/\r\n {credits.total.toLocaleString('pt-BR')}\r\n </span>\r\n </div>\r\n <Progress\r\n className=\"bg-white/10\"\r\n indicatorColor=\"bg-white\"\r\n value={creditsPercentage}\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"flex flex-col gap-2\">\r\n {menuItems.length > 0 && (\r\n <div className=\"flex flex-col\">\r\n {menuItems.map((item, index) => (\r\n <NavBarItem\r\n key={index}\r\n icon={item.icon}\r\n label={item.label}\r\n onClick={item.onClick}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n <Separator />\r\n <NavBarItem label=\"Sair\" onClick={handleLogout} />\r\n </div>\r\n </div>\r\n </PopoverPrimitive.Content>\r\n </PopoverPrimitive.Portal>\r\n </Popover>\r\n </>\r\n );\r\n}\r\n\r\nexport { ProfilePopover };\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/layouts/ProfilePopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport * as PopoverPrimitive from '@radix-ui/react-popover';\r\nimport { Popover } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Progress } from '../ui/feedback/Progress';\r\nimport { Separator } from '../ui/data-display/Separator';\r\nimport { NavBarItem } from './NavBarItem';\r\nimport { UserAvatar } from '../ui/data-display/UserAvatar';\r\nimport { useAuth } from '../../providers/auth.provider';\r\nimport { cn } from '../../infra/utils/clsx';\r\nimport { useIaCredits } from '../../modules/ia-credits/hooks/ia-credits.hook';\r\n\r\nexport interface ProfileMenuItem {\r\n icon?: React.ReactNode;\r\n label: string;\r\n onClick: () => void;\r\n}\r\n\r\nexport interface ProfilePopoverProps {\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n onEditProfile?: () => void;\r\n onCreditsClick?: () => void;\r\n menuItems?: ProfileMenuItem[];\r\n logoutRedirect?: string;\r\n logoutOverlay?: React.ReactNode;\r\n}\r\n\r\nfunction ProfilePopover({\r\n side = 'top',\r\n align = 'start',\r\n contentClassName = 'absolute bottom-2 left-[26px]',\r\n onEditProfile,\r\n onCreditsClick,\r\n menuItems = [],\r\n logoutRedirect = '/login',\r\n logoutOverlay,\r\n}: ProfilePopoverProps) {\r\n const router = useRouter();\r\n const { user, logout } = useAuth();\r\n const [isLoggingOut, setIsLoggingOut] = useState(false);\r\n\r\n const { summary, subscription, isSubscriptionLoading, isCreditsLoading } = useIaCredits();\r\n\r\n const handleLogout = async () => {\r\n try {\r\n setIsLoggingOut(true);\r\n await logout();\r\n router.push(logoutRedirect);\r\n } catch (error) {\r\n console.error('Erro ao fazer logout:', error);\r\n } finally {\r\n setIsLoggingOut(false);\r\n }\r\n };\r\n\r\n const hasSubscription = !isSubscriptionLoading && subscription !== null;\r\n const showCreditsSkeleton = hasSubscription && isCreditsLoading;\r\n const showCredits = hasSubscription && !isCreditsLoading && summary.totalCredits > 0;\r\n const creditsPercentage =\r\n showCredits && summary.totalCredits > 0\r\n ? (summary.usedCredits / summary.totalCredits) * 100\r\n : 0;\r\n\r\n return (\r\n <>\r\n {isLoggingOut && logoutOverlay}\r\n <Popover>\r\n <PopoverPrimitive.Trigger className=\"cursor-pointer\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={40}\r\n />\r\n )}\r\n </PopoverPrimitive.Trigger>\r\n\r\n <PopoverPrimitive.Portal>\r\n <PopoverPrimitive.Content\r\n className={cn(\r\n 'w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={32}\r\n />\r\n )}\r\n\r\n <div className=\"flex flex-col gap-0.5 min-w-0\">\r\n <span className=\"paragraph-small-semibold text-gray-950 truncate\">\r\n {user?.name || ''}\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-gray-500 truncate\">\r\n {user?.email || ''}\r\n </span>\r\n </div>\r\n\r\n {onEditProfile && (\r\n <Button\r\n variant=\"secondary\"\r\n className=\"paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit\"\r\n onClick={onEditProfile}\r\n >\r\n Editar Perfil\r\n </Button>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5\">\r\n {showCreditsSkeleton && (\r\n <div className=\"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4\">\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <div className=\"h-3.5 w-16 rounded bg-white/20 animate-pulse\" />\r\n </div>\r\n <div className=\"h-1.5 w-full rounded-full bg-white/20 animate-pulse\" />\r\n </div>\r\n )}\r\n\r\n {showCredits && (\r\n <div\r\n className={cn(\r\n 'flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors',\r\n onCreditsClick && 'cursor-pointer hover:bg-gray-900'\r\n )}\r\n onClick={onCreditsClick}\r\n >\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-white/50\">\r\n {summary.usedCredits.toLocaleString('pt-BR')}/\r\n {summary.totalCredits.toLocaleString('pt-BR')}\r\n </span>\r\n </div>\r\n <Progress\r\n className=\"bg-white/10\"\r\n indicatorColor=\"bg-white\"\r\n value={creditsPercentage}\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"flex flex-col gap-2\">\r\n {menuItems.length > 0 && (\r\n <div className=\"flex flex-col\">\r\n {menuItems.map((item, index) => (\r\n <NavBarItem\r\n key={index}\r\n icon={item.icon}\r\n label={item.label}\r\n onClick={item.onClick}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n <Separator />\r\n <NavBarItem label=\"Sair\" onClick={handleLogout} />\r\n </div>\r\n </div>\r\n </PopoverPrimitive.Content>\r\n </PopoverPrimitive.Portal>\r\n </Popover>\r\n </>\r\n );\r\n}\r\n\r\nexport { ProfilePopover };\r\n"],"mappings":"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","names":[]}
@@ -5,18 +5,18 @@ import { cn } from "../../../infra/utils/clsx";
5
5
  function getInitials(name, maxLength = 2) {
6
6
  return name.split(" ").map((n) => n[0]).join("").slice(0, maxLength).toUpperCase();
7
7
  }
8
+ const STORAGE_URL = process.env.NEXT_PUBLIC_STORAGE_URL || "";
8
9
  function UserAvatar({
9
10
  photo,
10
11
  name,
11
12
  initials,
12
13
  size = 32,
13
14
  shape = "circle",
14
- className,
15
- storageUrl
15
+ className
16
16
  }) {
17
17
  const shapeClass = shape === "circle" ? "rounded-full" : "rounded-lg";
18
18
  const displayInitials = initials || (name ? getInitials(name) : "?");
19
- const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;
19
+ const photoUrl = STORAGE_URL && photo ? `${STORAGE_URL}/${photo}` : photo;
20
20
  if (photoUrl) {
21
21
  return /* @__PURE__ */ jsx(
22
22
  Image,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/ui/data-display/UserAvatar.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport Image from 'next/image';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\nfunction getInitials(name: string, maxLength: number = 2): string {\r\n return name\r\n .split(' ')\r\n .map((n) => n[0])\r\n .join('')\r\n .slice(0, maxLength)\r\n .toUpperCase();\r\n}\r\n\r\ninterface UserAvatarProps {\r\n photo?: string | null;\r\n name?: string;\r\n initials?: string;\r\n size?: number;\r\n shape?: 'circle' | 'square';\r\n className?: string;\r\n storageUrl?: string;\r\n}\r\n\r\nfunction UserAvatar({\r\n photo,\r\n name,\r\n initials,\r\n size = 32,\r\n shape = 'circle',\r\n className,\r\n storageUrl,\r\n}: UserAvatarProps) {\r\n const shapeClass = shape === 'circle' ? 'rounded-full' : 'rounded-lg';\r\n const displayInitials = initials || (name ? getInitials(name) : '?');\r\n\r\n const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;\r\n\r\n if (photoUrl) {\r\n return (\r\n <Image\r\n alt={name || 'imagem do usuario'}\r\n src={photoUrl}\r\n width={size}\r\n height={size}\r\n className={cn('object-cover shrink-0', shapeClass, className)}\r\n style={{ width: size, height: size }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n 'flex items-center justify-center shrink-0 bg-gray-100',\r\n shapeClass,\r\n className\r\n )}\r\n style={{ width: size, height: size }}\r\n >\r\n <span className=\"text-xs font-semibold text-gray-700\">{displayInitials}</span>\r\n </div>\r\n );\r\n}\r\n\r\nexport { UserAvatar };\r\nexport type { UserAvatarProps };\r\n"],"mappings":";AAwCM;AAtCN,OAAO,WAAW;AAClB,SAAS,UAAU;AAEnB,SAAS,YAAY,MAAc,YAAoB,GAAW;AAChE,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,EAAE,EACP,MAAM,GAAG,SAAS,EAClB,YAAY;AACjB;AAYA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,aAAa,UAAU,WAAW,iBAAiB;AACzD,QAAM,kBAAkB,aAAa,OAAO,YAAY,IAAI,IAAI;AAEhE,QAAM,WAAW,cAAc,QAAQ,GAAG,UAAU,IAAI,KAAK,KAAK;AAElE,MAAI,UAAU;AACZ,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,QAAQ;AAAA,QACb,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW,GAAG,yBAAyB,YAAY,SAAS;AAAA,QAC5D,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA;AAAA,IACrC;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,MAEnC,8BAAC,UAAK,WAAU,uCAAuC,2BAAgB;AAAA;AAAA,EACzE;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/components/ui/data-display/UserAvatar.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport Image from 'next/image';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\nfunction getInitials(name: string, maxLength: number = 2): string {\r\n return name\r\n .split(' ')\r\n .map((n) => n[0])\r\n .join('')\r\n .slice(0, maxLength)\r\n .toUpperCase();\r\n}\r\n\r\nconst STORAGE_URL = process.env.NEXT_PUBLIC_STORAGE_URL || '';\r\n\r\ninterface UserAvatarProps {\r\n photo?: string | null;\r\n name?: string;\r\n initials?: string;\r\n size?: number;\r\n shape?: 'circle' | 'square';\r\n className?: string;\r\n}\r\n\r\nfunction UserAvatar({\r\n photo,\r\n name,\r\n initials,\r\n size = 32,\r\n shape = 'circle',\r\n className,\r\n}: UserAvatarProps) {\r\n const shapeClass = shape === 'circle' ? 'rounded-full' : 'rounded-lg';\r\n const displayInitials = initials || (name ? getInitials(name) : '?');\r\n\r\n const photoUrl = STORAGE_URL && photo ? `${STORAGE_URL}/${photo}` : photo;\r\n\r\n if (photoUrl) {\r\n return (\r\n <Image\r\n alt={name || 'imagem do usuario'}\r\n src={photoUrl}\r\n width={size}\r\n height={size}\r\n className={cn('object-cover shrink-0', shapeClass, className)}\r\n style={{ width: size, height: size }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n 'flex items-center justify-center shrink-0 bg-gray-100',\r\n shapeClass,\r\n className\r\n )}\r\n style={{ width: size, height: size }}\r\n >\r\n <span className=\"text-xs font-semibold text-gray-700\">{displayInitials}</span>\r\n </div>\r\n );\r\n}\r\n\r\nexport { UserAvatar };\r\nexport type { UserAvatarProps };\r\n"],"mappings":";AAwCM;AAtCN,OAAO,WAAW;AAClB,SAAS,UAAU;AAEnB,SAAS,YAAY,MAAc,YAAoB,GAAW;AAChE,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,EAAE,EACP,MAAM,GAAG,SAAS,EAClB,YAAY;AACjB;AAEA,MAAM,cAAc,QAAQ,IAAI,2BAA2B;AAW3D,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AACF,GAAoB;AAClB,QAAM,aAAa,UAAU,WAAW,iBAAiB;AACzD,QAAM,kBAAkB,aAAa,OAAO,YAAY,IAAI,IAAI;AAEhE,QAAM,WAAW,eAAe,QAAQ,GAAG,WAAW,IAAI,KAAK,KAAK;AAEpE,MAAI,UAAU;AACZ,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,QAAQ;AAAA,QACb,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW,GAAG,yBAAyB,YAAY,SAAS;AAAA,QAC5D,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA;AAAA,IACrC;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,MAEnC,8BAAC,UAAK,WAAU,uCAAuC,2BAAgB;AAAA;AAAA,EACzE;AAEJ;","names":[]}
package/dist/index.mjs CHANGED
@@ -6,6 +6,8 @@ export * from "./providers/query.provider";
6
6
  export * from "./providers/auth.provider";
7
7
  export * from "./providers/whitelabel.provider";
8
8
  import { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from "./modules/auth/hooks/useUserQuery";
9
+ import { useActiveSubscription } from "./modules/subscriptions/hooks/list-subscriptions.hook";
10
+ import { useIaCredits } from "./modules/ia-credits/hooks/ia-credits.hook";
9
11
  import { QueryProvider } from "./providers/query.provider";
10
12
  import { createAuthMiddleware } from "./middlewares/create-auth-middleware";
11
13
  import { createMiddlewareChain } from "./middlewares/chain";
@@ -179,6 +181,8 @@ export {
179
181
  stopChain,
180
182
  toastIconContainerVariants,
181
183
  toastVariants,
184
+ useActiveSubscription,
185
+ useIaCredits,
182
186
  useInvalidateUser,
183
187
  useMdSidebarStore,
184
188
  useSetUserData,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,cAAc,wBAAwB,mBAAmB,gBAAgB,sBAAsB;AAGxG,SAAS,qBAAqB;AAG9B,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,eAAe,iBAAiB;AAIzC,SAAS,UAAU;AACnB,SAAS,wBAAwB;AAGjC,SAAS,YAAY,mBAAmB,kBAAkB,sBAAsB;AAChF,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AAEjC,SAAS,4BAA4B;AAErC,SAAS,4BAA4B;AAErC,SAAS,sBAAsB;AAE/B,SAAS,kBAAkB;AAI3B,SAAS,QAAQ,sBAAsB;AACvC,SAAS,kBAAkB;AAC3B,SAAoB,WAAXA,gBAA+B;AAGxC,SAAS,WAAW,eAAe,kBAAkB,wBAAwB;AAC7E,SAAS,OAAO,qBAAqB;AACrC,SAAS,MAAM,YAAY,YAAY,WAAW,YAAY,iBAAiB,mBAAmB;AAClG,SAAS,YAAY,mBAAmB,gBAAgB,gBAAgB,oBAAoB,gBAAgB,0BAA0B;AACtI,SAAS,YAAY,iBAAiB;AACtC,SAAS,iBAAiB;AAC1B,SAAS,OAAO,aAAa,WAAW,aAAa,WAAW,UAAU,WAAW,oBAAoB;AACzG,SAAS,MAAM,UAAU,aAAa,mBAAmB;AACzD,SAAS,kBAAkB;AAI3B,SAAoB,WAAXA,gBAAmC;AAC5C,SAAoB,WAAXA,gBAA0C;AACnD,SAAS,gBAAgB;AACzB,SAAS,OAAO,eAAe,kCAAkC;AAIjE,SAAS,UAAU,yBAAyB;AAC5C,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,aAAa;AACtB,SAAS,UAAU,eAAe,cAAc,yBAAyB;AACzE,SAAS,YAAY,sBAAsB;AAC3C,SAAS,QAAQ,eAAe,aAAa,YAAY,aAAa,wBAAwB,sBAAsB,iBAAiB,eAAe,mBAAmB;AACvK,SAAS,cAAc;AACvB,SAAS,gBAAgB;AAGzB,SAAS,SAAS,eAAe,cAAc,aAAa,cAAc,cAAc,aAAa,iBAAiB,wBAAwB;AAC9I,SAAS,QAAQ,aAAa,eAAe,mBAAmB,cAAc,cAAc,eAAe,cAAc,aAAa,qBAAqB;AAC3J,SAAS,SAAS,gBAAgB,gBAAgB,qBAAqB;AACvE,SAAS,OAAO,cAAc,YAAY,cAAc,aAAa,aAAa,YAAY,wBAAwB;AACtH,SAAS,SAAS,gBAAgB,gBAAgB,uBAAuB;AAGzE,SAAS,yBAAyB;","names":["default"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\nexport { useActiveSubscription } from './modules/subscriptions/hooks/list-subscriptions.hook';\nexport { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';\nexport type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';\nexport type { Subscription, FindSubscriptionsParams } from './modules/subscriptions/types';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,cAAc,wBAAwB,mBAAmB,gBAAgB,sBAAsB;AACxG,SAAS,6BAA6B;AACtC,SAAS,oBAAoB;AAK7B,SAAS,qBAAqB;AAG9B,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,eAAe,iBAAiB;AAIzC,SAAS,UAAU;AACnB,SAAS,wBAAwB;AAGjC,SAAS,YAAY,mBAAmB,kBAAkB,sBAAsB;AAChF,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AAEjC,SAAS,4BAA4B;AAErC,SAAS,4BAA4B;AAErC,SAAS,sBAAsB;AAE/B,SAAS,kBAAkB;AAI3B,SAAS,QAAQ,sBAAsB;AACvC,SAAS,kBAAkB;AAC3B,SAAoB,WAAXA,gBAA+B;AAGxC,SAAS,WAAW,eAAe,kBAAkB,wBAAwB;AAC7E,SAAS,OAAO,qBAAqB;AACrC,SAAS,MAAM,YAAY,YAAY,WAAW,YAAY,iBAAiB,mBAAmB;AAClG,SAAS,YAAY,mBAAmB,gBAAgB,gBAAgB,oBAAoB,gBAAgB,0BAA0B;AACtI,SAAS,YAAY,iBAAiB;AACtC,SAAS,iBAAiB;AAC1B,SAAS,OAAO,aAAa,WAAW,aAAa,WAAW,UAAU,WAAW,oBAAoB;AACzG,SAAS,MAAM,UAAU,aAAa,mBAAmB;AACzD,SAAS,kBAAkB;AAI3B,SAAoB,WAAXA,gBAAmC;AAC5C,SAAoB,WAAXA,gBAA0C;AACnD,SAAS,gBAAgB;AACzB,SAAS,OAAO,eAAe,kCAAkC;AAIjE,SAAS,UAAU,yBAAyB;AAC5C,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,aAAa;AACtB,SAAS,UAAU,eAAe,cAAc,yBAAyB;AACzE,SAAS,YAAY,sBAAsB;AAC3C,SAAS,QAAQ,eAAe,aAAa,YAAY,aAAa,wBAAwB,sBAAsB,iBAAiB,eAAe,mBAAmB;AACvK,SAAS,cAAc;AACvB,SAAS,gBAAgB;AAGzB,SAAS,SAAS,eAAe,cAAc,aAAa,cAAc,cAAc,aAAa,iBAAiB,wBAAwB;AAC9I,SAAS,QAAQ,aAAa,eAAe,mBAAmB,cAAc,cAAc,eAAe,cAAc,aAAa,qBAAqB;AAC3J,SAAS,SAAS,gBAAgB,gBAAgB,qBAAqB;AACvE,SAAS,OAAO,cAAc,YAAY,cAAc,aAAa,aAAa,YAAY,wBAAwB;AACtH,SAAS,SAAS,gBAAgB,gBAAgB,uBAAuB;AAGzE,SAAS,yBAAyB;","names":["default"]}
@@ -0,0 +1,24 @@
1
+ import "server-only";
2
+ import { cookies } from "next/headers";
3
+ import { ApiError } from "../../../infra/api/types";
4
+ const AUTH_COOKIE_NAME = "greatapps";
5
+ async function getUserContext() {
6
+ const cookieStore = await cookies();
7
+ const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;
8
+ if (!token) {
9
+ throw new ApiError("Usu\xE1rio n\xE3o autenticado", "NOT_AUTHENTICATED", 401);
10
+ }
11
+ try {
12
+ const payload = JSON.parse(atob(token.split(".")[1]));
13
+ return {
14
+ id_account: payload.id_account,
15
+ id_user: payload.id_user
16
+ };
17
+ } catch {
18
+ throw new ApiError("Token inv\xE1lido", "INVALID_TOKEN", 401);
19
+ }
20
+ }
21
+ export {
22
+ getUserContext
23
+ };
24
+ //# sourceMappingURL=get-user-context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/auth/utils/get-user-context.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { cookies } from 'next/headers';\r\nimport { ApiError, JWTPayload } from '../../../infra/api/types';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\n\r\nexport async function getUserContext(): Promise<{\r\n id_account: number;\r\n id_user: number;\r\n}> {\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(atob(token.split('.')[1])) as JWTPayload;\r\n\r\n return {\r\n id_account: payload.id_account,\r\n id_user: payload.id_user,\r\n };\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n}\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,eAAe;AACxB,SAAS,gBAA4B;AAErC,MAAM,mBAAmB;AAEzB,eAAsB,iBAGnB;AACD,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,QAAQ,YAAY,IAAI,gBAAgB,GAAG;AAEjD,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,SAAS,iCAA2B,qBAAqB,GAAG;AAAA,EACxE;AAEA,MAAI;AACF,UAAM,UAAU,KAAK,MAAM,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAEpD,WAAO;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB,SAAS,QAAQ;AAAA,IACnB;AAAA,EACF,QAAQ;AACN,UAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,EAC3D;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { iaCreditsService } from "../services/ia-credits.service";
3
+ async function listIaCreditsAction(subscriptionId) {
4
+ return iaCreditsService.listOperations(subscriptionId);
5
+ }
6
+ export {
7
+ listIaCreditsAction
8
+ };
9
+ //# sourceMappingURL=list-ia-credits.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/ia-credits/actions/list-ia-credits.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport type { IaCreditOperation } from '../types';\r\nimport { iaCreditsService } from '../services/ia-credits.service';\r\n\r\nexport async function listIaCreditsAction(\r\n subscriptionId: number | string\r\n): Promise<PaginatedSuccessResult<IaCreditOperation>> {\r\n return iaCreditsService.listOperations(subscriptionId);\r\n}\r\n"],"mappings":";AAIA,SAAS,wBAAwB;AAEjC,eAAsB,oBACpB,gBACoD;AACpD,SAAO,iBAAiB,eAAe,cAAc;AACvD;","names":[]}
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { useActiveSubscription } from "../../subscriptions/hooks/list-subscriptions.hook";
5
+ import { listIaCreditsAction } from "../actions/list-ia-credits.action";
6
+ function calculateSummary(operations) {
7
+ const today = /* @__PURE__ */ new Date();
8
+ const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
9
+ const adds = operations.filter((op) => op.operation === "add");
10
+ const subtracts = operations.filter((op) => op.operation === "subtract");
11
+ let totalCredits = 0;
12
+ let usedCredits = 0;
13
+ let nextExpirationInDays = null;
14
+ let nextExpiringCredits = null;
15
+ for (const add of adds) {
16
+ const expirationRaw = add.expiration_time;
17
+ if (!expirationRaw) continue;
18
+ const expiration = new Date(expirationRaw);
19
+ const expirationDate = new Date(
20
+ expiration.getFullYear(),
21
+ expiration.getMonth(),
22
+ expiration.getDate()
23
+ );
24
+ const expiredByDate = expirationDate.getTime() < todayDate.getTime();
25
+ const hasExpired = add.has_expired || expiredByDate;
26
+ if (hasExpired) continue;
27
+ const addedCredits = add.operation_value;
28
+ const consumedForAdd = subtracts.filter((sub) => String(sub.consumed_from_add_id) === String(add.id)).reduce((sum, sub) => sum + sub.operation_value, 0);
29
+ const remainingForAdd = Math.max(0, addedCredits - consumedForAdd);
30
+ totalCredits += addedCredits;
31
+ usedCredits += consumedForAdd;
32
+ const diffMs = expirationDate.getTime() - todayDate.getTime();
33
+ const days = Math.max(0, Math.ceil(diffMs / (1e3 * 60 * 60 * 24)));
34
+ if (remainingForAdd > 0) {
35
+ if (nextExpirationInDays === null || days < nextExpirationInDays) {
36
+ nextExpirationInDays = days;
37
+ nextExpiringCredits = remainingForAdd;
38
+ }
39
+ }
40
+ }
41
+ const availableCredits = Math.max(0, totalCredits - usedCredits);
42
+ return {
43
+ totalCredits,
44
+ usedCredits,
45
+ availableCredits,
46
+ nextExpiringCredits,
47
+ nextExpirationInDays
48
+ };
49
+ }
50
+ function useIaCredits() {
51
+ const { data: subscriptionData, isPending: isSubscriptionLoading } = useActiveSubscription();
52
+ const subscription = subscriptionData?.data?.[0] ?? null;
53
+ const subscriptionId = subscription?.id;
54
+ const query = useQuery({
55
+ queryKey: ["ia-credits", subscriptionId],
56
+ queryFn: () => listIaCreditsAction(subscriptionId),
57
+ enabled: subscriptionId != null
58
+ });
59
+ const operations = query.data?.data ?? [];
60
+ const summary = useMemo(() => calculateSummary(operations), [operations]);
61
+ return {
62
+ subscription,
63
+ operations,
64
+ summary,
65
+ isLoading: isSubscriptionLoading || query.isPending,
66
+ isSubscriptionLoading,
67
+ isCreditsLoading: query.isPending,
68
+ isError: query.isError,
69
+ error: query.error
70
+ };
71
+ }
72
+ export {
73
+ useIaCredits
74
+ };
75
+ //# sourceMappingURL=ia-credits.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/ia-credits/hooks/ia-credits.hook.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useMemo } from 'react';\r\nimport { useQuery } from '@tanstack/react-query';\r\nimport { useActiveSubscription } from '../../subscriptions/hooks/list-subscriptions.hook';\r\nimport { listIaCreditsAction } from '../actions/list-ia-credits.action';\r\nimport type { IaCreditOperation, IaCreditsSummary } from '../types';\r\n\r\nfunction calculateSummary(operations: IaCreditOperation[]): IaCreditsSummary {\r\n const today = new Date();\r\n const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());\r\n\r\n const adds = operations.filter((op) => op.operation === 'add');\r\n const subtracts = operations.filter((op) => op.operation === 'subtract');\r\n\r\n let totalCredits = 0;\r\n let usedCredits = 0;\r\n let nextExpirationInDays: number | null = null;\r\n let nextExpiringCredits: number | null = null;\r\n\r\n for (const add of adds) {\r\n const expirationRaw = add.expiration_time;\r\n if (!expirationRaw) continue;\r\n\r\n const expiration = new Date(expirationRaw);\r\n const expirationDate = new Date(\r\n expiration.getFullYear(),\r\n expiration.getMonth(),\r\n expiration.getDate()\r\n );\r\n\r\n const expiredByDate = expirationDate.getTime() < todayDate.getTime();\r\n const hasExpired = add.has_expired || expiredByDate;\r\n\r\n if (hasExpired) continue;\r\n\r\n const addedCredits = add.operation_value;\r\n\r\n const consumedForAdd = subtracts\r\n .filter((sub) => String(sub.consumed_from_add_id) === String(add.id))\r\n .reduce((sum, sub) => sum + sub.operation_value, 0);\r\n\r\n const remainingForAdd = Math.max(0, addedCredits - consumedForAdd);\r\n\r\n totalCredits += addedCredits;\r\n usedCredits += consumedForAdd;\r\n\r\n const diffMs = expirationDate.getTime() - todayDate.getTime();\r\n const days = Math.max(0, Math.ceil(diffMs / (1000 * 60 * 60 * 24)));\r\n\r\n if (remainingForAdd > 0) {\r\n if (nextExpirationInDays === null || days < nextExpirationInDays) {\r\n nextExpirationInDays = days;\r\n nextExpiringCredits = remainingForAdd;\r\n }\r\n }\r\n }\r\n\r\n const availableCredits = Math.max(0, totalCredits - usedCredits);\r\n\r\n return {\r\n totalCredits,\r\n usedCredits,\r\n availableCredits,\r\n nextExpiringCredits,\r\n nextExpirationInDays,\r\n };\r\n}\r\n\r\nexport function useIaCredits() {\r\n const { data: subscriptionData, isPending: isSubscriptionLoading } = useActiveSubscription();\r\n const subscription = subscriptionData?.data?.[0] ?? null;\r\n const subscriptionId = subscription?.id;\r\n\r\n const query = useQuery({\r\n queryKey: ['ia-credits', subscriptionId],\r\n queryFn: () => listIaCreditsAction(subscriptionId!),\r\n enabled: subscriptionId != null,\r\n });\r\n\r\n const operations = query.data?.data ?? [];\r\n\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n const summary = useMemo(() => calculateSummary(operations), [operations]);\r\n\r\n return {\r\n subscription,\r\n operations,\r\n summary,\r\n isLoading: isSubscriptionLoading || query.isPending,\r\n isSubscriptionLoading,\r\n isCreditsLoading: query.isPending,\r\n isError: query.isError,\r\n error: query.error,\r\n };\r\n}\r\n"],"mappings":";AAEA,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AAGpC,SAAS,iBAAiB,YAAmD;AAC3E,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,YAAY,IAAI,KAAK,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;AAEjF,QAAM,OAAO,WAAW,OAAO,CAAC,OAAO,GAAG,cAAc,KAAK;AAC7D,QAAM,YAAY,WAAW,OAAO,CAAC,OAAO,GAAG,cAAc,UAAU;AAEvE,MAAI,eAAe;AACnB,MAAI,cAAc;AAClB,MAAI,uBAAsC;AAC1C,MAAI,sBAAqC;AAEzC,aAAW,OAAO,MAAM;AACtB,UAAM,gBAAgB,IAAI;AAC1B,QAAI,CAAC,cAAe;AAEpB,UAAM,aAAa,IAAI,KAAK,aAAa;AACzC,UAAM,iBAAiB,IAAI;AAAA,MACzB,WAAW,YAAY;AAAA,MACvB,WAAW,SAAS;AAAA,MACpB,WAAW,QAAQ;AAAA,IACrB;AAEA,UAAM,gBAAgB,eAAe,QAAQ,IAAI,UAAU,QAAQ;AACnE,UAAM,aAAa,IAAI,eAAe;AAEtC,QAAI,WAAY;AAEhB,UAAM,eAAe,IAAI;AAEzB,UAAM,iBAAiB,UACpB,OAAO,CAAC,QAAQ,OAAO,IAAI,oBAAoB,MAAM,OAAO,IAAI,EAAE,CAAC,EACnE,OAAO,CAAC,KAAK,QAAQ,MAAM,IAAI,iBAAiB,CAAC;AAEpD,UAAM,kBAAkB,KAAK,IAAI,GAAG,eAAe,cAAc;AAEjE,oBAAgB;AAChB,mBAAe;AAEf,UAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,QAAQ;AAC5D,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,UAAU,MAAO,KAAK,KAAK,GAAG,CAAC;AAElE,QAAI,kBAAkB,GAAG;AACvB,UAAI,yBAAyB,QAAQ,OAAO,sBAAsB;AAChE,+BAAuB;AACvB,8BAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,mBAAmB,KAAK,IAAI,GAAG,eAAe,WAAW;AAE/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,eAAe;AAC7B,QAAM,EAAE,MAAM,kBAAkB,WAAW,sBAAsB,IAAI,sBAAsB;AAC3F,QAAM,eAAe,kBAAkB,OAAO,CAAC,KAAK;AACpD,QAAM,iBAAiB,cAAc;AAErC,QAAM,QAAQ,SAAS;AAAA,IACrB,UAAU,CAAC,cAAc,cAAc;AAAA,IACvC,SAAS,MAAM,oBAAoB,cAAe;AAAA,IAClD,SAAS,kBAAkB;AAAA,EAC7B,CAAC;AAED,QAAM,aAAa,MAAM,MAAM,QAAQ,CAAC;AAGxC,QAAM,UAAU,QAAQ,MAAM,iBAAiB,UAAU,GAAG,CAAC,UAAU,CAAC;AAExE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,yBAAyB,MAAM;AAAA,IAC1C;AAAA,IACA,kBAAkB,MAAM;AAAA,IACxB,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,EACf;AACF;","names":[]}
@@ -0,0 +1,31 @@
1
+ import "server-only";
2
+ import { apiClient } from "../../../infra/api/client";
3
+ import { ApiError } from "../../../infra/api/types";
4
+ import { getUserContext } from "../../auth/utils/get-user-context";
5
+ import { IaCreditOperationSchema } from "../types";
6
+ class IaCreditsService {
7
+ async listOperations(subscriptionId) {
8
+ const { id_account } = await getUserContext();
9
+ const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;
10
+ const response = await apiClient.get(endpoint);
11
+ if (response.status === 0) {
12
+ throw new ApiError(
13
+ response.message || "Erro ao listar cr\xE9ditos de IA",
14
+ "LIST_IA_CREDITS_FAILED",
15
+ 400
16
+ );
17
+ }
18
+ const raw = response.data ?? [];
19
+ const data = raw.map((item) => IaCreditOperationSchema.parse(item));
20
+ return {
21
+ data,
22
+ total: response.total ?? data.length,
23
+ success: true
24
+ };
25
+ }
26
+ }
27
+ const iaCreditsService = new IaCreditsService();
28
+ export {
29
+ iaCreditsService
30
+ };
31
+ //# sourceMappingURL=ia-credits.service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/ia-credits/services/ia-credits.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { IaCreditOperation, IaCreditOperationSchema } from '../types';\r\n\r\nclass IaCreditsService {\r\n async listOperations(\r\n subscriptionId: number | string\r\n ): Promise<PaginatedSuccessResult<IaCreditOperation>> {\r\n const { id_account } = await getUserContext();\r\n\r\n const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;\r\n\r\n const response = await apiClient.get<ApiPaginatedActionResult<IaCreditOperation>>(endpoint);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar créditos de IA',\r\n 'LIST_IA_CREDITS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n const raw = response.data ?? [];\r\n const data = raw.map((item) => IaCreditOperationSchema.parse(item));\r\n\r\n return {\r\n data,\r\n total: response.total ?? data.length,\r\n success: true,\r\n };\r\n }\r\n}\r\n\r\nexport const iaCreditsService = new IaCreditsService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,iBAAiB;AAC1B,SAAS,gBAAkE;AAC3E,SAAS,sBAAsB;AAC/B,SAA4B,+BAA+B;AAE3D,MAAM,iBAAiB;AAAA,EACrB,MAAM,eACJ,gBACoD;AACpD,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,WAAW,aAAa,UAAU,kBAAkB,cAAc;AAExE,UAAM,WAAW,MAAM,UAAU,IAAiD,QAAQ;AAE1F,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAM,SAAS,QAAQ,CAAC;AAC9B,UAAM,OAAO,IAAI,IAAI,CAAC,SAAS,wBAAwB,MAAM,IAAI,CAAC;AAElE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS,SAAS,KAAK;AAAA,MAC9B,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEO,MAAM,mBAAmB,IAAI,iBAAiB;","names":[]}
@@ -0,0 +1,25 @@
1
+ import z from "zod";
2
+ const IaCreditOperationSchema = z.object({
3
+ id: z.union([z.number(), z.string()]),
4
+ deleted: z.number(),
5
+ datetime_add: z.string(),
6
+ id_wl: z.number(),
7
+ id_subscription: z.union([z.number(), z.string()]),
8
+ id_addon: z.number(),
9
+ operation: z.string(),
10
+ // 'add' | 'subtract'
11
+ operation_value: z.union([z.number(), z.string()]).transform((v) => Number(v)),
12
+ balance_after_operation: z.union([z.number(), z.string()]).optional(),
13
+ balance_before_operation: z.union([z.number(), z.string()]).optional(),
14
+ operation_ref: z.string().nullable().optional(),
15
+ operation_origin: z.string().nullable().optional(),
16
+ expiration_time: z.string().nullable(),
17
+ has_expired: z.boolean(),
18
+ consumed_from_add_id: z.union([z.number(), z.string()]).nullable(),
19
+ id_user_add: z.union([z.number(), z.string()]).nullable(),
20
+ user_name: z.string().nullable().optional()
21
+ }).passthrough();
22
+ export {
23
+ IaCreditOperationSchema
24
+ };
25
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/ia-credits/types.ts"],"sourcesContent":["import z from 'zod';\r\n\r\nexport const IaCreditOperationSchema = z\r\n .object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n datetime_add: z.string(),\r\n id_wl: z.number(),\r\n id_subscription: z.union([z.number(), z.string()]),\r\n id_addon: z.number(),\r\n operation: z.string(), // 'add' | 'subtract'\r\n operation_value: z.union([z.number(), z.string()]).transform((v) => Number(v)),\r\n balance_after_operation: z.union([z.number(), z.string()]).optional(),\r\n balance_before_operation: z.union([z.number(), z.string()]).optional(),\r\n operation_ref: z.string().nullable().optional(),\r\n operation_origin: z.string().nullable().optional(),\r\n expiration_time: z.string().nullable(),\r\n has_expired: z.boolean(),\r\n consumed_from_add_id: z.union([z.number(), z.string()]).nullable(),\r\n id_user_add: z.union([z.number(), z.string()]).nullable(),\r\n user_name: z.string().nullable().optional(),\r\n })\r\n .passthrough();\r\n\r\nexport type IaCreditOperation = z.infer<typeof IaCreditOperationSchema>;\r\n\r\nexport type IaCreditsSummary = {\r\n totalCredits: number;\r\n usedCredits: number;\r\n availableCredits: number;\r\n nextExpiringCredits: number | null;\r\n nextExpirationInDays: number | null;\r\n};\r\n"],"mappings":"AAAA,OAAO,OAAO;AAEP,MAAM,0BAA0B,EACpC,OAAO;AAAA,EACN,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,EACpC,SAAS,EAAE,OAAO;AAAA,EAClB,cAAc,EAAE,OAAO;AAAA,EACvB,OAAO,EAAE,OAAO;AAAA,EAChB,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,EACjD,UAAU,EAAE,OAAO;AAAA,EACnB,WAAW,EAAE,OAAO;AAAA;AAAA,EACpB,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,OAAO,CAAC,CAAC;AAAA,EAC7E,yBAAyB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EACpE,0BAA0B,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EACrE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC9C,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,aAAa,EAAE,QAAQ;AAAA,EACvB,sBAAsB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EACjE,aAAa,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EACxD,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC5C,CAAC,EACA,YAAY;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { subscriptionsService } from "../services/subscriptions.service";
3
+ async function listSubscriptionsAction(params) {
4
+ return subscriptionsService.listSubscriptions(params);
5
+ }
6
+ export {
7
+ listSubscriptionsAction
8
+ };
9
+ //# sourceMappingURL=list-subscriptions.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/subscriptions/actions/list-subscriptions.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport type { Subscription, FindSubscriptionsParams } from '../types';\r\nimport { subscriptionsService } from '../services/subscriptions.service';\r\n\r\nexport async function listSubscriptionsAction(\r\n params?: Partial<FindSubscriptionsParams>\r\n): Promise<PaginatedSuccessResult<Subscription>> {\r\n return subscriptionsService.listSubscriptions(params);\r\n}\r\n"],"mappings":";AAIA,SAAS,4BAA4B;AAErC,eAAsB,wBACpB,QAC+C;AAC/C,SAAO,qBAAqB,kBAAkB,MAAM;AACtD;","names":[]}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { listSubscriptionsAction } from "../actions/list-subscriptions.action";
4
+ const SUBSCRIPTIONS_QUERY_KEY = ["subscriptions"];
5
+ function useActiveSubscription() {
6
+ return useQuery({
7
+ queryKey: [...SUBSCRIPTIONS_QUERY_KEY, "active"],
8
+ queryFn: () => listSubscriptionsAction({ active: true })
9
+ });
10
+ }
11
+ export {
12
+ useActiveSubscription
13
+ };
14
+ //# sourceMappingURL=list-subscriptions.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/subscriptions/hooks/list-subscriptions.hook.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useQuery } from '@tanstack/react-query';\r\nimport { listSubscriptionsAction } from '../actions/list-subscriptions.action';\r\nimport type { FindSubscriptionsParams } from '../types';\r\n\r\nconst SUBSCRIPTIONS_QUERY_KEY = ['subscriptions'];\r\n\r\nexport function useActiveSubscription() {\r\n return useQuery({\r\n queryKey: [...SUBSCRIPTIONS_QUERY_KEY, 'active'],\r\n queryFn: () => listSubscriptionsAction({ active: true } as Partial<FindSubscriptionsParams>),\r\n });\r\n}\r\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,+BAA+B;AAGxC,MAAM,0BAA0B,CAAC,eAAe;AAEzC,SAAS,wBAAwB;AACtC,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,GAAG,yBAAyB,QAAQ;AAAA,IAC/C,SAAS,MAAM,wBAAwB,EAAE,QAAQ,KAAK,CAAqC;AAAA,EAC7F,CAAC;AACH;","names":[]}
@@ -0,0 +1,32 @@
1
+ import "server-only";
2
+ import { apiClient } from "../../../infra/api/client";
3
+ import { ApiError } from "../../../infra/api/types";
4
+ import { buildQueryParams } from "../../../infra/utils/params";
5
+ import { getUserContext } from "../../auth/utils/get-user-context";
6
+ import { SubscriptionSchema } from "../types";
7
+ class SubscriptionsService {
8
+ async listSubscriptions(params) {
9
+ const { id_account } = await getUserContext();
10
+ const query = buildQueryParams(params);
11
+ const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ""}`;
12
+ const response = await apiClient.get(url);
13
+ if (response.status === 0) {
14
+ throw new ApiError(
15
+ response.message || "Erro ao listar assinaturas",
16
+ "LIST_SUBSCRIPTIONS_FAILED",
17
+ 400
18
+ );
19
+ }
20
+ const data = response.data.map((item) => SubscriptionSchema.parse(item));
21
+ return {
22
+ data,
23
+ total: response.total,
24
+ success: true
25
+ };
26
+ }
27
+ }
28
+ const subscriptionsService = new SubscriptionsService();
29
+ export {
30
+ subscriptionsService
31
+ };
32
+ //# sourceMappingURL=subscriptions.service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/subscriptions/services/subscriptions.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';\r\nimport { buildQueryParams } from '../../../infra/utils/params';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport { Subscription, SubscriptionSchema, FindSubscriptionsParams } from '../types';\r\n\r\nclass SubscriptionsService {\r\n async listSubscriptions(\r\n params?: Partial<FindSubscriptionsParams>\r\n ): Promise<PaginatedSuccessResult<Subscription>> {\r\n const { id_account } = await getUserContext();\r\n\r\n const query = buildQueryParams(params as Record<string, string | boolean | undefined>);\r\n const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ''}`;\r\n\r\n const response = await apiClient.get<ApiPaginatedActionResult<Subscription>>(url);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar assinaturas',\r\n 'LIST_SUBSCRIPTIONS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n const data = response.data.map((item) => SubscriptionSchema.parse(item));\r\n\r\n return {\r\n data,\r\n total: response.total,\r\n success: true,\r\n } satisfies PaginatedSuccessResult<Subscription>;\r\n }\r\n}\r\n\r\nexport const subscriptionsService = new SubscriptionsService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,iBAAiB;AAC1B,SAAS,gBAAkE;AAC3E,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B,SAAuB,0BAAmD;AAE1E,MAAM,qBAAqB;AAAA,EACzB,MAAM,kBACJ,QAC+C;AAC/C,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAE5C,UAAM,QAAQ,iBAAiB,MAAsD;AACrF,UAAM,MAAM,aAAa,UAAU,iBAAiB,QAAQ,IAAI,KAAK,KAAK,EAAE;AAE5E,UAAM,WAAW,MAAM,UAAU,IAA4C,GAAG;AAEhF,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,SAAS,KAAK,IAAI,CAAC,SAAS,mBAAmB,MAAM,IAAI,CAAC;AAEvE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEO,MAAM,uBAAuB,IAAI,qBAAqB;","names":[]}
@@ -0,0 +1,12 @@
1
+ import z from "zod";
2
+ const SubscriptionSchema = z.object({
3
+ id: z.union([z.number(), z.string()]),
4
+ deleted: z.number(),
5
+ id_wl: z.number(),
6
+ id_account: z.union([z.number(), z.string()]),
7
+ active: z.boolean()
8
+ }).passthrough();
9
+ export {
10
+ SubscriptionSchema
11
+ };
12
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/subscriptions/types.ts"],"sourcesContent":["import z from 'zod';\r\n\r\nexport const SubscriptionSchema = z\r\n .object({\r\n id: z.union([z.number(), z.string()]),\r\n deleted: z.number(),\r\n id_wl: z.number(),\r\n id_account: z.union([z.number(), z.string()]),\r\n active: z.boolean(),\r\n })\r\n .passthrough();\r\n\r\nexport type Subscription = z.infer<typeof SubscriptionSchema>;\r\n\r\nexport interface FindSubscriptionsParams {\r\n active?: boolean;\r\n}\r\n"],"mappings":"AAAA,OAAO,OAAO;AAEP,MAAM,qBAAqB,EAC/B,OAAO;AAAA,EACN,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,EACpC,SAAS,EAAE,OAAO;AAAA,EAClB,OAAO,EAAE,OAAO;AAAA,EAChB,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC;AAAA,EAC5C,QAAQ,EAAE,QAAQ;AACpB,CAAC,EACA,YAAY;","names":[]}
package/dist/server.mjs CHANGED
@@ -2,15 +2,25 @@ import "server-only";
2
2
  import { apiClient, ApiClient } from "./infra/api/client";
3
3
  import { authService } from "./modules/auth/services/auth.service";
4
4
  import { whitelabelService } from "./modules/whitelabel/services/whitelabel.service";
5
+ import { subscriptionsService } from "./modules/subscriptions/services/subscriptions.service";
6
+ import { iaCreditsService } from "./modules/ia-credits/services/ia-credits.service";
5
7
  import { findWhitelabel } from "./modules/whitelabel/actions/find-whitelabel.action";
6
8
  import { validateSessionAction } from "./modules/auth/actions/validate-session.action";
9
+ import { listSubscriptionsAction } from "./modules/subscriptions/actions/list-subscriptions.action";
10
+ import { listIaCreditsAction } from "./modules/ia-credits/actions/list-ia-credits.action";
7
11
  import { getClientInfoFromRequest } from "./infra/utils/client-info";
12
+ import { getUserContext } from "./modules/auth/utils/get-user-context";
8
13
  export {
9
14
  ApiClient,
10
15
  apiClient,
11
16
  authService,
12
17
  findWhitelabel,
13
18
  getClientInfoFromRequest,
19
+ getUserContext,
20
+ iaCreditsService,
21
+ listIaCreditsAction,
22
+ listSubscriptionsAction,
23
+ subscriptionsService,
14
24
  validateSessionAction,
15
25
  whitelabelService
16
26
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { apiClient, ApiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,iBAAiB;AAGrC,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAGlC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AAGtC,SAAS,gCAAgC;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { apiClient, ApiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,iBAAiB;AAGrC,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AAGpC,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -11,6 +11,7 @@ import { NavBarItem } from './NavBarItem';
11
11
  import { UserAvatar } from '../ui/data-display/UserAvatar';
12
12
  import { useAuth } from '../../providers/auth.provider';
13
13
  import { cn } from '../../infra/utils/clsx';
14
+ import { useIaCredits } from '../../modules/ia-credits/hooks/ia-credits.hook';
14
15
 
15
16
  export interface ProfileMenuItem {
16
17
  icon?: React.ReactNode;
@@ -23,11 +24,9 @@ export interface ProfilePopoverProps {
23
24
  align?: 'start' | 'center' | 'end';
24
25
  contentClassName?: string;
25
26
  onEditProfile?: () => void;
26
- credits?: { used: number; total: number };
27
27
  onCreditsClick?: () => void;
28
28
  menuItems?: ProfileMenuItem[];
29
29
  logoutRedirect?: string;
30
- storageUrl?: string;
31
30
  logoutOverlay?: React.ReactNode;
32
31
  }
33
32
 
@@ -36,17 +35,17 @@ function ProfilePopover({
36
35
  align = 'start',
37
36
  contentClassName = 'absolute bottom-2 left-[26px]',
38
37
  onEditProfile,
39
- credits,
40
38
  onCreditsClick,
41
39
  menuItems = [],
42
40
  logoutRedirect = '/login',
43
- storageUrl,
44
41
  logoutOverlay,
45
42
  }: ProfilePopoverProps) {
46
43
  const router = useRouter();
47
44
  const { user, logout } = useAuth();
48
45
  const [isLoggingOut, setIsLoggingOut] = useState(false);
49
46
 
47
+ const { summary, subscription, isSubscriptionLoading, isCreditsLoading } = useIaCredits();
48
+
50
49
  const handleLogout = async () => {
51
50
  try {
52
51
  setIsLoggingOut(true);
@@ -59,9 +58,12 @@ function ProfilePopover({
59
58
  }
60
59
  };
61
60
 
61
+ const hasSubscription = !isSubscriptionLoading && subscription !== null;
62
+ const showCreditsSkeleton = hasSubscription && isCreditsLoading;
63
+ const showCredits = hasSubscription && !isCreditsLoading && summary.totalCredits > 0;
62
64
  const creditsPercentage =
63
- credits && credits.total > 0
64
- ? (credits.used / credits.total) * 100
65
+ showCredits && summary.totalCredits > 0
66
+ ? (summary.usedCredits / summary.totalCredits) * 100
65
67
  : 0;
66
68
 
67
69
  return (
@@ -75,7 +77,6 @@ function ProfilePopover({
75
77
  photo={user.photo}
76
78
  name={user.name}
77
79
  size={40}
78
- storageUrl={storageUrl}
79
80
  />
80
81
  )}
81
82
  </PopoverPrimitive.Trigger>
@@ -97,7 +98,6 @@ function ProfilePopover({
97
98
  photo={user.photo}
98
99
  name={user.name}
99
100
  size={32}
100
- storageUrl={storageUrl}
101
101
  />
102
102
  )}
103
103
 
@@ -122,7 +122,19 @@ function ProfilePopover({
122
122
  </div>
123
123
 
124
124
  <div className="flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5">
125
- {credits && (
125
+ {showCreditsSkeleton && (
126
+ <div className="flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4">
127
+ <div className="flex items-center justify-between gap-2">
128
+ <span className="paragraph-xsmall-semibold text-white truncate">
129
+ Créditos usados
130
+ </span>
131
+ <div className="h-3.5 w-16 rounded bg-white/20 animate-pulse" />
132
+ </div>
133
+ <div className="h-1.5 w-full rounded-full bg-white/20 animate-pulse" />
134
+ </div>
135
+ )}
136
+
137
+ {showCredits && (
126
138
  <div
127
139
  className={cn(
128
140
  'flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors',
@@ -135,8 +147,8 @@ function ProfilePopover({
135
147
  Créditos usados
136
148
  </span>
137
149
  <span className="paragraph-xsmall-medium text-white/50">
138
- {credits.used.toLocaleString('pt-BR')}/
139
- {credits.total.toLocaleString('pt-BR')}
150
+ {summary.usedCredits.toLocaleString('pt-BR')}/
151
+ {summary.totalCredits.toLocaleString('pt-BR')}
140
152
  </span>
141
153
  </div>
142
154
  <Progress
@@ -12,6 +12,8 @@ function getInitials(name: string, maxLength: number = 2): string {
12
12
  .toUpperCase();
13
13
  }
14
14
 
15
+ const STORAGE_URL = process.env.NEXT_PUBLIC_STORAGE_URL || '';
16
+
15
17
  interface UserAvatarProps {
16
18
  photo?: string | null;
17
19
  name?: string;
@@ -19,7 +21,6 @@ interface UserAvatarProps {
19
21
  size?: number;
20
22
  shape?: 'circle' | 'square';
21
23
  className?: string;
22
- storageUrl?: string;
23
24
  }
24
25
 
25
26
  function UserAvatar({
@@ -29,12 +30,11 @@ function UserAvatar({
29
30
  size = 32,
30
31
  shape = 'circle',
31
32
  className,
32
- storageUrl,
33
33
  }: UserAvatarProps) {
34
34
  const shapeClass = shape === 'circle' ? 'rounded-full' : 'rounded-lg';
35
35
  const displayInitials = initials || (name ? getInitials(name) : '?');
36
36
 
37
- const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;
37
+ const photoUrl = STORAGE_URL && photo ? `${STORAGE_URL}/${photo}` : photo;
38
38
 
39
39
  if (photoUrl) {
40
40
  return (
package/src/index.ts CHANGED
@@ -11,6 +11,10 @@ export * from './providers/whitelabel.provider';
11
11
 
12
12
  // Hooks
13
13
  export { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';
14
+ export { useActiveSubscription } from './modules/subscriptions/hooks/list-subscriptions.hook';
15
+ export { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';
16
+ export type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';
17
+ export type { Subscription, FindSubscriptionsParams } from './modules/subscriptions/types';
14
18
 
15
19
  // Providers
16
20
  export { QueryProvider } from './providers/query.provider';
@@ -0,0 +1,29 @@
1
+ import 'server-only';
2
+
3
+ import { cookies } from 'next/headers';
4
+ import { ApiError, JWTPayload } from '../../../infra/api/types';
5
+
6
+ const AUTH_COOKIE_NAME = 'greatapps';
7
+
8
+ export async function getUserContext(): Promise<{
9
+ id_account: number;
10
+ id_user: number;
11
+ }> {
12
+ const cookieStore = await cookies();
13
+ const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;
14
+
15
+ if (!token) {
16
+ throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);
17
+ }
18
+
19
+ try {
20
+ const payload = JSON.parse(atob(token.split('.')[1])) as JWTPayload;
21
+
22
+ return {
23
+ id_account: payload.id_account,
24
+ id_user: payload.id_user,
25
+ };
26
+ } catch {
27
+ throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);
28
+ }
29
+ }
@@ -0,0 +1,11 @@
1
+ 'use server';
2
+
3
+ import { PaginatedSuccessResult } from '../../../infra/api/types';
4
+ import type { IaCreditOperation } from '../types';
5
+ import { iaCreditsService } from '../services/ia-credits.service';
6
+
7
+ export async function listIaCreditsAction(
8
+ subscriptionId: number | string
9
+ ): Promise<PaginatedSuccessResult<IaCreditOperation>> {
10
+ return iaCreditsService.listOperations(subscriptionId);
11
+ }
@@ -0,0 +1,96 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import { useQuery } from '@tanstack/react-query';
5
+ import { useActiveSubscription } from '../../subscriptions/hooks/list-subscriptions.hook';
6
+ import { listIaCreditsAction } from '../actions/list-ia-credits.action';
7
+ import type { IaCreditOperation, IaCreditsSummary } from '../types';
8
+
9
+ function calculateSummary(operations: IaCreditOperation[]): IaCreditsSummary {
10
+ const today = new Date();
11
+ const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
12
+
13
+ const adds = operations.filter((op) => op.operation === 'add');
14
+ const subtracts = operations.filter((op) => op.operation === 'subtract');
15
+
16
+ let totalCredits = 0;
17
+ let usedCredits = 0;
18
+ let nextExpirationInDays: number | null = null;
19
+ let nextExpiringCredits: number | null = null;
20
+
21
+ for (const add of adds) {
22
+ const expirationRaw = add.expiration_time;
23
+ if (!expirationRaw) continue;
24
+
25
+ const expiration = new Date(expirationRaw);
26
+ const expirationDate = new Date(
27
+ expiration.getFullYear(),
28
+ expiration.getMonth(),
29
+ expiration.getDate()
30
+ );
31
+
32
+ const expiredByDate = expirationDate.getTime() < todayDate.getTime();
33
+ const hasExpired = add.has_expired || expiredByDate;
34
+
35
+ if (hasExpired) continue;
36
+
37
+ const addedCredits = add.operation_value;
38
+
39
+ const consumedForAdd = subtracts
40
+ .filter((sub) => String(sub.consumed_from_add_id) === String(add.id))
41
+ .reduce((sum, sub) => sum + sub.operation_value, 0);
42
+
43
+ const remainingForAdd = Math.max(0, addedCredits - consumedForAdd);
44
+
45
+ totalCredits += addedCredits;
46
+ usedCredits += consumedForAdd;
47
+
48
+ const diffMs = expirationDate.getTime() - todayDate.getTime();
49
+ const days = Math.max(0, Math.ceil(diffMs / (1000 * 60 * 60 * 24)));
50
+
51
+ if (remainingForAdd > 0) {
52
+ if (nextExpirationInDays === null || days < nextExpirationInDays) {
53
+ nextExpirationInDays = days;
54
+ nextExpiringCredits = remainingForAdd;
55
+ }
56
+ }
57
+ }
58
+
59
+ const availableCredits = Math.max(0, totalCredits - usedCredits);
60
+
61
+ return {
62
+ totalCredits,
63
+ usedCredits,
64
+ availableCredits,
65
+ nextExpiringCredits,
66
+ nextExpirationInDays,
67
+ };
68
+ }
69
+
70
+ export function useIaCredits() {
71
+ const { data: subscriptionData, isPending: isSubscriptionLoading } = useActiveSubscription();
72
+ const subscription = subscriptionData?.data?.[0] ?? null;
73
+ const subscriptionId = subscription?.id;
74
+
75
+ const query = useQuery({
76
+ queryKey: ['ia-credits', subscriptionId],
77
+ queryFn: () => listIaCreditsAction(subscriptionId!),
78
+ enabled: subscriptionId != null,
79
+ });
80
+
81
+ const operations = query.data?.data ?? [];
82
+
83
+ // eslint-disable-next-line react-hooks/exhaustive-deps
84
+ const summary = useMemo(() => calculateSummary(operations), [operations]);
85
+
86
+ return {
87
+ subscription,
88
+ operations,
89
+ summary,
90
+ isLoading: isSubscriptionLoading || query.isPending,
91
+ isSubscriptionLoading,
92
+ isCreditsLoading: query.isPending,
93
+ isError: query.isError,
94
+ error: query.error,
95
+ };
96
+ }
@@ -0,0 +1,37 @@
1
+ import 'server-only';
2
+
3
+ import { apiClient } from '../../../infra/api/client';
4
+ import { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';
5
+ import { getUserContext } from '../../auth/utils/get-user-context';
6
+ import { IaCreditOperation, IaCreditOperationSchema } from '../types';
7
+
8
+ class IaCreditsService {
9
+ async listOperations(
10
+ subscriptionId: number | string
11
+ ): Promise<PaginatedSuccessResult<IaCreditOperation>> {
12
+ const { id_account } = await getUserContext();
13
+
14
+ const endpoint = `/accounts/${id_account}/subscriptions/${subscriptionId}/items/balance/list?page=1&limit=20&sort=id:DESC`;
15
+
16
+ const response = await apiClient.get<ApiPaginatedActionResult<IaCreditOperation>>(endpoint);
17
+
18
+ if (response.status === 0) {
19
+ throw new ApiError(
20
+ response.message || 'Erro ao listar créditos de IA',
21
+ 'LIST_IA_CREDITS_FAILED',
22
+ 400
23
+ );
24
+ }
25
+
26
+ const raw = response.data ?? [];
27
+ const data = raw.map((item) => IaCreditOperationSchema.parse(item));
28
+
29
+ return {
30
+ data,
31
+ total: response.total ?? data.length,
32
+ success: true,
33
+ };
34
+ }
35
+ }
36
+
37
+ export const iaCreditsService = new IaCreditsService();
@@ -0,0 +1,33 @@
1
+ import z from 'zod';
2
+
3
+ export const IaCreditOperationSchema = z
4
+ .object({
5
+ id: z.union([z.number(), z.string()]),
6
+ deleted: z.number(),
7
+ datetime_add: z.string(),
8
+ id_wl: z.number(),
9
+ id_subscription: z.union([z.number(), z.string()]),
10
+ id_addon: z.number(),
11
+ operation: z.string(), // 'add' | 'subtract'
12
+ operation_value: z.union([z.number(), z.string()]).transform((v) => Number(v)),
13
+ balance_after_operation: z.union([z.number(), z.string()]).optional(),
14
+ balance_before_operation: z.union([z.number(), z.string()]).optional(),
15
+ operation_ref: z.string().nullable().optional(),
16
+ operation_origin: z.string().nullable().optional(),
17
+ expiration_time: z.string().nullable(),
18
+ has_expired: z.boolean(),
19
+ consumed_from_add_id: z.union([z.number(), z.string()]).nullable(),
20
+ id_user_add: z.union([z.number(), z.string()]).nullable(),
21
+ user_name: z.string().nullable().optional(),
22
+ })
23
+ .passthrough();
24
+
25
+ export type IaCreditOperation = z.infer<typeof IaCreditOperationSchema>;
26
+
27
+ export type IaCreditsSummary = {
28
+ totalCredits: number;
29
+ usedCredits: number;
30
+ availableCredits: number;
31
+ nextExpiringCredits: number | null;
32
+ nextExpirationInDays: number | null;
33
+ };
@@ -0,0 +1,11 @@
1
+ 'use server';
2
+
3
+ import { PaginatedSuccessResult } from '../../../infra/api/types';
4
+ import type { Subscription, FindSubscriptionsParams } from '../types';
5
+ import { subscriptionsService } from '../services/subscriptions.service';
6
+
7
+ export async function listSubscriptionsAction(
8
+ params?: Partial<FindSubscriptionsParams>
9
+ ): Promise<PaginatedSuccessResult<Subscription>> {
10
+ return subscriptionsService.listSubscriptions(params);
11
+ }
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+
3
+ import { useQuery } from '@tanstack/react-query';
4
+ import { listSubscriptionsAction } from '../actions/list-subscriptions.action';
5
+ import type { FindSubscriptionsParams } from '../types';
6
+
7
+ const SUBSCRIPTIONS_QUERY_KEY = ['subscriptions'];
8
+
9
+ export function useActiveSubscription() {
10
+ return useQuery({
11
+ queryKey: [...SUBSCRIPTIONS_QUERY_KEY, 'active'],
12
+ queryFn: () => listSubscriptionsAction({ active: true } as Partial<FindSubscriptionsParams>),
13
+ });
14
+ }
@@ -0,0 +1,38 @@
1
+ import 'server-only';
2
+
3
+ import { apiClient } from '../../../infra/api/client';
4
+ import { ApiError, ApiPaginatedActionResult, PaginatedSuccessResult } from '../../../infra/api/types';
5
+ import { buildQueryParams } from '../../../infra/utils/params';
6
+ import { getUserContext } from '../../auth/utils/get-user-context';
7
+ import { Subscription, SubscriptionSchema, FindSubscriptionsParams } from '../types';
8
+
9
+ class SubscriptionsService {
10
+ async listSubscriptions(
11
+ params?: Partial<FindSubscriptionsParams>
12
+ ): Promise<PaginatedSuccessResult<Subscription>> {
13
+ const { id_account } = await getUserContext();
14
+
15
+ const query = buildQueryParams(params as Record<string, string | boolean | undefined>);
16
+ const url = `/accounts/${id_account}/subscriptions${query ? `?${query}` : ''}`;
17
+
18
+ const response = await apiClient.get<ApiPaginatedActionResult<Subscription>>(url);
19
+
20
+ if (response.status === 0) {
21
+ throw new ApiError(
22
+ response.message || 'Erro ao listar assinaturas',
23
+ 'LIST_SUBSCRIPTIONS_FAILED',
24
+ 400
25
+ );
26
+ }
27
+
28
+ const data = response.data.map((item) => SubscriptionSchema.parse(item));
29
+
30
+ return {
31
+ data,
32
+ total: response.total,
33
+ success: true,
34
+ } satisfies PaginatedSuccessResult<Subscription>;
35
+ }
36
+ }
37
+
38
+ export const subscriptionsService = new SubscriptionsService();
@@ -0,0 +1,17 @@
1
+ import z from 'zod';
2
+
3
+ export const SubscriptionSchema = z
4
+ .object({
5
+ id: z.union([z.number(), z.string()]),
6
+ deleted: z.number(),
7
+ id_wl: z.number(),
8
+ id_account: z.union([z.number(), z.string()]),
9
+ active: z.boolean(),
10
+ })
11
+ .passthrough();
12
+
13
+ export type Subscription = z.infer<typeof SubscriptionSchema>;
14
+
15
+ export interface FindSubscriptionsParams {
16
+ active?: boolean;
17
+ }
package/src/server.ts CHANGED
@@ -6,10 +6,15 @@ export { apiClient, ApiClient } from './infra/api/client';
6
6
  // Services
7
7
  export { authService } from './modules/auth/services/auth.service';
8
8
  export { whitelabelService } from './modules/whitelabel/services/whitelabel.service';
9
+ export { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';
10
+ export { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';
9
11
 
10
12
  // Actions
11
13
  export { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';
12
14
  export { validateSessionAction } from './modules/auth/actions/validate-session.action';
15
+ export { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';
16
+ export { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';
13
17
 
14
18
  // Server Utils
15
19
  export { getClientInfoFromRequest } from './infra/utils/client-info';
20
+ export { getUserContext } from './modules/auth/utils/get-user-context';