refactor directories

This commit is contained in:
Philipinho
2024-04-04 21:16:26 +01:00
parent 4913975e99
commit b58399445e
20 changed files with 169 additions and 561 deletions

View File

@ -0,0 +1,52 @@
import { Group, Box, Button, TagsInput, Space, Select } from "@mantine/core";
import WorkspaceInviteSection from "@/features/settings/workspace/members/components/workspace-invite-section";
import React from "react";
enum UserRole {
OWNER = "Owner",
ADMIN = "Admin",
MEMBER = "Member",
}
export function WorkspaceInviteForm() {
function handleSubmit(data) {
console.log(data);
}
return (
<>
<Box maw="500" mx="auto">
<WorkspaceInviteSection />
<Space h="md" />
<TagsInput
description="Enter valid email addresses separated by comma or space"
label="Invite from email"
placeholder="enter valid emails addresses"
variant="filled"
splitChars={[",", " "]}
maxDropdownHeight={200}
maxTags={50}
/>
<Space h="md" />
<Select
description="Select role to assign to all invited members"
label="Select role"
placeholder="Pick a role"
variant="filled"
data={Object.values(UserRole)}
defaultValue={UserRole.MEMBER}
allowDeselect={false}
checkIconPosition="right"
/>
<Group justify="center" mt="md">
<Button>Send invitation</Button>
</Group>
</Box>
</>
);
}

View File

@ -0,0 +1,27 @@
import { WorkspaceInviteForm } from '@/features/settings/workspace/members/components/workspace-invite-form';
import { Button, Divider, Modal, ScrollArea } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
export default function WorkspaceInviteModal() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Button onClick={open}>
Invite members
</Button>
<Modal size="600" opened={opened} onClose={close} title="Invite new members" centered>
<Divider size="xs" mb="xs"/>
<ScrollArea h="80%">
<WorkspaceInviteForm />
</ScrollArea>
</Modal>
</>
);
}

View File

@ -0,0 +1,41 @@
import { useAtom } from "jotai";
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
import { useEffect, useState } from "react";
import { Button, CopyButton, Group, Text, TextInput } from "@mantine/core";
export default function WorkspaceInviteSection() {
const [currentUser] = useAtom(currentUserAtom);
const [inviteLink, setInviteLink] = useState<string>("");
useEffect(() => {
setInviteLink(
`${window.location.origin}/invite/${currentUser.workspace.inviteCode}`,
);
}, [currentUser.workspace.inviteCode]);
return (
<>
<div>
<Text fw={500} mb="sm">
Invite link
</Text>
<Text c="dimmed" mb="sm">
Anyone with this link can join this workspace.
</Text>
</div>
<Group>
<div style={{ flex: 1 }}>
<TextInput variant="filled" value={inviteLink} readOnly />
</div>
<CopyButton value={inviteLink}>
{({ copied, copy }) => (
<Button color={copied ? "teal" : ""} onClick={copy}>
{copied ? "Copied" : "Copy"}
</Button>
)}
</CopyButton>
</Group>
</>
);
}

View File

@ -0,0 +1,50 @@
import { Group, Table, Avatar, Text, Badge } from "@mantine/core";
import { useWorkspaceMembersQuery } from "@/features/workspace/queries/workspace-query";
import { UserAvatar } from "@/components/ui/user-avatar.tsx";
import React from "react";
export default function WorkspaceMembersTable() {
const { data, isLoading } = useWorkspaceMembersQuery();
return (
<>
{data && (
<Table verticalSpacing="sm">
<Table.Thead>
<Table.Tr>
<Table.Th>User</Table.Th>
<Table.Th>Status</Table.Th>
<Table.Th>Role</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{data?.items.map((user, index) => (
<Table.Tr key={index}>
<Table.Td>
<Group gap="sm">
<UserAvatar avatarUrl={user.avatarUrl} name={user.name} />
<div>
<Text fz="sm" fw={500}>
{user.name}
</Text>
<Text fz="xs" c="dimmed">
{user.email}
</Text>
</div>
</Group>
</Table.Td>
<Table.Td>
<Badge variant="light">Active</Badge>
</Table.Td>
<Table.Td>{user.role}</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
)}
</>
);
}

View File

@ -0,0 +1,65 @@
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
import { useAtom } from "jotai";
import * as z from "zod";
import { useState } from "react";
import { focusAtom } from "jotai-optics";
import { updateWorkspace } from "@/features/workspace/services/workspace-service";
import { IWorkspace } from "@/features/workspace/types/workspace.types";
import { TextInput, Button } from "@mantine/core";
import { useForm, zodResolver } from "@mantine/form";
import { notifications } from "@mantine/notifications";
const formSchema = z.object({
name: z.string().nonempty("Workspace name cannot be blank"),
});
type FormValues = z.infer<typeof formSchema>;
const workspaceAtom = focusAtom(currentUserAtom, (optic) =>
optic.prop("workspace"),
);
export default function WorkspaceNameForm() {
const [isLoading, setIsLoading] = useState(false);
const [currentUser] = useAtom(currentUserAtom);
const [, setWorkspace] = useAtom(workspaceAtom);
const form = useForm<FormValues>({
validate: zodResolver(formSchema),
initialValues: {
name: currentUser?.workspace?.name,
},
});
async function handleSubmit(data: Partial<IWorkspace>) {
setIsLoading(true);
try {
const updatedWorkspace = await updateWorkspace(data);
setWorkspace(updatedWorkspace);
notifications.show({ message: "Updated successfully" });
} catch (err) {
console.log(err);
notifications.show({
message: "Failed to update data",
color: "red",
});
}
setIsLoading(false);
}
return (
<form onSubmit={form.onSubmit(handleSubmit)}>
<TextInput
id="name"
label="Name"
placeholder="e.g ACME"
variant="filled"
{...form.getInputProps("name")}
/>
<Button mt="sm" type="submit" disabled={isLoading} loading={isLoading}>
Save
</Button>
</form>
);
}