diff --git a/src/app/actions.ts b/src/app/actions.ts index e1b17e7..c0dc92a 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -6,6 +6,14 @@ import { users } from "@/server/db/schema"; import type { PaperlessDocumentsType } from "@/types"; import { auth } from "@clerk/nextjs/server"; +/* +Clerk helpers + ___| | ___ _ __| | __ + / __| |/ _ | '__| |/ / +| (__| | __| | | < + \___|_|\___|_| |_|\_\ +*/ + export async function setUserProperty( propertyName: K, value: UsersTableType[K], @@ -43,6 +51,15 @@ export async function getUserData() { return userData; } +/* +Paperless +| _ \ __ _ _ __ ___ _ __| | ___ ___ ___ +| |_) / _` | '_ \ / _ | '__| |/ _ / __/ __| +| __| (_| | |_) | __| | | | __\__ \__ \ +|_| \__,_| .__/ \___|_| |_|\___|___|___/ + |_| +*/ + export async function getPaperlessDocuments(query: string) { const userData = await getUserData(); @@ -63,3 +80,33 @@ export async function getPaperlessDocuments(query: string) { return data; } + +/* +Whishper + \ \ / (_)___| |__ _ __ ___ _ __ + \ \ /\ / /| / __| '_ \| '_ \ / _ | '__| + \ V V / | \__ | | | | |_) | __| | + \_/\_/ |_|___|_| |_| .__/ \___|_| + |_| +*/ + +export async function getWhishperRecordings(query: string) { + const userData = await getUserData(); + + if (!query || query == "null" || query.length < 3 || !userData) return null; + + const response = await fetch( + `${userData.whishperURL}/api/documents/?query=${query}&page=1&page_size=10&truncate_content=true`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Token ${userData.paperlessToken}`, + }, + }, + ); + + const data = (await response.json()) as PaperlessDocumentsType; + + return data; +} diff --git a/src/app/whishper/page.tsx b/src/app/whishper/page.tsx new file mode 100644 index 0000000..a669718 --- /dev/null +++ b/src/app/whishper/page.tsx @@ -0,0 +1,165 @@ +"use client"; + +import { SignedIn, SignedOut } from "@clerk/nextjs"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import Link from "next/link"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useCallback } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { getUserData, getWhishperRecordings } from "../actions"; +import LoadingSpinner from "@/components/loading-spinner"; + +function SearchForm() { + const formSchema = z.object({ + query: z.string().min(3).max(256), + }); + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const givenQuery = searchParams.get("query") ?? ""; + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + query: givenQuery, + }, + }); + + const createQueryString = useCallback( + (name: string, value: string) => { + const params = new URLSearchParams(searchParams.toString()); + params.set(name, value); + + return params.toString(); + }, + [searchParams], + ); + + function onSubmit(values: z.infer) { + if (values.query) + router.replace(pathname + "?" + createQueryString("query", values.query)); + } + + return ( +
+ + ( + + Search for your voice recordings + + + + + + )} + /> + + + + ); +} + +function RecordingsList() { + const searchParams = useSearchParams(); + const query = searchParams.get("query"); + + const WhishperRecordings = useQuery({ + queryKey: ["key", query], + queryFn: async () => { + if (!query) { + return Promise.resolve(null); + } + const response = await getWhishperRecordings(query); + return response; + }, + // This ensures the query does not run if there's no query string + enabled: !!query, + }); + + const userData = useQuery({ + queryKey: ["userData"], + queryFn: async () => { + const data = await getUserData(); + return data; + }, + }); + + if (!query) { + return

Start Searching!

; + } + + if (WhishperRecordings.isLoading || userData.isLoading) { + return Loading...; + } else if (!userData.data?.whishperURL) { + return ( +

+ You need to set your paperless url in{" "} + settings +

+ ); + } else if (!WhishperRecordings.data || WhishperRecordings.error) { + return ( +

+ Connection failed! Check that the whishper url is set correctly in{" "} + settings +

+ ); + } + + const WhishperRecordingsMap = WhishperRecordings.data.results; + + if (WhishperRecordingsMap.length === 0) { + return

No results!

; + } + + return ( + <> +

Search Results

+
    + {WhishperRecordingsMap.map((recording, index) => ( +
  • + + {recording.title} + +
  • + ))} +
+ + ); +} + +export default function WhishperPage() { + return ( +
+
+ +
+ Please sign in +
+
+ + + +
+
+ ); +} diff --git a/src/components/topnav.tsx b/src/components/topnav.tsx index 15e63f8..7fe365a 100644 --- a/src/components/topnav.tsx +++ b/src/components/topnav.tsx @@ -130,6 +130,13 @@ export function TopNav() { Paperless-ngx + + Whishper + +
@@ -160,6 +167,16 @@ export function TopNav() { Paperless-ngx + + + + Whishper + + + diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 5104c6a..022c5e2 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -18,6 +18,7 @@ export const users = createTable("users", { userId: varchar("userId", { length: 256 }).notNull().unique(), paperlessURL: varchar("paperlessURL", { length: 256 }), paperlessToken: varchar("paperlessToken", { length: 256 }), + whishperURL: varchar("whishperURL", { length: 256 }), }); -export type UsersTableType = typeof users.$inferSelect; \ No newline at end of file +export type UsersTableType = typeof users.$inferSelect;