From b2ef80d58d39f5d0d75ac883e058e2c5c2a68883 Mon Sep 17 00:00:00 2001 From: Lars Hampe Date: Thu, 3 Oct 2024 22:47:47 +0200 Subject: [PATCH] feat(app): add changelog list, byId and create page --- apps/app/package.json | 5 +- apps/app/src/components/Navigation.tsx | 1 - apps/app/src/hooks/useChangelog.ts | 8 +- apps/app/src/routeTree.gen.ts | 63 +++++++++- apps/app/src/routes/changelog/$id.lazy.tsx | 33 +++++ apps/app/src/routes/changelog/create.lazy.tsx | 117 ++++++++++++++++++ apps/app/src/routes/changelog/index.lazy.tsx | 56 +++++++-- bun.lockb | Bin 423424 -> 423520 bytes 8 files changed, 265 insertions(+), 18 deletions(-) create mode 100644 apps/app/src/routes/changelog/$id.lazy.tsx create mode 100644 apps/app/src/routes/changelog/create.lazy.tsx diff --git a/apps/app/package.json b/apps/app/package.json index e5b7367..d3a854c 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -13,13 +13,16 @@ "@boring.tools/schema": "workspace:*", "@boring.tools/ui": "workspace:*", "@clerk/clerk-react": "^5.9.4", + "@hookform/resolvers": "^3.9.0", "@tanstack/react-query": "^5.59.0", "@tanstack/react-router": "^1.58.15", "axios": "^1.7.7", "lucide-react": "^0.446.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "tailwindcss-animate": "^1.0.7" + "react-hook-form": "^7.53.0", + "tailwindcss-animate": "^1.0.7", + "zod": "^3.23.8" }, "devDependencies": { "@eslint/js": "^9.9.0", diff --git a/apps/app/src/components/Navigation.tsx b/apps/app/src/components/Navigation.tsx index f0cf21a..33619e7 100644 --- a/apps/app/src/components/Navigation.tsx +++ b/apps/app/src/components/Navigation.tsx @@ -37,7 +37,6 @@ export const Navigation = () => { to={route.to} className="flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary" activeProps={{ className: 'bg-muted text-primary' }} - activeOptions={{ exact: true }} > {route.name} diff --git a/apps/app/src/hooks/useChangelog.ts b/apps/app/src/hooks/useChangelog.ts index 74ee00f..efb1990 100644 --- a/apps/app/src/hooks/useChangelog.ts +++ b/apps/app/src/hooks/useChangelog.ts @@ -28,7 +28,7 @@ export const useChangelogById = ({ id }: { id: string }) => { return useQuery({ queryKey: ['changelogById', id], - queryFn: async (): Promise> => + queryFn: async (): Promise> => await queryFetch({ path: `changelog/${id}`, method: 'get', @@ -44,7 +44,7 @@ export const useChangelogCreate = () => { return useMutation({ mutationFn: async ( payload: ChangelogCreate, - ): Promise> => + ): Promise> => await queryFetch({ path: 'changelog', data: payload, @@ -62,9 +62,7 @@ export const useChangelogRemove = () => { const queryClient = useQueryClient() return useMutation({ - mutationFn: async ({ - id, - }: { id: string }): Promise> => + mutationFn: async ({ id }: { id: string }): Promise> => await queryFetch({ path: `changelog/${id}`, method: 'delete', diff --git a/apps/app/src/routeTree.gen.ts b/apps/app/src/routeTree.gen.ts index d9629a7..97e1e63 100644 --- a/apps/app/src/routeTree.gen.ts +++ b/apps/app/src/routeTree.gen.ts @@ -19,6 +19,8 @@ import { Route as rootRoute } from './routes/__root' const IndexLazyImport = createFileRoute('/')() const UserIndexLazyImport = createFileRoute('/user/')() const ChangelogIndexLazyImport = createFileRoute('/changelog/')() +const ChangelogCreateLazyImport = createFileRoute('/changelog/create')() +const ChangelogIdLazyImport = createFileRoute('/changelog/$id')() // Create/Update Routes @@ -39,6 +41,18 @@ const ChangelogIndexLazyRoute = ChangelogIndexLazyImport.update({ import('./routes/changelog/index.lazy').then((d) => d.Route), ) +const ChangelogCreateLazyRoute = ChangelogCreateLazyImport.update({ + path: '/changelog/create', + getParentRoute: () => rootRoute, +} as any).lazy(() => + import('./routes/changelog/create.lazy').then((d) => d.Route), +) + +const ChangelogIdLazyRoute = ChangelogIdLazyImport.update({ + path: '/changelog/$id', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/changelog/$id.lazy').then((d) => d.Route)) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -50,6 +64,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexLazyImport parentRoute: typeof rootRoute } + '/changelog/$id': { + id: '/changelog/$id' + path: '/changelog/$id' + fullPath: '/changelog/$id' + preLoaderRoute: typeof ChangelogIdLazyImport + parentRoute: typeof rootRoute + } + '/changelog/create': { + id: '/changelog/create' + path: '/changelog/create' + fullPath: '/changelog/create' + preLoaderRoute: typeof ChangelogCreateLazyImport + parentRoute: typeof rootRoute + } '/changelog/': { id: '/changelog/' path: '/changelog' @@ -71,12 +99,16 @@ declare module '@tanstack/react-router' { export interface FileRoutesByFullPath { '/': typeof IndexLazyRoute + '/changelog/$id': typeof ChangelogIdLazyRoute + '/changelog/create': typeof ChangelogCreateLazyRoute '/changelog': typeof ChangelogIndexLazyRoute '/user': typeof UserIndexLazyRoute } export interface FileRoutesByTo { '/': typeof IndexLazyRoute + '/changelog/$id': typeof ChangelogIdLazyRoute + '/changelog/create': typeof ChangelogCreateLazyRoute '/changelog': typeof ChangelogIndexLazyRoute '/user': typeof UserIndexLazyRoute } @@ -84,27 +116,44 @@ export interface FileRoutesByTo { export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexLazyRoute + '/changelog/$id': typeof ChangelogIdLazyRoute + '/changelog/create': typeof ChangelogCreateLazyRoute '/changelog/': typeof ChangelogIndexLazyRoute '/user/': typeof UserIndexLazyRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/changelog' | '/user' + fullPaths: + | '/' + | '/changelog/$id' + | '/changelog/create' + | '/changelog' + | '/user' fileRoutesByTo: FileRoutesByTo - to: '/' | '/changelog' | '/user' - id: '__root__' | '/' | '/changelog/' | '/user/' + to: '/' | '/changelog/$id' | '/changelog/create' | '/changelog' | '/user' + id: + | '__root__' + | '/' + | '/changelog/$id' + | '/changelog/create' + | '/changelog/' + | '/user/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexLazyRoute: typeof IndexLazyRoute + ChangelogIdLazyRoute: typeof ChangelogIdLazyRoute + ChangelogCreateLazyRoute: typeof ChangelogCreateLazyRoute ChangelogIndexLazyRoute: typeof ChangelogIndexLazyRoute UserIndexLazyRoute: typeof UserIndexLazyRoute } const rootRouteChildren: RootRouteChildren = { IndexLazyRoute: IndexLazyRoute, + ChangelogIdLazyRoute: ChangelogIdLazyRoute, + ChangelogCreateLazyRoute: ChangelogCreateLazyRoute, ChangelogIndexLazyRoute: ChangelogIndexLazyRoute, UserIndexLazyRoute: UserIndexLazyRoute, } @@ -122,6 +171,8 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", + "/changelog/$id", + "/changelog/create", "/changelog/", "/user/" ] @@ -129,6 +180,12 @@ export const routeTree = rootRoute "/": { "filePath": "index.lazy.tsx" }, + "/changelog/$id": { + "filePath": "changelog/$id.lazy.tsx" + }, + "/changelog/create": { + "filePath": "changelog/create.lazy.tsx" + }, "/changelog/": { "filePath": "changelog/index.lazy.tsx" }, diff --git a/apps/app/src/routes/changelog/$id.lazy.tsx b/apps/app/src/routes/changelog/$id.lazy.tsx new file mode 100644 index 0000000..80b9362 --- /dev/null +++ b/apps/app/src/routes/changelog/$id.lazy.tsx @@ -0,0 +1,33 @@ +import { Button } from '@boring.tools/ui' +import { createLazyFileRoute } from '@tanstack/react-router' +import { useChangelogById } from '../../hooks/useChangelog' + +const Component = () => { + const { id } = Route.useParams() + const { data, error, isPending, refetch } = useChangelogById({ id }) + + if (error) { + return ( +
+

Changelogs

+

Please try again later

+ + +
+ ) + } + + return ( +
+ {!isPending && data && ( +
+

{data.title}

+
+ )} +
+ ) +} + +export const Route = createLazyFileRoute('/changelog/$id')({ + component: Component, +}) diff --git a/apps/app/src/routes/changelog/create.lazy.tsx b/apps/app/src/routes/changelog/create.lazy.tsx new file mode 100644 index 0000000..1257371 --- /dev/null +++ b/apps/app/src/routes/changelog/create.lazy.tsx @@ -0,0 +1,117 @@ +import { ChangelogCreateInput } from '@boring.tools/schema' +import { + Button, + Checkbox, + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, + Input, + Textarea, +} from '@boring.tools/ui' +import { zodResolver } from '@hookform/resolvers/zod' +import { createLazyFileRoute } from '@tanstack/react-router' +import { useNavigate } from '@tanstack/react-router' +import { useForm } from 'react-hook-form' +import type { z } from 'zod' +import { useChangelogCreate } from '../../hooks/useChangelog' + +const Component = () => { + const navigate = useNavigate({ from: '/changelog/create' }) + const changelogCreate = useChangelogCreate() + const form = useForm>({ + resolver: zodResolver(ChangelogCreateInput), + defaultValues: { + title: '', + description: '', + isSemver: true, + }, + }) + + const onSubmit = (values: z.infer) => { + changelogCreate.mutate(values, { + onSuccess(data) { + navigate({ to: '/changelog/$id', params: { id: data.id } }) + }, + }) + } + + return ( +
+

New changelog

+ +
+ + ( + + Title + + + {' '} + + + )} + /> + + ( + + Description + +