Skip to content

Commit

Permalink
feat: #1125: Update app detail features
Browse files Browse the repository at this point in the history
  • Loading branch information
nphivu414 committed May 5, 2020
1 parent 406b6c0 commit 07aae78
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 48 deletions.
2 changes: 1 addition & 1 deletion packages/elements/src/components/DropdownSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const DropdownSelect: React.FC<SelectProps & DropdownSelectProps> = ({
const handleRenderTags = (props: CustomTagProps) => {
const { value, onClose } = props
const option = options.find(option => option.value === value) as SelectOption
return <CustomTag label={option?.value} description={option.description} link={option.link} onClose={onClose} />
return <CustomTag label={option?.value} description={option?.description} link={option?.link} onClose={onClose} />
}

const handleChangeOption = field => value => {
Expand Down
107 changes: 95 additions & 12 deletions packages/marketplace/src/components/pages/developer-app-detail.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
import * as React from 'react'
import { Dispatch } from 'redux'
import { ReduxState } from '@/types/core'
import { useDispatch, useSelector } from 'react-redux'
import { RouteComponentProps } from 'react-router'
import { appDetailRequestData } from '@/actions/app-detail'
import { selectAppDetailData, selectAppDetailLoading } from '@/selector/developer-app-detail'
import { useHistory, RouteComponentProps } from 'react-router'
import { appDetailRequestData, removeAuthenticationCode } from '@/actions/app-detail'
import { selectAppDetailState, selectAppDetailData, selectAppDetailLoading } from '@/selector/developer-app-detail'
import { selectLoginType } from '@/selector/auth'
import { LoginType } from '@reapit/cognito-auth'
import { AppDetailModel } from '@reapit/foundations-ts-definitions'
import AppHeader from '../ui/developer-app-detail/app-header'
import AppContent from '../ui/developer-app-detail/app-content'
import AppDelete from '@/components/ui/app-delete'
import AppInstallations from '@/components/ui/app-installations/app-installations-modal'
import DeveloperAppRevisionModal from '@/components/ui/developer-app-revision-modal'

import { Loader } from '@reapit/elements'
import routes from '@/constants/routes'
import { AppDetailState } from '@/reducers/app-detail'
import styles from '@/styles/pages/developer-app-detail.scss?mod'

export type DeveloperAppDetailProps = {} & RouteComponentProps<{ id: string }>
export type MapState = {
appDetailState: AppDetailState
appDetailData: AppDetailModel & {
apiKey?: string | undefined
}
isLoadingAppDetail: boolean
loginType: LoginType
}

export const mapState = (state: ReduxState): MapState => {
export const mapState = (useSelector): MapState => {
return {
appDetailData: selectAppDetailData(state),
isLoadingAppDetail: selectAppDetailLoading(state),
loginType: selectLoginType(state),
appDetailState: useSelector(selectAppDetailState),
appDetailData: useSelector(selectAppDetailData),
isLoadingAppDetail: useSelector(selectAppDetailLoading),
loginType: useSelector(selectLoginType),
}
}

Expand All @@ -40,26 +47,102 @@ export const fetchDeveloperAppDetail = (dispatch: Dispatch<any>, appId: string)
}
}

export const handleEditDetailButtonClick = (history, dispatch: Dispatch<any>, id?: string) => {
return () => {
if (id) {
dispatch(removeAuthenticationCode())
history.push(`${routes.DEVELOPER_MY_APPS}/${id}/edit`)
}
}
}

export const handlenDeleteAppButtonClick = (setIsDeleteModalOpen: (isModalOpen: boolean) => void) => {
return () => {
setIsDeleteModalOpen(true)
}
}

export const handlePendingRevisionButtonClick = (
setIsAppRevisionComparisionModalOpen: (isModalOpen: boolean) => void,
) => {
return () => {
setIsAppRevisionComparisionModalOpen(true)
}
}

export const handleInstallationButtonClick = (setIsInstallationsModalOpen: (isModalOpen: boolean) => void) => {
return () => {
setIsInstallationsModalOpen(true)
}
}

const DeveloperAppDetail: React.FC<DeveloperAppDetailProps> = props => {
const history = useHistory()
const dispatch = useDispatch()
const [isDeleteModalOpen, setIsDeleteModalOpen] = React.useState(false)
const [isInstallationsModalOpen, setIsInstallationsModalOpen] = React.useState(false)
const [isAppRevisionComparisionModalOpen, setIsAppRevisionComparisionModalOpen] = React.useState(false)

const {
match: { params },
} = props
const { id: appId } = params
const { appDetailState, appDetailData, isLoadingAppDetail, loginType } = mapState(useSelector)

React.useEffect(fetchDeveloperAppDetail(dispatch, appId), [dispatch, appId])
const { appDetailData, isLoadingAppDetail, loginType } = useSelector(mapState)
const { developer, media, name } = appDetailData
const appIcon = media?.filter(({ type }) => type === 'icon')[0]

const onInstallationButtonClick = React.useCallback(handleInstallationButtonClick(setIsInstallationsModalOpen), [])
const onPendingRevisionButtonClick = React.useCallback(
handlePendingRevisionButtonClick(setIsAppRevisionComparisionModalOpen),
[],
)
const onEditDetailButtonClick = React.useCallback(
handleEditDetailButtonClick(history, dispatch, appDetailData.id),
[],
)
const onDeleteAppButtonClick = React.useCallback(handlenDeleteAppButtonClick(setIsDeleteModalOpen), [])

if (isLoadingAppDetail) {
return <Loader />
}

return (
<div className={styles.appDetailContainer}>
<AppHeader appIcon={appIcon} appName={name} developer={developer} />
<AppHeader
appDetailState={appDetailState}
onInstallationButtonClick={onInstallationButtonClick}
onPendingRevisionButtonClick={onPendingRevisionButtonClick}
onEditDetailButtonClick={onEditDetailButtonClick}
onDeleteAppButtonClick={onDeleteAppButtonClick}
/>
<AppContent appDetailData={appDetailData} loginType={loginType} />

<AppDelete
appId={appDetailData.id || ''}
appName={appDetailData.name || ''}
afterClose={() => setIsDeleteModalOpen(false)}
visible={isDeleteModalOpen}
onDeleteSuccess={() => {
setIsDeleteModalOpen(false)
}}
/>

<AppInstallations
appId={appDetailData.id || ''}
appName={appDetailData.name || ''}
visible={isInstallationsModalOpen}
afterClose={() => setIsInstallationsModalOpen(false)}
onUninstallSuccess={() => {
setIsInstallationsModalOpen(false)
}}
/>

<DeveloperAppRevisionModal
visible={isAppRevisionComparisionModalOpen}
appId={appDetailData.id || ''}
appDetailState={appDetailState}
afterClose={() => setIsAppRevisionComparisionModalOpen(false)}
/>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const AppAuthenticationDetail: React.FunctionComponent<AppAuthenticationD
{loading && <Loader body={false} />}
{!loading && code && (
<div className={styles.authenticationCodeWrap}>
<p>{code}</p>
<p className={styles.authenticationCode}>{code}</p>
<div onMouseLeave={handleMouseLeave} role="button" onClick={handleCopy} className={styles.btnCopy}>
<FaCopy size={24} />
<span className={styles.tooltiptext}>{tooltipMessage}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ export const renderShowApiKeyForWebComponent = ({
const AppContent: React.FC<AppContentProps> = ({ appDetailData, loginType }) => {
const {
externalId,
developer,
isListed,
id,
developer,
authFlow,
isWebComponent,
apiKey,
Expand Down Expand Up @@ -113,13 +113,13 @@ const AppContent: React.FC<AppContentProps> = ({ appDetailData, loginType }) =>

return (
<Grid>
<GridItem className="is-3">
<div className={styles.listed}>
<H6>{developer}</H6>
</div>
<GridItem className="is-4">
{isCurrentLoggedUserDeveloper && (
<>
<p className={styles.appInfo}>App Information</p>
<div key="app-developer" className={styles.appInfoRow}>
<p className={styles.appInfoProperty}>Developer:</p>
<p>{developer}</p>
</div>
<div key="app-id" className={styles.appInfoRow}>
<p className={styles.appInfoProperty}>Client ID:</p>
<p>{externalId}</p>
Expand All @@ -140,7 +140,9 @@ const AppContent: React.FC<AppContentProps> = ({ appDetailData, loginType }) =>
isCurrentLoggedUserDeveloper,
})}
</GridItem>
<GridItem className="is-9">
<GridItem className="is-8">
<p>{description}</p>
<br />
{carouselImages.length > 0 && (
<div className={carouselStyles.container}>
<Slider {...settings}>
Expand All @@ -153,9 +155,6 @@ const AppContent: React.FC<AppContentProps> = ({ appDetailData, loginType }) =>
</div>
)}
<br />
<p>{description}</p>
<br />

<H6>
{isCurrentLoggedUserDeveloper && 'Permissions requested'}
{isCurrentLoggedUserClient && (installedOn ? 'Permissions granted' : 'Permissions required')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,78 @@
import * as React from 'react'
import { Grid, GridItem, H3 } from '@reapit/elements'
import { MediaModel } from '@reapit/foundations-ts-definitions'
import { Grid, GridItem, H3, Button } from '@reapit/elements'

import styles from '@/styles/pages/developer-app-detail.scss?mod'
import { AppDetailState } from '@/reducers/app-detail'

type AppHeaderProps = {
appIcon?: MediaModel
appName?: string
developer?: string
export type AppHeaderProps = {
appDetailState: AppDetailState
onInstallationButtonClick: () => void
onPendingRevisionButtonClick: () => void
onEditDetailButtonClick: () => void
onDeleteAppButtonClick: () => void
}

const AppHeader: React.FC<AppHeaderProps> = ({ appIcon, appName, developer }) => {
const AppHeader: React.FC<AppHeaderProps> = ({
appDetailState,
onInstallationButtonClick,
onPendingRevisionButtonClick,
onDeleteAppButtonClick,
onEditDetailButtonClick,
}) => {
const { appDetailData } = appDetailState
const { media, name, pendingRevisions } = appDetailData?.data || {}
const appIcon = media?.filter(({ type }) => type === 'icon')[0]

return (
<Grid className="is-vcentered ">
<GridItem className="is-3">
<div className={styles.appIconContainer}>
<img
className="image"
src={(appIcon && appIcon.uri) || 'https://bulma.io/images/placeholders/48x48.png'}
alt={name}
/>
</div>
</GridItem>
<GridItem className="is-9">
<H3 className={styles.appName}>{appName}</H3>
<p>{developer}</p>
</GridItem>
</Grid>
<>
<Grid className="is-vcentered ">
<GridItem className="is-4">
<div className={styles.appIconContainer}>
<img
className="image"
src={(appIcon && appIcon.uri) || 'https://bulma.io/images/placeholders/48x48.png'}
alt={name}
/>
</div>
</GridItem>
<GridItem className="is-8">
<H3 className={styles.appName}>{name}</H3>
<Grid>
<GridItem className="is-narrow">
<Button variant="primary" type="button" onClick={onInstallationButtonClick}>
Installation
</Button>
</GridItem>
<GridItem>
{pendingRevisions ? (
<Button
className="is-pulled-right ml-2"
type="button"
variant="primary"
dataTest="detail-modal-edit-button"
onClick={onPendingRevisionButtonClick}
>
Pending Revision
</Button>
) : (
<Button
className="is-pulled-right ml-2"
variant="primary"
type="button"
onClick={onEditDetailButtonClick}
>
Edit Detail
</Button>
)}

<Button className="is-pulled-right" variant="danger" type="button" onClick={onDeleteAppButtonClick}>
Delete App
</Button>
</GridItem>
</Grid>
</GridItem>
</Grid>
</>
)
}

Expand Down
4 changes: 4 additions & 0 deletions packages/marketplace/src/selector/developer-app-detail.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ReduxState } from '@/types/core'

export const selectAppDetailState = (state: ReduxState) => {
return state.appDetail || {}
}

export const selectAppDetailData = (state: ReduxState) => {
return state.appDetail.appDetailData?.data || {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
justify-content: space-between;
}

.authenticationCode {
word-break: break-all;
}

.btnCopy {
cursor: pointer;
position: relative;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

.appDetailContainer {
width: 100%;
height: 100%;
max-width: 1012px;
margin: 0 auto;
padding: 0 16px;
padding: 15px;
background-color: $white;
}
.appIconContainer {
width: 128px;
height: 128px;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
background-color: $grey-lighter;
border-radius: 50%;
margin: 0 auto;
}

0 comments on commit 07aae78

Please sign in to comment.