Skip to content

Commit

Permalink
feat: add detail taxonomy page
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido committed Oct 20, 2023
1 parent 60b4359 commit a52cc85
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 8 deletions.
19 changes: 13 additions & 6 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import CourseAuthoringRoutes from './CourseAuthoringRoutes';
import Head from './head/Head';
import { StudioHome } from './studio-home';
import CourseRerun from './course-rerun';
import { TaxonomyListPage } from './taxonomy';
import { TaxonomyDetailPage, TaxonomyListPage } from './taxonomy';

import 'react-datepicker/dist/react-datepicker.css';
import './index.scss';
Expand Down Expand Up @@ -71,11 +71,18 @@ const App = () => {
}}
/>
{process.env.ENABLE_TAGGING_TAXONOMY_PAGES === 'true' && (
<Route
path="/taxonomy-list"
>
<TaxonomyListPage />
</Route>
<>
<Route exact path="/taxonomy-list/" component={TaxonomyListPage} />
<Route
path="/taxonomy-list/:taxonomyId"
render={({ match }) => {
const { params: { taxonomyId } } = match;
return (
<TaxonomyDetailPage taxonomyId={Number(taxonomyId)} />
);
}}
/>
</>
)}
</Switch>
</QueryClientProvider>
Expand Down
20 changes: 20 additions & 0 deletions src/taxonomy/api/hooks/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
const getTaxonomyListApiUrl = () => new URL('api/content_tagging/v1/taxonomies/?enabled=true', getApiBaseUrl()).href;
const getExportTaxonomyApiUrl = (pk, format) => new URL(
`api/content_tagging/v1/taxonomies/${pk}/export/?output_format=${format}`,
);

/**
* @param {number} taxonomyId
*/
export const getTaxonomyDetailApiUrl = (taxonomyId) => new URL(
`api/content_tagging/v1/taxonomies/${taxonomyId}/`,
getApiBaseUrl(),
).href;

Expand Down Expand Up @@ -51,3 +58,16 @@ export const useExportTaxonomy = () => {

return useMutation(exportTaxonomy);
};

