Skip to content

Commit

Permalink
bugfix: clear modal content on close + stylize users and invites tables
Browse files Browse the repository at this point in the history
to look the same as other tables
  • Loading branch information
vid277 authored and skeptrunedev committed Jul 15, 2024
1 parent 1b57995 commit c8cc750
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 155 deletions.
32 changes: 27 additions & 5 deletions frontends/dashboard/src/components/InviteUserModal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Accessor, Show, useContext } from "solid-js";
import { Accessor, createMemo, onMount, Show, useContext } from "solid-js";
import { createSignal } from "solid-js";
import { Dialog, DialogOverlay, DialogPanel, DialogTitle } from "terracotta";
import { UserContext } from "../contexts/UserContext";
import { DefaultError } from "shared/types";
import { DefaultError, fromI32ToUserRole } from "shared/types";
import { UserRole, fromUserRoleToI32, stringToUserRole } from "shared/types";
import { createToast } from "./ShowToasts";

Expand All @@ -20,6 +20,28 @@ export const InviteUserModal = (props: InviteUserModalProps) => {

const userContext = useContext(UserContext);

const currentUserRole = createMemo(() => {
const selectedOrgId = userContext.selectedOrganizationId?.();
if (!selectedOrgId) return 0;
return (
userContext
.user?.()
?.user_orgs.find(
(user_org) => user_org.organization_id === selectedOrgId,
)?.role ?? 0
);
});

onMount(() => {
setRole(fromI32ToUserRole(currentUserRole()));
});

const handleCloseModal = () => {
setEmail("");
setRole(fromI32ToUserRole(currentUserRole()));
props.closeModal();
};

const inviteUser = (closeModal: () => void) => {
setSendingEmail(true);
void fetch(`${apiHost}/invitation`, {
Expand Down Expand Up @@ -64,7 +86,7 @@ export const InviteUserModal = (props: InviteUserModalProps) => {
<Dialog
isOpen
class="fixed inset-0 z-10 overflow-y-auto"
onClose={props.closeModal}
onClose={handleCloseModal}
>
<div class="flex min-h-screen items-center justify-center px-4">
<DialogOverlay class="fixed inset-0 bg-neutral-900 bg-opacity-50" />
Expand All @@ -77,7 +99,7 @@ export const InviteUserModal = (props: InviteUserModalProps) => {
<form
onSubmit={(e) => {
e.preventDefault();
inviteUser(props.closeModal);
inviteUser(handleCloseModal);
}}
>
<div class="space-y-12 sm:space-y-16">
Expand Down Expand Up @@ -149,7 +171,7 @@ export const InviteUserModal = (props: InviteUserModalProps) => {
<button
type="button"
class="inline-flex justify-center rounded-md border bg-neutral-100 px-3 py-2 text-sm font-semibold text-black shadow-sm hover:bg-neutral-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-900 disabled:bg-magenta-200"
onClick={() => props.closeModal()}
onClick={handleCloseModal}
>
Cancel
</button>
Expand Down
298 changes: 148 additions & 150 deletions frontends/dashboard/src/pages/Dashboard/UserManagment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const UserManagement = () => {
setShowInvitations(!showInvitations());
}}
type="button"
class="block rounded-md bg-neutral-100 px-3 py-2 text-center shadow-sm hover:bg-neutral-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-200"
class="block h-[42px] rounded-md border bg-neutral-100 px-3 py-2 text-center shadow-sm hover:bg-neutral-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-200"
>
{showInvitations() ? "Show Users" : "Show Invitations"}
</button>
Expand All @@ -235,160 +235,158 @@ export const UserManagement = () => {
setInviteUserModalOpen(true);
}}
type="button"
class="block rounded-md bg-magenta-500 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-magenta-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-magenta-600"
class="block h-[42px] rounded-md border bg-magenta-500 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-magenta-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-magenta-600"
>
Add user
Add User
</button>
</Show>
</div>
</div>
<div class="mt-4 rounded border shadow">
<div class="">
<table class="min-w-full border-separate border-spacing-0">
<Show when={!showInvitations()}>
<thead>
<tr>
<th
scope="col"
class="sticky top-0 rounded-tl border-b border-neutral-300 bg-white bg-opacity-75 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter sm:pl-6 lg:pl-8"
>
Name
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 px-3 py-3.5 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter"
>
Email
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 px-3 py-3.5 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter"
>
Role
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 py-3.5 pl-3 backdrop-blur backdrop-filter"
>
<span class="sr-only">Edit</span>
</th>
<th
scope="col"
class="sticky top-0 rounded-tr border-b border-neutral-300 bg-white bg-opacity-75 pr-4 backdrop-blur backdrop-filter sm:pr-6 lg:pr-8"
>
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody>
<For each={users()}>
{(user) => (
<tr>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pl-4 pr-3 text-sm font-medium text-neutral-900 sm:pl-6 lg:pl-8">
{user.name}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{user.email}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{fromI32ToUserRole(user.user_orgs[0].role) as string}
</td>
<td class="relative whitespace-nowrap border-b border-neutral-200 py-4 text-right font-medium">
<button
onClick={() => {
setEditingUser(user);
}}
disabled={user.id === userContext.user?.()?.id}
classList={{
"text-neutral-200 cursor-not-allowed":
user.id === userContext.user?.()?.id,
"text-magenta-500 hover:text-magenta-900":
user.id !== userContext.user?.()?.id,
}}
>
Edit
</button>
</td>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pr-4 text-right text-sm font-medium">
<button
onClick={() => {
removeUser(user.id);
}}
disabled={user.id === userContext.user?.()?.id}
classList={{
"text-neutral-200 cursor-not-allowed":
user.id === userContext.user?.()?.id,
"text-red-500 hover:text-red-900":
user.id !== userContext.user?.()?.id,
}}
>
<FaRegularTrashCan />
</button>
</td>
</tr>
)}
</For>
</tbody>
</Show>
<Show when={showInvitations()}>
<thead>
<tr>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter sm:pl-6 lg:pl-8"
>
Email
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 px-3 py-3.5 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter"
>
Role
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 px-3 py-3.5 text-left text-sm font-semibold text-neutral-900 backdrop-blur backdrop-filter"
>
Status
</th>
<th
scope="col"
class="sticky top-0 border-b border-neutral-300 bg-white bg-opacity-75 py-3.5 pl-3 pr-4 backdrop-blur backdrop-filter sm:pr-6 lg:pr-8"
>
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody>
<For each={invitations()}>
{(invitation) => (
<tr>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pl-4 pr-3 text-sm font-medium text-neutral-900 sm:pl-6 lg:pl-8">
{invitation.email}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{fromI32ToUserRole(invitation.role) as string}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{invitation.used ? "Accepted" : "Not Accepted"}
</td>
<td class="relative whitespace-nowrap border-b border-neutral-200 py-4 pr-4 text-right font-medium sm:pr-8 lg:pr-36 xl:pr-48">
<button
onClick={() => {
deleteInvitation(invitation.id);
}}
class="text-magenta-500 hover:text-magenta-900"
>
Delete
</button>
</td>
</tr>
)}
</For>
</tbody>
</Show>
</table>
</div>
<div class="mt-8 overflow-hidden rounded shadow-sm ring-1 ring-black ring-opacity-5">
<table class="min-w-full divide-y divide-neutral-300">
<Show when={!showInvitations()}>
<thead class="bg-neutral-100">
<tr>
<th
scope="col"
class="py-3.5 pl-6 pr-3 text-left text-sm font-semibold"
>
Name
</th>
<th
scope="col"
class="py-3.5 pl-6 pr-3 text-left text-sm font-semibold"
>
Email
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold"
>
Role
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold"
>
<span class="sr-only">Edit</span>
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold"
>
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody>
<For each={users()}>
{(user) => (
<tr>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pl-4 pr-3 text-sm font-medium text-neutral-900 sm:pl-6 lg:pl-8">
{user.name}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{user.email}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{fromI32ToUserRole(user.user_orgs[0].role) as string}
</td>
<td class="relative whitespace-nowrap border-b border-neutral-200 py-4 text-right font-medium">
<button
onClick={() => {
setEditingUser(user);
}}
disabled={user.id === userContext.user?.()?.id}
classList={{
"text-neutral-200 cursor-not-allowed":
user.id === userContext.user?.()?.id,
"text-magenta-500 hover:text-magenta-900":
user.id !== userContext.user?.()?.id,
}}
>
Edit
</button>
</td>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pr-4 text-right text-sm font-medium">
<button
onClick={() => {
removeUser(user.id);
}}
disabled={user.id === userContext.user?.()?.id}
classList={{
"text-neutral-200 cursor-not-allowed":
user.id === userContext.user?.()?.id,
"text-red-500 hover:text-red-900":
user.id !== userContext.user?.()?.id,
}}
>
<FaRegularTrashCan />
</button>
</td>
</tr>
)}
</For>
</tbody>
</Show>
<Show when={showInvitations()}>
<thead class="bg-neutral-100">
<tr>
<th
scope="col"
class="py-3.5 pl-6 pr-3 text-left text-sm font-semibold"
>
Email
</th>
<th
scope="col"
class="py-3.5 pl-6 pr-3 text-left text-sm font-semibold"
>
Role
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold"
>
Status
</th>
<th
scope="col"
class="px-3 py-3.5 text-left text-sm font-semibold"
>
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody>
<For each={invitations()}>
{(invitation) => (
<tr>
<td class="whitespace-nowrap border-b border-neutral-200 py-4 pl-4 pr-3 text-sm font-medium text-neutral-900 sm:pl-6 lg:pl-8">
{invitation.email}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{fromI32ToUserRole(invitation.role) as string}
</td>
<td class="whitespace-nowrap border-b border-neutral-200 px-3 py-4 text-sm text-neutral-900">
{invitation.used ? "Accepted" : "Not Accepted"}
</td>
<td class="relative whitespace-nowrap border-b border-neutral-200 py-4 pr-4 text-right font-medium sm:pr-8 lg:pr-36 xl:pr-48">
<button
onClick={() => {
deleteInvitation(invitation.id);
}}
class="text-magenta-500 hover:text-magenta-900"
>
Delete
</button>
</td>
</tr>
)}
</For>
</tbody>
</Show>
</table>
</div>
<InviteUserModal
isOpen={inviteUserModalOpen}
Expand Down

0 comments on commit c8cc750

Please sign in to comment.