refactor(dashboard): use svelte context for lists

This commit is contained in:
Jake Fulmine 2023-06-03 12:27:58 +02:00
parent f2e160c526
commit a48f2b40c4
23 changed files with 598 additions and 433 deletions

View file

@ -142,9 +142,9 @@
<Link to={getGroupPageUrl(true)}><button class="link-button button-right btn btn-secondary" style={isPublic ? "float: none !important; margin-left: 0;" : ""} tabindex={-1} aria-label="randomize group members">Randomize group</button></Link>
{:else if editMode}
<Edit on:update on:deletion bind:group bind:editMode />
<Edit {group} bind:editMode />
{:else if memberMode}
<MemberEdit on:updateGroupMembers bind:group bind:memberMode bind:members />
<MemberEdit {group} bind:memberMode />
{/if}
</CardBody>

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { Card, CardHeader, CardTitle, Modal, Button, ListGroup, ListGroupItem, Label, Input, Alert, Tooltip, Row, Col } from 'sveltestrap';
import { getContext } from 'svelte';
import { CardHeader, CardTitle, Modal, Button, ListGroup, ListGroupItem, Label, Input, Alert, Tooltip, Row, Col } from 'sveltestrap';
import parseMarkdown from '../../api/parse-markdown';
import twemoji from 'twemoji';
import { Link } from 'svelte-navigator';
@ -12,16 +12,16 @@
import FaTimes from 'svelte-icons/fa/FaTimes.svelte'
import FaCheck from 'svelte-icons/fa/FaCheck.svelte'
import type { Group, Member} from '../../api/types';
import type { Group, Member } from '../../api/types';
import api from '../../api';
import default_avatar from '../../assets/default_avatar.png';
import resizeMedia from '../../api/resize-media';
import AwaitHtml from '../common/AwaitHtml.svelte';
import type { Writable } from 'svelte/store';
export let group: Group;
export let searchBy: string;
export let sortBy: string;
export let members: Member[];
export let isPublic = false;
export let isDash = false;
@ -60,17 +60,14 @@
let altText = `member ${group.name} avatar`;
$: memberList = members && members.filter(m => group.members && group.members.includes(m.uuid) && true).sort((a, b) => a.name.localeCompare(b.name)) || [];
$: members = getContext<Writable<Member[]>>("members")
$: memberList = $members && $members.filter(m => group.members && group.members.includes(m.uuid) && true).sort((a, b) => a.name.localeCompare(b.name)) || [];
$: groups = getContext<Writable<Member[]>>("groups")
let listGroupElements = [];
let pageLink = isPublic ? `/profile/g/${group.id}` : `/dash/g/${group.id}`;
const dispatch = createEventDispatcher();
function update(group: Group) {
dispatch('update', group);
}
async function submit() {
let data = input;
err = [];
@ -93,9 +90,17 @@
loading = true;
try {
let res = await api().groups(group.id).patch({data});
update({...group, ...res});
group = {...group, ...res};
const newgroup = {...group, ...res};
const newList = $groups.map((g: Group) => {
if (group.uuid === g.uuid) {
g = newgroup
}
return g
})
groups.set(newList)
err = [];
loading = false;
view = 'card';
} catch (error) {
console.log(error);
@ -179,7 +184,7 @@
<Input bind:value={input.icon} maxlength={256} type="url" placeholder={group.icon} aria-label="group avatar url"/>
<hr style="min-height: 1px" />
<Label>Display name:</Label>
<textarea class="form-control mb-2" style="resize: none; height: 1em" bind:value={input.display_name} maxlength={100} type="text" placeholder={group.display_name} aria-label="group display name" />
<textarea class="form-control mb-2" style="resize: none; height: 1em" bind:value={input.display_name} maxlength={100} placeholder={group.display_name} aria-label="group display name" />
<hr style="min-height: 1px" />
<Label>Description:</Label>
<textarea class="form-control" style="resize: none; overflow: hidden;" bind:value={input.description} maxlength={1000} use:autoresize placeholder={group.description} aria-label="group description"/>

View file

@ -1,6 +1,7 @@
<script lang="ts">
import type { Writable } from 'svelte/store';
import { Row, Col, Input, Button, Label, Alert, Spinner, Modal, ModalHeader, ModalBody } from 'sveltestrap';
import { createEventDispatcher, tick } from 'svelte';
import { getContext, tick } from 'svelte';
import type { Group } from '../../api/types';
import api from '../../api';
import { autoresize } from 'svelte-textarea-autoresize';
@ -13,19 +14,11 @@
export let group: Group;
export let editMode: boolean;
$: groups = getContext<Writable<Group[]>>("groups")
let err: string[] = [];
let input: Group = group;
const dispatch = createEventDispatcher();
function deletion() {
dispatch('deletion', group.id);
}
function update(group: Group) {
dispatch('update', group);
}
let input: Group = JSON.parse(JSON.stringify(group));
async function submit() {
let data = input;
@ -49,7 +42,15 @@
loading = true;
try {
let res = await api().groups(group.id).patch({data});
update({...group, ...res});
const newgroup = {...group, ...res};
const newList = $groups.map((g: Group) => {
if (group.uuid === g.uuid) {
g = newgroup
}
return g
})
groups.set(newList);
err = [];
editMode = false;
return;
@ -85,7 +86,10 @@
deleteErr = null;
toggleDeleteModal();
loading = false;
deletion();
const newList = $groups.filter((g: Group) => group.uuid !== g.uuid)
groups.set(newList);
} catch (error) {
loading = false;
}
@ -110,7 +114,7 @@
</Col>
<Col xs={12} lg={4} class="mb-2">
<Label>Display name:</Label>
<textarea class="form-control" style="resize: none; height: 1em" bind:value={input.display_name} maxlength={100} type="text" placeholder={group.display_name} aria-label="group display name"/>
<textarea class="form-control" style="resize: none; height: 1em" bind:value={input.display_name} maxlength={100} placeholder={group.display_name} aria-label="group display name"/>
</Col>
<Col xs={12} lg={4} class="mb-2">
<Label>Color:</Label>

View file

@ -1,4 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { Row, Col, Button, Alert, ListGroup, ListGroupItem, Spinner } from 'sveltestrap';
import ListPagination from "../common/ListPagination.svelte";
import twemoji from "twemoji";
@ -14,7 +16,9 @@
let err: string;
export let group: Group;
export let memberMode: boolean = true;
export let members: Member[];
$: groups = getContext<Writable<Group[]>>("groups")
$: members = getContext<Writable<Member[]>>("members")
let membersInGroup: Member[];
let membersNotInGroup: Member[];
@ -28,18 +32,13 @@
let smallPages = true;
updateMemberList();
function updateMemberList() {
membersInGroup = members.filter(member => group.members.includes(member.uuid));
membersInGroup = membersInGroup.sort((a, b) => a.name.localeCompare(b.name));
$: membersInGroup = $members.filter(member => group.members.includes(member.uuid)).sort((a, b) => a.name.localeCompare(b.name));;
membersNotInGroup = members.filter(member => !group.members.includes(member.uuid));
membersNotInGroup = membersNotInGroup.sort((a, b) => a.name.localeCompare(b.name));
$: membersNotInGroup = $members.filter(member => !group.members.includes(member.uuid)).sort((a, b) => a.name.localeCompare(b.name));
membersInGroupSelection = membersInGroup.map(function(member) { return {name: member.name, shortid: member.id, id: member.uuid, display_name: member.display_name}; }).sort((a, b) => a.name.localeCompare(b.name));
membersNotInGroupSelection = membersNotInGroup.map(function(member) { return {name: member.name, shortid: member.id, id: member.uuid, display_name: member.display_name}; }).sort((a, b) => a.name.localeCompare(b.name));
}
$: membersInGroupSelection = membersInGroup.map(function(member) { return {name: member.name, shortid: member.id, id: member.uuid, display_name: member.display_name}; }).sort((a, b) => a.name.localeCompare(b.name));
$: membersNotInGroupSelection = membersNotInGroup.map(function(member) { return {name: member.name, shortid: member.id, id: member.uuid, display_name: member.display_name}; }).sort((a, b) => a.name.localeCompare(b.name));
$: indexOfLastItem = currentPage * 10;
$: indexOfFirstItem = indexOfLastItem - 10;
@ -69,7 +68,13 @@ function memberListRenderer(item: any) {
loading = true;
await api().groups(group.id).members.add.post({data});
data.forEach(member => group.members.push(member));
updateMemberList();
$groups.forEach(g => {
if (g.uuid === group.uuid) {
g.members = group.members
}
})
groups.set($groups)
err = null;
membersToBeAdded = [];
loading = false;
@ -86,7 +91,13 @@ function memberListRenderer(item: any) {
loading = true;
await api().groups(group.id).members.remove.post({data});
group.members = group.members.filter(m => !data.includes(m));
updateMemberList();
$groups.forEach(g => {
if (g.uuid === group.uuid) {
g.members = group.members
}
})
groups.set($groups)
err = null;
membersToBeRemoved = [];
loading = false;

View file

@ -3,8 +3,9 @@
import type { Group } from '../../api/types';
import api from '../../api';
import { autoresize } from 'svelte-textarea-autoresize';
import { createEventDispatcher } from 'svelte';
import { getContext } from 'svelte';
import FaPlus from 'svelte-icons/fa/FaPlus.svelte';
import type { Writable } from 'svelte/store';
const descriptions: string[] = JSON.parse(localStorage.getItem("pk-config"))?.description_templates;
@ -24,11 +25,7 @@
}
}
const dispatch = createEventDispatcher();
function create(data: Group) {
dispatch('create', data);
}
$: groups = getContext<Writable<Group[]>>("groups");
let input: Group = JSON.parse(JSON.stringify(defaultGroup));
@ -55,7 +52,10 @@
try {
let res: Group = await api().groups().post({data});
res.members = [];
create(res);
$groups.push(res)
groups.set($groups)
input = JSON.parse(JSON.stringify(defaultGroup));
message = `Group ${data.name} successfully created!`
err = [];

View file

@ -1,14 +1,17 @@
<script lang="ts">
import { tick, createEventDispatcher } from "svelte";
import { tick, getContext } from "svelte";
import { ModalBody, ModalHeader, Col, Row, Input, Label, ModalFooter, Button, Spinner, Alert } from "sveltestrap";
import type { Group, GroupPrivacy } from '../../api/types';
import api from '../../api';
import type { Writable } from "svelte/store";
export let privacyOpen: boolean;
export let group: Group;
const togglePrivacyModal = () => (privacyOpen = !privacyOpen);
$: groups = getContext<Writable<Group[]>>("groups")
let err: string;
let loading = false;
let success = false;
@ -18,12 +21,6 @@
Object.keys(privacy).forEach(x => privacy[x] = target.value);
}
const dispatch = createEventDispatcher();
function update(group) {
dispatch('update', group);
}
// I can't use the hacked together Required<T> type from the bulk privacy here
// that breaks updating the displayed privacy after submitting
// but there's not really any way for any privacy fields here to be missing
@ -43,7 +40,15 @@
const data: Group = {privacy: privacy};
try {
let res = await api().groups(group.id).patch({data});
group = {...group, ...res};
const newgroup = {...group, ...res};
const newList = $groups.map((g: Group) => {
if (group.uuid === g.uuid) {
g = newgroup
}
return g
})
groups.set(newList);
success = true;
} catch (error) {
console.log(error);