Compare commits

..

20 Commits

Author SHA1 Message Date
Ephraim Atta-Duncan
6640f0496a feat: disable signing and editing for completed documents 2023-09-06 10:40:45 +00:00
Lucas Smith
de3ebe16ee Merge pull request #349 from documenso/feat/marketing-mobile-nav
feat: update marketing mobile nav
2023-09-05 18:20:53 +10:00
David Nguyen
84a2d3baf6 feat: update marketing mobile menu 2023-09-05 18:08:29 +10:00
Lucas Smith
74180defd1 Merge pull request #339 from G3root/feat-api-error
feat: add alert banner for errors in sigin page
2023-09-05 15:36:55 +10:00
Lucas Smith
aeeaaf0d8d Merge pull request #340 from G3root/fix-username-updateable
fix: user name not updatable
2023-09-05 15:33:19 +10:00
Lucas Smith
2b84293c4e Merge pull request #341 from documenso/feat/add-email-field
feat: add email field to document sign page
2023-09-05 13:25:29 +10:00
Lucas Smith
b38ef6c0a7 Merge pull request #346 from documenso/chore/remove-console-log-warn
chore: removed console logs and warn
2023-09-05 13:23:57 +10:00
Mythie
17af4d25bd fix: actually make timeouts clear 2023-09-05 11:33:49 +10:00
Mythie
6e095921e6 fix: tidy up code 2023-09-05 11:29:23 +10:00
nafees nazik
150c42b246 fix: value 2023-09-04 22:24:42 +05:30
Catalin Pit
aecf2f32b9 chore: removed one more console.log 2023-09-04 16:41:28 +03:00
Catalin Pit
b23967d777 chore: removed console.logs and warn 2023-09-04 16:08:22 +03:00
nafees nazik
7bcc26a987 fix: user name not updatable 2023-09-02 12:11:07 +05:30
nafees nazik
692722d32e revert: fix: component style 2023-09-02 11:55:44 +05:30
Nafees Nazik
e4f06d8e30 Merge branch 'feat/refresh' into feat-api-error 2023-09-02 11:53:18 +05:30
nafees nazik
c799380787 chore: add comments 2023-09-02 11:51:21 +05:30
nafees nazik
5540fcf0d2 fix: use toast 2023-09-02 11:46:12 +05:30
nafees nazik
d9da09c1e7 fix: typo 2023-09-01 16:25:49 +05:30
nafees nazik
fe90aa3b7b feat: add api error 2023-09-01 16:25:27 +05:30
nafees nazik
0c680e0111 fix: component style 2023-09-01 16:25:00 +05:30
9 changed files with 58 additions and 49 deletions

View File

@@ -22,6 +22,10 @@ export const MENU_NAVIGATION_LINKS = [
href: '/pricing', href: '/pricing',
text: 'Pricing', text: 'Pricing',
}, },
{
href: '/open',
text: 'Open',
},
{ {
href: 'https://status.documenso.com', href: 'https://status.documenso.com',
text: 'Status', text: 'Status',
@@ -59,7 +63,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
initial="initial" initial="initial"
animate="animate" animate="animate"
transition={{ transition={{
staggerChildren: 0.2, staggerChildren: 0.03,
}} }}
> >
{MENU_NAVIGATION_LINKS.map(({ href, text }) => ( {MENU_NAVIGATION_LINKS.map(({ href, text }) => (
@@ -75,6 +79,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat
x: 0, x: 0,
transition: { transition: {
duration: 0.5, duration: 0.5,
ease: 'backInOut',
}, },
}, },
}} }}

View File

@@ -82,14 +82,14 @@ export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) =
<DropdownMenuContent className="w-52" align="start" forceMount> <DropdownMenuContent className="w-52" align="start" forceMount>
<DropdownMenuLabel>Action</DropdownMenuLabel> <DropdownMenuLabel>Action</DropdownMenuLabel>
<DropdownMenuItem disabled={!recipient} asChild> <DropdownMenuItem disabled={!recipient || isComplete} asChild>
<Link href={`/sign/${recipient?.token}`}> <Link href={`/sign/${recipient?.token}`}>
<Pencil className="mr-2 h-4 w-4" /> <Pencil className="mr-2 h-4 w-4" />
Sign Sign
</Link> </Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem disabled={!isOwner} asChild> <DropdownMenuItem disabled={!isOwner || isComplete} asChild>
<Link href={`/documents/${row.id}`}> <Link href={`/documents/${row.id}`}>
<Edit className="mr-2 h-4 w-4" /> <Edit className="mr-2 h-4 w-4" />
Edit Edit

View File

@@ -44,7 +44,7 @@ export const ProfileForm = ({ className, user }: ProfileFormProps) => {
} = useForm<TProfileFormSchema>({ } = useForm<TProfileFormSchema>({
values: { values: {
name: user.name ?? '', name: user.name ?? '',
signature: '', signature: user.signature || '',
}, },
resolver: zodResolver(ZProfileFormSchema), resolver: zodResolver(ZProfileFormSchema),
}); });

