Add CreateWorkspaceModal

This commit is contained in:
2024-10-26 23:29:33 +02:00
parent 12312137b7
commit bbd7358d15
3 changed files with 195 additions and 93 deletions

View File

@@ -17,10 +17,12 @@ import { IconFolders, IconSettings, IconFolderPlus } from '@tabler/icons-react';
import { useWorkspace } from '../contexts/WorkspaceContext'; import { useWorkspace } from '../contexts/WorkspaceContext';
import { useModalContext } from '../contexts/ModalContext'; import { useModalContext } from '../contexts/ModalContext';
import { listWorkspaces } from '../services/api'; import { listWorkspaces } from '../services/api';
import CreateWorkspaceModal from './modals/CreateWorkspaceModal';
const WorkspaceSwitcher = () => { const WorkspaceSwitcher = () => {
const { currentWorkspace, switchWorkspace } = useWorkspace(); const { currentWorkspace, switchWorkspace } = useWorkspace();
const { setSettingsModalVisible } = useModalContext(); const { setSettingsModalVisible, setCreateWorkspaceModalVisible } =
useModalContext();
const [workspaces, setWorkspaces] = useState([]); const [workspaces, setWorkspaces] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [popoverOpened, setPopoverOpened] = useState(false); const [popoverOpened, setPopoverOpened] = useState(false);
@@ -36,100 +38,114 @@ const WorkspaceSwitcher = () => {
setLoading(false); setLoading(false);
}; };
return ( const handleCreateWorkspace = () => {
<Popover setPopoverOpened(false);
width={300} setCreateWorkspaceModalVisible(true);
position="bottom-start" };
shadow="md"
opened={popoverOpened}
onChange={setPopoverOpened}
>
<Popover.Target>
<UnstyledButton
onClick={() => {
setPopoverOpened((o) => !o);
if (!popoverOpened) {
loadWorkspaces();
}
}}
>
<Group gap="xs">
<IconFolders size={20} />
<div>
<Text size="sm" fw={500}>
{currentWorkspace?.name || 'No workspace'}
</Text>
</div>
</Group>
</UnstyledButton>
</Popover.Target>
<Popover.Dropdown> const handleWorkspaceCreated = async (newWorkspace) => {
<Text size="sm" fw={600} mb="md"> await loadWorkspaces();
Switch Workspace switchWorkspace(newWorkspace.id);
</Text> };
<ScrollArea.Autosize mah={400} mb="md" offsetScrollbars>
<Stack gap="xs"> return (
{loading ? ( <>
<Center p="md"> <Popover
<Loader size="sm" /> width={300}
</Center> position="bottom-start"
) : ( shadow="md"
workspaces.map((workspace) => ( opened={popoverOpened}
<UnstyledButton onChange={setPopoverOpened}
key={workspace.id} >
onClick={() => { <Popover.Target>
switchWorkspace(workspace.id); <UnstyledButton
setPopoverOpened(false); onClick={() => {
}} setPopoverOpened((o) => !o);
> if (!popoverOpened) {
<Paper loadWorkspaces();
p="xs" }
withBorder={workspace.id === currentWorkspace?.id} }}
bg={ >
workspace.id === currentWorkspace?.id <Group gap="xs">
? 'var(--mantine-color-blue-light)' <IconFolders size={20} />
: undefined <div>
} <Text size="sm" fw={500}>
{currentWorkspace?.name || 'No workspace'}
</Text>
</div>
</Group>
</UnstyledButton>
</Popover.Target>
<Popover.Dropdown>
<Text size="sm" fw={600} mb="md">
Switch Workspace
</Text>
<ScrollArea.Autosize mah={400} mb="md" offsetScrollbars>
<Stack gap="xs">
{loading ? (
<Center p="md">
<Loader size="sm" />
</Center>
) : (
workspaces.map((workspace) => (
<UnstyledButton
key={workspace.id}
onClick={() => {
switchWorkspace(workspace.id);
setPopoverOpened(false);
}}
> >
<Group justify="space-between" wrap="nowrap"> <Paper
<Box> p="xs"
<Text size="sm" fw={500} truncate> withBorder={workspace.id === currentWorkspace?.id}
{workspace.name} bg={
</Text> workspace.id === currentWorkspace?.id
<Text size="xs" c="dimmed"> ? 'var(--mantine-color-blue-light)'
{new Date(workspace.createdAt).toLocaleDateString()} : undefined
</Text> }
</Box> >
{workspace.id === currentWorkspace?.id && ( <Group justify="space-between" wrap="nowrap">
<ActionIcon <Box>
variant="subtle" <Text size="sm" fw={500} truncate>
size="sm" {workspace.name}
onClick={(e) => { </Text>
e.stopPropagation(); <Text size="xs" c="dimmed">
setSettingsModalVisible(true); {new Date(workspace.createdAt).toLocaleDateString()}
setPopoverOpened(false); </Text>
}} </Box>
> {workspace.id === currentWorkspace?.id && (
<IconSettings size={14} /> <ActionIcon
</ActionIcon> variant="subtle"
)} size="sm"
</Group> onClick={(e) => {
</Paper> e.stopPropagation();
</UnstyledButton> setSettingsModalVisible(true);
)) setPopoverOpened(false);
)} }}
</Stack> >
</ScrollArea.Autosize> <IconSettings size={14} />
<Button </ActionIcon>
variant="light" )}
leftSection={<IconFolderPlus size={14} />} </Group>
fullWidth </Paper>
> </UnstyledButton>
Create Workspace ))
</Button> )}
</Popover.Dropdown> </Stack>
</Popover> </ScrollArea.Autosize>
<Button
variant="light"
leftSection={<IconFolderPlus size={14} />}
fullWidth
onClick={handleCreateWorkspace}
>
Create Workspace
</Button>
</Popover.Dropdown>
</Popover>
<CreateWorkspaceModal onWorkspaceCreated={handleWorkspaceCreated} />
</>
); );
}; };

