Skip to content

Commit

Permalink
allow users to update info (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
zackzouk authored Mar 3, 2024
1 parent 8c85608 commit dbfb7bf
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 16 deletions.
2 changes: 2 additions & 0 deletions client/src/components/lib/Board.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { TopBar } from '@/components/lib/TopBar';
import { BoardScroll } from './BoardScroll';
import { Settings } from './Settings';
import { useCanvasBoardStore } from '@/stores/CanavasBoardStore';

/**
Expand All @@ -16,6 +17,7 @@ export const Board = () => {
<div className="flex flex-col w-5/6 h-full bg-[#FEFDFF]">
<TopBar />
{board === 'Folder' && <BoardScroll />}
{board == 'Settings' && <Settings />}
{/** To be added template and setting page */}
</div>
);
Expand Down
165 changes: 165 additions & 0 deletions client/src/components/lib/Settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import React, { useRef, useState } from 'react';
import { Input } from '../ui/input';
import { Label } from '../ui/label';
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '../ui/card';
import { generateImageUrl } from '@/views/SignUpPage';
import { generateRandId } from '@/lib/bytes';
import { Button } from '../ui/button';
import { useAuthStore } from '@/stores/AuthStore';
import { getDownloadURL, getStorage, ref, uploadBytes } from 'firebase/storage';
import { firebaseApp } from '@/firebaseDB/firebase';
import { REST } from '@/constants';
import axios from 'axios';

/**
* It is the setting page, allows users to change some params
* @author Zakariyya Almalki
*/

