@greatapps/common 1.1.218 → 1.1.221
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/account/ConfigurationsMyAccountModal.mjs +6 -6
- package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
- package/dist/components/account/ConfirmDeleteAccountModal.mjs +2 -2
- package/dist/components/account/ConfirmDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/ConfirmGlobalPreferencesModal.mjs +2 -2
- package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -1
- package/dist/components/account/DeleteAccountModal.mjs +3 -3
- package/dist/components/account/DeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/DisableTwoFactorAuthModal.mjs +2 -2
- package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs +2 -2
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/TwoFactorAuthModal.mjs +6 -6
- package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
- package/dist/components/account/sections/ChangeEmailModal.mjs +6 -6
- package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -1
- package/dist/components/account/sections/ChangePasswordSection.mjs +4 -4
- package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -1
- package/dist/components/account/sections/ChangePhoneModal.mjs +5 -5
- package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -1
- package/dist/components/account/sections/MyProfileSection.mjs +3 -3
- package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
- package/dist/components/account/sections/PreferencesSection.mjs +6 -6
- package/dist/components/account/sections/PreferencesSection.mjs.map +1 -1
- package/dist/components/account/sections/SecuritySection.mjs +3 -3
- package/dist/components/account/sections/SecuritySection.mjs.map +1 -1
- package/dist/components/layouts/AppMobileNavBar.mjs +0 -1
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/MdSideBarNavigation.mjs +2 -2
- package/dist/components/layouts/MdSideBarNavigation.mjs.map +1 -1
- package/dist/components/layouts/NavBar.mjs +2 -2
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/layouts/NotificationsPopover.mjs +4 -4
- package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
- package/dist/components/layouts/ProfilePopover.mjs +7 -10
- package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
- package/dist/components/layouts/UsersSelectorPopover.mjs +5 -5
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/ProjectSelectorPopover.mjs +6 -6
- package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs +5 -5
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
- package/dist/components/pages/notifications/Notifications.mjs +4 -4
- package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
- package/dist/components/ui/buttons/CopyButton.mjs +2 -2
- package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
- package/dist/components/ui/data-display/Accordion.mjs +2 -2
- package/dist/components/ui/data-display/Accordion.mjs.map +1 -1
- package/dist/components/ui/data-display/Pagination.mjs +7 -7
- package/dist/components/ui/data-display/Pagination.mjs.map +1 -1
- package/dist/components/ui/feedback/Toast.mjs +7 -7
- package/dist/components/ui/feedback/Toast.mjs.map +1 -1
- package/dist/components/ui/form/Calendar.mjs +7 -7
- package/dist/components/ui/form/Calendar.mjs.map +1 -1
- package/dist/components/ui/form/Checkbox.mjs +2 -2
- package/dist/components/ui/form/Checkbox.mjs.map +1 -1
- package/dist/components/ui/form/ComboboxField.mjs +4 -4
- package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
- package/dist/components/ui/form/DateRangePicker.mjs +2 -2
- package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
- package/dist/components/ui/form/FormField.mjs +3 -3
- package/dist/components/ui/form/FormField.mjs.map +1 -1
- package/dist/components/ui/form/InputOtp.mjs +2 -2
- package/dist/components/ui/form/InputOtp.mjs.map +1 -1
- package/dist/components/ui/form/RadioGroup.mjs +2 -2
- package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
- package/dist/components/ui/form/Select.mjs +5 -5
- package/dist/components/ui/form/Select.mjs.map +1 -1
- package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs.map +1 -1
- package/dist/components/ui/overlay/Command.mjs +2 -2
- package/dist/components/ui/overlay/Command.mjs.map +1 -1
- package/dist/components/ui/overlay/Dialog.mjs +2 -2
- package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
- package/dist/components/ui/overlay/Sheet.mjs +2 -2
- package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
- package/dist/components/widgets/notifications/NotificationCard.mjs +2 -2
- package/dist/components/widgets/notifications/NotificationCard.mjs.map +1 -1
- package/package.json +1 -2
- package/src/components/account/ConfigurationsMyAccountModal.tsx +150 -150
- package/src/components/account/ConfirmDeleteAccountModal.tsx +2 -2
- package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -66
- package/src/components/account/DeleteAccountModal.tsx +3 -3
- package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -86
- package/src/components/account/IsntPossibleDeleteAccountModal.tsx +2 -2
- package/src/components/account/TwoFactorAuthModal.tsx +223 -223
- package/src/components/account/sections/ChangeEmailModal.tsx +225 -225
- package/src/components/account/sections/ChangePasswordSection.tsx +64 -64
- package/src/components/account/sections/ChangePhoneModal.tsx +5 -5
- package/src/components/account/sections/MyProfileSection.tsx +327 -327
- package/src/components/account/sections/PreferencesSection.tsx +273 -273
- package/src/components/account/sections/SecuritySection.tsx +160 -160
- package/src/components/layouts/AppMobileNavBar.tsx +0 -1
- package/src/components/layouts/MdSideBarNavigation.tsx +54 -54
- package/src/components/layouts/NavBar.tsx +2 -2
- package/src/components/layouts/NotificationsPopover.tsx +115 -115
- package/src/components/layouts/ProfilePopover.tsx +179 -184
- package/src/components/layouts/UsersSelectorPopover.tsx +5 -5
- package/src/components/navigation/ProjectSelectorPopover.tsx +151 -151
- package/src/components/navigation/subcomponents/ProjectSelector.tsx +149 -149
- package/src/components/pages/notifications/Notifications.tsx +4 -4
- package/src/components/ui/buttons/CopyButton.tsx +2 -2
- package/src/components/ui/data-display/Accordion.tsx +2 -2
- package/src/components/ui/data-display/Pagination.tsx +7 -7
- package/src/components/ui/feedback/Toast.tsx +7 -7
- package/src/components/ui/form/Calendar.tsx +7 -7
- package/src/components/ui/form/Checkbox.tsx +2 -2
- package/src/components/ui/form/ComboboxField.tsx +154 -154
- package/src/components/ui/form/DateRangePicker.tsx +2 -2
- package/src/components/ui/form/FormField.tsx +131 -130
- package/src/components/ui/form/InputOtp.tsx +2 -2
- package/src/components/ui/form/RadioGroup.tsx +2 -2
- package/src/components/ui/form/Select.tsx +5 -5
- package/src/components/ui/form/SwitchOptionFieldWithIcon.tsx +2 -2
- package/src/components/ui/overlay/Command.tsx +2 -2
- package/src/components/ui/overlay/Dialog.tsx +2 -2
- package/src/components/ui/overlay/Sheet.tsx +2 -2
- package/src/components/widgets/notifications/NotificationCard.tsx +68 -68
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import {
|
|
5
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
-
import { Popover } from "../ui/overlay/Popover";
|
|
7
|
-
import { Button } from "../ui/buttons/Button";
|
|
8
|
-
import NotificationCard from "../widgets/notifications/NotificationCard";
|
|
9
|
-
import { cn } from "../../infra/utils/clsx";
|
|
10
|
-
import { useMessages, useMarkAllMessagesAsRead } from "../../modules/users/hooks/messages.hook";
|
|
11
|
-
import { formatDistanceToNow } from "date-fns";
|
|
12
|
-
import { ptBR } from "date-fns/locale";
|
|
13
|
-
|
|
14
|
-
export interface NotificationsPopoverProps {
|
|
15
|
-
onViewAll?: () => void;
|
|
16
|
-
side?: "top" | "bottom" | "left" | "right";
|
|
17
|
-
align?: "start" | "center" | "end";
|
|
18
|
-
contentClassName?: string;
|
|
19
|
-
badgeClassName?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function NotificationsPopover({
|
|
23
|
-
onViewAll,
|
|
24
|
-
side,
|
|
25
|
-
align,
|
|
26
|
-
contentClassName,
|
|
27
|
-
badgeClassName = "bg-pages-400",
|
|
28
|
-
}: NotificationsPopoverProps) {
|
|
29
|
-
const [open, setOpen] = useState(false);
|
|
30
|
-
const { data: messagesData } = useMessages({ type: 'notification', readed: true, limit: 5 });
|
|
31
|
-
const { mutate: markAllAsRead } = useMarkAllMessagesAsRead();
|
|
32
|
-
|
|
33
|
-
const messages = messagesData?.data ?? [];
|
|
34
|
-
const totalUnread = messagesData?.totalUnread ?? 0;
|
|
35
|
-
|
|
36
|
-
const handleOpenChange = (isOpen: boolean) => {
|
|
37
|
-
setOpen(isOpen);
|
|
38
|
-
if (isOpen && totalUnread > 0) {
|
|
39
|
-
markAllAsRead();
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
45
|
-
<PopoverPrimitive.Trigger className="cursor-pointer">
|
|
46
|
-
<div
|
|
47
|
-
className={`relative rounded-full p-2.5 ${open ? "bg-gray-100" : "hover:bg-gray-100"}`}
|
|
48
|
-
>
|
|
49
|
-
<
|
|
50
|
-
{totalUnread > 0 && (
|
|
51
|
-
<span
|
|
52
|
-
className={cn(
|
|
53
|
-
"absolute top-2 right-2 size-2.5 rounded-full",
|
|
54
|
-
badgeClassName,
|
|
55
|
-
)}
|
|
56
|
-
/>
|
|
57
|
-
)}
|
|
58
|
-
</div>
|
|
59
|
-
</PopoverPrimitive.Trigger>
|
|
60
|
-
<PopoverPrimitive.Portal>
|
|
61
|
-
<PopoverPrimitive.Content
|
|
62
|
-
className={cn(
|
|
63
|
-
"absolute bottom-2 left-[26px] z-[9999] w-[308px] p-0 pt-4 bg-white rounded-2xl shadow-md border border-gray-200",
|
|
64
|
-
contentClassName,
|
|
65
|
-
)}
|
|
66
|
-
side={side}
|
|
67
|
-
align={align}
|
|
68
|
-
sideOffset={8}
|
|
69
|
-
>
|
|
70
|
-
<span className="paragraph-small-semibold text-gray-950 px-4">
|
|
71
|
-
Últimas notificações
|
|
72
|
-
</span>
|
|
73
|
-
|
|
74
|
-
{messages.length > 0 ? (
|
|
75
|
-
messages.map((message, index) => (
|
|
76
|
-
<NotificationCard
|
|
77
|
-
key={message.id}
|
|
78
|
-
icon={<
|
|
79
|
-
iconBgColor="bg-gray-100"
|
|
80
|
-
title={message.subject}
|
|
81
|
-
time={formatDistanceToNow(new Date(message.datetime_add), {
|
|
82
|
-
addSuffix: true,
|
|
83
|
-
locale: ptBR,
|
|
84
|
-
})}
|
|
85
|
-
gapPx={6}
|
|
86
|
-
showBorder={index < messages.length - 1}
|
|
87
|
-
/>
|
|
88
|
-
))
|
|
89
|
-
) : (
|
|
90
|
-
<div className="flex flex-col items-center gap-4 pt-[41.5px] pb-[33.5px]">
|
|
91
|
-
<div className="bg-gray-50 rounded-md p-2.5">
|
|
92
|
-
<
|
|
93
|
-
</div>
|
|
94
|
-
<span className="paragraph-small-medium text-gray-950">
|
|
95
|
-
Sem notificações por enquanto
|
|
96
|
-
</span>
|
|
97
|
-
</div>
|
|
98
|
-
)}
|
|
99
|
-
|
|
100
|
-
{onViewAll && (
|
|
101
|
-
<Button
|
|
102
|
-
variant="secondary"
|
|
103
|
-
className="h-8! mt-2 mb-4 mx-4 paragraph-small-semibold"
|
|
104
|
-
onClick={onViewAll}
|
|
105
|
-
>
|
|
106
|
-
Todas as notificações
|
|
107
|
-
</Button>
|
|
108
|
-
)}
|
|
109
|
-
</PopoverPrimitive.Content>
|
|
110
|
-
</PopoverPrimitive.Portal>
|
|
111
|
-
</Popover>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export { NotificationsPopover };
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { IconBell } from '@tabler/icons-react';
|
|
5
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
+
import { Popover } from "../ui/overlay/Popover";
|
|
7
|
+
import { Button } from "../ui/buttons/Button";
|
|
8
|
+
import NotificationCard from "../widgets/notifications/NotificationCard";
|
|
9
|
+
import { cn } from "../../infra/utils/clsx";
|
|
10
|
+
import { useMessages, useMarkAllMessagesAsRead } from "../../modules/users/hooks/messages.hook";
|
|
11
|
+
import { formatDistanceToNow } from "date-fns";
|
|
12
|
+
import { ptBR } from "date-fns/locale";
|
|
13
|
+
|
|
14
|
+
export interface NotificationsPopoverProps {
|
|
15
|
+
onViewAll?: () => void;
|
|
16
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
17
|
+
align?: "start" | "center" | "end";
|
|
18
|
+
contentClassName?: string;
|
|
19
|
+
badgeClassName?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function NotificationsPopover({
|
|
23
|
+
onViewAll,
|
|
24
|
+
side,
|
|
25
|
+
align,
|
|
26
|
+
contentClassName,
|
|
27
|
+
badgeClassName = "bg-pages-400",
|
|
28
|
+
}: NotificationsPopoverProps) {
|
|
29
|
+
const [open, setOpen] = useState(false);
|
|
30
|
+
const { data: messagesData } = useMessages({ type: 'notification', readed: true, limit: 5 });
|
|
31
|
+
const { mutate: markAllAsRead } = useMarkAllMessagesAsRead();
|
|
32
|
+
|
|
33
|
+
const messages = messagesData?.data ?? [];
|
|
34
|
+
const totalUnread = messagesData?.totalUnread ?? 0;
|
|
35
|
+
|
|
36
|
+
const handleOpenChange = (isOpen: boolean) => {
|
|
37
|
+
setOpen(isOpen);
|
|
38
|
+
if (isOpen && totalUnread > 0) {
|
|
39
|
+
markAllAsRead();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
45
|
+
<PopoverPrimitive.Trigger className="cursor-pointer">
|
|
46
|
+
<div
|
|
47
|
+
className={`relative rounded-full p-2.5 ${open ? "bg-gray-100" : "hover:bg-gray-100"}`}
|
|
48
|
+
>
|
|
49
|
+
<IconBell size={20} className="text-gray-500" />
|
|
50
|
+
{totalUnread > 0 && (
|
|
51
|
+
<span
|
|
52
|
+
className={cn(
|
|
53
|
+
"absolute top-2 right-2 size-2.5 rounded-full",
|
|
54
|
+
badgeClassName,
|
|
55
|
+
)}
|
|
56
|
+
/>
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
</PopoverPrimitive.Trigger>
|
|
60
|
+
<PopoverPrimitive.Portal>
|
|
61
|
+
<PopoverPrimitive.Content
|
|
62
|
+
className={cn(
|
|
63
|
+
"absolute bottom-2 left-[26px] z-[9999] w-[308px] p-0 pt-4 bg-white rounded-2xl shadow-md border border-gray-200",
|
|
64
|
+
contentClassName,
|
|
65
|
+
)}
|
|
66
|
+
side={side}
|
|
67
|
+
align={align}
|
|
68
|
+
sideOffset={8}
|
|
69
|
+
>
|
|
70
|
+
<span className="paragraph-small-semibold text-gray-950 px-4">
|
|
71
|
+
Últimas notificações
|
|
72
|
+
</span>
|
|
73
|
+
|
|
74
|
+
{messages.length > 0 ? (
|
|
75
|
+
messages.map((message, index) => (
|
|
76
|
+
<NotificationCard
|
|
77
|
+
key={message.id}
|
|
78
|
+
icon={<IconBell size={16} />}
|
|
79
|
+
iconBgColor="bg-gray-100"
|
|
80
|
+
title={message.subject}
|
|
81
|
+
time={formatDistanceToNow(new Date(message.datetime_add), {
|
|
82
|
+
addSuffix: true,
|
|
83
|
+
locale: ptBR,
|
|
84
|
+
})}
|
|
85
|
+
gapPx={6}
|
|
86
|
+
showBorder={index < messages.length - 1}
|
|
87
|
+
/>
|
|
88
|
+
))
|
|
89
|
+
) : (
|
|
90
|
+
<div className="flex flex-col items-center gap-4 pt-[41.5px] pb-[33.5px]">
|
|
91
|
+
<div className="bg-gray-50 rounded-md p-2.5">
|
|
92
|
+
<IconBell size={20} color="var(--color-gray-950)" />
|
|
93
|
+
</div>
|
|
94
|
+
<span className="paragraph-small-medium text-gray-950">
|
|
95
|
+
Sem notificações por enquanto
|
|
96
|
+
</span>
|
|
97
|
+
</div>
|
|
98
|
+
)}
|
|
99
|
+
|
|
100
|
+
{onViewAll && (
|
|
101
|
+
<Button
|
|
102
|
+
variant="secondary"
|
|
103
|
+
className="h-8! mt-2 mb-4 mx-4 paragraph-small-semibold"
|
|
104
|
+
onClick={onViewAll}
|
|
105
|
+
>
|
|
106
|
+
Todas as notificações
|
|
107
|
+
</Button>
|
|
108
|
+
)}
|
|
109
|
+
</PopoverPrimitive.Content>
|
|
110
|
+
</PopoverPrimitive.Portal>
|
|
111
|
+
</Popover>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { NotificationsPopover };
|
|
@@ -1,184 +1,179 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { useRouter } from "next/navigation";
|
|
5
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
-
import { Popover } from "../ui/overlay/Popover";
|
|
7
|
-
import { Progress } from "../ui/feedback/Progress";
|
|
8
|
-
import { Separator } from "../ui/data-display/Separator";
|
|
9
|
-
import {
|
|
10
|
-
import { NavBarItem } from "./NavBarItem";
|
|
11
|
-
import { UserAvatar } from "../ui/data-display/UserAvatar";
|
|
12
|
-
import { LoadingOverlay } from "../ui/feedback/LoadingOverlay";
|
|
13
|
-
import { useAuth } from "../../providers/auth.provider";
|
|
14
|
-
import { cn } from "../../infra/utils/clsx";
|
|
15
|
-
import { useIaCredits } from "../../modules/ia-credits/hooks/ia-credits.hook";
|
|
16
|
-
|
|
17
|
-
export interface ProfileMenuItem {
|
|
18
|
-
icon?: React.ReactNode;
|
|
19
|
-
label: string;
|
|
20
|
-
onClick: () => void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ProfilePopoverProps {
|
|
24
|
-
side?: "top" | "bottom" | "left" | "right";
|
|
25
|
-
align?: "start" | "center" | "end";
|
|
26
|
-
contentClassName?: string;
|
|
27
|
-
onEditProfile?: () => void;
|
|
28
|
-
onCreditsClick?: () => void;
|
|
29
|
-
menuItems?: ProfileMenuItem[];
|
|
30
|
-
logoutRedirect?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function ProfilePopover({
|
|
34
|
-
side = "top",
|
|
35
|
-
align = "start",
|
|
36
|
-
contentClassName = "absolute bottom-2 left-[26px]",
|
|
37
|
-
onEditProfile,
|
|
38
|
-
onCreditsClick,
|
|
39
|
-
menuItems = [],
|
|
40
|
-
logoutRedirect = "/login",
|
|
41
|
-
}: ProfilePopoverProps) {
|
|
42
|
-
const router = useRouter();
|
|
43
|
-
const { user, logout } = useAuth();
|
|
44
|
-
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
45
|
-
|
|
46
|
-
const { summary, subscription, isSubscriptionLoading, isCreditsLoading } =
|
|
47
|
-
useIaCredits();
|
|
48
|
-
|
|
49
|
-
const handleLogout = async () => {
|
|
50
|
-
try {
|
|
51
|
-
setIsLoggingOut(true);
|
|
52
|
-
await logout();
|
|
53
|
-
} finally {
|
|
54
|
-
setIsLoggingOut(false);
|
|
55
|
-
if (logoutRedirect !== "/login") {
|
|
56
|
-
router.push(logoutRedirect);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const hasSubscription = !isSubscriptionLoading && subscription !== null;
|
|
62
|
-
const showCreditsSkeleton = hasSubscription && isCreditsLoading;
|
|
63
|
-
const showCredits =
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</>
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export { ProfilePopover };
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
+
import { Popover } from "../ui/overlay/Popover";
|
|
7
|
+
import { Progress } from "../ui/feedback/Progress";
|
|
8
|
+
import { Separator } from "../ui/data-display/Separator";
|
|
9
|
+
import { IconSettings } from "@tabler/icons-react";
|
|
10
|
+
import { NavBarItem } from "./NavBarItem";
|
|
11
|
+
import { UserAvatar } from "../ui/data-display/UserAvatar";
|
|
12
|
+
import { LoadingOverlay } from "../ui/feedback/LoadingOverlay";
|
|
13
|
+
import { useAuth } from "../../providers/auth.provider";
|
|
14
|
+
import { cn } from "../../infra/utils/clsx";
|
|
15
|
+
import { useIaCredits } from "../../modules/ia-credits/hooks/ia-credits.hook";
|
|
16
|
+
|
|
17
|
+
export interface ProfileMenuItem {
|
|
18
|
+
icon?: React.ReactNode;
|
|
19
|
+
label: string;
|
|
20
|
+
onClick: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ProfilePopoverProps {
|
|
24
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
25
|
+
align?: "start" | "center" | "end";
|
|
26
|
+
contentClassName?: string;
|
|
27
|
+
onEditProfile?: () => void;
|
|
28
|
+
onCreditsClick?: () => void;
|
|
29
|
+
menuItems?: ProfileMenuItem[];
|
|
30
|
+
logoutRedirect?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ProfilePopover({
|
|
34
|
+
side = "top",
|
|
35
|
+
align = "start",
|
|
36
|
+
contentClassName = "absolute bottom-2 left-[26px]",
|
|
37
|
+
onEditProfile,
|
|
38
|
+
onCreditsClick,
|
|
39
|
+
menuItems = [],
|
|
40
|
+
logoutRedirect = "/login",
|
|
41
|
+
}: ProfilePopoverProps) {
|
|
42
|
+
const router = useRouter();
|
|
43
|
+
const { user, logout } = useAuth();
|
|
44
|
+
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
45
|
+
|
|
46
|
+
const { summary, subscription, isSubscriptionLoading, isCreditsLoading } =
|
|
47
|
+
useIaCredits();
|
|
48
|
+
|
|
49
|
+
const handleLogout = async () => {
|
|
50
|
+
try {
|
|
51
|
+
setIsLoggingOut(true);
|
|
52
|
+
await logout();
|
|
53
|
+
} finally {
|
|
54
|
+
setIsLoggingOut(false);
|
|
55
|
+
if (logoutRedirect !== "/login") {
|
|
56
|
+
router.push(logoutRedirect);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const hasSubscription = !isSubscriptionLoading && subscription !== null;
|
|
62
|
+
const showCreditsSkeleton = hasSubscription && isCreditsLoading;
|
|
63
|
+
const showCredits = hasSubscription && !isCreditsLoading;
|
|
64
|
+
const creditsPercentage =
|
|
65
|
+
showCredits && summary.totalCredits > 0
|
|
66
|
+
? (summary.usedCredits / summary.totalCredits) * 100
|
|
67
|
+
: 0;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<LoadingOverlay
|
|
72
|
+
isLoading={isLoggingOut}
|
|
73
|
+
message="Saindo da sua conta..."
|
|
74
|
+
/>
|
|
75
|
+
<Popover>
|
|
76
|
+
<PopoverPrimitive.Trigger className="cursor-pointer">
|
|
77
|
+
{user && (
|
|
78
|
+
<UserAvatar
|
|
79
|
+
key={user.id}
|
|
80
|
+
photo={user.photo}
|
|
81
|
+
name={user.name}
|
|
82
|
+
size={40}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
85
|
+
</PopoverPrimitive.Trigger>
|
|
86
|
+
|
|
87
|
+
<PopoverPrimitive.Portal>
|
|
88
|
+
<PopoverPrimitive.Content
|
|
89
|
+
className={cn(
|
|
90
|
+
"w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99",
|
|
91
|
+
contentClassName,
|
|
92
|
+
)}
|
|
93
|
+
side={side}
|
|
94
|
+
align={align}
|
|
95
|
+
sideOffset={8}
|
|
96
|
+
>
|
|
97
|
+
<div className="grid grid-cols-[32px_1fr] items-center gap-3 p-3 w-full">
|
|
98
|
+
{user && (
|
|
99
|
+
<UserAvatar
|
|
100
|
+
key={user.id}
|
|
101
|
+
photo={user.photo}
|
|
102
|
+
name={user.name}
|
|
103
|
+
size={32}
|
|
104
|
+
/>
|
|
105
|
+
)}
|
|
106
|
+
|
|
107
|
+
<div className="flex flex-col gap-0.5 min-w-0">
|
|
108
|
+
<span className="paragraph-small-semibold text-gray-950 truncate">
|
|
109
|
+
{user?.name || ""}
|
|
110
|
+
</span>
|
|
111
|
+
<span className="paragraph-xsmall-medium text-gray-500 truncate">
|
|
112
|
+
{user?.email || ""}
|
|
113
|
+
</span>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div className="flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5">
|
|
118
|
+
{showCreditsSkeleton && (
|
|
119
|
+
<div className="flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4">
|
|
120
|
+
<div className="flex items-center justify-between gap-2">
|
|
121
|
+
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
122
|
+
Créditos usados
|
|
123
|
+
</span>
|
|
124
|
+
<div className="skeleton h-3.5 w-16 rounded" />
|
|
125
|
+
</div>
|
|
126
|
+
<div className="skeleton h-1.5 w-full rounded-full" />
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
{showCredits && (
|
|
131
|
+
<div
|
|
132
|
+
className={cn(
|
|
133
|
+
"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors",
|
|
134
|
+
onCreditsClick && "cursor-pointer hover:bg-gray-900",
|
|
135
|
+
)}
|
|
136
|
+
onClick={onCreditsClick}
|
|
137
|
+
>
|
|
138
|
+
<div className="flex items-center justify-between gap-2">
|
|
139
|
+
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
140
|
+
Créditos usados
|
|
141
|
+
</span>
|
|
142
|
+
<span className="paragraph-xsmall-medium text-white/50">
|
|
143
|
+
{summary.usedCredits.toLocaleString("pt-BR")}/
|
|
144
|
+
{summary.totalCredits.toLocaleString("pt-BR")}
|
|
145
|
+
</span>
|
|
146
|
+
</div>
|
|
147
|
+
<Progress
|
|
148
|
+
className="bg-white/10"
|
|
149
|
+
indicatorColor="bg-white"
|
|
150
|
+
value={creditsPercentage}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
)}
|
|
154
|
+
|
|
155
|
+
<div className="flex flex-col gap-2">
|
|
156
|
+
{menuItems.length > 0 && (
|
|
157
|
+
<div className="flex flex-col">
|
|
158
|
+
{menuItems.map((item, index) => (
|
|
159
|
+
<NavBarItem
|
|
160
|
+
key={index}
|
|
161
|
+
icon={item.icon}
|
|
162
|
+
label={item.label}
|
|
163
|
+
onClick={item.onClick}
|
|
164
|
+
/>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
)}
|
|
168
|
+
<Separator />
|
|
169
|
+
<NavBarItem label="Sair" onClick={handleLogout} />
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</PopoverPrimitive.Content>
|
|
173
|
+
</PopoverPrimitive.Portal>
|
|
174
|
+
</Popover>
|
|
175
|
+
</>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export { ProfilePopover };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { IconPlus, IconSettings, IconUser, IconUsers } from '@tabler/icons-react';
|
|
5
5
|
import { UserAvatar } from "../ui/data-display/UserAvatar";
|
|
6
6
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay/Popover";
|
|
7
7
|
import { Button } from "../ui/buttons/Button";
|
|
@@ -93,7 +93,7 @@ export function UsersSelectorPopover({
|
|
|
93
93
|
<PopoverTrigger className="cursor-pointer">
|
|
94
94
|
<div className="flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950">
|
|
95
95
|
<span className="paragraph-small-semibold">{totalInProject}</span>
|
|
96
|
-
<
|
|
96
|
+
<IconUser size={16} />
|
|
97
97
|
</div>
|
|
98
98
|
</PopoverTrigger>
|
|
99
99
|
|
|
@@ -117,7 +117,7 @@ export function UsersSelectorPopover({
|
|
|
117
117
|
window.location.href = `${GAPPS_URL}/my-teams?createNew=true`;
|
|
118
118
|
}}
|
|
119
119
|
>
|
|
120
|
-
<
|
|
120
|
+
<IconPlus size={16} />
|
|
121
121
|
Adicionar
|
|
122
122
|
</Button>
|
|
123
123
|
<Tooltip>
|
|
@@ -129,7 +129,7 @@ export function UsersSelectorPopover({
|
|
|
129
129
|
window.location.href = `${GAPPS_URL}/my-teams`;
|
|
130
130
|
}}
|
|
131
131
|
>
|
|
132
|
-
<
|
|
132
|
+
<IconSettings size={18} />
|
|
133
133
|
</Button>
|
|
134
134
|
</TooltipTrigger>
|
|
135
135
|
<TooltipContent className="z-[1002]">
|
|
@@ -157,7 +157,7 @@ export function UsersSelectorPopover({
|
|
|
157
157
|
</>
|
|
158
158
|
) : allUsers.length === 0 ? (
|
|
159
159
|
<div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
|
|
160
|
-
<
|
|
160
|
+
<IconUsers size={28} className="text-gray-300" />
|
|
161
161
|
<span className="paragraph-small-medium text-center text-gray-500">
|
|
162
162
|
Nenhum usuário encontrado.
|
|
163
163
|
</span>
|