View File

@@ -0,0 +1,82 @@
import React, { useState } from 'react';
import { Modal, TextInput, Button, Group, Box } from '@mantine/core';
import { useModalContext } from '../../contexts/ModalContext';
import { createWorkspace } from '../../services/api';
import { notifications } from '@mantine/notifications';
const CreateWorkspaceModal = ({ onWorkspaceCreated }) => {
const [name, setName] = useState('');
const [loading, setLoading] = useState(false);
const { createWorkspaceModalVisible, setCreateWorkspaceModalVisible } =
useModalContext();
const handleSubmit = async () => {
if (!name.trim()) {
notifications.show({
title: 'Error',
message: 'Workspace name is required',
color: 'red',
});
return;
}
setLoading(true);
try {
const workspace = await createWorkspace(name);
notifications.show({
title: 'Success',
message: 'Workspace created successfully',
color: 'green',
});
setName('');
setCreateWorkspaceModalVisible(false);
if (onWorkspaceCreated) {
onWorkspaceCreated(workspace);
}
} catch (error) {
notifications.show({
title: 'Error',
message: 'Failed to create workspace',
color: 'red',
});
} finally {
setLoading(false);
}
};
return (
<Modal
opened={createWorkspaceModalVisible}
onClose={() => setCreateWorkspaceModalVisible(false)}
title="Create New Workspace"
centered
size="sm"
>
<Box maw={400} mx="auto">
<TextInput
label="Workspace Name"
placeholder="Enter workspace name"
value={name}
onChange={(event) => setName(event.currentTarget.value)}
mb="md"
w="100%"
disabled={loading}
/>
<Group justify="flex-end" mt="md">
<Button
variant="default"
onClick={() => setCreateWorkspaceModalVisible(false)}
disabled={loading}
>
Cancel
</Button>
<Button onClick={handleSubmit} loading={loading}>
Create
</Button>
</Group>
</Box>
</Modal>
);
};
export default CreateWorkspaceModal;

View File

@@ -10,6 +10,8 @@ export const ModalProvider = ({ children }) => {
const [settingsModalVisible, setSettingsModalVisible] = useState(false); const [settingsModalVisible, setSettingsModalVisible] = useState(false);
const [switchWorkspaceModalVisible, setSwitchWorkspaceModalVisible] = const [switchWorkspaceModalVisible, setSwitchWorkspaceModalVisible] =
useState(false); useState(false);
const [createWorkspaceModalVisible, setCreateWorkspaceModalVisible] =
useState(false);
const value = { const value = {
newFileModalVisible, newFileModalVisible,
@@ -22,6 +24,8 @@ export const ModalProvider = ({ children }) => {
setSettingsModalVisible, setSettingsModalVisible,
switchWorkspaceModalVisible, switchWorkspaceModalVisible,
setSwitchWorkspaceModalVisible, setSwitchWorkspaceModalVisible,
createWorkspaceModalVisible,
setCreateWorkspaceModalVisible,
}; };
return ( return (