Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI] Merge patch-atomic-adding-a-profile-component-11-14-2024-1731598928 into dev #3220

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/expo-lcagents/src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function RootLayoutNav() {
<Stack.Screen name="login" options={{ animation: 'fade' }} />
<Stack.Screen name="profile" options={{ animation: 'fade' }} />
<Stack.Screen name="onboard" options={{ animation: 'fade' }} />

<Stack.Screen name="users" options={{ animation: 'fade'}} />

</Stack>

Expand Down
115 changes: 115 additions & 0 deletions apps/expo-lcagents/src/app/users.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useMemo, useCallback, useEffect } from 'react';
import { YStack, XStack, SizableText, Separator, ScrollView } from 'tamagui';
import {
TamaUserCard,
LottieAnimation,
createSupabaseClient,
TamaProfileContainer,
} from '@kbve/expo-bbq';
import { useNavigation, useLocalSearchParams } from 'expo-router';

const Users = () => {
const navigation = useNavigation();

const { username = 'h0lybyte' } = useLocalSearchParams<{
username?: string;
}>();

const supabaseUrl = 'https://supabase.kbve.com';
const supabaseAnonKey =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzI0NTM2ODAwLAogICJleHAiOiAxODgyMzAzMjAwCn0._fmEmblm0afeLoPXxt8wP2mYpa9gzU-ufx3v8oRTFGg';

const supabase = useMemo(
() => createSupabaseClient(supabaseUrl, supabaseAnonKey),
[supabaseUrl, supabaseAnonKey],
);

const lottieProfileAnimation = useMemo(
() => require('../../assets/json/profile.json'),
[],
);

const updateNavigationOptions = useCallback(() => {
navigation.setOptions({
title: 'KBVE Users',
headerBackTitle: 'Back',
});
}, [navigation]);

useEffect(() => {
updateNavigationOptions();
}, [updateNavigationOptions]);

const MemoizedLottieAnimation = React.memo(LottieAnimation);

return (
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
<XStack
f={1}
jc="center"
ai="center"
padding="$1"
flexDirection="column"
$gtMd={{
flexDirection: 'row',
justifyContent: 'space-between',
maxWidth: '90%',
gap: '$6',
}}
$gtLg={{
flexDirection: 'row',
justifyContent: 'space-between',
maxWidth: '80%',
gap: '$8',
}}>
<YStack
jc="center"
ai="center"
$sm={{ width: '50%', display: 'block' }}
$gtLg={{
flex: 1,
maxWidth: '100%',
}}>
<MemoizedLottieAnimation
lottieJSON={lottieProfileAnimation}
style={{
width: '100%',
height: 'auto',
aspectRatio: 1,
maxWidth: 800,
}}
/>
</YStack>

<YStack
jc="center"
ai="center"
$sm={{ width: '100%' }}
$gtLg={{
flex: 1,
maxWidth: '40%',
paddingLeft: '$8',
}}>
<SizableText size="$4" theme="alt1" $gtLg={{ size: '$6' }}>
KBVE Users
</SizableText>
<Separator
borderColor="cyan"
paddingVertical="$2"
alignSelf="stretch"
$gtLg={{
paddingVertical: '$5',
}}
/>

<TamaProfileContainer
username={username}
supabase={supabase}
/>
</YStack>
</XStack>
</ScrollView>
);
};

export default Users;
8 changes: 8 additions & 0 deletions apps/kbve.com/src/content/journal/11-14.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ import { Adsense, Tasks } from '@kbve/astropad';
The `useMemory` hook is almost done, but we still need to fix the offscreen integration and maybe even utilize the `useIdleCallback`.
Let me get this all pushed out and I will enter the testing realm again tonight.

After making the hook, we can test it out with a profile component?
The idea would be to create two files for us to use, the general profile container and then a wrapper around that said container for the rendering and caching.
The first file would be the Profile itself and the second would be a contaijner that would hold the profile and add the useMemory hook around it?

I am wondering what would be the best way to handle this without causing too many renders but also making it super fast to load and unload profiles.
I am also thinking that after we get the useMemory hook to work, we can add another hook that would help us create a pool of the objects that we could render offscreen and then transition them in.
In theory we would be creating one of those infinite scrolling situations but having it render as they scroll through the application.
The goal would also be to make sure that it does not pull any additional data, by having it cache the results and then use the cache to help build the profiles.
66 changes: 66 additions & 0 deletions packages/expo-bbq/src/components/card/TamaProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { memo } from 'react';
import {
YStack,
XStack,
SizableText,
Avatar,
Button,
Separator,
} from 'tamagui';
import { MessageCircle, Heart, MoreVertical } from '@tamagui/lucide-icons';
import { type IUserCardsPublic } from '../../type';



interface TamaProfileCardProps {
data: IUserCardsPublic;
loading: boolean;
onAction: (actionState: string, content: string) => void;
}

