Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/andrew_testing' into feat/revise…
Browse files Browse the repository at this point in the history
…-auth
  • Loading branch information
mikib0 committed Sep 7, 2024
2 parents b5b4688 + 91f0965 commit 55b8729
Show file tree
Hide file tree
Showing 44 changed files with 853 additions and 388 deletions.
2 changes: 0 additions & 2 deletions packages/app/hooks/favorites/index.ts

This file was deleted.

64 changes: 3 additions & 61 deletions packages/app/modules/auth/components/AuthWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { AuthLoader } from './AuthLoader';
import { Redirect } from 'app/components/Redirect';
import { RSpinner, RText, RButton } from '@packrat/ui';
import { Platform, View, Alert } from 'react-native';
import { RSpinner, RText } from '@packrat/ui';
import { Platform, View } from 'react-native';
import LandingPage from 'app/components/landing_page';
import * as LocalAuthentication from 'expo-local-authentication';
import useTheme from 'app/hooks/useTheme';

interface AuthWrapperProps {
Expand All @@ -16,65 +15,8 @@ export const AuthWrapper = ({
children,
unauthorizedElement,
}: AuthWrapperProps) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const { currentTheme } = useTheme();

const authenticate = async () => {
if (Platform.OS === 'web') {
setIsAuthenticated(true);
return;
}

const hasHardware = await LocalAuthentication.hasHardwareAsync();
if (!hasHardware) {
Alert.alert(
'Error',
'Your device does not support biometric authentication.',
);
return;
}

const hasBiometrics = await LocalAuthentication.isEnrolledAsync();
if (!hasBiometrics) {
Alert.alert(
'Error',
'No biometrics are enrolled. Please set up biometrics in your device settings.',
);
return;
}

const result = await LocalAuthentication.authenticateAsync({
promptMessage: 'Authenticate to continue',
fallbackLabel: 'Use Passcode',
});

if (result.success) {
setIsAuthenticated(true);
}
};

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

if (!isAuthenticated) {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: currentTheme.colors.background,
}}
>
<RText style={{ color: currentTheme.colors.text }}>
Please unlock to continue
</RText>
<RButton onPress={authenticate}>Unlock</RButton>
</View>
);
}

