Skip to content

Commit

Permalink
feat: use item lang instead of category lang
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia committed Oct 25, 2024
1 parent cb94f3d commit 0e6b8da
Show file tree
Hide file tree
Showing 19 changed files with 382 additions and 321 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"curly": "error",
"@typescript-eslint/indent": "off",
"@typescript-eslint/brace-style": "off",
"import/prefer-default-export": "off",
"no-underscore-dangle": [
"error",
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@emotion/server": "11.11.0",
"@emotion/styled": "11.13.0",
"@graasp/query-client": "5.0.0",
"@graasp/sdk": "4.32.1",
"@graasp/sdk": "4.33.0",
"@graasp/stylis-plugin-rtl": "2.2.0",
"@graasp/translations": "1.40.0",
"@graasp/ui": "5.4.0",
Expand Down
79 changes: 39 additions & 40 deletions src/components/collection/Collection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { validate } from 'uuid';

import { useContext, useEffect } from 'react';

import { Box } from '@mui/material';
import { Box, Skeleton } from '@mui/material';

import {
AccountType,
Expand All @@ -27,11 +27,7 @@ type Props = {
};
const Collection = ({ id }: Props) => {
const { hooks, mutations } = useContext(QueryClientContext);
const {
data: collection,
isLoading: isLoadingItem,
isError,
} = hooks.useItem(id);
const { data: collection, isLoading: isLoadingItem } = hooks.useItem(id);
const { data: currentMember } = hooks.useCurrentMember();
// get item published
const {
Expand Down Expand Up @@ -68,47 +64,50 @@ const Collection = ({ id }: Props) => {
);
}

if (isError) {
if (currentMember?.type === AccountType.Guest) {
return null;
}
if (collection) {
return (
<Box id={id} p={5}>
<Error code={ERROR_UNEXPECTED_ERROR_CODE} />
</Box>
<>
<UnpublishedItemAlert
itemId={id}
canRead={canRead}
canPublish={canPublish}
isPublished={
isLoadingPublishedEntry ||
(!!itemPublishEntry && !isErrorPublishedEntry)
}
currentMember={currentMember}
/>
<Box
id={id}
px={{
xs: 0,
sm: 2,
md: 5,
}}
py={5}
>
<Summary
collection={collection}
publishedRoot={itemPublishEntry}
isLoading={isLoadingItem}
totalViews={itemPublishEntry?.totalViews ?? 0}
/>
</Box>
</>
);
}

if (currentMember?.type === AccountType.Guest) {
return null;
if (isLoadingItem) {
return <Skeleton />;
}

return (
<>
<UnpublishedItemAlert
itemId={id}
canRead={canRead}
canPublish={canPublish}
isPublished={
isLoadingPublishedEntry ||
(!!itemPublishEntry && !isErrorPublishedEntry)
}
currentMember={currentMember}
/>
<Box
id={id}
px={{
xs: 0,
sm: 2,
md: 5,
}}
py={5}
>
<Summary
collection={collection}
publishedRoot={itemPublishEntry}
isLoading={isLoadingItem}
totalViews={itemPublishEntry?.totalViews ?? 0}
/>
</Box>
</>
<Box id={id} p={5}>
<Error code={ERROR_UNEXPECTED_ERROR_CODE} />
</Box>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/collection/summary/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import SummaryDetails from './SummaryDetails';
import SummaryHeader from './SummaryHeader';

type SummaryProps = {
collection?: DiscriminatedItem;
collection: DiscriminatedItem;
publishedRoot?: ItemPublished | null;
isLoading: boolean;
totalViews: number;
Expand Down
23 changes: 9 additions & 14 deletions src/components/collection/summary/SummaryDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
DiscriminatedItem,
formatDate,
} from '@graasp/sdk';
import { DEFAULT_LANG, langs } from '@graasp/translations';

import { CATEGORY_COLORS, UrlSearch } from '../../../config/constants';
import {
Expand Down Expand Up @@ -90,7 +91,7 @@ const CategoryDisplay = ({
};

type SummaryDetailsProps = {
collection?: DiscriminatedItem;
collection: DiscriminatedItem;
publishedRootItem?: DiscriminatedItem;
lang: string;
isLoading: boolean;
Expand Down Expand Up @@ -126,10 +127,11 @@ const SummaryDetails: React.FC<SummaryDetailsProps> = ({
?.filter((c) => c.category.type === CategoryType.Discipline)
?.map((c) => c.category);

// TODO: should use item language
const languages = itemCategories
?.filter((c) => c.category.type === CategoryType.Language)
?.map((c) => c.category);
let langValue = langs[DEFAULT_LANG];
if (collection.lang in langs) {
// @ts-ignore
langValue = langs[collection.lang];
}

return (
<Grid
Expand Down Expand Up @@ -175,17 +177,10 @@ const SummaryDetails: React.FC<SummaryDetailsProps> = ({
<Grid size={{ xs: 12, sm: 6, md: 4 }}>
<DetailCard id={SUMMARY_LANGUAGES_CONTAINER_ID}>
<Typography variant="body1" fontWeight="bold">
{t(LIBRARY.COLLECTION_LANGUAGES_TITLE)}
{t(LIBRARY.COLLECTION_LANGUAGE_TITLE)}
</Typography>
<Stack gap={1} direction="row" flexWrap="wrap">
{languages ? (
<CategoryDisplay
categories={languages}
emptyText={t(LIBRARY.SUMMARY_DETAILS_NO_LANGUAGES)}
/>
) : (
<Skeleton width="100%" />
)}
<Chip label={langValue} />
</Stack>
</DetailCard>
</Grid>
Expand Down
43 changes: 43 additions & 0 deletions src/components/filters/CategoryFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

import { Category } from '@graasp/sdk';

import { useCategoriesTranslation } from '../../config/i18n';
import { buildSearchFilterCategoryId } from '../../config/selectors';
import { Filter } from './Filter';

type FilterProps = {
category: string;
title: string;
options?: Category[];
// IDs of selected options.
selectedOptions: string[];
onOptionChange: (key: string, newValue: boolean) => void;
onClearOptions: () => void;
isLoading: boolean;
};

// eslint-disable-next-line react/function-component-definition
export function CategoryFilter({
category,
title,
onOptionChange,
onClearOptions,
options,
selectedOptions,
isLoading,
}: FilterProps) {
const { t: translateCategories } = useCategoriesTranslation();

return (
<Filter
id={buildSearchFilterCategoryId(category)}
title={title}
isLoading={isLoading}
options={options?.map((c) => [c.id, translateCategories(c.name)])}
selectedOptions={selectedOptions}
onOptionChange={onOptionChange}
onClearOptions={onClearOptions}
/>
);
}
136 changes: 136 additions & 0 deletions src/components/filters/Filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { useEffect, useRef, useState } from 'react';

import { ExpandMoreRounded } from '@mui/icons-material';
import { Box, Button, Skeleton, Stack, Typography } from '@mui/material';

import { GRAASP_COLOR } from '../../config/constants';
import { useLibraryTranslation } from '../../config/i18n';
import { buildSearchFilterPopperButtonId } from '../../config/selectors';
import LIBRARY from '../../langs/constants';
import { FilterPopper, FilterPopperProps } from './FilterPopper';

type FilterProps = {
title: string;
// IDs of selected options.
selectedOptions: string[];
isLoading?: boolean;
onClearOptions: FilterPopperProps['onClearOptions'];
onOptionChange: FilterPopperProps['onOptionChange'];
id: string;
options?: FilterPopperProps['options'];
};

// eslint-disable-next-line import/prefer-default-export
export const Filter = ({
title,
selectedOptions,
isLoading,
onClearOptions,
onOptionChange,
id,
options,
}: FilterProps) => {
const { t } = useLibraryTranslation();
const [showPopper, setShowPopper] = useState<boolean>(false);
const togglePopper = () => {
setShowPopper((oldVal) => !oldVal);
};

const popperAnchor = useRef<null | HTMLDivElement>(null);
const popper = useRef<null | HTMLDivElement>(null);

const onDocumentScrolled = () => {
setShowPopper(() => false);
};

const onDocumentClicked = (event: MouseEvent) => {
if (
!popper.current?.contains(event.target as Node) &&
!popperAnchor.current?.contains(event.target as Node)
) {
setShowPopper(() => false);
}
};
// Listens for clicks outside of the popper to dismiss it when we click outside.
useEffect(() => {
if (showPopper) {
document.addEventListener('click', onDocumentClicked);
document.addEventListener('scroll', onDocumentScrolled);
}
return () => {
document.removeEventListener('click', onDocumentClicked);
document.removeEventListener('scroll', onDocumentScrolled);
};
}, [showPopper]);

const content = isLoading ? (
<Skeleton width="100%" />
) : (
<Button
id={buildSearchFilterPopperButtonId('lang')}
onClick={togglePopper}
variant="text"
fullWidth
endIcon={<ExpandMoreRounded color="primary" />}
sx={{
textTransform: 'none',
alignItems: 'center',
paddingRight: 3,
justifyContent: 'space-between',
}}
>
<Typography
paddingLeft={1}
whiteSpace="nowrap"
width="100%"
textAlign="left"
color={selectedOptions.length ? 'black' : 'gray'}
variant="h6"
textOverflow="ellipsis"
overflow="hidden"
>
{options?.find((o) => o[0] === selectedOptions[0])?.[1] ??
t(LIBRARY.FILTER_DROPDOWN_NO_FILTER)}
</Typography>

{selectedOptions.length > 1 && (
<Box
style={{
color: GRAASP_COLOR,
fontSize: 14,
fontWeight: 'bold',
}}
>
{`+${selectedOptions.length - 1}`}
</Box>
)}
</Button>
);

return (
<Stack
id={id}
flexGrow={1}
ref={popperAnchor}
flex={1}
flexBasis={0}
width={0}
>
<Typography variant="body2" color="#7A7A7A">
{title}
</Typography>
<Stack direction="row" alignItems="center">
{content}
</Stack>
<FilterPopper
ref={popper}
open={showPopper}
options={options}
anchorEl={popperAnchor.current}
selectedOptions={selectedOptions}
onOptionChange={onOptionChange}
onClearOptions={onClearOptions}
/>
</Stack>
);
};
Loading

0 comments on commit 0e6b8da

Please sign in to comment.