update pay function
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { useState } from "react";
|
||||
import Switch from "@/components/Switch";
|
||||
import Button from "@/components/Button";
|
||||
|
||||
const DataControls = ({}) => {
|
||||
const [improve, setImprove] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between gap-6 mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="max-w-101">
|
||||
<div className="text-label-md">
|
||||
Improve the model for everyone
|
||||
</div>
|
||||
<div className="text-sub-600">
|
||||
Allow your content to be used to train our models, which
|
||||
makes AI better for you and everyone who uses it. We
|
||||
take steps to protect your privacy.{" "}
|
||||
<button className="underline text-blue-500 hover:no-underline">
|
||||
Learn more
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Switch checked={improve} onChange={setImprove} isSmall />
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-6 mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="text-label-md">Export Data</div>
|
||||
<Button
|
||||
className="!h-10 !rounded-[0.625rem] !bg-weak-50"
|
||||
isStroke
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-6 mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="text-label-md">Shared Links</div>
|
||||
<Button
|
||||
className="!h-10 !rounded-[0.625rem] !bg-weak-50"
|
||||
isStroke
|
||||
>
|
||||
Manage
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-6 mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="text-label-md">Archive all chats</div>
|
||||
<Button
|
||||
className="!h-10 !rounded-[0.625rem] !bg-weak-50"
|
||||
isStroke
|
||||
>
|
||||
Archive all
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex justify-between items-center gap-6">
|
||||
<div className="text-label-md">Delete Account</div>
|
||||
<Button className="!h-10 !rounded-[0.625rem]" isRed>
|
||||
Delete Account
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataControls;
|
||||
@@ -0,0 +1,76 @@
|
||||
import { useState, useRef } from "react";
|
||||
import Image from "@/components/Image";
|
||||
import Button from "@/components/Button";
|
||||
import Icon from "@/components/Icon";
|
||||
|
||||
const UploadImage = ({}) => {
|
||||
const [preview, setPreview] = useState<string | null>(
|
||||
"/images/avatar-1.png"
|
||||
);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
const objectUrl = URL.createObjectURL(file);
|
||||
setPreview(objectUrl);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemove = () => {
|
||||
setPreview(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="relative flex justify-center items-center bg-soft-200 size-11.5 rounded-full overflow-hidden">
|
||||
{preview ? (
|
||||
<Image
|
||||
className="size-full opacity-100"
|
||||
src={preview}
|
||||
width={48}
|
||||
height={48}
|
||||
alt="avatar"
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
className="size-6 fill-strong-950"
|
||||
name="profile"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative">
|
||||
<input
|
||||
className="absolute inset-0 opacity-0 cursor-pointer z-10 object-cover"
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
onChange={handleChange}
|
||||
accept="image/*"
|
||||
/>
|
||||
<Button className="!h-9 rounded-lg" isStroke>
|
||||
Upload image
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
className="!w-9 !h-9 !px-0 rounded-lg"
|
||||
isStroke
|
||||
onClick={handleRemove}
|
||||
>
|
||||
<Image
|
||||
className="size-6 opacity-100"
|
||||
src="/images/trash.svg"
|
||||
width={24}
|
||||
height={24}
|
||||
alt=""
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-1.5 text-soft-400 max-md:text-p-xs">
|
||||
We only support JPG, JPEG, or ,PNG file. 1MB max.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadImage;
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useState } from "react";
|
||||
import Field from "@/components/Field";
|
||||
import Icon from "@/components/Icon";
|
||||
import Button from "@/components/Button";
|
||||
import UploadImage from "./UploadImage";
|
||||
|
||||
const General = ({}) => {
|
||||
const [fullName, setFullName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [phoneNumber, setPhoneNumber] = useState("");
|
||||
|
||||
return (
|
||||
<div className="-mt-5 max-md:mt-0">
|
||||
<div className="flex items-center mb-3 pb-3 border-b border-stroke-soft-200 max-md:flex-col max-md:items-start max-md:gap-3">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Avatar</div>
|
||||
<div className="text-sub-600">Update full name</div>
|
||||
</div>
|
||||
<UploadImage />
|
||||
</div>
|
||||
<div className="mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="mb-3">
|
||||
<div className="text-label-md">Personal Information</div>
|
||||
<div className="text-sub-600">
|
||||
Edit your personal information
|
||||
</div>
|
||||
</div>
|
||||
<Field
|
||||
className="mb-3"
|
||||
label="Full name"
|
||||
placeholder="Enter full name"
|
||||
value={fullName}
|
||||
onChange={(e) => setFullName(e.target.value)}
|
||||
required
|
||||
isSmall
|
||||
/>
|
||||
<Field
|
||||
className="mb-1"
|
||||
label="Email"
|
||||
placeholder="Enter email"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
isSmall
|
||||
/>
|
||||
<button className="inline-flex items-center gap-2 text-label-xs text-sub-600 transition-opacity hover:opacity-80">
|
||||
<Icon className="!size-4" name="plus" />
|
||||
Add another
|
||||
</button>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<div className="mb-3">
|
||||
<div className="text-label-md">Phone number</div>
|
||||
<div className="text-sub-600">Update your phone number</div>
|
||||
</div>
|
||||
<Field
|
||||
className=""
|
||||
label="Phone number"
|
||||
placeholder="Enter phone number"
|
||||
type="tel"
|
||||
value={phoneNumber}
|
||||
onChange={(e) => setPhoneNumber(e.target.value)}
|
||||
required
|
||||
isSmall
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-end gap-3">
|
||||
<Button className="!h-10 !px-4.5 !bg-weak-50" isStroke>
|
||||
Discard
|
||||
</Button>
|
||||
<Button className="!h-10 !px-4.5" isBlack>
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default General;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useState } from "react";
|
||||
import Switch from "@/components/Switch";
|
||||
|
||||
const Speech = ({}) => {
|
||||
const [responses, setResponses] = useState(true);
|
||||
const [push, setPush] = useState(true);
|
||||
const [email, setEmail] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex items-center mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Responses</div>
|
||||
<div className="text-sub-600">Ai response Push</div>
|
||||
</div>
|
||||
<Switch checked={responses} onChange={setResponses} isSmall />
|
||||
</div>
|
||||
<div className="flex items-center mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Push</div>
|
||||
</div>
|
||||
<Switch checked={push} onChange={setPush} isSmall />
|
||||
</div>
|
||||
<div className="flex items-center mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Email</div>
|
||||
</div>
|
||||
<Switch checked={email} onChange={setEmail} isSmall />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Speech;
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useState } from "react";
|
||||
import Switch from "@/components/Switch";
|
||||
import Button from "@/components/Button";
|
||||
|
||||
const Security = ({}) => {
|
||||
const [authentication, setAuthentication] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between gap-6 mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="max-w-101">
|
||||
<div className="text-label-md">
|
||||
Mlti-factor authentication
|
||||
</div>
|
||||
<div className="text-sub-600">
|
||||
Require an extra security challenge when logging in. If
|
||||
you are unable to pass this challenge, you will have the
|
||||
option to recover your account via email.
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={authentication}
|
||||
onChange={setAuthentication}
|
||||
isSmall
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between gap-6 max-md:flex-col max-md:gap-3">
|
||||
<div className="max-w-101">
|
||||
<div className="text-label-md">Log out of all devices</div>
|
||||
<div className="text-sub-600">
|
||||
Log out of all active sessions across all devices,
|
||||
including your current session. It may take up to 30
|
||||
minutes for other devices to be logged out.
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
className="shrink-0 !h-10 !rounded-[0.625rem] !bg-weak-50"
|
||||
isStroke
|
||||
>
|
||||
Log out all
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Security;
|
||||
@@ -0,0 +1,62 @@
|
||||
import { useState } from "react";
|
||||
import Button from "@/components/Button";
|
||||
import Icon from "@/components/Icon";
|
||||
import Select from "@/components/Select";
|
||||
|
||||
const voiceOptions = [
|
||||
{ id: 1, name: "Default" },
|
||||
{ id: 2, name: "Echo" },
|
||||
{ id: 3, name: "Tempo" },
|
||||
];
|
||||
|
||||
const languages = [
|
||||
{ id: 1, name: "English" },
|
||||
{ id: 2, name: "French" },
|
||||
{ id: 3, name: "Spanish" },
|
||||
];
|
||||
|
||||
const Notifications = ({}) => {
|
||||
const [voice, setVoice] = useState(voiceOptions[0]);
|
||||
const [language, setLanguage] = useState(languages[0]);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex items-center mb-3 pb-3 border-b border-stroke-soft-200">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Voice</div>
|
||||
<div className="text-sub-600">Choose your ai voice.</div>
|
||||
</div>
|
||||
<div className="flex gap-1.5">
|
||||
<Button
|
||||
className="w-10 !h-10 !px-0 !rounded-[0.625rem] !bg-weak-50"
|
||||
isStroke
|
||||
>
|
||||
<Icon className="fill-icon-sub-600" name="volume" />
|
||||
</Button>
|
||||
<Select
|
||||
classButton="h-10 bg-weak-50 rounded-[0.625rem]"
|
||||
value={voice}
|
||||
onChange={setVoice}
|
||||
options={voiceOptions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="mr-auto">
|
||||
<div className="text-label-md">Main Language</div>
|
||||
<div className="text-sub-600">
|
||||
For best results, select the language you mainly speak.
|
||||
</div>
|
||||
</div>
|
||||
<Select
|
||||
classButton="h-10 bg-weak-50 rounded-[0.625rem]"
|
||||
value={language}
|
||||
onChange={setLanguage}
|
||||
options={languages}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notifications;
|
||||
@@ -0,0 +1,97 @@
|
||||
import { useTheme } from "next-themes";
|
||||
import Image from "@/components/Image";
|
||||
|
||||
const Theme = ({}) => {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
const themes = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Light mode",
|
||||
image: "/images/theme-light.png",
|
||||
value: "light",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Dark mode",
|
||||
image: "/images/theme-dark.png",
|
||||
value: "dark",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "System Preference",
|
||||
image: "/images/theme-preference.png",
|
||||
value: "system",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="text-label-md">Themes</div>
|
||||
<div className="mb-3 text-sub-600">
|
||||
Choose your style or customize your theme
|
||||
</div>
|
||||
<div className="flex gap-3 max-md:flex-col">
|
||||
{themes.map((button) => (
|
||||
<div
|
||||
className={`flex flex-col flex-1 border rounded-lg bg-white-0 overflow-hidden cursor-pointer transition-colors hover:border-blue-500 ${
|
||||
theme === button.value
|
||||
? "border-blue-500 dark:text-static-black"
|
||||
: "border-stroke-soft-200"
|
||||
}`}
|
||||
key={button.id}
|
||||
onClick={() => setTheme(button.value)}
|
||||
>
|
||||
<div className="p-2.5 py-4">
|
||||
<div className="border border-stroke-soft-200 rounded-lg overflow-hidden">
|
||||
<Image
|
||||
className="w-full opacity-100"
|
||||
src={button.image}
|
||||
width={152}
|
||||
height={95}
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`flex items-center grow gap-2.5 h-11 px-3 transition-colors ${
|
||||
theme === button.value
|
||||
? "bg-blue-50"
|
||||
: "bg-weak-50"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`flex justify-center items-center size-4.5 rounded-full border ${
|
||||
theme === button.value
|
||||
? "border-blue-500 bg-blue-500"
|
||||
: "border-stroke-soft-200 bg-white-0"
|
||||
}`}
|
||||
>
|
||||
<svg
|
||||
className={`fill-static-white transition-opacity ${
|
||||
theme === button.value
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
}`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="9"
|
||||
height="8"
|
||||
fill="none"
|
||||
viewBox="0 0 9 8"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.252 2.16a.79.79 0 1 0-1.167-1.07l-3.795 4.14-1.394-1.394a.79.79 0 1 0-1.12 1.12l1.979 1.979a.79.79 0 0 0 1.143-.025l4.354-4.75z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-label-sm">{button.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Theme;
|
||||
@@ -0,0 +1,90 @@
|
||||
import { useState } from "react";
|
||||
import Modal from "@/components/Modal";
|
||||
import Icon from "@/components/Icon";
|
||||
import General from "./General";
|
||||
import Notifications from "./Notifications";
|
||||
import Speech from "./Speech";
|
||||
import Theme from "./Theme";
|
||||
import Security from "./Security";
|
||||
import DataControls from "./DataControls";
|
||||
|
||||
import { menu } from "./menu";
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const Settings = ({ open, onClose }: Props) => {
|
||||
const [activeId, setActiveId] = useState(0);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
classWrapper="flex flex-col max-w-199.5 min-h-180 max-md:min-h-[calc(100svh-6rem)]"
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="mb-4.5 pb-2 border-b border-stroke-soft-200 max-md:mb-3">
|
||||
<div className="text-label-xl max-md:text-label-lg">
|
||||
Settings
|
||||
</div>
|
||||
<div className="mt-2 text-label-md text-sub-600 max-md:hidden">
|
||||
People with link will be able to view conversations and
|
||||
ideas in this board.Changes you make after creating the
|
||||
link will remain private.
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex grow max-md:block">
|
||||
<div className="flex flex-col gap-2 shrink-0 w-50 pr-4 border-r border-stroke-soft-200 max-lg:w-40 max-md:flex-row max-md:gap-4 max-md:w-auto max-md:mb-4 max-md:overflow-auto max-md:scrollbar-none max-md:-mx-4 max-md:px-4 max-md:border-0">
|
||||
{menu.map((item) => (
|
||||
<button
|
||||
className={`group flex items-center gap-2 h-10 transition-colors hover:text-strong-950 max-md:shrink-0 ${
|
||||
activeId === item.id
|
||||
? "!text-blue-500"
|
||||
: "text-sub-600"
|
||||
}`}
|
||||
onClick={() => setActiveId(item.id)}
|
||||
key={item.id}
|
||||
>
|
||||
<Icon
|
||||
className={`transition-colors group-hover:fill-strong-950 ${
|
||||
activeId === item.id
|
||||
? "!fill-blue-500"
|
||||
: "fill-sub-600"
|
||||
}`}
|
||||
name={item.icon}
|
||||
/>
|
||||
{item.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="grow pl-4 max-md:pl-0">
|
||||
{menu
|
||||
.filter((item) => item.id === activeId)
|
||||
.map((item) => (
|
||||
<div
|
||||
className="flex items-center gap-2.5 mb-8 text-label-lg max-md:hidden"
|
||||
key={item.id}
|
||||
>
|
||||
<Icon
|
||||
className="!size-7 fill-strong-950"
|
||||
name={item.icon}
|
||||
/>
|
||||
{item.name}
|
||||
</div>
|
||||
))}
|
||||
{activeId === 0 && <General />}
|
||||
{activeId === 1 && <Notifications />}
|
||||
{activeId === 2 && <Speech />}
|
||||
{activeId === 3 && <Theme />}
|
||||
{activeId === 4 && <Security />}
|
||||
{activeId === 5 && <DataControls />}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -0,0 +1,32 @@
|
||||
export const menu = [
|
||||
{
|
||||
id: 0,
|
||||
name: "General",
|
||||
icon: "folder",
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: "Notifications",
|
||||
icon: "bell",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Speech",
|
||||
icon: "voice",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Theme",
|
||||
icon: "document",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Security",
|
||||
icon: "security",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Data Controls",
|
||||
icon: "database",
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user