aboutsummaryrefslogtreecommitdiff
path: root/src/routes/user
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-02-17 21:50:17 -0800
committerFuwn <[email protected]>2024-02-17 21:50:17 -0800
commit4f07a27df74775e35775d34e800abfd683c5fa86 (patch)
tree2a7fb42fd15f1193c3c14a6535691730fe428565 /src/routes/user
parentfix(preferences): return preferences (diff)
downloaddue.moe-4f07a27df74775e35775d34e800abfd683c5fa86.tar.xz
due.moe-4f07a27df74775e35775d34e800abfd683c5fa86.zip
feat(badges): optionally hide missing badges
Diffstat (limited to 'src/routes/user')
-rw-r--r--src/routes/user/[user]/+page.svelte24
-rw-r--r--src/routes/user/[user]/badges/+page.svelte454
2 files changed, 256 insertions, 222 deletions
diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte
index 4103b7de..c93647f4 100644
--- a/src/routes/user/[user]/+page.svelte
+++ b/src/routes/user/[user]/+page.svelte
@@ -10,6 +10,7 @@
import authorisedUsers from '$lib/Data/Static/authorised.json';
import tooltip from '$lib/Tooltip/tooltip.js';
import AnimeRateLimited from '$lib/Error/AnimeRateLimited.svelte';
+ import identity from '$stores/identity';
export let data;
@@ -120,6 +121,29 @@
</div>
{/if}
</div>
+
+ {#if userData && userData.id === $identity.id}
+ {#await fetch(root(`/api/preferences?id=${userData.id}`)) then rawPreferences}
+ {#await rawPreferences.json() then preferences}
+ <p />
+
+ <details open>
+ <summary>User Preferences</summary>
+
+ <input
+ type="checkbox"
+ on:change={() => {
+ if (userData)
+ fetch(root(`/api/preferences?id=${userData.id}&toggleHideMissingBadges`), {
+ method: 'PUT'
+ });
+ }}
+ checked={preferences.hide_missing_badges}
+ /> Hide missing badges from Badge Wall
+ </details>
+ {/await}
+ {/await}
+ {/if}
{/if}
<style>
diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte
index bf575161..9b74abd8 100644
--- a/src/routes/user/[user]/badges/+page.svelte
+++ b/src/routes/user/[user]/badges/+page.svelte
@@ -19,6 +19,7 @@
import SettingHint from '$lib/Settings/SettingHint.svelte';
import Popup from '$lib/Popup.svelte';
import FallbackImage from '$lib/FallbackImage.svelte';
+ import FallbackBadge from '$lib/FallbackBadge.svelte';
// import { io } from 'socket.io-client';
export let data;
@@ -401,250 +402,259 @@
<Skeleton grid={true} count={100} width="150px" height="170px" />
{:then ungroupedBadges}
- <div id="badges">
- {#await awcPromise then badges}
- {#await badges.text() then text}
- {@const parsedBadges = awcBadgesGrouped(text)}
+ {#await fetch(root(`/api/preferences?id=${identity.id}`))}
+ <Message message="Loading user preferences ..." />
+
+ <Skeleton grid={true} count={100} width="150px" height="170px" />
+ {:then rawPreferences}
+ {#await rawPreferences.json()}
+ <Message message="Parsing user preferences ..." />
+
+ <Skeleton grid={true} count={100} width="150px" height="170px" />
+ {:then preferences}
+ <div id="badges">
+ {#await awcPromise then badges}
+ {#await badges.text() then text}
+ {@const parsedBadges = awcBadgesGrouped(text)}
+
+ {#if parsedBadges.length > 0}
+ {#each parsedBadges as group}
+ <details open>
+ <summary>
+ Anime Watching Club <span class="opaque">|</span>
+ {group.group}
+ </summary>
+
+ <p />
+
+ <div class="badges">
+ {#each group.badges as badge}
+ <a
+ href={badge.link}
+ target="_blank"
+ class="badge"
+ id={`badge-${badge.link}`}
+ title={badge.description}
+ use:tooltip
+ >
+ <FallbackImage
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ />
+ </a>
+ {/each}
+ </div>
+ </details>
+
+ <p />
+ {/each}
+ {/if}
+ {/await}
+ {/await}
- {#if parsedBadges.length > 0}
- {#each parsedBadges as group}
- <details open>
- <summary>
- Anime Watching Club <span class="opaque">|</span>
- {group.group}
- </summary>
+ {#if ungroupedBadges === null}
+ <Message message="Loading badges ..." />
- <p />
+ <Skeleton grid={true} count={10} width="150px" height="170px" />
+ {:else}
+ {@const groupedBadges = Object.entries(groupBadges(ungroupedBadges))}
- <div class="badges">
- {#each group.badges as badge}
- <a
- href={badge.link}
- target="_blank"
- class="badge"
- id={`badge-${badge.link}`}
- title={badge.description}
- use:tooltip
- >
- <FallbackImage
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
- />
- </a>
- {/each}
- </div>
- </details>
+ {#if isOwner}
+ <div class="card">
+ <a href={root(`/user/${data.username}`)}
+ >{$locale().user.badges.backToProfile}</a
+ >
+ <span style="margin: 0 0.625rem;">•</span>
+ <button
+ on:click={() => {
+ if (editMode) selectedBadge = undefined;
- <p />
- {/each}
- {/if}
- {/await}
- {/await}
+ editMode = !editMode;
+ }}
+ >
+ {editMode
+ ? $locale().user.badges.editMode.disable
+ : $locale().user.badges.editMode.enable}
+ </button>
+ <span style="margin: 0 0.625rem;">•</span>
+ <button
+ on:click={() => {
+ if (importMode) selectedBadge = undefined;
- {#if ungroupedBadges === null}
- <Message message="Loading badges ..." />
-
- <Skeleton grid={true} count={10} width="150px" height="170px" />
- {:else}
- {@const groupedBadges = Object.entries(groupBadges(ungroupedBadges))}
-
- {#if isOwner}
- <div class="card">
- <a href={root(`/user/${data.username}`)}>{$locale().user.badges.backToProfile}</a>
- <span style="margin: 0 0.625rem;">•</span>
- <button
- on:click={() => {
- if (editMode) selectedBadge = undefined;
-
- editMode = !editMode;
- }}
- >
- {editMode
- ? $locale().user.badges.editMode.disable
- : $locale().user.badges.editMode.enable}
- </button>
- <span style="margin: 0 0.625rem;">•</span>
- <button
- on:click={() => {
- if (importMode) selectedBadge = undefined;
-
- importMode = !importMode;
- }}
- >
- {importMode
- ? $locale().user.badges.importMode.disable
- : $locale().user.badges.importMode.enable}
- </button>
-
- {#if editMode && isOwner}
- {@const groups = groupedBadges
- .map((group) => group[0])
- .filter((group) => group !== 'Uncategorised')}
-
- <p />
-
- {#if error}
- <p style="color: red;">{error}</p>
- {/if}
+ importMode = !importMode;
+ }}
+ >
+ {importMode
+ ? $locale().user.badges.importMode.disable
+ : $locale().user.badges.importMode.enable}
+ </button>
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.imageURL}
- name="image_url"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge ? selectedBadge.image : ''}
- />
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.activityURL}
- name="activity_url"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge
- ? selectedBadge.post === '#'
- ? ''
- : selectedBadge.post
- : ''}
- />
- <input
- type="text"
- placeholder={$locale().user.badges.editMode.description}
- name="description"
- minlength="1"
- maxlength="1000"
- size="15"
- value={selectedBadge ? selectedBadge.description : ''}
- />
- <Dropdown
- items={groups.map((group) => ({
- name: group,
- url: '#',
- onClick: () => {
- const category = document.querySelector('input[name="category"]');
-
- if (category instanceof HTMLInputElement) category.value = group;
- }
- }))}
- header={false}
- center={false}
- >
- <span slot="title">
+ {#if editMode && isOwner}
+ {@const groups = groupedBadges
+ .map((group) => group[0])
+ .filter((group) => group !== 'Uncategorised')}
+
+ <p />
+
+ {#if error}
+ <p style="color: red;">{error}</p>
+ {/if}
+
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.imageURL}
+ name="image_url"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge ? selectedBadge.image : ''}
+ />
<input
type="text"
- placeholder={$locale().user.badges.editMode.category}
- name="category"
+ placeholder={$locale().user.badges.editMode.activityURL}
+ name="activity_url"
minlength="1"
maxlength="1000"
size="15"
value={selectedBadge
- ? selectedBadge.category === 'Uncategorised'
+ ? selectedBadge.post === '#'
? ''
- : selectedBadge.category
+ : selectedBadge.post
: ''}
- list="categories"
/>
- </span>
- </Dropdown>
- <button class="button-lined" on:click={submitBadge}
- >{selectedBadge
- ? $locale().user.badges.editMode.update
- : $locale().user.badges.editMode.add}</button
- >
- {#if selectedBadge}
- {$locale().user.badges.editMode.or}
- <button
- class="button-lined"
- on:click={() => {
- if (selectedBadge) removeBadge(selectedBadge);
- }}>{$locale().user.badges.editMode.delete}</button
- >
- {/if}
- <span style="float: right;">
- <input
- type="datetime-local"
- value={selectedBadge && selectedBadge.time
- ? dateToInputTime(databaseTimeToDate(selectedBadge.time))
- : ''}
- />
- <small>Must be full date and time, defaults to now if any fields empty</small>
- </span>
- {/if}
- </div>
- {/if}
-
- <p />
-
- {#if ungroupedBadges.length === 0}
- <div class="card">
- No due.moe registered badges found for this user. <a
- href={'#'}
- on:click={(e) => e.preventDefault()}
- title="This alert does not include AWC badges."
- use:tooltip>?</a
- >
- </div>
- {/if}
-
- {#each groupedBadges as [category, badges]}
- <details open>
- <summary>{category}</summary>
-
- <p />
-
- <div class="badges">
- {#each badges as badge}
- {#if editMode}
- <a
- href={`#`}
- on:click={() => (selectedBadge = badge)}
- id={`badge-${badge.id}`}
- title={`${
- badge.time
- ? $locale().dateFormatter(databaseTimeToDate(badge.time))
- : ''
- }${badge.description ? `\n${badge.description}` : ''}`}
- use:tooltip
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.description}
+ name="description"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge ? selectedBadge.description : ''}
+ />
+ <Dropdown
+ items={groups.map((group) => ({
+ name: group,
+ url: '#',
+ onClick: () => {
+ const category = document.querySelector('input[name="category"]');
+
+ if (category instanceof HTMLInputElement) category.value = group;
+ }
+ }))}
+ header={false}
+ center={false}
>
- <FallbackImage
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
- />
- </a>
- {:else}
- <a
- href={badge.post}
- target="_blank"
- id={`badge-${badge.id}`}
- class="badge"
- title={`${
- badge.time
- ? $locale().dateFormatter(databaseTimeToDate(badge.time))
- : ''
- }${badge.description ? `\n${badge.description}` : ''}`}
- use:tooltip
+ <span slot="title">
+ <input
+ type="text"
+ placeholder={$locale().user.badges.editMode.category}
+ name="category"
+ minlength="1"
+ maxlength="1000"
+ size="15"
+ value={selectedBadge
+ ? selectedBadge.category === 'Uncategorised'
+ ? ''
+ : selectedBadge.category
+ : ''}
+ list="categories"
+ />
+ </span>
+ </Dropdown>
+ <button class="button-lined" on:click={submitBadge}
+ >{selectedBadge
+ ? $locale().user.badges.editMode.update
+ : $locale().user.badges.editMode.add}</button
>
- <FallbackImage
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
+ {#if selectedBadge}
+ {$locale().user.badges.editMode.or}
+ <button
+ class="button-lined"
+ on:click={() => {
+ if (selectedBadge) removeBadge(selectedBadge);
+ }}>{$locale().user.badges.editMode.delete}</button
+ >
+ {/if}
+ <span style="float: right;">
+ <input
+ type="datetime-local"
+ value={selectedBadge && selectedBadge.time
+ ? dateToInputTime(databaseTimeToDate(selectedBadge.time))
+ : ''}
/>
- </a>
+ <small
+ >Must be full date and time, defaults to now if any fields empty</small
+ >
+ </span>
{/if}
- {/each}
- </div>
- </details>
+ </div>
+ {/if}
- {#if groupedBadges[groupedBadges.length - 1][0] !== category}
<p />
+
+ {#if ungroupedBadges.length === 0}
+ <div class="card">
+ No due.moe registered badges found for this user. <a
+ href={'#'}
+ on:click={(e) => e.preventDefault()}
+ title="This alert does not include AWC badges."
+ use:tooltip>?</a
+ >
+ </div>
+ {/if}
+
+ {#each groupedBadges as [category, badges]}
+ <details open>
+ <summary>{category}</summary>
+
+ <p />
+
+ <div class="badges">
+ {#each badges as badge}
+ {#if editMode}
+ <a
+ href={`#`}
+ on:click={() => (selectedBadge = badge)}
+ id={`badge-${badge.id}`}
+ title={`${
+ badge.time
+ ? $locale().dateFormatter(databaseTimeToDate(badge.time))
+ : ''
+ }${badge.description ? `\n${badge.description}` : ''}`}
+ use:tooltip
+ >
+ <FallbackImage
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ />
+ </a>
+ {:else}
+ <FallbackBadge
+ {badge}
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ hideOnError={preferences.hide_missing_badges}
+ />
+ {/if}
+ {/each}
+ </div>
+ </details>
+
+ {#if groupedBadges[groupedBadges.length - 1][0] !== category}
+ <p />
+ {/if}
+ {/each}
{/if}
- {/each}
- {/if}
- </div>
+ </div>
+ {:catch}
+ <Popup fullscreen locked>Could not parse badges</Popup>
+ {/await}
+ {:catch}
+ <Popup fullscreen locked>Could not fetch badges</Popup>
+ {/await}
{:catch}
<Popup fullscreen locked>Could not parse badges</Popup>
{/await}