mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Add account settings
This commit is contained in:
150
frontend/src/components/AccountSettings.jsx
Normal file
150
frontend/src/components/AccountSettings.jsx
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
Badge,
|
||||||
|
Button,
|
||||||
|
Group,
|
||||||
|
Title,
|
||||||
|
Stack,
|
||||||
|
Accordion,
|
||||||
|
TextInput,
|
||||||
|
Text,
|
||||||
|
PasswordInput,
|
||||||
|
Box,
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
|
|
||||||
|
const AccordionControl = ({ children }) => (
|
||||||
|
<Accordion.Control>
|
||||||
|
<Title order={4}>{children}</Title>
|
||||||
|
</Accordion.Control>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ProfileSettings = ({ displayName, email }) => (
|
||||||
|
<Stack spacing="md">
|
||||||
|
<TextInput label="Display Name" defaultValue={displayName || ''} disabled />
|
||||||
|
<TextInput label="Email" defaultValue={email} disabled />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
|
const SecuritySettings = () => (
|
||||||
|
<Stack spacing="md">
|
||||||
|
<PasswordInput
|
||||||
|
label="Current Password"
|
||||||
|
placeholder="Enter current password"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
label="New Password"
|
||||||
|
placeholder="Enter new password"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
label="Confirm New Password"
|
||||||
|
placeholder="Confirm new password"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
Password must be at least 8 characters long and contain at least one
|
||||||
|
uppercase letter, one lowercase letter, one number, and one special
|
||||||
|
character.
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
|
const DangerZone = () => (
|
||||||
|
<Stack spacing="md">
|
||||||
|
<Box mb="md">
|
||||||
|
<Button
|
||||||
|
color="red"
|
||||||
|
variant="light"
|
||||||
|
onClick={() => console.log('Delete Account')}
|
||||||
|
fullWidth
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
Delete Account
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
|
||||||
|
const AccountSettings = ({ opened, onClose }) => {
|
||||||
|
const { user } = useAuth();
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
opened={opened}
|
||||||
|
onClose={onClose}
|
||||||
|
title={<Title order={2}>Account Settings</Title>}
|
||||||
|
centered
|
||||||
|
size="lg"
|
||||||
|
>
|
||||||
|
<Stack spacing="xl">
|
||||||
|
<Badge color="yellow" variant="light">
|
||||||
|
Changes are currently disabled
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Accordion
|
||||||
|
defaultValue={['profile', 'security', 'danger']}
|
||||||
|
multiple
|
||||||
|
styles={(theme) => ({
|
||||||
|
control: {
|
||||||
|
paddingTop: theme.spacing.md,
|
||||||
|
paddingBottom: theme.spacing.md,
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
borderBottom: `1px solid ${
|
||||||
|
theme.colorScheme === 'dark'
|
||||||
|
? theme.colors.dark[4]
|
||||||
|
: theme.colors.gray[3]
|
||||||
|
}`,
|
||||||
|
'&[data-active]': {
|
||||||
|
backgroundColor:
|
||||||
|
theme.colorScheme === 'dark'
|
||||||
|
? theme.colors.dark[7]
|
||||||
|
: theme.colors.gray[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
chevron: {
|
||||||
|
'&[data-rotate]': {
|
||||||
|
transform: 'rotate(180deg)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Accordion.Item value="profile">
|
||||||
|
<AccordionControl>Profile</AccordionControl>
|
||||||
|
<Accordion.Panel>
|
||||||
|
<ProfileSettings
|
||||||
|
displayName={user.displayName}
|
||||||
|
email={user.email}
|
||||||
|
/>
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
|
||||||
|
<Accordion.Item value="security">
|
||||||
|
<AccordionControl>Security</AccordionControl>
|
||||||
|
<Accordion.Panel>
|
||||||
|
<SecuritySettings />
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
|
||||||
|
<Accordion.Item value="danger">
|
||||||
|
<AccordionControl>Danger Zone</AccordionControl>
|
||||||
|
<Accordion.Panel>
|
||||||
|
<DangerZone />
|
||||||
|
</Accordion.Panel>
|
||||||
|
</Accordion.Item>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Group justify="flex-end">
|
||||||
|
<Button variant="default" onClick={onClose}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button disabled>Save Changes</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccountSettings;
|
||||||
@@ -10,99 +10,108 @@ import {
|
|||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { IconUser, IconLogout, IconUserCircle } from '@tabler/icons-react';
|
import { IconUser, IconLogout, IconUserCircle } from '@tabler/icons-react';
|
||||||
import { useAuth } from '../contexts/AuthContext';
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
|
import AccountSettings from './AccountSettings';
|
||||||
|
|
||||||
const UserMenu = () => {
|
const UserMenu = () => {
|
||||||
|
const [accountSettingsOpened, setAccountSettingsOpened] = useState(false);
|
||||||
const [opened, setOpened] = useState(false);
|
const [opened, setOpened] = useState(false);
|
||||||
const { logout } = useAuth();
|
const { user, logout } = useAuth();
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
logout();
|
logout();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<>
|
||||||
width={200}
|
<Popover
|
||||||
position="bottom-end"
|
width={200}
|
||||||
withArrow
|
position="bottom-end"
|
||||||
shadow="md"
|
withArrow
|
||||||
opened={opened}
|
shadow="md"
|
||||||
onChange={setOpened}
|
opened={opened}
|
||||||
>
|
onChange={setOpened}
|
||||||
<Popover.Target>
|
>
|
||||||
<Avatar
|
<Popover.Target>
|
||||||
radius="xl"
|
<Avatar
|
||||||
style={{ cursor: 'pointer' }}
|
radius="xl"
|
||||||
onClick={() => setOpened((o) => !o)}
|
style={{ cursor: 'pointer' }}
|
||||||
>
|
onClick={() => setOpened((o) => !o)}
|
||||||
<IconUser size={24} />
|
|
||||||
</Avatar>
|
|
||||||
</Popover.Target>
|
|
||||||
|
|
||||||
<Popover.Dropdown>
|
|
||||||
<Stack gap="sm">
|
|
||||||
{/* User Info Section */}
|
|
||||||
<Group gap="sm">
|
|
||||||
<Avatar radius="xl" size="md">
|
|
||||||
<IconUser size={24} />
|
|
||||||
</Avatar>
|
|
||||||
<div>
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
John Doe
|
|
||||||
</Text>
|
|
||||||
<Text size="xs" c="dimmed">
|
|
||||||
john.doe@example.com
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* Menu Items */}
|
|
||||||
<UnstyledButton
|
|
||||||
onClick={() => console.log('Account settings')}
|
|
||||||
px="sm"
|
|
||||||
py="xs"
|
|
||||||
style={(theme) => ({
|
|
||||||
borderRadius: theme.radius.sm,
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor:
|
|
||||||
theme.colorScheme === 'dark'
|
|
||||||
? theme.colors.dark[5]
|
|
||||||
: theme.colors.gray[0],
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
<Group>
|
<IconUser size={24} />
|
||||||
<IconUserCircle size={16} />
|
</Avatar>
|
||||||
<Text size="sm">Account Settings</Text>
|
</Popover.Target>
|
||||||
</Group>
|
|
||||||
</UnstyledButton>
|
|
||||||
|
|
||||||
<UnstyledButton
|
<Popover.Dropdown>
|
||||||
onClick={handleLogout}
|
<Stack gap="sm">
|
||||||
px="sm"
|
{/* User Info Section */}
|
||||||
py="xs"
|
<Group gap="sm">
|
||||||
color="red"
|
<Avatar radius="xl" size="md">
|
||||||
style={(theme) => ({
|
<IconUser size={24} />
|
||||||
borderRadius: theme.radius.sm,
|
</Avatar>
|
||||||
'&:hover': {
|
<div>
|
||||||
backgroundColor:
|
<Text size="sm" fw={500}>
|
||||||
theme.colorScheme === 'dark'
|
{user.displayName || user.email}
|
||||||
? theme.colors.dark[5]
|
</Text>
|
||||||
: theme.colors.gray[0],
|
</div>
|
||||||
},
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Group>
|
|
||||||
<IconLogout size={16} color="red" />
|
|
||||||
<Text size="sm" c="red">
|
|
||||||
Logout
|
|
||||||
</Text>
|
|
||||||
</Group>
|
</Group>
|
||||||
</UnstyledButton>
|
|
||||||
</Stack>
|
<Divider />
|
||||||
</Popover.Dropdown>
|
|
||||||
</Popover>
|
{/* Menu Items */}
|
||||||
|
<UnstyledButton
|
||||||
|
onClick={() => {
|
||||||
|
setAccountSettingsOpened(true);
|
||||||
|
setOpened(false);
|
||||||
|
}}
|
||||||
|
px="sm"
|
||||||
|
py="xs"
|
||||||
|
style={(theme) => ({
|
||||||
|
borderRadius: theme.radius.sm,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor:
|
||||||
|
theme.colorScheme === 'dark'
|
||||||
|
? theme.colors.dark[5]
|
||||||
|
: theme.colors.gray[0],
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Group>
|
||||||
|
<IconUserCircle size={16} />
|
||||||
|
<Text size="sm">Account Settings</Text>
|
||||||
|
</Group>
|
||||||
|
</UnstyledButton>
|
||||||
|
|
||||||
|
<UnstyledButton
|
||||||
|
onClick={handleLogout}
|
||||||
|
px="sm"
|
||||||
|
py="xs"
|
||||||
|
color="red"
|
||||||
|
style={(theme) => ({
|
||||||
|
borderRadius: theme.radius.sm,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor:
|
||||||
|
theme.colorScheme === 'dark'
|
||||||
|
? theme.colors.dark[5]
|
||||||
|
: theme.colors.gray[0],
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Group>
|
||||||
|
<IconLogout size={16} color="red" />
|
||||||
|
<Text size="sm" c="red">
|
||||||
|
Logout
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
</UnstyledButton>
|
||||||
|
</Stack>
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
|
<AccountSettings
|
||||||
|
opened={accountSettingsOpened}
|
||||||
|
onClose={() => setAccountSettingsOpened(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user