Skip to content

Commit

Permalink
fix: shortcut and storybook build (#751)
Browse files Browse the repository at this point in the history
* fix: storybook build

* fix: shortcut

* fix: use target id in account cards for shortcut

* fix: add tests for the shortcut in recents
  • Loading branch information
spaenleh authored Jan 29, 2025
1 parent a7a3037 commit 79bc571
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 71 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/deploy-storybook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ jobs:

- name: Build storybook
run: pnpm storybook:build
env:
VITE_GRAASP_H5P_INTEGRATION_URL: http://mock.value.com
VITE_GOOGLE_KEY: 1234567890

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
Expand Down
52 changes: 51 additions & 1 deletion cypress/e2e/account/homePage.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { API_ROUTES } from '@graasp/query-client';
import { HttpMethod } from '@graasp/sdk';
import {
HttpMethod,
PackedFolderItemFactory,
PackedShortcutItemFactory,
} from '@graasp/sdk';

import { formatDistanceToNow } from 'date-fns';
import { StatusCodes } from 'http-status-codes';
Expand All @@ -25,6 +29,12 @@ import { ID_FORMAT } from '../../support/utils';

const { buildGetCurrentMemberRoute, buildUploadAvatarRoute } = API_ROUTES;

const targetItem = PackedFolderItemFactory({ name: 'Target' });
const shortcutItem = PackedShortcutItemFactory({
name: 'Shortcut',
extra: { shortcut: { target: targetItem.id } },
});

type TestHelperInput = { currentMember: MemberForTest };
class TestHelper {
private readonly currentMember: MemberForTest;
Expand Down Expand Up @@ -141,3 +151,43 @@ describe('Check member info', () => {
cy.get(`#${MEMBER_CREATED_AT_ID}`).should('contain', formattedDate);
});
});

describe('Recent items', () => {
beforeEach(() => {
cy.setUpApi({
currentMember: MEMBER_WITH_AVATAR,
items: [shortcutItem, targetItem],
});
cy.visit(ACCOUNT_HOME_PATH);
cy.wait('@getCurrentMember');
});

it('Shortcut item links to target item', () => {
cy.get(`#recentItem-${shortcutItem.id}`).should('be.visible');
cy.get(`#recentItem-${targetItem.id}`).should('be.visible');

// card action on the shortcut directs to the target item
cy.get(`a#recentItemCardAction-${shortcutItem.id}`).click();
cy.url().should('contain', `/player/${targetItem.id}/${targetItem.id}`);

// builder link
cy.visit('/account');
cy.get(`a#recentItemBuilder-${shortcutItem.id}`).click();
cy.url().should('contain', `/builder/items/${targetItem.id}`);

// player link
cy.visit('/account');
cy.get(`a#recentItemPlayer-${shortcutItem.id}`).click();
cy.url().should('contain', `/player/${targetItem.id}/${targetItem.id}`);

// analytics link
cy.visit('/account');
cy.get(`a#recentItemAnalytics-${shortcutItem.id}`).click();
cy.url().should('contain', `/analytics/items/${targetItem.id}`);

// the target item directs to the target item
cy.visit('/account');
cy.get(`a#recentItemCardAction-${targetItem.id}`).click();
cy.url().should('contain', `/player/${targetItem.id}/${targetItem.id}`);
});
});
15 changes: 0 additions & 15 deletions cypress/fixtures/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,21 +494,6 @@ export const PUBLIC_FOLDER_WITH_HIDDEN_ITEMS: { items: ItemForTest[] } = {
],
};

export const SHORTCUT = {
...DEFAULT_FOLDER_ITEM,
id: 'gcafbd2a-5688-11eb-ae92-0242ac130002',
name: 'shortcut for own_item_name1',
path: 'gcafbd2a_5688_11eb_ae92_0242ac130002',
type: ItemType.SHORTCUT,
extra: {
image: 'someimageurl',
},
settings: {
isPinned: false,
showChatbox: false,
},
};

