Skip to content

Commit

Permalink
Merge pull request #557 from urfit-tech/feat/SecondaryProgramPage-dat…
Browse files Browse the repository at this point in the history
…a-setup

feat/SecondaryProgramPage-data-setup
  • Loading branch information
clothe09986 authored Jun 7, 2024
2 parents 4f419ff + 552c645 commit f09451b
Show file tree
Hide file tree
Showing 15 changed files with 1,151 additions and 1,072 deletions.
10 changes: 5 additions & 5 deletions src/components/common/GiftPlanTag.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React from 'react'
import { defineMessages, useIntl } from 'react-intl'
import styled from 'styled-components'
const StyledTag = styled.p`
const StyledTag = styled.p<{ color?: string }>`
padding: 2px 6px;
font-size: 12px;
letter-spacing: 0.6px;
color: ${props => props.theme['@primary-color']};
border: 1px solid ${props => props.theme['@primary-color']};
color: ${props => (!!props.color ? props.color : props.theme['@primary-color'])};
border: 1px solid ${props => (!!props.color ? props.color : props.theme['@primary-color'])};
border-radius: 4px;
`
const messages = defineMessages({
hasGiftPlan: { id: 'common.label.hasGiftPlan', defaultMessage: '附贈品' },
})

const GiftPlanTag: React.VFC = () => {
const GiftPlanTag: React.VFC<{ color?: string }> = ({ color }) => {
const { formatMessage } = useIntl()
return <StyledTag>{formatMessage(messages.hasGiftPlan)}</StyledTag>
return <StyledTag color={color}>{formatMessage(messages.hasGiftPlan)}</StyledTag>
}

export default GiftPlanTag
1,802 changes: 898 additions & 904 deletions src/hasura.d.ts

Large diffs are not rendered by default.

34 changes: 29 additions & 5 deletions src/hooks/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export const usePublishedProgramCollection = (options?: {
list_price
sale_price
sold_at
program_categories {
id
category {
Expand All @@ -61,6 +60,9 @@ export const usePublishedProgramCollection = (options?: {
id
name
member_id
member {
name
}
}
program_plans(where: { published_at: { _lte: "now()" } }, order_by: { created_at: asc }) {
id
Expand Down Expand Up @@ -144,7 +146,6 @@ export const usePublishedProgramCollection = (options?: {
isSubscription: program.is_subscription,
isSoldOut: program.is_sold_out,
isPrivate: program.is_private,

listPrice: program.list_price,
salePrice: program.sale_price,
soldAt: program.sold_at && new Date(program.sold_at),
Expand All @@ -158,7 +159,7 @@ export const usePublishedProgramCollection = (options?: {
id: programRole.id,
name: programRole.name as ProgramRoleName,
memberId: programRole.member_id,
memberName: programRole.member_id,
memberName: programRole?.member?.name || '',
})),
plans: program.program_plans.map(programPlan => ({
id: programPlan.id,
Expand Down Expand Up @@ -261,6 +262,15 @@ export const useProgram = (programId: string) => {
is_enrolled_count_visible
display_header
display_footer
program_layout_template_configs(where: { is_active: { _eq: true } }) {
id
program_layout_template_id
module_data
program_layout_template {
id
variant
}
}
editors {
member_id
}
Expand All @@ -283,6 +293,12 @@ export const useProgram = (programId: string) => {
id
name
member_id
member {
name
description
abstract
picture_url
}
}
program_review_score {
score
Expand Down Expand Up @@ -409,6 +425,11 @@ export const useProgram = (programId: string) => {
editors: data?.program_by_pk?.editors.map(v => v?.member_id || ''),
displayHeader: data?.program_by_pk?.display_header ?? true,
displayFooter: data?.program_by_pk?.display_footer ?? true,
programLayoutTemplateId:
data?.program_by_pk?.program_layout_template_configs[0]?.program_layout_template_id || undefined,
moduleData: data?.program_by_pk?.program_layout_template_configs[0]?.module_data,
programLayoutTemplateVariant:
data?.program_by_pk?.program_layout_template_configs[0]?.program_layout_template?.variant,
categories:
data?.program_by_pk?.program_categories.map(programCategory => ({
id: programCategory.category.id,
Expand All @@ -419,7 +440,10 @@ export const useProgram = (programId: string) => {
id: programRole.id,
name: programRole.name as ProgramRoleName,
memberId: programRole.member_id,
memberName: programRole.member_id,
memberName: programRole?.member?.name || '',
pictureUrl: programRole?.member?.picture_url || '',
abstract: programRole?.member?.abstract || '',
description: programRole?.member?.description || '',
})) || [],
plans:
programPlans?.program_plan.map(programPlan => ({
Expand Down Expand Up @@ -458,7 +482,7 @@ export const useProgram = (programId: string) => {
id: programContentSection.id,
title: programContentSection.title,
description: programContentSection.description || '',
collapsed_status: programContentSection.collapsed_status,
collapsedStatus: programContentSection.collapsed_status,
contents: programContentSection.program_contents.map(programContent => ({
id: programContent.id,
title: programContent.title,
Expand Down
4 changes: 2 additions & 2 deletions src/pages/ProgramPage/Primary/ProgramContentListSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const ProgramContentListSection: React.VFC<{
id: programContentSection.id,
title: programContentSection.title,
description: programContentSection.description,
collapsed_status: programContentSection.collapsed_status,
collapsedStatus: programContentSection.collapsedStatus,
contents: isEquityProgram
? programContentSection.contents
: programContentSection.contents.filter(programContent =>
Expand All @@ -164,7 +164,7 @@ const ProgramContentListSection: React.VFC<{
const isAllPinned = sec.contents.every(content => content.pinnedStatus)

acc[sec.id] = {
isCollapsed: isAllPinned ? true : sec.collapsed_status,
isCollapsed: isAllPinned ? true : sec.collapsedStatus,
isAllPinned: isAllPinned,
}

Expand Down
2 changes: 1 addition & 1 deletion src/pages/ProgramPage/ProgramPageContent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PrimaryProgramPageContent from './Primary/PrimaryProgramPageContent'
import SecondaryProgramContent from './Secondary/SecondaryProgramPageContent'

const ProgramPageContent: React.FC<{ variant: string }> = ({ variant }) => {
const ProgramPageContent: React.FC<{ variant: string | null | undefined }> = ({ variant }) => {
switch (variant) {
case 'primary':
return <PrimaryProgramPageContent />
Expand Down
26 changes: 24 additions & 2 deletions src/pages/ProgramPage/Secondary/ProgramIntroTabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { BREAK_POINT } from 'lodestar-app-element/src/components/common/Responsi
import { BraftContent } from 'lodestar-app-element/src/components/common/StyledBraftEditor'
import React from 'react'
import styled from 'styled-components'
import { Program, ProgramRole } from '../../../../types/program'
import { useEquityProgramByProgramId } from '../../../../hooks/program'
import { DisplayModeEnum, Program, ProgramRole } from '../../../../types/program'
import SecondaryInstructorCollectionBlock from '../SecondaryInstructorCollectionBlock'
import SecondaryProgramContentListSection from '../SecondaryProgramContentListSection'
import { colors } from '../style'
Expand All @@ -30,6 +31,23 @@ const ProgramIntroTabs: React.VFC<{
roles: ProgramRole[]
}
}> = ({ program }) => {
const { isEquityProgram } = useEquityProgramByProgramId(program.id)
const programContentSections = program.contentSections
.filter(programContentSection => programContentSection.contents.length)
.map(programContentSection => ({
id: programContentSection.id,
title: programContentSection.title,
description: programContentSection.description,
collapsedStatus: programContentSection.collapsedStatus,
contents: isEquityProgram
? programContentSection.contents
: programContentSection.contents.filter(programContent =>
program.isIntroductionSectionVisible
? programContent
: programContent.displayMode === DisplayModeEnum.trial ||
programContent.displayMode === DisplayModeEnum.loginToTrial,
),
}))
return (
<Tabs position="relative" width="100%">
<StyledTabList justifyContent="center">
Expand All @@ -43,7 +61,11 @@ const ProgramIntroTabs: React.VFC<{
<BraftContent>{program.description}</BraftContent>
</StyledPanel>
<StyledPanel>
<SecondaryProgramContentListSection program={program} />
<SecondaryProgramContentListSection
program={program}
programContentSections={programContentSections}
isEquityProgram={isEquityProgram}
/>
</StyledPanel>
<StyledPanel>
<SecondaryInstructorCollectionBlock program={program} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Box } from '@chakra-ui/react'
import styled from 'styled-components'
import { usePostPreviewCollection } from '../../../../hooks/blog'
import { usePodcastProgramCollection } from '../../../../hooks/podcast'
import { usePublishedProgramCollection } from '../../../../hooks/program'
import EmptyCover from '../../../../images/empty-cover.png'
import CollapseContent from './CollapseContent'
import CollapseContentCard from './CollapseContentCard'

const StyledCollapseContentWrapper = styled(Box)`
display: grid;
grid-row-gap: 12px;
margin-top: 24px;
grid-template-columns: 1fr;
place-items: center;
padding-bottom: 24px;
`

const CollapseContentBlock: React.FC<{ creatorId: string }> = ({ creatorId }) => {
const { programs } = usePublishedProgramCollection({
instructorId: creatorId,
isPrivate: false,
})

const { podcastPrograms } = usePodcastProgramCollection(creatorId)
const { posts } = usePostPreviewCollection({ authorId: creatorId })
return (
<>
<CollapseContent title={`開設課程(${programs.length})`}>
<StyledCollapseContentWrapper>
{programs.map(program => (
<CollapseContentCard
imgSrc={program.coverThumbnailUrl || program.coverUrl || program.coverMobileUrl || EmptyCover}
href={`/program/${program.id}`}
key={program.id}
>
{program.title}
</CollapseContentCard>
))}
</StyledCollapseContentWrapper>
</CollapseContent>
<CollapseContent title={`廣播頻道(${podcastPrograms.length})`}>
<StyledCollapseContentWrapper>
{podcastPrograms.map(podcast => (
<CollapseContentCard
imgSrc={podcast.coverUrl || EmptyCover}
href={`/podcast/${podcast.id}`}
key={podcast.id}
>
{podcast.title}
</CollapseContentCard>
))}
</StyledCollapseContentWrapper>
</CollapseContent>
<CollapseContent title={`媒體文章(${posts.length})`}>
<StyledCollapseContentWrapper>
{posts.map(post => (
<CollapseContentCard imgSrc={post.coverUrl || EmptyCover} href={`/posts/${post.id}`} key={post.id}>
{post.title}
</CollapseContentCard>
))}
</StyledCollapseContentWrapper>
</CollapseContent>
</>
)
}

export default CollapseContentBlock
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Box, Image } from '@chakra-ui/react'
import { Box } from '@chakra-ui/react'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import { ProgramCover } from '../../../../components/common/Image'
import { colors } from '../style'

const Card = styled(Link)`
const StyledCard = styled(Link)`
width: 98%;
height: 85px;
border-radius: 4px;
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.06);
background-color: #fff;
display: flex;
gap: 16px;
justify-content: start;
align-items: center;
padding: 12px;
Expand All @@ -20,7 +22,6 @@ const Card = styled(Link)`

const ImageWrapper = styled(Box)`
width: 100px;
height: 60px;
border-radius: 4px;
`

Expand All @@ -30,12 +31,12 @@ const CollapseContentCard: React.VFC<{ href: string; imgSrc?: string; children:
href,
}) => {
return (
<Card to={href}>
<StyledCard to={href}>
<ImageWrapper>
<Image src={imgSrc} />
<ProgramCover width="100%" height="100%" paddingTop="calc(100% * 9/16)" src={imgSrc} shape="rounded" />
</ImageWrapper>
{children}
</Card>
</StyledCard>
)
}

Expand Down
Loading

0 comments on commit f09451b

Please sign in to comment.