diff options
| author | Fuwn <[email protected]> | 2024-01-02 21:47:28 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-01-02 21:47:28 -0800 |
| commit | c0e4dc886eaba03485ea4aaac37eaffb311aeb74 (patch) | |
| tree | 70cbc8aa9fd46ee0eb3216e52e8c797e035cc747 | |
| parent | fix(badges): datetime update (diff) | |
| download | due.moe-c0e4dc886eaba03485ea4aaac37eaffb311aeb74.tar.xz due.moe-c0e4dc886eaba03485ea4aaac37eaffb311aeb74.zip | |
feat(badges): categories
| -rw-r--r-- | src/lib/Database/badges.ts | 25 | ||||
| -rw-r--r-- | src/routes/api/badges/+server.ts | 31 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.svelte | 102 |
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%; |