Skip to content

Commit

Permalink
refactor(core): blogpost fragment colocation (#848)
Browse files Browse the repository at this point in the history
* refactor(core): blogpost fragment colocation

* fix: remove unused fields, append sharing links

* fix: remove seofragment

* refactor: move client logic to own component

* refactor: use site for fragment
  • Loading branch information
jorgemoya authored May 2, 2024
1 parent 39a3484 commit 00b5281
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import { Printer } from 'lucide-react';

export const PrintButton = () => (
<button
className="hover:text-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/20"
onClick={() => {
window.print();

return false;
}}
type="button"
>
<Printer size={24}>
<title>Print</title>
</Printer>
</button>
);
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
'use client';

import { SiFacebook, SiLinkedin, SiPinterest, SiX } from '@icons-pack/react-simple-icons';
import { Mail, Printer } from 'lucide-react';
import { Mail } from 'lucide-react';

import { FragmentOf, graphql } from '~/client/graphql';

import { PrintButton } from './print-button';

interface SharingLinksProps {
blogPostId: string;
blogPostImageUrl?: string;
blogPostTitle?: string;
vanityUrl?: string;
export const SharingLinksFragment = graphql(`
fragment SharingLinksFragment on Site {
content {
blog {
post(entityId: $entityId) {
entityId
thumbnailImage {
url: urlTemplate
}
seo {
pageTitle
}
}
}
}
settings {
url {
vanityUrl
}
}
}
`);

interface Props {
data: FragmentOf<typeof SharingLinksFragment>;
}

export const SharingLinks = ({
blogPostId,
/* TODO: use default image */
blogPostImageUrl = '',
blogPostTitle = '',
vanityUrl = '',
}: SharingLinksProps) => {
const encodedTitle = encodeURIComponent(blogPostTitle);
const encodedUrl = encodeURIComponent(`${vanityUrl}/blog/${blogPostId}/`);
export const SharingLinks = ({ data }: Props) => {
const blogPost = data.content.blog?.post;

if (!blogPost) {
return null;
}

const encodedTitle = encodeURIComponent(blogPost.seo.pageTitle);
const encodedUrl = encodeURIComponent(
`${data.settings?.url.vanityUrl || ''}/blog/${blogPost.entityId}/`,
);

return (
<div className="mb-10 flex items-center [&>*:not(:last-child)]:me-2.5">
Expand All @@ -41,19 +65,7 @@ export const SharingLinks = ({
<title>Email</title>
</Mail>
</a>
<button
className="hover:text-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/20"
onClick={() => {
window.print();

return false;
}}
type="button"
>
<Printer size={24}>
<title>Print</title>
</Printer>
</button>
<PrintButton />
<a
className="hover:text-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/20"
href={`https://twitter.com/intent/tweet/?text=${encodedTitle}&url=${encodedUrl}`}
Expand All @@ -72,7 +84,7 @@ export const SharingLinks = ({
</a>
<a
className="hover:text-primary focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-primary/20"
href={`https://pinterest.com/pin/create/button/?url=${encodedUrl}&media=${blogPostImageUrl}&description=${encodedTitle}`}
href={`https://pinterest.com/pin/create/button/?url=${encodedUrl}&media=${blogPost.thumbnailImage?.url || ''}&description=${encodedTitle}`} // TODO: use default image if thumbnailImage is not available
rel="noopener noreferrer"
target="_blank"
>
Expand Down
55 changes: 55 additions & 0 deletions apps/core/app/[locale]/(default)/blog/[blogId]/page-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { cache } from 'react';

import { client } from '~/client';
import { graphql } from '~/client/graphql';
import { revalidate } from '~/client/revalidate-target';

import { SharingLinksFragment } from './_components/sharing-links';

const PageQuery = graphql(
`
query PageQuery($entityId: Int!) {
site {
content {
blog {
isVisibleInNavigation
post(entityId: $entityId) {
author
htmlBody
name
publishedDate {
utc
}
tags
thumbnailImage {
altText
url: urlTemplate
}
seo {
pageTitle
}
}
}
}
...SharingLinksFragment
}
}
`,
[SharingLinksFragment],
);

export const getPageData = cache(async ({ entityId }: { entityId: number }) => {
const response = await client.fetch({
document: PageQuery,
variables: { entityId },
fetchOptions: { next: { revalidate } },
});

const { blog } = response.data.site.content;

if (!blog?.post) {
return null;
}

return response.data.site;
});
22 changes: 11 additions & 11 deletions apps/core/app/[locale]/(default)/blog/[blogId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getFormatter } from 'next-intl/server';

import { getBlogPost } from '~/client/queries/get-blog-post';
import { BcImage } from '~/components/bc-image';
import { Link } from '~/components/link';
import { SharingLinks } from '~/components/sharing-links';
import {
BlogPostAuthor,
BlogPostBanner,
Expand All @@ -16,6 +14,9 @@ import {
import { Tag, TagContent } from '~/components/ui/tag';
import { LocaleType } from '~/i18n';

import { SharingLinks } from './_components/sharing-links';
import { getPageData } from './page-data';

interface Props {
params: {
blogId: string;
Expand All @@ -24,7 +25,8 @@ interface Props {
}

export async function generateMetadata({ params: { blogId } }: Props): Promise<Metadata> {
const blogPost = await getBlogPost(+blogId);
const data = await getPageData({ entityId: Number(blogId) });
const blogPost = data?.content.blog?.post;

const title = blogPost?.seo.pageTitle ?? 'Blog';

Expand All @@ -35,9 +37,12 @@ export async function generateMetadata({ params: { blogId } }: Props): Promise<M

export default async function BlogPostPage({ params: { blogId, locale } }: Props) {
const format = await getFormatter({ locale });
const blogPost = await getBlogPost(+blogId);

if (!blogPost || !blogPost.isVisibleInNavigation) {
const data = await getPageData({ entityId: Number(blogId) });
const blogPost = data?.content.blog?.post;
const isVisibleInNavigation = data?.content.blog?.isVisibleInNavigation;

if (!blogPost || !isVisibleInNavigation) {
return notFound();
}

Expand Down Expand Up @@ -85,12 +90,7 @@ export default async function BlogPostPage({ params: { blogId, locale } }: Props
</Link>
))}
</div>
<SharingLinks
blogPostId={blogId}
blogPostImageUrl={blogPost.thumbnailImage?.url}
blogPostTitle={blogPost.seo.pageTitle}
vanityUrl={blogPost.vanityUrl}
/>
<SharingLinks data={data} />
</div>
);
}
Expand Down
63 changes: 0 additions & 63 deletions apps/core/client/queries/get-blog-post.ts

This file was deleted.

0 comments on commit 00b5281

Please sign in to comment.