This commit is contained in:
Owen Schwartz
2024-10-19 17:30:15 -04:00
23 changed files with 695 additions and 451 deletions

View File

@@ -1,5 +1,6 @@
"use client";
import api from "@app/api";
import { Avatar, AvatarFallback } from "@app/components/ui/avatar";
import { Button } from "@app/components/ui/button";
import {
@@ -19,15 +20,23 @@ import {
SelectTrigger,
SelectValue,
} from "@app/components/ui/select";
import { useToast } from "@app/hooks/use-toast";
import { ListOrgsResponse } from "@server/routers/org";
import Link from "next/link";
import { useRouter } from "next/navigation";
type HeaderProps = {
name?: string;
email: string;
orgName: string;
orgs: ListOrgsResponse["orgs"];
};
export default function Header({ email, orgName, name }: HeaderProps) {
export default function Header({ email, orgName, name, orgs }: HeaderProps) {
const { toast } = useToast();
const router = useRouter();
function getInitials() {
if (name) {
const [firstName, lastName] = name.split(" ");
@@ -36,6 +45,19 @@ export default function Header({ email, orgName, name }: HeaderProps) {
return email.substring(0, 2).toUpperCase();
}
function logout() {
api.post("/auth/logout")
.catch((e) => {
console.error("Error logging out", e);
toast({
title: "Error logging out",
});
})
.then(() => {
router.push("/auth/login");
});
}
return (
<>
<div className="flex items-center justify-between">
@@ -72,8 +94,9 @@ export default function Header({ email, orgName, name }: HeaderProps) {
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Log out</DropdownMenuItem>
<DropdownMenuItem onClick={logout}>
Log out
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
@@ -106,9 +129,14 @@ export default function Header({ email, orgName, name }: HeaderProps) {
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value={orgName}>
{orgName}
</SelectItem>
{orgs.map((org) => (
<SelectItem
value={org.name}
key={org.orgId}
>
{org.name}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>

View File

@@ -51,9 +51,7 @@ export function TopbarNav({
>
<div className="flex items-center gap-2">
{item.icon && (
<div className="hidden md:block">
{item.icon}
</div>
<div className="hidden md:block">{item.icon}</div>
)}
{item.title}
</div>

View File

@@ -7,11 +7,11 @@ import { redirect } from "next/navigation";
import { cache } from "react";
import { internal } from "@app/api";
import { AxiosResponse } from "axios";
import { GetOrgResponse } from "@server/routers/org";
import { GetOrgResponse, ListOrgsResponse } from "@server/routers/org";
import { authCookieHeader } from "@app/api/cookies";
export const metadata: Metadata = {
title: "Configuration",
title: `Configuration - ${process.env.NEXT_PUBLIC_APP_NAME}`,
description: "",
};
@@ -62,11 +62,28 @@ export default async function ConfigurationLaytout({
redirect(`/`);
}
let orgs: ListOrgsResponse["orgs"] = [];
try {
const res = await internal.get<AxiosResponse<ListOrgsResponse>>(
`/orgs`,
authCookieHeader(),
);
if (res && res.data.data.orgs) {
orgs = res.data.data.orgs;
}
} catch (e) {
console.error("Error fetching orgs", e);
}
return (
<>
<div className="w-full bg-muted mb-6 select-none sm:px-0 px-3 pt-3">
<div className="container mx-auto flex flex-col content-between gap-4 ">
<Header email={user.email} orgName={params.orgId} />
<Header
email={user.email}
orgName={params.orgId}
orgs={orgs}
/>
<TopbarNav items={topNavItems} orgId={params.orgId} />
</div>
</div>

View File

@@ -20,6 +20,21 @@ export const metadata: Metadata = {
description: "Advanced form example using react-hook-form and Zod.",
};
const sidebarNavItems = [
{
title: "Profile",
href: "/{orgId}/resources/{resourceId}",
},
// {
// title: "Appearance",
// href: "/{orgId}/resources/{resourceId}/appearance",
// },
// {
// title: "Notifications",
// href: "/{orgId}/resources/{resourceId}/notifications",
// },
]
interface SettingsLayoutProps {
children: React.ReactNode;
params: { resourceId: string; orgId: string };

View File

@@ -17,6 +17,8 @@ export type ResourceRow = {
id: string;
name: string;
orgId: string;
domain: string;
site: string;
};
export const columns: ColumnDef<ResourceRow>[] = [
@@ -36,6 +38,26 @@ export const columns: ColumnDef<ResourceRow>[] = [
);
},
},
{
accessorKey: "site",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
Site
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
},
},
{
accessorKey: "domain",
header: "Domain",
},
{
id: "actions",
cell: ({ row }) => {

View File

@@ -25,6 +25,8 @@ export default async function Page({ params }: ResourcesPageProps) {
id: resource.resourceId.toString(),
name: resource.name,
orgId: params.orgId,
domain: resource.subdomain || "",
site: resource.siteName || "None",
};
});

View File

@@ -15,10 +15,10 @@ import { useEffect, useState } from "react";
import { toast } from "@app/hooks/use-toast";
import { ClientLayout } from "./components/ClientLayout";
export const metadata: Metadata = {
title: "Forms",
description: "Advanced form example using react-hook-form and Zod.",
};
// export const metadata: Metadata = {
// title: "Forms",
// description: "Advanced form example using react-hook-form and Zod.",
// };
interface SettingsLayoutProps {
children: React.ReactNode;
@@ -70,7 +70,7 @@ export default async function SettingsLayout({
</Link>
</div>
<SiteProvider site={site}>
<SiteProvider site={site}>
<ClientLayout
isCreate={params.niceId === "create"}
>