Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: simplify setings page #126

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 86 additions & 116 deletions src/app/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import {
} from "@tanstack/react-query";
import { EyeIcon, EyeOffIcon } from "lucide-react";
import type { UsersTableType } from "@/server/db/schema";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import BodyMessage from "@/components/body-message";

const queryClient = new QueryClient();

Expand All @@ -37,99 +45,35 @@ interface FormProps {
userData: UsersTableType;
}

function PaperlessURL({ setActiveTab, userData }: FormProps) {
const [isAutofilled, setIsAutofilled] = useState(false);
const formSchema = z.object({
URL: z.string(),
});

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
URL: "",
},
});

if (userData.paperlessURL && !isAutofilled) {
form.setValue("URL", userData.paperlessURL);
setIsAutofilled(true);
}

async function onSubmit(values: z.infer<typeof formSchema>) {
if (values.URL == "") {
setActiveTab((prevTab) => prevTab + 2); // Skip api key form
} else {
setActiveTab((prevTab) => prevTab + 1); // Increment activeTab
}
try {
await setUserProperty("paperlessURL", values.URL);
// Operation succeeded, show success toast
toast("Your paperless URL preferences was saved");
// Optionally, move to a new tab or take another action to indicate success
} catch {
// Operation failed, show error toast
toast("Uh oh! Something went wrong.", {
description: "Your Paperless URL preferences were not saved.",
action: {
label: "Go back",
onClick: () => setActiveTab((prevTab) => prevTab - 1), // Go back to try again
},
});
}
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-64 space-y-4">
<FormField
control={form.control}
name="URL"
render={({ field }) => (
<FormItem>
<FormLabel>Paperless URL</FormLabel>
<FormControl>
<Input type="url" {...field} />
</FormControl>
<FormDescription>Leave empty to disable</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}

function PaperlessToken({ setActiveTab, userData }: FormProps) {
const [isAutofilled, setIsAutofilled] = useState(false);
function PaperlessCard({ setActiveTab, userData }: FormProps) {
const [isHidden, setIsHidden] = useState(false);

const formSchema = z.object({
token: z.string(),
PaperlessURL: z.string(),
PaperlessToken: z.string(),
});

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
token: "",
PaperlessURL: userData.paperlessURL ?? "",
PaperlessToken: userData.paperlessToken ?? "",
},
});

if (userData.paperlessToken && !isAutofilled) {
form.setValue("token", userData.paperlessToken);
setIsAutofilled(true);
}

async function onSubmit(values: z.infer<typeof formSchema>) {
setActiveTab((prevTab) => prevTab + 1); // Increment activeTab

try {
await setUserProperty("paperlessToken", values.token);
await setUserProperty("paperlessURL", values.PaperlessURL);
await setUserProperty("paperlessToken", values.PaperlessToken);
// Operation succeeded, show success toast
toast("Your paperless token preferences was saved");
toast("Your paperless preferences was saved");
void queryClient.invalidateQueries({ queryKey: ["userData"] });
// Optionally, move to a new tab or take another action to indicate success
} catch {
// Operation failed, show error toast
toast("Uh oh! Something went wrong.", {
description: "Your Paperless token preferences were not saved.",
description: "Your Paperless preferences were not saved.",
action: {
label: "Go back",
onClick: () => setActiveTab((prevTab) => prevTab - 1), // Go back to try again
Expand All @@ -139,35 +83,64 @@ function PaperlessToken({ setActiveTab, userData }: FormProps) {
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-64 space-y-4">
<FormField
control={form.control}
name="token"
render={({ field }) => (
<FormItem>
<FormLabel>Paperless API Token</FormLabel>
<FormControl>
<div className="flex flex-shrink items-center space-x-2">
<Input type={isHidden ? "text" : "password"} {...field} />
{isHidden ? (
<EyeIcon onClick={() => setIsHidden(false)} />
) : (
<EyeOffIcon onClick={() => setIsHidden(true)} />
)}
</div>
</FormControl>
<FormDescription>
You can create (or re-create) an API token by opening the
&quot;My Profile&quot; link in the user dropdown found in the
web UI and clicking the circular arrow button.
</FormDescription>
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
<Card>
<CardHeader>
<CardTitle>Paperless settings</CardTitle>
<CardDescription>Paperless ngx is a pdf organizer</CardDescription>
</CardHeader>
<CardContent className="items-center justify-center">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="w-64 space-y-4"
>
<FormField
control={form.control}
name="PaperlessURL"
render={({ field }) => (
<FormItem>
<FormLabel>Paperless URL</FormLabel>
<FormControl>
<Input type="url" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="PaperlessToken"
render={({ field }) => (
<FormItem>
<FormItem>
<FormLabel>Paperless API Token</FormLabel>
<FormControl>
<div className="flex flex-shrink items-center space-x-2">
<Input
type={isHidden ? "text" : "password"}
{...field}
/>
{isHidden ? (
<EyeIcon onClick={() => setIsHidden(false)} />
) : (
<EyeOffIcon onClick={() => setIsHidden(true)} />
)}
</div>
</FormControl>
<FormDescription>
You can create (or re-create) an API token by opening the
&quot;My Profile&quot; link in the user dropdown found in
the web UI and clicking the circular arrow button.
</FormDescription>
</FormItem>
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
</CardContent>
</Card>
);
}

Expand Down Expand Up @@ -199,6 +172,7 @@ function WhishperURL({ setActiveTab, userData }: FormProps) {
await setUserProperty("whishperURL", values.URL);
// Operation succeeded, show success toast
toast("Your whishper URL preferences was saved");
void queryClient.invalidateQueries({ queryKey: ["userData"] });
// Optionally, move to a new tab or take another action to indicate success
} catch {
// Operation failed, show error toast
Expand Down Expand Up @@ -263,46 +237,42 @@ const ProgressIndicator: React.FC<ProgressIndicatorProps> = ({

export function Forms() {
const [activeTab, setActiveTab] = useState(0);
const { user: clerkUser, isLoaded } = useUser();
const { user: clerkUser, isLoaded: clerkUserIsLoaded } = useUser();
const pathname = usePathname();

const { data: userData, isLoading } = useQuery({
const { data: userData, isLoading: userDataIsLoading } = useQuery({
queryKey: ["userData"],
queryFn: async () => {
const data = await getUserData();
return data;
},
});

if (!userData || isLoading || !isLoaded) {
if (!userData || userDataIsLoading || !clerkUserIsLoaded) {
return <LoadingSpinner>Loading...</LoadingSpinner>;
} else if (!clerkUser) {
return redirect("/sign-in?redirect=" + pathname);
}

const formElements = [
<PaperlessURL
<PaperlessCard
key="paperlessURL"
setActiveTab={setActiveTab}
userData={userData}
/>,
<PaperlessToken
key="paperlessToken"
setActiveTab={setActiveTab}
userData={userData}
/>,
<WhishperURL
key="paperlessToken"
setActiveTab={setActiveTab}
userData={userData}
/>,
<BodyMessage key="done">All done</BodyMessage>,
];
return (
<>
{formElements[activeTab]}
<ProgressIndicator
activeTab={activeTab}
totalTabs={formElements.length}
totalTabs={formElements.length - 1}
setActiveTab={setActiveTab}
/>
</>
Expand Down
79 changes: 79 additions & 0 deletions src/components/ui/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as React from "react"

import { cn } from "@/lib/utils"

const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-slate-200 bg-white text-slate-950 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
className
)}
{...props}
/>
))
Card.displayName = "Card"

const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"

const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"

const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-slate-500 dark:text-slate-400", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"

const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"

const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
Loading