mirror of
https://github.com/CompassConnections/Compass.git
synced 2025-12-23 22:18:43 -05:00
Add settings page
This commit is contained in:
@@ -1,61 +1,50 @@
|
||||
import {
|
||||
LogoutIcon,
|
||||
MoonIcon,
|
||||
SunIcon,
|
||||
LoginIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import {LoginIcon, LogoutIcon,} from '@heroicons/react/outline'
|
||||
import clsx from 'clsx'
|
||||
import { buildArray } from 'common/util/array'
|
||||
import Router, { useRouter } from 'next/router'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { firebaseLogin, firebaseLogout } from 'web/lib/firebase/users'
|
||||
import { withTracking } from 'web/lib/service/analytics'
|
||||
import { ProfileSummary } from './profile-summary'
|
||||
import { Item, SidebarItem } from './sidebar-item'
|
||||
import {buildArray} from 'common/util/array'
|
||||
import Router, {useRouter} from 'next/router'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {firebaseLogout} from 'web/lib/firebase/users'
|
||||
import {withTracking} from 'web/lib/service/analytics'
|
||||
import {ProfileSummary} from './profile-summary'
|
||||
import {Item, SidebarItem} from './sidebar-item'
|
||||
import SiteLogo from '../site-logo'
|
||||
import { Button, ColorType, SizeType } from 'web/components/buttons/button'
|
||||
import {Button, ColorType, SizeType} from 'web/components/buttons/button'
|
||||
import {signupRedirect} from 'web/lib/util/signup'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import { useTheme } from 'web/hooks/use-theme'
|
||||
import {useProfile} from 'web/hooks/use-profile'
|
||||
|
||||
export default function Sidebar(props: {
|
||||
className?: string
|
||||
isMobile?: boolean
|
||||
navigationOptions: Item[]
|
||||
}) {
|
||||
const { className, isMobile } = props
|
||||
const {className, isMobile} = props
|
||||
const router = useRouter()
|
||||
const currentPage = router.pathname
|
||||
|
||||
const user = useUser()
|
||||
const profile = useProfile()
|
||||
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const toggleTheme = () => {
|
||||
setTheme(theme === 'auto' ? 'dark' : theme === 'dark' ? 'light' : 'auto')
|
||||
}
|
||||
const navOptions = props.navigationOptions
|
||||
|
||||
const bottomNavOptions = bottomNav(!!user, theme, toggleTheme)
|
||||
const bottomNavOptions = bottomNav(!!user)
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label="Sidebar"
|
||||
className={clsx('flex h-screen flex-col h-full max-h-screen overflow-y-auto', className)}
|
||||
>
|
||||
<SiteLogo />
|
||||
<SiteLogo/>
|
||||
|
||||
{user === undefined && <div className="h-[56px]" />}
|
||||
{user === undefined && <div className="h-[56px]"/>}
|
||||
|
||||
{user && !isMobile && <ProfileSummary user={user} className="mb-3" />}
|
||||
{user && !isMobile && <ProfileSummary user={user} className="mb-3"/>}
|
||||
|
||||
<div className="mb-4 flex flex-col gap-1">
|
||||
{navOptions.map((item) => (
|
||||
<SidebarItem key={item.name} item={item} currentPage={currentPage} />
|
||||
<SidebarItem key={item.name} item={item} currentPage={currentPage}/>
|
||||
))}
|
||||
|
||||
{user === null && <SignUpButton className="mt-4" text="Sign up" />}
|
||||
{user === null && <SignUpButton className="mt-4" text="Sign up"/>}
|
||||
{/*{user === null && <SignUpAsMatchmaker className="mt-2" />}*/}
|
||||
|
||||
{user && profile === null && (
|
||||
@@ -66,7 +55,7 @@ export default function Sidebar(props: {
|
||||
</div>
|
||||
<div className="mb-6 mt-auto flex flex-col gap-1">
|
||||
{bottomNavOptions.map((item) => (
|
||||
<SidebarItem key={item.name} item={item} currentPage={currentPage} />
|
||||
<SidebarItem key={item.name} item={item} currentPage={currentPage}/>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
@@ -82,39 +71,10 @@ const logout = async () => {
|
||||
|
||||
const bottomNav = (
|
||||
loggedIn: boolean,
|
||||
theme: 'light' | 'dark' | 'auto' | 'loading',
|
||||
toggleTheme: () => void
|
||||
) =>
|
||||
buildArray<Item>(
|
||||
{
|
||||
name: theme ?? 'auto',
|
||||
children:
|
||||
theme === 'light' ? (
|
||||
'Light'
|
||||
) : theme === 'dark' ? (
|
||||
'Dark'
|
||||
) : (
|
||||
<>
|
||||
<span className="hidden dark:inline">Dark</span>
|
||||
<span className="inline dark:hidden">Light</span> (auto)
|
||||
</>
|
||||
),
|
||||
icon: ({ className, ...props }) => (
|
||||
<>
|
||||
<MoonIcon
|
||||
className={clsx(className, 'hidden dark:block')}
|
||||
{...props}
|
||||
/>
|
||||
<SunIcon
|
||||
className={clsx(className, 'block dark:hidden')}
|
||||
{...props}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
onClick: toggleTheme,
|
||||
},
|
||||
!loggedIn && { name: 'Sign in', icon: LoginIcon, href: '/signin' },
|
||||
loggedIn && { name: 'Sign out', icon: LogoutIcon, onClick: logout }
|
||||
!loggedIn && {name: 'Sign in', icon: LoginIcon, href: '/signin'},
|
||||
loggedIn && {name: 'Sign out', icon: LogoutIcon, onClick: logout}
|
||||
)
|
||||
|
||||
export const SignUpButton = (props: {
|
||||
@@ -123,7 +83,7 @@ export const SignUpButton = (props: {
|
||||
color?: ColorType
|
||||
size?: SizeType
|
||||
}) => {
|
||||
const { className, text, color, size } = props
|
||||
const {className, text, color, size} = props
|
||||
|
||||
return (
|
||||
<Button
|
||||
@@ -137,20 +97,20 @@ export const SignUpButton = (props: {
|
||||
)
|
||||
}
|
||||
|
||||
export const SignUpAsMatchmaker = (props: {
|
||||
className?: string
|
||||
size?: SizeType
|
||||
}) => {
|
||||
const { className, size } = props
|
||||
|
||||
return (
|
||||
<Button
|
||||
color={'indigo-outline'}
|
||||
size={size ?? 'md'}
|
||||
onClick={firebaseLogin}
|
||||
className={clsx('w-full', className)}
|
||||
>
|
||||
Sign up as matchmaker
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
// export const SignUpAsMatchmaker = (props: {
|
||||
// className?: string
|
||||
// size?: SizeType
|
||||
// }) => {
|
||||
// const {className, size} = props
|
||||
//
|
||||
// return (
|
||||
// <Button
|
||||
// color={'indigo-outline'}
|
||||
// size={size ?? 'md'}
|
||||
// onClick={firebaseLogin}
|
||||
// className={clsx('w-full', className)}
|
||||
// >
|
||||
// Sign up as matchmaker
|
||||
// </Button>
|
||||
// )
|
||||
// }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {HomeIcon, NewspaperIcon, QuestionMarkCircleIcon} from '@heroicons/react/outline'
|
||||
import {
|
||||
CogIcon,
|
||||
GlobeAltIcon,
|
||||
HomeIcon as SolidHomeIcon,
|
||||
LinkIcon,
|
||||
@@ -118,6 +119,7 @@ const Organization = {name: 'Organization', href: '/organization', icon: GlobeAl
|
||||
const Vote = {name: 'Vote', href: '/vote', icon: MdThumbUp};
|
||||
const Contact = {name: 'Contact', href: '/contact', icon: FaEnvelope};
|
||||
const News = {name: "What's new", href: '/news', icon: NewspaperIcon};
|
||||
const Settings = {name: "Settings", href: '/settings', icon: CogIcon};
|
||||
|
||||
const base = [
|
||||
About,
|
||||
@@ -144,7 +146,7 @@ function getBottomNavigation(user: User, profile: Profile | null | undefined) {
|
||||
icon: (props) => (
|
||||
<PrivateMessagesIcon bubbleClassName={'-mr-5'} solid {...props} />
|
||||
),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -160,6 +162,7 @@ const getDesktopNavigation = (user: User | null | undefined) => {
|
||||
ProfilesHome,
|
||||
Notifs,
|
||||
Messages,
|
||||
Settings,
|
||||
...base,
|
||||
)
|
||||
|
||||
@@ -170,6 +173,7 @@ const getDesktopNavigation = (user: User | null | undefined) => {
|
||||
|
||||
const getMobileSidebar = (_toggleModal: () => void) => {
|
||||
return buildArray(
|
||||
Settings,
|
||||
...base,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {DotsHorizontalIcon, EyeIcon, LockClosedIcon, PencilIcon} from '@heroicons/react/outline'
|
||||
import clsx from 'clsx'
|
||||
import Router from 'next/router'
|
||||
import router from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import {User, UserActivity} from 'common/user'
|
||||
import {Button} from 'web/components/buttons/button'
|
||||
@@ -20,7 +19,6 @@ import {linkClass} from 'web/components/widgets/site-link'
|
||||
import {updateProfile} from 'web/lib/api'
|
||||
import {useState} from 'react'
|
||||
import {VisibilityConfirmationModal} from './visibility-confirmation-modal'
|
||||
import {deleteAccount} from "web/lib/util/delete";
|
||||
import toast from "react-hot-toast";
|
||||
import {StarButton} from "web/components/widgets/star-button";
|
||||
import {disableProfile} from "web/lib/util/disable";
|
||||
@@ -57,7 +55,8 @@ export default function ProfileHeader(props: {
|
||||
<Row className={clsx('flex-wrap justify-between gap-2 py-1')}>
|
||||
<Row className="items-center gap-1">
|
||||
<Col className="gap-1">
|
||||
{currentUser && isCurrentUser && disabled && <div className="text-red-500">You disabled your profile, so no one else can access it.</div>}
|
||||
{currentUser && isCurrentUser && disabled &&
|
||||
<div className="text-red-500">You disabled your profile, so no one else can access it.</div>}
|
||||
<Row className="items-center gap-1 text-xl">
|
||||
{!isCurrentUser && <OnlineIcon last_online_time={userActivity?.last_online_time}/>}
|
||||
<span>
|
||||
@@ -110,34 +109,6 @@ export default function ProfileHeader(props: {
|
||||
),
|
||||
onClick: () => setShowVisibilityModal(true),
|
||||
},
|
||||
{
|
||||
name: 'Delete profile',
|
||||
icon: null,
|
||||
onClick: async () => {
|
||||
const confirmed = confirm(
|
||||
'Are you sure you want to delete your profile? This cannot be undone.'
|
||||
)
|
||||
if (confirmed) {
|
||||
toast
|
||||
.promise(deleteAccount(user.username), {
|
||||
loading: 'Deleting account...',
|
||||
success: () => {
|
||||
router.push('/')
|
||||
return 'Your account has been deleted.'
|
||||
},
|
||||
error: () => {
|
||||
return 'Failed to delete account.'
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
// return true
|
||||
})
|
||||
.catch(() => {
|
||||
// return false
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: disabled ? 'Enable profile' : 'Disable profile',
|
||||
icon: null,
|
||||
|
||||
38
web/components/theme-icon.tsx
Normal file
38
web/components/theme-icon.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import {MoonIcon, SunIcon} from "@heroicons/react/outline"
|
||||
import clsx from "clsx"
|
||||
import {useTheme} from "web/hooks/use-theme"
|
||||
import {Row} from "web/components/layout/row";
|
||||
|
||||
export default function ThemeIcon(props: {
|
||||
className?: string
|
||||
}) {
|
||||
const {className} = props
|
||||
const {theme, setTheme} = useTheme()
|
||||
|
||||
const toggleTheme = () => {
|
||||
setTheme(theme === 'auto' ? 'dark' : theme === 'dark' ? 'light' : 'auto')
|
||||
}
|
||||
const children = theme === 'light' ? (
|
||||
'Light'
|
||||
) : theme === 'dark' ? (
|
||||
'Dark'
|
||||
) : (
|
||||
<>
|
||||
<span className="hidden dark:inline">Dark</span>
|
||||
<span className="inline dark:hidden">Light</span> (auto)
|
||||
</>
|
||||
)
|
||||
const icon = <>
|
||||
<MoonIcon className={clsx(className, 'hidden dark:block')}/>
|
||||
<SunIcon className={clsx(className, 'block dark:hidden')}/>
|
||||
</>
|
||||
return <button onClick={toggleTheme}>
|
||||
<Row className="items-center gap-1 border-2 border-gray-500 rounded-full p-1 max-w-fit mx-2">
|
||||
{icon}
|
||||
{children}
|
||||
</Row>
|
||||
</button>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {useGroupedNotifications} from 'web/hooks/use-notifications'
|
||||
import {usePrivateUser, useUser} from 'web/hooks/use-user'
|
||||
import {api} from 'web/lib/api'
|
||||
import {useRedirectIfSignedOut} from "web/hooks/use-redirect-if-signed-out";
|
||||
import {NotificationSettings} from "web/components/notifications";
|
||||
|
||||
export default function NotificationsPage() {
|
||||
useRedirectIfSignedOut()
|
||||
@@ -23,6 +24,7 @@ export default function NotificationsPage() {
|
||||
<UncontrolledTabs
|
||||
tabs={[
|
||||
{title: 'Notifications', content: <NotificationsContent/>},
|
||||
{title: 'Settings', content: <NotificationSettings/>},
|
||||
]}
|
||||
trackingName={'notifications page'}
|
||||
/>
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
import {PrivateUser} from 'common/src/user'
|
||||
import {
|
||||
notification_destination_types,
|
||||
notification_preference,
|
||||
notification_preferences,
|
||||
} from 'common/user-notification-preferences'
|
||||
import {useCallback} from 'react'
|
||||
import {NoSEO} from 'web/components/NoSEO'
|
||||
import {UncontrolledTabs} from 'web/components/layout/tabs'
|
||||
import {PageBase} from 'web/components/page-base'
|
||||
import {Title} from 'web/components/widgets/title'
|
||||
import {usePrivateUser} from 'web/hooks/use-user'
|
||||
import {api} from 'web/lib/api'
|
||||
import {MultiSelectAnswers} from 'web/components/answers/answer-compatibility-question-content'
|
||||
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
|
||||
import {debounce} from 'lodash'
|
||||
import {useRedirectIfSignedOut} from "web/hooks/use-redirect-if-signed-out";
|
||||
import toast from "react-hot-toast";
|
||||
import {deleteAccount} from "web/lib/util/delete";
|
||||
import router from "next/router";
|
||||
import {Button} from "web/components/buttons/button";
|
||||
import {getAuth, sendEmailVerification, sendPasswordResetEmail, User} from 'firebase/auth';
|
||||
import {auth} from "web/lib/firebase/users";
|
||||
import {NotificationSettings} from "web/components/notifications";
|
||||
import ThemeIcon from "web/components/theme-icon";
|
||||
|
||||
export default function NotificationsPage() {
|
||||
useRedirectIfSignedOut()
|
||||
const privateUser = usePrivateUser()
|
||||
if (!privateUser) return null
|
||||
const user = auth.currentUser
|
||||
if (!privateUser || !user) return null
|
||||
return (
|
||||
<PageBase trackPageView={'settings page'} className={'mx-4'}>
|
||||
<NoSEO/>
|
||||
<Title>Settings</Title>
|
||||
<UncontrolledTabs
|
||||
tabs={[
|
||||
{title: 'Account', content: <AccountSettings privateUser={privateUser}/>},
|
||||
{title: 'Notifications', content: <NotificationSettings privateUser={privateUser}/>},
|
||||
{title: 'General', content: <GeneralSettings privateUser={privateUser} user={user}/>},
|
||||
{title: 'Notifications', content: <NotificationSettings/>},
|
||||
]}
|
||||
trackingName={'settings page'}
|
||||
/>
|
||||
@@ -35,140 +34,97 @@ export default function NotificationsPage() {
|
||||
)
|
||||
}
|
||||
|
||||
const AccountSettings = (props: { privateUser: PrivateUser }) => {
|
||||
const {privateUser} = props
|
||||
return <></>
|
||||
}
|
||||
|
||||
const NotificationSettings = (props: { privateUser: PrivateUser }) => {
|
||||
const {privateUser} = props
|
||||
|
||||
const [prefs, setPrefs] =
|
||||
usePersistentInMemoryState<notification_preferences>(
|
||||
privateUser.notificationPreferences,
|
||||
'notification-preferences'
|
||||
)
|
||||
|
||||
const notificationTypes: {
|
||||
type: notification_preference
|
||||
question: string
|
||||
}[] = [
|
||||
{
|
||||
type: 'new_match',
|
||||
question:
|
||||
'Where do you want to be notified when someone ... matches with you?',
|
||||
},
|
||||
{
|
||||
type: 'new_message',
|
||||
question: '... sends you a new message?',
|
||||
},
|
||||
{
|
||||
type: 'new_profile_like',
|
||||
question: '... likes your profile?',
|
||||
},
|
||||
{
|
||||
type: 'new_endorsement',
|
||||
question: '... endorses you?',
|
||||
},
|
||||
{
|
||||
type: 'new_profile_ship',
|
||||
question: '... ships you?',
|
||||
},
|
||||
{
|
||||
type: 'tagged_user',
|
||||
question: '... mentions you?',
|
||||
},
|
||||
{
|
||||
type: 'on_new_follow',
|
||||
question: '... follows you?',
|
||||
},
|
||||
{
|
||||
type: 'new_search_alerts',
|
||||
question: 'Alerts from bookmarked searches?',
|
||||
},
|
||||
{
|
||||
type: 'opt_out_all',
|
||||
question:
|
||||
'Do you want to opt out of all notifications? (You can always change this later)?',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-2xl">
|
||||
<div className="flex flex-col gap-8 p-4">
|
||||
{notificationTypes.map(({type, question}) => (
|
||||
<NotificationOption
|
||||
key={type}
|
||||
type={type}
|
||||
question={question}
|
||||
selected={prefs[type]}
|
||||
onUpdate={(selected) => {
|
||||
setPrefs((prevPrefs) => ({...prevPrefs, [type]: selected}))
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const NotificationOption = (props: {
|
||||
type: notification_preference
|
||||
question: string
|
||||
selected: notification_destination_types[]
|
||||
onUpdate: (selected: notification_destination_types[]) => void
|
||||
const GeneralSettings = (props: {
|
||||
privateUser: PrivateUser,
|
||||
user: User,
|
||||
}) => {
|
||||
const {type, question, selected, onUpdate} = props
|
||||
const {privateUser, user} = props
|
||||
|
||||
const getSelectedValues = (destinations: string[]) => {
|
||||
const values: number[] = []
|
||||
if ((destinations ?? []).includes('email')) values.push(0)
|
||||
if ((destinations ?? []).includes('browser')) values.push(1)
|
||||
return values
|
||||
}
|
||||
|
||||
const setValue = async (value: number[]) => {
|
||||
const newDestinations: notification_destination_types[] = []
|
||||
if (value.includes(0)) newDestinations.push('email')
|
||||
if (value.includes(1)) newDestinations.push('browser')
|
||||
|
||||
onUpdate(newDestinations)
|
||||
save(selected, newDestinations)
|
||||
}
|
||||
|
||||
const save = useCallback(
|
||||
debounce(
|
||||
(
|
||||
oldDestinations: notification_destination_types[],
|
||||
newDestinations: notification_destination_types[]
|
||||
) => {
|
||||
// for each medium, if it changed, trigger a save
|
||||
const mediums = ['email', 'browser'] as const
|
||||
mediums.forEach((medium) => {
|
||||
const wasEnabled = oldDestinations.includes(medium)
|
||||
const isEnabled = newDestinations.includes(medium)
|
||||
if (wasEnabled !== isEnabled) {
|
||||
api('update-notif-settings', {
|
||||
type,
|
||||
medium,
|
||||
enabled: isEnabled,
|
||||
})
|
||||
}
|
||||
const handleDeleteAccount = async () => {
|
||||
const confirmed = confirm(
|
||||
'Are you sure you want to delete your profile? This cannot be undone.'
|
||||
)
|
||||
if (confirmed) {
|
||||
toast
|
||||
.promise(deleteAccount(), {
|
||||
loading: 'Deleting account...',
|
||||
success: () => {
|
||||
router.push('/')
|
||||
return 'Your account has been deleted.'
|
||||
},
|
||||
error: () => {
|
||||
return 'Failed to delete account.'
|
||||
},
|
||||
})
|
||||
},
|
||||
500
|
||||
),
|
||||
[]
|
||||
)
|
||||
.catch(() => {
|
||||
console.log("Failed to delete account")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-ink-700 font-medium">{question}</div>
|
||||
<MultiSelectAnswers
|
||||
options={['By email', 'On notifications page']}
|
||||
values={getSelectedValues(selected)}
|
||||
setValue={setValue}
|
||||
/>
|
||||
const sendPasswordReset = async () => {
|
||||
if (!privateUser?.email) {
|
||||
toast.error('No email found on your account.')
|
||||
return
|
||||
}
|
||||
const auth = getAuth()
|
||||
toast.promise(
|
||||
sendPasswordResetEmail(auth, privateUser.email),
|
||||
{
|
||||
loading: 'Sending password reset email...',
|
||||
success: 'Password reset email sent — check your inbox and spam.',
|
||||
error: 'Failed to send password reset email.',
|
||||
}
|
||||
)
|
||||
.catch(() => {
|
||||
console.log("Failed to send password reset email")
|
||||
})
|
||||
}
|
||||
|
||||
const sendVerificationEmail = async () => {
|
||||
if (!privateUser?.email) {
|
||||
toast.error('No email found on your account.')
|
||||
return
|
||||
}
|
||||
if (!user) {
|
||||
toast.error('You must be signed in to send a verification email.')
|
||||
return
|
||||
}
|
||||
toast
|
||||
.promise(sendEmailVerification(user), {
|
||||
loading: 'Sending verification email...',
|
||||
success: 'Verification email sent — check your inbox and spam.',
|
||||
error: 'Failed to send verification email.',
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Failed to send verification email")
|
||||
})
|
||||
}
|
||||
|
||||
const isEmailVerified = user.emailVerified
|
||||
|
||||
return <>
|
||||
<div className="flex flex-col gap-2 max-w-fit">
|
||||
<h3>Theme</h3>
|
||||
<ThemeIcon className="h-6 w-6"/>
|
||||
<h3>Account</h3>
|
||||
<h5>Credentials</h5>
|
||||
<Button
|
||||
onClick={sendPasswordReset}
|
||||
>
|
||||
Send password reset email
|
||||
</Button>
|
||||
|
||||
<h5>Verification</h5>
|
||||
<Button onClick={sendVerificationEmail} disabled={!privateUser?.email || isEmailVerified}>
|
||||
{isEmailVerified ? 'Email Verified' : 'Send verification email'}
|
||||
</Button>
|
||||
|
||||
<h5>Dangerous</h5>
|
||||
<Button color="red" onClick={handleDeleteAccount}>
|
||||
Delete Account
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user