Skip to content

Commit

Permalink
refactor(bulk-list): centralize bookmark management with dedicated store
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Goniszewski <[email protected]>
  • Loading branch information
goniszewski committed Oct 29, 2024
1 parent a1f19ee commit b1cc513
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 53 deletions.
33 changes: 10 additions & 23 deletions src/lib/components/BulkList/BulkList.svelte
Original file line number Diff line number Diff line change
@@ -1,40 +1,28 @@
<script lang="ts">
import { writable } from 'svelte/store';
import { importBookmarkStore } from '$lib/stores/import-bookmarks.store';
import { type Readable } from 'svelte/store';
import BulkListItem from '../BulkListItem/BulkListItem.svelte';
export let itemList = writable<BulkListItem[]>([]);
export let itemList: Readable<BulkListItem[]>;
export let isLoading = false;
const isAnyItemSelected = writable(false);
$: $isAnyItemSelected = $itemList && $itemList.some((bookmark) => bookmark.selected);
const toggleItemSelection = (id: number) => {
$itemList = $itemList.map((item) => {
if (item.id === id) {
item.selected = !item.selected;
}
return item;
});
};
const selectAllItems = ({ target }: Event) => {
if (target instanceof HTMLInputElement) {
$itemList = $itemList.map((item) => {
item.selected = target.checked;
return item;
});
importBookmarkStore.setSelectStatusForAll(target.checked);
}
};
const removeSelectedItems = () => {
$itemList = $itemList.filter((item) => !item.selected);
importBookmarkStore.removeSelected();
};
</script>

