Skip to content

Commit

Permalink
Merge pull request #241 from graasp/237/Categories
Browse files Browse the repository at this point in the history
237/categories
added category selection menu
  • Loading branch information
louisewang1 authored Dec 2, 2021
2 parents 618cffd + c4e4992 commit eaca02f
Show file tree
Hide file tree
Showing 8 changed files with 620 additions and 413 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "AGPL-3.0-only",
"dependencies": {
"@graasp/chatbox": "git://github.com/graasp/graasp-chatbox.git#main",
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git#85/thumbnails",
"@graasp/query-client": "git://github.com/graasp/graasp-query-client.git",
"@graasp/ui": "git://github.com/graasp/graasp-ui.git",
"@material-ui/core": "4.11.2",
"@material-ui/icons": "5.0.0-beta.4",
Expand Down Expand Up @@ -35,7 +35,7 @@
"react-beautiful-dnd": "13.1.0",
"react-dom": "^17.0.1",
"react-i18next": "11.11.4",
"react-query": "3.16.0",
"react-query": "3.31.0",
"react-quill": "1.3.5",
"react-redux": "7.2.2",
"react-redux-toastr": "7.6.5",
Expand Down
2 changes: 1 addition & 1 deletion src/components/RecycleBinScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const RowActions = ({ data: item }) => (
</>
);
RowActions.propTypes = {
data: PropTypes.shape({}).isRequired,
data: PropTypes.shape({ id: PropTypes.string }).isRequired,
};

const ToolbarActions = ({ selectedIds }) => (
Expand Down
177 changes: 177 additions & 0 deletions src/components/item/sharing/CategorySelection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Loader } from '@graasp/ui';
import { Map } from 'immutable';
import { makeStyles } from '@material-ui/core/styles';
import { useTranslation } from 'react-i18next';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { useParams } from 'react-router';
import { MUTATION_KEYS } from '@graasp/query-client';
import { hooks, useMutation } from '../../../config/queryClient';
import {
SHARE_ITEM_CATEGORY_AGE,
SHARE_ITEM_CATEGORY_DISCIPLINE,
} from '../../../config/selectors';
import { CurrentUserContext } from '../../context/CurrentUserContext';

const { useCategoryTypes, useCategories, useItemCategories } = hooks;
const { POST_ITEM_CATEGORY, DELETE_ITEM_CATEGORY } = MUTATION_KEYS;

const SELECT_OPTION = 'select-option';
const REMOVE_OPTION = 'remove-option';

const useStyles = makeStyles((theme) => ({
selection: {
marginTop: theme.spacing(2),
},
dropMenu: {
marginBottom: theme.spacing(1),
},
}));

function CategorySelection({ item, edit }) {
const { t } = useTranslation();
const classes = useStyles();
const { mutate: createItemCategory } = useMutation(POST_ITEM_CATEGORY);
const { mutate: deleteItemCategory } = useMutation(DELETE_ITEM_CATEGORY);

// user
const { isLoading: isMemberLoading } = useContext(CurrentUserContext);

// current item
const { itemId } = useParams();

// get itemCategories, categoryTypes and allCategories
const {
data: itemCategories,
isLoading: isItemCategoriesLoading,
} = useItemCategories(itemId);
const {
data: categoryTypes,
isLoading: isCategoryTypesLoading,
} = useCategoryTypes();
const {
data: allCategories,
isLoading: isCategoriesLoading,
} = useCategories();

// process data
const categoriesMap = allCategories?.groupBy((entry) => entry.type);
const ageList = categoriesMap
?.get(categoryTypes?.filter((type) => type.name === 'age').get(0).id)
.toArray();
const disciplineList = categoriesMap
?.get(categoryTypes?.filter((type) => type.name === 'discipline').get(0).id)
.toArray();

// initialize state variable
const [selectedValues, setSelectedValues] = useState([]);

// update state variables depending on fetch values
useEffect(() => {
if (itemCategories && allCategories)
setSelectedValues(
allCategories
?.filter((entry) =>
itemCategories?.map((obj) => obj.categoryId).includes(entry.id),
)
.toArray(),
);
}, [item, itemCategories, allCategories]);

if (
isMemberLoading ||
isItemCategoriesLoading ||
isCategoryTypesLoading ||
isCategoriesLoading
) {
return <Loader />;
}

const handleChange = (categoryType) => (event, value, reason) => {
const typeMap = { age: ageList, discipline: disciplineList };
if (reason === SELECT_OPTION) {
// post new category
const newCategoryId = value.at(-1).id;
createItemCategory({
itemId,
categoryId: newCategoryId,
});
} else if (reason === REMOVE_OPTION) {
// remove an option
const previousValues = typeMap[categoryType]?.filter((entry) =>
selectedValues.includes(entry),
);
const result = previousValues.filter(
({ id: id1 }) => !value.some(({ id: id2 }) => id2 === id1),
);
const deletedEntry = itemCategories.find(
(entry) => entry.categoryId === result[0].id,
);
deleteItemCategory({
itemId,
entryId: deletedEntry.id,
});
}
};

/* eslint-disable react/jsx-props-no-spreading */
return (
<>
<Typography variant="h6" className={classes.Selection}>
{t('Category')}
</Typography>
<Typography variant="body1">{t('Age Range')}</Typography>
{edit && (
<Autocomplete
multiple
disableClearable
id={SHARE_ITEM_CATEGORY_AGE}
value={ageList?.filter((value) => selectedValues.includes(value))}
getOptionSelected={(option, value) => option.id === value.id}
options={ageList}
getOptionLabel={(option) => option.name}
onChange={handleChange('age')}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder={t('Please Choose From List')}
/>
)}
/>
)}
<Typography variant="body1">{t('Discipline')}</Typography>
{edit && (
<Autocomplete
multiple
disableClearable
id={SHARE_ITEM_CATEGORY_DISCIPLINE}
value={disciplineList?.filter((value) =>
selectedValues.includes(value),
)}
getOptionSelected={(option, value) => option.id === value.id}
options={disciplineList}
getOptionLabel={(option) => option.name}
onChange={handleChange('discipline')}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder={t('Please Choose From List')}
/>
)}
/>
)}
</>
);
}

