feat(platform): Add settings page (#8576)

Add settings input form and settings page
This commit is contained in:
Bently
2024-11-07 08:43:56 +00:00
committed by GitHub
parent bf459a17ba
commit b9c7d1a115
4 changed files with 331 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
import type { Meta, StoryObj } from "@storybook/react";
import { SettingsInputForm } from "./SettingsInputForm";
const meta: Meta<typeof SettingsInputForm> = {
title: "AGPT UI/Settings/Settings Input Form",
component: SettingsInputForm,
parameters: {
layout: "fullscreen",
},
};
export default meta;
type Story = StoryObj<typeof SettingsInputForm>;
export const Default: Story = {
args: {
email: "johndoe@email.com",
desktopNotifications: {
first: false,
second: true
}
}
};

View File

@@ -0,0 +1,150 @@
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
interface SettingsInputFormProps {
email?: string;
desktopNotifications?: {
first: boolean;
second: boolean;
};
}
export const SettingsInputForm = ({
email = "johndoe@email.com",
desktopNotifications = { first: false, second: true }
}: SettingsInputFormProps) => {
const [notifications, setNotifications] = React.useState(desktopNotifications);
const handleToggleFirst = () => {
setNotifications(prev => ({
...prev,
first: !prev.first
}));
};
const handleToggleSecond = () => {
setNotifications(prev => ({
...prev,
second: !prev.second
}));
};
return (
<div className="mx-auto w-full max-w-[1077px] px-4 pt-8 sm:px-6 sm:pt-16">
<h1 className="mb-8 text-2xl font-semibold sm:mb-16 sm:text-3xl">Settings</h1>
{/* My Account Section */}
<section aria-labelledby="account-heading">
<h2 id="account-heading" className="mb-8 text-lg font-medium text-neutral-500 sm:mb-12">
My account
</h2>
<div className="flex flex-col gap-7">
<div className="relative">
<div className="flex flex-col gap-1.5">
<label htmlFor="email-input" className="text-base font-medium text-slate-950">
Email
</label>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
<input
id="email-input"
type="email"
value={email}
className="w-full rounded-full border border-neutral-200 bg-transparent px-4 py-2.5 text-base sm:w-[638px]"
readOnly
aria-label="Email address"
/>
<div className="w-full sm:ml-4 sm:w-[88px]">
<Button
variant="default"
size="sm"
className="h-[43px] w-full rounded-full bg-black text-white hover:bg-black/90"
aria-label="Edit email"
>
Edit
</Button>
</div>
</div>
</div>
</div>
<div className="relative">
<div className="flex flex-col gap-1.5">
<label htmlFor="password-input" className="text-base font-medium text-slate-950">
Password
</label>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
<input
id="password-input"
type="password"
value="************"
className="w-full rounded-full border border-neutral-200 bg-transparent px-4 py-2.5 text-base sm:w-[638px]"
readOnly
aria-label="Password field"
/>
<div className="w-full sm:ml-4 sm:w-[88px]">
<Button
variant="default"
size="sm"
className="h-[43px] w-full rounded-full bg-black text-white hover:bg-black/90"
aria-label="Edit password"
>
Edit
</Button>
</div>
</div>
</div>
</div>
</div>
</section>
<div className="my-8 border-t border-neutral-200 sm:my-12" role="separator" />
{/* Notifications Section */}
<section aria-labelledby="notifications-heading">
<h2 id="notifications-heading" className="mb-8 text-lg font-medium text-neutral-500 sm:mb-12">
Notifications
</h2>
<div className="flex flex-col gap-7">
<div className="flex flex-col gap-4 sm:flex-row">
<div className="w-full sm:w-[638px]">
<h3 id="desktop-notif-1" className="text-base font-medium text-slate-950">
Enable desktop notifications
</h3>
<p className="mt-2 text-base text-neutral-600">
More detailed explanation for the notifications that this person is enabling
</p>
</div>
<div className="flex h-[43px] items-center sm:ml-4 sm:w-[88px] sm:justify-center">
<Switch
checked={notifications.first}
onCheckedChange={handleToggleFirst}
aria-labelledby="desktop-notif-1"
aria-label="Toggle desktop notifications"
/>
</div>
</div>
<div className="flex flex-col gap-4 sm:flex-row">
<div className="w-full sm:w-[638px]">
<h3 id="desktop-notif-2" className="text-base font-medium text-slate-950">
Enable desktop notifications
</h3>
<p className="mt-2 text-base text-neutral-600">
More detailed explanation for the notifications that this person is enabling
</p>
</div>
<div className="flex h-[43px] items-center sm:ml-4 sm:w-[88px] sm:justify-center">
<Switch
checked={notifications.second}
onCheckedChange={handleToggleSecond}
aria-labelledby="desktop-notif-2"
aria-label="Toggle desktop notifications"
/>
</div>
</div>
</div>
</section>
</div>
);
};

View File

@@ -0,0 +1,100 @@
import type { Meta, StoryObj } from "@storybook/react";
import { SettingsPage } from "./SettingsPage";
import { IconType } from "../../ui/icons";
const meta: Meta<typeof SettingsPage> = {
title: "AGPT UI/Settings/Settings Page",
component: SettingsPage,
parameters: {
layout: {
center: true,
fullscreen: true,
padding: 0,
},
},
tags: ["autodocs"],
argTypes: {
isLoggedIn: { control: "boolean" },
userName: { control: "text" },
userEmail: { control: "text" },
navLinks: { control: "object" },
activeLink: { control: "text" },
menuItemGroups: { control: "object" },
sidebarLinkGroups: { control: "object" },
},
};
export default meta;
type Story = StoryObj<typeof SettingsPage>;
const mockNavLinks = [
{ name: "Marketplace", href: "/" },
{ name: "Library", href: "/library" },
{ name: "Build", href: "/build" },
];
const mockMenuItemGroups = [
{
items: [
{ icon: IconType.Edit, text: "Edit profile", href: "/profile/edit" },
],
},
{
items: [
{
icon: IconType.LayoutDashboard,
text: "Creator Dashboard",
href: "/dashboard",
},
{
icon: IconType.UploadCloud,
text: "Publish an agent",
href: "/publish",
},
],
},
{
items: [{ icon: IconType.Settings, text: "Settings", href: "/settings" }],
},
{
items: [
{
icon: IconType.LogOut,
text: "Log out",
onClick: () => console.log("Logged out"),
},
],
},
];
const mockSidebarLinkGroups = [
{
links: [
{ text: "Agent dashboard", href: "/dashboard" },
{ text: "Integrations", href: "/integrations" },
{ text: "Profile", href: "/profile" },
{ text: "Settings", href: "/settings" },
],
},
];
export const Default: Story = {
args: {
isLoggedIn: true,
userName: "John Doe",
userEmail: "john@example.com",
navLinks: mockNavLinks,
activeLink: "/settings",
menuItemGroups: mockMenuItemGroups,
sidebarLinkGroups: mockSidebarLinkGroups,
},
};
export const LoggedOut: Story = {
args: {
...Default.args,
isLoggedIn: false,
userName: "",
userEmail: "",
},
};

View File

@@ -0,0 +1,58 @@
import * as React from "react";
import { Navbar } from "@/components/agptui/Navbar";
import { Sidebar } from "@/components/agptui/Sidebar";
import { SettingsInputForm } from "@/components/agptui/SettingsInputForm";
import { IconType } from "@/components/ui/icons";
interface SettingsPageProps {
isLoggedIn: boolean;
userName: string;
userEmail: string;
navLinks: { name: string; href: string }[];
activeLink: string;
menuItemGroups: {
groupName?: string;
items: {
icon: IconType;
text: string;
href?: string;
onClick?: () => void;
}[];
}[];
sidebarLinkGroups: {
links: {
text: string;
href: string;
}[];
}[];
}
export const SettingsPage: React.FC<SettingsPageProps> = ({
isLoggedIn,
userName,
userEmail,
navLinks,
activeLink,
menuItemGroups,
sidebarLinkGroups,
}) => {
return (
<div className="mx-auto w-screen max-w-[1440px] bg-white lg:w-full">
<Navbar
isLoggedIn={isLoggedIn}
userName={userName}
userEmail={userEmail}
links={navLinks}
activeLink={activeLink}
menuItemGroups={menuItemGroups}
/>
<div className="flex min-h-screen flex-col lg:flex-row">
<Sidebar linkGroups={sidebarLinkGroups} />
<main className="flex-1 overflow-hidden px-4 pb-8 pt-4 md:px-6 md:pt-6 lg:px-8 lg:pt-8">
<SettingsInputForm />
</main>
</div>
</div>
);
};