diff --git a/frontend/src/lib/api/entities.ts b/frontend/src/lib/api/entities.ts
index 399e7a4..875cb10 100644
--- a/frontend/src/lib/api/entities.ts
+++ b/frontend/src/lib/api/entities.ts
@@ -1,5 +1,8 @@
import { PUBLIC_BASE_URL } from "$env/static/public";
+export const MAX_MEMBERS = 500;
+export const MAX_DESCRIPTION_LENGTH = 1000;
+
export interface User {
id: string;
name: string;
@@ -15,6 +18,7 @@ export interface User {
}
export interface MeUser extends User {
+ max_invites: number;
discord: string | null;
discord_username: string | null;
}
@@ -68,6 +72,12 @@ export interface MemberPartialUser {
avatar: string | null;
}
+export interface Invite {
+ code: string;
+ created: Date;
+ used: boolean;
+}
+
export interface APIError {
code: ErrorCode;
message?: string;
diff --git a/frontend/src/routes/edit/profile/+page.svelte b/frontend/src/routes/edit/profile/+page.svelte
index 28f85f6..2ffb937 100644
--- a/frontend/src/routes/edit/profile/+page.svelte
+++ b/frontend/src/routes/edit/profile/+page.svelte
@@ -1,6 +1,7 @@
-
-{#if plain}
-
-{:else}
-
-
-
-{/if}
diff --git a/frontend/src/routes/settings/+layout.svelte b/frontend/src/routes/settings/+layout.svelte
new file mode 100644
index 0000000..6dcd3cf
--- /dev/null
+++ b/frontend/src/routes/settings/+layout.svelte
@@ -0,0 +1,20 @@
+
+
+
+
+
+
Settings
+
+
+ Your profile
+ Invites
+ API tokens
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/settings/+layout.ts b/frontend/src/routes/settings/+layout.ts
new file mode 100644
index 0000000..a3d1578
--- /dev/null
+++ b/frontend/src/routes/settings/+layout.ts
@@ -0,0 +1 @@
+export const ssr = false;
diff --git a/frontend/src/routes/settings/+page.svelte b/frontend/src/routes/settings/+page.svelte
new file mode 100644
index 0000000..ec9f29e
--- /dev/null
+++ b/frontend/src/routes/settings/+page.svelte
@@ -0,0 +1,159 @@
+
+
+
+ Settings - pronouns.cc
+
+
+Your profile
+
+
+
+
+
Username
+
+
+ changeUsername()}
+ disabled={username === data.user.name}>Change username
+
+ {#if username !== data.user.name}
+
+ Changing your username will make any existing links to your
+ or your members' profiles invalid.
+
+ {/if}
+ {#if error}
+
+ An error occurred
+ {error.code} : {error.message}
+
+ {/if}
+
+
+
+
+
+
Account info
+
+
+
+ ID
+ {data.user.id}
+
+
+ Members
+ {data.members.length}/{MAX_MEMBERS}
+
+ {#if data.invitesEnabled}
+
+ Invites
+ {data.invites.length}/{data.user.max_invites}
+
+ {/if}
+
+
+
+
+
+
+
Delete account
+
If you want to initiate the account deletion process, click the button below:
+
+ Delete account
+
+
+ Your account will be deleted 30 days after initiating the deletion
+ process. If you want to cancel your account deletion within 30 days, log in again and confirm
+ that you want to cancel deletion.
+ Simply logging in again will not cancel account deletion. Also, your account cannot be
+ recovered after the deletion period has passed.
+
+
+ Delete account
+
+ If you want to delete your account, type your current username below:
+
+
+
+ {#if deleteError}
+
+ An error occurred
+ {deleteError.code} : {deleteError.message}
+
+ {/if}
+
+
+
+ Delete account
+
+ Cancel
+
+
+
+
+
diff --git a/frontend/src/routes/settings/+page.ts b/frontend/src/routes/settings/+page.ts
new file mode 100644
index 0000000..dbe5eb7
--- /dev/null
+++ b/frontend/src/routes/settings/+page.ts
@@ -0,0 +1,30 @@
+import {
+ type Invite,
+ type APIError,
+ type MeUser,
+ type PartialMember,
+ ErrorCode,
+} from "$lib/api/entities";
+import { apiFetchClient } from "$lib/api/fetch";
+import { error } from "@sveltejs/kit";
+
+export const load = async () => {
+ try {
+ const user = await apiFetchClient("/users/@me");
+ const members = await apiFetchClient("/users/@me/members");
+
+ let invites: Invite[] = [];
+ let invitesEnabled = true;
+ try {
+ invites = await apiFetchClient("/auth/invites");
+ } catch (e) {
+ if ((e as APIError).code === ErrorCode.InvitesDisabled) {
+ invitesEnabled = false;
+ }
+ }
+
+ return { user, members, invites, invitesEnabled };
+ } catch (e) {
+ throw error(500, (e as APIError).message);
+ }
+};