Skip to content
This repository has been archived by the owner on Nov 16, 2024. It is now read-only.

Commit

Permalink
feat: added wizard tower
Browse files Browse the repository at this point in the history
  • Loading branch information
recoskyler committed Jan 11, 2024
1 parent 4864c43 commit 39f9a70
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib/stores/currentPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const CHATTER_PAGE = {
CHATS: "CHATS",
ACCOUNTS: "ACCOUNTS",
PROFILE: "PROFILE",
TOWER: "TOWER",
} as const;

type ObjectValues<T> = T[keyof T];
Expand Down
30 changes: 30 additions & 0 deletions src/routes/tower/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

import { db } from "$lib/server/drizzle";
import { error, redirect } from "@sveltejs/kit";
import type { LayoutServerLoad } from "./$types";
import { EMAIL_VERIFICATION } from "$lib/constants";
import { eq } from "drizzle-orm";
import { user } from "$lib/db/schema";

export const load: LayoutServerLoad = async ({ locals }) => {
const session = await locals.auth.validate();

if (!session || (EMAIL_VERIFICATION && !session.user.verified)) {
throw redirect(302, "/login");
}

const dbUser = await db.query.user.findFirst({
with: {
accounts: true,
chats: true,
config: { with: { defaultAccount: true } },
},
where: eq(user.id, session.user.userId),
});

if (!dbUser) throw error(404, "User not found");

if (!dbUser.config) throw redirect(302, "/app/setup");

return { user: dbUser };
};
52 changes: 52 additions & 0 deletions src/routes/tower/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { error, redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
import { db } from "$lib/server/drizzle";
import {
account, chat, user,
} from "$lib/db/schema";
import { eq, sql } from "drizzle-orm";
import { EMAIL_VERIFICATION } from "$lib/constants";

export const load: PageServerLoad = async ({ locals }) => {
const session = await locals.auth.validate();

if (!session || (EMAIL_VERIFICATION && !session.user.verified)) {
throw redirect(302, "/login");
}

const dbUser = await db.query.user.findFirst({
with: {
chats: true,
accounts: true,
config: { with: { defaultAccount: true } },
},
where: eq(user.id, session.user.userId),
});

if (!dbUser) throw error(404, "User not found");

if (dbUser.config === null) throw redirect(302, "/app/setup");

if (dbUser.config.userRole !== "admin") {
throw redirect(302, "/app");
}

const userCount = await db.select({ count: sql<number>`cast(count(${user.id}) as int)` })
.from(user).execute();

const chatsCount = await db.select({ count: sql<number>`cast(count(${chat.id}) as int)` })
.from(chat).execute();

const accountsCount = await db.select({ count: sql<number>`cast(count(${account.id}) as int)` })
.from(account).execute();

return {
user: dbUser,
stats: {
userCount: userCount[0].count,
chatsCount: chatsCount[0].count,
accountsCount: accountsCount[0].count,
},
};
};

178 changes: 178 additions & 0 deletions src/routes/tower/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<script lang="ts">
import {
Accordion,
AccordionItem,
LightSwitch,
} from "@skeletonlabs/skeleton";
import type { PageData } from "./$types";
import Minidenticon from "components/Minidenticon.svelte";
import { pageTitle } from "$lib/stores/pageTitle";
import Fa from "svelte-fa";
import {
faEnvelope,
faIdBadge,
faKey,
faTrash,
} from "@fortawesome/free-solid-svg-icons";
import { canGoBack } from "$lib/stores/canGoBack";
import { CHATTER_PAGE, currentPage } from "$lib/stores/currentPage";
import AnalyticsAccordion from "components/AnalyticsAccordion.svelte";
export let data: PageData;
$pageTitle = "Wizard Tower";
$currentPage = CHATTER_PAGE.TOWER;
$canGoBack = "/app";
</script>

<svelte:head>
<meta name="robots" content="noindex" />
<title>Chatter | Wizard Tower</title>
</svelte:head>

<main
class=" h-full flex flex-col mx-auto my-auto p-5 max-w-md auto-cols-min"
id="profile-cont"
>
<div class="flex flex-row gap-5">
<div class="flex justify-center items-center">
<Minidenticon email={data.user.email} size={4} />
</div>

<div class="flex flex-col items-start gap-2">
<h4 class="h4"><strong>{data.user.name}</strong></h4>
<p>{data.user.email}</p>
</div>
</div>

<form method="post" action="?/signOut" class="w-full mt-5">
<input
type="submit"
value="Sign out"
class="btn variant-filled-primary mt-5 w-full"
/>
</form>

<Accordion class="mt-10">
<AccordionItem>
<svelte:fragment slot="lead">
<Fa fw icon={faIdBadge} />
</svelte:fragment>

<svelte:fragment slot="summary">
Statistics
</svelte:fragment>

<svelte:fragment slot="content">
<div class="flex flex-row align-middle justify-between">
<p><strong>Users</strong></p>
<p class="text-end">{data.stats.userCount}</p>
</div>

<div class="flex flex-row align-middle justify-between">
<p><strong>Chats</strong></p>
<p class="text-end">{data.stats.chatsCount}</p>
</div>

<div class="flex flex-row align-middle justify-between">
<p><strong>Accounts</strong></p>
<p class="text-end">{data.stats.accountsCount}</p>
</div>
</svelte:fragment>
</AccordionItem>

<!-- <AccordionItem>
<svelte:fragment slot="lead">
<Fa fw icon={faEnvelope} />
</svelte:fragment>
<svelte:fragment slot="summary">Change email</svelte:fragment>
<svelte:fragment slot="content">
</svelte:fragment>
</AccordionItem>
<AccordionItem>
<svelte:fragment slot="lead">
<Fa fw icon={faKey} />
</svelte:fragment>
<svelte:fragment slot="summary">Change password</svelte:fragment>
<svelte:fragment slot="content">
</svelte:fragment>
</AccordionItem>
<AccordionItem>
<svelte:fragment slot="lead">
<Fa fw icon={faTrash} class="text-red-600 dark:text-red-400" />
</svelte:fragment>
<svelte:fragment slot="summary">
<span class="text-red-600 dark:text-red-400">Delete account</span>
</svelte:fragment>
<svelte:fragment slot="content">
</svelte:fragment>
</AccordionItem> -->
</Accordion>

<div class="w-full flex items-center justify-center md:hidden mt-5">
<LightSwitch bgDark="bg-surface-400" />
</div>

<!-- eslint-disable max-len -->
<div
class="flex flex-row flex-wrap items-center justify-center gap-x-3 gap-y-2 mt-10 py-2 px-5 bg-surface-200 dark:bg-surface-200 rounded-lg"
>
<!-- eslint-enable max-len -->
<a
href="/privacy"
target="_blank"
rel="noopener noreferrer"
class="anchor text-center"
>
Privacy Policy
</a>

<a
href="/disclaimer"
target="_blank"
rel="noopener noreferrer"
class="anchor text-center"
>
Disclaimer
</a>

<a
href="/cookie"
target="_blank"
rel="noopener noreferrer"
class="anchor text-center"
>
Cookie Policy
</a>

<a
href="https://github.com/recoskyler/chatter/blob/main/LICENSE"
target="_blank"
rel="noopener noreferrer"
class="anchor text-center"
>
License
</a>

<a
href="https://github.com/recoskyler/chatter"
target="_blank"
rel="noopener noreferrer"
class="anchor text-center"
data-umami-event="View source code anchor"
>
Source Code
</a>
</div>
</main>

0 comments on commit 39f9a70

Please sign in to comment.