Skip to content

Commit

Permalink
Merge pull request #1 from Design-System-Project/feature/tfr2-98-add-…
Browse files Browse the repository at this point in the history
…design-system-project-selector-on-navigation-bar

Add project selector on navigation bar
  • Loading branch information
tomasfrancisco authored Aug 14, 2024
2 parents 47d5fbc + 838f2ce commit 5af17e0
Show file tree
Hide file tree
Showing 70 changed files with 1,335 additions and 3,680 deletions.
6 changes: 5 additions & 1 deletion apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"type-check": "tsc --noEmit",
"db:types": "pnpm dlx supabase gen types --lang=typescript --linked > src/lib/supabase/__generated__/database.generated.types.ts",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate"
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio",
"db:reset": "pnpx supabase db reset",
"db:start": "pnpx supabase start",
"db:stop": "pnpx supabase stop"
},
"dependencies": {
"@ds-project/components": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { eq } from 'drizzle-orm';
import { database } from '@/lib/drizzle';
import { isAuthenticated } from '@/lib/supabase/server/utils/is-authenticated';
import { getDesignSystemId } from '@/lib/supabase/server/utils/get-design-system-id';
import { getProjectId } from '@/lib/supabase/server/utils/get-project-id';

export async function getResources() {
if (!(await isAuthenticated())) {
throw new Error('Not authenticated');
}

const designSystemId = await getDesignSystemId();
const projectId = await getProjectId();

if (!designSystemId)
throw new Error('No design system associated with this account');
if (!projectId) throw new Error('No project associated with this account');

return database.query.resourcesTable.findMany({
where: (resources) => eq(resources.designSystemId, designSystemId),
with: {
project: {
with: {
resources: true,
accountsToProjects: {
where: (accountsToProjects) =>
eq(accountsToProjects.projectId, projectId),
},
},
},
},
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
integrationsTableSchema,
integrationType,
} from '@/lib/drizzle/schema';
import { getDesignSystemId } from '@/lib/supabase/server/utils/get-design-system-id';
import { getProjectId } from '@/lib/supabase/server/utils/get-project-id';

export async function GET(request: NextRequest) {
const { searchParams, origin } = new URL(request.url);
Expand All @@ -16,9 +16,9 @@ export async function GET(request: NextRequest) {
if (!installationId) throw new Error('No installation id provided');

try {
const designSystemId = await getDesignSystemId(request);
const projectId = await getProjectId(request);

if (!designSystemId)
if (!projectId)
throw new Error('No design system associated with this account');

const validatedData = integrationDataSchema.parse({
Expand All @@ -28,7 +28,7 @@ export async function GET(request: NextRequest) {

const validatedValues = integrationsTableSchema.parse({
type: integrationType.Enum.github,
designSystemId,
projectId,
data: validatedData,
});

Expand Down
6 changes: 4 additions & 2 deletions apps/dashboard/src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Inter } from 'next/font/google';
import '../globals.css';
import { Navigation } from '@/components';
import { cn } from '@/lib/css';
import { getProjects } from '@/components/navigation/_actions/get-projects.action';

const inter = Inter({ subsets: ['latin'] });

Expand All @@ -11,15 +12,16 @@ export const metadata: Metadata = {
description: 'Manage Design System',
};

export default function RootLayout({
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const projects = await getProjects();
return (
<html lang="en">
<body className={cn('flex flex-col items-center', inter.className)}>
<Navigation className="mt-6" />
<Navigation className="mt-6 px-2" projects={projects} />
<main className="flex min-h-screen w-full flex-col items-center p-24">
{children}
</main>
Expand Down
6 changes: 3 additions & 3 deletions apps/dashboard/src/app/api/figma/design-systems/link/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ export async function POST(request: NextRequest) {
return new Response('Not authenticated', { status: 401 });
}

const { designSystemId, fileName } = (await request.json()) as {
designSystemId: string;
const { projectId, fileName } = (await request.json()) as {
projectId: string;
fileName: string;
};

await database.insert(resourcesTable).values({
designSystemId,
projectId,
name: fileName,
});

Expand Down
21 changes: 10 additions & 11 deletions apps/dashboard/src/app/api/figma/design-systems/list/route.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import type { NextRequest } from 'next/server';
import { isAuthenticated } from '@/lib/supabase/server/utils/is-authenticated';
import { database } from '@/lib/drizzle';
import { getUserAccount } from '@/lib/supabase/server/utils/get-user-account';
import { designSystemsTable } from '@/lib/drizzle/schema';
import { projectsTable } from '@/lib/drizzle/schema';
import { getProjectId } from '@/lib/supabase/server/utils/get-project-id';

export async function GET(request: NextRequest) {
if (!(await isAuthenticated(request))) {
return new Response('Not authenticated', { status: 401 });
}

const userAccount = await getUserAccount(request);
const designSystemId = userAccount?.designSystemId;
const projectId = await getProjectId(request);

if (!designSystemId) {
return new Response('No design system associated with this account', {
if (!projectId) {
return new Response('No project associated with this account', {
status: 404,
});
}

const designSystems = await database
const projects = await database
.select({
id: designSystemsTable.id,
name: designSystemsTable.name,
id: projectsTable.id,
name: projectsTable.name,
})
.from(designSystemsTable);
.from(projectsTable);

return new Response(
JSON.stringify({
designSystems,
projects,
}),
{ status: 200 }
);
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/src/app/api/figma/design-tokens/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ export async function POST(request: NextRequest) {

try {
const validatedData = insertResourcesSchema
.pick({ designTokens: true, designSystemId: true })
.pick({ designTokens: true, projectId: true })
.parse(await request.json());

await database
.update(resourcesTable)
.set({
designTokens: validatedData.designTokens,
})
.where(eq(resourcesTable.designSystemId, validatedData.designSystemId));
.where(eq(resourcesTable.projectId, validatedData.projectId));
} catch (error) {
return new Response(JSON.stringify(error), { status: 400 });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// eslint-disable-next-line import/named -- TODO: Review
import { useFormState } from 'react-dom';
import { Input, Label } from '@ds-project/components';
import { Input, Label, Text } from '@ds-project/components';
import { loginUser } from '../_actions';
import { Message } from './message';
import { SubmitButton } from './submit-button';
Expand All @@ -25,7 +25,9 @@ export const MagicLinkForm = () => {
<p>Sign in instantly by getting a magic link sent to your email</p>

<SubmitButton />

<Text>
<p>{state.error}</p>
</Text>
<Message email={state.email} visible={state.ok} />
</form>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use server';

import { eq } from 'drizzle-orm';
import { database } from '@/lib/drizzle';
import { getUserAccount } from '@/lib/supabase/server/utils/get-user-account';
import { isAuthenticated } from '@/lib/supabase/server/utils/is-authenticated';

export async function getProjects() {
if (!(await isAuthenticated())) {
throw new Error('Not authenticated');
}

const account = await getUserAccount();

if (!account) {
return undefined;
}

const projects = await database.query.projectsTable.findMany({
with: {
accountsToProjects: {
where: (accounts) => eq(accounts.accountId, account.id),
},
},
});

return projects;
}
54 changes: 30 additions & 24 deletions apps/dashboard/src/components/navigation/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,48 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
Icons,
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from '@ds-project/components';
import Link from 'next/link';
import { cn } from '@/lib/css';
import { HomeButton } from '../home-button/home-button';
import type { SelectProjects } from '@/lib/drizzle/schema';
import { HomeButton } from '../home-button';

export function Navigation({ className }: { className?: string }) {
interface NavigationProps {
className?: string;
projects?: SelectProjects[];
}

export function Navigation({ className, projects }: NavigationProps) {
return (
<nav className={cn(className)}>
<nav className={cn('flex w-full justify-start gap-2', className)}>
<HomeButton />
<DropdownMenu>
<DropdownMenuTrigger className="flex items-center gap-2 rounded-md border border-[hsl(var(--input))] p-2">
<Icons.FrameIcon /> {projects?.[0].name} <Icons.ChevronDownIcon />
</DropdownMenuTrigger>
<DropdownMenuContent>
{projects?.map((project) => (
<DropdownMenuItem key={project.id}>
<Icons.FrameIcon className="mr-2" /> {project.name}
</DropdownMenuItem>
))}
<DropdownMenuItem
aria-label="Soon you will be able to add new projects"
disabled
title="Coming Soon"
>
<Icons.PlusIcon className="mr-2" /> New Project
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<NavigationMenu>
<HomeButton className="mr-2" />
<NavigationMenuList>
<NavigationMenuItem>
<Link href="/tokens" legacyBehavior passHref>
Expand All @@ -36,23 +59,6 @@ export function Navigation({ className }: { className?: string }) {
</NavigationMenuLink>
</Link>
</NavigationMenuItem>
<NavigationMenuItem>
<DropdownMenu>
<DropdownMenuTrigger
asChild
className={navigationMenuTriggerStyle()}
>
<NavigationMenuTrigger>Account</NavigationMenuTrigger>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link href="/auth/logout">Logout</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</nav>
Expand Down
Loading

0 comments on commit 5af17e0

Please sign in to comment.