export const Settings = () => {
const profilePictureRef = useRef<HTMLInputElement | null>(null);
const firstNameRef = useRef<HTMLInputElement | null>(null);
const lastNameRef = useRef<HTMLInputElement | null>(null);
const { updateUser } = useAuthStore(['updateUser']);

const { userFirstName, userLastName, userPicture, userID } = useAuthStore([
'userFirstName',
'userLastName',
'userPicture',
'userID',
]);

const handleProfilePictureChange = (
e: React.ChangeEvent<HTMLInputElement>,
) => {
const selectedFile = e.target.files?.[0];
if (selectedFile) {
// Read the selected file and display it as a thumbnail
const reader = new FileReader();
reader.onload = (event) => {
if (event.target) {
const thumbnail = event.target.result;
setProfilePictureThumbnail(thumbnail as string);
}
};
reader.readAsDataURL(selectedFile);
}
};

const handleUpdateUserInfo = async () => {
try {
const pictureId = generateRandId();
const profilePic = profilePictureRef.current?.files
? generateImageUrl(profilePictureRef.current?.files[0])
: '';
const storage = getStorage(firebaseApp);
const storageRef = ref(storage, `profilePictures/${pictureId}.jpg`); // give the image a random id
profilePictureRef.current?.files?.[0] &&
uploadBytes(storageRef, profilePictureRef.current?.files[0])
.then((snapshot) => {
return getDownloadURL(snapshot.ref);
})
.catch(() => {
alert('Error uploading');
});
if (profilePictureRef.current?.files?.[0]) {
updateUser({
userFirstName: firstNameRef.current?.value ?? '',
userLastName: lastNameRef.current?.value ?? '',
userPicture: (await profilePic) ?? '',
});
axios.put(REST.user.update, {
id: userID,
fields: {
firstname: firstNameRef.current?.value ?? '',
lastname: lastNameRef.current?.value ?? '',
avatar: pictureId,
},
});
} else {
updateUser({
userFirstName: firstNameRef.current?.value ?? '',
userLastName: lastNameRef.current?.value ?? '',
});
axios.put(REST.user.update, {
id: userID,
fields: {
firstname: firstNameRef.current?.value ?? '',
lastname: lastNameRef.current?.value ?? '',
},
});
}
} catch (error) {
console.error('Error updating user info:', error);
}
};
const [profilePictureThumbnail, setProfilePictureThumbnail] = useState<
string | null
>(null);
if (userPicture.includes('googleuser')) {
// Here you can return a message or a different component indicating the page is disabled
return <div>This page is not available for Google Sign-In users.</div>;
}
return (
<Card className="rounded-none">
<CardHeader className="space-y-1">
<CardTitle className="text-2xl">Update Account Information</CardTitle>
<CardDescription>Edit Account Information Below</CardDescription>
</CardHeader>
<CardContent className="grid gap-1">
<div className="grid grid-cols-1 gap-1">
<Label htmlFor="firstName">Enter New First Name</Label>
<Input
id="firstName"
type="text"
defaultValue={userFirstName}
ref={firstNameRef}
required
/>
</div>
<div className="grid grid-cols-1 gap-1">
<Label htmlFor="lastName">Enter New Last Name</Label>
<Input
id="lastName"
type="text"
defaultValue={userLastName}
ref={lastNameRef}
required
/>
</div>
<div className="grid grid-cols-1 gap-1">
<Label htmlFor="profilePicture">Upload New Profile Picture</Label>
<Input
ref={profilePictureRef}
id="profilePicture"
type="file"
accept=".png, .jpg, .jpeg"
onChange={handleProfilePictureChange}
/>
{profilePictureThumbnail && (
<div>
<Label>Profile Picture Thumbnail</Label>
<img
src={profilePictureThumbnail}
alt="Profile Thumbnail"
className="max-w-xs h-auto"
/>
</div>
)}
</div>
</CardContent>
<CardFooter>
<div className="">
<Button onClick={handleUpdateUserInfo}>Save</Button>
</div>
</CardFooter>
</Card>
);
};
1 change: 1 addition & 0 deletions client/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const REST = {
user: {
get: `${REST_ROOT}/user/getUser`,
create: `${REST_ROOT}/user/createUser`,
update: `${REST_ROOT}/user/updateUser`,
},
sfu: {
poll: `${REST_ROOT}/sfu/poll`,
Expand Down
8 changes: 8 additions & 0 deletions client/src/stores/AuthStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface AuthActions {
userPicture: string,
userID: string,
) => void;
updateUser: (meta: Partial<AuthState>) => void;
}

type AuthStore = AuthActions & AuthState;
Expand Down Expand Up @@ -60,9 +61,16 @@ const setUser =
};
});

const updateUser = (set: SetState<AuthStore>) => (meta: Partial<AuthState>) => {
set((state) => {
return { ...state, ...meta };
});
};

/** Store Hook */
const AuthStore = create<AuthStore>()((set) => ({
...initialAuthState,
setUser: setUser(set),
updateUser: updateUser(set),
}));
export const useAuthStore = createStoreWithSelectors(AuthStore);
32 changes: 16 additions & 16 deletions client/src/views/SignUpPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ import { useCanvasElementStore } from '@/stores/CanvasElementsStore';
* @author Zakariyya Almalki
*/

export const generateImageUrl = (file: File): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
if (e.target && e.target.result) {
const generatedUrl = e.target.result as string;
resolve(generatedUrl);
} else {
reject(new Error('Failed to generate image URL'));
}
};
// Read the file as a data URL
reader.readAsDataURL(file);
});
};

export function signup(
email: string,
password: string,
Expand Down Expand Up @@ -108,22 +124,6 @@ export default function SignUp() {
pictureId,
);

const generateImageUrl = (file: File): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
if (e.target && e.target.result) {
const generatedUrl = e.target.result as string;
resolve(generatedUrl);
} else {
reject(new Error('Failed to generate image URL'));
}
};
// Read the file as a data URL
reader.readAsDataURL(file);
});
};

const profilePic = profilePictureRef.current?.files
? generateImageUrl(profilePictureRef.current?.files[0])
: '';
Expand Down

0 comments on commit dbfb7bf

Please sign in to comment.