@greatapps/common 1.1.154 → 1.1.156
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/layouts/UsersSelectorPopover.mjs +3 -6
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/AppNavigation.mjs +3 -1
- package/dist/components/navigation/AppNavigation.mjs.map +1 -1
- package/dist/components/navigation/CancelledSubscriptionBanner.mjs +59 -0
- package/dist/components/navigation/CancelledSubscriptionBanner.mjs.map +1 -0
- package/dist/components/navigation/NavItemsContext.mjs.map +1 -1
- package/dist/components/navigation/shells/DesktopShell.mjs +2 -14
- package/dist/components/navigation/shells/DesktopShell.mjs.map +1 -1
- package/dist/components/navigation/shells/MdShell.mjs +2 -14
- package/dist/components/navigation/shells/MdShell.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.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 -89
- 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 +112 -112
- package/src/components/layouts/UsersSelectorPopover.tsx +6 -10
- package/src/components/navigation/AppNavigation.tsx +4 -1
- package/src/components/navigation/CancelledSubscriptionBanner.tsx +69 -0
- package/src/components/navigation/NavItemsContext.ts +20 -20
- package/src/components/navigation/shells/DesktopShell.tsx +0 -7
- package/src/components/navigation/shells/MdShell.tsx +0 -6
- 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 +347 -347
- 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/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,97 +1,97 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
-
import { format } from "date-fns";
|
|
5
|
-
import { Calendar } from "./Calendar";
|
|
6
|
-
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
7
|
-
import { cn } from "../../../infra/utils/clsx";
|
|
8
|
-
|
|
9
|
-
// Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
|
|
10
|
-
// Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
|
|
11
|
-
const isoParaDataLocal = (iso: string): Date => {
|
|
12
|
-
const [ano, mes, dia] = iso.split("-").map(Number);
|
|
13
|
-
return new Date(ano, mes - 1, dia);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
interface DatePickerProps {
|
|
17
|
-
value?: string;
|
|
18
|
-
onChange?: (date: string | undefined) => void;
|
|
19
|
-
placeholder?: string;
|
|
20
|
-
className?: string;
|
|
21
|
-
disabled?: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
|
|
25
|
-
(
|
|
26
|
-
{ value, onChange, placeholder = "Selecione a data", className, disabled },
|
|
27
|
-
ref,
|
|
28
|
-
) => {
|
|
29
|
-
const [open, setOpen] = useState(false);
|
|
30
|
-
const [date, setDate] = useState<Date | undefined>(() => {
|
|
31
|
-
return value ? isoParaDataLocal(value) : undefined;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Sincroniza estado interno quando value mudar externamente
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (value) {
|
|
37
|
-
setDate(isoParaDataLocal(value));
|
|
38
|
-
} else {
|
|
39
|
-
setDate(undefined);
|
|
40
|
-
}
|
|
41
|
-
}, [value]);
|
|
42
|
-
|
|
43
|
-
const handleDateSelect = (selectedDate: Date | undefined) => {
|
|
44
|
-
setDate(selectedDate);
|
|
45
|
-
|
|
46
|
-
if (selectedDate) {
|
|
47
|
-
onChange?.(format(selectedDate, "yyyy-MM-dd"));
|
|
48
|
-
setOpen(false); // Fecha o popover após seleção
|
|
49
|
-
} else {
|
|
50
|
-
onChange?.(undefined);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const displayText = date ? format(date, "dd/MM/yyyy") : placeholder;
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<Popover open={open} onOpenChange={setOpen}>
|
|
58
|
-
<PopoverTrigger asChild>
|
|
59
|
-
<button
|
|
60
|
-
ref={ref}
|
|
61
|
-
disabled={disabled}
|
|
62
|
-
className={cn(
|
|
63
|
-
"flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
|
|
64
|
-
"border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
|
|
65
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
66
|
-
className,
|
|
67
|
-
)}
|
|
68
|
-
>
|
|
69
|
-
<span
|
|
70
|
-
className={cn(
|
|
71
|
-
"paragraph-small-medium",
|
|
72
|
-
date ? "text-gray-950" : "text-gray-500",
|
|
73
|
-
)}
|
|
74
|
-
>
|
|
75
|
-
{displayText}
|
|
76
|
-
</span>
|
|
77
|
-
</button>
|
|
78
|
-
</PopoverTrigger>
|
|
79
|
-
<PopoverContent
|
|
80
|
-
className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
|
|
81
|
-
align="start"
|
|
82
|
-
sideOffset={8}
|
|
83
|
-
>
|
|
84
|
-
<div className="p-3">
|
|
85
|
-
<Calendar
|
|
86
|
-
mode="single"
|
|
87
|
-
selected={date}
|
|
88
|
-
onSelect={handleDateSelect}
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
</PopoverContent>
|
|
92
|
-
</Popover>
|
|
93
|
-
);
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
DatePicker.displayName = "DatePicker";
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
+
import { format } from "date-fns";
|
|
5
|
+
import { Calendar } from "./Calendar";
|
|
6
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
7
|
+
import { cn } from "../../../infra/utils/clsx";
|
|
8
|
+
|
|
9
|
+
// Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
|
|
10
|
+
// Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
|
|
11
|
+
const isoParaDataLocal = (iso: string): Date => {
|
|
12
|
+
const [ano, mes, dia] = iso.split("-").map(Number);
|
|
13
|
+
return new Date(ano, mes - 1, dia);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
interface DatePickerProps {
|
|
17
|
+
value?: string;
|
|
18
|
+
onChange?: (date: string | undefined) => void;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
|
|
25
|
+
(
|
|
26
|
+
{ value, onChange, placeholder = "Selecione a data", className, disabled },
|
|
27
|
+
ref,
|
|
28
|
+
) => {
|
|
29
|
+
const [open, setOpen] = useState(false);
|
|
30
|
+
const [date, setDate] = useState<Date | undefined>(() => {
|
|
31
|
+
return value ? isoParaDataLocal(value) : undefined;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Sincroniza estado interno quando value mudar externamente
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (value) {
|
|
37
|
+
setDate(isoParaDataLocal(value));
|
|
38
|
+
} else {
|
|
39
|
+
setDate(undefined);
|
|
40
|
+
}
|
|
41
|
+
}, [value]);
|
|
42
|
+
|
|
43
|
+
const handleDateSelect = (selectedDate: Date | undefined) => {
|
|
44
|
+
setDate(selectedDate);
|
|
45
|
+
|
|
46
|
+
if (selectedDate) {
|
|
47
|
+
onChange?.(format(selectedDate, "yyyy-MM-dd"));
|
|
48
|
+
setOpen(false); // Fecha o popover após seleção
|
|
49
|
+
} else {
|
|
50
|
+
onChange?.(undefined);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const displayText = date ? format(date, "dd/MM/yyyy") : placeholder;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
58
|
+
<PopoverTrigger asChild>
|
|
59
|
+
<button
|
|
60
|
+
ref={ref}
|
|
61
|
+
disabled={disabled}
|
|
62
|
+
className={cn(
|
|
63
|
+
"flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
|
|
64
|
+
"border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
|
|
65
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
66
|
+
className,
|
|
67
|
+
)}
|
|
68
|
+
>
|
|
69
|
+
<span
|
|
70
|
+
className={cn(
|
|
71
|
+
"paragraph-small-medium",
|
|
72
|
+
date ? "text-gray-950" : "text-gray-500",
|
|
73
|
+
)}
|
|
74
|
+
>
|
|
75
|
+
{displayText}
|
|
76
|
+
</span>
|
|
77
|
+
</button>
|
|
78
|
+
</PopoverTrigger>
|
|
79
|
+
<PopoverContent
|
|
80
|
+
className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
|
|
81
|
+
align="start"
|
|
82
|
+
sideOffset={8}
|
|
83
|
+
>
|
|
84
|
+
<div className="p-3">
|
|
85
|
+
<Calendar
|
|
86
|
+
mode="single"
|
|
87
|
+
selected={date}
|
|
88
|
+
onSelect={handleDateSelect}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
</PopoverContent>
|
|
92
|
+
</Popover>
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
DatePicker.displayName = "DatePicker";
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
-
import { format } from "date-fns";
|
|
5
|
-
import { Calendar as CalendarIcon } from "lucide-react";
|
|
6
|
-
import { DateRange } from "react-day-picker";
|
|
7
|
-
import { Calendar } from "./Calendar";
|
|
8
|
-
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
9
|
-
import { cn } from "../../../infra/utils/clsx";
|
|
10
|
-
|
|
11
|
-
// Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
|
|
12
|
-
// Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
|
|
13
|
-
const isoParaDataLocal = (iso: string): Date => {
|
|
14
|
-
const [ano, mes, dia] = iso.split("-").map(Number);
|
|
15
|
-
return new Date(ano, mes - 1, dia);
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
interface DateRangePickerProps {
|
|
19
|
-
value?: { from: string; to: string };
|
|
20
|
-
onChange?: (range: { from: string; to: string } | undefined) => void;
|
|
21
|
-
placeholder?: string;
|
|
22
|
-
className?: string;
|
|
23
|
-
disabled?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const DateRangePicker = forwardRef<HTMLButtonElement, DateRangePickerProps>(
|
|
27
|
-
({ value, onChange, placeholder = "Selecione o período", className, disabled }, ref) => {
|
|
28
|
-
const [open, setOpen] = useState(false);
|
|
29
|
-
const [range, setRange] = useState<DateRange | undefined>(() => {
|
|
30
|
-
if (value?.from && value?.to) {
|
|
31
|
-
return {
|
|
32
|
-
from: isoParaDataLocal(value.from),
|
|
33
|
-
to: isoParaDataLocal(value.to)
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return undefined;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
if (value?.from && value?.to) {
|
|
41
|
-
setRange({
|
|
42
|
-
from: isoParaDataLocal(value.from),
|
|
43
|
-
to: isoParaDataLocal(value.to)
|
|
44
|
-
});
|
|
45
|
-
} else {
|
|
46
|
-
setRange(undefined);
|
|
47
|
-
}
|
|
48
|
-
}, [value]);
|
|
49
|
-
|
|
50
|
-
const handleRangeSelect = (newRange: DateRange | undefined) => {
|
|
51
|
-
setRange(newRange);
|
|
52
|
-
|
|
53
|
-
if (newRange?.from && newRange?.to) {
|
|
54
|
-
onChange?.({
|
|
55
|
-
from: format(newRange.from, "yyyy-MM-dd"),
|
|
56
|
-
to: format(newRange.to, "yyyy-MM-dd")
|
|
57
|
-
});
|
|
58
|
-
} else {
|
|
59
|
-
onChange?.(undefined);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const displayText = range?.from && range?.to
|
|
64
|
-
? `${format(range.from, "dd/MM/yyyy")} - ${format(range.to, "dd/MM/yyyy")}`
|
|
65
|
-
: placeholder;
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<Popover open={open} onOpenChange={setOpen}>
|
|
69
|
-
<PopoverTrigger asChild>
|
|
70
|
-
<button
|
|
71
|
-
ref={ref}
|
|
72
|
-
disabled={disabled}
|
|
73
|
-
className={cn(
|
|
74
|
-
"flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
|
|
75
|
-
"border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
|
|
76
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
77
|
-
className
|
|
78
|
-
)}
|
|
79
|
-
>
|
|
80
|
-
<CalendarIcon size={20} className="text-gray-400" />
|
|
81
|
-
<span className={cn(
|
|
82
|
-
"paragraph-small-medium",
|
|
83
|
-
range?.from && range?.to ? "text-gray-950" : "text-gray-500"
|
|
84
|
-
)}>
|
|
85
|
-
{displayText}
|
|
86
|
-
</span>
|
|
87
|
-
</button>
|
|
88
|
-
</PopoverTrigger>
|
|
89
|
-
<PopoverContent
|
|
90
|
-
className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
|
|
91
|
-
align="start"
|
|
92
|
-
sideOffset={8}
|
|
93
|
-
>
|
|
94
|
-
<div className="p-3">
|
|
95
|
-
<Calendar
|
|
96
|
-
mode="range"
|
|
97
|
-
selected={range}
|
|
98
|
-
onSelect={handleRangeSelect}
|
|
99
|
-
numberOfMonths={1}
|
|
100
|
-
/>
|
|
101
|
-
</div>
|
|
102
|
-
</PopoverContent>
|
|
103
|
-
</Popover>
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
DateRangePicker.displayName = "DateRangePicker";
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
+
import { format } from "date-fns";
|
|
5
|
+
import { Calendar as CalendarIcon } from "lucide-react";
|
|
6
|
+
import { DateRange } from "react-day-picker";
|
|
7
|
+
import { Calendar } from "./Calendar";
|
|
8
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
9
|
+
import { cn } from "../../../infra/utils/clsx";
|
|
10
|
+
|
|
11
|
+
// Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
|
|
12
|
+
// Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
|
|
13
|
+
const isoParaDataLocal = (iso: string): Date => {
|
|
14
|
+
const [ano, mes, dia] = iso.split("-").map(Number);
|
|
15
|
+
return new Date(ano, mes - 1, dia);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
interface DateRangePickerProps {
|
|
19
|
+
value?: { from: string; to: string };
|
|
20
|
+
onChange?: (range: { from: string; to: string } | undefined) => void;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const DateRangePicker = forwardRef<HTMLButtonElement, DateRangePickerProps>(
|
|
27
|
+
({ value, onChange, placeholder = "Selecione o período", className, disabled }, ref) => {
|
|
28
|
+
const [open, setOpen] = useState(false);
|
|
29
|
+
const [range, setRange] = useState<DateRange | undefined>(() => {
|
|
30
|
+
if (value?.from && value?.to) {
|
|
31
|
+
return {
|
|
32
|
+
from: isoParaDataLocal(value.from),
|
|
33
|
+
to: isoParaDataLocal(value.to)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (value?.from && value?.to) {
|
|
41
|
+
setRange({
|
|
42
|
+
from: isoParaDataLocal(value.from),
|
|
43
|
+
to: isoParaDataLocal(value.to)
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
setRange(undefined);
|
|
47
|
+
}
|
|
48
|
+
}, [value]);
|
|
49
|
+
|
|
50
|
+
const handleRangeSelect = (newRange: DateRange | undefined) => {
|
|
51
|
+
setRange(newRange);
|
|
52
|
+
|
|
53
|
+
if (newRange?.from && newRange?.to) {
|
|
54
|
+
onChange?.({
|
|
55
|
+
from: format(newRange.from, "yyyy-MM-dd"),
|
|
56
|
+
to: format(newRange.to, "yyyy-MM-dd")
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
onChange?.(undefined);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const displayText = range?.from && range?.to
|
|
64
|
+
? `${format(range.from, "dd/MM/yyyy")} - ${format(range.to, "dd/MM/yyyy")}`
|
|
65
|
+
: placeholder;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
69
|
+
<PopoverTrigger asChild>
|
|
70
|
+
<button
|
|
71
|
+
ref={ref}
|
|
72
|
+
disabled={disabled}
|
|
73
|
+
className={cn(
|
|
74
|
+
"flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
|
|
75
|
+
"border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
|
|
76
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
77
|
+
className
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
<CalendarIcon size={20} className="text-gray-400" />
|
|
81
|
+
<span className={cn(
|
|
82
|
+
"paragraph-small-medium",
|
|
83
|
+
range?.from && range?.to ? "text-gray-950" : "text-gray-500"
|
|
84
|
+
)}>
|
|
85
|
+
{displayText}
|
|
86
|
+
</span>
|
|
87
|
+
</button>
|
|
88
|
+
</PopoverTrigger>
|
|
89
|
+
<PopoverContent
|
|
90
|
+
className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
|
|
91
|
+
align="start"
|
|
92
|
+
sideOffset={8}
|
|
93
|
+
>
|
|
94
|
+
<div className="p-3">
|
|
95
|
+
<Calendar
|
|
96
|
+
mode="range"
|
|
97
|
+
selected={range}
|
|
98
|
+
onSelect={handleRangeSelect}
|
|
99
|
+
numberOfMonths={1}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
</PopoverContent>
|
|
103
|
+
</Popover>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { cn } from "../../../infra/utils/clsx"
|
|
5
|
-
|
|
6
|
-
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
7
|
-
return (
|
|
8
|
-
<input
|
|
9
|
-
type={type}
|
|
10
|
-
data-slot="input"
|
|
11
|
-
className={cn(
|
|
12
|
-
"outline-none",
|
|
13
|
-
className
|
|
14
|
-
)}
|
|
15
|
-
{...props}
|
|
16
|
-
/>
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export { Input }
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../../infra/utils/clsx"
|
|
5
|
+
|
|
6
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
7
|
+
return (
|
|
8
|
+
<input
|
|
9
|
+
type={type}
|
|
10
|
+
data-slot="input"
|
|
11
|
+
className={cn(
|
|
12
|
+
"outline-none",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Input }
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
"use client"
|
|
4
|
-
|
|
5
|
-
import * as React from "react"
|
|
6
|
-
import { OTPInput, OTPInputContext } from "input-otp"
|
|
7
|
-
import { MinusIcon } from "lucide-react"
|
|
8
|
-
import { cn } from "../../../infra/utils/clsx"
|
|
9
|
-
|
|
10
|
-
function InputOTP({
|
|
11
|
-
className,
|
|
12
|
-
containerClassName,
|
|
13
|
-
...props
|
|
14
|
-
}: React.ComponentProps<typeof OTPInput> & {
|
|
15
|
-
containerClassName?: string
|
|
16
|
-
}) {
|
|
17
|
-
return (
|
|
18
|
-
<OTPInput
|
|
19
|
-
data-slot="input-otp"
|
|
20
|
-
containerClassName={cn(
|
|
21
|
-
"flex items-center gap-2 has-disabled:opacity-50",
|
|
22
|
-
containerClassName
|
|
23
|
-
)}
|
|
24
|
-
className={cn("disabled:cursor-not-allowed", className)}
|
|
25
|
-
{...props}
|
|
26
|
-
/>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
31
|
-
return (
|
|
32
|
-
<div
|
|
33
|
-
data-slot="input-otp-group"
|
|
34
|
-
className={cn("flex items-center", className)}
|
|
35
|
-
{...props}
|
|
36
|
-
/>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function InputOTPSlot({
|
|
41
|
-
index,
|
|
42
|
-
className,
|
|
43
|
-
...props
|
|
44
|
-
}: React.ComponentProps<"div"> & {
|
|
45
|
-
index: number
|
|
46
|
-
}) {
|
|
47
|
-
const inputOTPContext = React.useContext(OTPInputContext)
|
|
48
|
-
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
data-slot="input-otp-slot"
|
|
53
|
-
data-active={isActive}
|
|
54
|
-
className={cn(
|
|
55
|
-
"relative flex h-9 w-9 items-center justify-center border text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md",
|
|
56
|
-
"border-gray-200 hover:border-gray-400 data-[active=true]:border-gray-950",
|
|
57
|
-
"data-[active=true]:z-10",
|
|
58
|
-
className
|
|
59
|
-
)}
|
|
60
|
-
{...props}
|
|
61
|
-
>
|
|
62
|
-
{char}
|
|
63
|
-
{hasFakeCaret && (
|
|
64
|
-
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
65
|
-
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
|
66
|
-
</div>
|
|
67
|
-
)}
|
|
68
|
-
</div>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
|
|
73
|
-
return (
|
|
74
|
-
<div data-slot="input-otp-separator" role="separator" {...props}>
|
|
75
|
-
<MinusIcon />
|
|
76
|
-
</div>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
5
|
+
import * as React from "react"
|
|
6
|
+
import { OTPInput, OTPInputContext } from "input-otp"
|
|
7
|
+
import { MinusIcon } from "lucide-react"
|
|
8
|
+
import { cn } from "../../../infra/utils/clsx"
|
|
9
|
+
|
|
10
|
+
function InputOTP({
|
|
11
|
+
className,
|
|
12
|
+
containerClassName,
|
|
13
|
+
...props
|
|
14
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
15
|
+
containerClassName?: string
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<OTPInput
|
|
19
|
+
data-slot="input-otp"
|
|
20
|
+
containerClassName={cn(
|
|
21
|
+
"flex items-center gap-2 has-disabled:opacity-50",
|
|
22
|
+
containerClassName
|
|
23
|
+
)}
|
|
24
|
+
className={cn("disabled:cursor-not-allowed", className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
data-slot="input-otp-group"
|
|
34
|
+
className={cn("flex items-center", className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function InputOTPSlot({
|
|
41
|
+
index,
|
|
42
|
+
className,
|
|
43
|
+
...props
|
|
44
|
+
}: React.ComponentProps<"div"> & {
|
|
45
|
+
index: number
|
|
46
|
+
}) {
|
|
47
|
+
const inputOTPContext = React.useContext(OTPInputContext)
|
|
48
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-slot="input-otp-slot"
|
|
53
|
+
data-active={isActive}
|
|
54
|
+
className={cn(
|
|
55
|
+
"relative flex h-9 w-9 items-center justify-center border text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md",
|
|
56
|
+
"border-gray-200 hover:border-gray-400 data-[active=true]:border-gray-950",
|
|
57
|
+
"data-[active=true]:z-10",
|
|
58
|
+
className
|
|
59
|
+
)}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
{char}
|
|
63
|
+
{hasFakeCaret && (
|
|
64
|
+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
65
|
+
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
|
|
73
|
+
return (
|
|
74
|
+
<div data-slot="input-otp-separator" role="separator" {...props}>
|
|
75
|
+
<MinusIcon />
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
|