feat(frontend): start settings

This commit is contained in:
sam 2024-11-24 17:36:02 +01:00
parent 0c78cd25b0
commit c179669799
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
13 changed files with 301 additions and 17 deletions

View file

@ -52,3 +52,15 @@ export type ValidationError = {
allowed_values?: any[];
actual_value?: any;
};
/**
* Returns the first error for the value `key` in `error`.
* @param error The error object to traverse.
* @param key The JSON key to find.
*/
export const firstErrorFor = (error: RawApiError, key: string): ValidationError | undefined => {
if (!error.errors) return undefined;
const field = error.errors.find((e) => e.key == key);
if (!field?.errors) return undefined;
return field.errors.length != 0 ? field.errors[0] : undefined;
};

View file

@ -1,14 +1,14 @@
<script lang="ts">
import { DEFAULT_AVATAR } from "$lib";
type Props = { url: string | null; alt: string; lazyLoad?: boolean };
let { url, alt, lazyLoad }: Props = $props();
type Props = { url: string | null; alt: string; lazyLoad?: boolean; width?: number };
let { url, alt, lazyLoad, width }: Props = $props();
</script>
<img
class="rounded-circle img-fluid"
src={url || DEFAULT_AVATAR}
{alt}
width={200}
width={width || 200}
loading={lazyLoad ? "lazy" : "eager"}
/>

View file

@ -4,17 +4,19 @@
import { t } from "$lib/i18n";
import KeyedValidationErrors from "./errors/KeyedValidationErrors.svelte";
type Props = { headerElem?: string; error: RawApiError };
let { headerElem, error }: Props = $props();
type Props = { showHeader?: boolean; headerElem?: string; error: RawApiError };
let { showHeader, headerElem, error }: Props = $props();
</script>
<svelte:element this={headerElem ?? "h4"}>
{#if error.code === ErrorCode.BadRequest}
{$t("error.bad-request-header")}
{:else}
{$t("error.generic-header")}
{/if}
</svelte:element>
{#if showHeader !== false}
<svelte:element this={headerElem ?? "h4"}>
{#if error.code === ErrorCode.BadRequest}
{$t("error.bad-request-header")}
{:else}
{$t("error.generic-header")}
{/if}
</svelte:element>
{/if}
<p>{errorDescription($t, error.code)}</p>
{#if error.errors}
<details>

View file

@ -16,7 +16,8 @@
},
"title": {
"log-in": "Log in",
"welcome": "Welcome"
"welcome": "Welcome",
"settings": "Settings"
},
"auth": {
"log-in-form-title": "Log in with email",
@ -59,5 +60,32 @@
"validation-reason": "Reason",
"validation-generic": "The value you entered is not allowed here. Reason",
"extra-info-header": "Extra error information"
}
},
"settings": {
"general-information-tab": "General information",
"your-profile-tab": "Your profile",
"members-tab": "Members",
"authentication-tab": "Authentication",
"export-tab": "Export your data",
"change-username-button": "Change username",
"username-change-hint": "Changing your username will make any existing links to your or your members' profiles invalid.\nYour username must be unique, be at most 40 characters long, and only contain letters from the basic English alphabet, dashes, underscores, and periods. Your username is used as part of your profile link, you can set a separate display name.",
"username-update-error": "Could not update your username as the new username is invalid:\n{{message}}",
"change-avatar-link": "Change your avatar here",
"new-username": "New username",
"table-role": "Role",
"table-custom-preferences": "Custom preferences",
"table-member-list-hidden": "Member list hidden?",
"table-member-count": "Member count",
"table-created-at": "Account created at",
"table-id": "Your ID",
"table-title": "Account information",
"force-log-out-title": "Log out everywhere",
"force-log-out-button": "Force log out",
"force-log-out-hint": "If you think one of your tokens might have been compromised, you can log out on all devices by clicking this button.",
"log-out-title": "Log out",
"log-out-hint": "Use this button to log out on this device only.",
"log-out-button": "Log out"
},
"yes": "Yes",
"no": "No"
}

View file

@ -1,6 +1,7 @@
// place files you want to import through the `$lib` alias in this folder.
import type { Cookies } from "@sveltejs/kit";
import { DateTime } from "luxon";
export const TOKEN_COOKIE_NAME = "__Host-pronounscc-token";
@ -10,3 +11,6 @@ export const clearToken = (cookies: Cookies) => cookies.delete(TOKEN_COOKIE_NAME
// TODO: change this to something we actually clearly have the rights to use
export const DEFAULT_AVATAR = "https://pronouns.cc/default/512.webp";
export const idTimestamp = (id: string) =>
DateTime.fromMillis(parseInt(id, 10) / (1 << 22) + 1_640_995_200_000);