Skip to content

Commit

Permalink
recommendations
Browse files Browse the repository at this point in the history
  • Loading branch information
wslyvh committed Nov 1, 2024
1 parent 2db6348 commit 45d4a55
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 46 deletions.
3 changes: 1 addition & 2 deletions devcon-app/src/components/domain/app/dc7/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import { Button } from 'lib/components/button'
// import Portal from 'assets/images/dc-7/portal.png'
import Portal from 'pages/login/dc-7-images/login-backdrop-2.png'
import PhonePreview from 'assets/images/dc-7/phone-preview.png'
import PassportLogo from 'assets/images/dc-7/passport-logo.png'
import PassportLogoBlack from 'assets/images/dc-7/passport-logo-black.png'
import { NotificationCard } from 'components/domain/app/dc7/profile/notifications'
import { SessionCard, PersonalizedSuggestions, tagClass } from 'components/domain/app/dc7/sessions'
import { PersonalizedSuggestions } from 'components/domain/app/dc7/sessions/recommendations'
import { useRecoilState, useRecoilValue } from 'recoil'
import { devaBotVisibleAtom, notificationsAtom, sessionsAtom, useSeenNotifications } from 'pages/_app'
import FoodIcon from 'assets/icons/food-beverage.svg'
Expand Down
43 changes: 1 addition & 42 deletions devcon-app/src/components/domain/app/dc7/sessions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import VideoIcon from 'assets/icons/video-play.svg'
import PenIcon from 'assets/icons/pen.svg'
import QuestionsIcon from 'assets/icons/questions.svg'
import { Button } from 'lib/components/button'
import { PersonalizedSuggestions } from './recommendations'

export const tagClassTwo = (active?: boolean, className?: string) =>
cn(
Expand Down Expand Up @@ -924,48 +925,6 @@ export const ScrollUpComponent = ({ visible }: { visible: boolean }) => {
)
}

// TODO: use recommendation engine to generate personalized suggestions
export const PersonalizedSuggestions = ({
sessions,
standalone,
}: {
sessions: SessionType[]
standalone?: boolean
}) => {
// @ts-ignore
const featuredSessions = useMemo(() => sessions.filter(s => s.featured).sort(() => Math.random() - 0.5), [sessions])

return (
<>
<div className="flex justify-between gap-3 pb-4 px-4 font-semibold">
Schedule Highlights{' '}
{standalone && (
<Link
to="/schedule"
className="shrink-0 select-none cursor-pointer mr-2 rounded-full bg-white border border-solid border-[#E1E4EA] px-3 py-1 text-xs flex items-center justify-center text-[#717784] hover:text-black transition-all duration-300"
>
<p>Go to Schedule</p>
</Link>
)}
</div>

<div className="overflow-hidden">
<SwipeToScroll scrollIndicatorDirections={{ right: true }}>
<div className="flex flex-row gap-3">
{featuredSessions.map((session, index) => (
<SessionCard
session={session}
key={session.sourceId}
className={cn('w-[360px] max-w-[360px] shrink-0', index === 0 ? 'ml-4' : '')}
/>
))}
</div>
</SwipeToScroll>
</div>
</>
)
}

const SESSIONS_PER_PAGE = 25

