Skip to content
This repository was archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
✨ Add support for multiple memberships
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Jan 11, 2021
1 parent 0f13aa5 commit dd66f28
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 8 deletions.
8 changes: 7 additions & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const api = async <T>({
if (index === i) {
return {
details: user.details,
memberships: user.memberships,
auth: { accessToken, refreshToken },
};
}
Expand Down Expand Up @@ -159,8 +160,13 @@ export const loginWithTokenResponse = async (auth: User["auth"]) => {
url: `/users/${userId}`,
token: auth.accessToken,
});
const memberships = await api<any>({
method: "GET",
url: `/users/${userId}/memberships`,
token: auth.accessToken,
});
users.update((val) =>
[...val, { details, auth }].filter(
[...val, { details, memberships, auth }].filter(
(v, i, a) => a.map((i) => i.details.id).indexOf(v.details.id) === i
)
);
Expand Down
7 changes: 6 additions & 1 deletion src/components/Table/GroupRecord.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import TimeAgo from "../TimeAgo.svelte";
export let item: any;
export let itemType: "membership" | "group" = "group";
export let data: any = {};
Expand All @@ -18,6 +20,9 @@
</div>
<div class="ml-5">
<div class="text-sm font-medium text-gray-900">{data.name}</div>
<div class="text-sm text-gray-500">#{data.id}</div>
<div class="text-sm text-gray-500">
Created
<TimeAgo date={data.createdAt} />
</div>
</div>
</a>
64 changes: 61 additions & 3 deletions src/routes/users/[slug]/groups.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
<script lang="ts">
import { stores } from "@sapper/app";
import type { Membership } from "@koj/types";
import { can } from "../../../api";
import { api, can } from "../../../api";
import DataTable from "../../../components/DataTable.svelte";
import DeleteModal from "../../../components/DeleteModal.svelte";
import GroupRecord from "../../../components/Table/GroupRecord.svelte";
import Form from "../../../components/Form.svelte";
import { users } from "../../../stores";
import Tag from "../../../components/Tag.svelte";
const { page } = stores();
const { slug } = $page.params;
const primaryKeyType = "id";
let data: Membership[] = [];
let deleteActiveKey: number | undefined = undefined;
const updateData = (item: any) => {
if (data.find((i) => i[primaryKeyType] === item[primaryKeyType]))
data = data.map((i) => {
if (i[primaryKeyType] === item[primaryKeyType]) return item;
return i;
});
else data = [...data, item];
};
const add = async (body: { name: string; scopes: string[] }) => {
const result = await api<any>({
method: "POST",
url: `/users/${slug}/memberships`,
body,
});
users.update((items) => {
items = items.map((i) => {
if (i.details.id === slug) return { ...i, memberships: [...i.memberships, result] };
return i;
});
return items;
});
updateData(result);
};
</script>

<svelte:head>
Expand All @@ -25,15 +53,36 @@
titleKey="name"
text="These are the groups associated with this user."
endpoint={`/users/${slug}/memberships`}
headers={['Group']}
headers={['Group', 'Role']}
onData={(val) => (data = val)}
{primaryKeyType}
filters={[{ title: 'Name', name: 'name', type: 'string' }, { title: 'ID', name: primaryKeyType, type: 'string' }, { title: 'Created at', name: 'createdAt', type: 'datetime' }, { title: 'Updated at', name: 'updatedAt', type: 'datetime' }]}>
<td class="px-7 py-4 whitespace-nowrap">
<GroupRecord item={item.group} />
</td>
<td class="px-7 py-4 whitespace-nowrap">
{#if item.role === 'OWNER'}
<Tag href={`/users/${slug}/groups?q=${encodeURIComponent('role: OWNER')}`} color="blue">
Owner
</Tag>
{:else if item.role === 'ADMIN'}
<Tag href={`/users/${slug}/groups?q=${encodeURIComponent('role: ADMIN')}`} color="indigo">
Admin
</Tag>
{:else if item.role === 'MEMBER'}
<Tag href={`/users/${slug}/groups?q=${encodeURIComponent('role: MEMBER')}`} color="green">
Member
</Tag>
{:else}
<Tag
href={`/users/${slug}/groups?q=${encodeURIComponent(`role: ${item.role}`)}`}
color="gray">
${item.role}
</Tag>
{/if}
</td>
<td class="px-7 py-4 whitespace-nowrap text-right text-sm font-medium">
{#if can(`email:write-info-${item[primaryKeyType]}`)}
{#if can(`user-${slug}:delete-membership-${item[primaryKeyType]}`)}
<button
aria-label="Leave"
data-balloon-pos="up"
Expand All @@ -54,6 +103,15 @@
</td>
</DataTable>

<div class="p-7">
<Form
title="Add group"
text="Create another group to invite your team to."
items={[{ name: 'name', label: 'Name', required: true }]}
submitText="Create group"
onSubmit={add} />
</div>

{#if deleteActiveKey}
<DeleteModal
title="Leave group"
Expand Down
8 changes: 5 additions & 3 deletions src/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { writable } from "svelte/store";

export interface User {
auth: { accessToken: string; refreshToken: string };
memberships: {
id: number;
group: { id: number; name: string; profilePicture: string; role: "ADMIN" | "OWNER" | "MEMBER" };
}[];
details: {
checkLocationOnLogin: boolean;
countryCode: string;
Expand Down Expand Up @@ -52,6 +56,4 @@ export const activeNotification = writable<{
text: string;
type: string;
} | null>(null);
activeNotification.subscribe(() =>
setTimeout(() => activeNotification.set(null), 3500)
);
activeNotification.subscribe(() => setTimeout(() => activeNotification.set(null), 3500));

0 comments on commit dd66f28

Please sign in to comment.