<div class="flex max-w-4xl flex-col gap-2">
<div class="mb-2 flex w-full items-end justify-end">
<button class="btn btn-primary" disabled={!$isAnyItemSelected} on:click={removeSelectedItems}
>DELETE</button>
<button
class="btn btn-primary"
disabled={!importBookmarkStore.isAnySelected}
on:click={removeSelectedItems}>DELETE</button>
</div>
<div class="max-h-[calc(100vh-16rem)] overflow-x-auto">
<table class="table table-pin-rows table-pin-cols table-xs">
Expand Down Expand Up @@ -62,8 +50,7 @@ const removeSelectedItems = () => {
category={category}
selected={selected}
isLoading={isLoading}
metadataFetched={!!contentHtml}
toggleItemSelection={toggleItemSelection} />
metadataFetched={!!contentHtml} />
{/each}
</tbody>
<!-- foot -->
Expand Down
10 changes: 7 additions & 3 deletions src/lib/components/BulkListItem/BulkListItem.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { importBookmarkStore } from '$lib/stores/import-bookmarks.store';
import {
IconCircleDashedCheck,
IconExclamationCircle,
Expand All @@ -14,9 +15,12 @@ export let title: string;
export let category: string;
export let isLoading: boolean;
export let metadataFetched: boolean;
export let toggleItemSelection: (id: number) => void;
let urlObj = new URL(url);
const removeItem = () => {
importBookmarkStore.removeItem(id);
};
</script>

<tr>
Expand All @@ -26,7 +30,7 @@ let urlObj = new URL(url);
type="checkbox"
class="checkbox"
bind:checked={selected}
on:change={() => toggleItemSelection(id)} />
on:change={() => importBookmarkStore.toggleSelectionForItem(id)} />
</label>
</th>
<td>
Expand Down Expand Up @@ -75,6 +79,6 @@ let urlObj = new URL(url);
<td><span class="link hover:link-secondary">{category}</span></td>
<th>
<button class="btn btn-ghost btn-xs text-secondary">edit</button>
<button class="btn btn-ghost btn-xs text-error">remove</button>
<button class="btn btn-ghost btn-xs text-error" on:click={removeItem}>remove</button>
</th>
</tr>
69 changes: 42 additions & 27 deletions src/lib/components/Pagination/Pagination.svelte
Original file line number Diff line number Diff line change
@@ -1,44 +1,58 @@
<script lang="ts">
export let page: number = 1;
export let limit: number = 20;
export let items: number = 0;
export let position: 'left' | 'center' | 'right' = 'center';
import type { Readable } from 'svelte/store';
import { get } from 'svelte/store';
const pagesCount = Math.ceil(items / limit);
export let page: number = 1;
export let limit: number = 20;
export let items: number | Readable<number> = 0;
export let position: 'left' | 'center' | 'right' = 'center';
function handlePageChange() {
window.location.search = `?page=${page}&limit=${limit}`;
let itemsCount: number;
$: {
// NOTE: We need to subscribe to the changes so it stays reactive
itemsCount = typeof items === 'number' ? items : get(items);
if (typeof items === 'object' && 'subscribe' in items) {
items.subscribe((value) => {
itemsCount = value;
});
}
}
$: pagesCount = Math.ceil(itemsCount / limit);
function handlePageChange() {
window.location.search = `?page=${page}&limit=${limit}`;
}
function getMarginPosition() {
switch (position) {
case 'left':
return 'mr-auto';
case 'center':
return 'mx-auto';
case 'right':
return 'ml-auto';
default:
return 'mx-auto';
}
function getMarginPosition() {
switch (position) {
case 'left':
return 'mr-auto';
case 'center':
return 'mx-auto';
case 'right':
return 'ml-auto';
default:
return 'mx-auto';
}
}
const limitOptions = [10, 20, 50, 100];
const limitOptions = [10, 20, 50, 100];
</script>

<div class={`flex gap-2 mt-8 ${getMarginPosition()}`}>
<div class={`mt-8 flex gap-2 ${getMarginPosition()}`}>
<div class="tooltip" data-tip="Select page">
<div class="join">
{#if pagesCount > 0}
{#each Array(pagesCount) as _, i}
<button
title={`Go to page ${i + 1}`}
class={`join-item btn btn-md ${page === i + 1 ? 'btn-active' : ''}`}
class={`btn join-item btn-md ${page === i + 1 ? 'btn-active' : ''}`}
on:click={() => {
page = i + 1;
handlePageChange();
}}>{i + 1}</button
>
}}>{i + 1}</button>
{/each}
{/if}
</div>
Expand All @@ -47,10 +61,11 @@
<select
class="select select-bordered w-full max-w-xs"
on:change={(event) => {
limit = parseInt(event.target?.value);
handlePageChange();
}}
>
if (event.target instanceof HTMLSelectElement) {
limit = parseInt(event.target?.value);
handlePageChange();
}
}}>
{#each limitOptions as option}
<option value={option} selected={option === limit}>{option}</option>
{/each}
Expand Down
28 changes: 28 additions & 0 deletions src/lib/stores/import-bookmarks.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { derived, writable } from 'svelte/store';

import type { BulkListItem } from '$lib/types/common/BulkList.type';

const store = writable<BulkListItem[]>([]);
const { subscribe, set, update } = store;

export const importBookmarkStore = {
subscribe,
set,
update,
addItem: (item: BulkListItem) => update((items) => [...items, item]),
removeItem: (itemId: number) => update((items) => items.filter((item) => item.id !== itemId)),
selectItem: (itemId: number) =>
update((items) => items.map((item) => ({ ...item, selected: item.id === itemId }))),
isAnySelected: derived(store, (items) => items.some((item) => item.selected)),
toggleSelectionForItem: (itemId: number) =>
update((items) =>
items.map((item) => ({
...item,
selected: item.id === itemId ? !item.selected : item.selected
}))
),
setSelectStatusForAll: (selected: boolean) =>
update((items) => items.map((item) => ({ ...item, selected }))),
removeSelected: () => update((items) => items.filter((item) => !item.selected)),
length: derived(store, (items) => items.length)
};

0 comments on commit b1cc513

Please sign in to comment.