export const generateLotsOfFoldersOnHome = ({
folderCount,
creator = DEFAULT_FOLDER_ITEM.creator,
Expand Down
4 changes: 3 additions & 1 deletion src/locales/en/builder.json
Original file line number Diff line number Diff line change
Expand Up @@ -531,5 +531,7 @@
"TAGS_DESCRITPION": "Tags are keywords or terms that you can attach to your items. They describe the subject, context, project, or intended audience of your items. They help other users to find your content when they search in the library if your collection is published. You can find out more about tags in <1>the documentation</1>.",
"TAGS_DISCIPLINE_HELPERTEXT": "Example: mathematics, history, biology",
"TAGS_LEVEL_HELPERTEXT": "Example: elementary, high school, undergraduate",
"TAGS_RESOURCE_TYPE_HELPERTEXT": "Example: article, video, quiz"
"TAGS_RESOURCE_TYPE_HELPERTEXT": "Example: article, video, quiz",
"ITEM_TYPE_COULD_NOT_BE_HANDLED": "Item type {{type}} could not be handled",
"SHORTCUT_FETCHING_ISSUE": "There was an issue fetching the content for this shortcut item."
}
86 changes: 49 additions & 37 deletions src/modules/builder/components/item/ItemContent.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import type { JSX } from 'react';
import { useTranslation } from 'react-i18next';

import { Container, Skeleton, Stack, styled } from '@mui/material';
import { Alert, Container, Skeleton, Stack, styled } from '@mui/material';

import { Api } from '@graasp/query-client';
import {
AccountType,
AppItemType,
Context,
CurrentAccount,
DocumentItemType,
EtherpadItemType,
H5PItemType,
ItemType,
LinkItemType,
LocalFileItemType,
PackedItem,
PermissionLevel,
S3FileItemType,
ShortcutItemType,
buildPdfViewerLink,
getH5PExtra,
getLinkThumbnailUrl,
getShortcutExtra,
} from '@graasp/sdk';

import { getRouteApi } from '@tanstack/react-router';

import { DEFAULT_LANG } from '@/config/constants';
import { AuthenticatedMember, useAuth } from '@/AuthContext';
import { DEFAULT_LANG, NS } from '@/config/constants';
import { API_HOST, GRAASP_ASSETS_URL, H5P_INTEGRATION_URL } from '@/config/env';
import { axios, hooks } from '@/config/queryClient';
import {
Expand Down Expand Up @@ -101,7 +102,7 @@ const LinkContent = ({
member,
}: {
item: LinkItemType;
member?: CurrentAccount | null;
member?: { id: string } | null;
}): JSX.Element => (
<LinkItem
id={item.id}
Expand Down Expand Up @@ -130,11 +131,11 @@ const DocumentContent = ({ item }: { item: DocumentItemType }): JSX.Element => (
const AppContent = ({
item,
member,
permission = PermissionLevel.Read,
permission,
}: {
item: AppItemType;
member?: CurrentAccount | null;
permission?: PermissionLevel;
member?: AuthenticatedMember | null;
permission?: PermissionLevel | null;
}): JSX.Element => (
<AppItem
isResizable={false}
Expand All @@ -149,12 +150,9 @@ const AppContent = ({
apiHost: API_HOST,
itemId: item.id,
accountId: member?.id,
permission,
permission: permission ?? PermissionLevel.Read,
settings: item.settings,
lang:
item.lang ||
(member?.type === AccountType.Individual && member?.extra?.lang) ||
DEFAULT_LANG,
lang: item.lang || member?.lang || DEFAULT_LANG,
context: Context.Builder,
}}
/>
Expand All @@ -180,6 +178,25 @@ const H5PContent = ({ item }: { item: H5PItemType }): JSX.Element => {
);
};

/**
* Helper component to render typed Shortcut items
*/
const ShortcutContent = ({ item }: { item: ShortcutItemType }): JSX.Element => {
const { t } = useTranslation(NS.Builder);
const extra = getShortcutExtra(item?.extra);
const { data: targetItem, isFetching } = hooks.useItem(extra.target);

if (targetItem) {
return <ItemContent item={targetItem} />;
}

if (isFetching) {
return <Skeleton width="100%" height="200px" />;
}

return <Alert severity="error">{t('SHORTCUT_FETCHING_ISSUE')}</Alert>;
};

/**
* Helper component to render typed Etherpad items
*/
Expand Down Expand Up @@ -210,24 +227,12 @@ const EtherpadContent = ({ item }: { item: EtherpadItemType }): JSX.Element => {
);
};

const itemRoute = getRouteApi('/builder/items/$itemId');
/**
* Main item renderer component
*/
const ItemContent = (): JSX.Element => {
const { data: member, isLoading, isError } = hooks.useCurrentMember();
// const { item, permission } = useOutletContext<OutletType>();
const { itemId } = itemRoute.useParams();
const { data: item } = hooks.useItem(itemId);
const permission = item?.permission ?? undefined;

if (isLoading) {
return <Loader />;
}

if (!item || !item.id || isError) {
return <ErrorAlert id={ITEM_SCREEN_ERROR_ALERT_ID} />;
}
export function ItemContent({ item }: Readonly<{ item: PackedItem }>) {
const { t } = useTranslation(NS.Builder);
const { user: member } = useAuth();

switch (item.type) {
case ItemType.LOCAL_FILE:
Expand All @@ -239,21 +244,28 @@ const ItemContent = (): JSX.Element => {
case ItemType.DOCUMENT:
return <DocumentContent item={item} />;
case ItemType.APP:
return <AppContent item={item} member={member} permission={permission} />;
return (
<AppContent item={item} member={member} permission={item?.permission} />
);
case ItemType.FOLDER:
return <FolderContent item={item} />;

case ItemType.H5P: {
return <H5PContent item={item} />;
}

case ItemType.ETHERPAD: {
return <EtherpadContent item={item} />;
}
case ItemType.SHORTCUT: {
return <ShortcutContent item={item} />;
}

default:
return <ErrorAlert id={ITEM_SCREEN_ERROR_ALERT_ID} />;
return (
<Alert id={ITEM_SCREEN_ERROR_ALERT_ID} severity="error">
{t('ITEM_TYPE_COULD_NOT_BE_HANDLED', {
type: item['type'],
})}
</Alert>
);
}
};

export default ItemContent;
}
31 changes: 22 additions & 9 deletions src/modules/player/common/ItemCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';

import { Box, Card, Stack, Typography } from '@mui/material';

import { PackedItem, formatDate } from '@graasp/sdk';
import { ItemType, PackedItem, formatDate } from '@graasp/sdk';

import { Link } from '@tanstack/react-router';

Expand All @@ -22,21 +22,28 @@ type Props = {
const SimpleCard = ({ item }: Props): JSX.Element => {
const { i18n } = useTranslation(NS.Player);

const itemId =
item.type === ItemType.SHORTCUT ? item.extra.shortcut.target : item.id;

return (
<Card>
<Card id={`recentItem-${item.id}`}>
<Stack
direction="row"
alignItems="center"
alignItems="stretch"
justifyContent="space-between"
width="100%"
>
<CardActionAreaLink
id={`recentItemCardAction-${item.id}`}
to="/player/$rootId/$itemId"
params={{ rootId: item.id, itemId: item.id }}
params={{ rootId: itemId, itemId: itemId }}
sx={{
minWidth: 0,
width: '100%',
p: 2,
flex: 1,
display: 'flex',
alignItems: 'center',
padding: 2,
}}
>
<Stack direction="row" spacing={2} width="100%" minWidth={0}>
Expand Down Expand Up @@ -66,10 +73,11 @@ const SimpleCard = ({ item }: Props): JSX.Element => {
</Stack>
</Stack>
</CardActionAreaLink>
<Stack paddingInlineEnd={2}>
<Stack p={1}>
<Link
id={`recentItemBuilder-${item.id}`}
to="/builder/items/$itemId"
params={{ itemId: item.id }}
params={{ itemId }}
style={{ minHeight: 0 }}
>
<BuildIcon
Expand All @@ -80,8 +88,9 @@ const SimpleCard = ({ item }: Props): JSX.Element => {
/>
</Link>
<Link
id={`recentItemPlayer-${item.id}`}
to="/player/$rootId/$itemId"
params={{ rootId: item.id, itemId: item.id }}
params={{ rootId: itemId, itemId }}
style={{ minHeight: 0 }}
>
<PlayIcon
Expand All @@ -91,7 +100,11 @@ const SimpleCard = ({ item }: Props): JSX.Element => {
sx={{ display: 'block' }}
/>
</Link>
<Link to="/analytics/items/$itemId" params={{ itemId: item.id }}>
<Link
id={`recentItemAnalytics-${item.id}`}
to="/analytics/items/$itemId"
params={{ itemId }}
>
<AnalyticsIcon
size={30}
secondaryColor="white"
Expand Down
Loading

0 comments on commit 79bc571

Please sign in to comment.