aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-01-02 21:47:28 -0800
committerFuwn <[email protected]>2024-01-02 21:47:28 -0800
commitc0e4dc886eaba03485ea4aaac37eaffb311aeb74 (patch)
tree70cbc8aa9fd46ee0eb3216e52e8c797e035cc747
parentfix(badges): datetime update (diff)
downloaddue.moe-c0e4dc886eaba03485ea4aaac37eaffb311aeb74.tar.xz
due.moe-c0e4dc886eaba03485ea4aaac37eaffb311aeb74.zip
feat(badges): categories
-rw-r--r--src/lib/Database/badges.ts25
-rw-r--r--src/routes/api/badges/+server.ts31
-rw-r--r--src/routes/user/[user]/badges/+page.svelte102
3 files changed, 96 insertions, 62 deletions
diff --git a/src/lib/Database/badges.ts b/src/lib/Database/badges.ts
index 1f3267e9..9819e10e 100644
--- a/src/lib/Database/badges.ts
+++ b/src/lib/Database/badges.ts
@@ -7,6 +7,7 @@ export interface Badge {
description?: string;
id?: number;
time?: string;
+ category?: string;
}
const database = new Database('./data/due_moe.sqlite3', {
@@ -21,6 +22,7 @@ database
post TEXT(1000) NOT NULL,
image TEXT(1000) NOT NULL,
description TEXT(1000) DEFAULT NULL,
+ category TEXT(1000) DEFAULT NULL,
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`
)
@@ -39,20 +41,22 @@ export const getUserBadges = (userId: number): Badge[] => {
};
export const addUserBadge = (userId: number, badge: Badge) => {
- const { post, image, description, time } = badge;
+ const { post, image, description, time, category } = badge;
if (post === undefined || image === undefined) return;
if (time) {
database
.query(
- `INSERT INTO user_badges (user_id, post, image, description, time) VALUES (?1, ?2, ?3, ?4, ?5);`
+ `INSERT INTO user_badges (user_id, post, image, description, time, category) VALUES (?1, ?2, ?3, ?4, ?5, ?6);`
)
- .run(userId.toString(), post, image, description || null, time);
+ .run(userId.toString(), post, image, description || null, time, category || null);
} else {
database
- .query(`INSERT INTO user_badges (user_id, post, image, description) VALUES (?1, ?2, ?3, ?4);`)
- .run(userId.toString(), post, image, description || null);
+ .query(
+ `INSERT INTO user_badges (user_id, post, image, description, category) VALUES (?1, ?2, ?3, ?4, ?5);`
+ )
+ .run(userId.toString(), post, image, description || null, category || null);
}
};
@@ -70,7 +74,14 @@ export const updateUserBadge = (userId: number, id: number, badge: Badge) => {
database
.query(
- 'UPDATE user_badges SET post = ?1, image = ?2, description = ?3 WHERE id = ?4 AND user_id = ?5'
+ 'UPDATE user_badges SET post = ?1, image = ?2, description = ?3, category = ?6 WHERE id = ?4 AND user_id = ?5'
)
- .run(badge.post || null, badge.image || null, badge.description || null, id, userId);
+ .run(
+ badge.post || null,
+ badge.image || null,
+ badge.description || null,
+ id,
+ userId,
+ badge.category || null
+ );
};
diff --git a/src/routes/api/badges/+server.ts b/src/routes/api/badges/+server.ts
index fc5a4d0a..63e6ace4 100644
--- a/src/routes/api/badges/+server.ts
+++ b/src/routes/api/badges/+server.ts
@@ -49,41 +49,18 @@ export const PUT = async ({ cookies, url }) => {
post: url.searchParams.get('post') || undefined,
image: url.searchParams.get('image') || undefined,
description: url.searchParams.get('description') || undefined,
- time: url.searchParams.get('time') || undefined
+ time: url.searchParams.get('time') || undefined,
+ category: url.searchParams.get('category') || undefined
});
} else {
addUserBadge(identity.id, {
post: url.searchParams.get('post') || undefined,
image: url.searchParams.get('image') || undefined,
description: url.searchParams.get('description') || undefined,
- time: url.searchParams.get('time') || undefined
+ time: url.searchParams.get('time') || undefined,
+ category: url.searchParams.get('category') || undefined
});
}
return Response.json({});
};
-
-export const PATCH = async ({ cookies, url }) => {
- const userCookie = cookies.get('user');
-
- if (!userCookie) {
- return new Response('Unauthenticated', { status: 401 });
- }
-
- const user = JSON.parse(userCookie);
- const identity = await userIdentity({
- tokenType: user['token_type'],
- expiresIn: user['expires_in'],
- accessToken: user['access_token'],
- refreshToken: user['refresh_token']
- });
-
- updateUserBadge(identity.id, Number(url.searchParams.get('id')), {
- post: url.searchParams.get('post') || undefined,
- image: url.searchParams.get('image') || undefined,
- description: url.searchParams.get('description') || undefined,
- time: url.searchParams.get('time') || undefined
- });
-
- return Response.json({});
-};
diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte
index 20d4775a..69965e83 100644
--- a/src/routes/user/[user]/badges/+page.svelte
+++ b/src/routes/user/[user]/badges/+page.svelte
@@ -21,6 +21,8 @@
let confirmDelete = 0;
let selectedBadge: Badge | undefined = undefined;
+ type GroupedBadges = { [key: string]: Badge[] };
+
onMount(async () => {
// socket.on('badges', (message) => (badges = message));
@@ -45,6 +47,7 @@
const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement;
const description = document.querySelector('input[name="description"]') as HTMLInputElement;
const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement;
+ const category = document.querySelector('input[name="category"]') as HTMLInputElement;
if (!imageURL.value) {
error = 'Image URL cannot be empty.';
@@ -66,7 +69,7 @@
activityURL.value || '#'
)}${
description.value.length > 0 ? `&description=${encodeURIComponent(description.value)}` : ''
- }${
+ }${category.value.length > 0 ? `&category=${encodeURIComponent(category.value)}` : ''}${
time.valueAsDate ? `&time=${encodeURIComponent(dateToDatabaseTime(time.valueAsDate))}` : ''
}${
selectedBadge && selectedBadge.id ? `&update=${encodeURIComponent(selectedBadge.id)}` : ''
@@ -163,6 +166,26 @@
element.classList.remove('invert');
}
};
+
+ const groupBadges = (badges: Badge[]) => {
+ const groupedBadges: GroupedBadges = {};
+
+ badges.forEach((badge) => {
+ if (!badge.category) badge.category = 'Uncategorized';
+
+ if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];
+
+ groupedBadges[badge.category].push(badge);
+ });
+
+ return Object.entries(groupedBadges)
+ .sort((a, b) => b[1].length - a[1].length)
+ .reduce((set: GroupedBadges, [key, value]) => {
+ set[key] = value;
+
+ return set;
+ }, {});
+ };
</script>
<HeadTitle route={`${data.username}'s Badge Wall`} path={`/user/${data.username}`} />
@@ -227,6 +250,15 @@
size="11"
value={selectedBadge ? selectedBadge.description : ''}
/>
+ <input
+ type="text"
+ placeholder="Category (Optional)"
+ name="category"
+ minlength="1"
+ maxlength="1000"
+ size="11"
+ value={selectedBadge ? selectedBadge.category : ''}
+ />
<a href={`#`} on:click={submitBadge}>{selectedBadge ? 'Update' : 'Add'} Badge</a>
{#if selectedBadge}
or
@@ -253,36 +285,50 @@
{#if badgesResponse}
{#await badgesResponse.json()}
Loading badges ... 80%
- {:then badges}
+ {:then ungroupedBadges}
<div id="badges">
- {#if badges === null}
+ {#if ungroupedBadges === null}
{@html nbsp('Loading badges ... 50%')}
- {:else if badges.length === 0}
+ {:else if ungroupedBadges.length === 0}
{@html nbsp('No badges found for this user.')}
{:else}
- {#each badges as badge}
- {#if editMode}
- <a
- href={`#`}
- on:click={() => (selectedBadge = badge)}
- id={`badge-${badge.id}`}
- title={`${databaseTimeToDate(badge.time).toLocaleString()}${
- badge.description ? `\n${badge.description}` : ''
- }`}
- >
- <img src={badge.image} alt={badge.description} />
- </a>
- {:else}
- <a
- href={badge.post}
- target="_blank"
- id={`badge-${badge.id}`}
- title={`${databaseTimeToDate(badge.time).toLocaleString()}${
- badge.description ? `\n${badge.description}` : ''
- }`}
- >
- <img src={badge.image} alt={badge.description} />
- </a>
+ {@const groupedBadges = Object.entries(groupBadges(ungroupedBadges))}
+
+ {#each groupedBadges as [category, badges]}
+ <details open>
+ <summary>{category}</summary>
+
+ <div class="badges">
+ {#each badges as badge}
+ {#if editMode}
+ <a
+ href={`#`}
+ on:click={() => (selectedBadge = badge)}
+ id={`badge-${badge.id}`}
+ title={`${
+ badge.time ? databaseTimeToDate(badge.time).toLocaleString() : ''
+ }${badge.description ? `\n${badge.description}` : ''}`}
+ >
+ <img src={badge.image} alt={badge.description} />
+ </a>
+ {:else}
+ <a
+ href={badge.post}
+ target="_blank"
+ id={`badge-${badge.id}`}
+ title={`${
+ badge.time ? databaseTimeToDate(badge.time).toLocaleString() : ''
+ }${badge.description ? `\n${badge.description}` : ''}`}
+ >
+ <img src={badge.image} alt={badge.description} />
+ </a>
+ {/if}
+ {/each}
+ </div>
+ </details>
+
+ {#if groupedBadges[groupedBadges.length - 1][0] !== category}
+ <p />
{/if}
{/each}
{/if}
@@ -311,7 +357,7 @@
height: auto;
}
- #badges {
+ .badges {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(8%, 1fr));
grid-gap: 0.25%;