diff --git a/backend/controllers/cover/cover.go b/backend/controllers/cover/cover.go
index 5aa6280..e24e3d9 100644
--- a/backend/controllers/cover/cover.go
+++ b/backend/controllers/cover/cover.go
@@ -29,7 +29,7 @@ func Get(c *gin.Context) {
return
}
- covers, err := cover.Get("user_id = $1", user.Id)
+ covers, err := cover.Get("user_id = $1 ORDER BY created_at DESC", user.Id)
if err != nil {
res.Error(c, err.Error(), http.StatusInternalServerError)
return
diff --git a/backend/controllers/template/template.go b/backend/controllers/template/template.go
index c0dd33a..2a86471 100644
--- a/backend/controllers/template/template.go
+++ b/backend/controllers/template/template.go
@@ -69,7 +69,7 @@ func Get(c *gin.Context) {
}
// Get all user templates
- templates, err := template.Get("user_id = $1", user.Id)
+ templates, err := template.Get("user_id = $1 ORDER BY created_at DESC", user.Id)
if err != nil {
res.Error(c, err.Error(), http.StatusInternalServerError)
return
diff --git a/frontend/src/components/ui/container.tsx b/frontend/src/components/ui/container.tsx
index ac40829..59bf855 100644
--- a/frontend/src/components/ui/container.tsx
+++ b/frontend/src/components/ui/container.tsx
@@ -1,3 +1,3 @@
export default function Container({ children, className = "" }: React.ComponentProps<"div">) {
- return
{children}
;
+ return {children}
;
}
diff --git a/frontend/src/editor.css b/frontend/src/editor.css
index 48f9d85..9a0a5aa 100644
--- a/frontend/src/editor.css
+++ b/frontend/src/editor.css
@@ -24,6 +24,11 @@
margin-top: 0;
}
+ /* Text */
+ p {
+ margin-top: 0.5rem;
+ }
+
/* Links */
a {
color: var(--editor-accent);
diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts
index 0242fff..dfbcd86 100644
--- a/frontend/src/routeTree.gen.ts
+++ b/frontend/src/routeTree.gen.ts
@@ -15,6 +15,7 @@ import { Route as IndexRouteImport } from './routes/index'
import { Route as TemplatesIndexRouteImport } from './routes/templates/index'
import { Route as TemplatesCreateRouteImport } from './routes/templates/create'
import { Route as CoverCreateRouteImport } from './routes/cover/create'
+import { Route as CoverCoverIdRouteImport } from './routes/cover/$coverId'
const RegisterRoute = RegisterRouteImport.update({
id: '/register',
@@ -46,11 +47,17 @@ const CoverCreateRoute = CoverCreateRouteImport.update({
path: '/cover/create',
getParentRoute: () => rootRouteImport,
} as any)
+const CoverCoverIdRoute = CoverCoverIdRouteImport.update({
+ id: '/cover/$coverId',
+ path: '/cover/$coverId',
+ getParentRoute: () => rootRouteImport,
+} as any)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/register': typeof RegisterRoute
+ '/cover/$coverId': typeof CoverCoverIdRoute
'/cover/create': typeof CoverCreateRoute
'/templates/create': typeof TemplatesCreateRoute
'/templates': typeof TemplatesIndexRoute
@@ -59,6 +66,7 @@ export interface FileRoutesByTo {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/register': typeof RegisterRoute
+ '/cover/$coverId': typeof CoverCoverIdRoute
'/cover/create': typeof CoverCreateRoute
'/templates/create': typeof TemplatesCreateRoute
'/templates': typeof TemplatesIndexRoute
@@ -68,6 +76,7 @@ export interface FileRoutesById {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/register': typeof RegisterRoute
+ '/cover/$coverId': typeof CoverCoverIdRoute
'/cover/create': typeof CoverCreateRoute
'/templates/create': typeof TemplatesCreateRoute
'/templates/': typeof TemplatesIndexRoute
@@ -78,6 +87,7 @@ export interface FileRouteTypes {
| '/'
| '/login'
| '/register'
+ | '/cover/$coverId'
| '/cover/create'
| '/templates/create'
| '/templates'
@@ -86,6 +96,7 @@ export interface FileRouteTypes {
| '/'
| '/login'
| '/register'
+ | '/cover/$coverId'
| '/cover/create'
| '/templates/create'
| '/templates'
@@ -94,6 +105,7 @@ export interface FileRouteTypes {
| '/'
| '/login'
| '/register'
+ | '/cover/$coverId'
| '/cover/create'
| '/templates/create'
| '/templates/'
@@ -103,6 +115,7 @@ export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
LoginRoute: typeof LoginRoute
RegisterRoute: typeof RegisterRoute
+ CoverCoverIdRoute: typeof CoverCoverIdRoute
CoverCreateRoute: typeof CoverCreateRoute
TemplatesCreateRoute: typeof TemplatesCreateRoute
TemplatesIndexRoute: typeof TemplatesIndexRoute
@@ -152,6 +165,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof CoverCreateRouteImport
parentRoute: typeof rootRouteImport
}
+ '/cover/$coverId': {
+ id: '/cover/$coverId'
+ path: '/cover/$coverId'
+ fullPath: '/cover/$coverId'
+ preLoaderRoute: typeof CoverCoverIdRouteImport
+ parentRoute: typeof rootRouteImport
+ }
}
}
@@ -159,6 +179,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
LoginRoute: LoginRoute,
RegisterRoute: RegisterRoute,
+ CoverCoverIdRoute: CoverCoverIdRoute,
CoverCreateRoute: CoverCreateRoute,
TemplatesCreateRoute: TemplatesCreateRoute,
TemplatesIndexRoute: TemplatesIndexRoute,
diff --git a/frontend/src/routes/cover/$coverId.tsx b/frontend/src/routes/cover/$coverId.tsx
new file mode 100644
index 0000000..a55190c
--- /dev/null
+++ b/frontend/src/routes/cover/$coverId.tsx
@@ -0,0 +1,48 @@
+import renderQueryState from "@/components/RenderQueryState";
+import Authorised from "@/layouts/Authorised";
+import requests from "@/lib/requests";
+import type { CoverLetter } from "@/types/api";
+import { useQuery } from "@tanstack/react-query";
+import { createFileRoute } from "@tanstack/react-router";
+import "../../editor.css";
+
+export const Route = createFileRoute("/cover/$coverId")({
+ component: RouteComponent,
+});
+
+function RouteComponent() {
+ const { coverId } = Route.useParams();
+
+ const cover = useQuery({
+ queryKey: ["cover", coverId],
+ queryFn: () => requests.get<{ cover: CoverLetter }>(`/cover/${coverId}`, {}),
+ });
+ const coverState = renderQueryState({
+ query: cover,
+ noFound: "cover letter",
+ skeleton: {
+ count: 1,
+ className: "h-[400px]",
+ },
+ });
+
+ return (
+
+
+
{cover.data?.cover.name || "Loading..."}
+ {/* edit buttons */}
+
+
+
+ {coverState !== null ? (
+ coverState
+ ) : (
+
+ )}
+
+
+ );
+}
diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx
index 98add8e..7b0b493 100644
--- a/frontend/src/routes/index.tsx
+++ b/frontend/src/routes/index.tsx
@@ -2,16 +2,31 @@ import { createFileRoute, Link } from "@tanstack/react-router";
import Authorised from "@/layouts/Authorised";
import { Button } from "@/components/ui/button";
import { Plus } from "lucide-react";
+import { useQuery } from "@tanstack/react-query";
+import requests from "@/lib/requests";
+import type { CoverLetterPreview } from "@/types/api";
+import renderQueryState from "@/components/RenderQueryState";
export const Route = createFileRoute("/")({
component: App,
});
function App() {
+ const letters = useQuery({
+ queryKey: ["cover_letters"],
+ queryFn: () => requests.get<{ covers: CoverLetterPreview[] }>("/cover", {}),
+ });
+ const lettersState = renderQueryState({
+ query: letters,
+ noFound: "cover letters",
+ });
+
return (
-
0 Cover letters
+
+ {letters.data?.covers.length} Cover letters
+
} variant="secondary">
@@ -19,6 +34,21 @@ function App() {
+
+
+ {lettersState !== null
+ ? lettersState
+ : letters.data?.covers.map((l) => (
+
+
{l.name}
+
+ ))}
+
);
}
diff --git a/frontend/src/types/api.ts b/frontend/src/types/api.ts
index c8a0131..36b4ed8 100644
--- a/frontend/src/types/api.ts
+++ b/frontend/src/types/api.ts
@@ -27,3 +27,15 @@ export interface Template {
template: string;
created_at: string;
}
+
+// -------- Cover letters --------
+export interface CoverLetterPreview {
+ id: number;
+ name: string;
+}
+
+export interface CoverLetter extends CoverLetterPreview {
+ user_id: number;
+ letter: string;
+ created_at: string;
+}