Skip to content
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
4 changes: 2 additions & 2 deletions apps/page/components/subscribe-prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ export default function SubscribePrompt({

const pageUrl = useMemo(() => getPageUrl(page, settings), [page, settings]);

const NewPageSchema = Yup.object().shape({
const InputSchema = Yup.object().shape({
email: Yup.string().email().required("Enter a valid email"),
});

const formik = useFormik({
initialValues: {
email: "",
},
validationSchema: NewPageSchema,
validationSchema: InputSchema,
onSubmit: async (values) => {
setLoading(true);
try {
Expand Down
32 changes: 8 additions & 24 deletions apps/web/components/forms/page-form.component.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
import {
IPage,
PageType,
PageTypeToLabel
} from "@changes-page/supabase/types/page";
import { Spinner, SpinnerWithSpacing } from "@changes-page/ui";
import classNames from "classnames";
import { FormikProps, useFormik } from "formik";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import slugify from "slugify";
import { InferType, object, string } from "yup";
import {
IPage,
PageType,
PageTypeToLabel,
URL_SLUG_REGEX,
} from "@changes-page/supabase/types/page";
import { InferType } from "yup";
import { NewPageSchema } from "../../data/schema";
import { PrimaryButton, SecondaryButton } from "../core/buttons.component";
import { Spinner, SpinnerWithSpacing } from "@changes-page/ui";
import { InfoMessage, InlineErrorMessage } from "./notification.component";

export const NewPageSchema = object().shape({
url_slug: string()
.min(4, "Too Short!")
.max(24, "Too Long!")
.required("Enter a valid url")
.matches(URL_SLUG_REGEX, "Enter a valid url"),
title: string()
.required("Enter a valid title")
.min(2, "Title too Short!")
.max(50, "Title too Long!"),
description: string()
.min(2, "Description too Short!")
.max(500, "Description too Long!"),
type: string().required("Enter a valid type"),
});

export type PageFormikForm = FormikProps<InferType<typeof NewPageSchema>>;

export default function PageFormComponent({
Expand Down
27 changes: 2 additions & 25 deletions apps/web/components/forms/post-form.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import { useFormik } from "formik";
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
import ReactMarkdown from "react-markdown";
import { v4 } from "uuid";
import { InferType, array, boolean, mixed, object, string } from "yup";
import { InferType } from "yup";
import { NewPostSchema } from "../../data/schema";
import { track } from "../../utils/analytics";
import { useUserData } from "../../utils/useUser";
import { PrimaryButton } from "../core/buttons.component";
Expand All @@ -31,30 +32,6 @@ import AiSuggestTitlePromptDialogComponent from "../dialogs/ai-suggest-title-pro
import DateTimePromptDialog from "../dialogs/date-time-prompt-dialog.component";
import SwitchComponent from "./switch.component";

export const NewPostSchema = object().shape({
title: string()
.required("Title cannot be empty")
.min(2, "Title too Short!")
.max(75, "Title too Long!"),
content: string()
.required("Content cannot be empty")
.min(2, "Content too Short!")
.max(9669, "Content too Long!"),
tags: array()
.of(mixed<PostType>().oneOf(Object.values(PostType)))
.required("Enter valid tags"),
status: mixed<PostStatus>()
.oneOf(Object.values(PostStatus))
.required("Enter valid status"),
page_id: string(),
images_folder: string(),
publish_at: string().optional().nullable(),
publication_date: string().optional().nullable(),
allow_reactions: boolean(),
email_notified: boolean(),
notes: string().optional().nullable(),
});

export type PostFormikForm = InferType<typeof NewPostSchema>;

export default function PostFormComponent({
Expand Down
8 changes: 5 additions & 3 deletions apps/web/components/layout/blog-layout.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DateTime } from "@changes-page/utils";
import { ArrowLeftIcon } from "@heroicons/react/solid";
import classNames from "classnames";
import Head from "next/head";
import Image from "next/image";
Expand Down Expand Up @@ -146,9 +147,10 @@ export default function BlogLayout({
<h1>
<Link
href={ROUTES.BLOG}
className="block text-center text-lg font-semibold text-indigo-600 dark:text-indigo-400 uppercase"
className="block text-center text-md font-semibold text-indigo-600 dark:text-indigo-400"
>
Blog
<ArrowLeftIcon className="inline w-4 h-4 -mt-1 font-semibold" />{" "}
Back to blog
</Link>
<span className="mt-2 block text-center text-3xl font-bold leading-8 tracking-tight text-gray-900 dark:text-gray-50 sm:text-4xl hero">
{title}
Expand Down Expand Up @@ -198,7 +200,7 @@ export default function BlogLayout({
/>
) : null}

<div className="blog-content-override prose dark:prose-invert prose-indigo mx-auto mt-6">
<div className="blog-content-override prose dark:prose-invert prose-indigo mx-auto mt-6 max-w-[70ch]">
<ReactMarkdown
rehypePlugins={[
rehypeRaw,
Expand Down
42 changes: 42 additions & 0 deletions apps/web/data/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { PostStatus, PostType, URL_SLUG_REGEX } from "@changes-page/supabase/types/page";
import { array, boolean, mixed, object, string } from "yup";

export const NewPageSchema = object().shape({
url_slug: string()
.min(4, "Too Short!")
.max(24, "Too Long!")
.required("Enter a valid url")
.matches(URL_SLUG_REGEX, "Enter a valid url"),
title: string()
.required("Enter a valid title")
.min(2, "Title too Short!")
.max(50, "Title too Long!"),
description: string()
.min(2, "Description too Short!")
.max(500, "Description too Long!"),
type: string().required("Enter a valid type"),
});

export const NewPostSchema = object().shape({
title: string()
.required("Title cannot be empty")
.min(2, "Title too Short!")
.max(75, "Title too Long!"),
content: string()
.required("Content cannot be empty")
.min(2, "Content too Short!")
.max(9669, "Content too Long!"),
tags: array()
.of(mixed<PostType>().oneOf(Object.values(PostType)))
.required("Enter valid tags"),
status: mixed<PostStatus>()
.oneOf(Object.values(PostStatus))
.required("Enter valid status"),
page_id: string(),
images_folder: string(),
publish_at: string().optional().nullable(),
publication_date: string().optional().nullable(),
allow_reactions: boolean(),
email_notified: boolean(),
notes: string().optional().nullable(),
});
14 changes: 14 additions & 0 deletions apps/web/pages/api/pages/new.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IErrorResponse } from "@changes-page/supabase/types/api";
import { IPage } from "@changes-page/supabase/types/page";
import type { NextApiRequest, NextApiResponse } from "next";
import { NewPageSchema } from "../../../data/schema";
import { apiRateLimiter } from "../../../utils/rate-limit";
import { getSupabaseServerClient } from "../../../utils/supabase/supabase-admin";
import {
Expand Down Expand Up @@ -28,6 +29,19 @@ const createNewPage = async (
});
}

const isValid = await NewPageSchema.isValid({
url_slug,
title: title.trim(),
description: description.trim(),
type,
});

if (!isValid) {
return res.status(400).json({
error: { statusCode: 400, message: "Invalid request body" },
});
}

console.log("createNewPage", user?.id);

const data = await createPage({
Expand Down
21 changes: 21 additions & 0 deletions apps/web/pages/api/posts/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PostStatus } from "@changes-page/supabase/types/page";
import { NextApiRequest, NextApiResponse } from "next";
import { NewPostSchema } from "../../../data/schema";
import { apiRateLimiter } from "../../../utils/rate-limit";
import { getSupabaseServerClient } from "../../../utils/supabase/supabase-admin";
import { createPost, getUserById } from "../../../utils/useDatabase";
Expand Down Expand Up @@ -32,6 +33,26 @@ const createNewPost = async (req: NextApiRequest, res: NextApiResponse) => {
});
}

const isValid = await NewPostSchema.isValid({
page_id,
title: title.trim(),
content: content.trim(),
tags,
status,
images_folder,
publish_at,
notes,
allow_reactions,
email_notified,
publication_date,
});

if (!isValid) {
return res.status(400).json({
error: { statusCode: 400, message: "Invalid request body" },
});
}

console.log("createNewPost", user?.id);

const post = await createPost({
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/pages/[page_id]/[post_id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useState } from "react";
import { InferType } from "yup";
import { notifyError } from "../../../components/core/toast.component";
import PostFormComponent, {
NewPostSchema,
PostFormikForm,
} from "../../../components/forms/post-form.component";
import AuthLayout from "../../../components/layout/auth-layout.component";
import Page from "../../../components/layout/page.component";
import { ROUTES } from "../../../data/routes.data";
import { NewPostSchema } from "../../../data/schema";
import { getSupabaseServerClient } from "../../../utils/supabase/supabase-admin";
import { createOrRetrievePageSettings } from "../../../utils/useDatabase";
import { useUserData } from "../../../utils/useUser";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/pages/[page_id]/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useState } from "react";
import { InferType } from "yup";
import { notifyError } from "../../../components/core/toast.component";
import PageFormComponent, {
NewPageSchema,
PageFormikForm,
} from "../../../components/forms/page-form.component";
import AuthLayout from "../../../components/layout/auth-layout.component";
import Page from "../../../components/layout/page.component";
import { ROUTES } from "../../../data/routes.data";
import { NewPageSchema } from "../../../data/schema";
import { httpPost } from "../../../utils/http";
import { getSupabaseServerClient } from "../../../utils/supabase/supabase-admin";
import { getPage } from "../../../utils/useSSR";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/pages/[page_id]/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useState } from "react";
import { InferType } from "yup";
import { notifyError } from "../../../components/core/toast.component";
import PostFormComponent, {
NewPostSchema,
PostFormikForm,
} from "../../../components/forms/post-form.component";
import AuthLayout from "../../../components/layout/auth-layout.component";
import Page from "../../../components/layout/page.component";
import { ROUTES } from "../../../data/routes.data";
import { NewPostSchema } from "../../../data/schema";
import { track } from "../../../utils/analytics";
import { httpPost } from "../../../utils/http";
import { getSupabaseServerClient } from "../../../utils/supabase/supabase-admin";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/pages/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { useState } from "react";
import { InferType } from "yup";
import { notifyError } from "../../components/core/toast.component";
import PageFormComponent, {
NewPageSchema,
PageFormikForm,
} from "../../components/forms/page-form.component";
import AuthLayout from "../../components/layout/auth-layout.component";
import Page from "../../components/layout/page.component";
import { ROUTES } from "../../data/routes.data";
import { NewPageSchema } from "../../data/schema";
import { track } from "../../utils/analytics";
import { httpPost } from "../../utils/http";

Expand Down
4 changes: 4 additions & 0 deletions apps/web/utils/useDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ export const updateSubscriptionUsage = async (
) => {
const user = await getUserById(user_id);

if (user.pro_gifted) {
return false;
}

if (!user.stripe_customer_id || !user.stripe_subscription_id) {
return false;
}
Expand Down