Skip to content

Commit

Permalink
Merge pull request #2497 from MahtabBukhari/Render-seed-episodes-on-t…
Browse files Browse the repository at this point in the history
…he-landing-page

[Graph Mindset] Render seed episodes on the landing page
  • Loading branch information
Rassl authored Dec 4, 2024
2 parents dea4b45 + 7ca7b12 commit b2e545d
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 12 deletions.
79 changes: 67 additions & 12 deletions src/components/mindset/components/LandingPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import styled from 'styled-components'
import { Flex } from '~/components/common/Flex'
import { NODE_ADD_ERROR } from '~/constants'
import { api } from '~/network/api'
import { getSchemaAll } from '~/network/fetchSourcesData'
import { getNodes, getSchemaAll } from '~/network/fetchSourcesData'
import { useDataStore } from '~/stores/useDataStore'
import { useMindsetStore } from '~/stores/useMindsetStore'
import { useSchemaStore } from '~/stores/useSchemaStore'
import { SubmitErrRes } from '~/types'
import { colors } from '~/utils/colors'
import { ChevronRight } from '../Icon/ChevronRight'
import { isValidMediaUrl } from './utils'
import { VideoCard } from '../VideoCard'

export type FormData = {
input: string
Expand All @@ -21,6 +22,26 @@ export type FormData = {
latitude: string
}

interface EpisodeProperties {
date: number
episode_title: string
image_url: string
media_url: string
pubkey: string
source_link: string
status: string
}

interface Node {
node_type: string
properties?: EpisodeProperties
}

export interface ApiResponse {
edges: never[]
nodes: Node[]
}

const handleSubmitForm = async (data: FieldValues): Promise<SubmitErrRes> => {
const endPoint = 'add_node'

Expand All @@ -44,13 +65,27 @@ export const LandingPage = () => {
const [inputValue, setInputValue] = useState('')
const [error, setError] = useState(false)
const [requestError, setRequestError] = useState<string>('')
const [episodes, setEpisodes] = useState<EpisodeProperties[]>([])
const { setRunningProjectId } = useDataStore((s) => s)
const { setSelectedEpisodeId, setSelectedEpisodeLink } = useMindsetStore((s) => s)
const { setSchemas } = useSchemaStore((s) => s)

const filterAndSortEpisodes = (data: ApiResponse): EpisodeProperties[] =>
data.nodes
.filter((node) => node.node_type.toLowerCase() === 'episode' && node.properties?.date)
.map((node) => node.properties!)
.sort((a, b) => b.date - a.date)
.slice(0, 3)

useEffect(() => {
const fetchSchemaData = async () => {
try {
const res: ApiResponse = await getNodes()

const topEpisodes = filterAndSortEpisodes(res)

setEpisodes(topEpisodes)

const response = await getSchemaAll()

setSchemas(response.schemas.filter((schema) => !schema.is_deleted))
Expand All @@ -69,18 +104,20 @@ export const LandingPage = () => {
setError(value !== '' && !isValidMediaUrl(value))
}

const handleSubmit = async () => {
if (isValidMediaUrl(inputValue)) {
const handleSubmit = async (url?: string) => {
const source = url || inputValue

if (isValidMediaUrl(source)) {
try {
const res = await handleSubmitForm({ source: inputValue })
const res = await handleSubmitForm({ source })

if (res.data.project_id) {
setRunningProjectId(res.data.project_id)
}

if (res.data.ref_id) {
setSelectedEpisodeId(res.data.ref_id)
setSelectedEpisodeLink(inputValue)
setSelectedEpisodeLink(source)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -94,7 +131,7 @@ export const LandingPage = () => {

if (res.data.ref_id) {
setSelectedEpisodeId(res.data.ref_id)
setSelectedEpisodeLink(inputValue)
setSelectedEpisodeLink(source)
}
} else if (err instanceof Error) {
errorMessage = err.message
Expand All @@ -116,11 +153,22 @@ export const LandingPage = () => {
placeholder="Paste podcast or video link"
value={inputValue}
/>
<IconWrapper error={error} onClick={!error ? handleSubmit : undefined}>
<IconWrapper error={error} onClick={!error ? () => handleSubmit() : undefined}>
<ChevronRight />
</IconWrapper>
</InputWrapper>
{requestError && <div>{requestError}</div>}
<SeedQuestionsWrapper>
{episodes.map((episode) => (
<VideoCard
key={episode?.episode_title}
imageUrl={(episode?.image_url as string) || ''}
onClick={() => handleSubmit(episode?.source_link)}
subtitle="Subtitle for episode seed"
title={(episode?.episode_title as string) || ''}
/>
))}
</SeedQuestionsWrapper>
</Wrapper>
)
}
Expand Down Expand Up @@ -154,19 +202,17 @@ const Title = styled(Flex)`

const Input = styled.input<{ error?: boolean }>`
width: 100%;
max-width: 450px;
max-width: 648px;
padding: 12px 28px 12px 16px;
border-radius: 100px;
border: 1px solid ${(props) => (props.error ? 'red' : colors.DIVIDER_4)};
background: ${colors.INPUT_BG};
color: ${colors.white};
font-family: Barlow;
font-size: 16px;
&::placeholder {
color: ${colors.INPUT_PLACEHOLDER};
}
&:focus {
outline: none;
border-color: ${(props) => (props.error ? 'red' : colors.primaryBlue)};
Expand All @@ -175,7 +221,7 @@ const Input = styled.input<{ error?: boolean }>`

const InputWrapper = styled.div`
position: relative;
width: 450px;
width: 648px;
display: flex;
align-items: center;
`
Expand All @@ -188,10 +234,19 @@ const IconWrapper = styled.div<{ error?: boolean }>`
color: ${colors.white};
font-size: 20px;
cursor: ${(props) => (props.error ? 'not-allowed' : 'pointer')};
svg {
width: 8px;
height: 17px;
color: ${colors.GRAY6};
}
`

const SeedQuestionsWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-top: 20px;
max-width: 648px;
height: 237px;
`
93 changes: 93 additions & 0 deletions src/components/mindset/components/VideoCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import styled from 'styled-components'
import { Flex } from '~/components/common/Flex'
import { colors } from '~/utils/colors'

interface VideoCardProps {
imageUrl: string
title: string
subtitle: string
onClick: () => void
}

export const VideoCard = ({ imageUrl, title, subtitle, onClick }: VideoCardProps) => {
const truncatedTitle = title.length > 35 ? `${title.substring(0, 32)}...` : title
const truncatedSubtitle = subtitle.length > 50 ? `${subtitle.substring(0, 47)}...` : subtitle

return (
<CardWrapper onClick={onClick}>
<ImageWrapper>
<CardImage alt={title} src={imageUrl} />
</ImageWrapper>
<TextWrapper>
<CardTitle>{truncatedTitle}</CardTitle>
<CardSubtitle>{truncatedSubtitle}</CardSubtitle>
</TextWrapper>
</CardWrapper>
)
}

const CardWrapper = styled(Flex)`
background: ${colors.BG1};
width: 170px;
height: 200px;
color: ${colors.white};
padding: 16px;
border-radius: 8px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
&:hover {
background: ${colors.SEEDQUESTION_HOVER};
}
&:active {
background: ${colors.SEEDQUESTION};
}
`

const ImageWrapper = styled.div`
width: 100%;
height: 140px; /* Fixed height for images */
border-radius: 6px;
overflow: hidden;
margin-bottom: 12px;
display: flex;
justify-content: center;
align-items: center;
`

const CardImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`

const TextWrapper = styled(Flex)`
flex-direction: column;
justify-content: flex-start;
gap: 8px;
`

const CardTitle = styled.p`
font-family: Inter;
font-size: 16px;
font-weight: 500;
line-height: 19px;
color: ${colors.white};
margin: 0;
white-space: wrap;
overflow: hidden;
text-overflow: ellipsis;
`

const CardSubtitle = styled.p`
font-family: Inter;
font-size: 14px;
font-weight: 400;
line-height: 17px;
color: ${colors.GRAY6};
margin: 0;
white-space: wrap;
overflow: hidden;
text-overflow: ellipsis;
`
9 changes: 9 additions & 0 deletions src/network/fetchSourcesData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SubmitErrRes,
} from '~/types'
import { api } from '../api'
import { ApiResponse } from '~/components/mindset/components/LandingPage'

type TradarParams = {
skip?: string
Expand Down Expand Up @@ -179,6 +180,14 @@ export interface UpdateSchemaParams {
}
}

export const getNodes = async (): Promise<ApiResponse> => {
const url = `/prediction/graph/search?node_type=['Episode']&&include_properties=true&&includecontent=true`

const response = await api.get<ApiResponse>(url)

return response
}

export const editNodeSchemaUpdate = async (ref_id: string, data: UpdateSchemaParams) => {
const response = await api.put(`/schema/${ref_id}`, JSON.stringify(data))

Expand Down

0 comments on commit b2e545d

Please sign in to comment.