Merge branch 'main' into logo

This commit is contained in:
Lucas Smith
2023-06-17 11:55:54 +10:00
committed by GitHub
49 changed files with 1116 additions and 456 deletions

View File

@@ -30,7 +30,7 @@ export default function PDFEditor(props: any) {
movedField.positionY = position.y.toFixed(0);
createOrUpdateField(props.document, movedField);
// no instant redraw neccessary, postion information for saving or later rerender is enough
// no instant redraw neccessary, position information for saving or later rerender is enough
// setFields(newFields);
}

View File

@@ -0,0 +1,115 @@
import { useState } from "react";
import Link from "next/link";
import { Button } from "@documenso/ui";
import Logo from "./logo";
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
import { FormProvider, useForm } from "react-hook-form";
import { toast } from "react-hot-toast";
interface ForgotPasswordForm {
email: string;
}
export default function ForgotPassword() {
const { register, formState, resetField, handleSubmit } = useForm<ForgotPasswordForm>();
const [resetSuccessful, setResetSuccessful] = useState(false);
const onSubmit = async (values: ForgotPasswordForm) => {
const response = await toast.promise(
fetch(`/api/auth/forgot-password`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
}),
{
loading: "Sending...",
success: "Reset link sent.",
error: "Could not send reset link :/",
}
);
if (!response.ok) {
toast.dismiss();
if (response.status == 404) {
toast.error("Email address not found.");
}
if (response.status == 400) {
toast.error("Password reset requested.");
}
if (response.status == 500) {
toast.error("Something went wrong.");
}
return;
}
if (response.ok) {
setResetSuccessful(true);
}
resetField("email");
};
return (
<>
<div className="flex min-h-full items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8">
<div>
<Logo className="mx-auto h-20 w-auto"></Logo>
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
{resetSuccessful ? "Reset Password" : "Forgot Password?"}
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
{resetSuccessful
? "Please check your email for reset instructions."
: "No worries, we'll send you reset instructions."}
</p>
</div>
{!resetSuccessful && (
<form className="mt-8 space-y-6" onSubmit={handleSubmit(onSubmit)}>
<div className="-space-y-px rounded-md shadow-sm">
<div>
<label htmlFor="email-address" className="sr-only">
Email
</label>
<input
{...register("email")}
id="email-address"
name="email"
type="email"
autoComplete="email"
required
className="focus:border-neon focus:ring-neon relative block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 text-gray-900 placeholder-gray-500 focus:z-10 focus:outline-none sm:text-sm"
placeholder="Email"
/>
</div>
</div>
<div>
<Button
type="submit"
disabled={formState.isSubmitting}
className="group relative flex w-full">
Reset password
</Button>
</div>
</form>
)}
<div>
<Link href="/login">
<div className="relative mt-10 flex items-center justify-center gap-2 text-sm text-gray-500 hover:cursor-pointer hover:text-gray-900">
<ArrowLeftIcon className="h-4 w-4" />
Back to log in
</div>
</Link>
</div>
</div>
</div>
</>
);
}

View File

