diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/lesson-content-renderer.test.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/lesson-content-renderer.test.tsx
new file mode 100644
index 000000000..2a5a2edf2
--- /dev/null
+++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/lesson-content-renderer.test.tsx
@@ -0,0 +1,394 @@
+import React from "react";
+import { render, screen, fireEvent, waitFor } from "@testing-library/react";
+import { LessonContentRenderer } from "../lesson-content-renderer";
+import { Constants } from "@courselit/common-models";
+import { AddressContext, ProfileContext } from "@components/contexts";
+import "@testing-library/jest-dom";
+
+// Mock dependencies
+jest.mock("@courselit/text-editor", () => {
+ const React = jest.requireActual("react");
+ return {
+ Editor: ({ onChange, initialContent }: any) =>
+ React.createElement(
+ "div",
+ { "data-testid": "text-editor" },
+ React.createElement("textarea", {
+ "data-testid": "text-editor-input",
+ onChange: (e: any) =>
+ onChange({ type: "doc", content: e.target.value }),
+ value: initialContent?.content || "",
+ }),
+ ),
+ emptyDoc: { type: "doc", content: [] },
+ };
+});
+
+jest.mock("@courselit/icons", () => {
+ const React = jest.requireActual("react");
+ return {
+ ExpandLess: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-expand-less" },
+ "ExpandLess",
+ ),
+ ExpandMore: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-expand-more" },
+ "ExpandMore",
+ ),
+ };
+});
+
+jest.mock("@ui-config/strings", () => ({
+ LESSON_QUIZ_ADD_QUESTION: "Add Question",
+ LESSON_QUIZ_QUESTION_PLACEHOLDER: "Question Placeholder",
+ LESSON_QUIZ_ADD_OPTION_BTN: "Add Option",
+ LESSON_QUIZ_CONTENT_HEADER: "Question",
+ LESSON_QUIZ_OPTION_PLACEHOLDER: "Option Placeholder",
+ QUESTION_BUILDER_COLLAPSE_TOOLTIP: "Collapse",
+ QUESTION_BUILDER_CORRECT_ANS_TOOLTIP: "Correct Answer",
+ QUESTION_BUILDER_DELETE_TOOLTIP: "Delete",
+ QUESTION_BUILDER_EXPAND_TOOLTIP: "Expand",
+}));
+
+jest.mock("@components/ui/button", () => {
+ const React = jest.requireActual("react");
+ return {
+ Button: ({ onClick, children }: any) =>
+ React.createElement(
+ "button",
+ { onClick, "data-testid": "button" },
+ children,
+ ),
+ };
+});
+
+jest.mock("@components/ui/label", () => {
+ const React = jest.requireActual("react");
+ return {
+ Label: ({ children }: any) =>
+ React.createElement("label", {}, children),
+ };
+});
+
+jest.mock("@components/ui/switch", () => {
+ const React = jest.requireActual("react");
+ return {
+ Switch: ({ checked, onCheckedChange }: any) =>
+ React.createElement("input", {
+ type: "checkbox",
+ checked,
+ onChange: (e: any) => onCheckedChange(e.target.checked),
+ "data-testid": "switch",
+ }),
+ };
+});
+
+jest.mock("@components/ui/input", () => {
+ const React = jest.requireActual("react");
+ return {
+ Input: (props: any) =>
+ React.createElement("input", { ...props, "data-testid": "input" }),
+ };
+});
+
+jest.mock("lucide-react", () => {
+ const React = jest.requireActual("react");
+ return {
+ Trash: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-trash" },
+ "Trash",
+ ),
+ };
+});
+
+jest.mock("@courselit/components-library", () => {
+ const React = jest.requireActual("react");
+ return {
+ MediaSelector: ({ onSelection, onRemove }: any) =>
+ React.createElement(
+ "div",
+ { "data-testid": "media-selector" },
+ React.createElement(
+ "button",
+ {
+ onClick: () =>
+ onSelection({
+ originalFileName: "test.mp4",
+ mediaId: "123",
+ }),
+ },
+ "Select Media",
+ ),
+ React.createElement(
+ "button",
+ { onClick: onRemove },
+ "Remove Media",
+ ),
+ ),
+ useToast: () => ({
+ toast: jest.fn(),
+ }),
+ Section: ({ children }: any) =>
+ React.createElement("div", { "data-testid": "section" }, children),
+ Checkbox: ({ checked, onChange }: any) =>
+ React.createElement("input", {
+ type: "checkbox",
+ checked,
+ onChange: (e: any) => onChange(e.target.checked),
+ "data-testid": "checkbox",
+ }),
+ IconButton: ({ onClick, children }: any) =>
+ React.createElement(
+ "button",
+ { onClick, "data-testid": "icon-button" },
+ children,
+ ),
+ Tooltip: ({ children, title }: any) =>
+ React.createElement(
+ "div",
+ { title, "data-testid": "tooltip" },
+ children,
+ ),
+ };
+});
+
+jest.mock("@components/public/lesson-viewer/embed-viewer", () => {
+ const React = jest.requireActual("react");
+ return {
+ __esModule: true,
+ default: ({ content }: any) =>
+ React.createElement(
+ "div",
+ { "data-testid": "embed-viewer" },
+ content.value,
+ ),
+ };
+});
+
+jest.mock("@courselit/utils", () => ({
+ FetchBuilder: jest.fn().mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: jest.fn().mockResolvedValue({}),
+ })),
+}));
+
+describe("LessonContentRenderer", () => {
+ const mockOnContentChange = jest.fn();
+ const mockOnLessonChange = jest.fn();
+ const defaultProps = {
+ lesson: {},
+ errors: {},
+ onContentChange: mockOnContentChange,
+ onLessonChange: mockOnLessonChange,
+ };
+
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
+
+
+ {children}
+
+
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it("renders text editor for TEXT lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByTestId("text-editor")).toBeInTheDocument();
+ });
+
+ it("renders embed viewer for EMBED lesson type", async () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(
+ screen.getByPlaceholderText(/e.g. YouTube video URL/i),
+ ).toBeInTheDocument();
+ await waitFor(() => {
+ expect(screen.getByTestId("embed-viewer")).toBeInTheDocument();
+ });
+ });
+
+ it("renders quiz builder for QUIZ lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByText("Add Question")).toBeInTheDocument();
+ });
+
+ it("renders media selector for VIDEO lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByTestId("media-selector")).toBeInTheDocument();
+ });
+
+ it("renders media selector for AUDIO lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByTestId("media-selector")).toBeInTheDocument();
+ });
+
+ it("renders media selector for PDF lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByTestId("media-selector")).toBeInTheDocument();
+ });
+
+ it("renders media selector for FILE lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ expect(screen.getByTestId("media-selector")).toBeInTheDocument();
+ });
+
+ it("handles content change in text editor", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ const input = screen.getByTestId("text-editor-input");
+ fireEvent.change(input, { target: { value: "New content" } });
+
+ expect(mockOnContentChange).toHaveBeenCalledWith({
+ type: "doc",
+ content: "New content",
+ });
+ });
+
+ it("handles content change in embed url", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ const input = screen.getByPlaceholderText(/e.g. YouTube video URL/i);
+ fireEvent.change(input, { target: { value: "https://new-url.com" } });
+
+ // The useEffect in the component triggers the change
+ expect(mockOnContentChange).toHaveBeenCalledWith({
+ value: "https://new-url.com",
+ });
+ });
+
+ it("renders quiz builder for QUIZ lesson type", () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ // Verify QuizBuilder is rendered (it contains "Add Question" button)
+ expect(screen.getByText("Add Question")).toBeInTheDocument();
+ });
+
+ it("handles media selection", async () => {
+ render(
+ ,
+ { wrapper },
+ );
+
+ fireEvent.click(screen.getByText("Select Media"));
+
+ expect(mockOnLessonChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ media: expect.objectContaining({
+ originalFileName: "test.mp4",
+ }),
+ }),
+ );
+ });
+});
diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/page.test.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/page.test.tsx
new file mode 100644
index 000000000..6c5be8105
--- /dev/null
+++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/__tests__/page.test.tsx
@@ -0,0 +1,941 @@
+import React from "react";
+import { render, screen, fireEvent, waitFor } from "@testing-library/react";
+import LessonPage from "../page";
+import { Constants } from "@courselit/common-models";
+import { AddressContext } from "@components/contexts";
+import { FetchBuilder } from "@courselit/utils";
+import "@testing-library/jest-dom";
+
+// Mock dependencies
+// Module-level variable to control lesson ID for edit mode
+let mockLessonId: string | null = null;
+
+jest.mock("next/navigation", () => ({
+ useRouter: () => ({
+ push: jest.fn(),
+ replace: jest.fn(),
+ }),
+ useParams: () => ({
+ id: "product-1",
+ section: "section-1",
+ }),
+ useSearchParams: () => ({
+ get: (key: string) => {
+ if (key === "id") return mockLessonId;
+ return null;
+ },
+ }),
+}));
+
+jest.mock("next/link", () => {
+ return ({ children }: { children: React.ReactNode }) => {
+ return children;
+ };
+});
+
+const mockProduct = {
+ title: "Test Course",
+ type: "course",
+};
+
+jest.mock("@/hooks/use-product", () => ({
+ __esModule: true,
+ default: () => ({
+ product: mockProduct,
+ loaded: true,
+ }),
+}));
+
+jest.mock("@courselit/utils", () => ({
+ FetchBuilder: jest.fn().mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: jest.fn().mockResolvedValue({}),
+ })),
+}));
+
+jest.mock("@courselit/text-editor", () => ({
+ emptyDoc: { type: "doc", content: [] },
+}));
+
+jest.mock("@courselit/components-library", () => ({
+ useToast: () => ({
+ toast: jest.fn(),
+ }),
+}));
+
+jest.mock("../lesson-content-renderer", () => ({
+ LessonContentRenderer: ({ errors, onContentChange }: any) => (
+
{
+ if (radioGroupState.onValueChange) {
+ radioGroupState.onValueChange(value);
+ }
+ }}
+ {...props}
+ />
+ ),
+ };
+});
+
+jest.mock("@components/ui/dialog", () => ({
+ Dialog: ({ children, open }: any) =>
+ open ?
{children}
: null,
+ DialogContent: ({ children }: any) =>
{children}
,
+ DialogHeader: ({ children }: any) =>
{children}
,
+ DialogTitle: ({ children }: any) =>
{children}
,
+ DialogDescription: ({ children }: any) =>
{children}
,
+ DialogFooter: ({ children }: any) =>
{children}
,
+ DialogTrigger: ({ children }: any) =>
{children}
,
+}));
+
+jest.mock("@components/admin/dashboard-content", () => ({
+ __esModule: true,
+ default: ({ children }: any) =>
{children}
,
+}));
+
+jest.mock("../skeleton", () => ({
+ LessonSkeleton: () =>
Loading...
,
+}));
+
+jest.mock("@ui-lib/utils", () => ({
+ isTextEditorNonEmpty: (content: any) => {
+ // For TEXT type, content is a TextEditorContent object with type: "doc" and content: []
+ // It's empty if content array is empty or only contains empty paragraphs
+ if (content?.type === "doc") {
+ return (
+ content.content &&
+ content.content.length > 0 &&
+ content.content.some(
+ (node: any) => node.content && node.content.length > 0,
+ )
+ );
+ }
+ // For other types, check if value exists
+ return !!content && content.value !== "";
+ },
+ truncate: (str: string) => str,
+}));
+
+describe("LessonPage", () => {
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
+
+ {children}
+
+ );
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockLessonId = null; // Reset to create mode
+ });
+
+ it("renders new lesson form", () => {
+ render(
, { wrapper });
+
+ expect(screen.getByText("New Lesson")).toBeInTheDocument();
+ expect(
+ screen.getByPlaceholderText("Enter lesson title"),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByTestId("lesson-content-renderer"),
+ ).toBeInTheDocument();
+ });
+
+ it("shows validation error for empty title", async () => {
+ render(
, { wrapper });
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(
+ screen.getByText("Please enter a lesson title."),
+ ).toBeInTheDocument();
+ });
+ });
+
+ it("shows validation error for empty content (TEXT)", async () => {
+ render(
, { wrapper });
+
+ // Set title to avoid title error
+ const titleInput = screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, { target: { value: "Test Lesson" } });
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(screen.getByTestId("content-error")).toHaveTextContent(
+ "Please enter the lesson content.",
+ );
+ });
+ });
+
+ it("shows validation error for empty URL (EMBED)", async () => {
+ render(
, { wrapper });
+
+ // Set title
+ const titleInput = screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, { target: { value: "Test Lesson" } });
+
+ // Switch to Embed type
+ const embedRadio = screen.getByTestId(
+ `radio-item-${Constants.LessonType.EMBED}`,
+ );
+ fireEvent.click(embedRadio);
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(screen.getByTestId("content-error")).toHaveTextContent(
+ "Please enter a YouTube video ID.",
+ );
+ });
+ });
+
+ it("shows validation error for QUIZ (no questions)", async () => {
+ render(
, { wrapper });
+
+ // Set title
+ const titleInput = screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, { target: { value: "Test Lesson" } });
+
+ // Switch to Quiz type
+ const quizRadio = screen.getByTestId(
+ `radio-item-${Constants.LessonType.QUIZ}`,
+ );
+ fireEvent.click(quizRadio);
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(screen.getByTestId("content-error")).toHaveTextContent(
+ "Please add at least one question to the quiz.",
+ );
+ });
+ });
+
+ it("creates a new lesson successfully", async () => {
+ const mockExec = jest.fn().mockResolvedValue({
+ lesson: { lessonId: "new-lesson-id" },
+ });
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ const titleInput = screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, { target: { value: "New Lesson" } });
+
+ // Simulate content change to pass validation
+ const updateContentButton = screen.getByText("Update Content");
+ fireEvent.click(updateContentButton);
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalled();
+ });
+ });
+
+ it("handles API error during save", async () => {
+ const mockExec = jest.fn().mockRejectedValue(new Error("API Error"));
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ const titleInput = screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, { target: { value: "New Lesson" } });
+
+ // Simulate content change to pass validation
+ const updateContentButton = screen.getByText("Update Content");
+ fireEvent.click(updateContentButton);
+
+ const saveButton = screen.getByText("Save Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalled();
+ });
+ });
+
+ describe("Editing existing lessons", () => {
+ it("loads and edits a TEXT lesson successfully", async () => {
+ mockLessonId = "lesson-123";
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-123",
+ title: "Existing TEXT Lesson",
+ type: "TEXT",
+ content: {
+ type: "doc",
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ {
+ type: "text",
+ text: "Existing content",
+ },
+ ],
+ },
+ ],
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-123" },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("Existing TEXT Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Edit the title
+ const titleInput =
+ screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, {
+ target: { value: "Updated TEXT Lesson" },
+ });
+
+ // Save
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalledTimes(2); // Once for load, once for update
+ });
+ });
+
+ it("loads and edits an EMBED lesson successfully", async () => {
+ mockLessonId = "lesson-456";
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-456",
+ title: "Existing EMBED Lesson",
+ type: "EMBED",
+ content: {
+ value: "https://youtube.com/watch?v=abc123",
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-456" },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("Existing EMBED Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Edit the title
+ const titleInput =
+ screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, {
+ target: { value: "Updated EMBED Lesson" },
+ });
+
+ // Save
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ it("loads and edits a QUIZ lesson successfully", async () => {
+ mockLessonId = "lesson-789";
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-789",
+ title: "Existing QUIZ Lesson",
+ type: "QUIZ",
+ content: {
+ questions: [
+ {
+ text: "What is 2+2?",
+ options: [
+ { text: "3", correctAnswer: false },
+ { text: "4", correctAnswer: true },
+ ],
+ },
+ ],
+ requiresPassingGrade: false,
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-789" },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("Existing QUIZ Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Edit the title
+ const titleInput =
+ screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, {
+ target: { value: "Updated QUIZ Lesson" },
+ });
+
+ // Save
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ it("shows validation error when editing TEXT lesson with empty content", async () => {
+ mockLessonId = "lesson-text-empty";
+ const mockExec = jest.fn().mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-text-empty",
+ title: "TEXT Lesson",
+ type: "TEXT",
+ content: { type: "doc", content: [] }, // Empty content
+ requiresEnrollment: true,
+ },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("TEXT Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Try to save without adding content
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ // Should show validation error
+ await waitFor(() => {
+ expect(screen.getByTestId("content-error")).toHaveTextContent(
+ "Please enter the lesson content.",
+ );
+ });
+ });
+
+ it("shows validation error when editing EMBED lesson with empty URL", async () => {
+ mockLessonId = "lesson-embed-empty";
+ const mockExec = jest.fn().mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-embed-empty",
+ title: "EMBED Lesson",
+ type: "EMBED",
+ content: { value: "" }, // Empty URL
+ requiresEnrollment: true,
+ },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("EMBED Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Try to save without adding URL
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ // Should show validation error
+ await waitFor(() => {
+ expect(screen.getByTestId("content-error")).toHaveTextContent(
+ "Please enter a YouTube video ID.",
+ );
+ });
+ });
+
+ it("prevents changing lesson type when editing", async () => {
+ mockLessonId = "lesson-type-lock";
+ const mockExec = jest.fn().mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-type-lock",
+ title: "Locked Type Lesson",
+ type: "TEXT",
+ content: {
+ type: "doc",
+ content: [
+ {
+ type: "paragraph",
+ content: [{ type: "text", text: "Content" }],
+ },
+ ],
+ },
+ requiresEnrollment: true,
+ },
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("Locked Type Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Try to click on QUIZ radio button (should be disabled)
+ const quizRadio = screen.getByTestId(
+ `radio-item-${Constants.LessonType.QUIZ}`,
+ );
+
+ // The radio button should be disabled or not change the type
+ // Since our mock doesn't handle disabled state, we just verify the lesson type doesn't change
+ fireEvent.click(quizRadio);
+
+ // The lesson type should still be TEXT (not changed to QUIZ)
+ // We can verify this by checking that the TEXT content renderer is still shown
+ expect(
+ screen.getByTestId("lesson-content-renderer"),
+ ).toBeInTheDocument();
+ });
+
+ it("handles API error when loading lesson", async () => {
+ mockLessonId = "lesson-error";
+ const mockExec = jest
+ .fn()
+ .mockRejectedValue(new Error("Failed to load lesson"));
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for error handling
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalled();
+ });
+
+ // The form should still render (with empty/default state)
+ expect(
+ screen.getByPlaceholderText("Enter lesson title"),
+ ).toBeInTheDocument();
+ });
+
+ it("handles API error when updating lesson", async () => {
+ mockLessonId = "lesson-update-error";
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-update-error",
+ title: "Lesson to Update",
+ type: "TEXT",
+ content: {
+ type: "doc",
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ { type: "text", text: "Content" },
+ ],
+ },
+ ],
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockRejectedValueOnce(new Error("Failed to update lesson"));
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: jest.fn().mockReturnThis(),
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("Lesson to Update"),
+ ).toBeInTheDocument();
+ });
+
+ // Edit and try to save
+ const titleInput =
+ screen.getByPlaceholderText("Enter lesson title");
+ fireEvent.change(titleInput, {
+ target: { value: "Updated Title" },
+ });
+
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ // Wait for error handling
+ await waitFor(() => {
+ expect(mockExec).toHaveBeenCalledTimes(2); // Load + failed update
+ });
+ });
+
+ it("sends correct payload when updating TEXT lesson content", async () => {
+ mockLessonId = "lesson-text-payload";
+ let capturedPayload: any = null;
+
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-text-payload",
+ title: "TEXT Lesson",
+ type: "TEXT",
+ content: {
+ type: "doc",
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ {
+ type: "text",
+ text: "Original content",
+ },
+ ],
+ },
+ ],
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-text-payload" },
+ });
+
+ const mockSetPayload = jest.fn((payload) => {
+ capturedPayload = payload;
+ return {
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ };
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: mockSetPayload,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("TEXT Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Update content by clicking the mock button
+ const updateContentButton = screen.getByText("Update Content");
+ fireEvent.click(updateContentButton);
+
+ // Save
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ // Verify the mutation payload
+ await waitFor(() => {
+ expect(capturedPayload).toBeDefined();
+ expect(capturedPayload.variables.lessonData.content).toBe(
+ JSON.stringify({ value: "New Content" }),
+ );
+ });
+ });
+
+ it("sends correct payload when updating EMBED lesson URL", async () => {
+ mockLessonId = "lesson-embed-payload";
+ let capturedPayload: any = null;
+
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-embed-payload",
+ title: "EMBED Lesson",
+ type: "EMBED",
+ content: { value: "https://old-url.com" },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-embed-payload" },
+ });
+
+ const mockSetPayload = jest.fn((payload) => {
+ capturedPayload = payload;
+ return {
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ };
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: mockSetPayload,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("EMBED Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Update content by clicking the mock button
+ const updateContentButton = screen.getByText("Update Content");
+ fireEvent.click(updateContentButton);
+
+ // Save
+ const saveButton2 = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton2);
+
+ // Verify the mutation payload contains the new URL
+ await waitFor(() => {
+ expect(capturedPayload).toBeDefined();
+ const content = JSON.parse(
+ capturedPayload.variables.lessonData.content,
+ );
+ expect(content.value).toBe("New Content");
+ });
+ });
+
+ it("sends correct payload when updating QUIZ lesson", async () => {
+ mockLessonId = "lesson-quiz-payload";
+ let capturedPayload: any = null;
+
+ const mockExec = jest
+ .fn()
+ .mockResolvedValueOnce({
+ lesson: {
+ lessonId: "lesson-quiz-payload",
+ title: "QUIZ Lesson",
+ type: "QUIZ",
+ content: {
+ questions: [
+ {
+ text: "Original question?",
+ options: [
+ { text: "A", correctAnswer: true },
+ { text: "B", correctAnswer: false },
+ ],
+ },
+ ],
+ requiresPassingGrade: false,
+ },
+ requiresEnrollment: true,
+ },
+ })
+ .mockResolvedValueOnce({
+ lesson: { lessonId: "lesson-quiz-payload" },
+ });
+
+ const mockSetPayload = jest.fn((payload) => {
+ capturedPayload = payload;
+ return {
+ setIsGraphQLEndpoint: jest.fn().mockReturnThis(),
+ build: jest.fn().mockReturnThis(),
+ exec: mockExec,
+ };
+ });
+
+ (FetchBuilder as unknown as jest.Mock).mockImplementation(() => ({
+ setUrl: jest.fn().mockReturnThis(),
+ setPayload: mockSetPayload,
+ }));
+
+ render(
, { wrapper });
+
+ // Wait for lesson to load
+ await waitFor(() => {
+ expect(
+ screen.getByDisplayValue("QUIZ Lesson"),
+ ).toBeInTheDocument();
+ });
+
+ // Update content by clicking the mock button (simulates quiz changes)
+ const updateContentButton = screen.getByText("Update Content");
+ fireEvent.click(updateContentButton);
+
+ // Save
+ const saveButton = screen.getByText("Update Lesson");
+ fireEvent.click(saveButton);
+
+ // Verify the mutation payload contains quiz data
+ await waitFor(
+ () => {
+ expect(mockSetPayload).toHaveBeenCalled();
+ },
+ { timeout: 3000 },
+ );
+
+ // If mockSetPayload was called, capturedPayload should be defined
+ if (capturedPayload) {
+ expect(capturedPayload.variables).toBeDefined();
+ expect(capturedPayload.variables.lessonData).toBeDefined();
+ }
+ });
+ });
+});
diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/lesson-content-renderer.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/lesson-content-renderer.tsx
new file mode 100644
index 000000000..1b09eedf9
--- /dev/null
+++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/lesson-content-renderer.tsx
@@ -0,0 +1,217 @@
+import {
+ Constants,
+ Lesson,
+ Media,
+ Profile,
+ TextEditorContent,
+} from "@courselit/common-models";
+import { MediaSelector, useToast } from "@courselit/components-library";
+import { Editor, emptyDoc as TextEditorEmptyDoc } from "@courselit/text-editor";
+import { QuizBuilder } from "@components/admin/products/quiz-builder";
+import { Info } from "lucide-react";
+import {
+ TEXT_EDITOR_PLACEHOLDER,
+ TOAST_TITLE_ERROR,
+ TOAST_TITLE_SUCCESS,
+} from "@ui-config/strings";
+import {
+ MIMETYPE_VIDEO,
+ MIMETYPE_AUDIO,
+ MIMETYPE_PDF,
+} from "@ui-config/constants";
+import { useContext, useState } from "react";
+import { AddressContext, ProfileContext } from "@components/contexts";
+import { FetchBuilder } from "@courselit/utils";
+import { Textarea } from "@components/ui/textarea";
+import dynamic from "next/dynamic";
+const LessonEmbedViewer = dynamic(
+ () => import("@components/public/lesson-viewer/embed-viewer"),
+);
+
+interface LessonContentRendererProps {
+ lesson: Partial
;
+ errors: Partial>;
+ onContentChange: (content: { value: string }) => void;
+ onLessonChange: (updates: Partial) => void;
+}
+
+export function LessonContentRenderer({
+ lesson,
+ errors,
+ onContentChange,
+ onLessonChange,
+}: LessonContentRendererProps) {
+ const address = useContext(AddressContext);
+ const { profile } = useContext(ProfileContext);
+ const [embedURL, setEmbedURL] = useState(
+ (lesson.content as any)?.value ?? "",
+ );
+ const { toast } = useToast();
+
+ const saveMediaContent = async (media?: Media) => {
+ const query = `
+ mutation ($id: ID!, $media: MediaInput) {
+ lesson: updateLesson(lessonData: {
+ id: $id
+ media: $media
+ }) {
+ lessonId
+ }
+ }
+ `;
+ const fetch = new FetchBuilder()
+ .setUrl(`${address.backend}/api/graph`)
+ .setPayload({
+ query,
+ variables: {
+ id: lesson?.lessonId,
+ media: media
+ ? Object.assign({}, media, {
+ file:
+ media.access === "public" ? media.file : null,
+ })
+ : null,
+ },
+ })
+ .setIsGraphQLEndpoint(true)
+ .build();
+
+ try {
+ await fetch.exec();
+ toast({
+ title: TOAST_TITLE_SUCCESS,
+ description: "Lesson updated",
+ });
+ } catch (err: any) {
+ toast({
+ title: TOAST_TITLE_ERROR,
+ description: err.message,
+ variant: "destructive",
+ });
+ }
+ };
+
+ switch (lesson.type) {
+ case Constants.LessonType.TEXT:
+ return (
+
+
{
+ onContentChange(state);
+ }}
+ url={address.backend}
+ placeholder={TEXT_EDITOR_PLACEHOLDER}
+ />
+ {errors.content && (
+ {errors.content}
+ )}
+
+ );
+ case Constants.LessonType.EMBED:
+ return (
+
+
+
+ {errors.content && (
+
{errors.content}
+ )}
+ {embedURL && (
+
+ )}
+
+ );
+ case Constants.LessonType.QUIZ:
+ return (
+
+
{
+ onContentChange(state);
+ }}
+ />
+ {errors.content && (
+ {errors.content}
+ )}
+
+ );
+ case Constants.LessonType.VIDEO:
+ case Constants.LessonType.AUDIO:
+ case Constants.LessonType.PDF:
+ case Constants.LessonType.FILE:
+ return (
+
+
{
+ if (media) {
+ onLessonChange({
+ title:
+ lesson?.title || media.originalFileName,
+ media,
+ });
+ saveMediaContent(media);
+ }
+ }}
+ mimeTypesToShow={
+ lesson.type === Constants.LessonType.VIDEO
+ ? MIMETYPE_VIDEO
+ : lesson.type === Constants.LessonType.AUDIO
+ ? MIMETYPE_AUDIO
+ : lesson.type === Constants.LessonType.PDF
+ ? MIMETYPE_PDF
+ : undefined
+ }
+ strings={{}}
+ profile={profile as Profile}
+ address={address}
+ mediaId={lesson?.media?.mediaId}
+ onRemove={() => {
+ onLessonChange({
+ media: {},
+ });
+ saveMediaContent();
+ }}
+ type="lesson"
+ />
+ {!(lesson?.lessonId && lesson?.title) && (
+
+
+ Set the title of the lesson to enable media upload
+
+ )}
+
+ );
+ default:
+ return null;
+ }
+}
diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx
index d4d108150..60ed59b8f 100644
--- a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx
+++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useCallback, useEffect, useContext } from "react";
+import { useState, useCallback, useEffect, useContext, useRef } from "react";
import { useRouter, useParams, useSearchParams } from "next/navigation";
import Link from "next/link";
import {
@@ -11,7 +11,6 @@ import {
FileImage,
HelpCircle,
File,
- Info,
Tv,
} from "lucide-react";
import { Button } from "@/components/ui/button";
@@ -33,36 +32,29 @@ import {
BUTTON_NEW_LESSON_TEXT,
COURSE_CONTENT_HEADER,
EDIT_LESSON_TEXT,
+ LESSON_EMBED_URL_LABEL,
+ LESSON_CONTENT_LABEL,
MANAGE_COURSES_PAGE_HEADING,
TOAST_TITLE_ERROR,
TOAST_TITLE_SUCCESS,
- TEXT_EDITOR_PLACEHOLDER,
} from "@ui-config/strings";
import DashboardContent from "@components/admin/dashboard-content";
import useProduct from "@/hooks/use-product";
-import { AddressContext, ProfileContext } from "@components/contexts";
+import { AddressContext } from "@components/contexts";
import {
Constants,
Lesson,
LessonType,
- Media,
- Profile,
- Quiz,
TextEditorContent,
UIConstants,
} from "@courselit/common-models";
-import { MediaSelector, useToast } from "@courselit/components-library";
-import {
- MIMETYPE_VIDEO,
- MIMETYPE_AUDIO,
- MIMETYPE_PDF,
-} from "@ui-config/constants";
+import { useToast } from "@courselit/components-library";
import { FetchBuilder } from "@courselit/utils";
-import { QuizBuilder } from "@components/admin/products/quiz-builder";
+import { LessonContentRenderer } from "./lesson-content-renderer";
import { isTextEditorNonEmpty, truncate } from "@ui-lib/utils";
-import { Skeleton } from "@/components/ui/skeleton";
import { Separator } from "@components/ui/separator";
-import { Editor, emptyDoc as TextEditorEmptyDoc } from "@courselit/text-editor";
+import { emptyDoc as TextEditorEmptyDoc } from "@courselit/text-editor";
+import { LessonSkeleton } from "./skeleton";
const { permissions } = UIConstants;
@@ -76,6 +68,8 @@ const lessonTypes = [
{ value: Constants.LessonType.QUIZ, label: "Quiz", icon: HelpCircle },
] as const;
+type LessonError = Partial>;
+
export default function LessonPage() {
const router = useRouter();
const params = useParams();
@@ -86,13 +80,8 @@ export default function LessonPage() {
const isEditing = !!lessonId;
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const { toast } = useToast();
- const [errors, setErrors] = useState>>(
- {},
- );
- const [initialLessonType, setInitialLessonType] =
- useState(null);
+ const [errors, setErrors] = useState({});
const address = useContext(AddressContext);
- const { profile } = useContext(ProfileContext);
const { product, loaded: productLoaded } = useProduct(productId);
const breadcrumbs = [
{ label: MANAGE_COURSES_PAGE_HEADING, href: "/dashboard/products" },
@@ -109,11 +98,10 @@ export default function LessonPage() {
href: "#",
},
];
- const [refresh, setRefresh] = useState(0);
- const [quizContent, setQuizContent] = useState>({});
- const [textContent, setTextContent] =
- useState(TextEditorEmptyDoc);
- const [content, setContent] = useState<{ value: string }>({ value: "" });
+
+ // Use ref to store the originally loaded lesson for comparison
+ const loadedLessonRef = useRef | null>(null);
+
const [lesson, setLesson] = useState>({
type: product
? product.type?.toLowerCase() === UIConstants.COURSE_TYPE_DOWNLOAD
@@ -128,9 +116,13 @@ export default function LessonPage() {
courseId: productId,
groupId: sectionId,
});
- const [originalLesson, setOriginalLesson] =
- useState | null>(null);
- const [hasChanges, setHasChanges] = useState(false);
+ const [content, setContent] = useState(
+ lesson.type === Constants.LessonType.TEXT
+ ? TextEditorEmptyDoc
+ : lesson.type === Constants.LessonType.QUIZ
+ ? {}
+ : { value: "" },
+ );
const [isLoading, setIsLoading] = useState(isEditing);
useEffect(() => {
@@ -146,506 +138,8 @@ export default function LessonPage() {
}
}, [product]);
- useEffect(() => {
- if (isEditing) {
- loadLesson(lessonId);
- }
- }, [isEditing]);
-
const updateLesson = (updates: Partial) => {
- setLesson((prev) => {
- const newLesson = { ...prev, ...updates };
- if (isEditing && initialLessonType) {
- newLesson.type = initialLessonType;
- }
- return newLesson;
- });
- };
-
- // const handleAddQuestion = (e: React.MouseEvent) => {
- // e.preventDefault();
- // const newQuestion = {
- // id: `q${quizContent.questions?.length + 1}`,
- // text: "",
- // options: [],
- // };
- // // updateLesson({ questions: [...quizContent.questions, newQuestion] });
- // setQuizContent((prev) => ({
- // ...prev,
- // questions: [...(prev.questions || []), newQuestion]
- // }));
- // setExpandedQuestion(newQuestion.id);
- // };
-
- // const handleAddOption = (questionId: string) => {
- // setQuizContent((prev) => ({
- // ...prev,
- // questions: prev.questions?.map((q) =>
- // q.id === questionId
- // ? { ...q, options: [...q.options, { id: `${questionId}-opt${q.options.length + 1}`, text: "", correctAnswer: false }] }
- // : q
- // )
- // }))
- // // updateLesson({
- // // questions: lesson.questions.map((q) =>
- // // q.id === questionId
- // // ? {
- // // ...q,
- // // options: [
- // // ...q.options,
- // // {
- // // id: `${questionId}-opt${q.options.length + 1}`,
- // // text: "",
- // // isCorrect: false,
- // // },
- // // ],
- // // }
- // // : q,
- // // ),
- // // });
- // };
-
- const renderLessonContent = () => {
- switch (lesson.type) {
- case Constants.LessonType.TEXT:
- return (
-
-
{
- setTextContent(state);
- }}
- url={address.backend}
- placeholder={TEXT_EDITOR_PLACEHOLDER}
- />
- {errors.content && (
-
- {errors.content}
-
- )}
-
- );
- case Constants.LessonType.EMBED:
- return (
-
-
-
- // updateLesson({ content: { value: e.target.value } })
- setContent({ value: e.target.value })
- }
- className={
- errors.content ? "border-red-500" : ""
- }
- />
- {/*
-
-
-
-
-
-
- Enter the YouTube video ID, which is
- the part after "v=" in the
- URL
-
-
-
- */}
-
- {errors.content && (
-
- {errors.content}
-
- )}
- {content.value && (
-
- {content.value.match(
- UIConstants.YOUTUBE_REGEX,
- ) && (
-
- VIDEO
-
- )}
-
- {content.value}
-
-
- )}
-
- );
- case Constants.LessonType.QUIZ:
- return (
-
-
{
- setQuizContent(state);
- }}
- />
- {errors.content && (
-
- {errors.content}
-
- )}
-
- );
- // return (
- //
- // {quizContent.questions?.map((question, index) => (
- //
- // setExpandedQuestion(question.id)
- // }
- // className={`border rounded-lg ${errors.questions ? "border-red-500" : ""}`}
- // >
- //
- //
- //
- // Question #{index + 1}
- //
- //
- // {question.text
- // ? `${question.text.substring(0, 50)}...`
- // : "No question text"}
- //
- //
- // {expandedQuestion === question.id ? (
- //
- // ) : (
- //
- // )}
- //
- //
- // {
- // updateLesson({
- // questions: quizContent.questions?.map(
- // (q) =>
- // q.id === question.id
- // ? {
- // ...q,
- // text: e.target
- // .value,
- // }
- // : q,
- // ),
- // });
- // }}
- // className={
- // errors.questions
- // ? "border-red-500"
- // : ""
- // }
- // />
- //
- // {question.options.map((option) => (
- //
- //
- //
- //
- //
- // {
- // updateLesson(
- // {
- // questions:
- // quizContent.questions?.map(
- // (
- // q,
- // ) =>
- // q.id ===
- // question.id
- // ? {
- // ...q,
- // options:
- // q.options.map(
- // (
- // opt,
- // ) =>
- // opt.id ===
- // option.id
- // ? {
- // ...opt,
- // isCorrect:
- // !!checked,
- // }
- // : opt,
- // ),
- // }
- // : q,
- // ),
- // },
- // );
- // }}
- // />
- //
- //
- //
- //
- // Mark as correct
- // answer
- //
- //
- //
- //
- //
{
- // updateLesson({
- // questions:
- // quizContent.questions?.map(
- // (q) =>
- // q.id ===
- // question.id
- // ? {
- // ...q,
- // options:
- // q.options.map(
- // (
- // opt,
- // ) =>
- // opt.id ===
- // option.id
- // ? {
- // ...opt,
- // text: e
- // .target
- // .value,
- // }
- // : opt,
- // ),
- // }
- // : q,
- // ),
- // });
- // }}
- // className="flex-1"
- // />
- //
{
- // updateLesson({
- // questions:
- // quizContent.questions?.map(
- // (q) =>
- // q.id ===
- // question.id
- // ? {
- // ...q,
- // options:
- // q.options.filter(
- // (
- // opt,
- // ) =>
- // opt.id !==
- // option.id,
- // ),
- // }
- // : q,
- // ),
- // });
- // }}
- // >
- //
- //
- //
- // ))}
- //
- // handleAddOption(question.id)
- // }
- // >
- //
- // Add option
- //
- //
- //
- //
- // ))}
- //
- //
- // Add question
- //
- // {errors.content && (
- //
- // {errors.content}
- //
- // )}
- //
- // );
- case Constants.LessonType.VIDEO:
- case Constants.LessonType.AUDIO:
- case Constants.LessonType.PDF:
- case Constants.LessonType.FILE:
- return (
- //
- // updateLesson({
- // mediaUrl: value,
- // mediaCaption: caption,
- // })
- // }
- // className={errors.content ? "border-red-500" : ""}
- // />
-
-
{
- if (media) {
- setLesson(
- Object.assign({}, lesson, {
- title:
- lesson?.title ||
- media.originalFileName,
- media,
- }),
- );
- saveMediaContent(media);
- }
- }}
- mimeTypesToShow={
- lesson.type === Constants.LessonType.VIDEO
- ? MIMETYPE_VIDEO
- : lesson.type === Constants.LessonType.AUDIO
- ? MIMETYPE_AUDIO
- : lesson.type === Constants.LessonType.PDF
- ? MIMETYPE_PDF
- : undefined
- }
- strings={{}}
- profile={profile as Profile}
- address={address}
- mediaId={lesson?.media?.mediaId}
- onRemove={() => {
- setLesson(
- Object.assign({}, lesson, {
- media: {},
- }),
- );
- saveMediaContent();
- }}
- type="lesson"
- />
- {!(lesson?.lessonId && lesson?.title) && (
-
-
- Set the title of the lesson to enable media
- upload
-
- )}
-
- );
- default:
- return null;
- }
- };
-
- // const getMimeTypesToShow = () => {
- // if (
- // lesson?.type ===
- // String.prototype.toUpperCase.call(Constants.LessonType.VIDEO)
- // ) {
- // return MIMETYPE_VIDEO;
- // }
- // if (
- // lesson?.type ===
- // String.prototype.toUpperCase.call(Constants.LessonType.AUDIO)
- // ) {
- // return MIMETYPE_AUDIO;
- // }
- // if (
- // lesson?.type ===
- // String.prototype.toUpperCase.call(Constants.LessonType.PDF)
- // ) {
- // return MIMETYPE_PDF;
- // }
-
- // return [...MIMETYPE_AUDIO, ...MIMETYPE_VIDEO, ...MIMETYPE_PDF];
- // };
-
- const saveMediaContent = async (media?: Media) => {
- const query = `
- mutation ($id: ID!, $media: MediaInput) {
- lesson: updateLesson(lessonData: {
- id: $id
- media: $media
- }) {
- lessonId
- }
- }
- `;
- const fetch = new FetchBuilder()
- .setUrl(`${address.backend}/api/graph`)
- .setPayload({
- query,
- variables: {
- id: lesson?.lessonId,
- media: media
- ? Object.assign({}, media, {
- file:
- media.access === "public" ? media.file : null,
- })
- : null,
- },
- })
- .setIsGraphQLEndpoint(true)
- .build();
-
- try {
- await fetch.exec();
- toast({
- title: TOAST_TITLE_SUCCESS,
- description: "Lesson updated",
- });
- } catch (err: any) {
- toast({
- title: TOAST_TITLE_ERROR,
- description: err.message,
- variant: "destructive",
- });
- } finally {
- }
+ setLesson({ ...lesson, ...updates });
};
useEffect(() => {
@@ -686,36 +180,16 @@ export default function LessonPage() {
try {
const response = await fetch.exec();
if (response.lesson) {
- const loadedLesson = Object.assign({}, response.lesson, {
+ const loadedLesson = {
+ ...response.lesson,
type: response.lesson.type.toLowerCase() as LessonType,
- });
- setLesson(JSON.parse(JSON.stringify(loadedLesson)));
- setOriginalLesson(JSON.parse(JSON.stringify(loadedLesson)));
- setInitialLessonType(
- response.lesson.type.toLowerCase() as LessonType,
- );
- switch (response.lesson.type.toLowerCase()) {
- case Constants.LessonType.TEXT:
- setTextContent(
- response.lesson.content
- ? response.lesson.content.type &&
- response.lesson.content.type === "doc"
- ? response.lesson.content
- : TextEditorEmptyDoc
- : TextEditorEmptyDoc,
- );
- setRefresh(refresh + 1);
- break;
- case Constants.LessonType.QUIZ:
- setQuizContent(
- JSON.parse(
- JSON.stringify(response.lesson.content || {}),
- ),
- );
- break;
- default:
- setContent(response.lesson.content || { value: "" });
- }
+ };
+
+ // Store the loaded lesson in ref for future comparison
+ loadedLessonRef.current = loadedLesson;
+
+ setLesson(loadedLesson);
+ setContent(response.lesson.content);
}
} catch (err: any) {
toast({
@@ -728,47 +202,6 @@ export default function LessonPage() {
}
};
- useEffect(() => {
- if (!originalLesson) return;
-
- const checkForChanges = () => {
- // Compare current lesson state with original lesson
- const hasLessonChanges = Object.keys(lesson).some((key) => {
- if (key === "content") {
- // Handle different content types
- switch (lesson.type?.toLowerCase()) {
- case Constants.LessonType.TEXT:
- return (
- JSON.stringify(textContent) !==
- JSON.stringify(originalLesson.content)
- );
- case Constants.LessonType.QUIZ:
- return (
- JSON.stringify(quizContent) !==
- JSON.stringify(originalLesson.content)
- );
- default:
- return (
- JSON.stringify(content) !==
- JSON.stringify(originalLesson.content)
- );
- }
- }
- if (key === "media") {
- return false;
- }
- return (
- lesson[key as keyof Lesson] !==
- originalLesson[key as keyof Lesson]
- );
- });
-
- setHasChanges(hasLessonChanges);
- };
-
- checkForChanges();
- }, [lesson, textContent, quizContent, content, originalLesson]);
-
const validateLesson = useCallback((): boolean => {
const newErrors: Partial> = {};
@@ -780,23 +213,23 @@ export default function LessonPage() {
case Constants.LessonType.TEXT:
if (
!isTextEditorNonEmpty(
- textContent as unknown as TextEditorContent,
+ content as unknown as TextEditorContent,
)
) {
newErrors.content = "Please enter the lesson content.";
}
break;
case Constants.LessonType.EMBED:
- if (!content.value.trim()) {
+ if (!content.value?.trim()) {
newErrors.content = "Please enter a YouTube video ID.";
}
break;
case Constants.LessonType.QUIZ:
- if (quizContent.questions?.length === 0) {
+ if (!content.questions || content.questions.length === 0) {
newErrors.content =
"Please add at least one question to the quiz.";
} else {
- for (const question of quizContent.questions!) {
+ for (const question of content.questions) {
if (!question.text.trim()) {
newErrors.content = "All questions must have text.";
break;
@@ -818,19 +251,11 @@ export default function LessonPage() {
}
}
break;
- // case Constants.LessonType.VIDEO:
- // case Constants.LessonType.AUDIO:
- // case Constants.LessonType.PDF:
- // case Constants.LessonType.FILE:
- // if (!lesson.mediaUrl) {
- // newErrors.content = `Please select a ${lesson.type} file.`;
- // }
- // break;
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
- }, [lesson, textContent, quizContent, content]);
+ }, [lesson, content]);
const handleSave = async (e: React.FormEvent) => {
e.preventDefault();
@@ -862,7 +287,7 @@ export default function LessonPage() {
id: lesson?.lessonId,
title: lesson?.title,
downloadable: lesson?.downloadable,
- content: formatContentForSending(),
+ content: JSON.stringify(content),
requiresEnrollment: lesson?.requiresEnrollment,
},
},
@@ -904,7 +329,7 @@ export default function LessonPage() {
title: lesson?.title,
downloadable: lesson?.downloadable,
type: lesson?.type?.toUpperCase(),
- content: formatContentForSending(),
+ content: JSON.stringify(content),
courseId: lesson?.courseId,
requiresEnrollment: lesson?.requiresEnrollment,
groupId: lesson?.groupId,
@@ -974,49 +399,6 @@ export default function LessonPage() {
}
};
- const formatContentForSending = () => {
- switch (lesson?.type?.toLowerCase()) {
- case Constants.LessonType.TEXT:
- return JSON.stringify(textContent);
- case Constants.LessonType.QUIZ:
- return JSON.stringify(quizContent);
- default:
- return JSON.stringify(content);
- }
- };
-
- // Add skeleton component
- const LessonSkeleton = () => (
-
-
-
-
- {[...Array(7)].map((_, i) => (
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-
return (
@@ -1132,13 +514,25 @@ export default function LessonPage() {
{lesson.type ===
Constants.LessonType.EMBED
- ? "Embed URL"
- : `${lesson.type ? lesson.type.charAt(0).toUpperCase() + lesson.type.slice(1) : ""} Content`}
+ ? LESSON_EMBED_URL_LABEL
+ : LESSON_CONTENT_LABEL}
- {renderLessonContent()}
+ {
+ setLesson(
+ Object.assign(
+ {},
+ lesson,
+ updates,
+ ),
+ );
+ }}
+ />
>
)}
- {/* {renderLessonContent()} */}
-
+
{isEditing ? "Update" : "Save"} Lesson
@@ -1236,7 +627,16 @@ export default function LessonPage() {
Media
- {renderLessonContent()}
+ {
+ setLesson(
+ Object.assign({}, lesson, updates),
+ );
+ }}
+ />
>
)}
diff --git a/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/skeleton.tsx b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/skeleton.tsx
new file mode 100644
index 000000000..596e7f09f
--- /dev/null
+++ b/apps/web/app/(with-contexts)/dashboard/(sidebar)/product/[id]/content/section/[section]/lesson/skeleton.tsx
@@ -0,0 +1,32 @@
+import { Skeleton } from "@/components/ui/skeleton";
+
+export const LessonSkeleton = () => (
+
+
+
+
+ {[...Array(7)].map((_, i) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/apps/web/components/admin/payments/payment-plan-form.tsx b/apps/web/components/admin/payments/payment-plan-form.tsx
index 3eb753eee..54ea9f07d 100644
--- a/apps/web/components/admin/payments/payment-plan-form.tsx
+++ b/apps/web/components/admin/payments/payment-plan-form.tsx
@@ -161,7 +161,7 @@ export function PaymentPlanForm({
const currencyISOCode = siteinfo.currencyISOCode?.toUpperCase() || "USD";
const form = useForm
({
- resolver: zodResolver(formSchema),
+ resolver: zodResolver(formSchema as any),
defaultValues: {
name: "",
description: "",
diff --git a/apps/web/components/admin/products/quiz-builder/__tests__/quiz-builder.test.tsx b/apps/web/components/admin/products/quiz-builder/__tests__/quiz-builder.test.tsx
new file mode 100644
index 000000000..594dba48d
--- /dev/null
+++ b/apps/web/components/admin/products/quiz-builder/__tests__/quiz-builder.test.tsx
@@ -0,0 +1,333 @@
+import React from "react";
+import { render, screen, fireEvent } from "@testing-library/react";
+import { QuizBuilder } from "../index";
+import "@testing-library/jest-dom";
+
+// Mock dependencies
+jest.mock("@courselit/components-library", () => {
+ const React = jest.requireActual("react");
+ return {
+ Section: ({ children }: any) =>
+ React.createElement("div", { "data-testid": "section" }, children),
+ Checkbox: ({ checked, onChange }: any) =>
+ React.createElement("input", {
+ type: "checkbox",
+ checked,
+ onChange: (e: any) => onChange(e.target.checked),
+ "data-testid": "checkbox",
+ }),
+ IconButton: ({ onClick, children }: any) =>
+ React.createElement(
+ "button",
+ { onClick, "data-testid": "icon-button" },
+ children,
+ ),
+ Tooltip: ({ children, title }: any) =>
+ React.createElement(
+ "div",
+ { title, "data-testid": "tooltip" },
+ children,
+ ),
+ };
+});
+
+jest.mock("@ui-config/strings", () => ({
+ LESSON_QUIZ_ADD_QUESTION: "Add Question",
+ LESSON_QUIZ_QUESTION_PLACEHOLDER: "Question Placeholder",
+ LESSON_QUIZ_ADD_OPTION_BTN: "Add Option",
+ LESSON_QUIZ_CONTENT_HEADER: "Question",
+ LESSON_QUIZ_OPTION_PLACEHOLDER: "Option Placeholder",
+ QUESTION_BUILDER_COLLAPSE_TOOLTIP: "Collapse",
+ QUESTION_BUILDER_CORRECT_ANS_TOOLTIP: "Correct Answer",
+ QUESTION_BUILDER_DELETE_TOOLTIP: "Delete",
+ QUESTION_BUILDER_EXPAND_TOOLTIP: "Expand",
+}));
+
+jest.mock("@components/ui/button", () => {
+ const React = jest.requireActual("react");
+ return {
+ Button: ({ onClick, children }: any) =>
+ React.createElement(
+ "button",
+ { onClick, "data-testid": "button" },
+ children,
+ ),
+ };
+});
+
+jest.mock("@components/ui/label", () => {
+ const React = jest.requireActual("react");
+ return {
+ Label: ({ children }: any) =>
+ React.createElement("label", {}, children),
+ };
+});
+
+jest.mock("@components/ui/switch", () => {
+ const React = jest.requireActual("react");
+ return {
+ Switch: ({ checked, onCheckedChange }: any) =>
+ React.createElement("input", {
+ type: "checkbox",
+ checked,
+ onChange: (e: any) => onCheckedChange(e.target.checked),
+ "data-testid": "switch",
+ }),
+ };
+});
+
+jest.mock("@components/ui/input", () => {
+ const React = jest.requireActual("react");
+ return {
+ Input: (props: any) =>
+ React.createElement("input", { ...props, "data-testid": "input" }),
+ };
+});
+
+jest.mock("@courselit/icons", () => {
+ const React = jest.requireActual("react");
+ return {
+ ExpandLess: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-expand-less" },
+ "ExpandLess",
+ ),
+ ExpandMore: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-expand-more" },
+ "ExpandMore",
+ ),
+ };
+});
+
+jest.mock("lucide-react", () => {
+ const React = jest.requireActual("react");
+ return {
+ Trash: () =>
+ React.createElement(
+ "span",
+ { "data-testid": "icon-trash" },
+ "Trash",
+ ),
+ };
+});
+
+describe("QuizBuilder", () => {
+ const mockOnChange = jest.fn();
+ const defaultProps = {
+ content: {
+ questions: [
+ {
+ text: "Question 1",
+ options: [{ text: "Option 1", correctAnswer: false }],
+ },
+ ],
+ requiresPassingGrade: false,
+ passingGrade: 0,
+ },
+ onChange: mockOnChange,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it("renders initial questions", () => {
+ render( );
+
+ expect(screen.getByDisplayValue("Question 1")).toBeInTheDocument();
+ expect(screen.getByDisplayValue("Option 1")).toBeInTheDocument();
+ });
+
+ it("adds a new question", () => {
+ render( );
+
+ fireEvent.click(screen.getByText("Add Question"));
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: expect.arrayContaining([
+ expect.objectContaining({ text: "Question 1" }),
+ expect.objectContaining({
+ text: "Question Placeholder #2",
+ }),
+ ]),
+ }),
+ );
+ });
+
+ it("deletes a question", () => {
+ // We need at least 2 questions to show delete button on the second one (index > 0)
+ // Or check logic: QuestionBuilder shows delete if index > 0.
+ // So we need to add a question first or start with 2.
+
+ const propsWithTwoQuestions = {
+ ...defaultProps,
+ content: {
+ ...defaultProps.content,
+ questions: [
+ { text: "Q1", options: [] },
+ { text: "Q2", options: [] },
+ ],
+ },
+ };
+
+ render( );
+
+ // Find delete button for second question.
+ // It's the Trash icon in the header of the second question.
+ // Structure: Section -> QuestionBuilder -> Header -> IconButton -> Trash
+
+ const trashIcons = screen.getAllByTestId("icon-trash");
+ // Q1: no delete. Q2: delete.
+ // Also options might have delete buttons. Here options are empty.
+
+ const deleteBtn = trashIcons[0].closest("button");
+ fireEvent.click(deleteBtn!);
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [expect.objectContaining({ text: "Q1" })],
+ }),
+ );
+ });
+
+ it("updates question text", () => {
+ render( );
+
+ const input = screen.getByDisplayValue("Question 1");
+ fireEvent.change(input, { target: { value: "Updated Question" } });
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [
+ expect.objectContaining({ text: "Updated Question" }),
+ ],
+ }),
+ );
+ });
+
+ it("adds an option to a question", () => {
+ render( );
+
+ fireEvent.click(screen.getByText("Add Option"));
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [
+ expect.objectContaining({
+ options: expect.arrayContaining([
+ expect.objectContaining({ text: "Option 1" }),
+ expect.objectContaining({ text: "" }),
+ ]),
+ }),
+ ],
+ }),
+ );
+ });
+
+ it("removes an option from a question", () => {
+ render( );
+
+ // Find remove option button.
+ const trashIcons = screen.getAllByTestId("icon-trash");
+ // Only 1 option, so 1 trash icon (since Q1 has no delete button).
+
+ const deleteBtn = trashIcons[0].closest("button");
+ fireEvent.click(deleteBtn!);
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [
+ expect.objectContaining({
+ options: [],
+ }),
+ ],
+ }),
+ );
+ });
+
+ it("updates option text", () => {
+ render( );
+
+ const input = screen.getByDisplayValue("Option 1");
+ fireEvent.change(input, { target: { value: "Updated Option" } });
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [
+ expect.objectContaining({
+ options: [
+ expect.objectContaining({ text: "Updated Option" }),
+ ],
+ }),
+ ],
+ }),
+ );
+ });
+
+ it("sets correct answer", () => {
+ render( );
+
+ const checkbox = screen.getByTestId("checkbox");
+ fireEvent.click(checkbox);
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ questions: [
+ expect.objectContaining({
+ options: [
+ expect.objectContaining({ correctAnswer: true }),
+ ],
+ }),
+ ],
+ }),
+ );
+ });
+
+ it("toggles graded quiz", () => {
+ render( );
+
+ fireEvent.click(screen.getByTestId("switch"));
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ requiresPassingGrade: true,
+ }),
+ );
+ });
+
+ it("updates passing grade", () => {
+ render(
+ ,
+ );
+
+ // The passing grade input is the number input.
+ // We have text inputs for questions/options.
+ // We can find by type="number" if we mocked it correctly or by value.
+ // Our mock for Input: React.createElement("input", { ...props, "data-testid": "input" })
+ // The component passes type="number".
+
+ // Let's find all inputs and filter or just assume the last one?
+ // Or better, check props passed to mock.
+
+ // Let's use value.
+ // The default passing grade is 70 when 0 is passed (falsy)
+ const input = screen.getByDisplayValue("70");
+ fireEvent.change(input, { target: { value: "80" } });
+
+ expect(mockOnChange).toHaveBeenCalledWith(
+ expect.objectContaining({
+ passingGrade: 80,
+ }),
+ );
+ });
+});
diff --git a/apps/web/components/admin/products/quiz-builder/index.tsx b/apps/web/components/admin/products/quiz-builder/index.tsx
index 894dfc1a9..ab1562f06 100644
--- a/apps/web/components/admin/products/quiz-builder/index.tsx
+++ b/apps/web/components/admin/products/quiz-builder/index.tsx
@@ -1,4 +1,4 @@
-import React, { startTransition, useEffect, useState } from "react";
+import React, { useState } from "react";
import { Section } from "@courselit/components-library";
import {
LESSON_QUIZ_ADD_QUESTION,
@@ -34,31 +34,17 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
(content && content.passingGrade) || DEFAULT_PASSING_GRADE,
);
- useEffect(() => {
- startTransition(() => {
- if (content.questions) {
- setQuestions(content.questions);
- }
- if (content.passingGrade) {
- setPassingGradePercentage(content.passingGrade);
- }
- if (content.requiresPassingGrade) {
- setPassingGradeRequired(content.requiresPassingGrade);
- }
- });
- }, [content]);
-
- useEffect(() => {
+ const notifyChange = (updatedQuestions: Question[]) => {
onChange({
- questions,
+ questions: updatedQuestions,
requiresPassingGrade: passingGradeRequired,
passingGrade: passingGradePercentage,
});
- }, [questions, passingGradeRequired, passingGradePercentage, onChange]);
+ };
const addNewOption = (questionIndex: number) => {
- setQuestions((prevQuestions) =>
- prevQuestions.map((question, index) =>
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.map((question, index) =>
index === questionIndex
? {
...question,
@@ -68,14 +54,16 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
],
}
: question,
- ),
- );
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
const setCorrectAnswer =
(questionIndex: number) => (index: number, checked: boolean) => {
- setQuestions((prevQuestions) =>
- prevQuestions.map((question, qIdx) =>
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.map((question, qIdx) =>
qIdx === questionIndex
? {
...question,
@@ -86,14 +74,16 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
),
}
: question,
- ),
- );
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
const setOptionText =
(questionIndex: number) => (index: number, text: string) => {
- setQuestions((prevQuestions) =>
- prevQuestions.map((question, qIdx) =>
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.map((question, qIdx) =>
qIdx === questionIndex
? {
...question,
@@ -104,21 +94,25 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
),
}
: question,
- ),
- );
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
const setQuestionText = (index: number) => (text: string) => {
- setQuestions((prevQuestions) =>
- prevQuestions.map((question, qIdx) =>
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.map((question, qIdx) =>
qIdx === index ? { ...question, text } : question,
- ),
- );
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
const removeOption = (questionIndex: number) => (index: number) => {
- setQuestions((prevQuestions) =>
- prevQuestions.map((question, qIdx) =>
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.map((question, qIdx) =>
qIdx === questionIndex
? {
...question,
@@ -127,26 +121,35 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
),
}
: question,
- ),
- );
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
const deleteQuestion = (questionIndex: number) => {
- setQuestions((prevQuestions) =>
- prevQuestions.filter((_, idx) => idx !== questionIndex),
- );
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = prevQuestions.filter(
+ (_, idx) => idx !== questionIndex,
+ );
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
};
- const addNewQuestion = () =>
- setQuestions((prevQuestions) => [
- ...prevQuestions,
- {
- text: `${LESSON_QUIZ_QUESTION_PLACEHOLDER} #${
- prevQuestions.length + 1
- }`,
- options: [{ text: "", correctAnswer: false }],
- },
- ]);
+ const addNewQuestion = () => {
+ setQuestions((prevQuestions) => {
+ const updatedQuestions = [
+ ...prevQuestions,
+ {
+ text: `${LESSON_QUIZ_QUESTION_PLACEHOLDER} #${prevQuestions.length + 1}`,
+ options: [{ text: "", correctAnswer: false }],
+ },
+ ];
+ notifyChange(updatedQuestions);
+ return updatedQuestions;
+ });
+ };
return (
@@ -190,17 +193,28 @@ export function QuizBuilder({ content, onChange }: QuizBuilderProps) {
- setPassingGradeRequired(checked)
- }
+ onCheckedChange={(checked) => {
+ setPassingGradeRequired(checked);
+ onChange({
+ questions,
+ requiresPassingGrade: checked,
+ passingGrade: passingGradePercentage,
+ });
+ }}
/>
- setPassingGradePercentage(parseInt(e.target.value))
- }
+ onChange={(e) => {
+ const newValue = parseInt(e.target.value);
+ setPassingGradePercentage(newValue);
+ onChange({
+ questions,
+ requiresPassingGrade: passingGradeRequired,
+ passingGrade: newValue,
+ });
+ }}
disabled={!passingGradeRequired}
min={0}
max={100}
diff --git a/apps/web/components/public/lesson-viewer/embed-viewer.tsx b/apps/web/components/public/lesson-viewer/embed-viewer.tsx
index 5a9ccc5fc..7b6ab3040 100644
--- a/apps/web/components/public/lesson-viewer/embed-viewer.tsx
+++ b/apps/web/components/public/lesson-viewer/embed-viewer.tsx
@@ -8,7 +8,7 @@ const YouTubeEmbed = ({ content }: { content: string }) => {
VIDEO
- {content.value.match(UIConstants.YOUTUBE_REGEX) && (
-
-
-
+ <>
+ {content.value.includes("youtube") ||
+ content.value.includes("youtu.be") ? (
+
+ ) : (
+
)}
-
- {content.value}
-
-
+ >
);
};
diff --git a/apps/web/components/public/lesson-viewer/index.tsx b/apps/web/components/public/lesson-viewer/index.tsx
index af1e76480..0a130d782 100644
--- a/apps/web/components/public/lesson-viewer/index.tsx
+++ b/apps/web/components/public/lesson-viewer/index.tsx
@@ -191,7 +191,7 @@ export const LessonViewer = ({
{!lesson && !error && (
-
+
@@ -217,7 +217,7 @@ export const LessonViewer = ({
{lesson && !error && (
<>
diff --git a/apps/web/components/public/payments/checkout.tsx b/apps/web/components/public/payments/checkout.tsx
index 34576e485..7f81939e7 100644
--- a/apps/web/components/public/payments/checkout.tsx
+++ b/apps/web/components/public/payments/checkout.tsx
@@ -88,7 +88,7 @@ export default function Checkout({
const { theme } = useContext(ThemeContext);
const form = useForm>({
- resolver: zodResolver(formSchema),
+ resolver: zodResolver(formSchema as any),
defaultValues: {
selectedPlan: product.defaultPaymentPlanId || "",
joiningReason: "",
diff --git a/apps/web/components/public/payments/login-form.tsx b/apps/web/components/public/payments/login-form.tsx
index 4f479f9eb..8e87d6a83 100644
--- a/apps/web/components/public/payments/login-form.tsx
+++ b/apps/web/components/public/payments/login-form.tsx
@@ -60,7 +60,7 @@ export function LoginForm({ onLoginComplete }: LoginFormProps) {
}, [profile]);
const form = useForm>({
- resolver: zodResolver(loginFormSchema),
+ resolver: zodResolver(loginFormSchema as any),
defaultValues: {
email: "",
otp: "",
diff --git a/apps/web/jest.client.config.ts b/apps/web/jest.client.config.ts
index d7f57841e..bbb05e977 100644
--- a/apps/web/jest.client.config.ts
+++ b/apps/web/jest.client.config.ts
@@ -37,6 +37,12 @@ const config = {
"@courselit/common-logic": "/../../packages/common-logic/src",
"@courselit/page-primitives":
"/../../packages/page-primitives/src",
+ "@courselit/components-library":
+ "/../../packages/components-library/src",
+ "@courselit/icons": "/../../packages/icons/src",
+ "@courselit/text-editor": "/../../packages/text-editor/src",
+ "@courselit/common-models":
+ "/../../packages/common-models/src",
nanoid: "/__mocks__/nanoid.ts",
slugify: "/__mocks__/slugify.ts",
"@models/(.*)": "/models/$1",
@@ -47,10 +53,14 @@ const config = {
"@/lib/(.*)": "/lib/$1",
"@/services/(.*)": "/services/$1",
"@/templates/(.*)": "/templates/$1",
+ "@/hooks/(.*)": "/hooks/$1",
"@/app/(.*)": "/app/$1",
"@ui-lib/(.*)": "/ui-lib/$1",
"@config/(.*)": "/config/$1",
"@/models/(.*)": "/models/$1",
+ "@components/(.*)": "/components/$1",
+ "@ui-config/(.*)": "/ui-config/$1",
+ "@ui-models/(.*)": "/ui-models/$1",
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
},
transform: {
diff --git a/apps/web/ui-config/strings.ts b/apps/web/ui-config/strings.ts
index 2a1ab5a11..46f3490c7 100644
--- a/apps/web/ui-config/strings.ts
+++ b/apps/web/ui-config/strings.ts
@@ -692,3 +692,5 @@ export const PRODUCTS_LIST_EMPTY_DESCRIPTION_PRIVATE =
"You have not added any products yet.";
export const LOGIN_CODE_SENT_MESSAGE =
"We have emailed you a one time password.";
+export const LESSON_EMBED_URL_LABEL = "URL or Iframe Code";
+export const LESSON_CONTENT_LABEL = "Content";
diff --git a/packages/components-library/package.json b/packages/components-library/package.json
index 7f8240b59..c59a8e210 100644
--- a/packages/components-library/package.json
+++ b/packages/components-library/package.json
@@ -37,6 +37,7 @@
"url": "https://github.com/codelitdev/courselit/issues"
},
"devDependencies": {
+ "@types/node": "^24.10.1",
"@types/react": "^18.3.7",
"@types/react-dom": "^18.3.0",
"eslint": "^8.57.0",
diff --git a/packages/components-library/tsconfig.json b/packages/components-library/tsconfig.json
index 6914d8109..de8d9e0d1 100644
--- a/packages/components-library/tsconfig.json
+++ b/packages/components-library/tsconfig.json
@@ -3,7 +3,8 @@
"exclude": ["dist", "build", "node_modules"],
"compilerOptions": {
"outDir": "./dist",
- "lib": ["dom"],
+ "lib": ["dom", "ES2017"],
+ "types": ["node"],
"strict": false,
"paths": {
"@/*": ["./src/*"],
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 65fa2d48f..5843d0d24 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -16,7 +16,7 @@ importers:
devDependencies:
'@changesets/cli':
specifier: ^2.29.7
- version: 2.29.7(@types/node@20.19.0)
+ version: 2.29.7(@types/node@24.10.1)
'@testing-library/dom':
specifier: ^10.4.0
version: 10.4.0
@@ -55,7 +55,7 @@ importers:
version: 9.1.7
jest:
specifier: ^29.7.0
- version: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ version: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
jest-environment-jsdom:
specifier: ^29.7.0
version: 29.7.0
@@ -70,10 +70,10 @@ importers:
version: 3.5.3
tailwindcss:
specifier: ^3.0.0
- version: 3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ version: 3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
ts-node:
specifier: ^10.9.2
- version: 10.9.2(@types/node@20.19.0)(typescript@5.9.3)
+ version: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -182,13 +182,13 @@ importers:
version: 10.1.4(@aws-sdk/credential-providers@3.797.0)(socks@2.8.4)
ts-jest:
specifier: ^29.4.4
- version: 29.4.4(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)))(typescript@5.9.3)
+ version: 29.4.4(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3)
tsconfig:
specifier: workspace:^
version: link:../../packages/tsconfig
tsup:
specifier: ^7.2.0
- version: 7.3.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))(typescript@5.9.3)
+ version: 7.3.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3)
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -511,7 +511,7 @@ importers:
version: link:../tsconfig
tsup:
specifier: 6.6.0
- version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@4.9.5))(typescript@4.9.5)
+ version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5))(typescript@4.9.5)
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -560,67 +560,67 @@ importers:
version: link:../utils
'@dnd-kit/core':
specifier: ^6.1.0
- version: 6.3.1(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@dnd-kit/sortable':
specifier: ^8.0.0
- version: 8.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@18.3.1))(react@18.3.1))(react@18.3.1)
+ version: 8.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)
'@dnd-kit/utilities':
specifier: ^3.2.2
- version: 3.2.2(react@18.3.1)
+ version: 3.2.2(react@19.2.0)
'@radix-ui/react-accordion':
specifier: ^1.1.2
- version: 1.2.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-alert-dialog':
specifier: ^1.1.11
- version: 1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-avatar':
specifier: ^1.0.4
- version: 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-checkbox':
specifier: ^1.0.4
- version: 1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-dialog':
specifier: ^1.1.14
- version: 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-dropdown-menu':
specifier: ^2.0.6
- version: 2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-form':
specifier: ^0.0.3
- version: 0.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 0.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-label':
specifier: ^2.1.2
- version: 2.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 2.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-popover':
specifier: ^1.1.14
- version: 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-progress':
specifier: ^1.1.7
- version: 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-scroll-area':
specifier: ^1.0.5
- version: 1.2.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-select':
specifier: ^2.1.6
- version: 2.2.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 2.2.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-slider':
specifier: ^1.1.2
- version: 1.3.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.3.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-slot':
specifier: ^1.2.3
- version: 1.2.3(@types/react@18.3.7)(react@18.3.1)
+ version: 1.2.3(@types/react@18.3.7)(react@19.2.0)
'@radix-ui/react-switch':
specifier: ^1.1.3
- version: 1.2.5(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.5(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-tabs':
specifier: ^1.1.3
- version: 1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-toast':
specifier: ^1.2.2
- version: 1.2.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
'@radix-ui/react-tooltip':
specifier: ^1.0.7
- version: 1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
class-variance-authority:
specifier: ^0.7.0
version: 0.7.1
@@ -629,7 +629,7 @@ importers:
version: 2.1.1
cmdk:
specifier: ^1.1.1
- version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
+ version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
currency-symbol-map:
specifier: ^5.1.0
version: 5.1.0
@@ -638,7 +638,7 @@ importers:
version: 4.0.8
lucide-react:
specifier: ^0.553.0
- version: 0.553.0(react@18.3.1)
+ version: 0.553.0(react@19.2.0)
next:
specifier: '*'
version: 15.5.3(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
@@ -647,17 +647,20 @@ importers:
version: 18.3.1
react-dom:
specifier: ^19.2.0
- version: 19.2.0(react@18.3.1)
+ version: 19.2.0(react@19.2.0)
tailwind-merge:
specifier: ^2.2.0
version: 2.6.0
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)))
+ version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))
tus-js-client:
specifier: ^4.3.1
version: 4.3.1
devDependencies:
+ '@types/node':
+ specifier: ^24.10.1
+ version: 24.10.1
'@types/react':
specifier: 18.3.7
version: 18.3.7
@@ -678,7 +681,7 @@ importers:
version: link:../tsconfig
tsup:
specifier: 6.6.0
- version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))(typescript@5.9.3)
+ version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3)
typescript:
specifier: ^5.1.6
version: 5.9.3
@@ -797,7 +800,7 @@ importers:
version: link:../tsconfig
tsup:
specifier: 6.6.0
- version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@4.9.5))(typescript@4.9.5)
+ version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5))(typescript@4.9.5)
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -885,7 +888,7 @@ importers:
version: link:../tsconfig
tsup:
specifier: 6.6.0
- version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))(typescript@5.9.3)
+ version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3)
typescript:
specifier: ^5.1.6
version: 5.9.3
@@ -967,13 +970,13 @@ importers:
version: link:../tailwind-config
tailwindcss:
specifier: '3'
- version: 3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ version: 3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
tsconfig:
specifier: workspace:^
version: link:../tsconfig
tsup:
specifier: 6.6.0
- version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))(typescript@5.9.3)
+ version: 6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3)
typescript:
specifier: ^5.8.3
version: 5.9.3
@@ -985,11 +988,11 @@ importers:
dependencies:
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)))
+ version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))
devDependencies:
tailwindcss:
specifier: ^3.4.1
- version: 3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ version: 3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
packages/text-editor:
dependencies:
@@ -5029,6 +5032,9 @@ packages:
'@types/node@20.19.0':
resolution: {integrity: sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==}
+ '@types/node@24.10.1':
+ resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
+
'@types/nodemailer@6.4.17':
resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==}
@@ -10356,6 +10362,9 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
unherit@3.0.1:
resolution: {integrity: sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==}
@@ -11729,7 +11738,7 @@ snapshots:
dependencies:
'@changesets/types': 6.1.0
- '@changesets/cli@2.29.7(@types/node@20.19.0)':
+ '@changesets/cli@2.29.7(@types/node@24.10.1)':
dependencies:
'@changesets/apply-release-plan': 7.0.13
'@changesets/assemble-release-plan': 6.0.9
@@ -11745,7 +11754,7 @@ snapshots:
'@changesets/should-skip-package': 0.1.2
'@changesets/types': 6.1.0
'@changesets/write': 0.4.0
- '@inquirer/external-editor': 1.0.3(@types/node@20.19.0)
+ '@inquirer/external-editor': 1.0.3(@types/node@24.10.1)
'@manypkg/get-packages': 1.1.3
ansi-colors: 4.1.3
ci-info: 3.9.0
@@ -11868,29 +11877,29 @@ snapshots:
'@csstools/css-tokenizer@3.0.4': {}
- '@dnd-kit/accessibility@3.1.1(react@18.3.1)':
+ '@dnd-kit/accessibility@3.1.1(react@19.2.0)':
dependencies:
- react: 18.3.1
+ react: 19.2.0
tslib: 2.8.1
- '@dnd-kit/core@6.3.1(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
+ '@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
- '@dnd-kit/accessibility': 3.1.1(react@18.3.1)
- '@dnd-kit/utilities': 3.2.2(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@dnd-kit/accessibility': 3.1.1(react@19.2.0)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
tslib: 2.8.1
- '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@18.3.1))(react@18.3.1))(react@18.3.1)':
+ '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)':
dependencies:
- '@dnd-kit/core': 6.3.1(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@dnd-kit/utilities': 3.2.2(react@18.3.1)
- react: 18.3.1
+ '@dnd-kit/core': 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.0)
+ react: 19.2.0
tslib: 2.8.1
- '@dnd-kit/utilities@3.2.2(react@18.3.1)':
+ '@dnd-kit/utilities@3.2.2(react@19.2.0)':
dependencies:
- react: 18.3.1
+ react: 19.2.0
tslib: 2.8.1
'@docsearch/css@3.9.0': {}
@@ -12231,12 +12240,6 @@ snapshots:
'@floating-ui/core': 1.6.9
'@floating-ui/utils': 0.2.9
- '@floating-ui/react-dom@2.1.2(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@floating-ui/dom': 1.6.13
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
-
'@floating-ui/react-dom@2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@floating-ui/dom': 1.6.13
@@ -12542,12 +12545,12 @@ snapshots:
'@img/sharp-win32-x64@0.34.5':
optional: true
- '@inquirer/external-editor@1.0.3(@types/node@20.19.0)':
+ '@inquirer/external-editor@1.0.3(@types/node@24.10.1)':
dependencies:
chardet: 2.1.1
iconv-lite: 0.7.0
optionalDependencies:
- '@types/node': 20.19.0
+ '@types/node': 24.10.1
'@ioredis/commands@1.2.0': {}
@@ -12614,7 +12617,7 @@ snapshots:
- supports-color
- ts-node
- '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))':
+ '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))':
dependencies:
'@jest/console': 29.7.0
'@jest/reporters': 29.7.0
@@ -12628,7 +12631,7 @@ snapshots:
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ jest-config: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -12992,33 +12995,19 @@ snapshots:
'@radix-ui/primitive@1.1.3': {}
- '@radix-ui/react-accordion@1.2.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collapsible': 1.1.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
- '@radix-ui/react-alert-dialog@1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-accordion@1.2.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dialog': 1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@radix-ui/react-collapsible': 1.1.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
optionalDependencies:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
@@ -13037,15 +13026,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-arrow@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-arrow@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -13055,15 +13035,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -13073,19 +13044,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-avatar@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-avatar@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13099,22 +13057,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-checkbox@1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-checkbox@1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13131,22 +13073,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-collapsible@1.1.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-collapsible@1.1.8(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13163,18 +13089,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-collection@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-collection@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13187,10 +13101,10 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.7)(react@18.3.1)':
+ '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- react: 18.3.1
+ react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
@@ -13206,10 +13120,10 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-context@1.0.1(@types/react@18.3.7)(react@18.3.1)':
+ '@radix-ui/react-context@1.0.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- react: 18.3.1
+ react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
@@ -13225,28 +13139,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-dialog@1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- aria-hidden: 1.2.4
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.7)(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-dialog@1.1.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13269,28 +13161,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-dialog@1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- aria-hidden: 1.2.4
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.7)(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-dialog@1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13335,31 +13205,12 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-direction@1.1.1(@types/react@18.3.7)(react@18.3.1)':
- dependencies:
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.3.7
-
'@radix-ui/react-direction@1.1.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13386,19 +13237,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13412,21 +13250,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-dropdown-menu@2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-menu': 2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-dropdown-menu@2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13442,12 +13265,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-focus-guards@1.1.2(@types/react@18.3.7)(react@18.3.1)':
- dependencies:
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.3.7
-
'@radix-ui/react-focus-guards@1.1.2(@types/react@18.3.7)(react@19.2.0)':
dependencies:
react: 19.2.0
@@ -13460,17 +13277,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-focus-scope@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13504,17 +13310,17 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-form@0.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-form@0.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
'@radix-ui/primitive': 1.0.1
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.0.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.0.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-label': 2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-label': 2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
optionalDependencies:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
@@ -13523,11 +13329,11 @@ snapshots:
dependencies:
react: 18.3.1
- '@radix-ui/react-id@1.0.1(@types/react@18.3.7)(react@18.3.1)':
+ '@radix-ui/react-id@1.0.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.7)(react@19.2.0)
+ react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
@@ -13545,21 +13351,12 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-label@2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-label@2.0.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
- '@radix-ui/react-label@2.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
optionalDependencies:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
@@ -13582,32 +13379,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-menu@2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-popper': 1.2.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-roving-focus': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- aria-hidden: 1.2.4
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.7)(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-menu@2.1.12(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13634,30 +13405,7 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-popover@1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- aria-hidden: 1.2.4
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.7)(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
- '@radix-ui/react-popover@1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
+ '@radix-ui/react-popover@1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13680,24 +13428,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-popper@1.2.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@floating-ui/react-dom': 2.1.2(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-arrow': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/rect': 1.1.1
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-popper@1.2.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@floating-ui/react-dom': 2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -13716,24 +13446,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-popper@1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@floating-ui/react-dom': 2.1.2(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/rect': 1.1.1
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-popper@1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@floating-ui/react-dom': 2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -13752,16 +13464,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-portal@1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-portal@1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -13792,16 +13494,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13822,21 +13514,12 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
+ '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- '@radix-ui/react-slot': 1.0.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
- '@radix-ui/react-primitive@2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.3.7)(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
optionalDependencies:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
@@ -13877,16 +13560,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-progress@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-progress@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@19.2.0)
@@ -13915,23 +13588,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-roving-focus@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-roving-focus@1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -13949,23 +13605,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-scroll-area@1.2.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/number': 1.1.1
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-scroll-area@1.2.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/number': 1.1.1
@@ -13983,35 +13622,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-select@2.2.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/number': 1.1.1
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-popper': 1.2.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.0(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-visually-hidden': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- aria-hidden: 1.2.4
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- react-remove-scroll: 2.6.3(@types/react@18.3.7)(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-select@2.2.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/number': 1.1.1
@@ -14050,25 +13660,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-slider@1.3.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/number': 1.1.1
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-slider@1.3.2(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/number': 1.1.1
@@ -14088,18 +13679,11 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-slot@1.0.2(@types/react@18.3.7)(react@18.3.1)':
+ '@radix-ui/react-slot@1.0.2(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.3.7
-
- '@radix-ui/react-slot@1.2.0(@types/react@18.3.7)(react@18.3.1)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.7)(react@19.2.0)
+ react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
@@ -14131,21 +13715,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-switch@1.2.5(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-switch@1.2.5(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -14176,22 +13745,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-tabs@1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-roving-focus': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-tabs@1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -14208,26 +13761,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-toast@1.2.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-collection': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-visually-hidden': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-toast@1.2.11(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -14274,26 +13807,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-tooltip@1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/primitive': 1.1.2
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-context': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-popper': 1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-tooltip@1.2.7(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
@@ -14370,13 +13883,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.7)(react@18.3.1)':
- dependencies:
- react: 18.3.1
- use-sync-external-store: 1.5.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
-
'@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.7)(react@19.2.0)':
dependencies:
react: 19.2.0
@@ -14384,10 +13890,10 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.7)(react@18.3.1)':
+ '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@babel/runtime': 7.27.0
- react: 18.3.1
+ react: 19.2.0
optionalDependencies:
'@types/react': 18.3.7
@@ -14415,13 +13921,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.7)(react@18.3.1)':
- dependencies:
- '@radix-ui/rect': 1.1.1
- react: 18.3.1
- optionalDependencies:
- '@types/react': 18.3.7
-
'@radix-ui/react-use-rect@1.1.1(@types/react@18.3.7)(react@19.2.0)':
dependencies:
'@radix-ui/rect': 1.1.1
@@ -14443,15 +13942,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.7
- '@radix-ui/react-visually-hidden@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-visually-hidden@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -14461,15 +13951,6 @@ snapshots:
'@types/react': 18.3.7
'@types/react-dom': 18.3.0
- '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.7
- '@types/react-dom': 18.3.0
-
'@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -16427,9 +15908,13 @@ snapshots:
dependencies:
undici-types: 6.21.0
+ '@types/node@24.10.1':
+ dependencies:
+ undici-types: 7.16.0
+
'@types/nodemailer@6.4.17':
dependencies:
- '@types/node': 18.19.87
+ '@types/node': 20.19.0
'@types/object.omit@3.0.3': {}
@@ -17697,14 +17182,14 @@ snapshots:
cluster-key-slot@1.1.2: {}
- cmdk@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1):
+ cmdk@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-dialog': 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@18.3.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 19.2.0(react@18.3.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-dialog': 1.1.14(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ '@radix-ui/react-id': 1.1.1(@types/react@18.3.7)(react@19.2.0)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
@@ -17841,13 +17326,13 @@ snapshots:
- supports-color
- ts-node
- create-jest@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ create-jest@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
'@jest/types': 29.6.3
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ jest-config: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
jest-util: 29.7.0
prompts: 2.4.2
transitivePeerDependencies:
@@ -19784,16 +19269,16 @@ snapshots:
- supports-color
- ts-node
- jest-cli@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ jest-cli@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ create-jest: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
exit: 0.1.2
import-local: 3.2.0
- jest-config: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ jest-config: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -19865,7 +19350,7 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-config@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ jest-config@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
'@babel/core': 7.26.10
'@jest/test-sequencer': 29.7.0
@@ -19891,7 +19376,38 @@ snapshots:
strip-json-comments: 3.1.1
optionalDependencies:
'@types/node': 20.19.0
- ts-node: 10.9.2(@types/node@20.19.0)(typescript@5.9.3)
+ ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-config@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
+ dependencies:
+ '@babel/core': 7.26.10
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.10)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0(babel-plugin-macros@3.1.0)
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 24.10.1
+ ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
@@ -19921,7 +19437,7 @@ snapshots:
'@jest/fake-timers': 29.7.0
'@jest/types': 29.6.3
'@types/jsdom': 20.0.1
- '@types/node': 18.19.87
+ '@types/node': 20.19.0
jest-mock: 29.7.0
jest-util: 29.7.0
jsdom: 20.0.3
@@ -20138,12 +19654,12 @@ snapshots:
- supports-color
- ts-node
- jest@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ jest@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
- '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
'@jest/types': 29.6.3
import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ jest-cli: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@@ -21571,6 +21087,22 @@ snapshots:
postcss: 8.5.3
ts-node: 10.9.2(@types/node@20.19.0)(typescript@5.9.3)
+ postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5)):
+ dependencies:
+ lilconfig: 2.1.0
+ yaml: 1.10.2
+ optionalDependencies:
+ postcss: 8.5.3
+ ts-node: 10.9.2(@types/node@24.10.1)(typescript@4.9.5)
+
+ postcss-load-config@3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
+ dependencies:
+ lilconfig: 2.1.0
+ yaml: 1.10.2
+ optionalDependencies:
+ postcss: 8.5.3
+ ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
+
postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@17.0.21)(typescript@5.9.3)):
dependencies:
lilconfig: 3.1.3
@@ -21587,13 +21119,13 @@ snapshots:
postcss: 8.5.3
ts-node: 10.9.2(@types/node@20.19.0)(typescript@4.9.5)
- postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ postcss-load-config@4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
lilconfig: 3.1.3
yaml: 2.7.1
optionalDependencies:
postcss: 8.5.3
- ts-node: 10.9.2(@types/node@20.19.0)(typescript@5.9.3)
+ ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3)
postcss-nested@6.2.0(postcss@8.5.3):
dependencies:
@@ -22961,7 +22493,7 @@ snapshots:
stripe@17.7.0:
dependencies:
- '@types/node': 18.19.87
+ '@types/node': 20.19.0
qs: 6.14.0
strnum@1.1.2:
@@ -23053,9 +22585,9 @@ snapshots:
dependencies:
tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@4.9.5))
- tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))):
+ tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))):
dependencies:
- tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
tailwindcss@3.4.17(ts-node@10.9.2(@types/node@17.0.21)(typescript@5.9.3)):
dependencies:
@@ -23111,7 +22643,7 @@ snapshots:
transitivePeerDependencies:
- ts-node
- tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)):
+ tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -23130,7 +22662,7 @@ snapshots:
postcss: 8.5.3
postcss-import: 15.1.0(postcss@8.5.3)
postcss-js: 4.0.1(postcss@8.5.3)
- postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
postcss-nested: 6.2.0(postcss@8.5.3)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
@@ -23259,12 +22791,12 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-jest@29.4.4(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3)))(typescript@5.9.3):
+ ts-jest@29.4.4(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)))(typescript@5.9.3):
dependencies:
bs-logger: 0.2.6
fast-json-stable-stringify: 2.1.0
handlebars: 4.7.8
- jest: 29.7.0(@types/node@20.19.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ jest: 29.7.0(@types/node@24.10.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
json5: 2.2.3
lodash.memoize: 4.1.2
make-error: 1.3.6
@@ -23374,6 +22906,44 @@ snapshots:
typescript: 5.9.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
+ optional: true
+
+ ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.11
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 24.10.1
+ acorn: 8.14.1
+ acorn-walk: 8.3.4
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 4.9.5
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
+ optional: true
+
+ ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.11
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 24.10.1
+ acorn: 8.14.1
+ acorn-walk: 8.3.4
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 5.9.3
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
tsconfig-paths@3.15.0:
dependencies:
@@ -23443,7 +23013,53 @@ snapshots:
- supports-color
- ts-node
- tsup@7.3.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))(typescript@5.9.3):
+ tsup@6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5))(typescript@4.9.5):
+ dependencies:
+ bundle-require: 4.2.1(esbuild@0.17.19)
+ cac: 6.7.14
+ chokidar: 3.6.0
+ debug: 4.4.0
+ esbuild: 0.17.19
+ execa: 5.1.1
+ globby: 11.1.0
+ joycon: 3.1.1
+ postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@4.9.5))
+ resolve-from: 5.0.0
+ rollup: 3.29.5
+ source-map: 0.8.0-beta.0
+ sucrase: 3.35.0
+ tree-kill: 1.2.2
+ optionalDependencies:
+ postcss: 8.5.3
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - supports-color
+ - ts-node
+
+ tsup@6.6.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3):
+ dependencies:
+ bundle-require: 4.2.1(esbuild@0.17.19)
+ cac: 6.7.14
+ chokidar: 3.6.0
+ debug: 4.4.0
+ esbuild: 0.17.19
+ execa: 5.1.1
+ globby: 11.1.0
+ joycon: 3.1.1
+ postcss-load-config: 3.1.4(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
+ resolve-from: 5.0.0
+ rollup: 3.29.5
+ source-map: 0.8.0-beta.0
+ sucrase: 3.35.0
+ tree-kill: 1.2.2
+ optionalDependencies:
+ postcss: 8.5.3
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+ - ts-node
+
+ tsup@7.3.0(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))(typescript@5.9.3):
dependencies:
bundle-require: 4.2.1(esbuild@0.19.12)
cac: 6.7.14
@@ -23453,7 +23069,7 @@ snapshots:
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
- postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@20.19.0)(typescript@5.9.3))
+ postcss-load-config: 4.0.2(postcss@8.5.3)(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3))
resolve-from: 5.0.0
rollup: 4.40.0
source-map: 0.8.0-beta.0
@@ -23597,6 +23213,8 @@ snapshots:
undici-types@6.21.0: {}
+ undici-types@7.16.0: {}
+
unherit@3.0.1: {}
unified@10.1.2: