Skip to content

Commit

Permalink
feat: add oer info page (to be done) (#612)
Browse files Browse the repository at this point in the history
* feat: add oer info page (to be done)

* feat: finalize oer page

* refactor: apply PR requested changes

* refactor: fix trans and tooltip for fb and twitter buttons
  • Loading branch information
pyphilia authored May 1, 2024
1 parent c1f4049 commit c719b05
Show file tree
Hide file tree
Showing 22 changed files with 699 additions and 168 deletions.
40 changes: 40 additions & 0 deletions app/oer/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Suspense } from 'react';
import { dehydrate } from 'react-query/core';

import Hydrate from '../../src/components/HydrateClient';
import Wrapper from '../../src/components/common/Wrapper';
import OERInformation from '../../src/components/pages/OERInformation';
import { APP_AUTHOR } from '../../src/config/constants';
import getQueryClient from '../../src/config/get-query-client';
import LIBRARY from '../../src/langs/constants';
import en from '../../src/langs/en.json';
import { buildSeo } from '../seo';

export async function generateMetadata() {
// todo: get lang from location and crawler
// question: how to get language from
// @ts-ignore
const t = (s: string): string => en[s];

return buildSeo({
title: t(LIBRARY.OER_INFORMATION_PAGE_TITLE),
description: t(LIBRARY.OER_INFORMATION_PAGE_DESCRIPTION),
author: APP_AUTHOR,
});
}

const Page = async () => {
const queryClient = getQueryClient();
const dehydratedState = dehydrate(queryClient);

return (
<Hydrate state={dehydratedState}>
<Suspense>
<Wrapper dehydratedState={dehydratedState}>
<OERInformation />
</Wrapper>
</Suspense>
</Hydrate>
);
};
export default Page;
61 changes: 13 additions & 48 deletions src/components/collection/Badges.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import truncate from 'lodash.truncate';
import { Stack } from '@mui/material';

import { useEffect, useState } from 'react';

import { Email, Facebook, Twitter } from '@mui/icons-material';
import { IconButton, Stack } from '@mui/material';

import {
MAIL_BREAK_LINE,
TWITTER_MESSAGE_MAX_LENGTH,
} from '../../config/constants';
import { useLibraryTranslation } from '../../config/i18n';
import LIBRARY from '../../langs/constants';
import { openInNewTab } from '../../utils/helpers';
import { removeTagsFromString } from '../../utils/text';
import EmailButton from '../common/EmailButton';
import FacebookButton from '../common/FacebookButton';
import TwitterButton from '../common/TwitterButton';