@@ -3,11 +3,11 @@ import Link from "next/link";
import { useRouter } from "next/router";
import { NEXT_PUBLIC_WEBAPP_URL } from "@documenso/lib/constants";
import { useSubscription } from "@documenso/lib/stripe";
import { BillingWarning } from "./billing-warning";
import Navigation from "./navigation";
import { PaperAirplaneIcon } from "@heroicons/react/24/outline";
import { SubscriptionStatus } from "@prisma/client";
import { useSession } from "next-auth/react";
import { BillingWarning } from "./billing-warning";
function useRedirectToLoginIfUnauthenticated() {
const { data: session, status } = useSession();

View File

@@ -111,9 +111,11 @@ export default function Login(props: any) {
</div>
<div className="flex items-center justify-between">
<div className="text-sm">
<a href="#" className="hover:text-neon-700 font-medium text-gray-500">
<Link
href="/forgot-password"
className="hover:text-neon-700 font-medium text-gray-500">
Forgot your password?
</a>
</Link>
</div>
</div>
<div>

View File

@@ -116,7 +116,6 @@ export default function TopNavigation() {
href="/dashboard"
className="flex flex-shrink-0 items-center gap-x-2 self-center overflow-hidden">
<Logo className="h-8 w-8 text-black" />
<h2 className="text-2xl font-semibold">Documenso</h2>
</Link>
<div className="hidden sm:-my-px sm:ml-6 sm:flex sm:space-x-8">

View File

@@ -0,0 +1,143 @@
import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import { Button } from "@documenso/ui";
import Logo from "./logo";
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { toast } from "react-hot-toast";
import * as z from "zod";
const ZResetPasswordFormSchema = z
.object({
password: z.string().min(8, { message: "Password must be at least 8 characters" }),
confirmPassword: z.string().min(8, { message: "Password must be at least 8 characters" }),
})
.refine((data) => data.password === data.confirmPassword, {
path: ["confirmPassword"],
message: "Password don't match",
});
type TResetPasswordFormSchema = z.infer<typeof ZResetPasswordFormSchema>;
export default function ResetPassword() {
const router = useRouter();
const { token } = router.query;
const {
register,
formState: { errors, isSubmitting },
handleSubmit,
} = useForm<TResetPasswordFormSchema>({
resolver: zodResolver(ZResetPasswordFormSchema),
});
const [resetSuccessful, setResetSuccessful] = useState(false);
const onSubmit = async ({ password }: TResetPasswordFormSchema) => {
const response = await toast.promise(
fetch(`/api/auth/reset-password`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ password, token }),
}),
{
loading: "Resetting...",
success: `Reset password successful`,
error: "Could not reset password :/",
}
);
if (!response.ok) {
toast.dismiss();
const error = await response.json();
toast.error(error.message);
}
if (response.ok) {
setResetSuccessful(true);
setTimeout(() => {
router.push("/login");
}, 3000);
}
};
return (
<>
<div className="flex min-h-full items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8">
<div>
<Logo className="mx-auto h-20 w-auto"></Logo>
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
Reset Password
</h2>
<p className="mt-2 text-center text-sm text-gray-600">
{resetSuccessful ? "Your password has been reset." : "Please chose your new password"}
</p>
</div>
{!resetSuccessful && (
<form className="mt-8 space-y-6" onSubmit={handleSubmit(onSubmit)}>
<div className="-space-y-px rounded-md shadow-sm">
<div>
<label htmlFor="password" className="sr-only">
Password
</label>
<input
{...register("password", { required: "Password is required" })}
id="password"
name="password"
type="password"
autoComplete="current-password"
required
className="focus:border-neon focus:ring-neon relative block w-full appearance-none rounded-none rounded-t-md border border-gray-300 px-3 py-2 text-gray-900 placeholder-gray-500 focus:z-10 focus:outline-none sm:text-sm"
placeholder="New password"
/>
</div>
<div>
<label htmlFor="confirmPassword" className="sr-only">
Password
</label>
<input
{...register("confirmPassword")}
id="confirmPassword"
name="confirmPassword"
type="password"
required
className="focus:border-neon focus:ring-neon relative block w-full appearance-none rounded-none rounded-b-md border border-gray-300 px-3 py-2 text-gray-900 placeholder-gray-500 focus:z-10 focus:outline-none sm:text-sm"
placeholder="Confirm new password"
/>
</div>
</div>
{errors && (
<span className="text-xs text-red-500">{errors.confirmPassword?.message}</span>
)}
<div>
<Button
type="submit"
disabled={isSubmitting}
className="group relative flex w-full">
Reset password
</Button>
</div>
</form>
)}
<div>
<Link href="/login">
<div className="relative mt-10 flex items-center justify-center gap-2 text-sm text-gray-500 hover:cursor-pointer hover:text-gray-900">
<ArrowLeftIcon className="h-4 w-4" />
Back to log in
</div>
</Link>
</div>
</div>
</div>
</>
);
}