@carlonicora/nextjs-jsonapi 6.32.1 → 6.33.0
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/{BlockNoteEditor-XIEMUQCO.mjs → BlockNoteEditor-DCVT7YHE.mjs} +4 -4
- package/dist/{BlockNoteEditor-RD3JNEV5.js → BlockNoteEditor-ZVK5MD34.js} +24 -24
- package/dist/{BlockNoteEditor-RD3JNEV5.js.map → BlockNoteEditor-ZVK5MD34.js.map} +1 -1
- package/dist/{BlockNoteViewer-RQBYHBQL.js → BlockNoteViewer-2KPGZSTJ.js} +3 -3
- package/dist/{BlockNoteViewer-RQBYHBQL.js.map → BlockNoteViewer-2KPGZSTJ.js.map} +1 -1
- package/dist/{BlockNoteViewer-NVSR67X5.mjs → BlockNoteViewer-XDAC6AL7.mjs} +2 -2
- package/dist/billing/index.js +477 -469
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +15 -7
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-5H25LM2Z.js → chunk-576XHOYH.js} +5 -5
- package/dist/{chunk-5H25LM2Z.js.map → chunk-576XHOYH.js.map} +1 -1
- package/dist/{chunk-NPGX2GJD.js → chunk-CI64OTRX.js} +98 -75
- package/dist/chunk-CI64OTRX.js.map +1 -0
- package/dist/{chunk-AEBZ67JJ.mjs → chunk-ETU3AW2X.mjs} +2 -2
- package/dist/{chunk-4JVLLBRS.mjs → chunk-GUNH3THR.mjs} +24 -1
- package/dist/chunk-GUNH3THR.mjs.map +1 -0
- package/dist/{chunk-SQNFYMYE.js → chunk-KH4Y4FU4.js} +1532 -1288
- package/dist/chunk-KH4Y4FU4.js.map +1 -0
- package/dist/{chunk-PNCO3HMJ.js → chunk-TCAOU6NH.js} +3 -3
- package/dist/{chunk-PNCO3HMJ.js.map → chunk-TCAOU6NH.js.map} +1 -1
- package/dist/{chunk-F25BVBEH.mjs → chunk-V4NPMUZ2.mjs} +2663 -2419
- package/dist/chunk-V4NPMUZ2.mjs.map +1 -0
- package/dist/{chunk-AMQFKCAX.mjs → chunk-WPFEPIKP.mjs} +2 -2
- package/dist/client/index.js +6 -4
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +5 -3
- package/dist/components/index.js +12 -4
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +11 -3
- package/dist/components/tables/ContentListTable.d.ts +14 -0
- package/dist/components/tables/ContentListTable.d.ts.map +1 -1
- package/dist/components/tables/SortableHeader.d.ts +17 -0
- package/dist/components/tables/SortableHeader.d.ts.map +1 -0
- package/dist/components/tables/cells/cell.date.d.ts +4 -0
- package/dist/components/tables/cells/cell.date.d.ts.map +1 -1
- package/dist/components/tables/cells/cell.dateTime.d.ts +4 -0
- package/dist/components/tables/cells/cell.dateTime.d.ts.map +1 -1
- package/dist/components/tables/cells/cell.link.d.ts +4 -0
- package/dist/components/tables/cells/cell.link.d.ts.map +1 -1
- package/dist/components/tables/cells/cell.text.d.ts +4 -0
- package/dist/components/tables/cells/cell.text.d.ts.map +1 -1
- package/dist/components/tables/index.d.ts +2 -0
- package/dist/components/tables/index.d.ts.map +1 -1
- package/dist/components/tables/sorting.d.ts +24 -0
- package/dist/components/tables/sorting.d.ts.map +1 -0
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.js +2 -2
- package/dist/core/index.mjs +1 -1
- package/dist/email-automations/index.js +120 -115
- package/dist/email-automations/index.js.map +1 -1
- package/dist/email-automations/index.mjs +18 -13
- package/dist/email-automations/index.mjs.map +1 -1
- package/dist/features/analytics/index.js +114 -114
- package/dist/features/analytics/index.mjs +3 -3
- package/dist/features/analytics/server.js +4 -4
- package/dist/features/analytics/server.mjs +2 -2
- package/dist/features/billing/stripe-coupon/components/lists/CouponCodesList.d.ts.map +1 -1
- package/dist/features/billing/stripe-coupon/components/lists/CouponsList.d.ts.map +1 -1
- package/dist/features/billing/stripe-coupon/data/stripe-coupon-code.service.d.ts +2 -0
- package/dist/features/billing/stripe-coupon/data/stripe-coupon-code.service.d.ts.map +1 -1
- package/dist/features/billing/stripe-coupon/data/stripe-coupon.service.d.ts +1 -0
- package/dist/features/billing/stripe-coupon/data/stripe-coupon.service.d.ts.map +1 -1
- package/dist/features/billing/stripe-coupon/hooks/useStripeCouponCodeTableStructure.d.ts.map +1 -1
- package/dist/features/billing/stripe-coupon/hooks/useStripeCouponTableStructure.d.ts.map +1 -1
- package/dist/features/billing/stripe-price/components/lists/PricesList.d.ts.map +1 -1
- package/dist/features/billing/stripe-price/data/stripe-price.service.d.ts +2 -0
- package/dist/features/billing/stripe-price/data/stripe-price.service.d.ts.map +1 -1
- package/dist/features/billing/stripe-price/hooks/useStripePriceTableStructure.d.ts.map +1 -1
- package/dist/features/billing/stripe-product/components/lists/ProductsList.d.ts.map +1 -1
- package/dist/features/billing/stripe-product/data/stripe-product.service.d.ts +2 -0
- package/dist/features/billing/stripe-product/data/stripe-product.service.d.ts.map +1 -1
- package/dist/features/billing/stripe-product/hooks/useStripeProductTableStructure.d.ts.map +1 -1
- package/dist/features/blog/components/admin/BlogPostsList.d.ts.map +1 -1
- package/dist/features/blog/data/BlogPostService.d.ts +1 -0
- package/dist/features/blog/data/BlogPostService.d.ts.map +1 -1
- package/dist/features/blog/index.js +134 -132
- package/dist/features/blog/index.js.map +1 -1
- package/dist/features/blog/index.mjs +8 -6
- package/dist/features/blog/index.mjs.map +1 -1
- package/dist/features/blog/server.js +7 -7
- package/dist/features/blog/server.mjs +1 -1
- package/dist/features/company/components/lists/CompaniesList.d.ts.map +1 -1
- package/dist/features/company/data/company.service.d.ts +1 -0
- package/dist/features/company/data/company.service.d.ts.map +1 -1
- package/dist/features/content/data/content.service.d.ts +3 -0
- package/dist/features/content/data/content.service.d.ts.map +1 -1
- package/dist/features/email-automation/components/lists/EmailAutomationRecipientsList.d.ts.map +1 -1
- package/dist/features/email-automation/components/lists/EmailAutomationsList.d.ts.map +1 -1
- package/dist/features/email-automation/data/EmailAutomationService.d.ts +3 -0
- package/dist/features/email-automation/data/EmailAutomationService.d.ts.map +1 -1
- package/dist/features/email-automation/hooks/useEmailAutomationTableStructure.d.ts.map +1 -1
- package/dist/features/email-blast/components/lists/EmailBlastsList.d.ts.map +1 -1
- package/dist/features/email-blast/data/EmailBlastService.d.ts +1 -0
- package/dist/features/email-blast/data/EmailBlastService.d.ts.map +1 -1
- package/dist/features/email-blast/hooks/useEmailBlastTableStructure.d.ts.map +1 -1
- package/dist/features/help/index.js +37 -37
- package/dist/features/help/index.mjs +3 -3
- package/dist/features/how-to/components/lists/HowToList.d.ts.map +1 -1
- package/dist/features/how-to/data/HowToService.d.ts +2 -0
- package/dist/features/how-to/data/HowToService.d.ts.map +1 -1
- package/dist/features/notification/components/lists/NotificationsList.d.ts.map +1 -1
- package/dist/features/notification/data/notification.service.d.ts +2 -0
- package/dist/features/notification/data/notification.service.d.ts.map +1 -1
- package/dist/features/referral/components/containers/ReferralsAdminContainer.d.ts.map +1 -1
- package/dist/features/referral/data/ReferralAdminService.d.ts +1 -0
- package/dist/features/referral/data/ReferralAdminService.d.ts.map +1 -1
- package/dist/features/referral/hooks/useReferralAdminReferralTableStructure.d.ts.map +1 -1
- package/dist/features/role/components/lists/RolesList.d.ts.map +1 -1
- package/dist/features/role/components/lists/UserRolesList.d.ts.map +1 -1
- package/dist/features/role/data/role.service.d.ts +3 -0
- package/dist/features/role/data/role.service.d.ts.map +1 -1
- package/dist/features/tokenusage/index.js +114 -114
- package/dist/features/tokenusage/index.mjs +3 -3
- package/dist/features/user/components/lists/AdminUsersList.d.ts.map +1 -1
- package/dist/features/user/components/lists/CompanyUsersList.d.ts.map +1 -1
- package/dist/features/user/components/lists/PlatformUsersList.d.ts.map +1 -1
- package/dist/features/user/components/lists/RoleUsersList.d.ts.map +1 -1
- package/dist/features/user/components/lists/UsersListByContentIds.d.ts.map +1 -1
- package/dist/features/user/data/user.service.d.ts +11 -0
- package/dist/features/user/data/user.service.d.ts.map +1 -1
- package/dist/features/waitlist/components/lists/WaitlistList.d.ts.map +1 -1
- package/dist/features/waitlist/data/WaitlistService.d.ts +2 -0
- package/dist/features/waitlist/data/WaitlistService.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useDataListRetriever.d.ts +13 -0
- package/dist/hooks/useDataListRetriever.d.ts.map +1 -1
- package/dist/hooks/useListSortParam.d.ts +23 -0
- package/dist/hooks/useListSortParam.d.ts.map +1 -0
- package/dist/index.js +3 -3
- package/dist/index.mjs +2 -2
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/shadcnui/ui/calendar.d.ts +1 -1
- package/dist/shadcnui/ui/calendar.d.ts.map +1 -1
- package/messages/en.json +11 -0
- package/messages/it.json +11 -0
- package/package.json +1 -1
- package/src/components/tables/ContentListTable.tsx +108 -10
- package/src/components/tables/SortableHeader.tsx +43 -0
- package/src/components/tables/__tests__/ContentListTable.rendering.spec.tsx +1 -0
- package/src/components/tables/__tests__/ContentListTable.sort.spec.tsx +273 -0
- package/src/components/tables/__tests__/sorting.spec.ts +61 -0
- package/src/components/tables/cells/cell.date.tsx +10 -2
- package/src/components/tables/cells/cell.dateTime.tsx +10 -2
- package/src/components/tables/cells/cell.link.tsx +6 -1
- package/src/components/tables/cells/cell.text.tsx +11 -2
- package/src/components/tables/index.ts +2 -0
- package/src/components/tables/sorting.ts +41 -0
- package/src/features/billing/stripe-coupon/components/lists/CouponCodesList.tsx +2 -0
- package/src/features/billing/stripe-coupon/components/lists/CouponsList.tsx +2 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-code.service.ts +4 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon.service.ts +7 -1
- package/src/features/billing/stripe-coupon/hooks/__tests__/useStripeCouponCodeTableStructure.sort.spec.tsx +30 -0
- package/src/features/billing/stripe-coupon/hooks/__tests__/useStripeCouponTableStructure.sort.spec.tsx +33 -0
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponCodeTableStructure.tsx +5 -4
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponTableStructure.tsx +7 -4
- package/src/features/billing/stripe-price/components/lists/PricesList.tsx +2 -0
- package/src/features/billing/stripe-price/data/stripe-price.service.ts +4 -0
- package/src/features/billing/stripe-price/hooks/__tests__/useStripePriceTableStructure.sort.spec.tsx +29 -0
- package/src/features/billing/stripe-price/hooks/useStripePriceTableStructure.tsx +8 -5
- package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +2 -0
- package/src/features/billing/stripe-product/data/stripe-product.service.ts +4 -0
- package/src/features/billing/stripe-product/hooks/__tests__/useStripeProductTableStructure.sort.spec.tsx +29 -0
- package/src/features/billing/stripe-product/hooks/useStripeProductTableStructure.tsx +3 -2
- package/src/features/blog/components/admin/BlogPostsList.tsx +2 -0
- package/src/features/blog/data/BlogPostService.ts +3 -1
- package/src/features/blog/hooks/__tests__/useBlogPostTableStructure.sort.spec.tsx +19 -0
- package/src/features/blog/hooks/useBlogPostTableStructure.tsx +2 -2
- package/src/features/company/components/lists/CompaniesList.tsx +2 -0
- package/src/features/company/data/company.service.ts +3 -1
- package/src/features/company/hooks/__tests__/useCompanyTableStructure.sort.spec.tsx +19 -0
- package/src/features/company/hooks/useCompanyTableStructure.tsx +1 -1
- package/src/features/content/data/content.service.ts +12 -1
- package/src/features/content/hooks/__tests__/useContentTableStructure.sort.spec.tsx +21 -0
- package/src/features/content/hooks/useContentTableStructure.tsx +1 -1
- package/src/features/email-automation/components/lists/EmailAutomationRecipientsList.tsx +2 -0
- package/src/features/email-automation/components/lists/EmailAutomationsList.tsx +2 -0
- package/src/features/email-automation/data/EmailAutomationService.ts +9 -1
- package/src/features/email-automation/hooks/__tests__/useEmailAutomationEnrollmentTableStructure.sort.spec.tsx +21 -0
- package/src/features/email-automation/hooks/__tests__/useEmailAutomationTableStructure.sort.spec.tsx +29 -0
- package/src/features/email-automation/hooks/useEmailAutomationEnrollmentTableStructure.tsx +4 -4
- package/src/features/email-automation/hooks/useEmailAutomationTableStructure.tsx +5 -4
- package/src/features/email-blast/components/lists/EmailBlastsList.tsx +2 -0
- package/src/features/email-blast/data/EmailBlastService.ts +5 -1
- package/src/features/email-blast/hooks/__tests__/useEmailBlastTableStructure.sort.spec.tsx +29 -0
- package/src/features/email-blast/hooks/useEmailBlastTableStructure.tsx +16 -8
- package/src/features/how-to/components/lists/HowToList.tsx +2 -0
- package/src/features/how-to/data/HowToService.ts +4 -0
- package/src/features/how-to/hooks/__tests__/useHowToTableStructure.sort.spec.tsx +18 -0
- package/src/features/how-to/hooks/useHowToTableStructure.tsx +1 -1
- package/src/features/notification/components/lists/NotificationsList.tsx +2 -0
- package/src/features/notification/data/notification.service.ts +4 -0
- package/src/features/notification/hooks/__tests__/useNotificationTableStructure.sort.spec.tsx +19 -0
- package/src/features/notification/hooks/useNotificationTableStructure.tsx +1 -1
- package/src/features/referral/components/containers/ReferralsAdminContainer.tsx +4 -2
- package/src/features/referral/data/ReferralAdminService.ts +6 -1
- package/src/features/referral/hooks/__tests__/useReferralAdminReferralTableStructure.sort.spec.tsx +35 -0
- package/src/features/referral/hooks/useReferralAdminReferralTableStructure.tsx +10 -5
- package/src/features/role/components/lists/RolesList.tsx +2 -0
- package/src/features/role/components/lists/UserRolesList.tsx +2 -0
- package/src/features/role/data/role.service.ts +7 -1
- package/src/features/role/hooks/__tests__/useRoleTableStructure.sort.spec.tsx +16 -0
- package/src/features/role/hooks/useRoleTableStructure.tsx +2 -2
- package/src/features/user/components/lists/AdminUsersList.tsx +2 -0
- package/src/features/user/components/lists/CompanyUsersList.tsx +4 -0
- package/src/features/user/components/lists/PlatformUsersList.tsx +2 -0
- package/src/features/user/components/lists/RoleUsersList.tsx +2 -0
- package/src/features/user/components/lists/UsersListByContentIds.tsx +2 -0
- package/src/features/user/data/user.service.ts +28 -1
- package/src/features/user/hooks/__tests__/useUserTableStructure.sort.spec.tsx +16 -0
- package/src/features/user/hooks/useUserTableStructure.tsx +2 -2
- package/src/features/waitlist/components/lists/WaitlistList.tsx +2 -0
- package/src/features/waitlist/data/WaitlistService.ts +4 -0
- package/src/features/waitlist/hooks/__tests__/useWaitlistTableStructure.sort.spec.tsx +17 -0
- package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +3 -3
- package/src/hooks/__tests__/useDataListRetriever.sort.spec.tsx +114 -0
- package/src/hooks/__tests__/useListSortParam.spec.tsx +91 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDataListRetriever.ts +44 -4
- package/src/hooks/useListSortParam.ts +53 -0
- package/src/shadcnui/ui/__tests__/calendar.spec.tsx +222 -0
- package/src/shadcnui/ui/calendar.tsx +28 -1
- package/dist/chunk-4JVLLBRS.mjs.map +0 -1
- package/dist/chunk-F25BVBEH.mjs.map +0 -1
- package/dist/chunk-NPGX2GJD.js.map +0 -1
- package/dist/chunk-SQNFYMYE.js.map +0 -1
- /package/dist/{BlockNoteEditor-XIEMUQCO.mjs.map → BlockNoteEditor-DCVT7YHE.mjs.map} +0 -0
- /package/dist/{BlockNoteViewer-NVSR67X5.mjs.map → BlockNoteViewer-XDAC6AL7.mjs.map} +0 -0
- /package/dist/{chunk-AEBZ67JJ.mjs.map → chunk-ETU3AW2X.mjs.map} +0 -0
- /package/dist/{chunk-AMQFKCAX.mjs.map → chunk-WPFEPIKP.mjs.map} +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { enUS, it as italian } from "date-fns/locale";
|
|
3
|
+
import { NextIntlClientProvider, useTranslations } from "next-intl";
|
|
4
|
+
import type { ReactElement } from "react";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import en from "../../../../messages/en.json";
|
|
7
|
+
import itMessages from "../../../../messages/it.json";
|
|
8
|
+
import { configureI18n, type I18nConfig } from "../../../i18n/config";
|
|
9
|
+
import { Calendar } from "../calendar";
|
|
10
|
+
|
|
11
|
+
// vitest.setup.ts replaces next-intl with a stub whose t() returns the key. This spec pins the
|
|
12
|
+
// real texts, so it reads the real next-intl and the library's own message files.
|
|
13
|
+
vi.mock("next-intl", async () => await vi.importActual<typeof import("next-intl")>("next-intl"));
|
|
14
|
+
|
|
15
|
+
const OCTOBER_2026 = new Date(2026, 9, 1);
|
|
16
|
+
const TODAY = new Date(2026, 9, 15);
|
|
17
|
+
|
|
18
|
+
function renderIn(locale: "en" | "it", ui: ReactElement) {
|
|
19
|
+
return render(
|
|
20
|
+
<NextIntlClientProvider locale={locale} messages={locale === "it" ? itMessages : en} timeZone="Europe/Rome">
|
|
21
|
+
{ui}
|
|
22
|
+
</NextIntlClientProvider>,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("ui.calendar messages", () => {
|
|
27
|
+
it.each([
|
|
28
|
+
["previous_month", "Go to the previous month", "Vai al mese precedente"],
|
|
29
|
+
["next_month", "Go to the next month", "Vai al mese successivo"],
|
|
30
|
+
["navigation", "Navigation bar", "Barra di navigazione"],
|
|
31
|
+
["choose_month", "Choose the month", "Scegli il mese"],
|
|
32
|
+
["choose_year", "Choose the year", "Scegli l'anno"],
|
|
33
|
+
["today", "Today, {date}", "Oggi, {date}"],
|
|
34
|
+
["selected", "{date}, selected", "{date}, selezionato"],
|
|
35
|
+
["week_number", "Week {number}", "Settimana {number}"],
|
|
36
|
+
["week_number_header", "Week number", "Numero settimana"],
|
|
37
|
+
] as const)("%s has its English and Italian text", (key, english, italianText) => {
|
|
38
|
+
expect(en.ui.calendar[key]).toBe(english);
|
|
39
|
+
expect(itMessages.ui.calendar[key]).toBe(italianText);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("holds exactly the nine keys, in the same order in both files", () => {
|
|
43
|
+
const keys = [
|
|
44
|
+
"choose_month",
|
|
45
|
+
"choose_year",
|
|
46
|
+
"navigation",
|
|
47
|
+
"next_month",
|
|
48
|
+
"previous_month",
|
|
49
|
+
"selected",
|
|
50
|
+
"today",
|
|
51
|
+
"week_number",
|
|
52
|
+
"week_number_header",
|
|
53
|
+
];
|
|
54
|
+
expect(Object.keys(en.ui.calendar)).toEqual(keys);
|
|
55
|
+
expect(Object.keys(itMessages.ui.calendar)).toEqual(keys);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// The calendar never imports next-intl: it reads the `useTranslations` the host app hands to
|
|
60
|
+
// configureI18n(), through useUiText. Here the host app is next-intl itself.
|
|
61
|
+
function configure(translations: unknown) {
|
|
62
|
+
configureI18n((translations ? { useTranslations: translations } : null) as unknown as I18nConfig);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
afterEach(() => configure(null));
|
|
66
|
+
|
|
67
|
+
describe("Calendar labels without the app's texts", () => {
|
|
68
|
+
it("renders react-day-picker's English texts when i18n is not configured, with no provider", () => {
|
|
69
|
+
render(
|
|
70
|
+
<Calendar
|
|
71
|
+
mode="single"
|
|
72
|
+
locale={enUS}
|
|
73
|
+
month={OCTOBER_2026}
|
|
74
|
+
today={TODAY}
|
|
75
|
+
selected={new Date(2026, 9, 3)}
|
|
76
|
+
onSelect={() => {}}
|
|
77
|
+
/>,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(screen.getByRole("button", { name: "Go to the Previous Month" })).toBeInTheDocument();
|
|
81
|
+
expect(screen.getByRole("button", { name: "Go to the Next Month" })).toBeInTheDocument();
|
|
82
|
+
expect(screen.getByRole("button", { name: "Today, Thursday, October 15th, 2026" })).toBeInTheDocument();
|
|
83
|
+
expect(screen.getByRole("button", { name: "Saturday, October 3rd, 2026, selected" })).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("renders the English texts when the app's messages have no calendar keys", () => {
|
|
87
|
+
configure(useTranslations);
|
|
88
|
+
render(
|
|
89
|
+
<NextIntlClientProvider locale="it" messages={{ ui: { labels: { close: "Chiudi" } } }} timeZone="Europe/Rome">
|
|
90
|
+
<Calendar locale={italian} month={OCTOBER_2026} today={TODAY} showWeekNumber />
|
|
91
|
+
</NextIntlClientProvider>,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(screen.getByRole("button", { name: "Go to the Previous Month" })).toBeInTheDocument();
|
|
95
|
+
expect(screen.getByLabelText("Week Number")).toBeInTheDocument();
|
|
96
|
+
expect(screen.getByLabelText("Week 40")).toBeInTheDocument();
|
|
97
|
+
expect(screen.queryByText(/ui\.calendar/)).not.toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("Calendar labels", () => {
|
|
102
|
+
beforeEach(() => configure(useTranslations));
|
|
103
|
+
|
|
104
|
+
it("names the previous button in Italian", () => {
|
|
105
|
+
renderIn("it", <Calendar locale={italian} month={OCTOBER_2026} today={TODAY} />);
|
|
106
|
+
|
|
107
|
+
expect(screen.getByRole("button", { name: "Vai al mese precedente" })).toBeInTheDocument();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("names the next button and the navigation bar in Italian", () => {
|
|
111
|
+
renderIn("it", <Calendar locale={italian} month={OCTOBER_2026} today={TODAY} />);
|
|
112
|
+
|
|
113
|
+
expect(screen.getByRole("button", { name: "Vai al mese successivo" })).toBeInTheDocument();
|
|
114
|
+
expect(screen.getByRole("navigation", { name: "Barra di navigazione" })).toBeInTheDocument();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("prefixes today's day button", () => {
|
|
118
|
+
renderIn("it", <Calendar mode="single" locale={italian} month={OCTOBER_2026} today={TODAY} />);
|
|
119
|
+
|
|
120
|
+
expect(screen.getByRole("button", { name: "Oggi, giovedì 15 ottobre 2026" })).toBeInTheDocument();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("names a plain day with the date in the given locale only", () => {
|
|
124
|
+
renderIn("it", <Calendar mode="single" locale={italian} month={OCTOBER_2026} today={TODAY} />);
|
|
125
|
+
|
|
126
|
+
expect(screen.getByRole("button", { name: "sabato 3 ottobre 2026" })).toBeInTheDocument();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("suffixes a selected day", () => {
|
|
130
|
+
renderIn(
|
|
131
|
+
"it",
|
|
132
|
+
<Calendar
|
|
133
|
+
mode="single"
|
|
134
|
+
locale={italian}
|
|
135
|
+
month={OCTOBER_2026}
|
|
136
|
+
today={TODAY}
|
|
137
|
+
selected={new Date(2026, 9, 3)}
|
|
138
|
+
onSelect={() => {}}
|
|
139
|
+
/>,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(screen.getByRole("button", { name: "sabato 3 ottobre 2026, selezionato" })).toBeInTheDocument();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("prefixes and suffixes a day that is both today and selected", () => {
|
|
146
|
+
renderIn(
|
|
147
|
+
"it",
|
|
148
|
+
<Calendar
|
|
149
|
+
mode="single"
|
|
150
|
+
locale={italian}
|
|
151
|
+
month={OCTOBER_2026}
|
|
152
|
+
today={TODAY}
|
|
153
|
+
selected={TODAY}
|
|
154
|
+
onSelect={() => {}}
|
|
155
|
+
/>,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
expect(screen.getByRole("button", { name: "Oggi, giovedì 15 ottobre 2026, selezionato" })).toBeInTheDocument();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("prefixes today's cell when the calendar has no selection mode", () => {
|
|
162
|
+
renderIn("it", <Calendar locale={italian} month={OCTOBER_2026} today={TODAY} />);
|
|
163
|
+
|
|
164
|
+
expect(screen.getByRole("gridcell", { name: "Oggi, giovedì 15 ottobre 2026" })).toBeInTheDocument();
|
|
165
|
+
expect(screen.getByRole("gridcell", { name: "sabato 3 ottobre 2026" })).toBeInTheDocument();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("names the month and year dropdowns in Italian", () => {
|
|
169
|
+
renderIn(
|
|
170
|
+
"it",
|
|
171
|
+
<Calendar
|
|
172
|
+
locale={italian}
|
|
173
|
+
month={OCTOBER_2026}
|
|
174
|
+
today={TODAY}
|
|
175
|
+
captionLayout="dropdown"
|
|
176
|
+
startMonth={new Date(2025, 0, 1)}
|
|
177
|
+
endMonth={new Date(2027, 11, 1)}
|
|
178
|
+
/>,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(screen.getByRole("combobox", { name: "Scegli il mese" })).toBeInTheDocument();
|
|
182
|
+
expect(screen.getByRole("combobox", { name: "Scegli l'anno" })).toBeInTheDocument();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("names the week numbers and their column in Italian", () => {
|
|
186
|
+
renderIn("it", <Calendar locale={italian} month={OCTOBER_2026} today={TODAY} showWeekNumber />);
|
|
187
|
+
|
|
188
|
+
// react-day-picker hides the weekday row from the accessibility tree, so the header is read by its label.
|
|
189
|
+
expect(screen.getByLabelText("Numero settimana")).toBeInTheDocument();
|
|
190
|
+
expect(screen.getByLabelText("Settimana 40")).toBeInTheDocument();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("renders the English texts with the English messages", () => {
|
|
194
|
+
renderIn(
|
|
195
|
+
"en",
|
|
196
|
+
<Calendar
|
|
197
|
+
mode="single"
|
|
198
|
+
locale={enUS}
|
|
199
|
+
month={OCTOBER_2026}
|
|
200
|
+
today={TODAY}
|
|
201
|
+
selected={new Date(2026, 9, 3)}
|
|
202
|
+
onSelect={() => {}}
|
|
203
|
+
/>,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
expect(screen.getByRole("button", { name: "Go to the previous month" })).toBeInTheDocument();
|
|
207
|
+
expect(screen.getByRole("button", { name: "Go to the next month" })).toBeInTheDocument();
|
|
208
|
+
expect(screen.getByRole("button", { name: "Today, Thursday, October 15th, 2026" })).toBeInTheDocument();
|
|
209
|
+
expect(screen.getByRole("button", { name: "Saturday, October 3rd, 2026, selected" })).toBeInTheDocument();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("lets a caller's labels prop win, and keeps the other labels translated", () => {
|
|
213
|
+
renderIn(
|
|
214
|
+
"it",
|
|
215
|
+
<Calendar locale={italian} month={OCTOBER_2026} today={TODAY} labels={{ labelPrevious: () => "Indietro" }} />,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
expect(screen.getByRole("button", { name: "Indietro" })).toBeInTheDocument();
|
|
219
|
+
expect(screen.queryByRole("button", { name: "Vai al mese precedente" })).not.toBeInTheDocument();
|
|
220
|
+
expect(screen.getByRole("button", { name: "Vai al mese successivo" })).toBeInTheDocument();
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { DayPicker, getDefaultClassNames, type DayButton } from "react-day-picker";
|
|
4
|
+
import { DateLib, DayPicker, getDefaultClassNames, type DayButton, type Labels } from "react-day-picker";
|
|
5
5
|
|
|
6
6
|
import { cn } from "@/lib/utils";
|
|
7
7
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
8
8
|
import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react";
|
|
9
9
|
import { useDir } from "../../contexts/DirectionContext";
|
|
10
|
+
import { useUiText } from "./use-ui-text";
|
|
10
11
|
|
|
11
12
|
function Calendar({
|
|
12
13
|
className,
|
|
@@ -16,12 +17,37 @@ function Calendar({
|
|
|
16
17
|
buttonVariant = "ghost",
|
|
17
18
|
formatters,
|
|
18
19
|
components,
|
|
20
|
+
labels,
|
|
19
21
|
...props
|
|
20
22
|
}: React.ComponentProps<typeof DayPicker> & {
|
|
21
23
|
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
22
24
|
}) {
|
|
23
25
|
const defaultClassNames = getDefaultClassNames();
|
|
24
26
|
const dir = useDir();
|
|
27
|
+
const uiText = useUiText();
|
|
28
|
+
|
|
29
|
+
// The accessible names react-day-picker builds, in the active language. Each falls back to
|
|
30
|
+
// react-day-picker's own English text when the app has no translation for it. The date part
|
|
31
|
+
// keeps react-day-picker's own format(date, "PPPP") in the locale the caller passed.
|
|
32
|
+
const translatedLabels: Partial<Labels> = {
|
|
33
|
+
labelPrevious: () => uiText("ui.calendar.previous_month", "Go to the Previous Month"),
|
|
34
|
+
labelNext: () => uiText("ui.calendar.next_month", "Go to the Next Month"),
|
|
35
|
+
labelNav: () => uiText("ui.calendar.navigation", ""),
|
|
36
|
+
labelMonthDropdown: () => uiText("ui.calendar.choose_month", "Choose the Month"),
|
|
37
|
+
labelYearDropdown: () => uiText("ui.calendar.choose_year", "Choose the Year"),
|
|
38
|
+
labelDayButton: (date, modifiers, options, dateLib) => {
|
|
39
|
+
let label = (dateLib ?? new DateLib(options)).format(date, "PPPP");
|
|
40
|
+
if (modifiers.today) label = uiText("ui.calendar.today", "Today, {date}", { date: label });
|
|
41
|
+
if (modifiers.selected) label = uiText("ui.calendar.selected", "{date}, selected", { date: label });
|
|
42
|
+
return label;
|
|
43
|
+
},
|
|
44
|
+
labelGridcell: (date, modifiers, options, dateLib) => {
|
|
45
|
+
const label = (dateLib ?? new DateLib(options)).format(date, "PPPP");
|
|
46
|
+
return modifiers?.today ? uiText("ui.calendar.today", "Today, {date}", { date: label }) : label;
|
|
47
|
+
},
|
|
48
|
+
labelWeekNumber: (weekNumber) => uiText("ui.calendar.week_number", "Week {number}", { number: weekNumber }),
|
|
49
|
+
labelWeekNumberHeader: () => uiText("ui.calendar.week_number_header", "Week Number"),
|
|
50
|
+
};
|
|
25
51
|
|
|
26
52
|
return (
|
|
27
53
|
<DayPicker
|
|
@@ -32,6 +58,7 @@ function Calendar({
|
|
|
32
58
|
className,
|
|
33
59
|
)}
|
|
34
60
|
captionLayout={captionLayout}
|
|
61
|
+
labels={{ ...translatedLabels, ...labels }}
|
|
35
62
|
formatters={{
|
|
36
63
|
formatMonthDropdown: (date) => date.toLocaleString(props.locale?.code ?? "default", { month: "short" }),
|
|
37
64
|
...formatters,
|