@greatapps/common 1.1.168 → 1.1.169
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/ConfirmDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/DeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -1
- package/dist/components/account/hooks/useTwoFactorAuthForm.mjs.map +1 -1
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
- package/dist/components/layouts/AppNavBar.mjs.map +1 -1
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/navigation/CancelledSubscriptionBanner.mjs.map +1 -1
- package/dist/components/navigation/NavItemsContext.mjs.map +1 -1
- package/dist/components/navigation/shells/TabsMobileShell.mjs.map +1 -1
- package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
- package/dist/components/ui/buttons/Button.mjs.map +1 -1
- package/dist/components/ui/buttons/CancelButton.mjs.map +1 -1
- package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
- package/dist/components/ui/data-display/Accordion.mjs.map +1 -1
- package/dist/components/ui/data-display/Badge.mjs.map +1 -1
- package/dist/components/ui/data-display/Card.mjs.map +1 -1
- package/dist/components/ui/data-display/Pagination.mjs.map +1 -1
- package/dist/components/ui/data-display/ScrollArea.mjs.map +1 -1
- package/dist/components/ui/data-display/Separator.mjs.map +1 -1
- package/dist/components/ui/data-display/Table.mjs.map +1 -1
- package/dist/components/ui/data-display/Tabs.mjs.map +1 -1
- package/dist/components/ui/feedback/CircularProgress.mjs.map +1 -1
- package/dist/components/ui/feedback/DefaultCircularProgress.mjs.map +1 -1
- package/dist/components/ui/feedback/LoadingOverlay.mjs.map +1 -1
- package/dist/components/ui/feedback/Progress.mjs.map +1 -1
- package/dist/components/ui/feedback/Toast.mjs.map +1 -1
- package/dist/components/ui/form/Calendar.mjs.map +1 -1
- package/dist/components/ui/form/Checkbox.mjs.map +1 -1
- package/dist/components/ui/form/DatePicker.mjs.map +1 -1
- package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
- package/dist/components/ui/form/Input.mjs.map +1 -1
- package/dist/components/ui/form/InputOtp.mjs.map +1 -1
- package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
- package/dist/components/ui/form/Select.mjs +1 -1
- package/dist/components/ui/form/Select.mjs.map +1 -1
- package/dist/components/ui/form/Switch.mjs.map +1 -1
- package/dist/components/ui/form/Textarea.mjs.map +1 -1
- package/dist/components/ui/overlay/Command.mjs.map +1 -1
- package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
- package/dist/components/ui/overlay/Popover.mjs.map +1 -1
- package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
- package/dist/components/ui/overlay/Tooltip.mjs.map +1 -1
- package/dist/hooks/copy-to-clipboard.hook.mjs.map +1 -1
- package/dist/index.mjs +26 -24
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.mjs.map +1 -1
- package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -1
- package/dist/modules/accounts/actions/find-current-account.action.mjs.map +1 -1
- package/dist/modules/accounts/actions/list-currencies.action.mjs.map +1 -1
- package/dist/modules/accounts/actions/list-timezones.action.mjs.map +1 -1
- package/dist/modules/accounts/hooks/current-account.hook.mjs.map +1 -1
- package/dist/modules/accounts/hooks/useAccountManagement.mjs.map +1 -1
- package/dist/modules/accounts/hooks/useCurrencies.mjs.map +1 -1
- package/dist/modules/accounts/hooks/useTimezones.mjs.map +1 -1
- package/dist/modules/auth/hooks/login.hook.mjs.map +1 -1
- package/dist/modules/auth/hooks/logout.hook.mjs.map +1 -1
- package/dist/modules/auth/hooks/register.hook.mjs.map +1 -1
- package/dist/modules/ia-credits/actions/list-ia-credits.action.mjs.map +1 -1
- package/dist/modules/projects/actions/add-project-user.action.mjs.map +1 -1
- package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -1
- package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -1
- package/dist/modules/projects/actions/remove-project-user.action.mjs.map +1 -1
- package/dist/modules/projects/hooks/list-available-users.hook.mjs.map +1 -1
- package/dist/modules/projects/hooks/list-project-users.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/actions/list-subscriptions.action.mjs.map +1 -1
- package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
- package/dist/modules/subscriptions/hooks/list-subscriptions.hook.mjs.map +1 -1
- package/dist/modules/users/action/find-user-by-id.action.mjs.map +1 -1
- package/dist/modules/users/action/list-messages.action.mjs.map +1 -1
- package/dist/modules/users/action/mark-all-messages-as-read.action.mjs.map +1 -1
- package/dist/modules/users/action/mark-message-as-read.action.mjs.map +1 -1
- package/dist/modules/users/hooks/messages.hook.mjs.map +1 -1
- package/dist/modules/whitelabel/actions/find-whitelabel-styles.action.mjs.map +1 -1
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
- package/dist/modules/whitelabel/services/whitelabel-styles.service.mjs.map +1 -1
- package/dist/providers/whitelabel.provider.mjs.map +1 -1
- package/dist/utils/safeServerAction.mjs.map +1 -1
- package/dist/utils/withAction.mjs.map +1 -1
- package/package.json +90 -90
- package/src/components/account/ConfirmDeleteAccountModal.tsx +55 -55
- package/src/components/account/DeleteAccountModal.tsx +130 -130
- package/src/components/account/IsntPossibleDeleteAccountModal.tsx +49 -49
- package/src/components/account/hooks/useTwoFactorAuthForm.tsx +101 -101
- package/src/components/layouts/AppMobileNavBar.tsx +125 -125
- package/src/components/layouts/AppNavBar.tsx +57 -57
- package/src/components/layouts/NavBar.tsx +139 -139
- package/src/components/navigation/CancelledSubscriptionBanner.tsx +69 -69
- package/src/components/navigation/NavItemsContext.ts +20 -20
- package/src/components/navigation/shells/TabsMobileShell.tsx +72 -72
- package/src/components/pages/notifications/Notifications.tsx +160 -160
- package/src/components/ui/buttons/Button.tsx +57 -57
- package/src/components/ui/buttons/CancelButton.tsx +14 -14
- package/src/components/ui/buttons/CopyButton.tsx +54 -54
- package/src/components/ui/data-display/Accordion.tsx +81 -81
- package/src/components/ui/data-display/Badge.tsx +47 -47
- package/src/components/ui/data-display/Card.tsx +93 -93
- package/src/components/ui/data-display/Pagination.tsx +126 -126
- package/src/components/ui/data-display/ScrollArea.tsx +59 -59
- package/src/components/ui/data-display/Separator.tsx +29 -29
- package/src/components/ui/data-display/Table.tsx +117 -117
- package/src/components/ui/data-display/Tabs.tsx +67 -67
- package/src/components/ui/feedback/CircularProgress.tsx +75 -75
- package/src/components/ui/feedback/DefaultCircularProgress.tsx +53 -53
- package/src/components/ui/feedback/LoadingOverlay.tsx +31 -31
- package/src/components/ui/feedback/Progress.tsx +40 -40
- package/src/components/ui/feedback/Toast.tsx +101 -101
- package/src/components/ui/form/Calendar.tsx +228 -228
- package/src/components/ui/form/Checkbox.tsx +31 -31
- package/src/components/ui/form/DatePicker.tsx +97 -97
- package/src/components/ui/form/DateRangePicker.tsx +108 -108
- package/src/components/ui/form/Input.tsx +20 -20
- package/src/components/ui/form/InputOtp.tsx +80 -80
- package/src/components/ui/form/RadioGroup.tsx +45 -45
- package/src/components/ui/form/Select.tsx +200 -200
- package/src/components/ui/form/Switch.tsx +32 -32
- package/src/components/ui/form/Textarea.tsx +19 -19
- package/src/components/ui/overlay/Command.tsx +185 -185
- package/src/components/ui/overlay/Dialog.tsx +151 -151
- package/src/components/ui/overlay/Popover.tsx +49 -49
- package/src/components/ui/overlay/Sheet.tsx +159 -159
- package/src/components/ui/overlay/Tooltip.tsx +62 -62
- package/src/hooks/copy-to-clipboard.hook.tsx +67 -67
- package/src/index.ts +351 -348
- package/src/middleware.ts +4 -4
- package/src/modules/accounts/actions/account-management.action.ts +90 -90
- package/src/modules/accounts/actions/find-current-account.action.ts +9 -9
- package/src/modules/accounts/actions/list-currencies.action.ts +8 -8
- package/src/modules/accounts/actions/list-timezones.action.ts +8 -8
- package/src/modules/accounts/hooks/current-account.hook.tsx +22 -22
- package/src/modules/accounts/hooks/useAccountManagement.ts +85 -85
- package/src/modules/accounts/hooks/useCurrencies.ts +15 -15
- package/src/modules/accounts/hooks/useTimezones.ts +15 -15
- package/src/modules/accounts/types.ts +214 -214
- package/src/modules/auth/hooks/login.hook.tsx +13 -13
- package/src/modules/auth/hooks/logout.hook.tsx +11 -11
- package/src/modules/auth/hooks/register.hook.tsx +11 -11
- package/src/modules/ia-credits/actions/list-ia-credits.action.ts +8 -8
- package/src/modules/projects/actions/add-project-user.action.ts +9 -9
- package/src/modules/projects/actions/list-available-users.action.ts +9 -9
- package/src/modules/projects/actions/list-project-users.action.ts +9 -9
- package/src/modules/projects/actions/remove-project-user.action.ts +9 -9
- package/src/modules/projects/hooks/list-available-users.hook.ts +33 -33
- package/src/modules/projects/hooks/list-project-users.hook.ts +33 -33
- package/src/modules/subscriptions/actions/list-subscriptions.action.ts +9 -9
- package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +19 -19
- package/src/modules/subscriptions/hooks/list-subscriptions.hook.ts +17 -17
- package/src/modules/users/action/find-user-by-id.action.ts +8 -8
- package/src/modules/users/action/list-messages.action.ts +12 -12
- package/src/modules/users/action/mark-all-messages-as-read.action.ts +8 -8
- package/src/modules/users/action/mark-message-as-read.action.ts +8 -8
- package/src/modules/users/hooks/messages.hook.ts +60 -60
- package/src/modules/whitelabel/actions/find-whitelabel-styles.action.ts +14 -14
- package/src/modules/whitelabel/actions/find-whitelabel.action.ts +23 -23
- package/src/modules/whitelabel/services/whitelabel-styles.service.ts +98 -98
- package/src/modules/whitelabel/styles-schema.ts +37 -37
- package/src/providers/whitelabel.provider.tsx +46 -46
- package/src/utils/safeServerAction.ts +21 -21
- package/src/utils/withAction.ts +13 -13
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Bell, Check, Loader2 } from "lucide-react";
|
|
4
|
-
import { Button } from "../../ui/buttons/Button";
|
|
5
|
-
import {
|
|
6
|
-
Tabs,
|
|
7
|
-
TabsContent,
|
|
8
|
-
TabsList,
|
|
9
|
-
TabsTrigger,
|
|
10
|
-
} from "../../ui/data-display/Tabs";
|
|
11
|
-
import { useInfiniteMessages, useMarkAllMessagesAsRead } from "../../../modules/users/hooks/messages.hook";
|
|
12
|
-
import NotificationCard from "../../widgets/notifications/NotificationCard";
|
|
13
|
-
import { Toast } from "../../ui/feedback/Toast";
|
|
14
|
-
import { formatDistanceToNow } from "date-fns";
|
|
15
|
-
import { ptBR } from "date-fns/locale";
|
|
16
|
-
import { toast } from "sonner";
|
|
17
|
-
import React from "react";
|
|
18
|
-
|
|
19
|
-
function NotificationsList({
|
|
20
|
-
pages,
|
|
21
|
-
isFetchingNextPage,
|
|
22
|
-
hasNextPage,
|
|
23
|
-
fetchNextPage,
|
|
24
|
-
}: {
|
|
25
|
-
pages: ReturnType<typeof useInfiniteMessages>["data"];
|
|
26
|
-
isFetchingNextPage: boolean;
|
|
27
|
-
hasNextPage: boolean;
|
|
28
|
-
fetchNextPage: () => void;
|
|
29
|
-
}) {
|
|
30
|
-
const notifications = pages?.pages.flatMap((p) => p.data) ?? [];
|
|
31
|
-
|
|
32
|
-
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
33
|
-
const target = e.currentTarget;
|
|
34
|
-
const nearBottom =
|
|
35
|
-
target.scrollTop + target.clientHeight >= target.scrollHeight - 50;
|
|
36
|
-
if (!nearBottom) return;
|
|
37
|
-
if (hasNextPage && !isFetchingNextPage) {
|
|
38
|
-
fetchNextPage();
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div
|
|
44
|
-
className="flex flex-col border border-gray-200 rounded-lg w-full bg-white max-h-[70vh] overflow-y-auto custom-scrollbar"
|
|
45
|
-
onScroll={handleScroll}
|
|
46
|
-
>
|
|
47
|
-
{notifications.map((notification, index) => (
|
|
48
|
-
<NotificationCard
|
|
49
|
-
key={notification.id}
|
|
50
|
-
icon={<Bell size={20} className="text-pages-600" />}
|
|
51
|
-
iconBgColor="bg-pages-100"
|
|
52
|
-
title={notification.subject}
|
|
53
|
-
description={notification.message}
|
|
54
|
-
gapPx={16}
|
|
55
|
-
time={formatDistanceToNow(new Date(notification.datetime_add), {
|
|
56
|
-
addSuffix: true,
|
|
57
|
-
locale: ptBR,
|
|
58
|
-
})}
|
|
59
|
-
isUnread={notification.status === 1}
|
|
60
|
-
showBorder={index < notifications.length - 1}
|
|
61
|
-
/>
|
|
62
|
-
))}
|
|
63
|
-
{isFetchingNextPage && (
|
|
64
|
-
<div className="flex items-center justify-center py-4">
|
|
65
|
-
<Loader2 size={20} className="animate-spin text-gray-400" />
|
|
66
|
-
</div>
|
|
67
|
-
)}
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function NotificationPageContent() {
|
|
73
|
-
const unreadNotifications = useInfiniteMessages({
|
|
74
|
-
readed: false,
|
|
75
|
-
type: "notification",
|
|
76
|
-
order: "desc",
|
|
77
|
-
});
|
|
78
|
-
const allNotifications = useInfiniteMessages({
|
|
79
|
-
type: "notification",
|
|
80
|
-
order: "desc",
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const totalAll = allNotifications.data?.pages[0]?.total ?? 0;
|
|
84
|
-
const totalUnread = unreadNotifications.data?.pages[0]?.total ?? 0;
|
|
85
|
-
|
|
86
|
-
const { mutate: markAllAsRead, isPending: isMarkingAll } = useMarkAllMessagesAsRead();
|
|
87
|
-
|
|
88
|
-
const handleMarkAllAsRead = () => {
|
|
89
|
-
markAllAsRead(undefined, {
|
|
90
|
-
onSuccess: () => {
|
|
91
|
-
toast.custom((t) => (
|
|
92
|
-
<Toast variant="success" message="Todas as notificações foram marcadas como lidas" toastId={t} />
|
|
93
|
-
));
|
|
94
|
-
},
|
|
95
|
-
onError: () => {
|
|
96
|
-
toast.custom((t) => (
|
|
97
|
-
<Toast variant="error" message="Erro ao marcar notificações como lidas" toastId={t} />
|
|
98
|
-
));
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
<div className="flex flex-col gap-6 lg:gap-10 px-4 py-6 lg:px-20 lg:py-14">
|
|
105
|
-
<div className="flex items-center justify-between gap-4">
|
|
106
|
-
<div className="flex flex-col gap-2">
|
|
107
|
-
<h1 className="paragraph-xlarge-semibold lg:title-large-semibold text-gray-950">
|
|
108
|
-
Notificações
|
|
109
|
-
</h1>
|
|
110
|
-
<p className="paragraph-medium-regular text-gray-600 hidden lg:block">
|
|
111
|
-
Tenha controle total sobre páginas, experiências e conversões.
|
|
112
|
-
</p>
|
|
113
|
-
</div>
|
|
114
|
-
<Button
|
|
115
|
-
variant={"secondary"}
|
|
116
|
-
className="h-10! lg:h-12! shrink-0"
|
|
117
|
-
onClick={handleMarkAllAsRead}
|
|
118
|
-
disabled={isMarkingAll || totalUnread === 0}
|
|
119
|
-
>
|
|
120
|
-
{isMarkingAll ? <Loader2 size={20} className="animate-spin" /> : <Check size={20} />}
|
|
121
|
-
<span className="lg:block hidden">Marcar todos como lidos</span>
|
|
122
|
-
<span className="lg:hidden">Marcar como lidos</span>
|
|
123
|
-
</Button>
|
|
124
|
-
</div>
|
|
125
|
-
<Tabs
|
|
126
|
-
defaultValue="all"
|
|
127
|
-
className="flex flex-col w-full bg-transparent gap-6 lg:gap-8"
|
|
128
|
-
>
|
|
129
|
-
<TabsList className="h-auto pb-0 bg-transparent">
|
|
130
|
-
<TabsTrigger className="gap-2" value="all">
|
|
131
|
-
Todas as notificações{" "}
|
|
132
|
-
<span className="text-gray-500">({totalAll})</span>
|
|
133
|
-
</TabsTrigger>
|
|
134
|
-
<TabsTrigger className="gap-2" value="unreads" disabled={totalUnread === 0}>
|
|
135
|
-
Não lidas{" "}
|
|
136
|
-
<span className="text-gray-500">({totalUnread})</span>
|
|
137
|
-
</TabsTrigger>
|
|
138
|
-
</TabsList>
|
|
139
|
-
|
|
140
|
-
<TabsContent value="all">
|
|
141
|
-
<NotificationsList
|
|
142
|
-
pages={allNotifications.data}
|
|
143
|
-
isFetchingNextPage={allNotifications.isFetchingNextPage}
|
|
144
|
-
hasNextPage={allNotifications.hasNextPage}
|
|
145
|
-
fetchNextPage={allNotifications.fetchNextPage}
|
|
146
|
-
/>
|
|
147
|
-
</TabsContent>
|
|
148
|
-
|
|
149
|
-
<TabsContent value="unreads">
|
|
150
|
-
<NotificationsList
|
|
151
|
-
pages={unreadNotifications.data}
|
|
152
|
-
isFetchingNextPage={unreadNotifications.isFetchingNextPage}
|
|
153
|
-
hasNextPage={unreadNotifications.hasNextPage}
|
|
154
|
-
fetchNextPage={unreadNotifications.fetchNextPage}
|
|
155
|
-
/>
|
|
156
|
-
</TabsContent>
|
|
157
|
-
</Tabs>
|
|
158
|
-
</div>
|
|
159
|
-
);
|
|
160
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Bell, Check, Loader2 } from "lucide-react";
|
|
4
|
+
import { Button } from "../../ui/buttons/Button";
|
|
5
|
+
import {
|
|
6
|
+
Tabs,
|
|
7
|
+
TabsContent,
|
|
8
|
+
TabsList,
|
|
9
|
+
TabsTrigger,
|
|
10
|
+
} from "../../ui/data-display/Tabs";
|
|
11
|
+
import { useInfiniteMessages, useMarkAllMessagesAsRead } from "../../../modules/users/hooks/messages.hook";
|
|
12
|
+
import NotificationCard from "../../widgets/notifications/NotificationCard";
|
|
13
|
+
import { Toast } from "../../ui/feedback/Toast";
|
|
14
|
+
import { formatDistanceToNow } from "date-fns";
|
|
15
|
+
import { ptBR } from "date-fns/locale";
|
|
16
|
+
import { toast } from "sonner";
|
|
17
|
+
import React from "react";
|
|
18
|
+
|
|
19
|
+
function NotificationsList({
|
|
20
|
+
pages,
|
|
21
|
+
isFetchingNextPage,
|
|
22
|
+
hasNextPage,
|
|
23
|
+
fetchNextPage,
|
|
24
|
+
}: {
|
|
25
|
+
pages: ReturnType<typeof useInfiniteMessages>["data"];
|
|
26
|
+
isFetchingNextPage: boolean;
|
|
27
|
+
hasNextPage: boolean;
|
|
28
|
+
fetchNextPage: () => void;
|
|
29
|
+
}) {
|
|
30
|
+
const notifications = pages?.pages.flatMap((p) => p.data) ?? [];
|
|
31
|
+
|
|
32
|
+
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
33
|
+
const target = e.currentTarget;
|
|
34
|
+
const nearBottom =
|
|
35
|
+
target.scrollTop + target.clientHeight >= target.scrollHeight - 50;
|
|
36
|
+
if (!nearBottom) return;
|
|
37
|
+
if (hasNextPage && !isFetchingNextPage) {
|
|
38
|
+
fetchNextPage();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
className="flex flex-col border border-gray-200 rounded-lg w-full bg-white max-h-[70vh] overflow-y-auto custom-scrollbar"
|
|
45
|
+
onScroll={handleScroll}
|
|
46
|
+
>
|
|
47
|
+
{notifications.map((notification, index) => (
|
|
48
|
+
<NotificationCard
|
|
49
|
+
key={notification.id}
|
|
50
|
+
icon={<Bell size={20} className="text-pages-600" />}
|
|
51
|
+
iconBgColor="bg-pages-100"
|
|
52
|
+
title={notification.subject}
|
|
53
|
+
description={notification.message}
|
|
54
|
+
gapPx={16}
|
|
55
|
+
time={formatDistanceToNow(new Date(notification.datetime_add), {
|
|
56
|
+
addSuffix: true,
|
|
57
|
+
locale: ptBR,
|
|
58
|
+
})}
|
|
59
|
+
isUnread={notification.status === 1}
|
|
60
|
+
showBorder={index < notifications.length - 1}
|
|
61
|
+
/>
|
|
62
|
+
))}
|
|
63
|
+
{isFetchingNextPage && (
|
|
64
|
+
<div className="flex items-center justify-center py-4">
|
|
65
|
+
<Loader2 size={20} className="animate-spin text-gray-400" />
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function NotificationPageContent() {
|
|
73
|
+
const unreadNotifications = useInfiniteMessages({
|
|
74
|
+
readed: false,
|
|
75
|
+
type: "notification",
|
|
76
|
+
order: "desc",
|
|
77
|
+
});
|
|
78
|
+
const allNotifications = useInfiniteMessages({
|
|
79
|
+
type: "notification",
|
|
80
|
+
order: "desc",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const totalAll = allNotifications.data?.pages[0]?.total ?? 0;
|
|
84
|
+
const totalUnread = unreadNotifications.data?.pages[0]?.total ?? 0;
|
|
85
|
+
|
|
86
|
+
const { mutate: markAllAsRead, isPending: isMarkingAll } = useMarkAllMessagesAsRead();
|
|
87
|
+
|
|
88
|
+
const handleMarkAllAsRead = () => {
|
|
89
|
+
markAllAsRead(undefined, {
|
|
90
|
+
onSuccess: () => {
|
|
91
|
+
toast.custom((t) => (
|
|
92
|
+
<Toast variant="success" message="Todas as notificações foram marcadas como lidas" toastId={t} />
|
|
93
|
+
));
|
|
94
|
+
},
|
|
95
|
+
onError: () => {
|
|
96
|
+
toast.custom((t) => (
|
|
97
|
+
<Toast variant="error" message="Erro ao marcar notificações como lidas" toastId={t} />
|
|
98
|
+
));
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="flex flex-col gap-6 lg:gap-10 px-4 py-6 lg:px-20 lg:py-14">
|
|
105
|
+
<div className="flex items-center justify-between gap-4">
|
|
106
|
+
<div className="flex flex-col gap-2">
|
|
107
|
+
<h1 className="paragraph-xlarge-semibold lg:title-large-semibold text-gray-950">
|
|
108
|
+
Notificações
|
|
109
|
+
</h1>
|
|
110
|
+
<p className="paragraph-medium-regular text-gray-600 hidden lg:block">
|
|
111
|
+
Tenha controle total sobre páginas, experiências e conversões.
|
|
112
|
+
</p>
|
|
113
|
+
</div>
|
|
114
|
+
<Button
|
|
115
|
+
variant={"secondary"}
|
|
116
|
+
className="h-10! lg:h-12! shrink-0"
|
|
117
|
+
onClick={handleMarkAllAsRead}
|
|
118
|
+
disabled={isMarkingAll || totalUnread === 0}
|
|
119
|
+
>
|
|
120
|
+
{isMarkingAll ? <Loader2 size={20} className="animate-spin" /> : <Check size={20} />}
|
|
121
|
+
<span className="lg:block hidden">Marcar todos como lidos</span>
|
|
122
|
+
<span className="lg:hidden">Marcar como lidos</span>
|
|
123
|
+
</Button>
|
|
124
|
+
</div>
|
|
125
|
+
<Tabs
|
|
126
|
+
defaultValue="all"
|
|
127
|
+
className="flex flex-col w-full bg-transparent gap-6 lg:gap-8"
|
|
128
|
+
>
|
|
129
|
+
<TabsList className="h-auto pb-0 bg-transparent">
|
|
130
|
+
<TabsTrigger className="gap-2" value="all">
|
|
131
|
+
Todas as notificações{" "}
|
|
132
|
+
<span className="text-gray-500">({totalAll})</span>
|
|
133
|
+
</TabsTrigger>
|
|
134
|
+
<TabsTrigger className="gap-2" value="unreads" disabled={totalUnread === 0}>
|
|
135
|
+
Não lidas{" "}
|
|
136
|
+
<span className="text-gray-500">({totalUnread})</span>
|
|
137
|
+
</TabsTrigger>
|
|
138
|
+
</TabsList>
|
|
139
|
+
|
|
140
|
+
<TabsContent value="all">
|
|
141
|
+
<NotificationsList
|
|
142
|
+
pages={allNotifications.data}
|
|
143
|
+
isFetchingNextPage={allNotifications.isFetchingNextPage}
|
|
144
|
+
hasNextPage={allNotifications.hasNextPage}
|
|
145
|
+
fetchNextPage={allNotifications.fetchNextPage}
|
|
146
|
+
/>
|
|
147
|
+
</TabsContent>
|
|
148
|
+
|
|
149
|
+
<TabsContent value="unreads">
|
|
150
|
+
<NotificationsList
|
|
151
|
+
pages={unreadNotifications.data}
|
|
152
|
+
isFetchingNextPage={unreadNotifications.isFetchingNextPage}
|
|
153
|
+
hasNextPage={unreadNotifications.hasNextPage}
|
|
154
|
+
fetchNextPage={unreadNotifications.fetchNextPage}
|
|
155
|
+
/>
|
|
156
|
+
</TabsContent>
|
|
157
|
+
</Tabs>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
5
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
-
import { cn } from "../../../infra/utils/clsx"
|
|
7
|
-
|
|
8
|
-
const buttonVariants = cva(
|
|
9
|
-
"paragraph-small-semibold cursor-pointer flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
10
|
-
{
|
|
11
|
-
variants: {
|
|
12
|
-
variant: {
|
|
13
|
-
default: " bg-gray-950 text-white hover:bg-gray-950/90",
|
|
14
|
-
secondary:
|
|
15
|
-
"bg-white text-gray-950 border-gray-200 hover:border-gray-400 border",
|
|
16
|
-
ghost:
|
|
17
|
-
"text-gray-600 hover:bg-accent hover:text-gray-950 dark:hover:bg-accent/50",
|
|
18
|
-
brand: "bg-pages-300 hover:bg-pages-200 text-gray-950",
|
|
19
|
-
},
|
|
20
|
-
size: {
|
|
21
|
-
default: "h-12 px-4 py-2 has-[>svg]:px-3",
|
|
22
|
-
sm: "rounded-md gap-1.5 px-2 py-2 has-[>svg]:px-2.5",
|
|
23
|
-
lg: "rounded-md px-6 has-[>svg]:px-4",
|
|
24
|
-
icon: "size-9",
|
|
25
|
-
"icon-sm": "size-8",
|
|
26
|
-
"icon-lg": "size-10",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
defaultVariants: {
|
|
30
|
-
variant: "default",
|
|
31
|
-
size: "default",
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
function Button({
|
|
37
|
-
className,
|
|
38
|
-
variant,
|
|
39
|
-
size,
|
|
40
|
-
asChild = false,
|
|
41
|
-
...props
|
|
42
|
-
}: React.ComponentProps<"button"> &
|
|
43
|
-
VariantProps<typeof buttonVariants> & {
|
|
44
|
-
asChild?: boolean
|
|
45
|
-
}) {
|
|
46
|
-
const Comp = asChild ? Slot : "button"
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<Comp
|
|
50
|
-
data-slot="button"
|
|
51
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
52
|
-
{...props}
|
|
53
|
-
/>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export { Button, buttonVariants }
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
import { cn } from "../../../infra/utils/clsx"
|
|
7
|
+
|
|
8
|
+
const buttonVariants = cva(
|
|
9
|
+
"paragraph-small-semibold cursor-pointer flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: " bg-gray-950 text-white hover:bg-gray-950/90",
|
|
14
|
+
secondary:
|
|
15
|
+
"bg-white text-gray-950 border-gray-200 hover:border-gray-400 border",
|
|
16
|
+
ghost:
|
|
17
|
+
"text-gray-600 hover:bg-accent hover:text-gray-950 dark:hover:bg-accent/50",
|
|
18
|
+
brand: "bg-pages-300 hover:bg-pages-200 text-gray-950",
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
default: "h-12 px-4 py-2 has-[>svg]:px-3",
|
|
22
|
+
sm: "rounded-md gap-1.5 px-2 py-2 has-[>svg]:px-2.5",
|
|
23
|
+
lg: "rounded-md px-6 has-[>svg]:px-4",
|
|
24
|
+
icon: "size-9",
|
|
25
|
+
"icon-sm": "size-8",
|
|
26
|
+
"icon-lg": "size-10",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
size: "default",
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
function Button({
|
|
37
|
+
className,
|
|
38
|
+
variant,
|
|
39
|
+
size,
|
|
40
|
+
asChild = false,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<"button"> &
|
|
43
|
+
VariantProps<typeof buttonVariants> & {
|
|
44
|
+
asChild?: boolean
|
|
45
|
+
}) {
|
|
46
|
+
const Comp = asChild ? Slot : "button"
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Comp
|
|
50
|
+
data-slot="button"
|
|
51
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { Button, buttonVariants }
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
export default function CancelButton({
|
|
6
|
-
...props
|
|
7
|
-
}: React.ComponentProps<"button">) {
|
|
8
|
-
return (
|
|
9
|
-
<button
|
|
10
|
-
className="flex h-8 px-2 justify-center items-center rounded-lg bg-red-50 text-red-600 font-semibold text-sm px-3 cursor-pointer hover:bg-red-100"
|
|
11
|
-
{...props}
|
|
12
|
-
/>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
export default function CancelButton({
|
|
6
|
+
...props
|
|
7
|
+
}: React.ComponentProps<"button">) {
|
|
8
|
+
return (
|
|
9
|
+
<button
|
|
10
|
+
className="flex h-8 px-2 justify-center items-center rounded-lg bg-red-50 text-red-600 font-semibold text-sm px-3 cursor-pointer hover:bg-red-100"
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Check, Copy } from "lucide-react";
|
|
4
|
-
import { toast } from "sonner";
|
|
5
|
-
import { Toast } from "../feedback/Toast";
|
|
6
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from "../overlay/Tooltip";
|
|
7
|
-
import useCopyToClipboard from "../../../hooks/copy-to-clipboard.hook";
|
|
8
|
-
import { cn } from "../../../infra/utils/clsx";
|
|
9
|
-
|
|
10
|
-
interface CopyButtonProps {
|
|
11
|
-
textToCopy: string;
|
|
12
|
-
size?: number;
|
|
13
|
-
className?: string;
|
|
14
|
-
tooltipText?: string;
|
|
15
|
-
successMessage?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function CopyButton({
|
|
19
|
-
textToCopy,
|
|
20
|
-
size = 14,
|
|
21
|
-
className,
|
|
22
|
-
tooltipText = "Copiar link",
|
|
23
|
-
successMessage = "Link copiado",
|
|
24
|
-
}: CopyButtonProps) {
|
|
25
|
-
const { isCopied, copy } = useCopyToClipboard({
|
|
26
|
-
onSuccess: () => {
|
|
27
|
-
toast.custom((t) => (
|
|
28
|
-
<Toast variant="success" message={successMessage} toastId={t} />
|
|
29
|
-
));
|
|
30
|
-
},
|
|
31
|
-
onError: () => {
|
|
32
|
-
toast.custom((t) => (
|
|
33
|
-
<Toast variant="error" message="Não foi possível copiar o link" toastId={t} />
|
|
34
|
-
));
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<Tooltip>
|
|
40
|
-
<TooltipTrigger
|
|
41
|
-
asChild
|
|
42
|
-
onClick={(e: React.MouseEvent) => {
|
|
43
|
-
e.stopPropagation();
|
|
44
|
-
copy(textToCopy);
|
|
45
|
-
}}
|
|
46
|
-
>
|
|
47
|
-
<span className={cn("cursor-pointer text-gray-500", className)}>
|
|
48
|
-
{isCopied ? <Check size={size} /> : <Copy size={size} />}
|
|
49
|
-
</span>
|
|
50
|
-
</TooltipTrigger>
|
|
51
|
-
<TooltipContent>{isCopied ? "Copiado!" : tooltipText}</TooltipContent>
|
|
52
|
-
</Tooltip>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Check, Copy } from "lucide-react";
|
|
4
|
+
import { toast } from "sonner";
|
|
5
|
+
import { Toast } from "../feedback/Toast";
|
|
6
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../overlay/Tooltip";
|
|
7
|
+
import useCopyToClipboard from "../../../hooks/copy-to-clipboard.hook";
|
|
8
|
+
import { cn } from "../../../infra/utils/clsx";
|
|
9
|
+
|
|
10
|
+
interface CopyButtonProps {
|
|
11
|
+
textToCopy: string;
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
tooltipText?: string;
|
|
15
|
+
successMessage?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function CopyButton({
|
|
19
|
+
textToCopy,
|
|
20
|
+
size = 14,
|
|
21
|
+
className,
|
|
22
|
+
tooltipText = "Copiar link",
|
|
23
|
+
successMessage = "Link copiado",
|
|
24
|
+
}: CopyButtonProps) {
|
|
25
|
+
const { isCopied, copy } = useCopyToClipboard({
|
|
26
|
+
onSuccess: () => {
|
|
27
|
+
toast.custom((t) => (
|
|
28
|
+
<Toast variant="success" message={successMessage} toastId={t} />
|
|
29
|
+
));
|
|
30
|
+
},
|
|
31
|
+
onError: () => {
|
|
32
|
+
toast.custom((t) => (
|
|
33
|
+
<Toast variant="error" message="Não foi possível copiar o link" toastId={t} />
|
|
34
|
+
));
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Tooltip>
|
|
40
|
+
<TooltipTrigger
|
|
41
|
+
asChild
|
|
42
|
+
onClick={(e: React.MouseEvent) => {
|
|
43
|
+
e.stopPropagation();
|
|
44
|
+
copy(textToCopy);
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<span className={cn("cursor-pointer text-gray-500", className)}>
|
|
48
|
+
{isCopied ? <Check size={size} /> : <Copy size={size} />}
|
|
49
|
+
</span>
|
|
50
|
+
</TooltipTrigger>
|
|
51
|
+
<TooltipContent>{isCopied ? "Copiado!" : tooltipText}</TooltipContent>
|
|
52
|
+
</Tooltip>
|
|
53
|
+
);
|
|
54
|
+
}
|