-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bootcamp: Details page #157: Refactor BootcampViewSection and related…
… components
- Loading branch information
1 parent
a0d2ba0
commit 5a0e488
Showing
4 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { Fragment, FC, useState } from 'react' | ||
import { TableRow, TableCell, Box, IconButton, Typography } from '@mui/material' | ||
import { STableRow, SCollapse } from 'section/bootcamp' | ||
import { useIcon } from 'hook' | ||
import { ICON_WEB_NAME } from 'config' | ||
import { KEY, TYPOGRAPHY } from 'constant' | ||
import { capitalize } from 'util/format' | ||
|
||
interface CourseRowProps { | ||
row: any | ||
} | ||
|
||
const CourseRow: FC<CourseRowProps> = ({ row }) => { | ||
const [open, setOpen] = useState(false) | ||
|
||
const { Icon: WebIcon, iconSrc: checkSrc } = useIcon(ICON_WEB_NAME.CHECK_OUTLINE) | ||
const { Icon, iconSrc: crossSrc } = useIcon(ICON_WEB_NAME.CLOSE_OUTLINE) | ||
const { Icon: ExpandIcon, iconSrc: expandSrc } = useIcon(ICON_WEB_NAME.PLUS) | ||
const { Icon: RetractIcon, iconSrc: retractSrc } = useIcon(ICON_WEB_NAME.RETRACT) | ||
return ( | ||
<Fragment> | ||
<STableRow> | ||
<TableCell sx={{ fontWeight: 'bold' }}>{row?.title}</TableCell> | ||
<TableCell>{row?.duration} weeks</TableCell> | ||
<TableCell align={KEY.CENTER}>${row?.tuition}</TableCell> | ||
<TableCell align={KEY.CENTER}>{capitalize(row?.minimumSkill)}</TableCell> | ||
<TableCell align={KEY.CENTER}> | ||
{row?.scholarshipAvailable ? <WebIcon icon={checkSrc} color='success.main' /> : <Icon icon={crossSrc} color='error.main' />} | ||
</TableCell> | ||
<TableCell align={KEY.CENTER}> | ||
<Box> | ||
<IconButton onClick={() => setOpen(!open)}>{open ? <RetractIcon icon={retractSrc} /> : <ExpandIcon icon={expandSrc} />}</IconButton> | ||
</Box> | ||
</TableCell> | ||
</STableRow> | ||
<TableRow> | ||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={8}> | ||
<SCollapse in={open} timeout={KEY.AUTO} unmountOnExit> | ||
<Box sx={{ margin: 1, paddingTop: 2, paddingBottom: 2 }}> | ||
<Typography variant={TYPOGRAPHY.BODY1}>{row?.description}</Typography> | ||
</Box> | ||
</SCollapse> | ||
</TableCell> | ||
</TableRow> | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default CourseRow |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { FC, Fragment, useState } from 'react' | ||
import { Table, TableBody, TableCell, TableHead } from '@mui/material' | ||
import { SRoot, STableContainer, STableHeader } from 'section/bootcamp' | ||
import { ARIA, KEY, LABEL } from 'constant' | ||
import CourseRow from './course-row' | ||
|
||
interface CourseTableProps { | ||
course: any | ||
} | ||
|
||
const CourseTable: FC<CourseTableProps> = ({ course }) => { | ||
return ( | ||
<SRoot> | ||
<STableContainer> | ||
<Table aria-label={ARIA.COURSE_TABLE}> | ||
<TableHead> | ||
<STableHeader> | ||
<TableCell>{LABEL.TITLE}</TableCell> | ||
<TableCell>{LABEL.DURATION}</TableCell> | ||
<TableCell align={KEY.CENTER}>{LABEL.COST}</TableCell> | ||
<TableCell align={KEY.CENTER}>{LABEL.SKILL_REQUIRED}</TableCell> | ||
<TableCell align={KEY.CENTER}>{LABEL.SCHOLARSHIP}</TableCell> | ||
<TableCell align={KEY.CENTER}></TableCell> | ||
</STableHeader> | ||
</TableHead> | ||
<TableBody> | ||
{course?.map((row: any, index: any) => ( | ||
<CourseRow key={index} row={row} /> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</STableContainer> | ||
</SRoot> | ||
) | ||
} | ||
|
||
export default CourseTable |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { default as BootcampViewSection } from './view' | ||
export { default as CourseTable } from './course-table' | ||
export { default as CourseRow } from './course-row' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
import { FC, useEffect } from 'react' | ||
import { useParams, Link } from 'react-router-dom' | ||
import { ICON_NAME, useIcon } from 'hook' | ||
import { useGetBootcampQuery, useGetAllCourseByBootcampQuery } from 'store/slice' | ||
import { | ||
Box, | ||
Grid, | ||
Typography, | ||
Container, | ||
CardMedia, | ||
Chip, | ||
CardContent, | ||
Divider, | ||
Accordion, | ||
AccordionSummary, | ||
AccordionDetails, | ||
List, | ||
ListItem, | ||
ListItemText | ||
} from '@mui/material' | ||
import { BackButton } from 'component' | ||
import { GSContainerGrid, SSpanBox } from 'theme/style' | ||
import { MotionLazyContainer } from 'component/motion' | ||
import { ICON_WEB_NAME } from 'config' | ||
import { FLEX, KEY, LABEL, PLACEHOLDER, TYPOGRAPHY, COMPONENT, ARIA, VARIANT, SIZE } from 'constant' | ||
import { badgeLocation, photoLocation } from 'util/asset-loc' | ||
import CourseTable from './course-table' | ||
|
||
interface BootcampViewSectionProps { | ||
bootcamp?: Bootcamp | ||
} | ||
|
||
const BootcampViewSection: FC<BootcampViewSectionProps> = () => { | ||
const { id } = useParams<{ id: string }>() | ||
const { data: bootcamp, error, isLoading } = useGetBootcampQuery(id) | ||
|
||
const { | ||
_id, | ||
name, | ||
description, | ||
badge, | ||
photo, | ||
location, | ||
careers, | ||
averageRating, | ||
user, | ||
duration, | ||
phone, | ||
website, | ||
slug, | ||
housing, | ||
jobAssistance, | ||
jobGuarantee | ||
} = bootcamp?.data || {} | ||
|
||
const courseQueryResult = useGetAllCourseByBootcampQuery(_id) | ||
|
||
const { data: course, error: courseError, isLoading: courseLoading } = courseQueryResult || { data: null, error: null, isLoading: false } | ||
|
||
const { Icon: PhoneIcon, iconSrc: phoneSrc } = useIcon(ICON_WEB_NAME.PHONE) | ||
const { Icon: RightIcon, iconSrc: rightSrc } = useIcon(ICON_WEB_NAME.CHEVRON_RIGHT) | ||
const { Icon: GlobeIcon, iconSrc: globeSrc } = useIcon(ICON_WEB_NAME.GLOBE) | ||
const { Icon, iconSrc: crossSrc } = useIcon(ICON_WEB_NAME.CLOSE_OUTLINE) | ||
const { iconSrc: checkSrc } = useIcon(ICON_WEB_NAME.CHECK_OUTLINE) | ||
|
||
return ( | ||
<MotionLazyContainer> | ||
<Box | ||
sx={{ | ||
height: '100vh' | ||
}}> | ||
<Grid container spacing={2}> | ||
<Grid item sm={12}> | ||
<BackButton /> | ||
</Grid> | ||
</Grid> | ||
<Container> | ||
<Grid container spacing={2} flexDirection='row'> | ||
<Grid item sm={9}> | ||
<Box marginBottom={2}> | ||
<Typography variant={TYPOGRAPHY.H4} color='common.black'> | ||
{name} | ||
</Typography> | ||
<Typography variant={TYPOGRAPHY.BODY1}>{description}</Typography> | ||
{slug && ( | ||
<SSpanBox mt={2}> | ||
<Typography variant={TYPOGRAPHY.CAPTION} color='common.black'> | ||
Tags: | ||
</Typography> | ||
<SSpanBox> | ||
<Typography variant={TYPOGRAPHY.CAPTION}>{slug || '5'}</Typography> | ||
</SSpanBox> | ||
</SSpanBox> | ||
)} | ||
</Box> | ||
<CardMedia | ||
component={COMPONENT.IMG} | ||
image={photoLocation({ _id, photo })} | ||
alt={bootcamp?.name} | ||
sx={{ | ||
height: { xs: '100vh', sm: 200, md: 200, lg: 250, xl: 300 }, | ||
objectFit: VARIANT.COVER, | ||
borderRadius: 2 | ||
}} | ||
/> | ||
<Grid container flexDirection='column' spacing={2} p={1}> | ||
<Grid item xs={12} sm={3}> | ||
<SSpanBox border='inherit'> | ||
<Typography variant={TYPOGRAPHY.OVERLINE} color='common.black'> | ||
Duration: | ||
</Typography> | ||
<Typography variant={TYPOGRAPHY.BODY1}>{duration}</Typography> | ||
</SSpanBox> | ||
</Grid> | ||
<Grid item xs={12} sm={3}> | ||
<SSpanBox> | ||
<Typography variant={TYPOGRAPHY.OVERLINE} color='common.black'> | ||
Housing: | ||
</Typography> | ||
{housing ? <Icon icon={checkSrc} color='success.main' /> : <Icon icon={crossSrc} color='error.main' />} | ||
</SSpanBox> | ||
</Grid> | ||
<Grid item xs={12} sm={3}> | ||
<SSpanBox> | ||
<Typography variant={TYPOGRAPHY.OVERLINE} color='common.black'> | ||
Job Assistance: | ||
</Typography> | ||
{jobAssistance ? <Icon icon={checkSrc} color='success.main' /> : <Icon icon={crossSrc} color='error.main' />} | ||
</SSpanBox> | ||
</Grid> | ||
<Grid item xs={12} sm={3}> | ||
<SSpanBox> | ||
<Typography variant={TYPOGRAPHY.OVERLINE} color='common.black'> | ||
Job Guarantee: | ||
</Typography> | ||
{jobGuarantee ? <Icon icon={checkSrc} color='success.main' /> : <Icon icon={crossSrc} color='error.main' />} | ||
</SSpanBox> | ||
</Grid> | ||
</Grid> | ||
</Grid> | ||
<Grid item sm={3}> | ||
<SSpanBox> | ||
<CardMedia | ||
component={KEY.IMAGE} | ||
src={badgeLocation({ _id, badge })} | ||
alt={ARIA.COMPANY_BADGE} | ||
height={50} | ||
sx={{ width: 70, height: 70, marginRight: 2, display: FLEX.FLEX, justifyContent: FLEX.FLEX_END, borderRadius: 2 }} | ||
/> | ||
<Typography variant={TYPOGRAPHY.H5}>{user?.organization || 'TCCP'}</Typography> | ||
</SSpanBox> | ||
|
||
<Divider | ||
sx={{ | ||
marginY: 2 | ||
}} | ||
/> | ||
<Box gap={5}> | ||
<CardContent> | ||
<Box my={2}> | ||
<Typography variant={TYPOGRAPHY.H6} color='common.black'> | ||
{LABEL.LOCATION} | ||
</Typography> | ||
<Typography variant={TYPOGRAPHY.BODY2}> | ||
{location?.city}, {location?.state} | ||
</Typography> | ||
</Box> | ||
<Box my={2}> | ||
<Typography variant={TYPOGRAPHY.BODY1} color='common.black'> | ||
{LABEL.CAREER} | ||
</Typography> | ||
|
||
{careers?.map((career: string, index: any) => ( | ||
// chip for each career | ||
<Chip | ||
key={index} | ||
label={<Typography variant={TYPOGRAPHY.BODY2}>{career}</Typography>} | ||
size={SIZE.SMALL} | ||
sx={{ | ||
margin: 0.5 | ||
}} | ||
/> | ||
)) || PLACEHOLDER.NO_CAREER} | ||
</Box> | ||
<Box my={2}> | ||
<Typography variant={TYPOGRAPHY.H5} color='common.black'> | ||
{LABEL.RATING} | ||
</Typography> | ||
<Typography variant={TYPOGRAPHY.BODY1}>{averageRating || '5'}</Typography> | ||
</Box> | ||
|
||
<Box | ||
my={2} | ||
sx={{ | ||
padding: 2, | ||
border: '1px solid #D4D4D4', | ||
borderRadius: 2 | ||
}}> | ||
<Box mb={2}> | ||
<Typography variant={TYPOGRAPHY.SUBTITLE1} color='common.black' sx={{ backgroundColor: 'comm' }}> | ||
{LABEL.CONTACT} | ||
</Typography> | ||
<SSpanBox> | ||
<PhoneIcon icon={phoneSrc} /> <Typography variant={TYPOGRAPHY.OVERLINE1}>{phone || '0'}</Typography> | ||
</SSpanBox> | ||
</Box> | ||
<Box my={2}> | ||
<Typography variant={TYPOGRAPHY.SUBTITLE1} color='common.black' sx={{ backgroundColor: 'comm' }}> | ||
{LABEL.WEBSITE} | ||
</Typography> | ||
<SSpanBox sx={{ backgroundColor: 'grey.200', padding: 1 }}> | ||
<GlobeIcon icon={globeSrc} color='common.black' height={20} /> | ||
| ||
<Link | ||
to={'#'} | ||
style={{ | ||
textDecoration: 'none', | ||
color: 'inherit' | ||
}}> | ||
<Typography variant='overline0' color='common.black' sx={{ backgroundColor: 'comm' }}> | ||
{LABEL.VISIT_WEBSITE} | ||
</Typography> | ||
</Link> | ||
<RightIcon icon={rightSrc} color='success' /> | ||
</SSpanBox> | ||
</Box> | ||
</Box> | ||
</CardContent> | ||
</Box> | ||
</Grid> | ||
<Grid item sm={9}> | ||
<Box my={2}> | ||
<Typography variant={TYPOGRAPHY.H5} color='common.black'> | ||
{LABEL.COURSE_COVERED} | ||
</Typography> | ||
</Box> | ||
{course?.data?.length > 0 ? ( | ||
<CourseTable course={course?.data} /> | ||
) : ( | ||
<Typography variant={TYPOGRAPHY.BODY1}>{PLACEHOLDER.NO_COURSE_AVAILABLE}</Typography> | ||
)} | ||
</Grid> | ||
</Grid> | ||
</Container> | ||
</Box> | ||
</MotionLazyContainer> | ||
) | ||
} | ||
|
||
export default BootcampViewSection |