Skip to content

Commit

Permalink
Bootcamp: Details page #157: Refactor BootcampViewSection and related…
Browse files Browse the repository at this point in the history
… components
  • Loading branch information
ballyalley-o committed May 5, 2024
1 parent a0d2ba0 commit 5a0e488
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/section/bootcamp/view/course-row.tsx
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
37 changes: 37 additions & 0 deletions src/section/bootcamp/view/course-table.tsx
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
3 changes: 3 additions & 0 deletions src/section/bootcamp/view/index.ts
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'
250 changes: 250 additions & 0 deletions src/section/bootcamp/view/view.tsx
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: &nbsp;
</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: &nbsp;
</Typography>
<Typography variant={TYPOGRAPHY.BODY1}>{duration}</Typography>
</SSpanBox>
</Grid>
<Grid item xs={12} sm={3}>
<SSpanBox>
<Typography variant={TYPOGRAPHY.OVERLINE} color='common.black'>
Housing: &nbsp;
</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: &nbsp;
</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: &nbsp;
</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} /> &nbsp; <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} />
&nbsp;
<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

0 comments on commit 5a0e488

Please sign in to comment.