const loadingElement =
Platform.OS === 'web' ? (
<RText>Loading...</RText>
Expand Down
2 changes: 2 additions & 0 deletions packages/app/modules/auth/hooks/useUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const useUserQuery = () => {
isLoading: isRequestLoading,
} = queryTrpc.getMe.useQuery(undefined, {
enabled: isRequestEnabled,
staleTime: Infinity,
cacheTime: Infinity,
});

// Sometimes the isLoading state don't work as expected so we have this solution here
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { XStack, RText } from '@packrat/ui';
import { Clock } from '@tamagui/lucide-icons';
import React, { type FC } from 'react';

interface CreatedAtLabelProps {
date: string;
}
export const CreatedAtLabel: FC<CreatedAtLabelProps> = ({ date }) => {
return (
<XStack
style={{ marginTop: 4, alignItems: 'center', maxWidth: '100%' }}
space={4}
>
<Clock size={16} />
<RText>{date}</RText>
</XStack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CreatedAtLabel } from './CreatedAtLabel';
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { AntDesign } from '@expo/vector-icons';
import { RText, XStack } from '@packrat/ui';
import React, { type FC } from 'react';
import { Pressable, type GestureResponderEvent } from 'react-native';

interface FavoriteButtonProps {
isAuthUserFavorite: boolean;
onClick: (e: GestureResponderEvent) => void;
count: number;
}
export const FavoriteButton: FC<FavoriteButtonProps> = ({
onClick,
isAuthUserFavorite,
count,
}) => {
return (
<XStack style={{ alignItems: 'center' }} space="$2">
<Pressable onPress={onClick}>
<AntDesign
name="heart"
size={16}
color={isAuthUserFavorite ? 'red' : undefined}
/>
</Pressable>
<RText style={{ fontSize: 14 }}>{count}</RText>
</XStack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { FavoriteButton } from './FavoriteButton';
Original file line number Diff line number Diff line change
@@ -1,49 +1,60 @@
import { AntDesign } from '@expo/vector-icons';
import { formatDistanceToNow } from 'date-fns';
import { MaterialIcons, Entypo } from '@expo/vector-icons';
import useTheme from 'app/hooks/useTheme';
import { TouchableOpacity } from 'react-native';
import { DuplicateIcon } from 'app/assets/icons';
import { truncateString } from 'app/utils/truncateString';
import { RLink, RText as OriginalRText, ContextMenu } from '@packrat/ui';
import { formatNumber } from 'app/utils/formatNumber';
import { useAddFavorite } from 'app/hooks/favorites';
import React, { type FC } from 'react';
import { type FeedItem, type FeedType } from 'app/modules/feed/model';
import { feedItemPackCardConverter } from './utils';
import { PackCard } from 'app/modules/pack';
import { type CardType } from '@packrat/ui';
import { useAddFavorite } from 'app/modules/feed';
import { useAuthUser } from 'app/modules/auth';
import { useRouter } from 'app/hooks/router';
import { useItemWeightUnit } from 'app/modules/item';
import { convertWeight } from 'app/utils/convertWeight';
import Layout from 'app/components/layout/Layout';
import { Button, Card, H2, Paragraph, XStack, YStack } from 'tamagui';

const RText: any = OriginalRText;

interface CardProps {
type: string;
id: string;
owner: {
id: string;
username: string;
};
name: string;
total_weight: number;
is_public: boolean;
favorited_by: Array<{
id: string;
}>;
favorites_count: number;
owner_id: string | { id: string };
destination: string;
createdAt: string;
owners: Array<{ any: any }>;
duration: string;
itemPacks?: any[];
}

interface User {
id: string;
const convertersByType = {
pack: feedItemPackCardConverter,
};

const cardComponentsByType = {
pack: PackCard,
};

interface FeedCardProps {
feedType: FeedType;
cardType: CardType;
item: FeedItem;
}

export function FeedCard({
export const FeedCard: FC<FeedCardProps> = ({ item, cardType, feedType }) => {
const { addFavorite } = useAddFavorite();
const user = useAuthUser();
const cardProps =
typeof convertersByType[feedType] === 'function'
? convertersByType[feedType](item, user?.id)
: null;

const handleAddToFavorite = () => {
if (!user) return;
const data = {
packId: item.id,
userId: user.id,
};

addFavorite(data);
};

if (!cardProps) {
return null;
}

const CardComponent = cardComponentsByType[feedType];

return (
<CardComponent
{...cardProps}
cardType={cardType}
toggleFavorite={handleAddToFavorite}
/>
);
};

/*
export function FeedCardOld({
type,
id,
owner,
Expand All @@ -58,7 +69,7 @@ export function FeedCard({
owners,
duration,
itemPacks,
}: CardProps) {
}: FeedCardProps) {
console.log('CardProps:', favorited_by);
const user = useAuthUser();
const { currentTheme } = useTheme();
Expand Down Expand Up @@ -246,3 +257,4 @@ export function FeedCard({
</Layout>
);
}
*/
1 change: 1 addition & 0 deletions packages/app/modules/feed/components/FeedCard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { FeedCard } from './FeedCard';
40 changes: 40 additions & 0 deletions packages/app/modules/feed/components/FeedCard/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { type FeedCardProps, type FeedItem } from 'modules/feed/model';
import { formatDistanceToNowStrict } from 'date-fns';
import { type PackDetails } from 'app/modules/pack';
import { truncateString } from 'app/utils/truncateString';

type Converter<Input, Result> = (
input: Input,
currentUserId?: string | number,
) => Result;

export const feedItemPackCardConverter: Converter<
FeedItem,
Omit<FeedCardProps<PackDetails>, 'cardType' | 'toggleFavorite'>
> = (input, currentUserId) => {
return {
id: input.id,
createdAt: formatDistanceToNowStrict(new Date(input.createdAt), {
addSuffix: false,
}),
title: truncateString(input.name, 25),
ownerId:
typeof input.owner_id === 'string'
? input.owner_id
: input.owner_id?.id || '',
details: {
score: input.total_score,
weight: input.total_weight,
quantity:
input?.itemPacks?.reduce(
(accumulator, currentValue) =>
accumulator + currentValue?.item?.quantity,
0,
) ?? 0,
},
isUserFavorite: input?.userFavoritePacks?.some(
(obj) => obj?.userId === currentUserId,
),
favoriteCount: input.favorites_count,
};
};
2 changes: 2 additions & 0 deletions packages/app/modules/feed/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export { FeedCard } from './FeedCard';
export { FeedSearchFilter } from './FeedSearchFilter';
export { SearchProvider, SearchContext } from './SearchProvider';
export { FavoriteButton } from './FavoriteButton';
export { CreatedAtLabel } from './CreatedAtLabel';
2 changes: 2 additions & 0 deletions packages/app/modules/feed/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { useFeed } from './useFeed';
export { useAddFavorite } from './useAddFavorite';
export { useFetchUserFavorites } from './useFetchUserFavorites';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { queryTrpc } from '../../trpc';
import { queryTrpc } from 'app/trpc';

export function useAddFavorite() {
const utils = queryTrpc.useContext();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { queryTrpc } from '../../trpc';
import { queryTrpc } from 'app/trpc';

export const useFetchUserFavorites = (userId: string) => {
const enabled = !!userId;
Expand Down
11 changes: 9 additions & 2 deletions packages/app/modules/feed/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export * from './widgets';
export * from './screens';
export { useFeed } from './hooks';
export { SearchProvider, FeedSearchFilter, FeedCard } from './components';
export { useFeed, useAddFavorite, useFetchUserFavorites } from './hooks';
export {
SearchProvider,
FeedSearchFilter,
FeedCard,
FavoriteButton,
CreatedAtLabel,
} from './components';
export { type FeedCardProps, type FeedItem } from './model';
39 changes: 39 additions & 0 deletions packages/app/modules/feed/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { type CardType } from '@packrat/ui';

export type FeedType = 'pack';

export interface FeedItem {
id: string;
owner: {
id: string;
username: string;
};
name: string;
total_weight: number;
total_score: number;
is_public: boolean;
favorited_by: Array<{
id: string;
}>;
userFavoritePacks?: Array<{ userId: string }>;
favorites_count: number;
owner_id: string | { id: string };
destination: string;
createdAt: string;
owners: Array<{ any: any }>;
duration: string;
type: FeedType;
itemPacks?: any[];
}

export interface FeedCardProps<Details> {
id: string;
title: string;
cardType: CardType;
createdAt: string;
details: Details;
ownerId: string;
favoriteCount: number;
isUserFavorite: boolean;
toggleFavorite: () => void;
}
9 changes: 6 additions & 3 deletions packages/app/modules/feed/screens/FeedScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,16 @@ const Feed = ({ feedType = 'public' }: FeedProps) => {
<FlatList
data={filteredData}
horizontal={false}
ItemSeparatorComponent={() => (
<View style={{ height: 12, width: '100%' }} />
)}
keyExtractor={(item) => item?.id + item?.type}
renderItem={({ item }) => (
<FeedCard
key={item?.id}
type={item?.type}
favorited_by={item?.userFavoritePacks}
{...item}
item={item}
cardType="primary"
feedType={item.type}
/>
)}
ListFooterComponent={() => <View style={{ height: 50 }} />}
Expand Down
Loading

0 comments on commit 55b8729

Please sign in to comment.