View File

@@ -1,5 +1,9 @@
'use client'; 'use client';
import { useEffect } from 'react';
import { useSearchParams } from 'next/navigation';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Loader } from 'lucide-react'; import { Loader } from 'lucide-react';
import { signIn } from 'next-auth/react'; import { signIn } from 'next-auth/react';
@@ -7,12 +11,20 @@ import { useForm } from 'react-hook-form';
import { FcGoogle } from 'react-icons/fc'; import { FcGoogle } from 'react-icons/fc';
import { z } from 'zod'; import { z } from 'zod';
import { ErrorCode, isErrorCode } from '@documenso/lib/next-auth/error-codes';
import { cn } from '@documenso/ui/lib/utils'; import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button'; import { Button } from '@documenso/ui/primitives/button';
import { Input } from '@documenso/ui/primitives/input'; import { Input } from '@documenso/ui/primitives/input';
import { Label } from '@documenso/ui/primitives/label'; import { Label } from '@documenso/ui/primitives/label';
import { useToast } from '@documenso/ui/primitives/use-toast'; import { useToast } from '@documenso/ui/primitives/use-toast';
const ErrorMessages = {
[ErrorCode.CREDENTIALS_NOT_FOUND]: 'The email or password provided is incorrect',
[ErrorCode.INCORRECT_EMAIL_PASSWORD]: 'The email or password provided is incorrect',
[ErrorCode.USER_MISSING_PASSWORD]:
'This account appears to be using a social login method, please sign in using that method',
};
export const ZSignInFormSchema = z.object({ export const ZSignInFormSchema = z.object({
email: z.string().email().min(1), email: z.string().email().min(1),
password: z.string().min(6).max(72), password: z.string().min(6).max(72),
@@ -26,6 +38,7 @@ export type SignInFormProps = {
export const SignInForm = ({ className }: SignInFormProps) => { export const SignInForm = ({ className }: SignInFormProps) => {
const { toast } = useToast(); const { toast } = useToast();
const searchParams = useSearchParams();
const { const {
register, register,
@@ -39,6 +52,27 @@ export const SignInForm = ({ className }: SignInFormProps) => {
resolver: zodResolver(ZSignInFormSchema), resolver: zodResolver(ZSignInFormSchema),
}); });
const errorCode = searchParams?.get('error');
useEffect(() => {
let timeout: NodeJS.Timeout | null = null;
if (isErrorCode(errorCode)) {
timeout = setTimeout(() => {
toast({
variant: 'destructive',
description: ErrorMessages[errorCode] ?? 'An unknown error occurred',
});
}, 0);
}
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, [errorCode, toast]);
const onFormSubmit = async ({ email, password }: TSignInFormSchema) => { const onFormSubmit = async ({ email, password }: TSignInFormSchema) => {
try { try {
await signIn('credentials', { await signIn('credentials', {

View File

@@ -7,7 +7,7 @@ import GoogleProvider, { GoogleProfile } from 'next-auth/providers/google';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { getUserByEmail } from '../server-only/user/get-user-by-email'; import { getUserByEmail } from '../server-only/user/get-user-by-email';
import { ErrorCodes } from './error-codes'; import { ErrorCode } from './error-codes';
export const NEXT_AUTH_OPTIONS: AuthOptions = { export const NEXT_AUTH_OPTIONS: AuthOptions = {
adapter: PrismaAdapter(prisma), adapter: PrismaAdapter(prisma),
@@ -24,23 +24,23 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
}, },
authorize: async (credentials, _req) => { authorize: async (credentials, _req) => {
if (!credentials) { if (!credentials) {
throw new Error(ErrorCodes.CredentialsNotFound); throw new Error(ErrorCode.CREDENTIALS_NOT_FOUND);
} }
const { email, password } = credentials; const { email, password } = credentials;
const user = await getUserByEmail({ email }).catch(() => { const user = await getUserByEmail({ email }).catch(() => {
throw new Error(ErrorCodes.IncorrectEmailPassword); throw new Error(ErrorCode.INCORRECT_EMAIL_PASSWORD);
}); });
if (!user.password) { if (!user.password) {
throw new Error(ErrorCodes.UserMissingPassword); throw new Error(ErrorCode.USER_MISSING_PASSWORD);
} }
const isPasswordsSame = await compare(password, user.password); const isPasswordsSame = await compare(password, user.password);
if (!isPasswordsSame) { if (!isPasswordsSame) {
throw new Error(ErrorCodes.IncorrectEmailPassword); throw new Error(ErrorCode.INCORRECT_EMAIL_PASSWORD);
} }
return { return {

View File

@@ -1,5 +1,11 @@
export const ErrorCodes = { export const isErrorCode = (code: unknown): code is ErrorCode => {
IncorrectEmailPassword: 'incorrect-email-password', return typeof code === 'string' && code in ErrorCode;
UserMissingPassword: 'missing-password', };
CredentialsNotFound: 'credentials-not-found',
export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
export const ErrorCode = {
INCORRECT_EMAIL_PASSWORD: 'INCORRECT_EMAIL_PASSWORD',
USER_MISSING_PASSWORD: 'USER_MISSING_PASSWORD',
CREDENTIALS_NOT_FOUND: 'CREDENTIALS_NOT_FOUND',
} as const; } as const;

View File

@@ -83,10 +83,7 @@ export const completeDocumentWithToken = async ({
}, },
}); });
console.log('documents', documents);
if (documents.count > 0) { if (documents.count > 0) {
console.log('sealing document');
await sealDocument({ documentId: document.id }); await sealDocument({ documentId: document.id });
} }
}; };

View File

@@ -53,10 +53,6 @@ export const sealDocument = async ({ documentId }: SealDocumentOptions) => {
const doc = await PDFDocument.load(pdfData); const doc = await PDFDocument.load(pdfData);
for (const field of fields) { for (const field of fields) {
console.log('inserting field', {
...field,
Signature: null,
});
await insertFieldInPDF(doc, field); await insertFieldInPDF(doc, field);
} }

View File

@@ -35,15 +35,6 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
const fieldX = pageWidth * (Number(field.positionX) / 100); const fieldX = pageWidth * (Number(field.positionX) / 100);
const fieldY = pageHeight * (Number(field.positionY) / 100); const fieldY = pageHeight * (Number(field.positionY) / 100);
console.log({
fieldWidth,
fieldHeight,
fieldX,
fieldY,
pageWidth,
pageHeight,
});
const font = await pdf.embedFont(isSignatureField ? fontCaveat : StandardFonts.Helvetica); const font = await pdf.embedFont(isSignatureField ? fontCaveat : StandardFonts.Helvetica);
if (field.type === FieldType.SIGNATURE || field.type === FieldType.FREE_SIGNATURE) { if (field.type === FieldType.SIGNATURE || field.type === FieldType.FREE_SIGNATURE) {
@@ -75,15 +66,6 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
// Invert the Y axis since PDFs use a bottom-left coordinate system // Invert the Y axis since PDFs use a bottom-left coordinate system
imageY = pageHeight - imageY - imageHeight; imageY = pageHeight - imageY - imageHeight;
console.log({
initialDimensions,
scalingFactor,
imageWidth,
imageHeight,
imageX,
imageY,
});
page.drawImage(image, { page.drawImage(image, {
x: imageX, x: imageX,
y: imageY, y: imageY,
@@ -107,17 +89,6 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
const textX = fieldX + (fieldWidth - textWidth) / 2; const textX = fieldX + (fieldWidth - textWidth) / 2;
let textY = fieldY + (fieldHeight - textHeight) / 2; let textY = fieldY + (fieldHeight - textHeight) / 2;
console.log({
initialDimensions,
scalingFactor,
textWidth,
textHeight,
textX,
textY,
pageWidth,
pageHeight,
});
// Invert the Y axis since PDFs use a bottom-left coordinate system // Invert the Y axis since PDFs use a bottom-left coordinate system
textY = pageHeight - textY - textHeight; textY = pageHeight - textY - textHeight;