type Props = {
name?: string;
Expand All @@ -21,48 +14,20 @@ type Props = {

const Badges = ({ name, description }: Props) => {
const { t } = useLibraryTranslation();
const [pageLocation, setPageLocation] = useState<string>();
const parsedDescription = removeTagsFromString(description);

useEffect(() => {
setPageLocation(window?.location.href);
}, []);

const shareOnTwitter = () => {
const message = truncate(
`${t(LIBRARY.SHARE_TWITTER_MESSAGE, {
name,
})} ${pageLocation} : ${parsedDescription}`,
{ length: TWITTER_MESSAGE_MAX_LENGTH, separator: /,? +/ },
);
openInNewTab(`https://twitter.com/intent/tweet?text=${message}`);
};

const shareOnFacebook = () => {
const link = pageLocation;
openInNewTab(`https://www.facebook.com/sharer/sharer.php?u=${link}`);
};

const subject = `${t(LIBRARY.SHARE_FACEBOOK_SUBJECT, { name })}`;
const message = `${t(LIBRARY.SHARE_FACEBOOK_SUBJECT, {
name,
})} ${pageLocation}${MAIL_BREAK_LINE}${MAIL_BREAK_LINE}${parsedDescription}`;
const mailString = `mailto:?subject=${subject}&body=${message}`;
const parsedDescription = removeTagsFromString(description);

const iconSize = 'medium';
return (
<Stack direction="row" justifyItems="space-between" alignItems="center">
<IconButton color="primary" onClick={shareOnFacebook}>
<Facebook fontSize={iconSize} />
</IconButton>
<IconButton color="primary" onClick={shareOnTwitter}>
<Twitter fontSize={iconSize} />
</IconButton>
<a href={mailString} aria-label="Send by email">
<IconButton color="primary">
<Email fontSize={iconSize} />
</IconButton>
</a>
<FacebookButton iconSize={iconSize} />
<TwitterButton
message={`${t(LIBRARY.SHARE_TWITTER_MESSAGE, {
name,
})}: ${parsedDescription}`}
iconSize={iconSize}
/>
<EmailButton description={description} name={name} iconSize={iconSize} />
</Stack>
);
};
Expand Down
16 changes: 2 additions & 14 deletions src/components/collection/ItemCollection.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
import React from 'react';

import {
Box,
Container,
SxProps,
Theme,
Typography,
styled,
} from '@mui/material';
import { Container, SxProps, Theme, Typography } from '@mui/material';

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

import { SECTION_TITLE_ID } from '../../config/selectors';
import StyledContainer from '../layout/StyledContainer';
import CollectionsGrid from './CollectionsGrid';

const StyledContainer = styled(Box)(({ theme }) => ({
backgroundColor: 'white',
':nth-child(even)': { backgroundColor: '#fafafa' },
padding: theme.spacing(4, 3, 8, 3),
}));

type ItemCollectionProps = {
id: string;
collectionGridId?: string;
Expand Down
89 changes: 89 additions & 0 deletions src/components/collection/oer/VideoWithCC.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { List, ListItem, Stack } from '@mui/material';

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

import { useLibraryTranslation } from '../../../config/i18n';
import LIBRARY from '../../../langs/constants';
import CreativeCommons from '../../common/CreativeCommons';

type Props = {
ccLicenseAdaption?: CCLicenseAdaptions;
url: string;
title: string;
production?: string;
duration?: string;
edition?: string;
};

const VideoWithCC = ({
url,
title,
ccLicenseAdaption = CCLicenseAdaptions.CC_BY_SA,
production,
duration,
edition,
}: Props): JSX.Element => {
const { t } = useLibraryTranslation();

return (
<Stack
p={3}
borderRadius={3}
textAlign="center"
width="fit-content"
margin="auto"
border="1px solid lightgrey"
style={{
background: 'white',
}}
gap={3}
alignContent="center"
>
<iframe
style={{ margin: 'auto', border: 'none', display: 'block' }}
width="560"
height="315"
src={url}
title={title}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
/>
<Stack direction="row" justifyContent="center" alignItems="center">
<List dense>
{production && (
<ListItem>
<strong>
{t(LIBRARY.OER_INFORMATION_VIDEO_DESCRIPTION_PRODUCTION)}
</strong>
: {production}
</ListItem>
)}
{duration && (
<ListItem>
<strong>
{t(LIBRARY.OER_INFORMATION_VIDEO_DESCRIPTION_DURATION)}
</strong>
: {duration}
</ListItem>
)}
{edition && (
<ListItem>
<strong>
{t(LIBRARY.OER_INFORMATION_VIDEO_DESCRIPTION_EDITION)}
</strong>
: {edition}
</ListItem>
)}
</List>
{ccLicenseAdaption && (
<CreativeCommons
iconSize={30}
ccLicenseAdaption={ccLicenseAdaption}
/>
)}
</Stack>
</Stack>
);
};

export default VideoWithCC;
48 changes: 3 additions & 45 deletions src/components/collection/summary/SummaryDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
DiscriminatedItem,
formatDate,
} from '@graasp/sdk';
import { CCSharingVariant, CreativeCommons } from '@graasp/ui';

import { CATEGORY_COLORS, UrlSearch } from '../../../config/constants';
import {
Expand All @@ -37,6 +36,7 @@ import {
} from '../../../config/selectors';
import LIBRARY from '../../../langs/constants';
import { QueryClientContext } from '../../QueryClientContext';
import CreativeCommons from '../../common/CreativeCommons';

const DetailCard = styled(Box)(() => ({
border: '1px solid #ddd',
Expand All @@ -45,31 +45,6 @@ const DetailCard = styled(Box)(() => ({
height: '100%',
}));

const convertLicense = (ccLicenseAdaption: string) => {
// Legacy licenses.
if (['alike', 'allow'].includes(ccLicenseAdaption)) {
return {
requireAccreditation: true,
allowCommercialUse: true,
allowSharing: ccLicenseAdaption === 'alike' ? 'alike' : 'yes',
};
}

return {
requireAccreditation: ccLicenseAdaption?.includes('BY'),
allowCommercialUse: !ccLicenseAdaption?.includes('NC'),
allowSharing: (() => {
if (!ccLicenseAdaption || !ccLicenseAdaption.length) {
return '';
}
if (ccLicenseAdaption?.includes('SA')) {
return 'alike';
}
return ccLicenseAdaption?.includes('ND') ? 'no' : 'yes';
})(),
};
};

type CategoryChipProps = {
category: Category;
};
Expand Down Expand Up @@ -157,12 +132,6 @@ const SummaryDetails: React.FC<SummaryDetailsProps> = ({
?.filter((c) => c.category.type === CategoryType.Language)
?.map((c) => c.category);

const { allowSharing, allowCommercialUse, requireAccreditation } =
React.useMemo(
() => convertLicense(ccLicenseAdaption ?? ''),
[ccLicenseAdaption],
);

return (
<Grid
container
Expand Down Expand Up @@ -244,12 +213,7 @@ const SummaryDetails: React.FC<SummaryDetailsProps> = ({
{isLoading ? (
<Skeleton>
<Box maxWidth={600}>
<CreativeCommons
allowCommercialUse
allowSharedAdaptation="yes"
iconSize={48}
sx={{ marginY: 0, paddingY: 0 }}
/>
<CreativeCommons ccLicenseAdaption="CC BY-NC" />
</Box>
</Skeleton>
) : (
Expand All @@ -258,13 +222,7 @@ const SummaryDetails: React.FC<SummaryDetailsProps> = ({
className={ccLicenseAdaption}
>
{ccLicenseAdaption && ccLicenseAdaption.length > 0 ? (
<CreativeCommons
allowSharedAdaptation={allowSharing as CCSharingVariant}
allowCommercialUse={allowCommercialUse}
requireAccreditation={requireAccreditation}
iconSize={48}
sx={{ marginY: 0, paddingY: 0 }}
/>
<CreativeCommons ccLicenseAdaption={ccLicenseAdaption} />
) : (
<Typography
variant="body1"
Expand Down
Loading

0 comments on commit c719b05

Please sign in to comment.