export const TamaProfileCard = memo(function TamaProfileCard({
data,
loading,
onAction,
}: TamaProfileCardProps) {
if (loading) {
return <div>Loading...</div>;
}

return (
<YStack
width={400}
backgroundColor="$background"
borderRadius="$4"
padding="$4"
shadowColor="$shadowColor"
shadowOffset={{ width: 0, height: 4 }}
shadowOpacity={0.1}
shadowRadius={20}>

<XStack justifyContent="space-between" alignItems="center">
<XStack alignItems="center" gap="$2">
{/* <Avatar circular size="$5">
<Avatar.Image source={{ uri: data.avatarUrl }} width="100%" height="100%" />
</Avatar> */}
<YStack>
<SizableText fontWeight="600" fontSize="$2">{data.username}</SizableText>
<SizableText fontSize="$1" color="$gray10">{data.bio}</SizableText>
</YStack>
</XStack>
<Button iconAfter={MoreVertical} onPress={() => onAction("Options", "Options menu opened")} />
</XStack>

<YStack paddingVertical="$3">
<SizableText fontSize="$2" color="$gray11">{data.bio}</SizableText>
</YStack>

<Separator marginVertical="$3" />

<XStack justifyContent="space-between" alignItems="center">
<Button iconAfter={MessageCircle} onPress={() => onAction("Send Message", "Message sent")} />
<Button iconAfter={Heart} onPress={() => onAction("Follow", "User followed")} />
</XStack>
</YStack>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { Suspense, useCallback } from 'react';
import { TamaProfileCard } from '../card/TamaProfileCard';
import { useMemory } from '../../core/useMemory';
import { Spinner as SkeletonLoader, YStack, Button } from 'tamagui';
import { type IUserCardsPublic } from '../../type';

export const TamaProfileContainer = ({
username,
supabase,
}: {
username: string;
supabase: any;
}) => {
const fetchProfileData =
useCallback(async (): Promise<IUserCardsPublic> => {
const { data, error } = await supabase
.from('user_cards_public')
.select('username, bio, socials, style')
.eq('username', username)
.single();

if (error) {
console.error('Error fetching profile:', error);
return { username: '', socials: '', style: '', bio: '' };
}
return data;
}, [supabase, username]);

const { LazyLoadedComponent: MemoizedProfileCard, refreshData } = useMemory(
`profile_${username}`,
fetchProfileData,
TamaProfileCard,
SkeletonLoader,
{
onAction: (actionState: string, content: string) =>
console.log(`Action: ${actionState}, Content: ${content}`),
},
);

return (
<YStack space="$4" padding="$4" alignItems="center">
<Suspense fallback={<SkeletonLoader />}>
<MemoizedProfileCard />
</Suspense>
<Button onPress={refreshData}>Refresh Profile</Button>
</YStack>
);
};

export default TamaProfileContainer;
10 changes: 5 additions & 5 deletions packages/expo-bbq/src/core/useMemory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ type LazyComponentProps<T> = {
loading: boolean;
};

export const useMemory = <T,>(
export const useMemory = <T, P, >(
key: string,
fetchData: () => Promise<T>,
Component: React.ComponentType<LazyComponentProps<T>>,
Component: React.ComponentType<LazyComponentProps<T> & P>,
Skeleton?: React.ComponentType,
extraProps?: P,
) => {
const { data, loading } = useCache<T>(key, fetchData);

Expand All @@ -21,11 +22,10 @@ export const useMemory = <T,>(

const LazyLoadedComponent = useMemo(() => {
const LazyComponent = React.lazy(async () => {
await fetchData();
return {
default: () =>
data ? (
<Component data={data} loading={loading} />
<Component data={data} loading={loading} {...(extraProps as P)} />
) : Skeleton ? (
<Skeleton />
) : (
Expand All @@ -42,7 +42,7 @@ export const useMemory = <T,>(
<LazyComponent />
</Suspense>
);
}, [data, loading, fetchData, Component, Skeleton]);
}, [data, loading, Component, Skeleton, extraProps]);

return { LazyLoadedComponent, refreshData };
};
Expand Down
6 changes: 6 additions & 0 deletions packages/expo-bbq/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export { LottieAnimation } from './components/animation/LottieAnimation';
export { LottieHero } from './components/animation/LottieHero';
export { MaskedView } from './components/creative/MaskedView';

// [WRAPPER]
export { createSupabaseClient } from './components/wrapper/Supabase';

// [CONTAINER]
export { TamaProfileContainer } from './components/container/TamaProfileContainer';

// [CORE]
export { useBBQ } from './core/BBQ';
export { payloadInstance } from './core/Payload';
Expand Down
7 changes: 7 additions & 0 deletions packages/expo-bbq/src/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

export interface IUserCardsPublic {
username: string;
bio: string;
socials: string;
style: string;
}