/**
* @param {number} taxonomyId
* @returns {import('@tanstack/react-query').UseQueryResult<import('../types.mjs').TaxonomyData>}
*/
export const useTaxonomyDetailData = (taxonomyId) => (
useQuery({
queryKey: ['taxonomyList', taxonomyId],
queryFn: () => getAuthenticatedHttpClient().get(getTaxonomyDetailApiUrl(taxonomyId))
.then(camelCaseObject)
.then((response) => response.data),
})
);
34 changes: 33 additions & 1 deletion src/taxonomy/api/hooks/selectors.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-check
import {
useTaxonomyDetailData,
useTaxonomyListData,
useExportTaxonomy,
} from './api';
Expand All @@ -10,7 +11,7 @@ import {
export const useTaxonomyListDataResponse = () => {
const response = useTaxonomyListData();
if (response.status === 'success') {
return response.data.data;
return response.data;
}
return undefined;
};
Expand All @@ -25,3 +26,34 @@ export const useIsTaxonomyListDataLoaded = () => (
export const useExportTaxonomyMutation = () => (
useExportTaxonomy()
);
/**
* @params {number} taxonomyId
* @returns {Pick<import('@tanstack/react-query').UseQueryResult, "error" | "isError" | "isFetched" | "isSuccess">}
*/
export const useTaxonomyDetailDataStatus = (taxonomyId) => {
const {
isError,
error,
isFetched,
isSuccess,
} = useTaxonomyDetailData(taxonomyId);
return {
isError,
error,
isFetched,
isSuccess,
};
};

/**
* @params {number} taxonomyId
* @returns {import("../types.mjs").TaxonomyData | undefined}
*/
export const useTaxonomyDetailDataResponse = (taxonomyId) => {
const { isSuccess, data } = useTaxonomyDetailData(taxonomyId);
if (isSuccess) {
return data;
}

return undefined;
};
2 changes: 1 addition & 1 deletion src/taxonomy/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export { default as TaxonomyListPage } from './TaxonomyListPage';
export { TaxonomyDetailPage } from './taxonomy-detail';
42 changes: 42 additions & 0 deletions src/taxonomy/taxonomy-detail/TagListTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
DataTable,
TextFilter,
} from '@edx/paragon';
import Proptypes from 'prop-types';

const tagsSample = [
{ name: 'Tag 1' },
{ name: 'Tag 2' },
{ name: 'Tag 3' },
{ name: 'Tag 4' },
{ name: 'Tag 5' },
{ name: 'Tag 6' },
{ name: 'Tag 7' },
];

const TagListTable = ({ tags }) => (

Check failure on line 17 in src/taxonomy/taxonomy-detail/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

'tags' is defined but never used
<DataTable
isFilterable
isSortable
defaultColumnValues={{ Filter: TextFilter }}
itemCount={tagsSample.length}
data={tagsSample}
columns={[
{
Header: 'Name',
accessor: 'name',
},
]}
>
<DataTable.TableControlBar />
<DataTable.Table />
<DataTable.EmptyTable content="No results found" />
<DataTable.TableFooter />
</DataTable>
);

TagListTable.propTypes = {
tags: Proptypes.array.isRequired,

Check failure on line 39 in src/taxonomy/taxonomy-detail/TagListTable.jsx

View workflow job for this annotation

GitHub Actions / tests

Prop type "array" is forbidden
};

export default TagListTable;
97 changes: 97 additions & 0 deletions src/taxonomy/taxonomy-detail/TaxonomyDetailPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import {
Container,
Layout,
} from '@edx/paragon';
import Proptypes from 'prop-types';

import PermissionDeniedAlert from '../../generic/PermissionDeniedAlert';
import Loading from '../../generic/Loading';
import Header from '../../header';
import SubHeader from '../../generic/sub-header/SubHeader';
import TaxonomyDetailSideCard from './TaxonomyDetailSideCard';
import TagListTable from './TagListTable';
import { useTaxonomyDetailDataResponse, useTaxonomyDetailDataStatus } from '../api/hooks/selectors';

const TaxonomyDetailContent = ({ taxonomyId }) => {
const useTaxonomyDetailData = () => {
const { isError, isFetched } = useTaxonomyDetailDataStatus(taxonomyId);
const taxonomy = useTaxonomyDetailDataResponse(taxonomyId);
return { isError, isFetched, taxonomy };
};

const { isError, isFetched, taxonomy } = useTaxonomyDetailData(taxonomyId);

if (isError) {
return (
<PermissionDeniedAlert />
);
}

if (!isFetched) {
return (
<Loading />
);
}

if (taxonomy) {
return (
<>
<div className="pt-4.5 pr-4.5 pl-4.5 pb-2 bg-light-100 box-shadow-down-2">
<Container size="xl">
<SubHeader
title={taxonomy.name}
hideBorder
/>
</Container>
</div>
<div className="bg-light-400 m-4">
<Layout
lg={[{ span: 9 }, { span: 3 }]}
md={[{ span: 9 }, { span: 3 }]}
sm={[{ span: 9 }, { span: 3 }]}
xs={[{ span: 9 }, { span: 3 }]}
xl={[{ span: 9 }, { span: 3 }]}
>
<Layout.Element>
<TagListTable />
</Layout.Element>
<Layout.Element>
<TaxonomyDetailSideCard taxonomy={taxonomy} />
</Layout.Element>

</Layout>
</div>
</>
);
}

return undefined;
};

const TaxonomyDetailPage = ({ taxonomyId }) => (
<>
<style>
{`
body {
background-color: #E9E6E4; /* light-400 */
}
`}
</style>
<Header isHiddenMainMenu />
<TaxonomyDetailContent taxonomyId={taxonomyId} />
</>
);

TaxonomyDetailPage.propTypes = {
taxonomyId: Proptypes.number,
};

TaxonomyDetailPage.defaultProps = {
taxonomyId: undefined,
};

TaxonomyDetailContent.propTypes = TaxonomyDetailPage.propTypes;
TaxonomyDetailContent.defaultProps = TaxonomyDetailPage.defaultProps;

export default TaxonomyDetailPage;
27 changes: 27 additions & 0 deletions src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
Card,
} from '@edx/paragon';
import Proptypes from 'prop-types';

const TaxonomyDetailSideCard = ({ taxonomy }) => (
<Card>
<Card.Header title="Taxonomy details" />
<Card.Section title="Title">
{taxonomy.name}
</Card.Section>
<Card.Divider className="ml-3 mr-3" />
<Card.Section title="Description">
{taxonomy.description}
</Card.Section>
<Card.Divider className="ml-3 mr-3" />
<Card.Section title="Copyright">
No copyright added
</Card.Section>
</Card>
);

TaxonomyDetailSideCard.propTypes = {
taxonomy: Proptypes.object.isRequired,

Check failure on line 24 in src/taxonomy/taxonomy-detail/TaxonomyDetailSideCard.jsx

View workflow job for this annotation

GitHub Actions / tests

Prop type "object" is forbidden
};

export default TaxonomyDetailSideCard;
2 changes: 2 additions & 0 deletions src/taxonomy/taxonomy-detail/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export { default as TaxonomyDetailPage } from './TaxonomyDetailPage';

0 comments on commit a52cc85

Please sign in to comment.