@greatapps/common 1.1.671 → 1.1.673
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/layouts/NavBar.mjs +5 -3
- package/dist/components/layouts/NavBar.mjs.map +1 -1
- package/dist/components/layouts/NotificationsPopover.mjs +5 -3
- package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
- package/dist/components/layouts/ProfilePopover.mjs +6 -4
- package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
- package/dist/components/layouts/UsersSelectorPopover.mjs +9 -7
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/components/modals/BuyCreditsModal.mjs +17 -18
- package/dist/components/modals/BuyCreditsModal.mjs.map +1 -1
- package/dist/components/modals/CreditsDisabledModal.mjs +6 -4
- package/dist/components/modals/CreditsDisabledModal.mjs.map +1 -1
- package/dist/components/modals/PaidPlanRequiredModal.mjs +5 -3
- package/dist/components/modals/PaidPlanRequiredModal.mjs.map +1 -1
- package/dist/components/modals/cards/AddCardModal.mjs +27 -24
- package/dist/components/modals/cards/AddCardModal.mjs.map +1 -1
- package/dist/components/modals/cards/CannotDeleteCardModal.mjs +9 -7
- package/dist/components/modals/cards/CannotDeleteCardModal.mjs.map +1 -1
- package/dist/components/modals/cards/CardFormFields.mjs +25 -22
- package/dist/components/modals/cards/CardFormFields.mjs.map +1 -1
- package/dist/components/modals/cards/DeleteCardModal.mjs +10 -8
- package/dist/components/modals/cards/DeleteCardModal.mjs.map +1 -1
- package/dist/components/navigation/CancelledSubscriptionBanner.mjs +4 -2
- package/dist/components/navigation/CancelledSubscriptionBanner.mjs.map +1 -1
- package/dist/components/navigation/OverdueInvoiceBanner.mjs +4 -2
- package/dist/components/navigation/OverdueInvoiceBanner.mjs.map +1 -1
- package/dist/components/navigation/PendingCancellationBanner.mjs +4 -6
- package/dist/components/navigation/PendingCancellationBanner.mjs.map +1 -1
- package/dist/components/navigation/ProjectSelectorPopover.mjs +8 -6
- package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
- package/dist/components/navigation/UpcomingInvoiceBanner.mjs +4 -6
- package/dist/components/navigation/UpcomingInvoiceBanner.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/BottomLinks.mjs +5 -3
- package/dist/components/navigation/subcomponents/BottomLinks.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/CreditsCard.mjs +3 -1
- package/dist/components/navigation/subcomponents/CreditsCard.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/PlanCard.mjs +3 -1
- package/dist/components/navigation/subcomponents/PlanCard.mjs.map +1 -1
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs +5 -3
- package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
- package/dist/components/pages/NotFoundPage.mjs +5 -3
- package/dist/components/pages/NotFoundPage.mjs.map +1 -1
- package/dist/components/pages/notifications/Notifications.mjs +13 -10
- package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
- package/dist/components/ui/buttons/CopyButton.mjs +9 -5
- package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
- package/dist/components/ui/data-display/CardItem.mjs +7 -5
- package/dist/components/ui/data-display/CardItem.mjs.map +1 -1
- package/dist/components/ui/data-display/PaymentInfoCard.mjs +10 -8
- package/dist/components/ui/data-display/PaymentInfoCard.mjs.map +1 -1
- package/dist/components/ui/feedback/DefaultCircularProgress.mjs +3 -1
- package/dist/components/ui/feedback/DefaultCircularProgress.mjs.map +1 -1
- package/dist/components/ui/form/ComboboxField.mjs +11 -6
- package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
- package/dist/components/ui/form/DatePicker.mjs +5 -2
- package/dist/components/ui/form/DatePicker.mjs.map +1 -1
- package/dist/components/ui/form/DateRangePicker.mjs +5 -2
- package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
- package/dist/components/ui/form/PhoneInput.mjs +5 -3
- package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
- package/dist/components/ui/form/SelectField.mjs +6 -3
- package/dist/components/ui/form/SelectField.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageCropModal.mjs +11 -18
- package/dist/components/widgets/ImageUpload/ImageCropModal.mjs.map +1 -1
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs +6 -15
- package/dist/components/widgets/ImageUpload/ImageTooSmallModal.mjs.map +1 -1
- package/dist/i18n/messages/en-us.mjs +231 -0
- package/dist/i18n/messages/en-us.mjs.map +1 -1
- package/dist/i18n/messages/es-es.mjs +231 -0
- package/dist/i18n/messages/es-es.mjs.map +1 -1
- package/dist/i18n/messages/pt-br.mjs +239 -0
- package/dist/i18n/messages/pt-br.mjs.map +1 -1
- package/dist/modules/cards/hooks/handle-delete-card.hook.mjs +2 -1
- package/dist/modules/cards/hooks/handle-delete-card.hook.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/NavBar.tsx +5 -3
- package/src/components/layouts/NotificationsPopover.tsx +5 -3
- package/src/components/layouts/ProfilePopover.tsx +6 -4
- package/src/components/layouts/UsersSelectorPopover.tsx +9 -7
- package/src/components/modals/BuyCreditsModal.tsx +18 -16
- package/src/components/modals/CreditsDisabledModal.tsx +6 -6
- package/src/components/modals/PaidPlanRequiredModal.tsx +5 -3
- package/src/components/modals/cards/AddCardModal.tsx +29 -27
- package/src/components/modals/cards/CannotDeleteCardModal.tsx +9 -8
- package/src/components/modals/cards/CardFormFields.tsx +25 -22
- package/src/components/modals/cards/DeleteCardModal.tsx +10 -8
- package/src/components/navigation/CancelledSubscriptionBanner.tsx +4 -2
- package/src/components/navigation/OverdueInvoiceBanner.tsx +4 -2
- package/src/components/navigation/PendingCancellationBanner.tsx +4 -2
- package/src/components/navigation/ProjectSelectorPopover.tsx +8 -6
- package/src/components/navigation/UpcomingInvoiceBanner.tsx +4 -2
- package/src/components/navigation/subcomponents/BottomLinks.tsx +5 -3
- package/src/components/navigation/subcomponents/CreditsCard.tsx +3 -1
- package/src/components/navigation/subcomponents/PlanCard.tsx +3 -1
- package/src/components/navigation/subcomponents/ProjectSelector.tsx +5 -3
- package/src/components/pages/NotFoundPage.tsx +5 -3
- package/src/components/pages/notifications/Notifications.tsx +13 -10
- package/src/components/ui/buttons/CopyButton.tsx +10 -5
- package/src/components/ui/data-display/CardItem.tsx +7 -5
- package/src/components/ui/data-display/PaymentInfoCard.tsx +10 -8
- package/src/components/ui/feedback/DefaultCircularProgress.tsx +3 -1
- package/src/components/ui/form/ComboboxField.tsx +11 -6
- package/src/components/ui/form/DatePicker.tsx +5 -2
- package/src/components/ui/form/DateRangePicker.tsx +5 -2
- package/src/components/ui/form/PhoneInput.tsx +5 -3
- package/src/components/ui/form/SelectField.tsx +6 -3
- package/src/components/widgets/ImageUpload/ImageCropModal.tsx +19 -11
- package/src/components/widgets/ImageUpload/ImageTooSmallModal.tsx +6 -5
- package/src/i18n/messages/en-us.ts +234 -0
- package/src/i18n/messages/es-es.ts +234 -0
- package/src/i18n/messages/pt-br.ts +248 -0
- package/src/modules/cards/hooks/handle-delete-card.hook.ts +8 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { IconBell, IconCheck, IconLoader2 } from '@tabler/icons-react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import { Button } from "../../ui/buttons/Button";
|
|
5
6
|
import {
|
|
6
7
|
Tabs,
|
|
@@ -34,6 +35,7 @@ function NotificationsList({
|
|
|
34
35
|
hasNextPage: boolean;
|
|
35
36
|
fetchNextPage: () => void;
|
|
36
37
|
}) {
|
|
38
|
+
const translate = useTranslations();
|
|
37
39
|
const notifications = pages?.pages.flatMap((p) => p.data) ?? [];
|
|
38
40
|
|
|
39
41
|
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
@@ -50,7 +52,7 @@ function NotificationsList({
|
|
|
50
52
|
return (
|
|
51
53
|
<div className="rounded-lg border border-zinc-200 bg-white">
|
|
52
54
|
<div className="flex flex-col items-center justify-center py-16 gap-2">
|
|
53
|
-
<span className="paragraph-medium-regular text-zinc-500">
|
|
55
|
+
<span className="paragraph-medium-regular text-zinc-500">{translate('common.notifications.page.empty')}</span>
|
|
54
56
|
</div>
|
|
55
57
|
</div>
|
|
56
58
|
);
|
|
@@ -80,7 +82,7 @@ function NotificationsList({
|
|
|
80
82
|
actions={
|
|
81
83
|
detailsUrl ? (
|
|
82
84
|
<Button asChild variant="secondary" className="h-8! px-3! paragraph-small-semibold">
|
|
83
|
-
<Link href={detailsUrl}>
|
|
85
|
+
<Link href={detailsUrl}>{translate('common.notifications.page.details')}</Link>
|
|
84
86
|
</Button>
|
|
85
87
|
) : undefined
|
|
86
88
|
}
|
|
@@ -97,6 +99,7 @@ function NotificationsList({
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
export function NotificationPageContent() {
|
|
102
|
+
const translate = useTranslations();
|
|
100
103
|
const unreadNotifications = useInfiniteMessages({
|
|
101
104
|
readed: false,
|
|
102
105
|
type: "notification",
|
|
@@ -116,12 +119,12 @@ export function NotificationPageContent() {
|
|
|
116
119
|
markAllAsRead(undefined, {
|
|
117
120
|
onSuccess: () => {
|
|
118
121
|
toast.custom((t) => (
|
|
119
|
-
<Toast variant="success" message=
|
|
122
|
+
<Toast variant="success" message={translate('common.notifications.page.markAllSuccess')} toastId={t} />
|
|
120
123
|
));
|
|
121
124
|
},
|
|
122
125
|
onError: () => {
|
|
123
126
|
toast.custom((t) => (
|
|
124
|
-
<Toast variant="error" message=
|
|
127
|
+
<Toast variant="error" message={translate('common.notifications.page.markAllError')} toastId={t} />
|
|
125
128
|
));
|
|
126
129
|
},
|
|
127
130
|
});
|
|
@@ -132,10 +135,10 @@ export function NotificationPageContent() {
|
|
|
132
135
|
<div className="flex items-center justify-between gap-4">
|
|
133
136
|
<div className="flex flex-col gap-2">
|
|
134
137
|
<h1 className="title-large-semibold text-gray-950">
|
|
135
|
-
|
|
138
|
+
{translate('common.notifications.page.title')}
|
|
136
139
|
</h1>
|
|
137
140
|
<p className="paragraph-small-regular text-gray-600 hidden lg:block">
|
|
138
|
-
|
|
141
|
+
{translate('common.notifications.page.subtitle')}
|
|
139
142
|
</p>
|
|
140
143
|
</div>
|
|
141
144
|
<Button
|
|
@@ -145,8 +148,8 @@ export function NotificationPageContent() {
|
|
|
145
148
|
disabled={isMarkingAll || totalUnread === 0}
|
|
146
149
|
>
|
|
147
150
|
{isMarkingAll ? <IconLoader2 size={20} className="animate-spin" /> : <IconCheck size={20} />}
|
|
148
|
-
<span className="lg:block hidden">
|
|
149
|
-
<span className="lg:hidden">
|
|
151
|
+
<span className="lg:block hidden">{translate('common.notifications.page.markAllReadDesktop')}</span>
|
|
152
|
+
<span className="lg:hidden">{translate('common.notifications.page.markAllReadMobile')}</span>
|
|
150
153
|
</Button>
|
|
151
154
|
</div>
|
|
152
155
|
<Tabs
|
|
@@ -155,11 +158,11 @@ export function NotificationPageContent() {
|
|
|
155
158
|
>
|
|
156
159
|
<TabsList className="h-auto pb-0 bg-transparent">
|
|
157
160
|
<TabsTrigger className="gap-2" value="all">
|
|
158
|
-
|
|
161
|
+
{translate('common.notifications.page.tabAll')}{" "}
|
|
159
162
|
<span className="text-gray-500">({totalAll})</span>
|
|
160
163
|
</TabsTrigger>
|
|
161
164
|
<TabsTrigger className="gap-2" value="unreads" disabled={totalUnread === 0}>
|
|
162
|
-
|
|
165
|
+
{translate('common.notifications.page.tabUnread')}{" "}
|
|
163
166
|
<span className="text-gray-500">({totalUnread})</span>
|
|
164
167
|
</TabsTrigger>
|
|
165
168
|
</TabsList>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from 'next-intl';
|
|
3
4
|
import { IconCheck, IconCopy } from '@tabler/icons-react';
|
|
4
5
|
import { toast } from "sonner";
|
|
5
6
|
import { Toast } from "../feedback/Toast";
|
|
@@ -19,18 +20,22 @@ export function CopyButton({
|
|
|
19
20
|
textToCopy,
|
|
20
21
|
size = 14,
|
|
21
22
|
className,
|
|
22
|
-
tooltipText
|
|
23
|
-
successMessage
|
|
23
|
+
tooltipText,
|
|
24
|
+
successMessage,
|
|
24
25
|
}: CopyButtonProps) {
|
|
26
|
+
const translate = useTranslations();
|
|
27
|
+
const resolvedTooltipText = tooltipText ?? translate('common.forms.copyButton.tooltipDefault');
|
|
28
|
+
const resolvedSuccessMessage = successMessage ?? translate('common.forms.copyButton.successDefault');
|
|
29
|
+
|
|
25
30
|
const { isCopied, copy } = useCopyToClipboard({
|
|
26
31
|
onSuccess: () => {
|
|
27
32
|
toast.custom((t) => (
|
|
28
|
-
<Toast variant="success" message={
|
|
33
|
+
<Toast variant="success" message={resolvedSuccessMessage} toastId={t} />
|
|
29
34
|
));
|
|
30
35
|
},
|
|
31
36
|
onError: () => {
|
|
32
37
|
toast.custom((t) => (
|
|
33
|
-
<Toast variant="error" message=
|
|
38
|
+
<Toast variant="error" message={translate('common.forms.copyButton.errorMessage')} toastId={t} />
|
|
34
39
|
));
|
|
35
40
|
},
|
|
36
41
|
});
|
|
@@ -48,7 +53,7 @@ export function CopyButton({
|
|
|
48
53
|
{isCopied ? <IconCheck size={size} /> : <IconCopy size={size} />}
|
|
49
54
|
</span>
|
|
50
55
|
</TooltipTrigger>
|
|
51
|
-
<TooltipContent>{isCopied ?
|
|
56
|
+
<TooltipContent>{isCopied ? translate('common.actions.copied') : resolvedTooltipText}</TooltipContent>
|
|
52
57
|
</Tooltip>
|
|
53
58
|
);
|
|
54
59
|
}
|
|
@@ -10,6 +10,7 @@ import { CardBrandIcon } from './CardBrandIcons';
|
|
|
10
10
|
import { useSetDefaultCard } from '../../../modules/cards/hooks/set-default-card.hook';
|
|
11
11
|
import { useHandleDeleteCard } from '../../../modules/cards/hooks/handle-delete-card.hook';
|
|
12
12
|
import type { Card } from '../../../modules/cards/types';
|
|
13
|
+
import { useTranslations } from 'next-intl';
|
|
13
14
|
|
|
14
15
|
type CardItemProps = {
|
|
15
16
|
card: Card;
|
|
@@ -32,6 +33,7 @@ export function CardItem({
|
|
|
32
33
|
onAfterDelete,
|
|
33
34
|
onAfterSetDefault,
|
|
34
35
|
}: CardItemProps) {
|
|
36
|
+
const translate = useTranslations();
|
|
35
37
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
36
38
|
|
|
37
39
|
const setDefaultCardMutation = useSetDefaultCard();
|
|
@@ -44,7 +46,7 @@ export function CardItem({
|
|
|
44
46
|
toast.custom((t) => (
|
|
45
47
|
<Toast
|
|
46
48
|
variant="success"
|
|
47
|
-
message=
|
|
49
|
+
message={translate('common.cards.item.setDefaultSuccess')}
|
|
48
50
|
toastId={t}
|
|
49
51
|
/>
|
|
50
52
|
));
|
|
@@ -54,7 +56,7 @@ export function CardItem({
|
|
|
54
56
|
toast.custom((t) => (
|
|
55
57
|
<Toast
|
|
56
58
|
variant="error"
|
|
57
|
-
message=
|
|
59
|
+
message={translate('common.cards.item.setDefaultError')}
|
|
58
60
|
toastId={t}
|
|
59
61
|
/>
|
|
60
62
|
));
|
|
@@ -86,7 +88,7 @@ export function CardItem({
|
|
|
86
88
|
</div>
|
|
87
89
|
{card.is_default && (
|
|
88
90
|
<span className="paragraph-xsmall-semibold text-zinc-600 bg-zinc-100 px-2 py-0.5 rounded-lg whitespace-nowrap">
|
|
89
|
-
|
|
91
|
+
{translate('common.cards.item.defaultBadge')}
|
|
90
92
|
</span>
|
|
91
93
|
)}
|
|
92
94
|
<CardBrandIcon brand={card.brand} />
|
|
@@ -108,7 +110,7 @@ export function CardItem({
|
|
|
108
110
|
{menuHasSetDefault && (
|
|
109
111
|
<NavBarItem
|
|
110
112
|
icon={<IconStar size={18} className="text-zinc-400" />}
|
|
111
|
-
label=
|
|
113
|
+
label={translate('common.cards.item.makeDefault')}
|
|
112
114
|
onClick={() => {
|
|
113
115
|
setPopoverOpen(false);
|
|
114
116
|
handleSetDefault();
|
|
@@ -118,7 +120,7 @@ export function CardItem({
|
|
|
118
120
|
{menuHasDelete && (
|
|
119
121
|
<NavBarItem
|
|
120
122
|
icon={<IconTrash size={18} className="text-zinc-400" />}
|
|
121
|
-
label=
|
|
123
|
+
label={translate('common.actions.delete')}
|
|
122
124
|
onClick={() => {
|
|
123
125
|
setPopoverOpen(false);
|
|
124
126
|
handleDeleteCard(card);
|
|
@@ -9,6 +9,7 @@ import { useCards } from '../../../modules/cards/hooks/cards.hook';
|
|
|
9
9
|
import { useModalManager } from '../../../store/useModalManager';
|
|
10
10
|
import { useIsDefaultWhitelabel } from '../../../providers/whitelabel.provider';
|
|
11
11
|
import type { Card } from '../../../modules/cards/types';
|
|
12
|
+
import { useTranslations } from 'next-intl';
|
|
12
13
|
|
|
13
14
|
type PaymentInfoCardProps = {
|
|
14
15
|
email?: string;
|
|
@@ -29,6 +30,7 @@ export function PaymentInfoCard({
|
|
|
29
30
|
hideDelete,
|
|
30
31
|
hideSetDefault,
|
|
31
32
|
}: PaymentInfoCardProps) {
|
|
33
|
+
const translate = useTranslations();
|
|
32
34
|
const isMobile = useIsMobile();
|
|
33
35
|
const { openModal } = useModalManager();
|
|
34
36
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
@@ -83,19 +85,19 @@ export function PaymentInfoCard({
|
|
|
83
85
|
<div className="border border-zinc-200 rounded-lg overflow-hidden">
|
|
84
86
|
{email && (
|
|
85
87
|
<div className="flex items-center h-[60px] px-4 border-b border-zinc-200 gap-3">
|
|
86
|
-
<span className="paragraph-small-medium text-zinc-500 w-[100px]">
|
|
88
|
+
<span className="paragraph-small-medium text-zinc-500 w-[100px]">{translate('common.cards.paymentInfo.email')}</span>
|
|
87
89
|
<span className="paragraph-small-medium text-zinc-950 flex-1">{email}</span>
|
|
88
90
|
</div>
|
|
89
91
|
)}
|
|
90
92
|
<div className="flex items-center h-[60px] px-4 gap-3">
|
|
91
|
-
<span className="paragraph-small-medium text-zinc-500 w-[100px]">
|
|
93
|
+
<span className="paragraph-small-medium text-zinc-500 w-[100px]">{translate('common.cards.paymentInfo.payment')}</span>
|
|
92
94
|
<button
|
|
93
95
|
type="button"
|
|
94
96
|
onClick={handleOpenAddCardModal}
|
|
95
97
|
className="flex items-center h-8 px-2 paragraph-small-semibold text-zinc-950 border border-zinc-200 rounded-md hover:border-zinc-400 transition-colors cursor-pointer w-fit"
|
|
96
98
|
>
|
|
97
99
|
<IconPlus className="size-[18px]" />
|
|
98
|
-
<span className="px-1.5">
|
|
100
|
+
<span className="px-1.5">{translate('common.cards.paymentInfo.addCard')}</span>
|
|
99
101
|
</button>
|
|
100
102
|
</div>
|
|
101
103
|
</div>
|
|
@@ -107,7 +109,7 @@ export function PaymentInfoCard({
|
|
|
107
109
|
<div className="border border-zinc-200 rounded-lg overflow-hidden">
|
|
108
110
|
{email && (
|
|
109
111
|
<div className="flex items-center h-[60px] px-4 border-b border-zinc-200 gap-3">
|
|
110
|
-
<span className="paragraph-small-medium text-zinc-500 w-[100px]">
|
|
112
|
+
<span className="paragraph-small-medium text-zinc-500 w-[100px]">{translate('common.cards.paymentInfo.email')}</span>
|
|
111
113
|
<span className="paragraph-small-medium text-zinc-950 flex-1">{email}</span>
|
|
112
114
|
</div>
|
|
113
115
|
)}
|
|
@@ -118,7 +120,7 @@ export function PaymentInfoCard({
|
|
|
118
120
|
>
|
|
119
121
|
{!isExpanded ? (
|
|
120
122
|
<>
|
|
121
|
-
<span className="paragraph-small-medium text-zinc-500 w-[100px]">
|
|
123
|
+
<span className="paragraph-small-medium text-zinc-500 w-[100px]">{translate('common.cards.paymentInfo.payment')}</span>
|
|
122
124
|
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
|
123
125
|
<span className="paragraph-small-semibold text-zinc-950 truncate">
|
|
124
126
|
{selectedCard?.name}
|
|
@@ -135,7 +137,7 @@ export function PaymentInfoCard({
|
|
|
135
137
|
) : (
|
|
136
138
|
<>
|
|
137
139
|
<span className="paragraph-small-semibold text-zinc-950 flex-1">
|
|
138
|
-
|
|
140
|
+
{translate('common.cards.paymentInfo.selectPaymentMethod')}
|
|
139
141
|
</span>
|
|
140
142
|
<div className="size-8 flex items-center justify-center rounded-lg">
|
|
141
143
|
<IconChevronDown className="size-[18px] text-zinc-500 rotate-180" />
|
|
@@ -170,7 +172,7 @@ export function PaymentInfoCard({
|
|
|
170
172
|
: 'text-zinc-600 border border-zinc-200 hover:bg-zinc-50'
|
|
171
173
|
}`}
|
|
172
174
|
>
|
|
173
|
-
|
|
175
|
+
{translate('common.cards.paymentInfo.manageCards')}
|
|
174
176
|
</button>
|
|
175
177
|
)}
|
|
176
178
|
</div>
|
|
@@ -183,7 +185,7 @@ export function PaymentInfoCard({
|
|
|
183
185
|
>
|
|
184
186
|
<IconPlus className="size-[18px]" />
|
|
185
187
|
<span className="px-1.5">
|
|
186
|
-
{isExpanded ? '
|
|
188
|
+
{isExpanded ? translate('common.cards.paymentInfo.addCard') : translate('common.cards.paymentInfo.newPaymentMethod')}
|
|
187
189
|
</span>
|
|
188
190
|
</button>
|
|
189
191
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from 'next-intl';
|
|
3
4
|
import {
|
|
4
5
|
calculateRadius,
|
|
5
6
|
calculateCircumference,
|
|
@@ -21,6 +22,7 @@ export default function DefaultCircularProgress({
|
|
|
21
22
|
size = 62,
|
|
22
23
|
strokeWidth = 3,
|
|
23
24
|
}: CircularProgressProps) {
|
|
25
|
+
const translate = useTranslations();
|
|
24
26
|
const isDefaultWl = useIsDefaultWhitelabel();
|
|
25
27
|
const radius = calculateRadius(size, strokeWidth);
|
|
26
28
|
const circumference = calculateCircumference(radius);
|
|
@@ -35,7 +37,7 @@ export default function DefaultCircularProgress({
|
|
|
35
37
|
aria-valuenow={current}
|
|
36
38
|
aria-valuemin={0}
|
|
37
39
|
aria-valuemax={total}
|
|
38
|
-
aria-label=
|
|
40
|
+
aria-label={translate('common.forms.circularProgress.ariaLabel')}
|
|
39
41
|
>
|
|
40
42
|
<svg width={size} height={size} className="absolute">
|
|
41
43
|
<circle
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useMemo } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';
|
|
5
6
|
import { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';
|
|
6
7
|
import { cn } from '../../../infra/utils/clsx';
|
|
@@ -28,9 +29,9 @@ interface ComboboxFieldProps {
|
|
|
28
29
|
export function ComboboxField({
|
|
29
30
|
options,
|
|
30
31
|
label,
|
|
31
|
-
placeholder
|
|
32
|
-
searchPlaceholder
|
|
33
|
-
emptyMessage
|
|
32
|
+
placeholder,
|
|
33
|
+
searchPlaceholder,
|
|
34
|
+
emptyMessage,
|
|
34
35
|
value,
|
|
35
36
|
onChange,
|
|
36
37
|
disabled = false,
|
|
@@ -38,6 +39,10 @@ export function ComboboxField({
|
|
|
38
39
|
className,
|
|
39
40
|
containerClassName,
|
|
40
41
|
}: ComboboxFieldProps) {
|
|
42
|
+
const translate = useTranslations();
|
|
43
|
+
const resolvedPlaceholder = placeholder ?? translate('common.forms.combobox.placeholder');
|
|
44
|
+
const resolvedSearchPlaceholder = searchPlaceholder ?? translate('common.forms.combobox.searchPlaceholder');
|
|
45
|
+
const resolvedEmptyMessage = emptyMessage ?? translate('common.forms.combobox.emptyMessage');
|
|
41
46
|
const [open, setOpen] = useState(false);
|
|
42
47
|
const [search, setSearch] = useState('');
|
|
43
48
|
|
|
@@ -90,7 +95,7 @@ export function ComboboxField({
|
|
|
90
95
|
<span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>
|
|
91
96
|
{selectedOption
|
|
92
97
|
? (selectedOption.displayValue ?? selectedOption.label)
|
|
93
|
-
:
|
|
98
|
+
: resolvedPlaceholder}
|
|
94
99
|
</span>
|
|
95
100
|
{icon ?? (
|
|
96
101
|
<IconChevronDown
|
|
@@ -114,7 +119,7 @@ export function ComboboxField({
|
|
|
114
119
|
<IconSearch className="size-4 shrink-0 opacity-50 text-gray-500" />
|
|
115
120
|
<input
|
|
116
121
|
autoFocus
|
|
117
|
-
placeholder={
|
|
122
|
+
placeholder={resolvedSearchPlaceholder}
|
|
118
123
|
value={search}
|
|
119
124
|
onChange={(e) => setSearch(e.target.value)}
|
|
120
125
|
className="flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950"
|
|
@@ -123,7 +128,7 @@ export function ComboboxField({
|
|
|
123
128
|
|
|
124
129
|
<div className="overflow-y-auto max-h-[280px] p-1">
|
|
125
130
|
{filteredOptions.length === 0 ? (
|
|
126
|
-
<p className="py-6 text-center paragraph-small-medium text-gray-500">{
|
|
131
|
+
<p className="py-6 text-center paragraph-small-medium text-gray-500">{resolvedEmptyMessage}</p>
|
|
127
132
|
) : (
|
|
128
133
|
filteredOptions.map((option) => {
|
|
129
134
|
const isSelected = value === option.value;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { format } from "date-fns";
|
|
5
6
|
import { Calendar } from "./Calendar";
|
|
6
7
|
import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
|
|
@@ -23,9 +24,11 @@ interface DatePickerProps {
|
|
|
23
24
|
|
|
24
25
|
export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
|
|
25
26
|
(
|
|
26
|
-
{ value, onChange, placeholder
|
|
27
|
+
{ value, onChange, placeholder, className, disabled },
|
|
27
28
|
ref,
|
|
28
29
|
) => {
|
|
30
|
+
const translate = useTranslations();
|
|
31
|
+
const resolvedPlaceholder = placeholder ?? translate('common.forms.datePicker.placeholder');
|
|
29
32
|
const [open, setOpen] = useState(false);
|
|
30
33
|
const [date, setDate] = useState<Date | undefined>(() => {
|
|
31
34
|
return value ? isoParaDataLocal(value) : undefined;
|
|
@@ -51,7 +54,7 @@ export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
|
|
|
51
54
|
}
|
|
52
55
|
};
|
|
53
56
|
|
|
54
|
-
const displayText = date ? format(date, "dd/MM/yyyy") :
|
|
57
|
+
const displayText = date ? format(date, "dd/MM/yyyy") : resolvedPlaceholder;
|
|
55
58
|
|
|
56
59
|
return (
|
|
57
60
|
<Popover open={open} onOpenChange={setOpen}>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, forwardRef, useEffect } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { format } from "date-fns";
|
|
5
6
|
import { IconCalendar } from '@tabler/icons-react';
|
|
6
7
|
import { DateRange } from "react-day-picker";
|
|
@@ -24,7 +25,9 @@ interface DateRangePickerProps {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export const DateRangePicker = forwardRef<HTMLButtonElement, DateRangePickerProps>(
|
|
27
|
-
({ value, onChange, placeholder
|
|
28
|
+
({ value, onChange, placeholder, className, disabled }, ref) => {
|
|
29
|
+
const translate = useTranslations();
|
|
30
|
+
const resolvedPlaceholder = placeholder ?? translate('common.forms.dateRangePicker.placeholder');
|
|
28
31
|
const [open, setOpen] = useState(false);
|
|
29
32
|
const [range, setRange] = useState<DateRange | undefined>(() => {
|
|
30
33
|
if (value?.from && value?.to) {
|
|
@@ -62,7 +65,7 @@ export const DateRangePicker = forwardRef<HTMLButtonElement, DateRangePickerProp
|
|
|
62
65
|
|
|
63
66
|
const displayText = range?.from && range?.to
|
|
64
67
|
? `${format(range.from, "dd/MM/yyyy")} - ${format(range.to, "dd/MM/yyyy")}`
|
|
65
|
-
:
|
|
68
|
+
: resolvedPlaceholder;
|
|
66
69
|
|
|
67
70
|
return (
|
|
68
71
|
<Popover open={open} onOpenChange={setOpen}>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import { AsYouType, CountryCode } from 'libphonenumber-js';
|
|
5
6
|
import { Input, Separator, Popover, PopoverTrigger, PopoverContent, cn } from '@greatapps/common';
|
|
6
7
|
import { IconChevronDown, IconSearch } from '@tabler/icons-react';
|
|
@@ -41,6 +42,7 @@ export default function PhoneInput({
|
|
|
41
42
|
classnameContainer,
|
|
42
43
|
className,
|
|
43
44
|
}: PhoneInputProps) {
|
|
45
|
+
const translate = useTranslations();
|
|
44
46
|
const parsed = parsePhoneValue(value ?? '');
|
|
45
47
|
const [selectedCountry, setSelectedCountry] = useState<Country>(parsed.country);
|
|
46
48
|
const [phoneNumber, setPhoneNumber] = useState(parsed.number);
|
|
@@ -115,7 +117,7 @@ export default function PhoneInput({
|
|
|
115
117
|
{label && (
|
|
116
118
|
<div className="flex items-center gap-1 paragraph-xsmall-semibold">
|
|
117
119
|
<span className="text-zinc-600">{label}</span>
|
|
118
|
-
{optional && <span className="text-zinc-500">(
|
|
120
|
+
{optional && <span className="text-zinc-500">{translate('common.forms.phoneInput.optional')}</span>}
|
|
119
121
|
{required && <span className="text-red-600">*</span>}
|
|
120
122
|
</div>
|
|
121
123
|
)}
|
|
@@ -148,7 +150,7 @@ export default function PhoneInput({
|
|
|
148
150
|
<input
|
|
149
151
|
type="text"
|
|
150
152
|
className="flex-1 text-sm outline-none placeholder:text-zinc-400"
|
|
151
|
-
placeholder=
|
|
153
|
+
placeholder={translate('common.forms.phoneInput.searchPlaceholder')}
|
|
152
154
|
value={search}
|
|
153
155
|
onChange={(e) => setSearch(e.target.value)}
|
|
154
156
|
autoFocus
|
|
@@ -175,7 +177,7 @@ export default function PhoneInput({
|
|
|
175
177
|
</button>
|
|
176
178
|
))}
|
|
177
179
|
{filtered.length === 0 && (
|
|
178
|
-
<p className="text-sm text-zinc-500 p-3 text-center">
|
|
180
|
+
<p className="text-sm text-zinc-500 p-3 text-center">{translate('common.forms.phoneInput.emptyMessage')}</p>
|
|
179
181
|
)}
|
|
180
182
|
</div>
|
|
181
183
|
</PopoverContent>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import {
|
|
5
6
|
Select,
|
|
6
7
|
SelectContent,
|
|
@@ -41,7 +42,7 @@ export function SelectField({
|
|
|
41
42
|
hintMessage,
|
|
42
43
|
error = false,
|
|
43
44
|
errorMessage,
|
|
44
|
-
placeholder
|
|
45
|
+
placeholder,
|
|
45
46
|
options,
|
|
46
47
|
value,
|
|
47
48
|
defaultValue,
|
|
@@ -51,6 +52,8 @@ export function SelectField({
|
|
|
51
52
|
className,
|
|
52
53
|
containerClassName,
|
|
53
54
|
}: SelectFieldProps) {
|
|
55
|
+
const translate = useTranslations();
|
|
56
|
+
const resolvedPlaceholder = placeholder ?? translate('common.forms.select.placeholder');
|
|
54
57
|
const handleValueChange = (selectedValue: string) => {
|
|
55
58
|
if (!onChange) return;
|
|
56
59
|
const selectedOption = options.find((option) => String(option.value) === selectedValue);
|
|
@@ -67,7 +70,7 @@ export function SelectField({
|
|
|
67
70
|
{label && (
|
|
68
71
|
<div className="flex items-center gap-1 paragraph-xsmall-semibold">
|
|
69
72
|
<span className="text-gray-600">{label}</span>
|
|
70
|
-
{optional && <span className="text-gray-500">(
|
|
73
|
+
{optional && <span className="text-gray-500">{translate('common.forms.select.optional')}</span>}
|
|
71
74
|
{required && <span className="text-red-600">*</span>}
|
|
72
75
|
</div>
|
|
73
76
|
)}
|
|
@@ -89,7 +92,7 @@ export function SelectField({
|
|
|
89
92
|
)}
|
|
90
93
|
icon={icon}
|
|
91
94
|
>
|
|
92
|
-
<SelectValue placeholder={
|
|
95
|
+
<SelectValue placeholder={resolvedPlaceholder}>
|
|
93
96
|
{value !== undefined &&
|
|
94
97
|
(() => {
|
|
95
98
|
const selectedOption = options.find((opt) => String(opt.value) === String(value));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef, useState } from 'react'
|
|
4
|
+
import { useTranslations } from 'next-intl'
|
|
4
5
|
import ReactCrop, {
|
|
5
6
|
type Crop,
|
|
6
7
|
centerCrop,
|
|
@@ -178,6 +179,7 @@ export function ImageCropModal({
|
|
|
178
179
|
fileName,
|
|
179
180
|
onSelectAnother,
|
|
180
181
|
}: ImageCropModalProps) {
|
|
182
|
+
const translate = useTranslations()
|
|
181
183
|
const imgRef = useRef<HTMLImageElement>(null)
|
|
182
184
|
const [crop, setCrop] = useState<Crop>()
|
|
183
185
|
const [imageSize, setImageSize] = useState({ width: 0, height: 0 })
|
|
@@ -301,22 +303,28 @@ export function ImageCropModal({
|
|
|
301
303
|
<>
|
|
302
304
|
<DialogHeader className="p-5">
|
|
303
305
|
<DialogTitle className="text-center text-[16px]!">
|
|
304
|
-
{dimensionText
|
|
306
|
+
{dimensionText
|
|
307
|
+
? translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })
|
|
308
|
+
: translate('common.imageUpload.tooSmallTitleGeneric')}
|
|
305
309
|
</DialogTitle>
|
|
306
310
|
</DialogHeader>
|
|
307
311
|
|
|
308
312
|
<div className="px-5 pb-5">
|
|
309
313
|
<p className="paragraph-small-regular text-zinc-600 text-center">
|
|
310
|
-
{fileName
|
|
311
|
-
|
|
312
|
-
|
|
314
|
+
{fileName && dimensionText
|
|
315
|
+
? translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })
|
|
316
|
+
: fileName && !dimensionText
|
|
317
|
+
? translate('common.imageUpload.tooSmallBodyFileGeneric', { fileName })
|
|
318
|
+
: !fileName && dimensionText
|
|
319
|
+
? translate('common.imageUpload.tooSmallBodyNoFileWithDimension', { dimensionText })
|
|
320
|
+
: translate('common.imageUpload.tooSmallBodyNoFileGeneric')}
|
|
313
321
|
</p>
|
|
314
322
|
</div>
|
|
315
323
|
|
|
316
324
|
<DialogFooter className="flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200">
|
|
317
|
-
{onSelectAnother && <Button onClick={onSelectAnother}>
|
|
325
|
+
{onSelectAnother && <Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>}
|
|
318
326
|
<Button variant="secondary" onClick={handleCancel}>
|
|
319
|
-
|
|
327
|
+
{translate('common.actions.cancel')}
|
|
320
328
|
</Button>
|
|
321
329
|
</DialogFooter>
|
|
322
330
|
</>
|
|
@@ -324,7 +332,7 @@ export function ImageCropModal({
|
|
|
324
332
|
<>
|
|
325
333
|
<DialogHeader className="p-5">
|
|
326
334
|
<DialogTitle className="text-center text-[16px]!">
|
|
327
|
-
|
|
335
|
+
{translate('common.imageUpload.cropTitle')}
|
|
328
336
|
</DialogTitle>
|
|
329
337
|
</DialogHeader>
|
|
330
338
|
|
|
@@ -344,7 +352,7 @@ export function ImageCropModal({
|
|
|
344
352
|
<img
|
|
345
353
|
ref={imgRef}
|
|
346
354
|
src={imageSrc}
|
|
347
|
-
alt=
|
|
355
|
+
alt={translate('common.imageUpload.cropAlt')}
|
|
348
356
|
onLoad={onCropImgLoad}
|
|
349
357
|
draggable={false}
|
|
350
358
|
className="max-h-[50vh] object-contain select-none"
|
|
@@ -354,16 +362,16 @@ export function ImageCropModal({
|
|
|
354
362
|
</div>
|
|
355
363
|
|
|
356
364
|
<p className="paragraph-small-regular text-zinc-500 text-center">
|
|
357
|
-
|
|
365
|
+
{translate('common.imageUpload.cropHint')}
|
|
358
366
|
</p>
|
|
359
367
|
</div>
|
|
360
368
|
|
|
361
369
|
<DialogFooter className="flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200">
|
|
362
370
|
<Button onClick={handleConfirm} disabled={imageStatus !== 'ok' || !crop}>
|
|
363
|
-
|
|
371
|
+
{translate('common.actions.confirm')}
|
|
364
372
|
</Button>
|
|
365
373
|
<Button variant="secondary" onClick={handleCancel}>
|
|
366
|
-
|
|
374
|
+
{translate('common.actions.cancel')}
|
|
367
375
|
</Button>
|
|
368
376
|
</DialogFooter>
|
|
369
377
|
</>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { useTranslations } from 'next-intl'
|
|
3
4
|
import {
|
|
4
5
|
Dialog,
|
|
5
6
|
DialogContent,
|
|
@@ -28,6 +29,7 @@ export function ImageTooSmallModal({
|
|
|
28
29
|
onSelectAnother,
|
|
29
30
|
onCancel,
|
|
30
31
|
}: ImageTooSmallModalProps) {
|
|
32
|
+
const translate = useTranslations()
|
|
31
33
|
const dimensionText = `${minWidth}x${minHeight}px`
|
|
32
34
|
|
|
33
35
|
return (
|
|
@@ -38,21 +40,20 @@ export function ImageTooSmallModal({
|
|
|
38
40
|
>
|
|
39
41
|
<DialogHeader className="p-5">
|
|
40
42
|
<DialogTitle className="text-center text-[16px]!">
|
|
41
|
-
|
|
43
|
+
{translate('common.imageUpload.tooSmallTitleWithDimension', { dimensionText })}
|
|
42
44
|
</DialogTitle>
|
|
43
45
|
</DialogHeader>
|
|
44
46
|
|
|
45
47
|
<div className="px-5 pb-5">
|
|
46
48
|
<p className="paragraph-small-regular text-zinc-600 text-center">
|
|
47
|
-
|
|
48
|
-
uma imagem com pelo menos {dimensionText} para continuar.
|
|
49
|
+
{translate('common.imageUpload.tooSmallBodyFileWithDimension', { fileName, dimensionText })}
|
|
49
50
|
</p>
|
|
50
51
|
</div>
|
|
51
52
|
|
|
52
53
|
<DialogFooter className="flex-row! items-center justify-start! gap-3 p-5 border-t border-zinc-200">
|
|
53
|
-
<Button onClick={onSelectAnother}>
|
|
54
|
+
<Button onClick={onSelectAnother}>{translate('common.imageUpload.sendAnother')}</Button>
|
|
54
55
|
<Button variant="secondary" onClick={onCancel}>
|
|
55
|
-
|
|
56
|
+
{translate('common.actions.cancel')}
|
|
56
57
|
</Button>
|
|
57
58
|
</DialogFooter>
|
|
58
59
|
</DialogContent>
|