export const SessionList = ({
Expand Down
141 changes: 141 additions & 0 deletions devcon-app/src/components/domain/app/dc7/sessions/recommendations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useMemo, useState } from 'react'
import SwipeToScroll from 'lib/components/event-schedule/swipe-to-scroll'
import { Session as SessionType } from 'types/Session'
import { Link } from 'components/common/link'
import { SessionCard } from '.'
import { useQuery } from '@tanstack/react-query'
import { useAccountContext } from 'context/account-context'
import { APP_CONFIG } from 'utils/config'
import { Separator } from 'lib/components/ui/separator'
import cn from 'classnames'

interface Props {
sessions: SessionType[]
standalone?: boolean
}

export function PersonalizedSuggestions({ sessions, standalone }: Props) {
const { account } = useAccountContext()
const [filter, setFilter] = useState<'featured' | 'personal' | 'recommended'>('featured')

const featured = useMemo(
() => sessions.filter(s => s.featured).sort((a, b) => a.slot_start - b.slot_start),
[sessions]
)
const personal = useMemo(
() =>
sessions
.filter(s => account?.attending_sessions.includes(s.sourceId))
.sort((a, b) => a.slot_start - b.slot_start),
[sessions, account]
)

const { data: recommended } = useQuery({
queryKey: ['account', 'sessions', 'recommended', account?.id],
queryFn: async () => {
if (!account?.id) {
console.log('Not logged in... No recommendations')
return []
}

try {
const response = await fetch(`${APP_CONFIG.API_BASE_URL}/account/sessions/recommended`)
const { data } = await response.json()
return data.sort((a: SessionType, b: SessionType) => a.slot_start - b.slot_start)
} catch (error) {
console.error('Error fetching recommended sessions', error)
return []
}
},
})

const sessionList = useMemo(() => {
if (filter === 'featured') return featured
if (filter === 'personal') return personal
if (filter === 'recommended') return recommended
return []
}, [filter, featured, personal, recommended])

console.log('FEATURED', featured, featured?.length)
console.log('PERSONAL', personal, personal?.length)
console.log('RECOMMENDED', recommended, recommended?.length)

return (
<>
<div className="flex justify-between gap-3 pb-4 px-4 font-semibold">
Schedule Highlights{' '}
{standalone && (
<Link
to="/schedule"
className="shrink-0 select-none cursor-pointer mr-2 rounded-full bg-white border border-solid border-[#E1E4EA] px-3 py-1 text-xs flex items-center justify-center text-[#717784] hover:text-black transition-all duration-300"
>
<p>Go to Schedule</p>
</Link>
)}
</div>

{standalone && (
<SwipeToScroll scrollIndicatorDirections={{ right: true }}>
<div className="flex flex-row gap-3 flex-nowrap p-1 px-4 text-xs items-center">
<div
className={cn(
'flex shrink-0 items-center justify-center align-middle rounded-full border bg-white border-solid border-transparent shadow px-4 py-1 select-none transition-all duration-300',
filter === 'featured' ? 'border-[#ac9fdf] !bg-[#EFEBFF]' : ''
)}
onClick={() => setFilter('featured')}
>
Featured
</div>

<Separator orientation="vertical" className="h-6" />

{[
{
name: 'Personal',
list: personal,
},
{
name: 'Recommended',
list: recommended,
},
].map(({ name, list }) => {
const isEmpty = !list?.length
return (
<div
key={name}
title={'Login for more personalized recommendations'}
className={cn(
'flex shrink-0 items-center justify-center align-middle rounded-full border bg-white border-solid border-transparent shadow px-4 py-1 select-none transition-all duration-300',
filter === name.toLowerCase() ? 'border-[#ac9fdf] !bg-[#EFEBFF]' : '',
isEmpty ? 'opacity-50 cursor-not-allowed' : 'hover:bg-[#f8f7ff] cursor-pointer'
)}
onClick={() => {
if (!isEmpty) {
setFilter(name.toLowerCase() as 'featured' | 'personal' | 'recommended')
}
}}
>
{name}
</div>
)
})}
</div>
</SwipeToScroll>
)}

<div className={cn('overflow-hidden mb-3', standalone ? 'my-4' : '')}>
<SwipeToScroll scrollIndicatorDirections={{ right: true }}>
<div className="flex flex-row gap-3">
{sessionList?.map((session: SessionType, index: number) => (
<SessionCard
session={session}
key={session.sourceId}
className={cn('w-[360px] max-w-[360px] shrink-0', index === 0 ? 'ml-4' : '')}
/>
))}
</div>
</SwipeToScroll>
</div>
</>
)
}
14 changes: 12 additions & 2 deletions devcon-app/src/context/web3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { mainnet } from '@reown/appkit/networks'
import { cookieToInitialState, WagmiProvider, type Config } from 'wagmi'
import { APP_CONFIG } from 'utils/config'

const queryClient = new QueryClient()

createAppKit({
adapters: [wagmiAdapter],
projectId: APP_CONFIG.WC_PROJECT_ID,
Expand All @@ -36,6 +34,18 @@ interface Props extends PropsWithChildren {

export function Web3Provider(props: Props) {
const initialState = cookieToInitialState(wagmiAdapter.wagmiConfig as Config, props.cookies)
const [queryClient] = React.useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 60 * 1000,
},
},
})
)

return (
<WagmiProvider config={wagmiAdapter.wagmiConfig as Config} initialState={initialState}>
Expand Down

0 comments on commit 45d4a55

Please sign in to comment.