CategorySelection.propTypes = {
item: PropTypes.instanceOf(Map).isRequired,
edit: PropTypes.bool.isRequired,
};

export default CategorySelection;
2 changes: 2 additions & 0 deletions src/components/item/sharing/ItemSharingTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { PSEUDONIMIZED_USER_MAIL } from '../../../config/constants';
import { getItemLoginSchema } from '../../../utils/itemExtra';
import { LayoutContext } from '../../context/LayoutContext';
import { CurrentUserContext } from '../../context/CurrentUserContext';
import CategorySelection from './CategorySelection';

const useStyles = makeStyles((theme) => ({
title: {
Expand Down Expand Up @@ -128,6 +129,7 @@ const ItemSharingTab = ({ item, memberships }) => {
<SharingLink itemId={item.get('id')} />

<VisibilitySelect item={item} edit={canEdit} />
<CategorySelection item={item} edit={canEdit} />

{renderMembershipSettings()}
</Container>
Expand Down
4 changes: 3 additions & 1 deletion src/components/table/DragCellRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ const DragCellRenderer = ({ data: item, registerRowDragger }) => {
};

DragCellRenderer.propTypes = {
data: PropTypes.shape({}).isRequired,
data: PropTypes.shape({
id: PropTypes.string,
}).isRequired,
registerRowDragger: PropTypes.func.isRequired,
};

Expand Down
7 changes: 6 additions & 1 deletion src/components/table/NameCellRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ const NameCellRenderer = ({ data: item }) => {
};

NameCellRenderer.propTypes = {
data: PropTypes.shape({}).isRequired,
data: PropTypes.shape({
type: PropTypes.string,
id: PropTypes.string,
name: PropTypes.string,
extra: PropTypes.shape({}),
}).isRequired,
};

export default NameCellRenderer;
2 changes: 2 additions & 0 deletions src/config/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ export const CHATBOX_ID = 'chatbox';
export const CHATBOX_INPUT_BOX_ID = 'chatboxInputBox';
export const CONFIRM_RECYCLE_BUTTON_ID = 'confirmRecycleButton';
export const SHARE_ITEM_VISIBILITY_SELECT_ID = 'shareItemVisiblitySelect';
export const SHARE_ITEM_CATEGORY_AGE = 'shareItemCategoryAge';
export const SHARE_ITEM_CATEGORY_DISCIPLINE = 'shareItemCategoryDiscipline';
export const SHARE_ITEM_PSEUDONYMIZED_SCHEMA_ID =
'shareItemPseudonymizedSchema';
export const ITEM_RECYCLE_BUTTON_CLASS = 'itemRecycleButton';
Expand Down
Loading

0 comments on commit eaca02f

Please sign in to comment.