diff --git a/src/components/api/searchApi.ts b/src/components/api/searchApi.ts index 625aafcf..72578403 100644 --- a/src/components/api/searchApi.ts +++ b/src/components/api/searchApi.ts @@ -2,7 +2,6 @@ import axiosInstance from "@/config/axios-config"; type SearchCommon = { query: string; - language?: string; limit?: number; skip?: number; }; diff --git a/src/components/auth/login/Login.tsx b/src/components/auth/login/Login.tsx index c2947c99..6f1d2c19 100644 --- a/src/components/auth/login/Login.tsx +++ b/src/components/auth/login/Login.tsx @@ -17,7 +17,6 @@ const Login = () => { const { t } = useTranslate(); const navigate = useNavigate(); const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); const [errors, setErrors] = useState(""); const [successMessage, setSuccessMessage] = useState(""); const [showEmailReverify, setShowEmailReverify] = useState(false); @@ -69,10 +68,12 @@ const Login = () => { }, }); - const handleLogin = (e: React.FormEvent) => { + const handleLogin = (e: React.FormEvent) => { e.preventDefault(); setShowEmailReverify(false); setSuccessMessage(""); + const formData = new FormData(e.currentTarget); + const password = formData.get("password") as string; const clientPassword = createPasswordHash(email, password); loginMutation.mutate({ email, @@ -111,13 +112,10 @@ const Login = () => { { - setPassword(e.target.value); - }} />
diff --git a/src/components/routes/create-plan/CreatePlan.test.tsx b/src/components/routes/create-plan/CreatePlan.test.tsx index a21c881b..63ead223 100644 --- a/src/components/routes/create-plan/CreatePlan.test.tsx +++ b/src/components/routes/create-plan/CreatePlan.test.tsx @@ -83,6 +83,19 @@ describe("CreatePlan Component", () => { } return Promise.resolve({ data: {} }); }); + vi.spyOn(axiosInstance, "get").mockResolvedValue({ + data: { + id: "plan-123", + title: "Existing Plan", + description: "Existing description", + total_days: 14, + difficulty_level: "Beginner", + plan_image_url: "https://example.com/image.jpg", + image_url: "https://example.com/image.jpg", + tags: ["meditation"], + language: "en", + }, + }); }); it("renders create plan form with main heading", () => { renderWithProviders(); @@ -162,7 +175,7 @@ describe("CreatePlan Component", () => { fireEvent.change(titleInput, { target: { value: "Test Plan Title" } }); - expect((titleInput as HTMLInputElement).value).toBe("Test Plan Title"); + expect(titleInput).toHaveValue("Test Plan Title"); }); it("allows typing in description textarea", () => { @@ -176,9 +189,7 @@ describe("CreatePlan Component", () => { target: { value: "Test plan description" }, }); - expect((descriptionTextarea as HTMLTextAreaElement).value).toBe( - "Test plan description", - ); + expect(descriptionTextarea).toHaveValue("Test plan description"); }); it("allows typing in number of days input", () => { @@ -190,7 +201,7 @@ describe("CreatePlan Component", () => { fireEvent.change(daysInput, { target: { value: "30" } }); - expect((daysInput as HTMLInputElement).value).toBe("30"); + expect(daysInput).toHaveValue(30); }); it("renders image upload area", () => { @@ -382,4 +393,80 @@ describe("CreatePlan Component", () => { fireEvent.click(confirmButton); expect(mockBlocker.proceed).toHaveBeenCalled(); }); + + it("fetches and populates form in edit mode", async () => { + vi.mocked(useParams).mockReturnValue({ plan_id: "plan-123" }); + + renderWithProviders(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText("studio.plan.form.placeholder.title"), + ).toHaveValue("Existing Plan"); + }); + + expect( + screen.getByPlaceholderText("studio.plan.form.placeholder.description"), + ).toHaveValue("Existing description"); + + expect( + screen.getByPlaceholderText( + "studio.plan.form.placeholder.number_of_days", + ), + ).toHaveValue(14); + + expect(screen.getByAltText("Cover preview")).toBeInTheDocument(); + }); + + it("handles navigation cancellation", async () => { + const mockBlocker = { + state: "blocked" as const, + proceed: vi.fn(), + reset: vi.fn(), + location: {} as any, + }; + vi.mocked(useBlocker).mockReturnValue(mockBlocker); + renderWithProviders(); + await waitFor(() => { + expect( + screen.getByText("studio.plan.navigation.confirm_title"), + ).toBeInTheDocument(); + }); + const cancelButtons = screen.getAllByText("common.button.cancel"); + const dialogCancelButton = cancelButtons.find((btn) => + btn.closest('[role="dialog"]'), + ); + fireEvent.click(dialogCancelButton!); + expect(mockBlocker.reset).toHaveBeenCalled(); + }); + + it("submits update in edit mode", async () => { + vi.mocked(useParams).mockReturnValue({ plan_id: "plan-123" }); + vi.spyOn(axiosInstance, "put").mockResolvedValue({ data: {} }); + renderWithProviders(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText("studio.plan.form.placeholder.title"), + ).toHaveValue("Existing Plan"); + }); + + fireEvent.change( + screen.getByPlaceholderText("studio.plan.form.placeholder.title"), + { target: { value: "Updated Plan" } }, + ); + + const submitButton = screen.getByText("studio.plan.update_button"); + await act(async () => { + fireEvent.click(submitButton); + }); + + await waitFor(() => { + expect(axiosInstance.put).toHaveBeenCalledWith( + "/api/v1/cms/plans/plan-123", + expect.any(Object), + expect.any(Object), + ); + }); + }); }); diff --git a/src/components/routes/dashboard/Dashboard.test.tsx b/src/components/routes/dashboard/Dashboard.test.tsx index e5a46774..273d5765 100644 --- a/src/components/routes/dashboard/Dashboard.test.tsx +++ b/src/components/routes/dashboard/Dashboard.test.tsx @@ -148,4 +148,44 @@ describe("Dashboard Component", () => { ); }); }); + + it("handles toggle featured on a plan", async () => { + vi.spyOn(axiosInstance, "get").mockResolvedValue({ + data: { + plans: [ + { + id: "plan-1", + image_url: "", + title: "Test Plan", + description: "Test description", + total_days: "7", + subscription_count: "10", + status: "PUBLISHED", + featured: false, + language: "EN", + }, + ], + total: 1, + }, + }); + axiosInstance.patch = vi.fn().mockResolvedValue({ data: {} }); + + renderWithProviders(); + + await waitFor(() => { + expect(screen.queryByText("Loading...")).not.toBeInTheDocument(); + }); + + expect(screen.getByText("Test Plan")).toBeInTheDocument(); + + const featuredButton = screen.getByText("Not Featured"); + fireEvent.click(featuredButton); + + await waitFor(() => { + expect(axiosInstance.patch).toHaveBeenCalledWith( + "/api/v1/cms/plans/plan-1/featured", + expect.any(Object), + ); + }); + }); }); diff --git a/src/components/routes/task/PlanDetailsPage.test.tsx b/src/components/routes/task/PlanDetailsPage.test.tsx index 20e310c7..4f7b3d58 100644 --- a/src/components/routes/task/PlanDetailsPage.test.tsx +++ b/src/components/routes/task/PlanDetailsPage.test.tsx @@ -1,4 +1,5 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { vi } from "vitest"; import { BrowserRouter } from "react-router-dom"; @@ -93,7 +94,10 @@ Object.defineProperty(window, "sessionStorage", { writable: true, }); -const renderWithProviders = (component: React.ReactElement, isDraft = true) => { +const renderWithProviders = ( + component: React.ReactElement, + isEditable = true, +) => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, @@ -101,7 +105,7 @@ const renderWithProviders = (component: React.ReactElement, isDraft = true) => { }); queryClient.setQueryData(["planDetails", "test-plan-id"], { ...mockPlanData, - status: isDraft ? "DRAFT" : "ARCHIVED", + status: isEditable ? "DRAFT" : "PUBLISHED", }); return render( @@ -230,4 +234,142 @@ describe("PlanDetailsPanel Component", () => { expect(screen.getByText("Task")).toBeInTheDocument(); }); }); + + it("fetches plan details via queryFn when cache is empty", async () => { + const { default: axiosInstance } = await import("@/config/axios-config"); + const mockAxios = axiosInstance as any; + mockAxios.get.mockResolvedValue({ + data: { ...mockPlanData, status: "DRAFT" }, + }); + + const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, + }); + + render( + + + + + , + ); + + await waitFor(() => { + expect(mockAxios.get).toHaveBeenCalledWith( + expect.stringContaining("/api/v1/cms/plans/test-plan-id"), + expect.any(Object), + ); + }); + await waitFor(() => { + expect(screen.getByText(mockPlanData.title)).toBeInTheDocument(); + }); + }); + + it("clears selected task when that task is deleted from sidebar", async () => { + const user = userEvent.setup(); + const { default: axiosInstance } = await import("@/config/axios-config"); + const mockAxios = axiosInstance as any; + mockAxios.get.mockImplementation((url: string) => { + if (url.includes("/tasks/task1")) { + return Promise.resolve({ + data: { + id: "task1", + title: "Morning Intention Setting", + display_order: 1, + estimated_time: 30, + subtasks: [], + }, + }); + } + return Promise.resolve({ data: { ...mockPlanData, status: "DRAFT" } }); + }); + mockAxios.delete.mockResolvedValue({ data: {} }); + + renderWithProviders(, true); + await waitFor(() => { + expect(screen.getByText(mockPlanData.title)).toBeInTheDocument(); + }); + + fireEvent.click(screen.getByText("Morning Intention Setting")); + await waitFor(() => { + expect(screen.getByText("Task")).toBeInTheDocument(); + }); + + const taskElements = screen.getAllByText("Morning Intention Setting"); + const sidebarSpan = taskElements.find( + (el) => el.tagName === "SPAN" && el.classList.contains("cursor-pointer"), + ); + const taskRow = sidebarSpan!.parentElement!; + const dropdownTrigger = taskRow.querySelector( + '[data-slot="dropdown-menu-trigger"]', + ) as HTMLElement; + await user.click(dropdownTrigger); + + const deleteText = await screen.findByText("Delete"); + await user.click(deleteText); + + const deleteTaskBtn = await screen.findByText("Delete Task"); + await user.click(deleteTaskBtn); + + await waitFor(() => { + expect(screen.getByText("Add Task")).toBeInTheDocument(); + }); + }); + + it("clears editing task when that task is deleted from sidebar", async () => { + const user = userEvent.setup(); + const { default: axiosInstance } = await import("@/config/axios-config"); + const mockAxios = axiosInstance as any; + mockAxios.get.mockImplementation((url: string) => { + if (url.includes("/tasks/task1")) { + return Promise.resolve({ + data: { + id: "task1", + title: "Morning Intention Setting", + display_order: 1, + estimated_time: 30, + subtasks: [], + }, + }); + } + return Promise.resolve({ data: { ...mockPlanData, status: "DRAFT" } }); + }); + mockAxios.delete.mockResolvedValue({ data: {} }); + + renderWithProviders(, true); + await waitFor(() => { + expect(screen.getByText(mockPlanData.title)).toBeInTheDocument(); + }); + + fireEvent.click(screen.getByText("Morning Intention Setting")); + await waitFor(() => { + expect(screen.getByText("Task")).toBeInTheDocument(); + }); + + const editBtn = await screen.findByRole("button", { name: /edit/i }); + fireEvent.click(editBtn); + await waitFor(() => { + expect(screen.getByText("Edit Task")).toBeInTheDocument(); + }); + + const taskElements = screen.getAllByText("Morning Intention Setting"); + const sidebarSpan = taskElements.find( + (el) => el.tagName === "SPAN" && el.classList.contains("cursor-pointer"), + ); + const taskRow = sidebarSpan!.parentElement!; + const dropdownTrigger = taskRow.querySelector( + '[data-slot="dropdown-menu-trigger"]', + ) as HTMLElement; + await user.click(dropdownTrigger); + + const deleteText = await screen.findByText("Delete"); + await user.click(deleteText); + + const deleteTaskBtn = await screen.findByText("Delete Task"); + await user.click(deleteTaskBtn); + + await waitFor(() => { + expect(screen.getByText("Add Task")).toBeInTheDocument(); + }); + }); }); diff --git a/src/components/routes/task/PlanDetailsPage.tsx b/src/components/routes/task/PlanDetailsPage.tsx index 2cff7272..d66e6362 100644 --- a/src/components/routes/task/PlanDetailsPage.tsx +++ b/src/components/routes/task/PlanDetailsPage.tsx @@ -19,7 +19,7 @@ const PlanDetailsPage = () => { }); const status = planDetails?.status || "DRAFT"; - const isDraft = status === "DRAFT"; + const isEditable = status === "DRAFT" || status === "ARCHIVED"; const handleDaySelect = (dayNumber: number) => { setSelectedDay(dayNumber); @@ -28,7 +28,7 @@ const PlanDetailsPage = () => { }; const handleEditTask = (task: any) => { - if (!isDraft) { + if (!isEditable) { return; } setEditingTask(task); @@ -60,21 +60,21 @@ const PlanDetailsPage = () => { setSelectedTaskId(taskId); }} onTaskDelete={handleTaskDelete} - isDraft={isDraft} + isEditable={isEditable} />
{selectedTaskId ? ( ) : ( )}
diff --git a/src/components/routes/task/api/taskApi.ts b/src/components/routes/task/api/taskApi.ts index d6fa0a7e..7c37ee27 100644 --- a/src/components/routes/task/api/taskApi.ts +++ b/src/components/routes/task/api/taskApi.ts @@ -46,6 +46,7 @@ export const createSubTasks = async ( duration?: string; source_text_id?: string | null; pecha_segment_id?: string | null; + segment_id?: string | null; }[], ) => { const { data } = await axiosInstance.post( @@ -71,6 +72,7 @@ export const updateSubTasks = async ( duration?: string; source_text_id?: string | null; pecha_segment_id?: string | null; + segment_id?: string | null; }[], ) => { await axiosInstance.put( diff --git a/src/components/routes/task/components/sidebar-component/SideBar.tsx b/src/components/routes/task/components/sidebar-component/SideBar.tsx index d99f46e5..5eb90ecf 100644 --- a/src/components/routes/task/components/sidebar-component/SideBar.tsx +++ b/src/components/routes/task/components/sidebar-component/SideBar.tsx @@ -19,7 +19,7 @@ interface SideBarProps { onDaySelect: (dayNumber: number) => void; onTaskClick?: (taskId: string) => void; onTaskDelete?: (taskId: string) => void; - isDraft?: boolean; + isEditable?: boolean; } const SideBar = ({ @@ -27,7 +27,7 @@ const SideBar = ({ onDaySelect, onTaskClick, onTaskDelete, - isDraft, + isEditable, }: SideBarProps) => { const [expandedDay, setExpandedDay] = useState(selectedDay); const { plan_id } = useParams<{ plan_id: string }>(); @@ -116,7 +116,7 @@ const SideBar = ({ onReorder={(activeId: any, overId: any) => { handleDayReorder(activeId, overId); }} - disabled={!isDraft} + disabled={!isEditable} > {displayDays.map((day: any) => ( @@ -129,7 +129,7 @@ const SideBar = ({ }} >
- {isDraft && ( + {isEditable && ( { e.stopPropagation(); - if (isDraft) { + if (isEditable) { handleDayClick(day.day_number); } }} /> - {isDraft && currentPlan?.days.length > 1 && ( + {isEditable && currentPlan?.days.length > 1 && ( @@ -229,7 +229,7 @@ const SideBar = ({ onReorder={(activeId: any, overId: any) => { handleTaskReorder(activeId, overId); }} - disabled={!isDraft} + disabled={!isEditable} > {getDisplayTasks(day).map((task: any) => ( {({ listeners }: any) => ( <> - {isDraft && ( + {isEditable && ( {task.title} - {isDraft && ( + {isEditable && ( diff --git a/src/components/routes/task/components/sidebar-component/Sidebar.test.tsx b/src/components/routes/task/components/sidebar-component/Sidebar.test.tsx index 907f6788..e47cb0e1 100644 --- a/src/components/routes/task/components/sidebar-component/Sidebar.test.tsx +++ b/src/components/routes/task/components/sidebar-component/Sidebar.test.tsx @@ -193,7 +193,7 @@ describe("SideBar Component", () => { selectedDay={1} onDaySelect={mockOnDaySelect} onTaskClick={mockOnTaskClick} - isDraft={true} + isEditable={true} />, ); await waitFor(() => { @@ -247,7 +247,7 @@ describe("SideBar Component", () => { selectedDay={1} onDaySelect={mockOnDaySelect} onTaskClick={mockOnTaskClick} - isDraft={true} + isEditable={true} />, ); await waitFor(() => { @@ -279,7 +279,7 @@ describe("SideBar Component", () => { selectedDay={1} onDaySelect={mockOnDaySelect} onTaskClick={mockOnTaskClick} - isDraft={true} + isEditable={true} />, ); await waitFor(() => { diff --git a/src/components/routes/task/components/view/TaskForm.test.tsx b/src/components/routes/task/components/view/TaskForm.test.tsx index 0112968e..6f167e7f 100644 --- a/src/components/routes/task/components/view/TaskForm.test.tsx +++ b/src/components/routes/task/components/view/TaskForm.test.tsx @@ -530,4 +530,28 @@ describe("TaskForm Component", () => { ).toBeInTheDocument(); }); }); + + it("shows error when image exceeds 1MB", async () => { + renderWithProviders(); + fireEvent.click(screen.getByText("Add Image")); + await waitFor(() => { + expect(screen.getByTestId("image-upload-input")).toBeInTheDocument(); + }); + const imageInput = screen.getByTestId("image-upload-input"); + const largeFile = new File( + [new ArrayBuffer(1.5 * 1024 * 1024)], + "big.jpg", + { + type: "image/jpeg", + }, + ); + fireEvent.change(imageInput, { target: { files: [largeFile] } }); + await waitFor(() => { + expect( + screen.getByText( + "File size exceeds 1MB limit. Please select a smaller image.", + ), + ).toBeInTheDocument(); + }); + }); }); diff --git a/src/components/routes/task/components/view/TaskForm.tsx b/src/components/routes/task/components/view/TaskForm.tsx index d47f6bc9..d4ba6a5b 100644 --- a/src/components/routes/task/components/view/TaskForm.tsx +++ b/src/components/routes/task/components/view/TaskForm.tsx @@ -27,7 +27,7 @@ interface TaskFormProps { selectedDay: number; editingTask?: any; onCancel: (newlyCreatedTaskId?: string) => void; - isDraft?: boolean; + isEditable?: boolean; } type TaskFormData = z.infer; @@ -36,7 +36,7 @@ const TaskForm = ({ selectedDay, editingTask, onCancel, - isDraft = true, + isEditable = true, }: TaskFormProps) => { const { plan_id } = useParams(); const queryClient = useQueryClient(); @@ -84,6 +84,7 @@ const TaskForm = ({ ...(subTask.content_type === "SOURCE_REFERENCE" && { source_text_id: subTask.source_text_id || null, pecha_segment_id: subTask.pecha_segment_id || null, + segment_id: subTask.segment_id || null, }), })); await createSubTasks(taskResponse.id, subTasksPayload); @@ -116,6 +117,7 @@ const TaskForm = ({ ...(subTask.content_type === "SOURCE_REFERENCE" && { source_text_id: subTask.source_text_id || null, pecha_segment_id: subTask.pecha_segment_id || null, + segment_id: subTask.segment_id || null, }), })); await updateSubTasks(editingTask.id, subTasksPayload); @@ -192,6 +194,7 @@ const TaskForm = ({ content: data.content, source_text_id: data.source_text_id || null, pecha_segment_id: data.pecha_segment_id || null, + segment_id: data.segment_id || null, }; default: return { @@ -207,8 +210,9 @@ const TaskForm = ({ interface SourceData { content: string; - segment_id: string; + pecha_segment_id: string; text_id: string; + segment_id: string; } const handleAddSubTask = (content_type: any, sourceData?: SourceData) => { @@ -251,7 +255,8 @@ const TaskForm = ({ content_type: "SOURCE_REFERENCE", content: sourceData?.content || "", source_text_id: sourceData?.text_id || null, - pecha_segment_id: sourceData?.segment_id || null, + pecha_segment_id: sourceData?.pecha_segment_id || null, + segment_id: sourceData?.segment_id || null, }; break; } @@ -339,10 +344,10 @@ const TaskForm = ({ isTitleEditing={isTitleEditing} formValue={formValues.title} control={form.control} - onEdit={() => isDraft && setIsTitleEditing(true)} + onEdit={() => isEditable && setIsTitleEditing(true)} onSave={handleSaveTitle} onCancel={() => setIsTitleEditing(false)} - disabled={!isDraft} + disabled={!isEditable} /> {isEditMode && ( @@ -372,7 +377,9 @@ const TaskForm = ({ {imageUploadError && (
{imageUploadError}
)} - {isDraft && } + {isEditable && ( + + )}
@@ -390,7 +397,7 @@ const TaskForm = ({ className="cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed" type="submit" disabled={ - !isDraft || + !isEditable || createTaskMutation.isPending || updateTaskMutation.isPending || subTasks.length === 0 diff --git a/src/components/routes/task/components/view/TaskView.tsx b/src/components/routes/task/components/view/TaskView.tsx index 5aa3ac74..1a0a67a8 100644 --- a/src/components/routes/task/components/view/TaskView.tsx +++ b/src/components/routes/task/components/view/TaskView.tsx @@ -19,7 +19,7 @@ type ContentType = "TEXT" | "IMAGE" | "AUDIO" | "VIDEO" | "SOURCE_REFERENCE"; interface TaskViewProps { taskId: string; onEditTask: (task: any) => void; - isDraft?: boolean; + isEditable?: boolean; } const fetchTaskDetails = async (task_id: string) => { @@ -56,11 +56,11 @@ const SubtaskContent = ({ const SubtaskCard = ({ subtask, listeners, - isDraft, + isEditable, }: { subtask: any; listeners?: any; - isDraft?: boolean; + isEditable?: boolean; }) => { return (
{subtask.content_type}
- {listeners && isDraft && ( + {listeners && isEditable && ( { +const TaskView = ({ taskId, onEditTask, isEditable }: TaskViewProps) => { const { data: taskDetails, isLoading } = useQuery({ queryKey: ["taskDetails", taskId], queryFn: () => fetchTaskDetails(taskId), @@ -101,7 +101,7 @@ const TaskView = ({ taskId, onEditTask, isDraft }: TaskViewProps) => {

Task

- {isDraft && ( + {isEditable && ( { onReorder={(activeId: any, overId: any) => { handleSubtaskReorder(activeId, overId); }} - disabled={!isDraft} + disabled={!isEditable} > {displaySubtasks.map((subtask: any) => ( @@ -148,7 +148,7 @@ const TaskView = ({ taskId, onEditTask, isDraft }: TaskViewProps) => { )} diff --git a/src/components/ui/molecules/content-sub/ContentTypeSelector.tsx b/src/components/ui/molecules/content-sub/ContentTypeSelector.tsx index 3e84d409..62d6e135 100644 --- a/src/components/ui/molecules/content-sub/ContentTypeSelector.tsx +++ b/src/components/ui/molecules/content-sub/ContentTypeSelector.tsx @@ -1,6 +1,6 @@ import { Pecha } from "@/components/ui/shadimport"; import { IoMdAdd, IoMdVideocam } from "react-icons/io"; -import { IoTextOutline } from "react-icons/io5"; +import { IoMusicalNotesSharp, IoTextOutline } from "react-icons/io5"; import { MdOutlineImage } from "react-icons/md"; import pechaIcon from "@/assets/icon/pecha_icon.png"; import { useState } from "react"; @@ -8,8 +8,9 @@ import { SourceSelectorSheet } from "../webuddhist-source/SourceSelectorSheet"; interface SourceData { content: string; - segment_id: string; + pecha_segment_id: string; text_id: string; + segment_id: string; } interface ContentTypeSelectorProps { @@ -26,10 +27,10 @@ const contentTypes = [ key: "IMAGE", icon: , }, - // { - // key: "AUDIO", - // icon: , - // }, + { + key: "AUDIO", + icon: , + }, { key: "VIDEO", icon: , diff --git a/src/components/ui/molecules/dropdown-button/DropdownButton.tsx b/src/components/ui/molecules/dropdown-button/DropdownButton.tsx index bb9ab935..539dff4f 100644 --- a/src/components/ui/molecules/dropdown-button/DropdownButton.tsx +++ b/src/components/ui/molecules/dropdown-button/DropdownButton.tsx @@ -84,7 +84,7 @@ export function DropdownButton({ allowedStatuses.includes(status.value), ); - const canEdit = currentStatus === "DRAFT"; + const canEdit = currentStatus === "DRAFT" || currentStatus === "ARCHIVED"; const canDelete = currentStatus === "DRAFT" || currentStatus === "ARCHIVED"; return ( diff --git a/src/components/ui/molecules/subtask-card/SubTaskCard.tsx b/src/components/ui/molecules/subtask-card/SubTaskCard.tsx index 646e8aba..92c2b449 100644 --- a/src/components/ui/molecules/subtask-card/SubTaskCard.tsx +++ b/src/components/ui/molecules/subtask-card/SubTaskCard.tsx @@ -46,6 +46,7 @@ interface SourceSubTask { display_order?: number; source_text_id?: string | null; pecha_segment_id?: string | null; + segment_id?: string | null; } export type SubTask = | VideoSubTask diff --git a/src/components/ui/molecules/webuddhist-source/SourceSelectorSheet.tsx b/src/components/ui/molecules/webuddhist-source/SourceSelectorSheet.tsx index 9864ffaa..5a0ef26c 100644 --- a/src/components/ui/molecules/webuddhist-source/SourceSelectorSheet.tsx +++ b/src/components/ui/molecules/webuddhist-source/SourceSelectorSheet.tsx @@ -11,8 +11,9 @@ import { searchSources } from "@/components/api/searchApi"; interface SourceData { content: string; - segment_id: string; + pecha_segment_id: string; text_id: string; + segment_id: string; } interface SourceSelectorSheetProps { @@ -40,13 +41,12 @@ export const SourceSelectorSheet = ({ pagination.currentPage, pagination.limit, ], - queryFn: () => { - return searchSources({ + queryFn: () => + searchSources({ query: debouncedSearchFilter, limit: pagination.limit, skip, - }); - }, + }), refetchOnWindowFocus: false, enabled: isOpen, }); diff --git a/src/components/ui/molecules/webuddhist-source/sourceItem.tsx b/src/components/ui/molecules/webuddhist-source/sourceItem.tsx index 2e3082b9..9cc49b62 100644 --- a/src/components/ui/molecules/webuddhist-source/sourceItem.tsx +++ b/src/components/ui/molecules/webuddhist-source/sourceItem.tsx @@ -17,8 +17,9 @@ const SourceItem = ({ source, onSegment }: any) => { onClick={() => onSegment?.({ content: segment.content, - segment_id: segment.pecha_segment_id, + pecha_segment_id: segment.pecha_segment_id, text_id: source.text.text_id, + segment_id: segment.segment_id, }) } >