Skip to content

Commit

Permalink
Merge pull request #27 from UofA-Blueprint/ASC-76-member-profile-picture
Browse files Browse the repository at this point in the history
✨ profile picture component
  • Loading branch information
PaulHo0501 authored Jun 7, 2024
2 parents 7679de9 + 113a8fa commit 1bbe1eb
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import GalleryTestRoute from "./routes/GalleryTestRoute";
// components
import { MemberInformation } from "./components/MemberInformation";
import { LoginModal } from "./components/LoginModal";
import MemberProfilePictureTest from "@/routes/MemberProfilePictureTest";

//#endregion

Expand Down Expand Up @@ -127,6 +128,10 @@ const router = createBrowserRouter([
path: "/gallery-test",
element: <GalleryTestRoute />,
},
{
path: "/member-profile-picture-test",
element: <MemberProfilePictureTest />,
},
]);

function App() {
Expand Down
24 changes: 16 additions & 8 deletions src/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function ColorPickerDropdown({

interface ColorPickerButtonProps {
/** The color currently selected */
selectedColor: ProfileColor;
backgroundColor: ProfileColor;

/** The ref to the button */
buttonRef: React.RefObject<HTMLButtonElement>;
Expand All @@ -115,7 +115,7 @@ interface ColorPickerButtonProps {
handleClick: () => void;
}
function ColorPickerButton({
selectedColor,
backgroundColor,
buttonRef,
handleClick,
}: ColorPickerButtonProps) {
Expand All @@ -132,17 +132,25 @@ function ColorPickerButton({
className={clsx(body)}
onClick={handleClick}
>
<ColorCircle color={selectedColor} />
<ColorCircle color={backgroundColor} />
<div className={clsx(text)}>Background</div>
</button>
);
}

function ColorPicker() {
interface ColorPickerProps {
/** The color currently selected */
backgroundColor: ProfileColor;

/** The callback function to invoke when a color is selected */
setBackgroundColor: (color: ProfileColor) => void;
}
function ColorPicker({
backgroundColor,
setBackgroundColor,
}: ColorPickerProps) {
// State for the color picker
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [selectedColor, setSelectedColor] =
useState<ProfileColor>("bg-profile-air");

// Refs for the button and the dropdown
const buttonRef = useRef<HTMLButtonElement>(null);
Expand Down Expand Up @@ -175,14 +183,14 @@ function ColorPicker() {
return (
<div className={clsx(body)}>
<ColorPickerButton
selectedColor={selectedColor}
backgroundColor={backgroundColor}
buttonRef={buttonRef}
handleClick={() => setIsDropdownOpen(!isDropdownOpen)}
/>
{isDropdownOpen && (
<ColorPickerDropdown
dropdownRef={dropdownRef}
handleClick={setSelectedColor}
handleClick={setBackgroundColor}
/>
)}
</div>
Expand Down
20 changes: 17 additions & 3 deletions src/components/IconOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,29 @@ interface IconOptionProps {

/** Whether the option is selected or not */
selected: boolean;

/** The function to call when the option is clicked */
setSelectedIcon: () => void;
}

const IconOption = ({ icon, color, selected }: IconOptionProps) => {
const body = "flex items-center justify-center w-16 h-16 rounded";
const IconOption = ({
icon,
color,
selected,
setSelectedIcon,
}: IconOptionProps) => {
const body =
"flex items-center justify-center w-16 h-16 rounded cursor-pointer";

const border = "outline outline-2 outline-primary-dark outline-offset-2";

return (
<div className={clsx(body, color, { [border]: selected })}>{icon}</div>
<div
className={clsx(body, color, { [border]: selected })}
onClick={setSelectedIcon}
>
{icon}
</div>
);
};

Expand Down
69 changes: 69 additions & 0 deletions src/components/MemberProfilePicture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ReactNode, useState, useCallback } from "react";
import IconOption from "./IconOption";
import ColorPicker from "./ColorPicker";
import {
PawPrint,
Tree,
Camera,
Pizza,
Atom,
Binoculars,
SoccerBall,
Coffee,
} from "@phosphor-icons/react";
import clsx from "clsx";
import ProfileColor from "@/types/ProfileColor";

const MemberProfilePicture = () => {
const body = "flex flex-col w-full gap-2";

const controls = "flex flex-row items-start justify-between w-full";

const icons =
"flex flex-row items-start justify-start flex-wrap gap-4 w-full";

const header = "text-h4";

const [backgroundColor, setBackgroundColor] =
useState<ProfileColor>("bg-profile-water");

const [selectedIcon, setSelectedIcon] = useState<string | null>(null);

const iconMap: Record<string, ReactNode> = {
PawPrint: <PawPrint size={32} />,
Tree: <Tree size={32} />,
Camera: <Camera size={32} />,
Pizza: <Pizza size={32} />,
Atom: <Atom size={32} />,
Binoculars: <Binoculars size={32} />,
SoccerBall: <SoccerBall size={32} />,
Coffee: <Coffee size={32} />,
};

const iconList = Object.keys(iconMap);

return (
<div className={clsx(body)}>
<div className={clsx(controls)}>
<h2 className={clsx(header)}>Member Profile Picture</h2>
<ColorPicker
backgroundColor={backgroundColor}
setBackgroundColor={setBackgroundColor}
/>
</div>
<div className={clsx(icons)}>
{iconList.map((iconName) => (
<IconOption
key={iconName}
icon={iconMap[iconName]}
color={backgroundColor}
selected={selectedIcon === iconName}
setSelectedIcon={() => setSelectedIcon(iconName)}
/>
))}
</div>
</div>
);
};

export default MemberProfilePicture;
20 changes: 20 additions & 0 deletions src/routes/MemberProfilePictureTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import MemberProfilePicture from "@/components/MemberProfilePicture";
import { Pencil } from "@phosphor-icons/react";
import Modal from "@/components/Modal";

const MemberProfilePictureTest = () => {
return (
<div className="fixed inset-0 flex flex-col gap-6 items-center justify-center bg-gray-900">
<Modal
isOpen={true}
onClose={() => {}}
title="Edit Member Modal"
icon={<Pencil size={32} />}
content={<MemberProfilePicture />}
/>
</div>
);
};

export default MemberProfilePictureTest;

0 comments on commit 1bbe1eb

Please sign in to comment.