diff --git a/cypress/support/commands/item.ts b/cypress/support/commands/item.ts index 51472ad06..a802f9598 100644 --- a/cypress/support/commands/item.ts +++ b/cypress/support/commands/item.ts @@ -1,7 +1,7 @@ import { ItemType, getAppExtra, getDocumentExtra } from '@graasp/sdk'; import { - CUSTOM_APP_CYPRESS_ID, + CUSTOM_APP_BUTTON_ID, CUSTOM_APP_URL_ID, FOLDER_FORM_DESCRIPTION_ID, HOME_MODAL_ITEM_ID, @@ -155,7 +155,7 @@ Cypress.Commands.add( if (type) { cy.get(`#${ITEM_FORM_APP_URL_ID}`).type(getAppExtra(extra)?.url); } else if (custom) { - cy.get(`#${buildItemFormAppOptionId(CUSTOM_APP_CYPRESS_ID)}`).click(); + cy.get(`#${buildItemFormAppOptionId(CUSTOM_APP_BUTTON_ID)}`).click(); // check name get added automatically cy.fillBaseItemModal({ name }, { confirm: false }); cy.get(`#${CUSTOM_APP_URL_ID}`).type(CUSTOM_APP_URL); diff --git a/src/components/item/form/AppForm.tsx b/src/components/item/form/AppForm.tsx index f7102e3f8..df17dee96 100644 --- a/src/components/item/form/AppForm.tsx +++ b/src/components/item/form/AppForm.tsx @@ -1,68 +1,109 @@ import { ChangeEventHandler, useState } from 'react'; -import { ArrowBack } from '@mui/icons-material'; -import { Alert, Box, Stack, TextField, Typography } from '@mui/material'; -import Grid2 from '@mui/material/Unstable_Grid2/Grid2'; +import { Add, ArrowBack } from '@mui/icons-material'; +import { Alert, Stack, TextField, Typography, alpha } from '@mui/material'; -import { DiscriminatedItem, ItemType, buildAppExtra } from '@graasp/sdk'; +import { App, DiscriminatedItem, ItemType, buildAppExtra } from '@graasp/sdk'; import { Button } from '@graasp/ui'; import AppCard from '@/components/main/AppCard'; -import { CUSTOM_APP_CYPRESS_ID, CUSTOM_APP_URL_ID } from '@/config/selectors'; +import { CUSTOM_APP_BUTTON_ID, CUSTOM_APP_URL_ID } from '@/config/selectors'; +import defaultImage from '@/resources/defaultApp.png'; import { sortByName } from '@/utils/item'; import { useBuilderTranslation } from '../../../config/i18n'; import { hooks } from '../../../config/queryClient'; import { BUILDER } from '../../../langs/constants'; -import addNewImage from '../../../resources/addNew.png'; import NameForm from './NameForm'; type AppGridProps = { + showFull: boolean; currentUrl: string; handleSelection: (value: null | { name: string; url: string }) => void; searchQuery?: string; }; +type MostUsedApp = { + url: string; + name: string; + count: number; +}; + +type AppCardListProps = { + apps: (App | MostUsedApp)[]; + currentUrl: string; + handleSelection: (value: null | { name: string; url: string }) => void; + searchQuery?: string; +}; + +const AppCardList = ({ + apps, + currentUrl, + handleSelection, + searchQuery, +}: AppCardListProps) => { + // filter out with search query + const dataToShow = searchQuery + ? apps.filter((app) => + app.name.toLowerCase().includes(searchQuery.toLowerCase()), + ) + : apps; + dataToShow.sort(sortByName); + return ( + <> + {dataToShow.map((ele) => ( + { + if (ele.url === currentUrl) { + // reset fields + handleSelection(null); + } else { + handleSelection({ url: ele.url, name: ele.name }); + } + }} + /> + ))} + + ); +}; + const AppGrid = ({ + showFull, currentUrl, handleSelection, searchQuery, }: AppGridProps): JSX.Element | JSX.Element[] => { - const { useApps } = hooks; - const { data, isLoading } = useApps(); - + const { useApps, useMostUsedApps } = hooks; + const { data: allApps, isLoading } = useApps(); + const { data: mostUsedApps } = useMostUsedApps(); const { t: translateBuilder } = useBuilderTranslation(); - if (data) { - // filter out with search query - const dataToShow = searchQuery - ? data.filter((d) => - d.name.toLowerCase().includes(searchQuery.toLowerCase()), - ) - : data; - dataToShow.sort(sortByName); + // at first, try to present the user the 'most used' data + if (mostUsedApps && mostUsedApps.length !== 0 && !showFull) { + return ( + + ); + } + if (allApps) { return ( - <> - {dataToShow.map((ele) => ( - { - if (ele.url === currentUrl) { - // reset fields - handleSelection(null); - } else { - handleSelection({ url: ele.url, name: ele.name }); - } - }} - /> - ))} - + ); } @@ -85,6 +126,7 @@ type Props = { }; const AppForm = ({ onChange, updatedProperties = {} }: Props): JSX.Element => { + const [showFull, setShowFull] = useState(false); const { t: translateBuilder } = useBuilderTranslation(); const [isCustomApp, setIsCustomApp] = useState(false); @@ -168,39 +210,75 @@ const AppForm = ({ onChange, updatedProperties = {} }: Props): JSX.Element => { ); } return ( - - - - + + + + + {!showFull + ? translateBuilder(BUILDER.APP_SECTION_MOST_USED) + : translateBuilder(BUILDER.APP_SECTION_ALL_APP)} + + + + - - - + + + + + {translateBuilder(BUILDER.CREATE_CUSTOM_APP_LABEL)} + + + ( - - - { + const theme = useTheme(); + return ( + + - - - - - - - {name ?? } - - - {description ?? } - - - - - - -); -const AppCardWrapper = (props: Props): JSX.Element => ( - - - -); + + + + + + + + + {name ?? } + + + {description ?? ''} + + + + + + + + ); +}; -export default AppCardWrapper; +export default AppCard; diff --git a/src/config/selectors.ts b/src/config/selectors.ts index 1fd773ba4..64f88aedc 100644 --- a/src/config/selectors.ts +++ b/src/config/selectors.ts @@ -123,7 +123,7 @@ export const buildItemFormAppOptionId = (id?: string): string => export const TEXT_EDITOR_CLASS = 'ql-editor'; export const buildSaveButtonId = (id: string): string => `saveButton-${id}`; export const buildCancelButtonId = (id: string): string => `cancelButton-${id}`; -export const CUSTOM_APP_CYPRESS_ID = 'custom-app'; +export const CUSTOM_APP_BUTTON_ID = 'custom-app'; export const FLAVOR_SELECT_ID = 'flavorSelect'; export const REDIRECTION_CONTENT_ID = 'redirectionContent'; diff --git a/src/langs/constants.ts b/src/langs/constants.ts index abc1a453c..749f8e90f 100644 --- a/src/langs/constants.ts +++ b/src/langs/constants.ts @@ -424,7 +424,13 @@ export const BUILDER = { APPROVE_BUTTON_TEXT: 'APPROVE_BUTTON_TEXT', APP_URL: 'APP_URL', CREATE_APP_SEARCH_FIELD_HELPER: 'CREATE_APP_SEARCH_FIELD_HELPER', + APP_SECTION_MOST_USED: 'APP_SECTION_MOST_USED', + APP_SECTION_MOST_USED_BUTTON_TEXT: 'APP_SECTION_MOST_USED_BUTTON_TEXT', + APP_SECTION_ALL_APP: 'APP_SECTION_ALL_APP', + APP_SECTION_ALL_APP_BUTTON_TEXT: 'APP_SECTION_ALL_APP_BUTTON_TEXT', + ADD_BUILT_IN_APP_TEXT: 'ADD_BUILT_IN_APP_TEXT', CREATE_CUSTOM_APP: 'CREATE_CUSTOM_APP', + CREATE_CUSTOM_APP_LABEL: 'CREATE_CUSTOM_APP_LABEL', CREATE_CUSTOM_APP_DESCRIPTION: 'CREATE_CUSTOM_APP_DESCRIPTION', DOWNGRADE_PERMISSION_TITLE: 'DOWNGRADE_PERMISSION_TITLE', DOWNGRADE_PERMISSION_DESCRIPTION: 'DOWNGRADE_PERMISSION_DESCRIPTION', diff --git a/src/langs/en.json b/src/langs/en.json index a266cfd01..667bdb6ce 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -76,7 +76,7 @@ "EDIT_ITEM_MODAL_TITLE": "Edit Item", "EDIT_ITEM_IMAGE_ALT_TEXT_LABEL": "Alternative text (for accessibility purposes)", "EMPTY_ITEM_MESSAGE": "This item is empty.", - "ERROR_MESSAGE": "An error occured.", + "ERROR_MESSAGE": "An error occurred.", "BOOKMARKED_ITEM_ADD_TEXT": "Add to Bookmarks", "BOOKMARKED_ITEM_REMOVE_TEXT": "Remove from Bookmarks", "BOOKMARKED_ITEMS_TITLE": "Bookmarks", @@ -184,7 +184,7 @@ "LIBRARY_SETTINGS_PUBLISH_BUTTON": "Publish", "LIBRARY_SETTINGS_PUBLISH_BUTTON_DISABLED": "Published", "LIBRARY_SETTINGS_PUBLISH_NOTIFICATIONS_LABEL": "Send email notifications to all co-editors", - "LIBRARY_SETTINGS_PUBLISHED_STATUS": "This element is published. Anyone can access it and is available on Graasp Library, our public repository of learning ressources.", + "LIBRARY_SETTINGS_PUBLISHED_STATUS": "This element is published. Anyone can access it and is available on Graasp Library, our public repository of learning resources.", "LIBRARY_SETTINGS_CHILD_PUBLISHED_STATUS": "This element is part of a collection that is already published. Publishing and un-publishing can be done at the collection root.", "LIBRARY_SETTINGS_TYPE_NOT_ALLOWED_STATUS_one": "This element cannot be published. Only a {{allowedItemTypes}} is allowed to be published on Graasp Library.", "LIBRARY_SETTINGS_TYPE_NOT_ALLOWED_STATUS_other": "This element cannot be published. Only the {{allowedItemTypes}} are allowed to be published on Graasp Library.", @@ -345,9 +345,16 @@ "DELETE_LAST_ADMIN_ALERT_MESSAGE": "You are not allowed to delete this admin as this is the only admin", "APPROVE_BUTTON_TEXT": "OK", "APP_URL": "App Url", + "APP_SECTION_ALL_APP": "All Applications", + "APP_SECTION_MOST_USED": "Most Used", + "APP_SECTION_ALL_APP_BUTTON_TEXT": "Show all applications", + "APP_SECTION_MOST_USED_BUTTON_TEXT": "Show most used applications", + "ADD_BUILT_IN_APP_TEXT": "Search the application here...", "CREATE_CUSTOM_APP": "Add Your Custom App", "CREATE_APP_SEARCH_FIELD_HELPER": "Search for an app", - "CREATE_CUSTOM_APP_DESCRIPTION": "Advanced option to create a custom app", + "CREATE_CUSTOM_APP_LABEL": "Need a custom solution?", + "CREATE_CUSTOM_APP_DESCRIPTION": "Create your own application", + "BACK_TO_APP_LIST": "Back To App's List", "DOWNGRADE_PERMISSION_TITLE": "Downgrade Your Own Permission", "DOWNGRADE_PERMISSION_DESCRIPTION": "Are you sure you want to downgrade your own permission? Once it's done you can't undo.", "CREATE_CUSTOM_APP_HELPER_TEXT": "If you know the URL of an interactive app that can leverage Graasp's API you can input it here.", diff --git a/yarn.lock b/yarn.lock index c207d3d42..3539ccf67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -425,10 +425,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: 10/ab220db218089a2aadd0582f5833fd17fa300245999f5f8784b10f5a75267c4e808592284a29438a0da365e702f05acb369f99e1c915c02f9f9210ec60eab8ea +"@babel/helper-plugin-utils@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: 10/dc8c7af321baf7653d93315beffee1790eb2c464b4f529273a24c8743a3f3095bf3f2d11828cb2c52d56282ef43a4bdc67a79c9ab8dd845e35d01871f3f28a0e languageName: node linkType: hard @@ -631,13 +631,13 @@ __metadata: linkType: hard "@babel/plugin-transform-react-jsx-self@npm:^7.18.6": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.23.3" + version: 7.24.1 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/882bf56bc932d015c2d83214133939ddcf342e5bcafa21f1a93b19f2e052145115e1e0351730897fd66e5f67cad7875b8a8d81ceb12b6e2a886ad0102cb4eb1f + checksum: 10/a0ff893b946bb0e501ad5aab43ce4b321ed9e74b94c0bc7191e2ee6409014fc96ee1a47dcb1ecdf445c44868564667ae16507ed4516dcacf6aa9c37a0ad28382 languageName: node linkType: hard @@ -653,13 +653,13 @@ __metadata: linkType: hard "@babel/plugin-transform-react-jsx-source@npm:^7.19.6": - version: 7.23.3 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.23.3" + version: 7.24.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.24.1" dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" + "@babel/helper-plugin-utils": "npm:^7.24.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10/92287fb797e522d99bdc77eaa573ce79ff0ad9f1cf4e7df374645e28e51dce0adad129f6f075430b129b5bac8dad843f65021970e12e992d6d6671f0d65bb1e0 + checksum: 10/396ce878dc588e74113d38c5a1773e0850bb878a073238a74f8cdf62d968d56a644f5485bf4032dc095fe8863fe2bd9fbbbab6abc3adf69542e038ac5c689d4c languageName: node linkType: hard