diff --git a/web/apps/app-listing.react.js b/web/apps/app-listing.react.js new file mode 100644 --- /dev/null +++ b/web/apps/app-listing.react.js @@ -0,0 +1,83 @@ +// @flow + +import { faCheckCircle } from '@fortawesome/free-regular-svg-icons'; +import { faPlusCircle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import classnames from 'classnames'; +import * as React from 'react'; +import { useDispatch } from 'react-redux'; + +import { + disableAppActionType, + enableAppActionType, +} from 'lib/reducers/enabled-apps-reducer'; +import type { SupportedApps } from 'lib/types/enabled-apps'; + +import SWMansionIcon from '../SWMansionIcon.react'; +import css from './apps.css'; + +type Props = { + +id: SupportedApps | 'chat', + +readOnly: boolean, + +enabled: boolean, + +name: string, + +icon: 'message-square' | 'calendar', + +copy: string, +}; + +function AppListing(props: Props): React.Node { + const { id, readOnly, enabled, name, icon, copy } = props; + const dispatch = useDispatch(); + + const switchAppState = React.useCallback( + () => + dispatch({ + type: enabled ? disableAppActionType : enableAppActionType, + payload: id, + }), + [dispatch, enabled, id], + ); + + const actionButton = React.useMemo(() => { + const switchIcon = enabled ? faCheckCircle : faPlusCircle; + if (readOnly) { + const readOnlyIconClasses = classnames( + css.appListingIcon, + css.appListingIconState, + css.iconReadOnly, + ); + return ( +
+ +
+ ); + } + const iconClasses = classnames( + css.appListingIcon, + css.appListingIconState, + { + [css.iconEnabled]: enabled, + [css.iconDisabled]: !enabled, + }, + ); + return ( +
+ +
+ ); + }, [enabled, readOnly, switchAppState]); + return ( +
+
+ +
+
+
{name}
+ {copy} +
+ {actionButton} +
+ ); +} + +export default AppListing; diff --git a/web/apps/apps-directory.react.js b/web/apps/apps-directory.react.js --- a/web/apps/apps-directory.react.js +++ b/web/apps/apps-directory.react.js @@ -1,9 +1,56 @@ // @flow import * as React from 'react'; +import { useSelector } from 'react-redux'; + +import AppListing from './app-listing.react'; +import css from './apps.css'; + +const APP_DIRECTORY_DATA = [ + { + id: 'chat', + defaultEnabled: true, + readOnly: true, + name: 'Chat', + icon: 'message-square', + copy: 'Keep in touch with your community', + }, + { + id: 'calendar', + defaultEnabled: true, + readOnly: false, + name: 'Calendar', + icon: 'calendar', + copy: 'Shared calendar for your community', + }, +]; function AppsDirectory(): React.Node { - return
Apps directory
; + const enabledApps = useSelector(state => state.enabledApps); + + const appData = React.useMemo( + () => + APP_DIRECTORY_DATA.map(app => { + const { defaultEnabled, ...data } = app; + return { + ...data, + enabled: enabledApps[app.id] ?? defaultEnabled, + }; + }), + [enabledApps], + ); + + const appItems = React.useMemo( + () => appData.map(item => ), + [appData], + ); + + return ( +
+

Choose Apps

+
{appItems}
+
+ ); } export default AppsDirectory; diff --git a/web/apps/apps.css b/web/apps/apps.css new file mode 100644 --- /dev/null +++ b/web/apps/apps.css @@ -0,0 +1,63 @@ +div.appsDirectoryContainer { + display: flex; + flex-direction: column; + align-items: flex-start; +} + +h4.appsHeader { + color: var(--fg); + padding: 20px 0px 40px 40px; + font-weight: var(--semi-bold); +} + +div.appsDirectoryList { + margin-left: 20px; + display: flex; + flex-direction: column; + row-gap: 10px; +} + +div.appListingContainer { + color: var(--fg); + display: flex; + flex-direction: row; + align-items: center; +} + +div.appListingTextContainer { + display: flex; + flex-direction: column; + flex: 1; +} + +h5.appName { + font-weight: var(--semi-bold); + margin-bottom: 4px; +} + +small.appCopy { + font-size: var(--xs-font-12); +} + +div.appListingIcon { + padding: 0 20px; + align-self: stretch; + display: flex; + align-items: center; +} + +div.appListingIconState { + font-size: var(--xl-font-20); +} + +div.iconReadOnly { + color: var(--app-list-icon-read-only-color); +} + +div.iconEnabled { + color: var(--app-list-icon-enabled-color); +} + +div.iconDisabled { + color: var(--app-list-icon-disabled-color); +} diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -108,4 +108,7 @@ --thread-menu-color-hover: var(--shades-white-100); --thread-menu-color-dangerous: var(--error-primary); --thread-menu-color-dangerous-hover: var(--error-light-50); + --app-list-icon-read-only-color: var(--shades-black-60); + --app-list-icon-enabled-color: var(--success-primary); + --app-list-icon-disabled-color: var(--shades-white-80); }