diff --git a/apps/codeforafrica/payload.config.ts b/apps/codeforafrica/payload.config.ts
index 83c3e6173..02820279d 100644
--- a/apps/codeforafrica/payload.config.ts
+++ b/apps/codeforafrica/payload.config.ts
@@ -17,8 +17,9 @@ import Members from "./src/payload/collections/Members";
import Pages from "./src/payload/collections/Pages";
import Partners from "./src/payload/collections/Partners";
import Posts from "./src/payload/collections/Posts";
+import Publication from "./src/payload/globals/Publication";
import Projects from "./src/payload/collections/Projects";
-import Settings from "./src/payload/globals/Settings";
+import Site from "./src/payload/globals/Site";
import Tags from "./src/payload/collections/Tags";
import Teams from "./src/payload/collections/Teams";
import Users from "./src/payload/collections/Users";
@@ -67,7 +68,7 @@ export default buildConfig({
Teams,
Users,
] as CollectionConfig[],
- globals: [Settings] as GlobalConfig[],
+ globals: [Publication, Site] as GlobalConfig[],
...(locales?.length
? {
localization: {
diff --git a/apps/codeforafrica/src/components/Articles/Articles.js b/apps/codeforafrica/src/components/Articles/Articles.js
index 8576ae156..f2950a146 100644
--- a/apps/codeforafrica/src/components/Articles/Articles.js
+++ b/apps/codeforafrica/src/components/Articles/Articles.js
@@ -35,7 +35,7 @@ const Articles = React.forwardRef(function Articles(props, ref) {
const [q, setQ] = useState();
const [filtering, setFiltering] = useState(false);
const [tag, setTag] = useState(allTag);
- const queryParams = useFilterQuery({ page, q, tag: tag.slug });
+ const queryParams = useFilterQuery({ page, q, tag });
const router = useRouter();
@@ -59,7 +59,13 @@ const Articles = React.forwardRef(function Articles(props, ref) {
setFiltering(isFiltering);
}, [page, q, tag]);
- const { data } = useArticles({ page, q, tag: tag.slug }, primaryTag);
+ const { data } = useArticles(
+ { page, q, tag },
+ {
+ primaryTag,
+ featured: !filtering && featuredArticle ? featuredArticle.slug : null,
+ },
+ );
useEffect(() => {
if (data) {
const { posts: results, pagination } = data;
diff --git a/apps/codeforafrica/src/components/Articles/useArticles.js b/apps/codeforafrica/src/components/Articles/useArticles.js
index 0db0cbf37..3fa395ce8 100644
--- a/apps/codeforafrica/src/components/Articles/useArticles.js
+++ b/apps/codeforafrica/src/components/Articles/useArticles.js
@@ -4,11 +4,13 @@ import useFilterQuery from "@/codeforafrica/components/useFilterQuery";
const fetcher = (url) => fetch(url).then((res) => res.json());
-function useArticles(params, primaryTag) {
+function useArticles(params, { primaryTag, featured }) {
const queryParams = useFilterQuery(params);
- const query = queryParams
- ? `${queryParams}&primaryTag=${primaryTag}`
- : `?primaryTag=${primaryTag}`;
+ const separator = queryParams ? "" : "?";
+ const filterQuery = queryParams ? `${queryParams}&` : "";
+ const primaryTagQuery = `primaryTag=${primaryTag}`;
+ const featuredQuery = featured ? `&featured=${featured}` : "";
+ const query = `${separator}${filterQuery}${primaryTagQuery}${featuredQuery}`;
const { data, error } = useSWR(`/api/v1/posts${query}`, fetcher);
return {
diff --git a/apps/codeforafrica/src/components/Opportunities/Opportunities.js b/apps/codeforafrica/src/components/Opportunities/Opportunities.js
index 93b5d8e9a..d98f9585e 100644
--- a/apps/codeforafrica/src/components/Opportunities/Opportunities.js
+++ b/apps/codeforafrica/src/components/Opportunities/Opportunities.js
@@ -36,7 +36,7 @@ const Opportunities = React.forwardRef(function Opportunities(
const [opportunities, setOpportunities] = useState(opportunitiesList);
const [q, setQ] = useState();
const [tag, setTag] = useState(allTag);
- const queryParams = useFilterQuery({ page, q, tag: tag.slug });
+ const queryParams = useFilterQuery({ page, q, tag });
const router = useRouter();
const handleChangePage = (_, value) => {
@@ -54,7 +54,7 @@ const Opportunities = React.forwardRef(function Opportunities(
setPage(1);
};
- const { data } = useOpportunities({ page, q, tag: tag.slug }, primaryTag);
+ const { data } = useOpportunities({ page, q, tag }, primaryTag);
useEffect(() => {
if (data) {
const { posts: results, pagination } = data;
diff --git a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.js b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.js
index 52a2e731d..928d22570 100644
--- a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.js
+++ b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.js
@@ -5,9 +5,9 @@ import React from "react";
import ArticleCardList from "@/codeforafrica/components/ArticleCardList";
const RelatedStories = React.forwardRef(function RelatedStories(props, ref) {
- const { articles, sx, title } = props;
+ const { posts, sx, title } = props;
- if (!articles?.length) {
+ if (!posts?.length) {
return null;
}
return (
@@ -25,10 +25,7 @@ const RelatedStories = React.forwardRef(function RelatedStories(props, ref) {
>
{title}
-
+
);
});
diff --git a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.snap.js b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.snap.js
index db5aa7a87..94b062097 100644
--- a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.snap.js
+++ b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.snap.js
@@ -1,3 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` renders unchanged 1`] = `
`;
+exports[` renders unchanged 1`] = `
+
+
+
+ Related Stories
+
+
+
+
+`;
diff --git a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.test.js b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.test.js
index 5b45158fc..4742aa706 100644
--- a/apps/codeforafrica/src/components/RelatedStories/RelatedStories.test.js
+++ b/apps/codeforafrica/src/components/RelatedStories/RelatedStories.test.js
@@ -10,6 +10,20 @@ const render = createRender({ theme });
const defaultProps = {
title: "Related Stories",
+ posts: [
+ {
+ title: "Battle for gender equality in African media continues",
+ excerpt:
+ "Lorem ipsum dolor sit amet consectetur adipiscing elit mattis, vestibulum potenti rhoncus eget lacus fermentum taciti quam, quis curae accumsan viverra semper dapibus sed.",
+ publishedOn: "Jan 6, 2022",
+ image: {
+ src: "https://res.cloudinary.com/code-for-africa/image/upload/v1650885664/codeforafrica/unsplash_L6hr1BptcNc_of23p3.png",
+ alt: "Featured Article Image",
+ },
+ readMoreLabel: "Read Story",
+ href: "/stories/article-1",
+ },
+ ],
};
describe("", () => {
diff --git a/apps/codeforafrica/src/lib/data/blockify/posts.js b/apps/codeforafrica/src/lib/data/blockify/posts.js
index 11463d6da..bfbbf0253 100644
--- a/apps/codeforafrica/src/lib/data/blockify/posts.js
+++ b/apps/codeforafrica/src/lib/data/blockify/posts.js
@@ -11,6 +11,13 @@ async function posts(block, api, context) {
const featured = featuredStory ? formatPost(featuredStory, primaryTag) : null;
const options = {
...query,
+ ...(featured && {
+ where: {
+ slug: {
+ not_equals: featured.slug,
+ },
+ },
+ }),
};
// rename post to fix eslint no-shadow
const { posts: list, pagination } = await getPosts(api, options, primaryTag);
diff --git a/apps/codeforafrica/src/lib/data/common/index.js b/apps/codeforafrica/src/lib/data/common/index.js
index 8858787a9..92394bef0 100644
--- a/apps/codeforafrica/src/lib/data/common/index.js
+++ b/apps/codeforafrica/src/lib/data/common/index.js
@@ -172,11 +172,11 @@ export async function getPageProps(api, context) {
}
}
const blocks = await blockify(page?.blocks, api, context);
- const settings = await api.findGlobal("settings");
- const navbar = getNavBar(settings);
- const footer = getFooter(settings);
+ const siteSettings = await api.findGlobal("settings-site");
+ const navbar = getNavBar(siteSettings);
+ const footer = getFooter(siteSettings);
- const seo = getPageSeoFromMeta(page, settings);
+ const seo = getPageSeoFromMeta(page, siteSettings);
return {
blocks,
footer,
diff --git a/apps/codeforafrica/src/lib/data/utils/posts.js b/apps/codeforafrica/src/lib/data/utils/posts.js
index d83b458b9..c0d6b900a 100644
--- a/apps/codeforafrica/src/lib/data/utils/posts.js
+++ b/apps/codeforafrica/src/lib/data/utils/posts.js
@@ -31,7 +31,7 @@ export function formatPost(post, primaryTag) {
}
export async function getPosts(api, params, primaryTag) {
- const { page: queryPage = 1, tag, q, ...other } = params;
+ const { page: queryPage = 1, tag, q, where, ...other } = params;
const options = {
limit: 9,
page: queryPage,
@@ -68,6 +68,7 @@ export async function getPosts(api, params, primaryTag) {
},
],
}),
+ ...where,
},
...other,
};
@@ -117,29 +118,54 @@ export async function getPost(api, slug, primaryTag) {
image: coverImage,
...meta,
};
- return {
- title,
- blocks: [
+ const blocks = [
+ {
+ authors: authors.map(({ fullName, bio }) => {
+ return {
+ name: fullName,
+ bio,
+ };
+ }),
+ title,
+ coverImage,
+ excerpt,
+ tags,
+ publishedOn: formatDate(publishedOn, {
+ includeTime: false,
+ month: "short",
+ }),
+ primaryTag,
+ blockType: "article",
+ ...other,
+ },
+ ];
+
+ const publicationSettings = await api.findGlobal("settings-publication");
+ const primaryTagPostSettings = publicationSettings?.[primaryTag] ?? {};
+ const { showRecent, title: recentTitle } = primaryTagPostSettings;
+ if (showRecent) {
+ const { posts } = await getPosts(
+ api,
{
- authors: authors.map(({ fullName, bio }) => {
- return {
- name: fullName,
- bio,
- };
- }),
- title,
- coverImage,
- excerpt,
- tags,
- publishedOn: formatDate(publishedOn, {
- includeTime: false,
- month: "short",
- }),
- primaryTag,
- blockType: "article",
- ...other,
+ limit: 3,
+ where: {
+ slug: {
+ not_equals: slug,
+ },
+ },
},
- ],
+ primaryTag,
+ );
+ blocks.push({
+ title: recentTitle,
+ posts,
+ blockType: "recent-posts",
+ });
+ }
+
+ return {
+ title,
+ blocks,
meta: postMeta,
};
}
diff --git a/apps/codeforafrica/src/pages/[...slugs].page.js b/apps/codeforafrica/src/pages/[...slugs].page.js
index 73bd5493a..d04a47ca2 100644
--- a/apps/codeforafrica/src/pages/[...slugs].page.js
+++ b/apps/codeforafrica/src/pages/[...slugs].page.js
@@ -22,6 +22,7 @@ import OurTeam from "@/codeforafrica/components/OurTeam";
import PageHeader from "@/codeforafrica/components/PageHeader";
import Project from "@/codeforafrica/components/Project";
import Projects from "@/codeforafrica/components/Projects";
+import RelatedStories from "@/codeforafrica/components/RelatedStories";
import { getPageServerSideProps } from "@/codeforafrica/lib/data";
const componentsBySlugs = {
@@ -45,6 +46,7 @@ const componentsBySlugs = {
"our-work": Projects,
"page-header": PageHeader,
project: Project,
+ "recent-posts": RelatedStories,
stories: Articles,
};
diff --git a/apps/codeforafrica/src/pages/api/v1/posts.page.js b/apps/codeforafrica/src/pages/api/v1/posts.page.js
index 30ebe9296..040d71a8e 100644
--- a/apps/codeforafrica/src/pages/api/v1/posts.page.js
+++ b/apps/codeforafrica/src/pages/api/v1/posts.page.js
@@ -2,12 +2,25 @@ import { getPosts } from "@/codeforafrica/lib/data/utils/posts";
import api from "@/codeforafrica/lib/payload";
export default async function handler(req, res) {
- const { primaryTag, ...other } = req.query;
+ const { primaryTag, featured, ...other } = req.query;
if (!primaryTag) {
return res.status(400).json({ error: "Primary Tag is required" });
}
try {
- const data = await getPosts(api, other, primaryTag);
+ const data = await getPosts(
+ api,
+ {
+ ...other,
+ ...(featured && {
+ where: {
+ slug: {
+ not_equals: featured,
+ },
+ },
+ }),
+ },
+ primaryTag,
+ );
return res.json(data);
} catch (error) {
return res.status(500).json(error);
diff --git a/apps/codeforafrica/src/payload/collections/Posts.js b/apps/codeforafrica/src/payload/collections/Posts.js
index 154b7803d..04330cd14 100644
--- a/apps/codeforafrica/src/payload/collections/Posts.js
+++ b/apps/codeforafrica/src/payload/collections/Posts.js
@@ -23,6 +23,7 @@ const Posts = {
description: "Stories and Opportunities",
group: "Publication",
useAsTitle: "title",
+ listSearchableFields: ["content", "excerpt"],
},
fields: [
{
diff --git a/apps/codeforafrica/src/payload/collections/Users.js b/apps/codeforafrica/src/payload/collections/Users.js
index 814d37b80..daeeef760 100644
--- a/apps/codeforafrica/src/payload/collections/Users.js
+++ b/apps/codeforafrica/src/payload/collections/Users.js
@@ -16,7 +16,7 @@ const Users = {
admin: {
defaultColumns: ["firstName", "lastName", "email", "updatedAt"],
enableRichTextLink: false,
- group: "Website",
+ group: "Settings",
useAsTitle: "email",
},
auth: {
diff --git a/apps/codeforafrica/src/payload/globals/Publication/PostTab.js b/apps/codeforafrica/src/payload/globals/Publication/PostTab.js
new file mode 100644
index 000000000..e57aabf69
--- /dev/null
+++ b/apps/codeforafrica/src/payload/globals/Publication/PostTab.js
@@ -0,0 +1,75 @@
+const PostTab = {
+ label: "Post",
+ fields: [
+ {
+ type: "collapsible",
+ label: "Story",
+ fields: [
+ {
+ name: "stories",
+ label: "Recent stories",
+ type: "group",
+ localized: true,
+ fields: [
+ {
+ name: "showRecent",
+ label: "Show recent stories",
+ type: "checkbox",
+ required: true,
+ defaultValue: false,
+ },
+ {
+ name: "title",
+ label: "Title",
+ type: "text",
+ required: true,
+ defaultValue: "Recent Stories",
+ admin: {
+ condition: (_, data) => data.showRecent,
+ },
+ },
+ ],
+ admin: {
+ className: "group-field-nested",
+ },
+ },
+ ],
+ },
+ {
+ type: "collapsible",
+ label: "Opportunity",
+ fields: [
+ {
+ name: "opportunities",
+ label: "Recent opportunities",
+ type: "group",
+ localized: true,
+ fields: [
+ {
+ name: "showRecent",
+ label: "Show recent opportunities",
+ type: "checkbox",
+ required: true,
+ defaultValue: false,
+ },
+ {
+ name: "title",
+ label: "Title",
+ type: "text",
+ required: true,
+ defaultValue: "Recent Opportunities",
+ admin: {
+ condition: (_, data) => data.showRecent,
+ },
+ },
+ ],
+ admin: {
+ className: "group-field-nested",
+ },
+ },
+ ],
+ },
+ ],
+};
+
+export default PostTab;
diff --git a/apps/codeforafrica/src/payload/globals/Publication/index.js b/apps/codeforafrica/src/payload/globals/Publication/index.js
new file mode 100644
index 000000000..3f08a2dab
--- /dev/null
+++ b/apps/codeforafrica/src/payload/globals/Publication/index.js
@@ -0,0 +1,20 @@
+import PostTab from "./PostTab";
+
+const Publication = {
+ slug: "settings-publication",
+ label: "Publication",
+ access: {
+ read: () => true,
+ },
+ admin: {
+ group: "Settings",
+ },
+ fields: [
+ {
+ type: "tabs",
+ tabs: [PostTab],
+ },
+ ],
+};
+
+export default Publication;
diff --git a/apps/codeforafrica/src/payload/globals/Settings/EngagementTab.js b/apps/codeforafrica/src/payload/globals/Site/EngagementTab.js
similarity index 100%
rename from apps/codeforafrica/src/payload/globals/Settings/EngagementTab.js
rename to apps/codeforafrica/src/payload/globals/Site/EngagementTab.js
diff --git a/apps/codeforafrica/src/payload/globals/Settings/GeneralTab.js b/apps/codeforafrica/src/payload/globals/Site/GeneralTab.js
similarity index 100%
rename from apps/codeforafrica/src/payload/globals/Settings/GeneralTab.js
rename to apps/codeforafrica/src/payload/globals/Site/GeneralTab.js
diff --git a/apps/codeforafrica/src/payload/globals/Settings/NavigationTab.js b/apps/codeforafrica/src/payload/globals/Site/NavigationTab.js
similarity index 100%
rename from apps/codeforafrica/src/payload/globals/Settings/NavigationTab.js
rename to apps/codeforafrica/src/payload/globals/Site/NavigationTab.js
diff --git a/apps/codeforafrica/src/payload/globals/Settings/index.js b/apps/codeforafrica/src/payload/globals/Site/index.js
similarity index 74%
rename from apps/codeforafrica/src/payload/globals/Settings/index.js
rename to apps/codeforafrica/src/payload/globals/Site/index.js
index 1680b1186..207b83587 100644
--- a/apps/codeforafrica/src/payload/globals/Settings/index.js
+++ b/apps/codeforafrica/src/payload/globals/Site/index.js
@@ -2,13 +2,14 @@ import EngagementTab from "./EngagementTab";
import GeneralTab from "./GeneralTab";
import NavigationTab from "./NavigationTab";
-const Settings = {
- slug: "settings",
+const Site = {
+ slug: "settings-site",
+ label: "Site",
access: {
read: () => true,
},
admin: {
- group: "Website",
+ group: "Settings",
},
fields: [
{
@@ -18,4 +19,4 @@ const Settings = {
],
};
-export default Settings;
+export default Site;