Skip to content

Commit

Permalink
Merge branch 'main' into feature/inv-29
Browse files Browse the repository at this point in the history
  • Loading branch information
xilucks authored Jul 19, 2024
2 parents 339c8dd + 3902a89 commit 7468094
Show file tree
Hide file tree
Showing 35 changed files with 1,362 additions and 28 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=
8 changes: 7 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"extends": "next/core-web-vitals"
"extends": [
"next/core-web-vitals",
"plugin:@tanstack/eslint-plugin-query/recommended"
],
"rules": {
"react/no-children-prop": "no"
}
}
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
],
"typescript.updateImportsOnFileMove.enabled": "always",
"typescript.preferences.importModuleSpecifier": "non-relative"
}
Binary file modified bun.lockb
Binary file not shown.
12 changes: 12 additions & 0 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from "drizzle-kit";

import { env } from "~/lib/env";

export default defineConfig({
dialect: "postgresql",
schema: "./src/lib/db/schema",
out: "./src/lib/db/migrations",
dbCredentials: {
url: env.DATABASE_URL,
},
});
22 changes: 21 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@
"lint": "next lint",
"ui": "bunx shadcn-ui@latest",
"ui:add": "bunx shadcn-ui@latest add",
"ui:lint": "bunx prettier src/components/ui/* --write"
"ui:lint": "bunx prettier src/components/ui/* --write",
"db:lint": "bunx prettier src/lib/db/migrations/**/*.json --write",
"db:generate": "drizzle-kit generate && bun db:lint",
"db:migrate": "drizzle-kit migrate && bun db:lint",
"db:push": "drizzle-kit push",
"db:pull": "drizzle-kit introspect",
"db:drop": "drizzle-kit drop",
"db:studio": "drizzle-kit studio",
"db:check": "drizzle-kit check"
},
"dependencies": {
"@neondatabase/serverless": "^0.9.4",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
Expand All @@ -24,21 +34,31 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@t3-oss/env-nextjs": "^0.10.1",
"@tanstack/react-form": "^0.26.1",
"@tanstack/react-query": "^5.50.1",
"@tanstack/zod-form-adapter": "^0.25.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"drizzle-orm": "^0.31.3",
"es-hangul": "^1.4.2",
"next": "14.2.4",
"next-themes": "^0.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"sonner": "^1.5.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8",
"zustand": "^4.5.4"
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "^5.50.1",
"@tanstack/react-query-devtools": "^5.50.1",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"drizzle-kit": "^0.22.8",
"eslint": "^8",
"eslint-config-next": "14.2.4",
"postcss": "^8.4.39",
Expand Down
29 changes: 29 additions & 0 deletions src/app/(playground)/playground/inner-tools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Link, { type LinkProps } from "next/link";
import { cn } from "~/lib/utils";

export function AMain(props: React.HTMLAttributes<HTMLDivElement>) {
return (
<main
{...props}
className={cn(
"mx-auto w-full max-w-2xl space-y-20 px-10 pt-20",
props.className,
)}
/>
);
}

export function ALink({
className,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & LinkProps) {
return (
<Link
{...props}
className={cn(
"inline-block font-bold text-blue-500 transition-all hover:text-blue-700",
className,
)}
/>
);
}
17 changes: 17 additions & 0 deletions src/app/(playground)/playground/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { GlobalAlert } from "~/components/global-alert";
import Providers from "~/components/providers";
import { Toaster } from "~/components/ui/sonner";

export default async function AppLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<Providers>
{children}
<Toaster />
<GlobalAlert />
</Providers>
);
}
43 changes: 43 additions & 0 deletions src/app/(playground)/playground/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { promises as fs } from "fs";
import path from "path";
import { ALink, AMain } from "~/app/(playground)/playground/inner-tools";

async function getPlaygroundRoutes() {
const playgroundDir = path.join(
process.cwd(),
"src/app/(playground)/playground",
);
const entries = await fs.readdir(playgroundDir, { withFileTypes: true });

const routes = await Promise.all(
entries
.filter((entry) => entry.isDirectory())
.map(async (entry) => {
const fullPath = path.join(playgroundDir, entry.name);
const files = await fs.readdir(fullPath);
if (files.includes("page.tsx")) {
return `/playground/${entry.name}`;
}
return null;
}),
);

return routes.filter((route) => route !== null);
}

