Skip to content

Commit

Permalink
Merge branch 'main' into dark_theme
Browse files Browse the repository at this point in the history
  • Loading branch information
MSghais committed Jul 17, 2024
2 parents fd0c7f7 + 3faf738 commit 75f8a03
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 23 deletions.
1 change: 1 addition & 0 deletions JoyboyCommunity/src/hooks/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {useClaim} from './useClaim';
export {useEstimateClaim} from './useEstimateClaim';
export {useFileUpload} from './useFileUpload';
32 changes: 32 additions & 0 deletions JoyboyCommunity/src/hooks/api/useFileUpload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {ImagePickerAsset} from 'expo-image-picker';
import {Platform} from 'react-native';

import {ApiInstance} from '../../services/api';
import {dataURLToBlob} from '../../utils/helpers';
import {useApiMutation} from './useApiMutation';

export const useFileUpload = () => {
return useApiMutation({
mutationKey: ['fileUpload'],
mutationFn: (file: ImagePickerAsset) => {
const formData = new FormData();

formData.append(
'file',
Platform.OS === 'web'
? dataURLToBlob(file.uri)
: ({
uri: file.uri,
name: 'file',
type: file.mimeType,
} as any),
);

return ApiInstance.post('/file', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
},
});
};
7 changes: 6 additions & 1 deletion JoyboyCommunity/src/modules/Post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ export const Post: React.FC<PostProps> = ({asComment, event}) => {
<View style={styles.info}>
<View style={styles.infoUser}>
<Pressable onPress={() => handleProfilePress(event?.pubkey)}>
<Avatar size={asComment ? 40 : 50} source={require('../../assets/joyboy-logo.png')} />
<Avatar
size={asComment ? 40 : 50}
source={
profile?.image ? {uri: profile.image} : require('../../assets/joyboy-logo.png')
}
/>
</Pressable>

<Pressable style={styles.infoProfile} onPress={handleNavigateToPostDetails}>
Expand Down
4 changes: 2 additions & 2 deletions JoyboyCommunity/src/screens/Auth/SaveKeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const SaveKeys: React.FC<AuthSaveKeysScreenProps> = ({route}) => {
<Auth title="Save your keys">
<View style={styles.inputWithLabel}>
<Text weight="semiBold" color="textSecondary">
Your secret key
Your private key
</Text>
<Input
value={privateKey}
Expand Down Expand Up @@ -74,7 +74,7 @@ export const SaveKeys: React.FC<AuthSaveKeysScreenProps> = ({route}) => {
<InfoIcon width={20} height={20} color={theme.colors.primary} />

<Text color="primary" weight="medium" fontSize={13}>
Your private key is your password, if you lose this key, you will lose access to your
Your private key is your identity, if you lose this key, you will lose access to your
account.
</Text>
</View>
Expand Down
58 changes: 39 additions & 19 deletions JoyboyCommunity/src/screens/EditProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {ScrollView, TouchableOpacity, View} from 'react-native';
import {CopyIconStack} from '../../assets/icons';
import {Button, SquareInput, Text} from '../../components';
import {useEditProfile, useProfile, useStyles, useTheme} from '../../hooks';
import {useFileUpload} from '../../hooks/api';
import {useToast} from '../../hooks/modals';
import {useAuth} from '../../store/auth';
import {EditProfileScreenProps} from '../../types';
Expand All @@ -21,6 +22,8 @@ const UsernameInputLeft = (
);

type FormValues = {
image: string | undefined;
banner: string | undefined;
username: string;
displayName: string;
bio: string;
Expand All @@ -40,6 +43,7 @@ export const EditProfile: React.FC<EditProfileScreenProps> = () => {

const publicKey = useAuth((state) => state.publicKey);
const profile = useProfile({publicKey});
const fileUpload = useFileUpload();
const editProfile = useEditProfile();
const queryClient = useQueryClient();
const {showToast} = useToast();
Expand All @@ -51,7 +55,7 @@ export const EditProfile: React.FC<EditProfileScreenProps> = () => {
showToast({type: 'info', title: 'Public Key Copied to clipboard'});
};

const handlePhotoUpload = async (type: 'profile' | 'cover') => {
const handlePhotoSelect = async (type: 'profile' | 'cover') => {
const pickerResult = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
aspect: type === 'profile' ? [1, 1] : [16, 9],
Expand All @@ -67,20 +71,18 @@ export const EditProfile: React.FC<EditProfileScreenProps> = () => {
};

const onProfilePhotoUpload = async () => {
const file = await handlePhotoUpload('profile');
const file = await handlePhotoSelect('profile');
if (file) setProfilePhoto(file);

// TODO: upload file
};

const onCoverPhotoUpload = async () => {
const file = await handlePhotoUpload('cover');
const file = await handlePhotoSelect('cover');
if (file) setCoverPhoto(file);

// TODO: upload file
};

const initialFormValues: FormValues = {
image: profile.data?.image ?? undefined,
banner: profile.data?.banner ?? undefined,
username: profile.data?.nip05 ?? '',
displayName: profile.data?.displayName ?? profile.data?.name ?? '',
bio: profile.data?.about ?? '',
Expand All @@ -102,18 +104,36 @@ export const EditProfile: React.FC<EditProfileScreenProps> = () => {
};

const onFormSubmit = async (values: FormValues) => {
await editProfile.mutateAsync({
nip05: values.username,
displayName: values.displayName,
about: values.bio,
telegram: values.telegram,
github: values.github,
twitter: values.twitter,
});

queryClient.invalidateQueries({queryKey: ['profile', publicKey]});

showToast({type: 'success', title: 'Profile updated successfully'});
let {image, banner} = values;

try {
if (profilePhoto) {
const result = await fileUpload.mutateAsync(profilePhoto);
if (result.data.url) image = result.data.url;
}

if (coverPhoto) {
const result = await fileUpload.mutateAsync(coverPhoto);
if (result.data.url) banner = result.data.url;
}

await editProfile.mutateAsync({
image,
banner,
nip05: values.username || undefined,
displayName: values.displayName || undefined,
about: values.bio || undefined,
telegram: values.telegram || undefined,
github: values.github || undefined,
twitter: values.twitter || undefined,
});

queryClient.invalidateQueries({queryKey: ['profile', publicKey]});

showToast({type: 'success', title: 'Profile updated successfully'});
} catch (error) {
showToast({type: 'error', title: 'Failed to update profile'});
}
};

return (
Expand Down
14 changes: 14 additions & 0 deletions JoyboyCommunity/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,17 @@ export const decimalsScale = (decimals: number) => `1${Array(decimals).fill('0')

export const shortenPubkey = (pubkey?: string, length = 6) =>
pubkey ? `${pubkey.slice(0, length)}...${pubkey.slice(-length)}` : undefined;

export const dataURLToBlob = (dataURL: string) => {
const byteString = atob(dataURL.split(',')[1]);
const mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];

const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);

for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

return new Blob([ab], {type: mimeString});
};
4 changes: 4 additions & 0 deletions website/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ ACCOUNT_PRIVATE_KEY="0x"

PROVIDER_URL="https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/your_api_key"
NETWORK_NAME="SN_SEPOLIA" # SN_SEPOLIA, SN_MAIN

PINATA_API_KEY="YOUR_PINATA_API_KEY"
PINATA_SECRET_API_KEY="YOUR_PINATA_SECRET_API_KEY"
IPFS_GATEWAT="https://your.ipfs.gateway.url/ipfs"
1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@avnu/avnu-sdk": "^2.0.0",
"@pinata/sdk": "^2.1.0",
"ethers": "^6.13.1",
"framer-motion": "^11.2.4",
"next": "^14.2.3",
Expand Down
1 change: 0 additions & 1 deletion website/src/app/api/deposit/claim/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export async function POST(request: NextRequest) {
return NextResponse.json({transaction_hash}, {status: HTTPStatus.OK});
}
} catch (error) {
console.log(error);
return NextResponse.json(
{code: ErrorCode.TRANSACTION_ERROR, error},
{status: HTTPStatus.InternalServerError},
Expand Down
37 changes: 37 additions & 0 deletions website/src/app/api/file/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {Readable} from 'node:stream';

import {NextRequest, NextResponse} from 'next/server';

import {pinata} from '@/services/pinata';
import {ErrorCode} from '@/utils/errors';
import {HTTPStatus} from '@/utils/http';

export async function POST(request: NextRequest) {
const data = await request.formData();
const file: File | null = data.get('file') as unknown as File;

if (!file) {
return NextResponse.json({code: ErrorCode.BAD_REQUEST}, {status: HTTPStatus.BadRequest});
}

try {
const stream = Readable.fromWeb(file.stream() as any);

const {IpfsHash} = await pinata.pinFileToIPFS(stream, {
pinataMetadata: {
name: file.name,
},
});

return NextResponse.json(
{hash: IpfsHash, url: `${process.env.IPFS_GATEWAY}/${IpfsHash}`},
{status: HTTPStatus.OK},
);
} catch (error) {
console.log(error);
return NextResponse.json(
{code: ErrorCode.TRANSACTION_ERROR, error},
{status: HTTPStatus.InternalServerError},
);
}
}
12 changes: 12 additions & 0 deletions website/src/services/pinata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import PinataSDK from '@pinata/sdk';

if (!process.env.PINATA_API_KEY) throw new Error('PINATA_API_KEY is not set');
if (!process.env.PINATA_SECRET_API_KEY) throw new Error('PINATA_SECRET_API_KEY is not set');
if (!process.env.IPFS_GATEWAY) throw new Error('IPFS_GATEWAY is not set');

export const pinata = new PinataSDK({
pinataApiKey: process.env.PINATA_API_KEY,
pinataSecretApiKey: process.env.PINATA_SECRET_API_KEY,
});

pinata.testAuthentication();
Loading

0 comments on commit 75f8a03

Please sign in to comment.