Skip to content

Commit

Permalink
Merge branch 'main' into FEAT-snip5
Browse files Browse the repository at this point in the history
  • Loading branch information
VictoriaAde authored Jun 5, 2024
2 parents fe753cb + 63e1f3b commit 4773e16
Show file tree
Hide file tree
Showing 24 changed files with 561 additions and 34 deletions.
6 changes: 6 additions & 0 deletions JoyboyCommunity/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
{
"faceIDPermission": "Allow $(PRODUCT_NAME) to use Face ID."
}
],
[
"expo-image-picker",
{
"photosPermission": "The app accesses your photos to let you share them with your friends."
}
]
]
}
Expand Down
2 changes: 2 additions & 0 deletions JoyboyCommunity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
"expo": "~51.0.8",
"expo-clipboard": "~6.0.3",
"expo-crypto": "~13.0.2",
"expo-image-picker": "~15.0.5",
"expo-secure-store": "~13.0.1",
"expo-splash-screen": "~0.27.4",
"expo-status-bar": "~1.12.1",
"fast-text-encoding": "^1.0.6",
"formik": "^2.4.6",
"memoize-one": "^6.0.0",
"pbkdf2": "^3.1.2",
"react": "18.2.0",
Expand Down
2 changes: 2 additions & 0 deletions JoyboyCommunity/src/app/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {CreateAccount} from '../screens/Auth/CreateAccount';
import {Login} from '../screens/Auth/Login';
import {SaveKeys} from '../screens/Auth/SaveKeys';
import {CreatePost} from '../screens/CreatePost';
import {EditProfile} from '../screens/EditProfile';
import {Feed} from '../screens/Feed';
import {PostDetail} from '../screens/PostDetail';
import {Profile} from '../screens/Profile';
Expand Down Expand Up @@ -127,6 +128,7 @@ const MainNavigator: React.FC = () => {
<MainStack.Navigator screenOptions={{headerShown: false}}>
<MainStack.Screen name="Home" component={HomeBottomTabNavigator} />
<MainStack.Screen name="Profile" component={Profile} />
<MainStack.Screen name="EditProfile" component={EditProfile} />
<MainStack.Screen name="CreatePost" component={CreatePost} />
<MainStack.Screen name="PostDetail" component={PostDetail} />
</MainStack.Navigator>
Expand Down
27 changes: 22 additions & 5 deletions JoyboyCommunity/src/assets/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ export const CommentIcon: React.FC<SvgProps> = (props) => {
};

export const CopyIconStack: React.FC<SvgProps> = (props: SvgProps) => (
<Svg width={24} height={24} fill="none" {...props} viewBox="0 0 24 24">
<Svg width={24} height={24} viewBox="0 0 24 24" fill="none" {...props}>
<Path
opacity="0.4"
d="M16.0549 8.25C17.4225 8.24998 18.5248 8.24996 19.3918 8.36652C20.2919 8.48754 21.0497 8.74643 21.6517 9.34835C22.2536 9.95027 22.5125 10.7081 22.6335 11.6083C22.75 12.4752 22.75 13.5775 22.75 14.9451V16.0549C22.75 17.4225 22.75 18.5248 22.6335 19.3918C22.5125 20.2919 22.2536 21.0497 21.6517 21.6517C21.0497 22.2536 20.2919 22.5125 19.3918 22.6335C18.5248 22.75 17.4225 22.75 16.0549 22.75H14.9451C13.5775 22.75 12.4752 22.75 11.6082 22.6335C10.7081 22.5125 9.95027 22.2536 9.34835 21.6516C8.74643 21.0497 8.48754 20.2919 8.36652 19.3918C8.24996 18.5248 8.24998 17.4225 8.25 16.0549V14.9451C8.24998 13.5775 8.24996 12.4752 8.36652 11.6082C8.48754 10.7081 8.74643 9.95027 9.34835 9.34835C9.95027 8.74643 10.7081 8.48754 11.6083 8.36652C12.4752 8.24996 13.5775 8.24998 14.9451 8.25H16.0549Z"
Expand All @@ -265,8 +265,8 @@ export const CopyIconStack: React.FC<SvgProps> = (props: SvgProps) => (
</Svg>
);

export const InfoIcon = (props: SvgProps) => (
<Svg width={18} height={18} fill="none" {...props} viewBox="0 0 18 18">
export const InfoIcon: React.FC<SvgProps> = (props) => (
<Svg width={18} height={18} viewBox="0 0 18 18" fill="none" {...props}>
<Path
fillRule="evenodd"
clipRule="evenodd"
Expand All @@ -276,8 +276,8 @@ export const InfoIcon = (props: SvgProps) => (
</Svg>
);

export const LockIcon = (props: SvgProps) => (
<Svg width={32} height={32} fill="none" {...props} viewBox="0 0 32 32">
export const LockIcon: React.FC<SvgProps> = (props) => (
<Svg width={32} height={32} viewBox="0 0 32 32" fill="none" {...props}>
<Path
fillRule="evenodd"
clipRule="evenodd"
Expand All @@ -286,3 +286,20 @@ export const LockIcon = (props: SvgProps) => (
/>
</Svg>
);

export const UploadIcon: React.FC<SvgProps> = (props) => (
<Svg viewBox="0 0 44 44" fill="none" {...props}>
<Rect width="44" height="44" rx="22" fill="#14142C" />
<Path
fillRule="evenodd"
clipRule="evenodd"
d="M22.8382 29.7083C22.8382 30.1685 22.4651 30.5416 22.0049 30.5416C21.5447 30.5416 21.1716 30.1685 21.1716 29.7083V25.9583H20.6763C20.53 25.9583 20.3502 25.9585 20.2032 25.9401L20.2004 25.9398C20.0951 25.9266 19.615 25.8668 19.3864 25.3954C19.1573 24.923 19.4089 24.5063 19.4633 24.4161L19.4653 24.4128C19.5422 24.2853 19.654 24.1428 19.7459 24.0257L19.7657 24.0005C20.0112 23.6873 20.3295 23.2838 20.6466 22.9579C20.8047 22.7953 20.9858 22.6277 21.1782 22.4953C21.3492 22.3776 21.6411 22.2083 22 22.2083C22.3589 22.2083 22.6507 22.3776 22.8217 22.4953C23.0142 22.6277 23.1952 22.7953 23.3534 22.9579C23.6705 23.2838 23.9887 23.6873 24.2343 24.0005L24.2541 24.0257C24.346 24.1428 24.4578 24.2852 24.5347 24.4128L24.5367 24.4161C24.5911 24.5063 24.8427 24.9231 24.6136 25.3954C24.385 25.8668 23.9049 25.9266 23.7996 25.9398L23.7967 25.9401C23.6497 25.9585 23.47 25.9583 23.3237 25.9583H22.8382V29.7083Z"
fill="currentColor"
/>
<Path
opacity="0.75"
d="M13.0417 22.4166C13.0417 20.2151 14.5259 18.3609 16.5485 17.7992C16.7119 17.7539 16.7935 17.7312 16.8406 17.683C16.8877 17.6348 16.9082 17.5531 16.9494 17.3898C17.5189 15.1304 19.5639 13.4583 22 13.4583C24.6791 13.4583 26.8857 15.481 27.176 18.0826C27.1987 18.2871 27.2102 18.3893 27.2622 18.4485C27.3143 18.5076 27.4157 18.5323 27.6186 18.5815C29.5352 19.0465 30.9583 20.7737 30.9583 22.8333C30.9583 25.2495 28.9996 27.2083 26.5833 27.2083H25.6672C25.285 27.2083 25.0938 27.2083 25.0688 27.1765C25.0566 27.161 25.0534 27.1532 25.0514 27.1335C25.0472 27.0933 25.2099 26.9352 25.5354 26.6188C26.3605 25.8169 26.3792 24.4979 25.5772 23.6728C25.0368 22.9984 24.5262 22.2851 23.8649 21.7218C23.3405 21.2752 22.7022 20.9583 22 20.9583C21.2978 20.9583 20.6595 21.2752 20.1351 21.7218C19.4737 22.2851 18.9631 22.9984 18.4227 23.6728C17.6208 24.4979 17.6395 25.8169 18.4646 26.6188C18.79 26.9352 18.9528 27.0933 18.9486 27.1335C18.9465 27.1532 18.9434 27.161 18.9311 27.1765C18.9061 27.2083 18.715 27.2083 18.3328 27.2083H17.8333C15.187 27.2083 13.0417 25.0629 13.0417 22.4166Z"
fill="currentColor"
/>
</Svg>
);
35 changes: 35 additions & 0 deletions JoyboyCommunity/src/components/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {useId} from 'react';
import {ImageSourcePropType} from 'react-native';
import {Defs, Image, ImageProps, Path, Pattern, Svg} from 'react-native-svg';

export type AvatarProps = ImageProps & {
size?: number;
source?: ImageSourcePropType;
};

export const Avatar: React.FC<AvatarProps> = ({size, source}) => {
const id = useId();

return (
<Svg width={size} height={size} viewBox="0 0 96 96" fill="none">
<Path
d="M40.75 4.91784C45.2363 2.32766 50.7637 2.32766 55.25 4.91784L81.6852 20.1802C86.1716 22.7704 88.9352 27.5573 88.9352 32.7376V63.2624C88.9352 68.4427 86.1716 73.2296 81.6852 75.8198L55.25 91.0822C50.7637 93.6723 45.2363 93.6723 40.75 91.0822L14.3148 75.8198C9.82844 73.2296 7.06475 68.4427 7.06475 63.2624V32.7376C7.06475 27.5573 9.82844 22.7704 14.3148 20.1802L40.75 4.91784Z"
fill={`url(#pattern_${id})`}
stroke="#F4F9FF"
strokeWidth="3"
/>

<Defs>
<Pattern id={`pattern_${id}`} patternUnits="userSpaceOnUse" width="96" height="96">
<Image
id={`image_${id}`}
width="96"
height="96"
preserveAspectRatio="xMinYMin slice"
xlinkHref={source}
/>
</Pattern>
</Defs>
</Svg>
);
};
4 changes: 0 additions & 4 deletions JoyboyCommunity/src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ export type InputProps = TextInputProps & {

export const Input: React.FC<InputProps> = (props) => {
const {
value,
placeholder,
error,
left,
right,
Expand All @@ -41,8 +39,6 @@ export const Input: React.FC<InputProps> = (props) => {
{left}

<TextInput
value={value}
placeholder={placeholder}
style={[styles.input, inputStyleProp]}
placeholderTextColor={theme.colors.inputPlaceholder}
underlineColorAndroid="transparent"
Expand Down
33 changes: 33 additions & 0 deletions JoyboyCommunity/src/components/SquareInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {useStyles} from '../../hooks';
import {Input, InputProps} from '../Input';
import stylesheet from './styles';

export type SquareInputProps = InputProps;

export const SquareInput: React.FC<SquareInputProps> = (props) => {
const {
error,
left,
right,
style: styleProp,
containerStyle: containerStyleProp,
inputStyle: inputStyleProp,
multiline,
...inputProps
} = props;

const styles = useStyles(stylesheet, !!left, !!right, !!multiline);

return (
<Input
style={[styles.content, styleProp]}
containerStyle={[styles.container, containerStyleProp]}
inputStyle={[styles.input, inputStyleProp]}
error={error}
left={left}
right={right}
multiline={multiline}
{...inputProps}
/>
);
};
40 changes: 40 additions & 0 deletions JoyboyCommunity/src/components/SquareInput/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {Spacing, ThemedStyleSheet} from '../../styles';

export default ThemedStyleSheet((theme, left: boolean, right: boolean, multiline: boolean) => ({
container: {
width: '100%',
},
content: {
borderRadius: 8,
height: 48,

...(multiline && {
height: 110,
}),

...(left && {
paddingLeft: Spacing.small,
}),

...(right && {
paddingRight: Spacing.small,
}),
},

input: {
paddingHorizontal: Spacing.small,

...(multiline && {
paddingVertical: Spacing.small,
textAlignVertical: 'top',
}),

...(left && {
paddingLeft: Spacing.none,
}),

...(right && {
paddingRight: Spacing.none,
}),
},
}));
2 changes: 2 additions & 0 deletions JoyboyCommunity/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {Avatar} from './Avatar';
export {Button} from './Button';
export {Divider} from './Divider';
export {Header} from './Header';
Expand All @@ -14,6 +15,7 @@ export {RootScreenContainer} from './Skeleton/RootScreenContainer';
export {RowContainer} from './Skeleton/RowContainer';
export {ScreenContainer} from './Skeleton/ScreenContainer';
export {ScrollableContainer} from './Skeleton/ScrollableContainer';
export {SquareInput} from './SquareInput';
export {Story} from './Story';
export {Text} from './Text';
export {TextButton} from './TextButton';
8 changes: 6 additions & 2 deletions JoyboyCommunity/src/context/NostrContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import NDK from '@nostr-dev-kit/ndk';
import NDK, {NDKPrivateKeySigner} from '@nostr-dev-kit/ndk';
import {createContext, useContext, useMemo} from 'react';

import {useAuth} from '../store/auth';
import {JOYBOY_RELAYS} from '../utils/relay';

export type NostrContextType = {
Expand All @@ -11,12 +12,15 @@ export type NostrContextType = {
export const NostrContext = createContext<NostrContextType | null>(null);

export const NostrProvider: React.FC<React.PropsWithChildren> = ({children}) => {
const privateKey = useAuth((state) => state.privateKey);

const relays = JOYBOY_RELAYS;
const ndk = useMemo(() => {
return new NDK({
explicitRelayUrls: relays,
signer: privateKey ? new NDKPrivateKeySigner(privateKey) : undefined,
});
}, [relays]);
}, [relays, privateKey]);

return <NostrContext.Provider value={{ndk, relays}}>{children}</NostrContext.Provider>;
};
Expand Down
1 change: 1 addition & 0 deletions JoyboyCommunity/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export {useColor} from './useColor';
export {useEditProfile} from './useEditProfile';
export {useNote} from './useNote';
export {useProfile} from './useProfile';
export {useReactions} from './useReactions';
Expand Down
35 changes: 35 additions & 0 deletions JoyboyCommunity/src/hooks/useEditProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {NDKUserProfile} from '@nostr-dev-kit/ndk';
import {useMutation} from '@tanstack/react-query';

import {useNostrContext} from '../context/NostrContext';
import {useAuth} from '../store/auth';

export const useEditProfile = () => {
const {ndk} = useNostrContext();
const {publicKey, privateKey} = useAuth();

return useMutation({
mutationKey: ['editProfile'],
mutationFn: async (data: NDKUserProfile) => {
try {
if (!privateKey) {
throw new Error('Private key is required');
}

const user = ndk.getUser({pubkey: publicKey});
await user.fetchProfile();

if (!user.profile) {
throw new Error('Profile not found');
}

user.profile = {...user.profile, ...data};

return user.publish();
} catch (error) {
console.error('Error editing profile', error);
throw error;
}
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const useSendNote = () => {
const {privateKey} = useAuth();

return useMutation({
mutationKey: ['sendNote'],
mutationFn: async (data: {content: string; tags?: string[][]}) => {
if (!privateKey) {
throw new Error('Private key is required');
Expand Down
8 changes: 4 additions & 4 deletions JoyboyCommunity/src/modules/Post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Animated, {
} from 'react-native-reanimated';

import {CommentIcon, LikeFillIcon, LikeIcon, RepostIcon} from '../../assets/icons';
import {Text} from '../../components';
import {Avatar, Text} from '../../components';
import {useProfile, useStyles, useTheme} from '../../hooks';
import {MainStackNavigationProps} from '../../types';
import {timestampToHumanReadable} from '../../utils/common-utils';
Expand All @@ -33,7 +33,7 @@ export const Post: React.FC<PostProps> = ({asComment, event}) => {
const {data: profile} = useProfile({publicKey: event?.pubkey});

const theme = useTheme();
const styles = useStyles(stylesheet, asComment);
const styles = useStyles(stylesheet);

const [isLiked, setIsLiked] = useState(false);
const [likes, setLikes] = useState(12); // static value for now
Expand Down Expand Up @@ -100,9 +100,9 @@ export const Post: React.FC<PostProps> = ({asComment, event}) => {
<View style={styles.info}>
<View style={styles.infoUser}>
<Pressable onPress={() => handleProfilePress(event?.pubkey)}>
<Image
<Avatar
size={asComment ? 40 : 50}
source={require('../../../assets/joyboy-logo.png')}
style={styles.infoUserAvatar}
/>
</Pressable>

Expand Down
6 changes: 1 addition & 5 deletions JoyboyCommunity/src/modules/Post/styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Spacing, ThemedStyleSheet} from '../../styles';

export default ThemedStyleSheet((theme, asComment: boolean) => ({
export default ThemedStyleSheet((theme) => ({
container: {},

repost: {
Expand All @@ -21,10 +21,6 @@ export default ThemedStyleSheet((theme, asComment: boolean) => ({
alignItems: 'center',
gap: Spacing.small,
},
infoUserAvatar: {
width: asComment ? 40 : 50,
height: asComment ? 40 : 50,
},
infoProfile: {
flex: 1,
},
Expand Down
4 changes: 2 additions & 2 deletions JoyboyCommunity/src/screens/Auth/CreateAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {canUseBiometricAuthentication} from 'expo-secure-store';
import {useState} from 'react';
import {Alert} from 'react-native';
import {Alert, Platform} from 'react-native';

import {LockIcon} from '../../assets/icons';
import {Button, Input, TextButton} from '../../components';
Expand All @@ -27,7 +27,7 @@ export const CreateAccount: React.FC<AuthCreateAccountScreenProps> = ({navigatio
await storePrivateKey(privateKey, password);
await storePublicKey(publicKey);

const biometySupported = canUseBiometricAuthentication();
const biometySupported = Platform.OS !== 'web' && canUseBiometricAuthentication();
if (biometySupported) {
Alert.alert('Easy login', 'Would you like to use biometrics to login?', [
{
Expand Down
3 changes: 2 additions & 1 deletion JoyboyCommunity/src/screens/Auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {canUseBiometricAuthentication} from 'expo-secure-store';
import {useEffect, useState} from 'react';
import {Platform} from 'react-native';

import {LockIcon} from '../../assets/icons';
import {Button, Input, TextButton} from '../../components';
Expand All @@ -22,7 +23,7 @@ export const Login: React.FC<AuthLoginScreenProps> = ({navigation}) => {

useEffect(() => {
(async () => {
const biometrySupported = canUseBiometricAuthentication();
const biometrySupported = Platform.OS !== 'web' && canUseBiometricAuthentication?.();

if (biometrySupported) {
const storedPassword = await retrievePassword();
Expand Down
Loading

0 comments on commit 4773e16

Please sign in to comment.