Skip to content

Commit

Permalink
Server action folder refactoring and meta type update for articles (#132
Browse files Browse the repository at this point in the history
)

* update on next.js version and unoptimized pug

* update content and seo keywords

* server action refactoring and changing meta tags

---------

Co-authored-by: Arkar <[email protected]>
  • Loading branch information
Riley1101 and Arkar authored Jun 19, 2024
1 parent cb5399b commit b427a4a
Show file tree
Hide file tree
Showing 30 changed files with 368 additions and 288 deletions.
13 changes: 13 additions & 0 deletions actions/categoryActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Category } from "@/types/articles";
import client from "@/utils/client";
import { cache } from "react";

export const getCategories = cache(async function (): Promise<Category[]> {
const query = `
*[_type=='category']{
title,
_id
}
`;
return await client.fetch(query);
});
34 changes: 27 additions & 7 deletions utils/newsletter.ts → actions/newsLetterActions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use server";
import { redirect } from "next/navigation";
import { db, QueryResult, QueryResultRow } from "@vercel/postgres";

export interface User {
Expand All @@ -8,7 +9,7 @@ export interface User {
}

export async function queryDb<T extends QueryResultRow>(
query: string
query: string,
): Promise<QueryResult<T> | null> {
const client = await db.connect();
try {
Expand All @@ -20,17 +21,20 @@ export async function queryDb<T extends QueryResultRow>(
}
}

export const unsubscribe= async (mail: string) => {
export const unsubscribe = async (mail: string) => {
"use server";
const exists = await user_exists(mail);
if (exists) {
const res = await queryDb(`DELETE FROM mailing_list WHERE email = '${mail}'`);
console.log(res)
const res = await queryDb(
`DELETE FROM mailing_list WHERE email = '${mail}'`,
);
console.log(res);
}
};

export async function user_exists(email: string): Promise<boolean> {
const result = await queryDb(
`SELECT * FROM mailing_list WHERE email='${email}'`
`SELECT * FROM mailing_list WHERE email='${email}'`,
);
if (result && result.rowCount > 0) {
return true;
Expand All @@ -39,11 +43,11 @@ export async function user_exists(email: string): Promise<boolean> {

export async function add_user(
email: string,
name: string
name: string,
): Promise<User | null> {
try {
const result = await queryDb<User>(
`INSERT INTO mailing_list (name, email) VALUES ('${name}', '${email}') RETURNING *`
`INSERT INTO mailing_list (name, email) VALUES ('${name}', '${email}') RETURNING *`,
);
if (result && result.rowCount > 0) {
return result.rows[0];
Expand All @@ -53,3 +57,19 @@ export async function add_user(
return null;
}
}

export async function handleSubmit(formData: FormData) {
const email = formData.get("email");
const name = formData.get("name");
if (email) {
const exists = await user_exists(email as string);
if (!exists) {
const response = await add_user(email as string, name as string);
if (response !== null) {
redirect("/newsletter/thank-you");
}
} else {
redirect("/newsletter/already-with-me");
}
}
}
100 changes: 100 additions & 0 deletions actions/postAcions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use server";
import client from "@/utils/client";
import { cache } from "react";
import type { ArticlCardType, ArticleDetailType } from "@/types/articles";
import type { Serie } from "@/types/series";

export const getLatestHomePosts = cache(async function (): Promise<
ArticlCardType[]
> {
const query = `*[_type == "article"] | order(releasedAt desc) [0..4] {
title,
'slug':slug.current,
releasedAt,
description,
'categories':categories[]->title,
}`;
return await client.fetch(query);
});

export const getArticleSeries = cache(async function (): Promise<Serie[]> {
const query = `
*[_type=='serie'] {
_id,
title,
description,
'articles':articles[]->{
title,
'categories':categories[]->title,
'slug':slug.current,
releasedAt,
},
}`;
return await client.fetch(query);
});

export const getArticles = cache(async function (): Promise<ArticlCardType[]> {
let query = `
*[_type=='article'] | order(releasedAt desc) {
'slug':slug.current,
title,
releasedat,
description,
mainImage,
'categories':categories[]->title,
}
`;
return await client.fetch(query);
});

export const getArticleBySlug = cache(async function (
slug?: string,
): Promise<ArticleDetailType> {
const query = `
*[_type == "article" && slug.current == $slug][0]{
title,
'slug':slug.current,
releasedAt,
description,
'categories':categories[]->title,
body[]{
...,
asset->{
metadata,
"_type":"reference",
"_ref": _id
}
},
"related": *[_type == "article" && _id != ^._id && count(categories[@._ref in ^.^.categories[]._ref]) > 0] | order(releasedAt desc, _createdAt desc) [0..2] {
title,
_id,
"mainImage":{
"asset":{
...mainImage.asset,
"metadata":mainImage.asset->metadata
},
},
"slug": slug.current,
description
}
}`;
return await client.fetch(query, {
slug: slug,
});
});

export const getArticleSEOContentBySlug = cache(async function (
slug?: string,
): Promise<ArticleDetailType> {
const seoQuery = `
*[_type == "article" && slug.current == $slug][0]{
title,
'slug':slug.current,
description,
'categories':categories[]->title,
'mainImage':mainImage.asset->{url}.url
}`;
return await client.fetch(seoQuery, {
slug: slug,
});
});
18 changes: 18 additions & 0 deletions actions/projectActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use server";

import client from "@/utils/client";
import type { Project } from "@/types/projects";
import { cache } from "react";

export const getHomeProjects = cache(
async function (): Promise<Project[]> {
const query = `
*[_type=='project' && pinned==true][0..6]{
...,
"slug": slug.current
}
`;

return await client.fetch(query);
},
);
18 changes: 18 additions & 0 deletions actions/snippetActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use server";

import { ArticlCardType } from "@/types/articles";
import client from "@/utils/client";
import { cache } from "react";

export const getSnippets = cache(async function (): Promise<ArticlCardType[]> {
let query = `
*[_type=='snippet'] | order(releasedAt desc) {
title,
'slug':slug.current,
'categories':categories[]->title,
description,
releasedAt
}
`;
return await client.fetch(query);
});
9 changes: 5 additions & 4 deletions app/(web)/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ import Image from "next/image";
import Hero from "@/components/pages/hero";
import { getOpenGraph, getTwitterCard, metaData } from "@/utils/metadata";
import type { Metadata } from "next";

const ComputerModel = dynamic(() => import("@/components/common/model"), {
ssr: false,
});

const hero = {
title: "About",
subtitle: "Arkar",
subtitle: "Arkar Myat",
description: "",
};

export const metadata: Metadata = {
title: "About | Arkar",
title: "About | Arkar Myat",
openGraph: getOpenGraph(
"/images/arkar.png",
"About | " + metaData.title,
Expand All @@ -31,8 +32,8 @@ export const metadata: Metadata = {

function AboutPage() {
return (
<div className="page-container ">
<div>
<div className="page-container">
<div className="col-span-full md:col-span-1">
<Hero
title={hero.title}
description={hero.description}
Expand Down
61 changes: 12 additions & 49 deletions app/(web)/articles/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,24 @@
export const revalidate = 60;
import { NewsLetter } from "@/components/common/newsletter";
import { Related } from "@/components/common/related";

import Hero from "@/components/pages/article/hero";
import client from "@/utils/client";
import type { ArticleDetailType } from "@/types/articles";
import PortableBody from "@/components/common/portable";
import TableOfContents from "@/components/common/toc";
import type { ArticleDetailType } from "@/types/articles";
import type { DetailPageParamTypes } from "@/types";
import { NewsLetter } from "@/components/common/newsletter";
import { Related } from "@/components/common/related";
import {
getArticleBySlug,
getArticleSEOContentBySlug,
} from "@/actions/postAcions";
import { getOpenGraph, getTwitterCard, metaData } from "@/utils/metadata";

const query = `
*[_type == "article" && slug.current == $slug][0]{
title,
'slug':slug.current,
releasedAt,
description,
'categories':categories[]->title,
body[]{
...,
asset->{
metadata,
"_type":"reference",
"_ref": _id
}
},
"related": *[_type == "article" && _id != ^._id && count(categories[@._ref in ^.^.categories[]._ref]) > 0] | order(releasedAt desc, _createdAt desc) [0..2] {
title,
_id,
"mainImage":{
"asset":{
...mainImage.asset,
"metadata":mainImage.asset->metadata
},
},
"slug": slug.current,
description
}
}`;
export async function generateMetadata({
params,
}: {
params: { slug: string };
}) {
const seoQuery = `
*[_type == "article" && slug.current == $slug][0]{
title,
'slug':slug.current,
description,
'categories':categories[]->title,
'mainImage':mainImage.asset->{url}.url
}`;

const data: ArticleDetailType = await client.fetch(seoQuery, {
slug: params?.slug,
});

const data: ArticleDetailType = await getArticleSEOContentBySlug(params.slug);
return {
title: data?.title,
description: data?.description,
Expand All @@ -64,17 +28,16 @@ export async function generateMetadata({
data?.title,
data.description,
new URL(`/snippets/${data?.slug}`, metaData?.url),
"article",
),
twitter: getTwitterCard(data?.mainImage, data.title, data.description),
};
}

async function ArticleDetailPage(props: DetailPageParamTypes) {
const { params } = props;
const data: ArticleDetailType = await client.fetch(query, {
slug: params?.slug,
});
if (data === null) return <div>404</div>;
const data = await getArticleBySlug(params?.slug);
if (data === null) return <></>;
return (
<div className="page-container md:gap-4 lg:gap-12">
<div className="flex shrink page-left flex-col gap-4">
Expand Down
17 changes: 5 additions & 12 deletions app/(web)/articles/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export const revalidate = 60;

import { getOpenGraph, getTwitterCard, metaData } from "@/utils/metadata";
import { Categories } from "@/components/pages/article/categories";
import { ArticleTimeLine } from "@/components/pages/article/timeline";
import { Banner } from "@/components/pages/banner";
import { Categories } from "@/components/pages/article/categories";
import { Metadata } from "next";
import client from "@/utils/client";
import { getCategories } from "@/actions/categoryActions";
import { getOpenGraph, getTwitterCard, metaData } from "@/utils/metadata";

export const metadata: Metadata = {
title: "Articles | Arkar",
Expand All @@ -22,18 +22,11 @@ export const metadata: Metadata = {
),
};

const categoryQuery = `
*[_type=='category']{
title,
_id
}
`;

export default async function ArticlePage(props: {
searchParams?: { [key: string]: string | undefined };
searchParams?: { category: string | undefined };
}) {
const { searchParams } = props;
const categories = await client.fetch(categoryQuery);
const categories = await getCategories();
return (
<div className="page-container gap-4 md:gap-12">
<div className="page-left">
Expand Down
3 changes: 1 addition & 2 deletions app/(web)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ export const metadata: Metadata = {
keywords: metaData.keywords,
authors: [
{ name: metaData.title, url: metaData.url },
{ name: "Arkar", url: "https://arkar.space" },
{ name: "Arkar", url: "https://arkar.space" },
{ name: "Arkar Myat", url: "https://arkar.space" },
],
creator: metaData.title,
publisher: metaData.title,
Expand Down
Loading

0 comments on commit b427a4a

Please sign in to comment.