@carlonicora/nextjs-jsonapi 1.36.1 → 1.38.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-4MDHRUS2.js → BlockNoteEditor-3S2B36O3.js} +15 -15
- package/dist/{BlockNoteEditor-4MDHRUS2.js.map → BlockNoteEditor-3S2B36O3.js.map} +1 -1
- package/dist/{BlockNoteEditor-SZWO3MDO.mjs → BlockNoteEditor-WQUJTVJL.mjs} +5 -5
- package/dist/BlockNoteEditor-WQUJTVJL.mjs.map +1 -0
- package/dist/billing/index.d.mts +15 -5
- package/dist/billing/index.d.ts +15 -5
- package/dist/billing/index.js +750 -520
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +665 -435
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-53IPQJVH.js → chunk-3EZX4G2E.js} +147 -23
- package/dist/chunk-3EZX4G2E.js.map +1 -0
- package/dist/{chunk-I7DFEJFF.mjs → chunk-4PHADEKA.mjs} +738 -1418
- package/dist/chunk-4PHADEKA.mjs.map +1 -0
- package/dist/{chunk-E6PQQTWF.js → chunk-T2JCZYWK.js} +999 -1679
- package/dist/chunk-T2JCZYWK.js.map +1 -0
- package/dist/{chunk-P7R2DPD6.mjs → chunk-TQ5GRRTM.mjs} +125 -1
- package/dist/chunk-TQ5GRRTM.mjs.map +1 -0
- package/dist/client/index.js +3 -3
- package/dist/client/index.mjs +2 -2
- package/dist/components/index.d.mts +23 -8
- package/dist/components/index.d.ts +23 -8
- package/dist/components/index.js +3 -3
- package/dist/components/index.mjs +2 -2
- package/dist/contexts/index.d.mts +1 -1
- package/dist/contexts/index.d.ts +1 -1
- package/dist/contexts/index.js +3 -3
- package/dist/contexts/index.mjs +2 -2
- package/dist/core/index.d.mts +47 -3
- package/dist/core/index.d.ts +47 -3
- package/dist/core/index.js +8 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +7 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +1 -1
- package/dist/{stripe-subscription.interface-DK7BJaNd.d.ts → stripe-promotion-code.interface-BcJty0rv.d.ts} +18 -1
- package/dist/{stripe-subscription.interface-C8uhCYIZ.d.mts → stripe-promotion-code.interface-Dnm2DJKQ.d.mts} +18 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/billing/index.ts +1 -0
- package/src/client/context/JsonApiProvider.tsx +1 -5
- package/src/client/hooks/__tests__/useJsonApiGet.test.tsx +9 -9
- package/src/client/hooks/__tests__/useJsonApiMutation.test.tsx +11 -11
- package/src/client/hooks/__tests__/useRehydration.test.ts +13 -34
- package/src/components/editors/BlockNoteEditor.tsx +2 -2
- package/src/components/forms/CommonEditorTrigger.tsx +1 -1
- package/src/components/forms/FormCheckbox.tsx +2 -12
- package/src/components/forms/FormDate.tsx +1 -6
- package/src/components/forms/FormInput.tsx +1 -1
- package/src/components/forms/FormPassword.tsx +1 -7
- package/src/components/forms/FormSelect.tsx +2 -8
- package/src/components/forms/FormSlider.tsx +1 -5
- package/src/components/forms/FormSwitch.tsx +1 -5
- package/src/components/forms/GdprConsentCheckbox.tsx +2 -8
- package/src/components/forms/PasswordInput.tsx +28 -26
- package/src/components/forms/__tests__/FormCheckbox.test.tsx +16 -18
- package/src/components/forms/__tests__/FormDate.test.tsx +14 -30
- package/src/components/forms/__tests__/FormInput.test.tsx +21 -37
- package/src/components/forms/__tests__/FormSelect.test.tsx +15 -21
- package/src/components/tables/ContentListTable.tsx +1 -1
- package/src/components/tables/__tests__/ContentListTable.test.tsx +17 -89
- package/src/components/tables/cells/cell.component.tsx +1 -1
- package/src/contexts/HeaderChildrenContext.tsx +3 -1
- package/src/core/endpoint/__tests__/EndpointCreator.test.ts +2 -7
- package/src/core/factories/__tests__/JsonApiDataFactory.test.ts +3 -3
- package/src/core/factories/__tests__/RehydrationFactory.test.ts +4 -6
- package/src/core/index.ts +1 -0
- package/src/core/registry/ModuleRegistry.ts +1 -0
- package/src/core/registry/__tests__/DataClassRegistry.test.ts +5 -15
- package/src/core/registry/__tests__/ModuleRegistrar.test.ts +5 -15
- package/src/features/auth/components/GdprConsentSection.tsx +1 -6
- package/src/features/auth/components/details/LandingComponent.tsx +6 -1
- package/src/features/auth/components/forms/AcceptInvitation.tsx +1 -1
- package/src/features/auth/components/forms/ResetPassword.tsx +1 -1
- package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +13 -18
- package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +12 -17
- package/src/features/billing/components/modals/BillingDetailModal.tsx +2 -13
- package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +8 -1
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +2 -13
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +2 -12
- package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +6 -1
- package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +1 -0
- package/src/features/billing/stripe-price/components/lists/PricesList.tsx +13 -5
- package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +5 -5
- package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +108 -0
- package/src/features/billing/stripe-promotion-code/components/index.ts +1 -0
- package/src/features/billing/stripe-promotion-code/data/index.ts +3 -0
- package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.interface.ts +14 -0
- package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.service.ts +64 -0
- package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.ts +66 -0
- package/src/features/billing/stripe-promotion-code/index.ts +2 -0
- package/src/features/billing/stripe-promotion-code/stripe-promotion-code.module.ts +9 -0
- package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +1 -3
- package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +4 -1
- package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +1 -1
- package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +24 -4
- package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +9 -2
- package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +3 -1
- package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +7 -7
- package/src/features/billing/stripe-subscription/components/wizards/WizardProgressIndicator.tsx +2 -10
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +3 -13
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +134 -23
- package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +2 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +8 -0
- package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +93 -7
- package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +1 -1
- package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +1 -1
- package/src/features/company/components/details/CompanyDetails.tsx +2 -2
- package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +1 -1
- package/src/features/index.ts +1 -0
- package/src/features/notification/components/containers/NotificationsListContainer.tsx +1 -1
- package/src/features/notification/components/modals/NotificationModal.tsx +6 -2
- package/src/features/notification/contexts/NotificationContext.tsx +1 -3
- package/src/features/oauth/components/OAuthClientCard.tsx +15 -17
- package/src/features/oauth/components/OAuthClientDetail.tsx +7 -19
- package/src/features/oauth/components/OAuthClientForm.tsx +4 -13
- package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +4 -20
- package/src/features/oauth/components/OAuthRedirectUriInput.tsx +5 -12
- package/src/features/oauth/components/OAuthScopeSelector.tsx +17 -23
- package/src/features/oauth/components/consent/OAuthConsentActions.tsx +3 -16
- package/src/features/oauth/components/consent/OAuthConsentHeader.tsx +3 -12
- package/src/features/oauth/components/consent/OAuthConsentScreen.tsx +5 -20
- package/src/features/oauth/components/consent/OAuthScopeList.tsx +3 -18
- package/src/features/onboarding/contexts/OnboardingContext.tsx +3 -3
- package/src/features/role/components/forms/FormRoles.tsx +1 -7
- package/src/features/user/components/containers/UserContainer.tsx +1 -1
- package/src/features/user/components/details/UserDetails.tsx +1 -1
- package/src/features/user/components/forms/UserDeleter.tsx +1 -1
- package/src/features/user/components/forms/UserEditor.tsx +1 -1
- package/src/features/user/components/forms/UserMultiSelect.tsx +7 -7
- package/src/features/user/components/lists/UserListInAdd.tsx +2 -2
- package/src/features/user/components/lists/UsersList.tsx +7 -1
- package/src/features/user/contexts/CurrentUserContext.tsx +36 -33
- package/src/hooks/__tests__/useDataListRetriever.test.ts +15 -21
- package/src/hooks/__tests__/useDebounce.test.ts +2 -7
- package/src/hooks/useCustomD3Graph.tsx +2 -2
- package/src/shadcnui/custom/multi-select.tsx +28 -2
- package/src/shadcnui/ui/accordion.tsx +21 -23
- package/src/shadcnui/ui/alert-dialog.tsx +45 -62
- package/src/shadcnui/ui/alert.tsx +25 -41
- package/src/shadcnui/ui/avatar.tsx +23 -36
- package/src/shadcnui/ui/badge.tsx +13 -11
- package/src/shadcnui/ui/breadcrumb.tsx +21 -55
- package/src/shadcnui/ui/button.tsx +17 -18
- package/src/shadcnui/ui/calendar.tsx +44 -93
- package/src/shadcnui/ui/carousel.tsx +72 -100
- package/src/shadcnui/ui/chart.tsx +102 -161
- package/src/shadcnui/ui/checkbox.tsx +8 -9
- package/src/shadcnui/ui/combobox.tsx +52 -83
- package/src/shadcnui/ui/command.tsx +43 -77
- package/src/shadcnui/ui/context-menu.tsx +47 -86
- package/src/shadcnui/ui/dialog.tsx +34 -60
- package/src/shadcnui/ui/drawer.tsx +32 -53
- package/src/shadcnui/ui/dropdown-menu.tsx +48 -65
- package/src/shadcnui/ui/field.tsx +39 -48
- package/src/shadcnui/ui/hover-card.tsx +9 -14
- package/src/shadcnui/ui/input-group.tsx +44 -55
- package/src/shadcnui/ui/input-otp.tsx +22 -26
- package/src/shadcnui/ui/input.tsx +6 -6
- package/src/shadcnui/ui/label.tsx +6 -6
- package/src/shadcnui/ui/navigation-menu.tsx +36 -60
- package/src/shadcnui/ui/popover.tsx +15 -38
- package/src/shadcnui/ui/progress.tsx +12 -29
- package/src/shadcnui/ui/radio-group.tsx +9 -15
- package/src/shadcnui/ui/resizable.tsx +14 -24
- package/src/shadcnui/ui/scroll-area.tsx +12 -27
- package/src/shadcnui/ui/select.tsx +41 -65
- package/src/shadcnui/ui/separator.tsx +7 -11
- package/src/shadcnui/ui/sheet.tsx +30 -55
- package/src/shadcnui/ui/sidebar.tsx +141 -189
- package/src/shadcnui/ui/skeleton.tsx +3 -9
- package/src/shadcnui/ui/slider.tsx +11 -23
- package/src/shadcnui/ui/switch.tsx +8 -8
- package/src/shadcnui/ui/tabs.tsx +14 -21
- package/src/shadcnui/ui/textarea.tsx +5 -5
- package/src/shadcnui/ui/toggle.tsx +8 -14
- package/src/shadcnui/ui/tooltip.tsx +11 -23
- package/src/testing/providers/MockJsonApiProvider.tsx +1 -5
- package/src/testing/utils/renderWithProviders.tsx +6 -10
- package/dist/BlockNoteEditor-SZWO3MDO.mjs.map +0 -1
- package/dist/chunk-53IPQJVH.js.map +0 -1
- package/dist/chunk-E6PQQTWF.js.map +0 -1
- package/dist/chunk-I7DFEJFF.mjs.map +0 -1
- package/dist/chunk-P7R2DPD6.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return (\n <JsonApiContext.Provider value={mergedConfig}>\n {children}\n </JsonApiContext.Provider>\n );\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\ndeclare module \"vitest\" {\n interface Assertion<T = any> {\n toBeValidJsonApi(): T;\n toHaveJsonApiType(expectedType: string): T;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): T;\n toHaveJsonApiRelationship(relationshipName: string): T;\n toHaveJsonApiLength(expectedLength: number): T;\n }\n interface AsymmetricMatchersContaining {\n toBeValidJsonApi(): any;\n toHaveJsonApiType(expectedType: string): any;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): any;\n toHaveJsonApiRelationship(relationshipName: string): any;\n toHaveJsonApiLength(expectedLength: number): any;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport { MockJsonApiProvider, MockJsonApiProviderProps } from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(\n ui: ReactElement,\n options: RenderWithProvidersOptions = {}\n): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = (\n <MockJsonApiProvider config={jsonApiConfig}>\n {children}\n </MockJsonApiProvider>\n );\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"],"mappings":"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","names":["render","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/providers/MockJsonApiProvider.tsx","../../src/testing/factories/createMockModule.ts","../../src/testing/factories/createMockResponse.ts","../../src/testing/factories/createMockService.ts","../../src/testing/factories/createMockApiData.ts","../../src/testing/matchers/jsonApiMatchers.ts","../../src/testing/utils/renderWithProviders.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport { JsonApiConfig, JsonApiContext } from \"../../client/context/JsonApiContext\";\n\nexport interface MockJsonApiProviderProps {\n children: React.ReactNode;\n config?: Partial<JsonApiConfig>;\n}\n\nconst defaultMockConfig: JsonApiConfig = {\n apiUrl: \"https://api.test.com\",\n tokenGetter: async () => \"mock-token-for-testing\",\n languageGetter: async () => \"en\",\n defaultHeaders: {},\n onError: () => {},\n cacheConfig: {\n defaultProfile: \"default\",\n },\n};\n\n/**\n * A test-friendly provider that wraps components with mock JSON:API context.\n *\n * @example\n * ```tsx\n * import { MockJsonApiProvider } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * render(\n * <MockJsonApiProvider>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n *\n * @example With custom config\n * ```tsx\n * render(\n * <MockJsonApiProvider config={{ apiUrl: 'https://custom.api.com' }}>\n * <MyComponent />\n * </MockJsonApiProvider>\n * );\n * ```\n */\nexport function MockJsonApiProvider({ children, config }: MockJsonApiProviderProps) {\n const mergedConfig: JsonApiConfig = {\n ...defaultMockConfig,\n ...config,\n };\n\n return <JsonApiContext.Provider value={mergedConfig}>{children}</JsonApiContext.Provider>;\n}\n\nexport { defaultMockConfig };\n","import { ApiRequestDataTypeInterface } from \"../../core/interfaces/ApiRequestDataTypeInterface\";\n\nexport interface CreateMockModuleOptions {\n name: string;\n cache?: string;\n inclusions?: ApiRequestDataTypeInterface[\"inclusions\"];\n}\n\n/**\n * Creates a mock module definition for testing.\n *\n * @example\n * ```ts\n * import { createMockModule } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticleModule = createMockModule({ name: 'articles' });\n * ```\n */\nexport function createMockModule(options: CreateMockModuleOptions): ApiRequestDataTypeInterface {\n // Create a mock model class\n class MockModel {\n id = \"mock-id\";\n type = options.name;\n }\n\n return {\n name: options.name,\n cache: options.cache,\n inclusions: options.inclusions,\n model: MockModel,\n };\n}\n","import { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockResponseOptions {\n data?: ApiDataInterface | ApiDataInterface[] | null;\n ok?: boolean;\n response?: number;\n error?: string;\n meta?: Record<string, any>;\n self?: string;\n next?: string;\n prev?: string;\n}\n\n/**\n * Creates a mock API response for testing.\n *\n * @example\n * ```ts\n * import { createMockResponse, createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockData = createMockApiData({ type: 'articles', id: '1' });\n * const response = createMockResponse({ data: mockData, ok: true });\n * ```\n *\n * @example With pagination\n * ```ts\n * const response = createMockResponse({\n * data: [mockData],\n * ok: true,\n * next: '/articles?page=2',\n * prev: '/articles?page=0',\n * });\n * ```\n */\nexport function createMockResponse(options: CreateMockResponseOptions = {}): ApiResponseInterface {\n const {\n data = null,\n ok = true,\n response = ok ? 200 : 500,\n error = ok ? \"\" : \"Error\",\n meta,\n self,\n next,\n prev,\n } = options;\n\n const mockResponse: ApiResponseInterface = {\n ok,\n response,\n data: data as ApiDataInterface | ApiDataInterface[],\n error,\n meta,\n self,\n next,\n prev,\n };\n\n // Add pagination methods if next/prev provided\n if (next) {\n mockResponse.nextPage = async () => createMockResponse({ ...options, next: undefined, prev: self });\n }\n\n if (prev) {\n mockResponse.prevPage = async () => createMockResponse({ ...options, prev: undefined, next: self });\n }\n\n return mockResponse;\n}\n\n/**\n * Creates a mock error response for testing error scenarios.\n *\n * @example\n * ```ts\n * import { createMockErrorResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorResponse = createMockErrorResponse(404, 'Not Found');\n * ```\n */\nexport function createMockErrorResponse(statusCode: number, errorMessage: string): ApiResponseInterface {\n return createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n data: null,\n });\n}\n","import { vi, type Mock } from \"vitest\";\nimport { ApiResponseInterface } from \"../../core/interfaces/ApiResponseInterface\";\nimport { createMockResponse } from \"./createMockResponse\";\n\nexport type MockApiMethod = Mock<(...args: any[]) => Promise<ApiResponseInterface>>;\n\nexport interface MockService {\n get: MockApiMethod;\n post: MockApiMethod;\n put: MockApiMethod;\n patch: MockApiMethod;\n delete: MockApiMethod;\n}\n\nexport interface CreateMockServiceOptions {\n defaultResponse?: ApiResponseInterface;\n}\n\n/**\n * Creates a mock service with Vitest mock functions for all HTTP methods.\n *\n * @example\n * ```ts\n * import { createMockService, createMockResponse } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockService = createMockService();\n * mockService.get.mockResolvedValue(createMockResponse({ data: mockData }));\n *\n * // Use in test\n * expect(mockService.get).toHaveBeenCalled();\n * ```\n *\n * @example With default response\n * ```ts\n * const mockService = createMockService({\n * defaultResponse: createMockResponse({ ok: true, data: [] }),\n * });\n * ```\n */\nexport function createMockService(options: CreateMockServiceOptions = {}): MockService {\n const defaultResponse = options.defaultResponse ?? createMockResponse({ ok: true });\n\n return {\n get: vi.fn().mockResolvedValue(defaultResponse),\n post: vi.fn().mockResolvedValue(defaultResponse),\n put: vi.fn().mockResolvedValue(defaultResponse),\n patch: vi.fn().mockResolvedValue(defaultResponse),\n delete: vi.fn().mockResolvedValue(defaultResponse),\n };\n}\n\n/**\n * Creates a mock service that returns errors for all methods.\n *\n * @example\n * ```ts\n * import { createMockErrorService } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const errorService = createMockErrorService(500, 'Internal Server Error');\n * ```\n */\nexport function createMockErrorService(statusCode: number = 500, errorMessage: string = \"Error\"): MockService {\n const errorResponse = createMockResponse({\n ok: false,\n response: statusCode,\n error: errorMessage,\n });\n\n return {\n get: vi.fn().mockResolvedValue(errorResponse),\n post: vi.fn().mockResolvedValue(errorResponse),\n put: vi.fn().mockResolvedValue(errorResponse),\n patch: vi.fn().mockResolvedValue(errorResponse),\n delete: vi.fn().mockResolvedValue(errorResponse),\n };\n}\n","import { ApiDataInterface } from \"../../core/interfaces/ApiDataInterface\";\n\nexport interface CreateMockApiDataOptions {\n type: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n included?: any[];\n createdAt?: Date;\n updatedAt?: Date;\n self?: string;\n}\n\n/**\n * Creates a mock ApiDataInterface object for testing.\n *\n * @example\n * ```ts\n * import { createMockApiData } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test Article', body: 'Content here' },\n * });\n * ```\n *\n * @example With relationships\n * ```ts\n * const mockArticle = createMockApiData({\n * type: 'articles',\n * id: '1',\n * attributes: { title: 'Test' },\n * relationships: {\n * author: { data: { type: 'users', id: '42' } },\n * },\n * });\n * ```\n */\nexport function createMockApiData(options: CreateMockApiDataOptions): ApiDataInterface {\n const {\n type,\n id = `mock-${type}-${Math.random().toString(36).substring(7)}`,\n attributes = {},\n relationships = {},\n included = [],\n createdAt = new Date(),\n updatedAt = new Date(),\n self,\n } = options;\n\n const jsonApiData = {\n type,\n id,\n attributes: {\n ...attributes,\n createdAt: createdAt.toISOString(),\n updatedAt: updatedAt.toISOString(),\n },\n relationships,\n };\n\n const mockData: ApiDataInterface = {\n get included() {\n return included;\n },\n get type() {\n return type;\n },\n get id() {\n return id;\n },\n get createdAt() {\n return createdAt;\n },\n get updatedAt() {\n return updatedAt;\n },\n get self() {\n return self;\n },\n get jsonApi() {\n return jsonApiData;\n },\n generateApiUrl: (params?: any) => {\n const baseUrl = `/${type}/${id}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n return `${baseUrl}?${searchParams.toString()}`;\n }\n return baseUrl;\n },\n dehydrate: () => ({\n jsonApi: jsonApiData,\n included,\n allData: [jsonApiData],\n }),\n rehydrate: function (_data: any) {\n return this;\n },\n createJsonApi: (data: any) => ({\n type,\n id,\n attributes: data,\n }),\n };\n\n // Add attribute accessors to the mock object\n Object.keys(attributes).forEach((key) => {\n Object.defineProperty(mockData, key, {\n get: () => attributes[key],\n enumerable: true,\n });\n });\n\n return mockData;\n}\n\n/**\n * Creates an array of mock ApiDataInterface objects.\n *\n * @example\n * ```ts\n * import { createMockApiDataList } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const mockArticles = createMockApiDataList('articles', 5, (index) => ({\n * title: `Article ${index + 1}`,\n * }));\n * ```\n */\nexport function createMockApiDataList(\n type: string,\n count: number,\n attributesFactory?: (index: number) => Record<string, any>,\n): ApiDataInterface[] {\n return Array.from({ length: count }, (_, index) =>\n createMockApiData({\n type,\n id: `${index + 1}`,\n attributes: attributesFactory?.(index) ?? {},\n }),\n );\n}\n","import { expect } from \"vitest\";\n\ninterface JsonApiResponse {\n data?:\n | {\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }\n | Array<{\n type?: string;\n id?: string;\n attributes?: Record<string, any>;\n relationships?: Record<string, any>;\n }>;\n}\n\n/**\n * Custom Vitest matchers for JSON:API assertions.\n *\n * @example\n * ```ts\n * import { jsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n * import { expect } from 'vitest';\n *\n * expect.extend(jsonApiMatchers);\n *\n * // Then use in tests:\n * expect(response).toBeValidJsonApi();\n * expect(response).toHaveJsonApiType('articles');\n * expect(response).toHaveJsonApiAttribute('title', 'My Article');\n * expect(response).toHaveJsonApiRelationship('author');\n * ```\n */\nexport const jsonApiMatchers = {\n /**\n * Asserts that the response has a valid JSON:API structure with type and id.\n */\n toBeValidJsonApi(received: JsonApiResponse) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const hasType = typeof data?.type === \"string\" && data.type.length > 0;\n const hasId = typeof data?.id === \"string\" && data.id.length > 0;\n const isValid = hasType && hasId;\n\n return {\n pass: isValid,\n message: () =>\n isValid\n ? `Expected response not to be valid JSON:API, but it has type \"${data?.type}\" and id \"${data?.id}\"`\n : `Expected response to be valid JSON:API with type and id, but got type: ${JSON.stringify(data?.type)}, id: ${JSON.stringify(data?.id)}`,\n };\n },\n\n /**\n * Asserts that the response data has the expected JSON:API type.\n */\n toHaveJsonApiType(received: JsonApiResponse, expectedType: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const actualType = data?.type;\n const pass = actualType === expectedType;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have JSON:API type \"${expectedType}\"`\n : `Expected response to have JSON:API type \"${expectedType}\", but got \"${actualType}\"`,\n };\n },\n\n /**\n * Asserts that the response data has an attribute with the expected value.\n */\n toHaveJsonApiAttribute(received: JsonApiResponse, attributeName: string, expectedValue?: any) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const attributes = data?.attributes ?? {};\n const hasAttribute = attributeName in attributes;\n const actualValue = attributes[attributeName];\n\n if (expectedValue === undefined) {\n // Just check existence\n return {\n pass: hasAttribute,\n message: () =>\n hasAttribute\n ? `Expected response not to have JSON:API attribute \"${attributeName}\"`\n : `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found. Available attributes: ${Object.keys(attributes).join(\", \") || \"none\"}`,\n };\n }\n\n const valuesMatch = actualValue === expectedValue;\n return {\n pass: hasAttribute && valuesMatch,\n message: () =>\n hasAttribute && valuesMatch\n ? `Expected response not to have JSON:API attribute \"${attributeName}\" with value \"${expectedValue}\"`\n : !hasAttribute\n ? `Expected response to have JSON:API attribute \"${attributeName}\", but it was not found`\n : `Expected JSON:API attribute \"${attributeName}\" to be \"${expectedValue}\", but got \"${actualValue}\"`,\n };\n },\n\n /**\n * Asserts that the response data has the specified relationship.\n */\n toHaveJsonApiRelationship(received: JsonApiResponse, relationshipName: string) {\n const data = Array.isArray(received?.data) ? received.data[0] : received?.data;\n const relationships = data?.relationships ?? {};\n const hasRelationship = relationshipName in relationships;\n\n return {\n pass: hasRelationship,\n message: () =>\n hasRelationship\n ? `Expected response not to have JSON:API relationship \"${relationshipName}\"`\n : `Expected response to have JSON:API relationship \"${relationshipName}\", but it was not found. Available relationships: ${Object.keys(relationships).join(\", \") || \"none\"}`,\n };\n },\n\n /**\n * Asserts that the response data array has the expected length.\n */\n toHaveJsonApiLength(received: JsonApiResponse, expectedLength: number) {\n const data = received?.data;\n const isArray = Array.isArray(data);\n const actualLength = isArray ? data.length : data ? 1 : 0;\n const pass = actualLength === expectedLength;\n\n return {\n pass,\n message: () =>\n pass\n ? `Expected response not to have ${expectedLength} items`\n : `Expected response to have ${expectedLength} items, but got ${actualLength}`,\n };\n },\n};\n\n// Type declarations for the custom matchers\ndeclare module \"vitest\" {\n interface Assertion<T = any> {\n toBeValidJsonApi(): T;\n toHaveJsonApiType(expectedType: string): T;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): T;\n toHaveJsonApiRelationship(relationshipName: string): T;\n toHaveJsonApiLength(expectedLength: number): T;\n }\n interface AsymmetricMatchersContaining {\n toBeValidJsonApi(): any;\n toHaveJsonApiType(expectedType: string): any;\n toHaveJsonApiAttribute(attributeName: string, expectedValue?: any): any;\n toHaveJsonApiRelationship(relationshipName: string): any;\n toHaveJsonApiLength(expectedLength: number): any;\n }\n}\n\n/**\n * Extends Vitest's expect with JSON:API matchers.\n * Call this in your test setup file.\n *\n * @example\n * ```ts\n * // vitest.setup.ts\n * import { extendExpectWithJsonApiMatchers } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * extendExpectWithJsonApiMatchers();\n * ```\n */\nexport function extendExpectWithJsonApiMatchers(): void {\n expect.extend(jsonApiMatchers);\n}\n","\"use client\";\n\nimport React, { ReactElement } from \"react\";\nimport { render, RenderOptions, RenderResult } from \"@testing-library/react\";\nimport {\n MockJsonApiProvider,\n MockJsonApiProviderProps as _MockJsonApiProviderProps,\n} from \"../providers/MockJsonApiProvider\";\nimport { JsonApiConfig } from \"../../client/context/JsonApiContext\";\n\nexport interface RenderWithProvidersOptions extends Omit<RenderOptions, \"wrapper\"> {\n /**\n * Custom JSON:API configuration to pass to the mock provider.\n */\n jsonApiConfig?: Partial<JsonApiConfig>;\n\n /**\n * Additional wrapper component to wrap around the providers.\n */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Renders a component wrapped with all necessary providers for testing.\n *\n * @example\n * ```tsx\n * import { renderWithProviders } from '@carlonicora/nextjs-jsonapi/testing';\n *\n * const { getByText } = renderWithProviders(<MyComponent />);\n * expect(getByText('Hello')).toBeInTheDocument();\n * ```\n *\n * @example With custom config\n * ```tsx\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * jsonApiConfig: { apiUrl: 'https://custom.api.com' },\n * });\n * ```\n *\n * @example With additional wrapper\n * ```tsx\n * const CustomWrapper = ({ children }) => (\n * <ThemeProvider>{children}</ThemeProvider>\n * );\n *\n * const { getByText } = renderWithProviders(<MyComponent />, {\n * wrapper: CustomWrapper,\n * });\n * ```\n */\nexport function renderWithProviders(ui: ReactElement, options: RenderWithProvidersOptions = {}): RenderResult {\n const { jsonApiConfig, wrapper: AdditionalWrapper, ...renderOptions } = options;\n\n function AllProviders({ children }: { children: React.ReactNode }) {\n const content = <MockJsonApiProvider config={jsonApiConfig}>{children}</MockJsonApiProvider>;\n\n if (AdditionalWrapper) {\n return <AdditionalWrapper>{content}</AdditionalWrapper>;\n }\n\n return content;\n }\n\n return render(ui, { wrapper: AllProviders, ...renderOptions });\n}\n\n/**\n * Re-export render utilities from Testing Library for convenience.\n */\nexport { render, screen, waitFor, fireEvent, within } from \"@testing-library/react\";\nexport { userEvent } from \"@testing-library/user-event\";\n"],"mappings":"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","names":["render","jsx"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carlonicora/nextjs-jsonapi",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Next.js JSON:API client with server/client support and caching",
|
|
5
5
|
"author": "Carlo Nicora",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"build": "NODE_OPTIONS='--max-old-space-size=8192' tsup && tsc -p scripts/generate-web-module/tsconfig.json",
|
|
59
59
|
"dev": "tsup --watch",
|
|
60
60
|
"clean": "rm -rf dist",
|
|
61
|
-
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
61
|
+
"lint": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" --fix",
|
|
62
62
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
63
63
|
"prepublishOnly": "pnpm build",
|
|
64
64
|
"generate-web-module": "node dist/scripts/generate-web-module/index.js",
|
package/src/billing/index.ts
CHANGED
|
@@ -6,3 +6,4 @@ export * from "../features/billing/stripe-price/components";
|
|
|
6
6
|
export * from "../features/billing/stripe-product/components";
|
|
7
7
|
export * from "../features/billing/stripe-subscription/components";
|
|
8
8
|
export * from "../features/billing/stripe-usage/components";
|
|
9
|
+
export * from "../features/billing/stripe-promotion-code/components";
|
|
@@ -19,9 +19,5 @@ export function JsonApiProvider({ config, children }: JsonApiProviderProps) {
|
|
|
19
19
|
// Memoize config to prevent unnecessary re-renders
|
|
20
20
|
const memoizedConfig = useMemo(() => config, [config]);
|
|
21
21
|
|
|
22
|
-
return
|
|
23
|
-
<JsonApiContext.Provider value={memoizedConfig}>
|
|
24
|
-
{children}
|
|
25
|
-
</JsonApiContext.Provider>
|
|
26
|
-
);
|
|
22
|
+
return <JsonApiContext.Provider value={memoizedConfig}>{children}</JsonApiContext.Provider>;
|
|
27
23
|
}
|
|
@@ -36,7 +36,7 @@ describe("useJsonApiGet", () => {
|
|
|
36
36
|
classKey: mockModule,
|
|
37
37
|
endpoint: "/articles/1",
|
|
38
38
|
}),
|
|
39
|
-
{ wrapper }
|
|
39
|
+
{ wrapper },
|
|
40
40
|
);
|
|
41
41
|
|
|
42
42
|
expect(result.current.loading).toBe(true);
|
|
@@ -55,7 +55,7 @@ describe("useJsonApiGet", () => {
|
|
|
55
55
|
classKey: mockModule,
|
|
56
56
|
endpoint: "/articles/1",
|
|
57
57
|
}),
|
|
58
|
-
{ wrapper }
|
|
58
|
+
{ wrapper },
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
await waitFor(() => {
|
|
@@ -78,7 +78,7 @@ describe("useJsonApiGet", () => {
|
|
|
78
78
|
endpoint: "/articles/1",
|
|
79
79
|
options: { enabled: false },
|
|
80
80
|
}),
|
|
81
|
-
{ wrapper }
|
|
81
|
+
{ wrapper },
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
// Wait a bit to ensure no fetch happens
|
|
@@ -104,7 +104,7 @@ describe("useJsonApiGet", () => {
|
|
|
104
104
|
classKey: mockModule,
|
|
105
105
|
endpoint: "/articles/999",
|
|
106
106
|
}),
|
|
107
|
-
{ wrapper }
|
|
107
|
+
{ wrapper },
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
await waitFor(() => {
|
|
@@ -125,7 +125,7 @@ describe("useJsonApiGet", () => {
|
|
|
125
125
|
classKey: mockModule,
|
|
126
126
|
endpoint: "/articles/1",
|
|
127
127
|
}),
|
|
128
|
-
{ wrapper }
|
|
128
|
+
{ wrapper },
|
|
129
129
|
);
|
|
130
130
|
|
|
131
131
|
await waitFor(() => {
|
|
@@ -148,7 +148,7 @@ describe("useJsonApiGet", () => {
|
|
|
148
148
|
attributes: { title: `Article ${callCount}` },
|
|
149
149
|
}),
|
|
150
150
|
ok: true,
|
|
151
|
-
})
|
|
151
|
+
}),
|
|
152
152
|
);
|
|
153
153
|
});
|
|
154
154
|
|
|
@@ -158,7 +158,7 @@ describe("useJsonApiGet", () => {
|
|
|
158
158
|
classKey: mockModule,
|
|
159
159
|
endpoint: "/articles/1",
|
|
160
160
|
}),
|
|
161
|
-
{ wrapper }
|
|
161
|
+
{ wrapper },
|
|
162
162
|
);
|
|
163
163
|
|
|
164
164
|
await waitFor(() => {
|
|
@@ -191,7 +191,7 @@ describe("useJsonApiGet", () => {
|
|
|
191
191
|
classKey: mockModule,
|
|
192
192
|
endpoint: "/articles",
|
|
193
193
|
}),
|
|
194
|
-
{ wrapper }
|
|
194
|
+
{ wrapper },
|
|
195
195
|
);
|
|
196
196
|
|
|
197
197
|
await waitFor(() => {
|
|
@@ -216,7 +216,7 @@ describe("useJsonApiGet", () => {
|
|
|
216
216
|
classKey: mockModule,
|
|
217
217
|
endpoint: "/articles/1",
|
|
218
218
|
}),
|
|
219
|
-
{ wrapper }
|
|
219
|
+
{ wrapper },
|
|
220
220
|
);
|
|
221
221
|
|
|
222
222
|
await waitFor(() => {
|
|
@@ -41,7 +41,7 @@ describe("useJsonApiMutation", () => {
|
|
|
41
41
|
method: "POST",
|
|
42
42
|
classKey: mockModule,
|
|
43
43
|
}),
|
|
44
|
-
{ wrapper }
|
|
44
|
+
{ wrapper },
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
expect(result.current.loading).toBe(false);
|
|
@@ -61,7 +61,7 @@ describe("useJsonApiMutation", () => {
|
|
|
61
61
|
method: "POST",
|
|
62
62
|
classKey: mockModule,
|
|
63
63
|
}),
|
|
64
|
-
{ wrapper }
|
|
64
|
+
{ wrapper },
|
|
65
65
|
);
|
|
66
66
|
|
|
67
67
|
let mutationResult: any;
|
|
@@ -93,7 +93,7 @@ describe("useJsonApiMutation", () => {
|
|
|
93
93
|
method: "POST",
|
|
94
94
|
classKey: mockModule,
|
|
95
95
|
}),
|
|
96
|
-
{ wrapper }
|
|
96
|
+
{ wrapper },
|
|
97
97
|
);
|
|
98
98
|
|
|
99
99
|
let mutationResult: any;
|
|
@@ -122,7 +122,7 @@ describe("useJsonApiMutation", () => {
|
|
|
122
122
|
classKey: mockModule,
|
|
123
123
|
onSuccess,
|
|
124
124
|
}),
|
|
125
|
-
{ wrapper }
|
|
125
|
+
{ wrapper },
|
|
126
126
|
);
|
|
127
127
|
|
|
128
128
|
await act(async () => {
|
|
@@ -151,7 +151,7 @@ describe("useJsonApiMutation", () => {
|
|
|
151
151
|
classKey: mockModule,
|
|
152
152
|
onError,
|
|
153
153
|
}),
|
|
154
|
-
{ wrapper }
|
|
154
|
+
{ wrapper },
|
|
155
155
|
);
|
|
156
156
|
|
|
157
157
|
await act(async () => {
|
|
@@ -177,7 +177,7 @@ describe("useJsonApiMutation", () => {
|
|
|
177
177
|
method: "PUT",
|
|
178
178
|
classKey: mockModule,
|
|
179
179
|
}),
|
|
180
|
-
{ wrapper }
|
|
180
|
+
{ wrapper },
|
|
181
181
|
);
|
|
182
182
|
|
|
183
183
|
await act(async () => {
|
|
@@ -204,7 +204,7 @@ describe("useJsonApiMutation", () => {
|
|
|
204
204
|
method: "PATCH",
|
|
205
205
|
classKey: mockModule,
|
|
206
206
|
}),
|
|
207
|
-
{ wrapper }
|
|
207
|
+
{ wrapper },
|
|
208
208
|
);
|
|
209
209
|
|
|
210
210
|
await act(async () => {
|
|
@@ -231,7 +231,7 @@ describe("useJsonApiMutation", () => {
|
|
|
231
231
|
method: "DELETE",
|
|
232
232
|
classKey: mockModule,
|
|
233
233
|
}),
|
|
234
|
-
{ wrapper }
|
|
234
|
+
{ wrapper },
|
|
235
235
|
);
|
|
236
236
|
|
|
237
237
|
await act(async () => {
|
|
@@ -256,7 +256,7 @@ describe("useJsonApiMutation", () => {
|
|
|
256
256
|
method: "POST",
|
|
257
257
|
classKey: mockModule,
|
|
258
258
|
}),
|
|
259
|
-
{ wrapper }
|
|
259
|
+
{ wrapper },
|
|
260
260
|
);
|
|
261
261
|
|
|
262
262
|
await act(async () => {
|
|
@@ -294,7 +294,7 @@ describe("useJsonApiMutation", () => {
|
|
|
294
294
|
method: "POST",
|
|
295
295
|
classKey: mockModule,
|
|
296
296
|
}),
|
|
297
|
-
{ wrapper }
|
|
297
|
+
{ wrapper },
|
|
298
298
|
);
|
|
299
299
|
|
|
300
300
|
// Start mutation without awaiting
|
|
@@ -331,7 +331,7 @@ describe("useJsonApiMutation", () => {
|
|
|
331
331
|
method: "POST",
|
|
332
332
|
classKey: mockModule,
|
|
333
333
|
}),
|
|
334
|
-
{ wrapper }
|
|
334
|
+
{ wrapper },
|
|
335
335
|
);
|
|
336
336
|
|
|
337
337
|
await act(async () => {
|
|
@@ -56,26 +56,20 @@ describe("useRehydration", () => {
|
|
|
56
56
|
included: [],
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
const { result } = renderHook(() =>
|
|
60
|
-
useRehydration<MockArticle>(mockModule as any, hydratedData)
|
|
61
|
-
);
|
|
59
|
+
const { result } = renderHook(() => useRehydration<MockArticle>(mockModule as any, hydratedData));
|
|
62
60
|
|
|
63
61
|
expect(result.current).toBeInstanceOf(MockArticle);
|
|
64
62
|
expect(result.current?.rehydratedData).toBe(hydratedData);
|
|
65
63
|
});
|
|
66
64
|
|
|
67
65
|
it("should return null for null data", () => {
|
|
68
|
-
const { result } = renderHook(() =>
|
|
69
|
-
useRehydration<MockArticle>(mockModule as any, null)
|
|
70
|
-
);
|
|
66
|
+
const { result } = renderHook(() => useRehydration<MockArticle>(mockModule as any, null));
|
|
71
67
|
|
|
72
68
|
expect(result.current).toBeNull();
|
|
73
69
|
});
|
|
74
70
|
|
|
75
71
|
it("should return null for undefined data", () => {
|
|
76
|
-
const { result } = renderHook(() =>
|
|
77
|
-
useRehydration<MockArticle>(mockModule as any, undefined)
|
|
78
|
-
);
|
|
72
|
+
const { result } = renderHook(() => useRehydration<MockArticle>(mockModule as any, undefined));
|
|
79
73
|
|
|
80
74
|
expect(result.current).toBeNull();
|
|
81
75
|
});
|
|
@@ -86,9 +80,7 @@ describe("useRehydration", () => {
|
|
|
86
80
|
included: [],
|
|
87
81
|
};
|
|
88
82
|
|
|
89
|
-
const { result, rerender } = renderHook(() =>
|
|
90
|
-
useRehydration<MockArticle>(mockModule as any, hydratedData)
|
|
91
|
-
);
|
|
83
|
+
const { result, rerender } = renderHook(() => useRehydration<MockArticle>(mockModule as any, hydratedData));
|
|
92
84
|
|
|
93
85
|
const firstResult = result.current;
|
|
94
86
|
rerender();
|
|
@@ -108,10 +100,9 @@ describe("useRehydration", () => {
|
|
|
108
100
|
included: [],
|
|
109
101
|
};
|
|
110
102
|
|
|
111
|
-
const { result, rerender } = renderHook(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
103
|
+
const { result, rerender } = renderHook(({ data }) => useRehydration<MockArticle>(mockModule as any, data), {
|
|
104
|
+
initialProps: { data: hydratedData1 },
|
|
105
|
+
});
|
|
115
106
|
|
|
116
107
|
const firstResult = result.current;
|
|
117
108
|
rerender({ data: hydratedData2 });
|
|
@@ -135,9 +126,7 @@ describe("useRehydrationList", () => {
|
|
|
135
126
|
{ jsonApi: { type: "articles", id: "3" }, included: [] },
|
|
136
127
|
];
|
|
137
128
|
|
|
138
|
-
const { result } = renderHook(() =>
|
|
139
|
-
useRehydrationList<MockArticle>(mockModule as any, hydratedDataList)
|
|
140
|
-
);
|
|
129
|
+
const { result } = renderHook(() => useRehydrationList<MockArticle>(mockModule as any, hydratedDataList));
|
|
141
130
|
|
|
142
131
|
expect(result.current).toHaveLength(3);
|
|
143
132
|
result.current.forEach((item, index) => {
|
|
@@ -147,37 +136,27 @@ describe("useRehydrationList", () => {
|
|
|
147
136
|
});
|
|
148
137
|
|
|
149
138
|
it("should return empty array for null data", () => {
|
|
150
|
-
const { result } = renderHook(() =>
|
|
151
|
-
useRehydrationList<MockArticle>(mockModule as any, null)
|
|
152
|
-
);
|
|
139
|
+
const { result } = renderHook(() => useRehydrationList<MockArticle>(mockModule as any, null));
|
|
153
140
|
|
|
154
141
|
expect(result.current).toEqual([]);
|
|
155
142
|
});
|
|
156
143
|
|
|
157
144
|
it("should return empty array for undefined data", () => {
|
|
158
|
-
const { result } = renderHook(() =>
|
|
159
|
-
useRehydrationList<MockArticle>(mockModule as any, undefined)
|
|
160
|
-
);
|
|
145
|
+
const { result } = renderHook(() => useRehydrationList<MockArticle>(mockModule as any, undefined));
|
|
161
146
|
|
|
162
147
|
expect(result.current).toEqual([]);
|
|
163
148
|
});
|
|
164
149
|
|
|
165
150
|
it("should return empty array for empty array input", () => {
|
|
166
|
-
const { result } = renderHook(() =>
|
|
167
|
-
useRehydrationList<MockArticle>(mockModule as any, [])
|
|
168
|
-
);
|
|
151
|
+
const { result } = renderHook(() => useRehydrationList<MockArticle>(mockModule as any, []));
|
|
169
152
|
|
|
170
153
|
expect(result.current).toEqual([]);
|
|
171
154
|
});
|
|
172
155
|
|
|
173
156
|
it("should memoize result for same data", () => {
|
|
174
|
-
const hydratedDataList: JsonApiHydratedDataInterface[] = [
|
|
175
|
-
{ jsonApi: { type: "articles", id: "1" }, included: [] },
|
|
176
|
-
];
|
|
157
|
+
const hydratedDataList: JsonApiHydratedDataInterface[] = [{ jsonApi: { type: "articles", id: "1" }, included: [] }];
|
|
177
158
|
|
|
178
|
-
const { result, rerender } = renderHook(() =>
|
|
179
|
-
useRehydrationList<MockArticle>(mockModule as any, hydratedDataList)
|
|
180
|
-
);
|
|
159
|
+
const { result, rerender } = renderHook(() => useRehydrationList<MockArticle>(mockModule as any, hydratedDataList));
|
|
181
160
|
|
|
182
161
|
const firstResult = result.current;
|
|
183
162
|
rerender();
|
|
@@ -211,7 +211,7 @@ export default function BlockNoteEditor({
|
|
|
211
211
|
rejectedChanges,
|
|
212
212
|
);
|
|
213
213
|
return removeTrailingEmptyBlocks(renderedDiff);
|
|
214
|
-
} catch (
|
|
214
|
+
} catch (_error) {
|
|
215
215
|
return initialContent && Array.isArray(initialContent) && initialContent.length > 0
|
|
216
216
|
? removeTrailingEmptyBlocks(initialContent)
|
|
217
217
|
: [];
|
|
@@ -360,7 +360,7 @@ export default function BlockNoteEditor({
|
|
|
360
360
|
}, [processedContent, editor]);
|
|
361
361
|
|
|
362
362
|
// Handle audio received from whisper transcription
|
|
363
|
-
const
|
|
363
|
+
const _handleAudioReceived = useCallback(
|
|
364
364
|
(message: string) => {
|
|
365
365
|
try {
|
|
366
366
|
// Ensure the editor has focus
|
|
@@ -7,7 +7,7 @@ import { Button, DialogTrigger } from "../../shadcnui";
|
|
|
7
7
|
|
|
8
8
|
type CommonEditorTriggerProps = { isEdit: boolean; edit?: string; create?: string };
|
|
9
9
|
|
|
10
|
-
export function CommonEditorTrigger({ isEdit, edit, create }: CommonEditorTriggerProps) {
|
|
10
|
+
export function CommonEditorTrigger({ isEdit, edit: _edit, create }: CommonEditorTriggerProps) {
|
|
11
11
|
const t = useTranslations();
|
|
12
12
|
|
|
13
13
|
return (
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
Checkbox,
|
|
5
|
-
FieldLabel,
|
|
6
|
-
Tooltip,
|
|
7
|
-
TooltipContent,
|
|
8
|
-
TooltipTrigger,
|
|
9
|
-
} from "../../shadcnui";
|
|
3
|
+
import { Checkbox, FieldLabel, Tooltip, TooltipContent, TooltipTrigger } from "../../shadcnui";
|
|
10
4
|
import { FormFieldWrapper } from "./FormFieldWrapper";
|
|
11
5
|
|
|
12
6
|
type FormCheckboxProps = {
|
|
@@ -40,11 +34,7 @@ export function FormCheckbox({ form, id, name, labelBefore, description, isRequi
|
|
|
40
34
|
|
|
41
35
|
return (
|
|
42
36
|
<div className="flex w-full flex-col">
|
|
43
|
-
<FormFieldWrapper
|
|
44
|
-
form={form}
|
|
45
|
-
name={id}
|
|
46
|
-
orientation="horizontal"
|
|
47
|
-
>
|
|
37
|
+
<FormFieldWrapper form={form} name={id} orientation="horizontal">
|
|
48
38
|
{(field) => (
|
|
49
39
|
<div className="flex gap-x-4">
|
|
50
40
|
{labelBefore && label()}
|
|
@@ -129,12 +129,7 @@ export function FormDate({
|
|
|
129
129
|
|
|
130
130
|
return (
|
|
131
131
|
<div className="flex w-full flex-col">
|
|
132
|
-
<FormFieldWrapper
|
|
133
|
-
form={form}
|
|
134
|
-
name={id}
|
|
135
|
-
label={name}
|
|
136
|
-
isRequired={isRequired}
|
|
137
|
-
>
|
|
132
|
+
<FormFieldWrapper form={form} name={id} label={name} isRequired={isRequired}>
|
|
138
133
|
{(field) => (
|
|
139
134
|
<Popover open={open} onOpenChange={setOpen} modal={true}>
|
|
140
135
|
<InputGroup>
|
|
@@ -24,13 +24,7 @@ export function FormPassword({
|
|
|
24
24
|
}) {
|
|
25
25
|
return (
|
|
26
26
|
<div className="flex w-full flex-col">
|
|
27
|
-
<FormFieldWrapper
|
|
28
|
-
form={form}
|
|
29
|
-
name={id}
|
|
30
|
-
label={name}
|
|
31
|
-
isRequired={isRequired}
|
|
32
|
-
testId={testId}
|
|
33
|
-
>
|
|
27
|
+
<FormFieldWrapper form={form} name={id} label={name} isRequired={isRequired} testId={testId}>
|
|
34
28
|
{(field) => (
|
|
35
29
|
<PasswordInput
|
|
36
30
|
{...field}
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
Select,
|
|
5
|
-
SelectContent,
|
|
6
|
-
SelectItem,
|
|
7
|
-
SelectTrigger,
|
|
8
|
-
SelectValue,
|
|
9
|
-
} from "../../shadcnui";
|
|
3
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../shadcnui";
|
|
10
4
|
import { FormFieldWrapper } from "./FormFieldWrapper";
|
|
11
5
|
|
|
12
6
|
export function FormSelect({
|
|
13
7
|
form,
|
|
14
8
|
id,
|
|
15
9
|
name,
|
|
16
|
-
placeholder,
|
|
10
|
+
placeholder: _placeholder,
|
|
17
11
|
disabled,
|
|
18
12
|
values,
|
|
19
13
|
onChange,
|
|
@@ -22,11 +22,7 @@ export function FormSlider({
|
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<div className="flex w-full flex-col">
|
|
25
|
-
<FormFieldWrapper
|
|
26
|
-
form={form}
|
|
27
|
-
name={id}
|
|
28
|
-
label={name}
|
|
29
|
-
>
|
|
25
|
+
<FormFieldWrapper form={form} name={id} label={name}>
|
|
30
26
|
{() => (
|
|
31
27
|
<div>
|
|
32
28
|
{showPercentage && (
|
|
@@ -6,11 +6,7 @@ import { FormFieldWrapper } from "./FormFieldWrapper";
|
|
|
6
6
|
export function FormSwitch({ form, id, name, disabled }: { form: any; id: string; name?: string; disabled?: boolean }) {
|
|
7
7
|
return (
|
|
8
8
|
<div className="flex w-full flex-col">
|
|
9
|
-
<FormFieldWrapper
|
|
10
|
-
form={form}
|
|
11
|
-
name={id}
|
|
12
|
-
orientation="horizontal"
|
|
13
|
-
>
|
|
9
|
+
<FormFieldWrapper form={form} name={id} orientation="horizontal">
|
|
14
10
|
{(field) => (
|
|
15
11
|
<div className="flex flex-row gap-x-4">
|
|
16
12
|
<Switch checked={field.value} onCheckedChange={field.onChange} disabled={disabled} />
|
|
@@ -24,19 +24,13 @@ export function GdprConsentCheckbox<T extends FieldValues>({
|
|
|
24
24
|
<FormFieldWrapper form={form} name={id} orientation="horizontal">
|
|
25
25
|
{(field) => (
|
|
26
26
|
<div className="flex flex-row items-start space-x-3 space-y-0">
|
|
27
|
-
<Checkbox
|
|
28
|
-
checked={field.value}
|
|
29
|
-
onCheckedChange={field.onChange}
|
|
30
|
-
aria-required={required}
|
|
31
|
-
/>
|
|
27
|
+
<Checkbox checked={field.value} onCheckedChange={field.onChange} aria-required={required} />
|
|
32
28
|
<div className="space-y-1 leading-none">
|
|
33
29
|
<span className="text-sm font-normal">
|
|
34
30
|
{label}
|
|
35
31
|
{required && <span className="text-destructive ml-1">*</span>}
|
|
36
32
|
</span>
|
|
37
|
-
{description &&
|
|
38
|
-
<FieldDescription className="text-xs">{description}</FieldDescription>
|
|
39
|
-
)}
|
|
33
|
+
{description && <FieldDescription className="text-xs">{description}</FieldDescription>}
|
|
40
34
|
</div>
|
|
41
35
|
</div>
|
|
42
36
|
)}
|