Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions frontend/src/main-page/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import GrantPage from "./grants/GrantPage";
import Header from "./header/Header";
import Users from "./users/Users";
import RestrictedPage from "./restricted/RestrictedPage";
import Settings from "./settings/Settings";


function MainPage() {
Expand All @@ -18,6 +19,7 @@ function MainPage() {
<Route path="/my-grants" element={<GrantPage showOnlyMyGrants={true} />} />
<Route path="/users" element={<Users />} />
<Route path="/restricted" element={<RestrictedPage />} />
<Route path="/settings" element={<Settings />} />
{/* fallback route */}
<Route path="*" element={<GrantPage />} />
</Routes>
Expand Down
77 changes: 77 additions & 0 deletions frontend/src/main-page/settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Button from "./components/Button";
import InfoCard from "./components/InfoCard";
import logo from "../../images/logo.svg";

export default function Settings() {
return (
<div className="px-12 py-8 max-w-5xl">
<h1 className="text-4xl font-bold mb-8 flex justify-start">Settings</h1>

<div className="mb-12">
<div className="flex items-center gap-6">
{/* Avatar */}
<img
src={logo}
alt="Profile"
className="w-24 h-24 rounded-full object-cover"
/>

{/* Buttons + helper text */}
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-bold mb-1 flex justify-start">Profile Picture</h2>
<div className="flex gap-3">

<Button
text="Upload Image"
onClick={() => alert("add upload functionality")}
//To-do: add a upload logo next to the "Upload Image" button
className="bg-primary-900 text-white"
/>
<Button
text="Remove"
onClick={() => alert("remove image")}
className="bg-white text-black border-2 border-grey-500"
/>
</div>

<p className="text-sm text-gray-500">
We support PNGs, JPEGs, and PDFs under 10 MB
</p>
</div>
</div>
</div>

<InfoCard
title="Personal Information"
action={
<Button
//To-do: add a edit logo next to the "Edit" button
text="Edit"
onClick={() => alert("edit personal info")}
className="bg-white text-black border-2 border-grey-500"
/>
}
fields={[
{ label: "First Name", value: "John" },
{ label: "Last Name", value: "Doe" },
{ label: "Email Address", value: "john.doe@gmail.com" },
]}
/>

<div className="flex gap-40 items-center mt-12">
<div>
<h2 className="text-2xl font-bold mb-1 flex justify-start">Change Password</h2>
<p className="text-gray-500">
Re-enter your current password in order to change your password.
</p>
</div>

<Button
text="Change Password"
onClick={() => alert("change password")}
className="bg-white text-black border-2 border-grey-500"
/>
</div>
</div>
);
}
34 changes: 34 additions & 0 deletions frontend/src/main-page/settings/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
type ButtonProps = {
text: string;
onClick: () => void;
className?: string;
logo?: string;
logoPosition?: 'left' | 'right';
}


// Button component where you can pass in text, onClick handler, optional className
// for styling, and an optional logo with its position.
//Styling is default, but can be overridden by passing in a className prop
export default function Button({ text, onClick, className, logo, logoPosition }: ButtonProps) {
return (
<button onClick={onClick}
className={`
px-4 py-2 rounded-3xl font-medium bg-primary-800 text-black border
flex items-center justify-center
${className}
`}
>
{logo && logoPosition === 'left' &&
<span className="mr-2">
<img src={logo}
alt="" className="w-4 h-4" />
</span>}
{text}
{logo && logoPosition === 'right' &&
<span className="ml-2">
<img src={logo} alt="" className="w-4 h-4" />
</span>}
</button>
);
}
40 changes: 40 additions & 0 deletions frontend/src/main-page/settings/components/InfoCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { ReactNode } from "react";

type InfoField = {
label: string;
value: string;
};

type InfoCardProps = {
title?: string;
fields: InfoField[];
action?: ReactNode;
};

export default function InfoCard({ title, fields, action }: InfoCardProps) {
return (
<div className="w-full max-w-3xl rounded-lg bg-white p-6 shadow-sm flex flex-col">
{(title || action) && (
<div className="mb-4 flex items-center justify-between">
{title && (
<h2 className="text-xl font-bold flex justify-start">
{title}
</h2>
)}
{action}
</div>
)}

<div className="grid grid-cols-2 gap-6 text-left">
{fields.map((field) => (
<div key={field.label}>
<p className="text-sm text-gray-500">{field.label}</p>
<p className="text-base font-medium text-gray-900">
{field.value}
</p>
</div>
))}
</div>
</div>
);
}