export default async function Page() {
const routes = await getPlaygroundRoutes();

return (
<AMain>
<h2 className="font-bold">playground</h2>
<ul className="space-y-2">
{routes.map((route) => (
<li key={route}>
<ALink href={route}>{route}</ALink>
</li>
))}
</ul>
</AMain>
);
}
33 changes: 33 additions & 0 deletions src/app/(playground)/playground/test/[testId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";
import { cache } from "react";
import { ALink, AMain } from "~/app/(playground)/playground/inner-tools";
import TestInfo from "~/app/(playground)/playground/test/[testId]/test-info";
import TestEditDialog from "~/app/(playground)/playground/test/test-edit-dialog";
import { getTestWithTestJobs } from "~/lib/db/schema/test.query";

const getQueryClient = cache(() => new QueryClient());

export default async function Page({ params }: { params: { testId: string } }) {
const { testId } = params;

const queryClient = getQueryClient();

await queryClient.prefetchQuery({
queryKey: ["tests", testId],
queryFn: () => getTestWithTestJobs(+testId),
});

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<AMain>
<ALink href="/playground/test">뒤로가기</ALink>
<TestInfo />
<TestEditDialog />
</AMain>
</HydrationBoundary>
);
}
70 changes: 70 additions & 0 deletions src/app/(playground)/playground/test/[testId]/test-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use client";

import { GearIcon } from "@radix-ui/react-icons";
import { useQuery } from "@tanstack/react-query";
import { useParams } from "next/navigation";
import { useTestEditDialog } from "~/app/(playground)/playground/test/test-edit-dialog";
import { Button } from "~/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "~/components/ui/dropdown-menu";
import { getTestWithTestJobs } from "~/lib/db/schema/test.query";

export default function TestInfo() {
const { testId } = useParams<{ testId: string }>();

const { data, isLoading, error } = useQuery({
queryKey: ["tests", testId],
queryFn: () => getTestWithTestJobs(+testId),
});

const onOpenEditDialog = useTestEditDialog((state) => state.openDialog);

if (!data) {
return <div>{JSON.stringify(error, null, 2)}</div>;
}

return (
<div>
<Card className="relative">
<CardHeader>
<CardTitle>{data.name}</CardTitle>
<CardDescription>{data.email}</CardDescription>
</CardHeader>
<CardContent>
<CardDescription>ID {data.id}</CardDescription>
<CardDescription>숫자 {data.number}</CardDescription>
<CardDescription>테스트 작업 {data.jobs.length}</CardDescription>
</CardContent>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="icon"
className="absolute bottom-5 right-4"
>
<GearIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => onOpenEditDialog(data)}>
수정하기
</DropdownMenuItem>
<DropdownMenuItem>삭제하기</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</Card>
<div>{data.jobs?.map((job) => <div key={job?.id}>{job?.id}</div>)}</div>
</div>
);
}
33 changes: 33 additions & 0 deletions src/app/(playground)/playground/test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";
import { cache } from "react";
import { ALink, AMain } from "~/app/(playground)/playground/inner-tools";
import TestEditDialog from "~/app/(playground)/playground/test/test-edit-dialog";
import TestForm from "~/app/(playground)/playground/test/test-form";
import TestList from "~/app/(playground)/playground/test/test-list";
import { getTestWithTestJobCnt } from "~/lib/db/schema/test.query";

const getQueryClient = cache(() => new QueryClient());

export default async function Page() {
const queryClient = getQueryClient();

await queryClient.prefetchQuery({
queryKey: ["tests"],
queryFn: getTestWithTestJobCnt,
});

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<AMain>
<ALink href="/playground">playground</ALink>
<TestForm />
<TestList />
<TestEditDialog />
</AMain>
</HydrationBoundary>
);
}
Loading

0 comments on commit 7468094

Please sign in to comment.