diff --git a/apps/roboshield/.env b/apps/roboshield/.env index bd685430f..c2e3f6f24 100644 --- a/apps/roboshield/.env +++ b/apps/roboshield/.env @@ -9,3 +9,6 @@ SENTRY_PROJECT=roboshield NEXT_PUBLIC_IMAGE_DOMAINS="*.codeforafrica.org" NEXT_PUBLIC_IMAGE_UNOPTIMIZED="true" + +NEXT_PUBLIC_APP_URL=http://localhost:3000 +PAYLOAD_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL diff --git a/apps/roboshield/payload-types.ts b/apps/roboshield/payload-types.ts index f7b1d2b82..7677cb90d 100644 --- a/apps/roboshield/payload-types.ts +++ b/apps/roboshield/payload-types.ts @@ -74,7 +74,7 @@ export interface Page { blockType: "mediaBlock"; } | { - externalEmbeddFields?: { + externalEmbedFields?: { embedType?: ("url" | "code") | null; url?: string | null; caption?: string | null; @@ -82,7 +82,7 @@ export interface Page { }; id?: string | null; blockName?: string | null; - blockType: "externalEmbedd"; + blockType: "externalEmbed"; } )[] | null; diff --git a/apps/roboshield/payload.config.ts b/apps/roboshield/payload.config.ts index 7bc788338..aa86376ff 100644 --- a/apps/roboshield/payload.config.ts +++ b/apps/roboshield/payload.config.ts @@ -1,5 +1,3 @@ -import path from "path"; - import { buildConfig } from "payload/config"; import { slateEditor } from "@payloadcms/richtext-slate"; import { mongooseAdapter } from "@payloadcms/db-mongodb"; @@ -99,7 +97,7 @@ export default buildConfig({ }, }), seo({ - collections: ["pages", "posts"], + collections: ["pages"], globals: [], uploadsCollection: "media", generateTitle: ({ doc }: any) => doc?.title?.value as string, diff --git a/apps/roboshield/public/images/cms/blocks/blockBots.png b/apps/roboshield/public/images/cms/blocks/blockBots.png new file mode 100644 index 000000000..68100afa9 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/blockBots.png differ diff --git a/apps/roboshield/public/images/cms/blocks/blog.png b/apps/roboshield/public/images/cms/blocks/blog.png new file mode 100644 index 000000000..c937c8e2e Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/blog.png differ diff --git a/apps/roboshield/public/images/cms/blocks/delays.png b/apps/roboshield/public/images/cms/blocks/delays.png new file mode 100644 index 000000000..a3ce8f315 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/delays.png differ diff --git a/apps/roboshield/public/images/cms/blocks/existingRobots.png b/apps/roboshield/public/images/cms/blocks/existingRobots.png new file mode 100644 index 000000000..36892153b Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/existingRobots.png differ diff --git a/apps/roboshield/public/images/cms/blocks/finish.png b/apps/roboshield/public/images/cms/blocks/finish.png new file mode 100644 index 000000000..18e0f5f94 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/finish.png differ diff --git a/apps/roboshield/public/images/cms/blocks/hero.png b/apps/roboshield/public/images/cms/blocks/hero.png new file mode 100644 index 000000000..097757658 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/hero.png differ diff --git a/apps/roboshield/public/images/cms/blocks/pageHeader.png b/apps/roboshield/public/images/cms/blocks/pageHeader.png new file mode 100644 index 000000000..4ebc71a0d Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/pageHeader.png differ diff --git a/apps/roboshield/public/images/cms/blocks/paths.png b/apps/roboshield/public/images/cms/blocks/paths.png new file mode 100644 index 000000000..61f8d4632 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/paths.png differ diff --git a/apps/roboshield/public/images/cms/blocks/robotsGenerator.png b/apps/roboshield/public/images/cms/blocks/robotsGenerator.png new file mode 100644 index 000000000..6f4fb31ac Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/robotsGenerator.png differ diff --git a/apps/roboshield/public/images/cms/blocks/siteMaps.png b/apps/roboshield/public/images/cms/blocks/siteMaps.png new file mode 100644 index 000000000..aa7b83c73 Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/siteMaps.png differ diff --git a/apps/roboshield/public/images/cms/blocks/statistics.png b/apps/roboshield/public/images/cms/blocks/statistics.png new file mode 100644 index 000000000..7feefbfff Binary files /dev/null and b/apps/roboshield/public/images/cms/blocks/statistics.png differ diff --git a/apps/roboshield/src/components/Content/Content.tsx b/apps/roboshield/src/components/Content/Content.tsx index 66f914f00..5f1a04ba8 100644 --- a/apps/roboshield/src/components/Content/Content.tsx +++ b/apps/roboshield/src/components/Content/Content.tsx @@ -14,9 +14,9 @@ type ContentProps = ExtractBlockType< "content" >; -export type ExternalEmbeddBlock = ExtractNestedBlockType< +export type ExternalEmbedBlock = ExtractNestedBlockType< NonNullable[number], - "externalEmbedd" + "externalEmbed" >; export type RichTextBlock = ExtractNestedBlockType< @@ -32,14 +32,14 @@ export type MediaBlock = ExtractNestedBlockType< type ComponentMap = { richtext: React.FC; mediaBlock: React.FC; - externalEmbedd: React.FC; + externalEmbed: React.FC; }; export default function Content({ content }: ContentProps) { const COMPONENT_BY_CONTENT_TYPE: ComponentMap = { richtext: LongFormRichText, mediaBlock: LongFormMedia, - externalEmbedd: LongFormExternalEmbed, + externalEmbed: LongFormExternalEmbed, }; return ( diff --git a/apps/roboshield/src/components/LongFormExternalEmbed/LongFormExternalEmbed.tsx b/apps/roboshield/src/components/LongFormExternalEmbed/LongFormExternalEmbed.tsx index 7f75a2a79..54a38fbdc 100644 --- a/apps/roboshield/src/components/LongFormExternalEmbed/LongFormExternalEmbed.tsx +++ b/apps/roboshield/src/components/LongFormExternalEmbed/LongFormExternalEmbed.tsx @@ -1,10 +1,10 @@ import { RichTypography } from "@commons-ui/core"; import { Box } from "@mui/material"; import React from "react"; -import { ExternalEmbeddBlock } from "@/roboshield/components/Content/Content"; +import { ExternalEmbedBlock } from "@/roboshield/components/Content/Content"; -export default function LongFormExternalEmbed(props: ExternalEmbeddBlock) { - const { externalEmbeddFields: { code = "", caption = "", url = "" } = {} } = +export default function LongFormExternalEmbed(props: ExternalEmbedBlock) { + const { externalEmbedFields: { code = "", caption = "", url = "" } = {} } = props; return ( diff --git a/apps/roboshield/src/pages/api/draft.ts b/apps/roboshield/src/pages/api/draft.ts new file mode 100644 index 000000000..98e12f703 --- /dev/null +++ b/apps/roboshield/src/pages/api/draft.ts @@ -0,0 +1,28 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +type User = object; + +interface CustomNextApiRequest extends NextApiRequest { + user: User; + query: { + slug: string; + [key: string]: string | string[]; + }; +} + +export default async function handler( + req: CustomNextApiRequest, + res: NextApiResponse, +) { + if (!req.user) { + return res.status(401).json({ message: "UNAUTHORIZED_USER" }); + } + const { slug = "/" } = req.query; + res.setDraftMode({ enable: true }); + const appUrl = new URL(process.env.NEXT_PUBLIC_APP_URL ?? ""); + const requestedUrl = new URL(slug, appUrl); + if (requestedUrl.origin !== appUrl.origin) { + return res.status(401).json({ message: "UNAUTHORIZED_REDIRECT" }); + } + return res.redirect(requestedUrl.pathname); +} diff --git a/apps/roboshield/src/payload/blocks/Content.ts b/apps/roboshield/src/payload/blocks/Content.ts index 272c0dc80..566f40555 100644 --- a/apps/roboshield/src/payload/blocks/Content.ts +++ b/apps/roboshield/src/payload/blocks/Content.ts @@ -1,7 +1,7 @@ import { Block } from "payload/types"; import { RichText } from "./RichText"; import { MediaBlock } from "./MediaBlock"; -import { ExternalEmbedd } from "./ExternalEmbedd"; +import { ExternalEmbed } from "./ExternalEmbed"; export const Content: Block = { slug: "content", @@ -9,11 +9,13 @@ export const Content: Block = { singular: "Content", plural: "Content", }, + imageURL: "/images/cms/blocks/blog.png", + imageAltText: "Used in About page. Allows addition of blog like content", fields: [ { type: "blocks", name: "content", - blocks: [RichText, MediaBlock, ExternalEmbedd], + blocks: [RichText, MediaBlock, ExternalEmbed], }, ], }; diff --git a/apps/roboshield/src/payload/blocks/ExternalEmbedd.ts b/apps/roboshield/src/payload/blocks/ExternalEmbed.ts similarity index 88% rename from apps/roboshield/src/payload/blocks/ExternalEmbedd.ts rename to apps/roboshield/src/payload/blocks/ExternalEmbed.ts index a5a43131c..0a69b4cc1 100644 --- a/apps/roboshield/src/payload/blocks/ExternalEmbedd.ts +++ b/apps/roboshield/src/payload/blocks/ExternalEmbed.ts @@ -1,14 +1,14 @@ import { Block } from "payload/types"; -export const ExternalEmbedd: Block = { - slug: "externalEmbedd", +export const ExternalEmbed: Block = { + slug: "externalEmbed", labels: { - singular: "External Embedd", - plural: "External Embedd", + singular: "External Embed", + plural: "External Embed", }, fields: [ { - name: "externalEmbeddFields", + name: "externalEmbedFields", type: "group", fields: [ { diff --git a/apps/roboshield/src/payload/blocks/PageHeader.ts b/apps/roboshield/src/payload/blocks/PageHeader.ts index b8a6a688f..d3a9b8f39 100644 --- a/apps/roboshield/src/payload/blocks/PageHeader.ts +++ b/apps/roboshield/src/payload/blocks/PageHeader.ts @@ -6,6 +6,8 @@ export const PageHeader: Block = { singular: "Page Header", plural: "Page Header", }, + imageURL: "/images/cms/blocks/pageHeader.png", + imageAltText: "Used in About page.", fields: [ { name: "title", diff --git a/apps/roboshield/src/payload/blocks/PageHero.ts b/apps/roboshield/src/payload/blocks/PageHero.ts index 3aa4e64f3..7a7e1c80f 100644 --- a/apps/roboshield/src/payload/blocks/PageHero.ts +++ b/apps/roboshield/src/payload/blocks/PageHero.ts @@ -4,6 +4,8 @@ import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types export const PageHero: Block = { slug: "page-hero", + imageURL: "/images/cms/blocks/hero.png", + imageAltText: "Used in homepage", labels: { singular: "Page Hero", plural: "Page Hero", diff --git a/apps/roboshield/src/payload/blocks/RobotsTxtGenerator.ts b/apps/roboshield/src/payload/blocks/RobotsTxtGenerator.ts index e17695554..726c718ff 100644 --- a/apps/roboshield/src/payload/blocks/RobotsTxtGenerator.ts +++ b/apps/roboshield/src/payload/blocks/RobotsTxtGenerator.ts @@ -30,6 +30,8 @@ const validateSteps: Validate = (value = [], args) => { const ExistingRobots: Block = { slug: "existing-robots-txt", labels: { singular: "Existing Robots Txt", plural: "Existing Robots Txt" }, + imageURL: "/images/cms/blocks/existingRobots.png", + imageAltText: "Fetch existing robots.txt", fields: [ { name: "title", @@ -87,6 +89,8 @@ const ExistingRobots: Block = { const Delays: Block = { slug: "delays", labels: { singular: "Delays", plural: "Delays" }, + imageURL: "/images/cms/blocks/delays.png", + imageAltText: "Set bot delays for the robots you want to generate.", fields: [ { name: "title", @@ -170,6 +174,9 @@ const Delays: Block = { const Paths: Block = { slug: "paths", labels: { singular: "Paths", plural: "Paths" }, + imageURL: "/images/cms/blocks/paths.png", + imageAltText: + "Set disallowed and allowed paths for the robots you want to generate.", fields: [ { name: "title", @@ -254,6 +261,8 @@ const Paths: Block = { const BlockBots: Block = { slug: "block-bots", labels: { singular: "Block Bots", plural: "Block Bots" }, + imageURL: "/images/cms/blocks/blockBots.png", + imageAltText: "Select bots you want to block from crawling your website.", fields: [ { name: "title", @@ -318,6 +327,8 @@ const BlockBots: Block = { const SiteMaps: Block = { slug: "site-maps", labels: { singular: "Site Maps", plural: "Site Maps" }, + imageURL: "/images/cms/blocks/siteMaps.png", + imageAltText: "Add sitemap URLs to your robots.txt file.", fields: [ { name: "title", @@ -347,6 +358,8 @@ const SiteMaps: Block = { const Finish: Block = { slug: "finish", labels: { singular: "Finish", plural: "Finish" }, + imageURL: "/images/cms/blocks/finish.png", + imageAltText: "Completes robots generation process", fields: [ { name: "title", @@ -376,7 +389,7 @@ const Finish: Block = { ], }; -const Labels: Field = { +const Actions: Field = { name: "actions", label: "Actions", type: "group", @@ -422,6 +435,8 @@ const Labels: Field = { const RobotsTxtGenerator: Block = { slug: "robots-txt-generator", labels: { singular: "robots.txt Generator", plural: "robots.txt Generator" }, + imageURL: "/images/cms/blocks/robotsGenerator.png", + imageAltText: "Set action labels and content for robots.txt generator.", fields: [ { type: "blocks", @@ -432,7 +447,7 @@ const RobotsTxtGenerator: Block = { }, validate: validateSteps, }, - Labels, + Actions, ], }; diff --git a/apps/roboshield/src/payload/blocks/Statistics.ts b/apps/roboshield/src/payload/blocks/Statistics.ts index e4b7feb85..86d440245 100644 --- a/apps/roboshield/src/payload/blocks/Statistics.ts +++ b/apps/roboshield/src/payload/blocks/Statistics.ts @@ -7,6 +7,8 @@ export const Statistics: Block = { singular: "Statistics", plural: "Statistics", }, + imageURL: "/images/cms/blocks/statistics.png", + imageAltText: "Used in About page.", fields: [ { name: "title", diff --git a/apps/roboshield/src/payload/collections/Pages.ts b/apps/roboshield/src/payload/collections/Pages.ts index eaf47b380..ff73ce8f3 100644 --- a/apps/roboshield/src/payload/collections/Pages.ts +++ b/apps/roboshield/src/payload/collections/Pages.ts @@ -6,6 +6,7 @@ import { PageHeader } from "../blocks/PageHeader"; import { PageHero } from "../blocks/PageHero"; import { Content } from "../blocks/Content"; import { Statistics } from "../blocks/Statistics"; +import formatDraftUrl from "../utils/formatDraftUrl"; const Pages: CollectionConfig = { slug: "pages", @@ -15,8 +16,10 @@ const Pages: CollectionConfig = { update: () => true, }, admin: { + defaultColumns: ["fullTitle", "slug", "updatedAt"], group: "Publication", useAsTitle: "title", + preview: (doc) => formatDraftUrl("pages", doc), }, fields: [ { diff --git a/apps/roboshield/src/payload/globals/Site/InitiativeTab.ts b/apps/roboshield/src/payload/globals/Site/InitiativeTab.ts index cff569bf2..c57d7e6c9 100644 --- a/apps/roboshield/src/payload/globals/Site/InitiativeTab.ts +++ b/apps/roboshield/src/payload/globals/Site/InitiativeTab.ts @@ -2,6 +2,7 @@ import { Tab } from "payload/types"; import image from "../../fields/image"; import link from "../../fields/links/link"; import richText from "../../fields/richText"; +import { RowLabelArgs } from "payload/dist/admin/components/forms/RowLabel/types"; const PartnersTab: Tab = { label: "Initiative", @@ -42,6 +43,13 @@ const PartnersTab: Tab = { disableOpenInNewTab: true, }), ], + admin: { + components: { + RowLabel: ({ data, index = 0 }: RowLabelArgs) => { + return data?.name || `Partner ${index + 1}`; + }, + }, + }, }, ], }, diff --git a/apps/roboshield/src/payload/utils/formatDraftUrl.ts b/apps/roboshield/src/payload/utils/formatDraftUrl.ts new file mode 100644 index 000000000..714a7e111 --- /dev/null +++ b/apps/roboshield/src/payload/utils/formatDraftUrl.ts @@ -0,0 +1,17 @@ +import formatPagePath from "./formatPagePath"; +import { Document } from "payload/types"; + +const payloadUrl = + process.env.PAYLOAD_PUBLIC_APP_URL || process.env.NEXT_PUBLIC_APP_URL; + +function formatDraftUrl(collection: string, doc: Document) { + const pagePath = formatPagePath(collection, doc); + if (pagePath) { + const slug = pagePath; + const url = new URL(`/api/draft?slug=${slug}`, payloadUrl); + return url.href; + } + return null; +} + +export default formatDraftUrl;