diff --git a/frontends/mit-open/src/pages/ListDetailsPage/ItemsListing.test.tsx b/frontends/mit-open/src/page-components/ItemsListing/ItemsListing.test.tsx similarity index 100% rename from frontends/mit-open/src/pages/ListDetailsPage/ItemsListing.test.tsx rename to frontends/mit-open/src/page-components/ItemsListing/ItemsListing.test.tsx diff --git a/frontends/mit-open/src/pages/ListDetailsPage/ItemsListing.tsx b/frontends/mit-open/src/page-components/ItemsListing/ItemsListing.tsx similarity index 92% rename from frontends/mit-open/src/pages/ListDetailsPage/ItemsListing.tsx rename to frontends/mit-open/src/page-components/ItemsListing/ItemsListing.tsx index b01d0b96ed..ffd0c8c05c 100644 --- a/frontends/mit-open/src/pages/ListDetailsPage/ItemsListing.tsx +++ b/frontends/mit-open/src/page-components/ItemsListing/ItemsListing.tsx @@ -33,17 +33,19 @@ type ItemsListingProps = { isRefetching?: boolean emptyMessage: string sortable?: boolean + condensed?: boolean } const ItemsListingViewOnly: React.FC<{ items: NonNullable -}> = ({ items }) => { + condensed?: boolean +}> = ({ items, condensed }) => { return ( - + {items.map((item) => { return (
  • - +
  • ) })} @@ -139,11 +141,13 @@ const ItemsListing: React.FC = ({ isRefetching, emptyMessage, sortable = false, + condensed = false, }) => { return ( <> - {isLoading && } - {items.length === 0 ? ( + {isLoading ? ( + + ) : items.length === 0 ? ( {emptyMessage} ) : sortable ? ( = ({ isRefetching={isRefetching} /> ) : ( - + )} ) diff --git a/frontends/mit-open/src/page-components/ItemsListing/ItemsListingComponent.tsx b/frontends/mit-open/src/page-components/ItemsListing/ItemsListingComponent.tsx new file mode 100644 index 0000000000..524e7139f3 --- /dev/null +++ b/frontends/mit-open/src/page-components/ItemsListing/ItemsListingComponent.tsx @@ -0,0 +1,118 @@ +import React from "react" +import { Grid, Button, Typography, styled } from "ol-components" +import { RiPencilFill, RiArrowUpDownLine } from "@remixicon/react" +import { useUserMe } from "api/hooks/user" +import { useToggle, pluralize } from "ol-utilities" +import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" +import ItemsListing from "./ItemsListing" +import type { LearningResourceListItem } from "./ItemsListing" + +const Container = styled(GridContainer)` + margin-top: 30px; + margin-bottom: 100px; +` + +const TitleContainer = styled(Grid)` + margin-top: 10px; + margin-bottom: 20px; +` + +type OnEdit = () => void +type ListData = { + title: string + description?: string | null + item_count: number +} + +type ItemsListingComponentProps = { + listType: string + list?: ListData + items: LearningResourceListItem[] + isLoading: boolean + isFetching: boolean + handleEdit: OnEdit + condensed?: boolean +} + +const ItemsListingComponent: React.FC = ({ + listType, + list, + items, + isLoading, + isFetching, + handleEdit, + condensed = false, +}) => { + const { data: user } = useUserMe() + const [isSorting, toggleIsSorting] = useToggle(false) + + const canEdit = user?.is_learning_path_editor + const showSort = canEdit && !!items.length + const count = list?.item_count + + return ( + + + + + + {list?.title} + + {list?.description &&

    {list.description}

    } +
    + + {showSort && ( + + )} + {count !== undefined && count > 0 + ? `${count} ${pluralize("item", count)}` + : null} + + + {canEdit ? ( + + ) : null} + +
    + +
    +
    + ) +} + +export default ItemsListingComponent +export type { ItemsListingComponentProps } diff --git a/frontends/mit-open/src/pages/DashboardPage/DashboardPage.tsx b/frontends/mit-open/src/pages/DashboardPage/DashboardPage.tsx index 8a82fb5777..b578c594f3 100644 --- a/frontends/mit-open/src/pages/DashboardPage/DashboardPage.tsx +++ b/frontends/mit-open/src/pages/DashboardPage/DashboardPage.tsx @@ -1,3 +1,4 @@ +import React, { useCallback, useState } from "react" import { RiAccountCircleFill, RiDashboardLine, @@ -19,19 +20,12 @@ import { styled, } from "ol-components" import { MetaTags } from "ol-utilities" -import React, { useCallback, useMemo, useState } from "react" import { Link } from "react-router-dom" import { useUserMe } from "api/hooks/user" import { useLocation } from "react-router" import { UserListListingComponent } from "../UserListListingPage/UserListListingPage" import { UserList } from "api" -import { - useInfiniteUserListItems, - useUserListsDetail, -} from "api/hooks/learningResources" -import { ListDetailsComponent } from "../ListDetailsPage/ListDetailsPage" -import { ListType } from "api/constants" -import { manageListDialogs } from "@/page-components/ManageListDialogs/ManageListDialogs" + import { ProfileEditForm } from "./ProfileEditForm" import { useProfileMeQuery } from "api/hooks/profile" import { @@ -43,6 +37,7 @@ import { FREE_COURSES_CAROUSEL, } from "./carousels" import ResourceCarousel from "@/page-components/ResourceCarousel/ResourceCarousel" +import UserListDetailsTab from "./UserListDetailsTab" /** * @@ -304,30 +299,6 @@ const keyFromHash = (hash: string) => { return match ?? "home" } -interface UserListDetailsTabProps { - userListId: number -} - -const UserListDetailsTab: React.FC = (props) => { - const { userListId } = props - const listQuery = useUserListsDetail(userListId) - const itemsQuery = useInfiniteUserListItems({ userlist_id: userListId }) - const items = useMemo(() => { - const pages = itemsQuery.data?.pages - return pages?.flatMap((p) => p.results ?? []) ?? [] - }, [itemsQuery.data]) - return ( - manageListDialogs.upsertUserList(listQuery.data)} - /> - ) -} - const DashboardPage: React.FC = () => { const { isLoading: isLoadingUser, data: user } = useUserMe() const { isLoading: isLoadingProfile, data: profile } = useProfileMeQuery() diff --git a/frontends/mit-open/src/pages/DashboardPage/UserListDetailsTab.tsx b/frontends/mit-open/src/pages/DashboardPage/UserListDetailsTab.tsx new file mode 100644 index 0000000000..9e81126107 --- /dev/null +++ b/frontends/mit-open/src/pages/DashboardPage/UserListDetailsTab.tsx @@ -0,0 +1,36 @@ +import React, { useMemo } from "react" +import { + useInfiniteUserListItems, + useUserListsDetail, +} from "api/hooks/learningResources" +import { ListType } from "api/constants" +import { manageListDialogs } from "@/page-components/ManageListDialogs/ManageListDialogs" +import ItemsListingComponent from "@/page-components/ItemsListing/ItemsListingComponent" + +interface UserListDetailsTabProps { + userListId: number +} + +const UserListDetailsTab: React.FC = (props) => { + const { userListId } = props + const listQuery = useUserListsDetail(userListId) + const itemsQuery = useInfiniteUserListItems({ userlist_id: userListId }) + + const items = useMemo(() => { + const pages = itemsQuery.data?.pages + return pages?.flatMap((p) => p.results ?? []) ?? [] + }, [itemsQuery.data]) + + return ( + manageListDialogs.upsertUserList(listQuery.data)} + /> + ) +} + +export default UserListDetailsTab diff --git a/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.test.ts b/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.test.ts index 2aaaa55403..138c97c5b5 100644 --- a/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.test.ts +++ b/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.test.ts @@ -5,7 +5,7 @@ import type { PaginatedLearningPathRelationshipList, } from "api" import { manageListDialogs } from "@/page-components/ManageListDialogs/ManageListDialogs" -import ItemsListing from "./ItemsListing" +import ItemsListing from "@/page-components/ItemsListing/ItemsListing" import { learningPathsView } from "@/common/urls" import { screen, @@ -20,8 +20,10 @@ import { User } from "../../types/settings" import { ControlledPromise } from "ol-test-utilities" import invariant from "tiny-invariant" -jest.mock("./ItemsListing", () => { - const actual = jest.requireActual("./ItemsListing") +jest.mock("../../page-components/ItemsListing/ItemsListing", () => { + const actual = jest.requireActual( + "../../page-components/ItemsListing/ItemsListing", + ) return { __esModule: true, ...actual, diff --git a/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.tsx b/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.tsx index 34f34a75bc..0dd24a6ff6 100644 --- a/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.tsx +++ b/frontends/mit-open/src/pages/ListDetailsPage/ListDetailsPage.tsx @@ -1,100 +1,10 @@ import React from "react" -import { Container, Grid, Button, BannerPage, Typography } from "ol-components" -import { RiPencilFill, RiArrowUpDownLine } from "@remixicon/react" -import { useUserMe } from "api/hooks/user" -import { useToggle, pluralize, MetaTags } from "ol-utilities" -import { GridColumn, GridContainer } from "@/components/GridLayout/GridLayout" +import { Container, BannerPage } from "ol-components" +import { MetaTags } from "ol-utilities" +import ItemsListingComponent from "@/page-components/ItemsListing/ItemsListingComponent" +import type { ItemsListingComponentProps } from "@/page-components/ItemsListing/ItemsListingComponent" -import ItemsListing from "./ItemsListing" -import type { LearningResourceListItem } from "./ItemsListing" - -type OnEdit = () => void -type ListData = { - title: string - description?: string | null - item_count: number -} -type ListDetailsPageProps = { - listType: string - list?: ListData - items: LearningResourceListItem[] - isLoading: boolean - isFetching: boolean - handleEdit: OnEdit -} - -const ListDetailsComponent: React.FC = (props) => { - const { listType, list, items, isLoading, isFetching, handleEdit } = props - const { data: user } = useUserMe() - const [isSorting, toggleIsSorting] = useToggle(false) - - const canEdit = user?.is_learning_path_editor - const showSort = canEdit && !!items.length - const count = list?.item_count - return ( - - - - - - {list?.title} - - {list?.description &&

    {list.description}

    } -
    - - {showSort && ( - - )} - {count !== undefined && count > 0 - ? `${count} ${pluralize("item", count)}` - : null} - - - {canEdit ? ( - - ) : null} - -
    - -
    -
    - ) -} - -const ListDetailsPage: React.FC = ({ +const ListDetailsPage: React.FC = ({ listType, list, items, @@ -108,8 +18,8 @@ const ListDetailsPage: React.FC = ({ className="learningpaths-page" > - - + = ({ ) } -export { ListDetailsPage, ListDetailsComponent } -export type { ListDetailsPageProps } +export { ListDetailsPage }