Compare commits

...

15 Commits

Author SHA1 Message Date
Mythie 7722e63e1b fix: tidying broke generation 2023-08-31 12:08:53 +10:00
Mythie 14fd0eb906 fix: tidy code and expect jsx errors 2023-08-30 18:41:37 +10:00
Lucas Smith af6c62d0bf Merge branch 'feat/refresh' into feat/blog-og-image 2023-08-30 18:28:21 +10:00
Mythie 8d7d6a19e7 fix: update import for feature-flag helpers 2023-08-30 18:06:41 +10:00
Mythie 463dc48ea6 fix: extract feature-flag zod schema to separate file 2023-08-30 17:31:23 +10:00
Lucas Smith d8f6a25059 Merge pull request #332 from documenso/feat/billing-page
feat: make billing page functional
2023-08-30 16:41:39 +10:00
Mythie 5d4a07bcc5 fix: center align heading 2023-08-30 15:41:29 +10:00
Mythie d28bb5de99 fix: use nextjs opengraph-image component 2023-08-30 15:32:44 +10:00
Lucas Smith 83a83164d4 Merge pull request #330 from documenso/feat/profile-password-form
feat: avoid user from updating password with the same password
2023-08-30 14:32:21 +10:00
Mythie d71e43c5d6 fix: minor tidying 2023-08-30 14:01:30 +10:00
Ephraim Atta-Duncan ed6fa4dc2a feat: avoid updating password with existing password 2023-08-30 03:26:24 +00:00
Ephraim Atta-Duncan 4f3970c361 feat: prevent a user from updating password with the same password 2023-08-30 03:22:47 +00:00
Ephraim Atta-Duncan 40767430d9 feat: reset password from on submit 2023-08-30 03:09:40 +00:00
Ephraim Atta-Duncan 1edfe9548d feat: add og image to blog posts 2023-08-30 02:50:02 +00:00
Ephraim Atta-Duncan 2f78922421 feat: add blog og image 2023-08-30 02:33:22 +00:00
12 changed files with 113 additions and 19 deletions
@@ -0,0 +1,76 @@
import { ImageResponse } from 'next/server';
import { allBlogPosts } from 'contentlayer/generated';
export const runtime = 'edge';
export const size = {
width: 1200,
height: 630,
};
export const contentType = 'image/png';
type BlogPostOpenGraphImageProps = {
params: { post: string };
};
export default async function BlogPostOpenGraphImage({ params }: BlogPostOpenGraphImageProps) {
const blogPost = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`);
if (!blogPost) {
return null;
}
// The long urls are needed for a compiler optimisation on the Next.js side, lifting this up
// to a constant will break og image generation.
const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([
fetch(new URL('./../../../../assets/inter-bold.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
fetch(new URL('./../../../../assets/inter-regular.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
fetch(new URL('./../../../../assets/background-blog-og.png', import.meta.url)).then(
async (res) => res.arrayBuffer(),
),
fetch(new URL('./../../../../../public/logo.png', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
]);
return new ImageResponse(
(
<div tw="relative h-full w-full flex flex-col items-center justify-center text-center">
{/* @ts-expect-error Lack of typing from ImageResponse */}
<img src={backgroundImage} alt="og-background" tw="absolute inset-0 w-full h-full" />
{/* @ts-expect-error Lack of typing from ImageResponse */}
<img src={logoImage} alt="logo" tw="h-8" />
<h1 tw="mt-8 text-6xl text-center flex items-center justify-center w-full max-w-[800px] font-bold text-center mx-auto">
{blogPost.title}
</h1>
<p tw="font-normal">Written by {blogPost.authorName}</p>
</div>
),
{
...size,
fonts: [
{
name: 'Inter',
data: interRegular,
style: 'normal',
weight: 400,
},
{
name: 'Inter',
data: interBold,
style: 'normal',
weight: 700,
},
],
},
);
}
@@ -17,7 +17,9 @@ export const generateMetadata = ({ params }: { params: { post: string } }) => {
notFound();
}
return { title: `Documenso - ${blogPost.title}` };
return {
title: `Documenso - ${blogPost.title}`,
};
};
const mdxComponents: MDXComponents = {
Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.
Binary file not shown.
+4 -1
View File
@@ -39,6 +39,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
const {
register,
handleSubmit,
reset,
formState: { errors, isSubmitting },
} = useForm<TPasswordFormSchema>({
values: {
@@ -56,6 +57,8 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
password,
});
reset();
toast({
title: 'Password updated',
description: 'Your password has been updated successfully.',
@@ -73,7 +76,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
title: 'An unknown error occurred',
variant: 'destructive',
description:
'We encountered an unknown error while attempting to sign you In. Please try again later.',
'We encountered an unknown error while attempting to update your password. Please try again later.',
});
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ import { z } from 'zod';
import { LOCAL_FEATURE_FLAGS, isFeatureFlagEnabled } from '@documenso/lib/constants/feature-flags';
import { TFeatureFlagValue, ZFeatureFlagValueSchema } from '~/providers/feature-flag';
import { TFeatureFlagValue, ZFeatureFlagValueSchema } from '~/providers/feature-flag.types';
/**
* Evaluate whether a flag is enabled for the current user.
+1 -10
View File
@@ -2,8 +2,6 @@
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { z } from 'zod';
import {
FEATURE_FLAG_POLL_INTERVAL,
LOCAL_FEATURE_FLAGS,
@@ -12,14 +10,7 @@ import {
import { getAllFlags } from '~/helpers/get-feature-flag';
export const ZFeatureFlagValueSchema = z.union([
z.boolean(),
z.string(),
z.number(),
z.undefined(),
]);
export type TFeatureFlagValue = z.infer<typeof ZFeatureFlagValueSchema>;
import { TFeatureFlagValue } from './feature-flag.types';
export type FeatureFlagContextValue = {
getFlag: (_key: string) => TFeatureFlagValue;
@@ -0,0 +1,10 @@
import { z } from 'zod';
export const ZFeatureFlagValueSchema = z.union([
z.boolean(),
z.string(),
z.number(),
z.undefined(),
]);
export type TFeatureFlagValue = z.infer<typeof ZFeatureFlagValueSchema>;
+2 -1
View File
@@ -16319,6 +16319,7 @@
}
},
"packages/ee": {
"name": "@documenso/ee",
"version": "1.0.0",
"license": "COMMERCIAL",
"dependencies": {
@@ -16362,7 +16363,7 @@
"packages/lib": {
"name": "@documenso/lib",
"version": "1.0.0",
"license": "SEE LICENSE IN LICENSE",
"license": "MIT",
"dependencies": {
"@documenso/email": "*",
"@documenso/prisma": "*",
@@ -1,4 +1,4 @@
import { hash } from 'bcrypt';
import { compare, hash } from 'bcrypt';
import { prisma } from '@documenso/prisma';
@@ -11,7 +11,7 @@ export type UpdatePasswordOptions = {
export const updatePassword = async ({ userId, password }: UpdatePasswordOptions) => {
// Existence check
await prisma.user.findFirstOrThrow({
const user = await prisma.user.findFirstOrThrow({
where: {
id: userId,
},
@@ -19,6 +19,13 @@ export const updatePassword = async ({ userId, password }: UpdatePasswordOptions
const hashedPassword = await hash(password, SALT_ROUNDS);
// Compare the new password with the old password
const isSamePassword = await compare(password, user.password as string);
if (isSamePassword) {
throw new Error('Your new password cannot be the same as your old password.');
}
const updatedUser = await prisma.user.update({
where: {
id: userId,
@@ -40,12 +40,16 @@ export const profileRouter = router({
password,
});
} catch (err) {
console.error(err);
let message =
'We were unable to update your profile. Please review the information you provided and try again.';
if (err instanceof Error) {
message = err.message;
}
throw new TRPCError({
code: 'BAD_REQUEST',
message:
'We were unable to update your profile. Please review the information you provided and try again.',
message,
});
}
}),