download link and analytics link for admin
This commit is contained in:
@@ -17,8 +17,46 @@ import { ActivityHeatmap } from "./ActivityHeatmap";
|
|||||||
import { DarkModeToggle } from "./DarkModeToggle";
|
import { DarkModeToggle } from "./DarkModeToggle";
|
||||||
import { SkeletonBox, SkeletonText } from "./SkeletonLoader";
|
import { SkeletonBox, SkeletonText } from "./SkeletonLoader";
|
||||||
import { env } from "~/env/client";
|
import { env } from "~/env/client";
|
||||||
import { A, useNavigate, useLocation } from "@solidjs/router";
|
import {
|
||||||
|
A,
|
||||||
|
useNavigate,
|
||||||
|
useLocation,
|
||||||
|
query,
|
||||||
|
createAsync
|
||||||
|
} from "@solidjs/router";
|
||||||
import { BREAKPOINTS } from "~/config";
|
import { BREAKPOINTS } from "~/config";
|
||||||
|
import { getRequestEvent } from "solid-js/web";
|
||||||
|
|
||||||
|
const getUserState = query(async () => {
|
||||||
|
"use server";
|
||||||
|
const { getPrivilegeLevel, getUserID } = await import("~/server/utils");
|
||||||
|
const { ConnectionFactory } = await import("~/server/utils");
|
||||||
|
const event = getRequestEvent()!;
|
||||||
|
const privilegeLevel = await getPrivilegeLevel(event.nativeEvent);
|
||||||
|
const userId = await getUserID(event.nativeEvent);
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return {
|
||||||
|
isAuthenticated: false,
|
||||||
|
email: null,
|
||||||
|
privilegeLevel: "anonymous" as const
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const conn = ConnectionFactory();
|
||||||
|
const res = await conn.execute({
|
||||||
|
sql: "SELECT email FROM User WHERE id = ?",
|
||||||
|
args: [userId]
|
||||||
|
});
|
||||||
|
|
||||||
|
const email = res.rows[0] ? (res.rows[0].email as string | null) : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
isAuthenticated: true,
|
||||||
|
email,
|
||||||
|
privilegeLevel
|
||||||
|
};
|
||||||
|
}, "bars-user-state");
|
||||||
|
|
||||||
function formatDomainName(url: string): string {
|
function formatDomainName(url: string): string {
|
||||||
const domain = url.split("://")[1]?.split(":")[0] ?? url;
|
const domain = url.split("://")[1]?.split(":")[0] ?? url;
|
||||||
@@ -157,6 +195,26 @@ export function RightBarContent() {
|
|||||||
<span>Resume</span>
|
<span>Resume</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="/downloads"
|
||||||
|
onClick={handleLinkClick}
|
||||||
|
class="hover:text-subtext0 flex items-center gap-3 transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
|
||||||
|
>
|
||||||
|
<span class="shaker rounded-full p-2">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height={24}
|
||||||
|
width={24}
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
class="fill-text"
|
||||||
|
>
|
||||||
|
<path d="M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32V274.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32zM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V416c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>Downloads</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Typewriter>
|
</Typewriter>
|
||||||
|
|
||||||
@@ -188,17 +246,13 @@ export function RightBarContent() {
|
|||||||
export function LeftBar() {
|
export function LeftBar() {
|
||||||
const { leftBarVisible, setLeftBarVisible } = useBars();
|
const { leftBarVisible, setLeftBarVisible } = useBars();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const userState = createAsync(() => getUserState());
|
||||||
let ref: HTMLDivElement | undefined;
|
let ref: HTMLDivElement | undefined;
|
||||||
|
|
||||||
const [recentPosts, setRecentPosts] = createSignal<any[] | undefined>(
|
const [recentPosts, setRecentPosts] = createSignal<any[] | undefined>(
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const [userInfo, setUserInfo] = createSignal<{
|
|
||||||
email: string | null;
|
|
||||||
isAuthenticated: boolean;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const [isMounted, setIsMounted] = createSignal(false);
|
const [isMounted, setIsMounted] = createSignal(false);
|
||||||
const [signOutLoading, setSignOutLoading] = createSignal(false);
|
const [signOutLoading, setSignOutLoading] = createSignal(false);
|
||||||
const [getLostText, setGetLostText] = createSignal("What's this?");
|
const [getLostText, setGetLostText] = createSignal("What's this?");
|
||||||
@@ -229,31 +283,6 @@ export function LeftBar() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchUserInfo = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch("/api/trpc/user.getProfile", {
|
|
||||||
method: "GET"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const result = await response.json();
|
|
||||||
if (result.result?.data) {
|
|
||||||
setUserInfo({
|
|
||||||
email: result.result.data.email,
|
|
||||||
isAuthenticated: true
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setUserInfo({ email: null, isAuthenticated: false });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setUserInfo({ email: null, isAuthenticated: false });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to fetch user info:", error);
|
|
||||||
setUserInfo({ email: null, isAuthenticated: false });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
setIsMounted(true);
|
setIsMounted(true);
|
||||||
|
|
||||||
@@ -377,8 +406,6 @@ export function LeftBar() {
|
|||||||
console.error("Failed to fetch recent posts:", error);
|
console.error("Failed to fetch recent posts:", error);
|
||||||
setRecentPosts([]);
|
setRecentPosts([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchUserInfo();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -386,14 +413,6 @@ export function LeftBar() {
|
|||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
location.pathname;
|
|
||||||
|
|
||||||
if (isMounted()) {
|
|
||||||
fetchUserInfo();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const getMainNavStyles = () => {
|
const getMainNavStyles = () => {
|
||||||
const baseStyles = {
|
const baseStyles = {
|
||||||
@@ -539,6 +558,15 @@ export function LeftBar() {
|
|||||||
Blog
|
Blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<Show
|
||||||
|
when={isMounted() && userState()?.privilegeLevel === "admin"}
|
||||||
|
>
|
||||||
|
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
|
||||||
|
<a href="/analytics" onClick={handleLinkClick}>
|
||||||
|
Analytics
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</Show>
|
||||||
<li
|
<li
|
||||||
class="hover:text-subtext0 w-fit cursor-pointer transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold"
|
class="hover:text-subtext0 w-fit cursor-pointer transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -547,7 +575,7 @@ export function LeftBar() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Show
|
<Show
|
||||||
when={isMounted() && userInfo()?.isAuthenticated}
|
when={isMounted() && userState()?.isAuthenticated}
|
||||||
fallback={
|
fallback={
|
||||||
<a href="/login" onClick={handleLinkClick}>
|
<a href="/login" onClick={handleLinkClick}>
|
||||||
Login
|
Login
|
||||||
@@ -556,16 +584,16 @@ export function LeftBar() {
|
|||||||
>
|
>
|
||||||
<A href="/account" onClick={handleLinkClick}>
|
<A href="/account" onClick={handleLinkClick}>
|
||||||
Account
|
Account
|
||||||
<Show when={userInfo()?.email}>
|
<Show when={userState()?.email}>
|
||||||
<span class="text-subtext0 text-sm font-normal">
|
<span class="text-subtext0 text-sm font-normal">
|
||||||
{" "}
|
{" "}
|
||||||
({userInfo()!.email})
|
({userState()!.email})
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
</A>
|
</A>
|
||||||
</Show>
|
</Show>
|
||||||
</li>
|
</li>
|
||||||
<Show when={isMounted() && userInfo()?.isAuthenticated}>
|
<Show when={isMounted() && userState()?.isAuthenticated}>
|
||||||
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
|
<li class="hover:text-subtext0 w-fit transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-110 hover:font-bold">
|
||||||
<button
|
<button
|
||||||
onClick={handleSignOut}
|
onClick={handleSignOut}
|
||||||
|
|||||||
Reference in New Issue
Block a user