Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1d30e43
Fix sponsor image to fit within container; partial circle shape imple…
fisayoadabs Jan 16, 2025
cf49901
Hmt 99/login redirect (#169)
anthonyych4n Jan 16, 2025
889c7c7
Merge branch 'main' of https://github.com/Code-the-Change-YYC/hackath…
fisayoadabs Feb 5, 2025
169808d
Using base64 and browser compression profile Image is stored in database
fisayoadabs Feb 10, 2025
1875a03
Forgot to update the initialData with profilePicture
fisayoadabs Feb 10, 2025
f336426
I do not have access to s3 but this should work if you try it burton
fisayoadabs Feb 24, 2025
52ab860
Merge branch 'main' of https://github.com/Code-the-Change-YYC/hackath…
fisayoadabs Mar 29, 2025
f1e3254
Added some more config and permissions but it seems as though I still…
fisayoadabs Mar 31, 2025
52457a0
feat: Got the upload to work by using public and linking the identity…
fisayoadabs May 20, 2025
31aaf34
Merge branch 'main' of https://github.com/Code-the-Change-YYC/hackath…
fisayoadabs May 20, 2025
707bf2a
fix: replace useEffect with useQuery and require image to be png(this…
fisayoadabs Jun 5, 2025
1b28df3
fix: changed styling and removed unused code
fisayoadabs Jun 10, 2025
61e7176
Merge branch 'main' of https://github.com/Code-the-Change-YYC/hackath…
fisayoadabs Jun 10, 2025
e43d73e
Merge branch 'main' into HMT-112-profile-picture-storage
fisayoadabs Jun 10, 2025
135a3c2
reinstalled node modules which updated packages
fisayoadabs Jul 2, 2025
c00f76d
downgraded react and next
fisayoadabs Jul 3, 2025
5168423
feat: updated next and react to latest version
fisayoadabs Jul 9, 2025
1dcf8e4
Merge branch 'main' of https://github.com/Code-the-Change-YYC/hackath…
fisayoadabs Aug 7, 2025
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
8 changes: 0 additions & 8 deletions amplify/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,3 @@ backend.auth.resources.cfnResources.cfnUserPool.emailConfiguration = {
sourceArn:
"arn:aws:ses:ca-central-1:847668204885:identity/hackthechangeyyc.ca",
};

backend.addOutput({
storage: {
aws_region: "ca-central-1",
bucket_name:
"amplify-dvv7xnx31hgrk-hmt-amplifydataamplifycodege-o8ge4guj5s8m",
},
});
29 changes: 14 additions & 15 deletions amplify/storage/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ import { defineStorage } from "@aws-amplify/backend";
export const storage = defineStorage({
name: "profileImageStorage",
access: (allow) => ({
"profile-pictures/{entity_id}/*": [
allow.guest.to(["read"]),
allow.entity("identity").to(["read", "write", "delete"]),
"public/*": [
allow.authenticated.to(["read", "write", "delete"]),
allow.groups(["Participant"]).to(["read", "write"]),
allow.groups(["Judge"]).to(["read", "write", "delete"]),
allow.groups(["Admin"]).to(["read", "write", "delete"]),
],
"picture-submissions/*": [
allow.authenticated.to(["read", "write"]),
allow.guest.to(["read", "write"]),
"private/${user}/profilePicture/*": [
// Allow users to manage their own profile pictures
allow.authenticated.to(["read", "write", "delete"]),
allow.groups(["Admin"]).to(["read", "write", "delete"]),
],
"private/{entity_id}/*": [
allow.entity("identity").to(["read", "write", "delete"]),
],
"media/*": [allow.authenticated.to(["read", "write", "delete"])],
"media/profile-pictures/*": [allow.guest.to(["read"])],
"media/albums/*": [allow.authenticated.to(["read"])],
"other/*": [
allow.guest.to(["read"]),
allow.authenticated.to(["read", "write"]),
"media/*": [
allow.authenticated.to(["read", "write", "delete"]),
allow.groups(["Participant"]).to(["read", "write"]),
allow.groups(["Judge"]).to(["read", "write", "delete"]),
allow.groups(["Admin"]).to(["read", "write", "delete"]),
],
}),
});
5 changes: 4 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ["images.ctfassets.net"],
domains: [
"images.ctfassets.net",
"amplify-hackathonmanageme-profileimagestoragebucke-qigdi1utj018.s3.ca-central-1.amazonaws.com",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have to make this global, because this bucket is specific to you only

https://nextjs.org/docs/messages/next-image-unconfigured-host

you might have to upgrade next version to latest, which should be fine

],
},
};

Expand Down
7 changes: 5 additions & 2 deletions src/components/LoginForm/PersonalFormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default function PersonalFormFields({ user }: { user: AuthUser }) {
setFormState((prevState) => ({ ...prevState, [name]: value }));
}
};

if (isPending) {
return <LoadingRing />;
}
Expand Down Expand Up @@ -140,10 +141,12 @@ export default function PersonalFormFields({ user }: { user: AuthUser }) {
<Label htmlFor="profilePicture">* Profile Picture:</Label>
<FileUploader
acceptedFileTypes={["image/*"]}
autoUpload={false}
path="profile-pictures/"
path={({ identityId }) => `public/${identityId}/`}
maxFileCount={1}
isResumable
onUploadSuccess={async ({ key }) => {
console.log("Upload successful! File key:", key);
}}
/>
</div>
<div className="flex w-1/2 flex-col gap-2">
Expand Down
131 changes: 126 additions & 5 deletions src/components/UserProfile/ProfileHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"use client";

import { fetchAuthSession } from "aws-amplify/auth";
import { getUrl, list } from "aws-amplify/storage";
import Image from "next/image";
import { useEffect, useState } from "react";

import { useUser } from "@/components/contexts/UserContext";

Expand All @@ -18,18 +21,136 @@ const RIGHT_SQUIGGLE_STYLES =

export default function ProfileHeader() {
const user = useUser().currentUser;
const [profileImageUrl, setProfileImageUrl] = useState<string | null>(null);

// console.log(user);

// useEffect(() => {
// const getProfilePicture = async () => {
// // Get user ID from appropriate property
// const userId = user?.username;

// if (!userId) {
// console.log("No user ID found in user object", user);
// return;
// }

// console.log("User Found", user);

// try {
// // Try multiple common image filenames since we can't list the directory
// const possibleFilenames = [
// "profile.jpg",
// "profile.jpeg",
// "profile.png",
// "avatar.jpg",
// "avatar.png",
// "photo.jpg",
// "photo.png",
// "image.jpg",
// "image.png",
// ];

// // Try each possible filename
// for (const filename of possibleFilenames) {
// try {
// const profileImageKey = `private/${userId}/profilePicture/${filename}`;

// // Attempt to get the URL directly
// const { url } = await getUrl({
// key: profileImageKey,
// options: { accessLevel: "private" },
// });

// // If successful, set the URL and exit
// setProfileImageUrl(url.href);
// return;
// } catch (fileError) {
// // Continue to the next filename if this one doesn't work
// continue;
// }
// }

// // If we get here, none of the common filenames worked
// // We can still try the list approach as a last resort
// try {
// const result = await list({
// path: `private/${userId}/profilePicture/`,
// options: { accessLevel: "private" },
// });

// if (result.items && result.items.length > 0) {
// // Sort files by last modified date (newest first)
// const sortedFiles = result.items.sort((a, b) => {
// return (
// (b.lastModified?.getTime() || 0) -
// (a.lastModified?.getTime() || 0)
// );
// });

// const latestFile = sortedFiles[0];

// // Get the file URL
// const { url } = await getUrl({
// key: latestFile.path,
// options: { accessLevel: "private" },
// });

// setProfileImageUrl(url.href);
// }
// } catch (listError) {
// // ListBucket permission is likely missing - silently fall back to default
// console.log("List operation failed, using default profile image");
// }
// } catch (error) {
// // Just silently fall back to default image
// console.log("Using default profile image due to access restrictions");
// }
// };

// if (user) {
// getProfilePicture();
// }
// }, [user]);

useEffect(() => {
const fetchProfilePicture = async () => {
try {
const session = await fetchAuthSession();
const identityId = session.identityId;

// Step 1: List all files in the user's folder
const { items } = await list({
path: `public/${identityId}/`,
});

if (items.length > 0) {
// Step 2: Get the key of the first file
const firstFileKey = items[0].path;

// Step 3: Get the public URL of that file
const { url } = await getUrl({
path: firstFileKey || "",
});

// Step 4: Set the URL as the profile picture
setProfileImageUrl(url.href);
} else {
console.warn("No profile picture found for this user.");
}
} catch (error) {
console.error("Error fetching profile picture:", error);
}
};

fetchProfilePicture();
}, []);

return (
<div className={CONTAINER_STYLES}>
<div className={PROFILE_CONTAINER}>
<Image
src={
user?.profilePicture
? user.profilePicture
: "/images/userProfile/profile.png"
} //temporary profile image
src={profileImageUrl || "/images/userProfile/profile.png"} //temporary profile image
alt="Profile Image"
width={120}
height={120}
Expand Down