Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User profile settings #959

Merged
merged 5 commits into from
Jun 25, 2024
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
11 changes: 9 additions & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ThemeProvider } from './ThemeProvider'
import { Toaster } from 'sonner'
import { useStickyState } from './hooks/useStickyState'
import MobileTabsPage from './pages/MobileTabsPage'
import { UserProfile } from './components/feature/userSettings/UserProfile/UserProfile'


const router = createBrowserRouter(
Expand All @@ -23,9 +24,15 @@ const router = createBrowserRouter(
<Route path="channel" element={<MainPage />} >
<Route index element={<MobileTabsPage />} />
<Route path="saved-messages" lazy={() => import('./components/feature/saved-messages/SavedMessages')} />
<Route path="settings" lazy={() => import('./pages/settings/Settings')}>
<Route index element={<UserProfile />} />
<Route path="profile" element={<UserProfile />} />
<Route path="users" lazy={() => import('./components/feature/userSettings/Users/AddUsers')} />
{/* <Route path="bots" lazy={() => import('./components/feature/userSettings/Bots')} /> */}
</Route>
<Route path=":channelID" lazy={() => import('@/pages/ChatSpace')} />
</Route>
<Route path='settings' lazy={() => import('./pages/settings/Settings')}>
{/* <Route path='settings' lazy={() => import('./pages/settings/Settings')}>
<Route path='integrations'>
<Route path='webhooks' lazy={() => import('./pages/settings/Webhooks/WebhookList')} />
<Route path='webhooks/create' lazy={() => import('./pages/settings/Webhooks/CreateWebhook')} />
Expand All @@ -34,7 +41,7 @@ const router = createBrowserRouter(
<Route path='scheduled-messages/create' lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/CreateSchedulerEvent')} />
<Route path='scheduled-messages/:ID' lazy={() => import('./pages/settings/ServerScripts/SchedulerEvents/ViewSchedulerEvent')} />
</Route>
</Route>
</Route> */}
</Route>
</Route>
</>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/UserAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { clsx } from 'clsx'
import { generateAvatarColor } from '../feature/select-member/GenerateAvatarColor'
import { RiRobot2Fill } from 'react-icons/ri'
import { useMemo } from 'react'
import { AvailabilityStatus } from '../feature/userSettings/SetUserAvailabilityMenu'
import { AvailabilityStatus } from '../feature/userSettings/AvailabilityStatus/SetUserAvailabilityMenu'

interface UserAvatarProps extends Partial<AvatarProps> {
alt?: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { RiRobot2Fill } from 'react-icons/ri'
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { useDoubleTap } from 'use-double-tap'
import useOutsideClick from '@/hooks/useOutsideClick'
import { getStatusText } from '../../userSettings/SetUserAvailabilityMenu'
import { getStatusText } from '../../userSettings/AvailabilityStatus/SetUserAvailabilityMenu'

interface MessageBlockProps {
message: Message,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UserAvatar } from '@/components/common/UserAvatar';
import { getStatusText } from '@/components/feature/userSettings/SetUserAvailabilityMenu';
import { getStatusText } from '@/components/feature/userSettings/AvailabilityStatus/SetUserAvailabilityMenu';
import { useGetUser } from '@/hooks/useGetUser';
import { useIsUserActive } from '@/hooks/useIsUserActive';
import { Flex, HoverCard, Link, Text } from '@radix-ui/themes';
Expand Down
22 changes: 0 additions & 22 deletions frontend/src/components/feature/raven-users/AddRavenUsers.tsx

This file was deleted.

104 changes: 0 additions & 104 deletions frontend/src/components/feature/userSettings/ImageUploader.tsx

This file was deleted.

79 changes: 79 additions & 0 deletions frontend/src/components/feature/userSettings/SettingsSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useIsDesktop } from '@/hooks/useMediaQuery'
import { Box, Flex, Separator, Text } from '@radix-ui/themes'
import clsx from 'clsx'
import { PropsWithChildren, createElement } from 'react'
import { IconType } from 'react-icons'
import { BiBuildings } from 'react-icons/bi'
import { BsBoxes } from 'react-icons/bs'
import { LuUserCircle2 } from 'react-icons/lu'
import { NavLink } from 'react-router-dom'

export const SettingsSidebar = () => {

const isDesktop = useIsDesktop()

return (
<Box className="h-[full] w-64 border-r border-gray-4 dark:border-gray-6">
<Flex direction="column" gap='2' className='px-4'>
<SettingsGroup title="My Account" icon={LuUserCircle2}>
<SettingsSidebarItem title="Profile" to='profile' />
{/* <SettingsSidebarItem title="Preferences" to='preferences' /> */}
</SettingsGroup>
<SettingsSeparator />
<SettingsGroup title="Workspace" icon={BiBuildings}>
<SettingsSidebarItem title="Users" to='users' />
{/* <SettingsSidebarItem title="Bots" to='bots' /> */}
</SettingsGroup>
{/* <SettingsSeparator />
<SettingsGroup title='Integrations' icon={BsBoxes}>
<SettingsSidebarItem title="ERPNext" to='erpnext' />
<SettingsSidebarItem title="Frappe HR" to='frappe-hr' />
<SettingsSidebarItem title="Frappe LMS" to='frappe-lms' />
<SettingsSidebarItem title="Frappe CRM" to='frappe-crm' />
</SettingsGroup> */}
</Flex>
</Box>
)
}

const SettingsGroup = ({ title, icon, children }: PropsWithChildren<{ title: string, icon: IconType }>) => {
return <Flex direction="column" className='gap-0.5'>
<SettingsSidebarGroupHeader title={title} icon={icon} />
{children}
</Flex>
}

const SettingsSeparator = () => {
return <Separator className={'w-full'} />
}
const SettingsSidebarGroupHeader = ({ title, icon }: { title: string, icon: IconType }) => {
return (
<Flex className="py-1.5 flex items-center gap-1.5 text-gray-11">
{createElement(icon, { size: 15 })}
<Text size='1'>{title}</Text>
</Flex>
)
}

const SettingsSidebarItem = ({ title, to, end }: { title: string, to: string, end?: boolean }) => {

const activeClass = "bg-slate-3 dark:bg-slate-4 hover:bg-slate-3 hover:dark:bg-slate-4"

return (
<NavLink
to={to}
end={end}
className='no-underline'
>
{({ isActive }) => {
return (
<Box className='ml-4'>
<Flex className={clsx(`px-2 py-1 text-gray-12 rounded-md cursor-default w-full`, isActive ? activeClass : "bg-transparent hover:bg-slate-2 hover:dark:bg-slate-3")}>
<Text className='text-[13px]' weight='medium'>{title}</Text>
</Flex>
</Box>
)
}}
</NavLink>
)
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import { useFrappeUpdateDoc } from 'frappe-react-sdk'
import { AlertDialog, Button, Flex, Text } from '@radix-ui/themes'
import { Loader } from '@/components/common/Loader'
import { useFrappePostCall } from 'frappe-react-sdk'
import { toast } from 'sonner'
import { AlertDialog, Button, Flex, Text } from '@radix-ui/themes'
import { ErrorBanner } from '@/components/layout/AlertBanner'
import { useUserData } from '@/hooks/useUserData'
import { Loader } from '@/components/common/Loader'
import useCurrentRavenUser from '@/hooks/useCurrentRavenUser'

interface DeleteImageModalProps {
onClose: () => void
}

export const DeleteImageModal = ({ onClose }: DeleteImageModalProps) => {

const { updateDoc, error, loading } = useFrappeUpdateDoc()
const userData = useUserData()
const { call, error, loading } = useFrappePostCall('frappe.client.set_value')
const { myProfile, mutate } = useCurrentRavenUser()

const deleteImage = () => {
updateDoc('Raven User', userData.name, {
'user_image': null
const removeImage = () => {
call({
doctype: 'Raven User',
name: myProfile?.name,
fieldname: 'user_image',
value: ''
}).then(() => {
toast.success("User status updated")
mutate()
onClose()
toast.success("Image deleted successfully")
}).catch(() => {
toast("Could not delete image")
})
}

return (
<>
<AlertDialog.Title>Delete Image</AlertDialog.Title>
<AlertDialog.Title>Remove Image</AlertDialog.Title>

<Flex direction={'column'} gap='2'>
<ErrorBanner error={error} />
<Text>Are you sure you want to delete this image?</Text>
<Text>Are you sure you want to remove this image?</Text>
</Flex>

<Flex gap="3" mt="4" justify="end">
Expand All @@ -41,9 +43,9 @@ export const DeleteImageModal = ({ onClose }: DeleteImageModalProps) => {
</Button>
</AlertDialog.Cancel>
<AlertDialog.Action>
<Button variant="solid" color="red" onClick={deleteImage} disabled={loading}>
<Button variant="solid" color="red" onClick={removeImage} disabled={loading}>
{loading && <Loader />}
{loading ? "Deleting" : "Delete"}
{loading ? "Removing" : "Remove"}
</Button>
</AlertDialog.Action>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { FlexProps } from "@radix-ui/themes/dist/cjs/components/flex";
import { forwardRef, useImperativeHandle, useState } from "react";
import { Accept, useDropzone } from "react-dropzone";
import { toast } from "sonner";
import { CustomFile } from "../file-upload/FileDrop";
import { FileUploadProgress } from "../chat/ChatInput/FileInput/useFileUpload";
import { getFileSize } from "../file-upload/FileListItem";
import { useGetFilePreviewUrl } from "@/hooks/useGetFilePreviewUrl";
import { Loader } from "@/components/common/Loader";
import { BiTrash } from "react-icons/bi";
import { CustomFile } from "../../file-upload/FileDrop";
import { FileUploadProgress } from "../../chat/ChatInput/FileInput/useFileUpload";
import { getFileSize } from "../../file-upload/FileListItem";

export interface FileUploadBoxProps extends FlexProps {
/** File to be uploaded */
Expand Down Expand Up @@ -37,13 +37,12 @@ export const FileUploadBox = forwardRef((props: FileUploadBoxProps, ref) => {
}

const { getRootProps, getInputProps, open } = useDropzone({
onDrop: (receivedFiles) => {
onDrop: (receivedFiles: File[]) => {
if (receivedFiles.length > 0) {
onFileChange({
...receivedFiles[0],
fileID: receivedFiles[0].name + Date.now(),
uploadProgress: 0,
})
const f: CustomFile = receivedFiles[0] as CustomFile
f.uploadProgress = 0
f.fileID = f.name + Date.now()
onFileChange(f)
}
},
maxFiles: 1,
Expand Down Expand Up @@ -116,8 +115,6 @@ interface FileItemProps {

const FileItem = ({ file, removeFile, uploadProgress }: FileItemProps) => {

console.log('file', file)

const previewURL = useGetFilePreviewUrl(file)
const fileSizeString = getFileSize(file)
const isUploadComplete = uploadProgress?.[file.fileID]?.isComplete ?? false
Expand All @@ -126,13 +123,13 @@ const FileItem = ({ file, removeFile, uploadProgress }: FileItemProps) => {
return (
<Flex width='100%' gap='2' mt='2' px='4' className='border rounded-md border-slate-8' justify={'between'}>

<Flex align='center' justify='center'>
<Flex align='center' justify='center' gap='2'>
<Flex align='center' justify='center' className='w-12 h-12'>
{previewURL && <img src={previewURL} alt='File preview' className='w-10 h-10 aspect-square object-cover rounded-md' />}
</Flex>
<Flex direction='column' width='100%' className='overflow-hidden whitespace-nowrap'>
<Text as="span" size="2" className='overflow-hidden text-ellipsis whitespace-nowrap'>{file.name}</Text>
<Text size='1' className='italic' color='gray'>
<Flex direction='column' width='100%' className='overflow-hidden whitespace-nowrap gap-0.5'>
<Text as="span" size="1" className='overflow-hidden text-ellipsis whitespace-nowrap'>{file.name}</Text>
<Text size='1' color='gray'>
{fileSizeString}
</Text>
</Flex>
Expand Down
Loading
Loading