Skip to content

Commit

Permalink
feat: init episode-ai-thingy
Browse files Browse the repository at this point in the history
  • Loading branch information
altaywtf committed Dec 15, 2023
1 parent 9741949 commit c82f5e8
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 4 deletions.
167 changes: 167 additions & 0 deletions components/episode-ai-thingy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
'use client';

import type { Tables } from '@/types/supabase/database';

import { Box, Button, Flex, Text } from '@radix-ui/themes';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { PiRobotBold } from 'react-icons/pi';

import { CollapsiblePanel } from './ui/collapsible-panel';

type Props = {
id: Tables<'episode'>['id'];
};

function MockAIThingy() {
return (
<Box>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam quod
voluptatum quia quos, voluptatem quibusdam quae voluptas, quas, doloribus
voluptate. Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam quod voluptatum quia quos, voluptatem quibusdam quae voluptas,
quas, doloribus voluptate. Lorem ipsum dolor sit amet consectetur
adipisicing elit. Quisquam quod voluptatum quia quos, voluptatem quibusdam
quae voluptas, quas, doloribus voluptate. Lorem ipsum dolor sit amet
consectetur adipisicing elit. Quisquam quod voluptatum quia quos,
voluptatem quibusdam quae voluptas, quas, doloribus voluptate. Lorem ipsum
dolor sit amet consectetur adipisicing elit. Quisquam quod voluptatum quia
quos, voluptatem quibusdam quae voluptas, quas, doloribus voluptate. Lorem
ipsum dolor sit amet consectetur adipisicing elit. Quisquam quod
voluptatum quia quos, voluptatem quibusdam quae voluptas, quas, doloribus
voluptate. Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam quod voluptatum quia quos, voluptatem quibusdam quae voluptas,
quas, doloribus voluptate.
<br />
<br />
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam quod
voluptatum quia quos, voluptatem quibusdam quae voluptas, quas, doloribus
voluptate. Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam quod voluptatum quia quos, voluptatem quibusdam quae voluptas,
quas, doloribus voluptate. Lorem ipsum dolor sit amet consectetur
adipisicing elit. Quisquam quod voluptatum quia quos, voluptatem quibusdam
quae voluptas, quas, doloribus voluptate. Lorem ipsum dolor sit amet
consectetur adipisicing elit. Quisquam quod voluptatum quia quos,
voluptatem quibusdam quae voluptas, quas, doloribus voluptate. Lorem ipsum
dolor sit amet consectetur adipisicing elit. Quisquam quod voluptatum quia
quos, voluptatem quibusdam quae voluptas, quas, doloribus voluptate. Lorem
ipsum dolor sit amet consectetur adipisicing elit. Quisquam quod
voluptatum quia quos, voluptatem quibusdam quae voluptas, quas, doloribus
voluptate. Lorem ipsum dolor sit amet consectetur adipisicing elit.
Quisquam quod voluptatum quia quos, voluptatem quibusdam quae voluptas,
quas, doloribus voluptate.
</Box>
);
}

type State =
| {
timeRemaining: number;
type: 'countdown';
}
| {
type: 'error';
}
| {
type: 'idle';
}
| {
type: 'loading';
}
| {
type: 'success';
};

export function EpisodeAIThingy(props: Props) {
const [state, setState] = useState<State>({ type: 'idle' });

const doTheThingy = useCallback(async () => {
if (state.type !== 'idle') {
return;
}

try {
setState({ type: 'loading' });
await fetch(`https://dummyjson.com/todos`);
setState({ timeRemaining: 5, type: 'countdown' });
} catch (error) {
setState({ type: 'error' });
}
}, [state.type]);

useEffect(() => {
if (state.type === 'countdown') {
const interval = setInterval(() => {
setState((_state) => {
if (_state.type !== 'countdown') {
return _state;
}

if (_state.timeRemaining <= 0) {
return { type: 'success' };
}

return { ..._state, timeRemaining: _state.timeRemaining - 1 };
});
}, 1000);

return () => {
clearInterval(interval);
};
}
}, [state]);

const buttonText = useMemo(() => {
switch (state.type) {
case 'countdown':
return state.timeRemaining === 0
? `THERE YOU GO!`
: `Presenting the AI thingy in ${state.timeRemaining} seconds...`;
case 'error':
return 'Error';
case 'idle':
return 'Do the AI thingy!';
case 'loading':
return 'Doing the AI thingy...';
case 'success':
return 'Done!';
}
}, [state]);

return (
<Box id={props.id.toString()} position="relative">
{state.type === 'success' ? null : (
<Flex
align="center"
height="100%"
justify="center"
left="0"
position="absolute"
style={{ backdropFilter: 'blur(3px)', borderRadius: 10, zIndex: 1 }}
top="0"
width="100%"
>
<Button highContrast onClick={doTheThingy} size="4">
<Flex align="center" gap="2" justify="center">
<Text mt="1" size="6" trim="both">
<PiRobotBold />
</Text>

<Text
style={{
textTransform: 'uppercase',
}}
weight="bold"
>
{buttonText}
</Text>
</Flex>
</Button>
</Flex>
)}

<CollapsiblePanel open={state.type === 'success'} title="Episode summary">
<MockAIThingy />
</CollapsiblePanel>
</Box>
);
}
1 change: 1 addition & 0 deletions components/episode-detail.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const Primary: StoryObj<typeof EpisodeDetail.Content> = {
<EpisodeDetail.Content
description="Guillermo Rauch (@rauchg) is the CEO of Vercel and the creator of Next.js. In this episode, we talk about how Vercel found extreme product-market fit by focusing on simplification."
duration={4021}
id={0}
image="https://megaphone.imgix.net/podcasts/9426cbf8-25fe-11ec-a0b4-fb6861cc1eaf/image/In_Depth_Podcast_Logo.jpeg?ixlib=rails-4.3.1&max-w=3000&max-h=3000&fit=crop&auto=format,compress"
published_date={1699531200}
show={{
Expand Down
8 changes: 4 additions & 4 deletions components/episode-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { createSupabaseServerClient } from '@/lib/services/supabase/server';
import { Avatar, Box, Flex, Heading, Text } from '@radix-ui/themes';
import { cookies } from 'next/headers';

import { EpisodeAIThingy } from './episode-ai-thingy';
import { EpisodeDescription } from './episode-description';
import { CollapsiblePanel } from './ui/collapsible-panel';
import { DecorativeBox } from './ui/decorative-box';

function EpisodeDetailContent(
props: Pick<
Tables<'episode'>,
'description' | 'duration' | 'image' | 'published_date' | 'title'
'description' | 'duration' | 'id' | 'image' | 'published_date' | 'title'
> & {
show: {
id: Tables<'show'>['id'];
Expand Down Expand Up @@ -51,9 +52,7 @@ function EpisodeDetailContent(
</CollapsiblePanel>
) : null}

<Box height="9" width="100%">
<DecorativeBox />
</Box>
<EpisodeAIThingy id={props.id} />
</Flex>
);
}
Expand All @@ -75,6 +74,7 @@ async function EpisodeDetailPage(props: { id: Tables<'episode'>['id'] }) {
<EpisodeDetailContent
description={data.description}
duration={data.duration}
id={data.id}
image={data.image}
published_date={data.published_date}
show={data.show}
Expand Down

0 comments on commit c82f5e8

Please sign in to comment.