Skip to content

Commit

Permalink
feat: 点赞
Browse files Browse the repository at this point in the history
  • Loading branch information
wanghao1993 committed Sep 9, 2024
1 parent e566831 commit 6563890
Show file tree
Hide file tree
Showing 22 changed files with 271 additions and 186 deletions.
1 change: 0 additions & 1 deletion app/api/blog/create/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import prisma from "@/lib/pg";

export const dynamic = "force-dynamic"; // defaults to auto
export async function POST(request: Request) {
await prisma.$connect();
const body = await request.json();
try {
const res = await prisma.post.findUnique({
Expand Down
79 changes: 79 additions & 0 deletions app/api/blog/detail/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { BusinessCode, responseHandler } from "@/lib/fetch_utils";
import prisma from "@/lib/pg";
import { PostTypes } from "@/types/post";
import { getSession } from "next-auth/react";

export const dynamic = "force-dynamic"; // defaults to auto
export async function GET(request: Request) {
const key = new URL(request.url).searchParams.get("key");
if (!key) {
return responseHandler(
null,
BusinessCode.normal,
BusinessCode.abnormal,
"无key"
);
} else {
try {
const res = await prisma.post.findUnique({
where: { blog_key: key },
});

if (!res) {
return responseHandler(
null,
BusinessCode.normal,
BusinessCode.abnormal,
"key值错误"
);
} else {
return responseHandler(res);
}
} catch (e) {
return responseHandler(
null,
BusinessCode.normal,
BusinessCode.abnormal,
"未知异常"
);
}
}
}

export async function POST(request: Request) {
const body: PostTypes.PostDetail = await request.json();
const session = await getSession();
const post = await prisma.post.findUnique({
where: {
blog_key: body.blog_key,
},
});

if (post && session?.user.email) {
const user = await prisma.user.findUnique({
where: {
email: session.user.email,
},
});
const likes_count = post.likes_count;

if (user) {
const idx = likes_count.findIndex((item) => item === user.id);
if (idx > -1) {
likes_count.splice(idx, 1);
} else {
likes_count.push(user.id);
}
const updatePost = await prisma.post.update({
where: {
blog_key: body.blog_key,
},
data: {
likes_count,
},
});

return responseHandler(updatePost);
}
}
}
21 changes: 0 additions & 21 deletions app/api/mail/code.ts

This file was deleted.

30 changes: 0 additions & 30 deletions app/api/user/route.ts

This file was deleted.

27 changes: 13 additions & 14 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { AntdRegistry } from "@ant-design/nextjs-registry";
import { content } from "@/lib/font";
import Footer from "@/components/Footer";
import { GoogleTagManager } from "@next/third-parties/google";

import { ProgressProvider } from "@/components/Providers/ProgressProdivder";
import Script from "next/script";
import type { Metadata } from "next";
import dynamic from "next/dynamic";
const APP_NAME = "汪浩的博客";
const APP_DEFAULT_TITLE = "汪浩(Isaac Wang)的博客";
const APP_TITLE_TEMPLATE = "汪浩(Isaac Wang)的博客";
Expand All @@ -18,6 +19,7 @@ export type Metadatas = Metadata & {
"baidu-site-verification": string;
};

const DHeader = dynamic(() => import("@/components/Header"), { ssr: false });
export const metadata: Metadatas = {
keywords:
"博客,汪浩,Isaac Wang, Javascript, Vue, Css, Nextjs, Nodejs, Docker, web3,区块链",
Expand All @@ -29,12 +31,6 @@ export const metadata: Metadatas = {
"baidu-site-verification": "codeva-n7vACpBbX1",
description: APP_DESCRIPTION,
manifest: "./manifest.json",
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: APP_DEFAULT_TITLE,
// startUpImage: [],
},
formatDetection: {
telephone: false,
},
Expand Down Expand Up @@ -68,18 +64,21 @@ export default function RootLayout({
id="stripe-js"
src="https://hm.baidu.com/hm.js?922218601e8a18ab79e59afcf18803b9"
/>

<GoogleTagManager gtmId="G-4Z3CSGWXGR" />
{process.env.mode !== "development" && (
<GoogleTagManager gtmId="G-4Z3CSGWXGR" />
)}
<meta name="baidu-site-verification" content="codeva-n7vACpBbX1" />
<body className={content.className}>
<AntdRegistry>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
<LenisProvider>
<div className="sticky top-0 z-10">
<Header />
</div>
<main className="min-h-[calc(100vh-110px)] ">{children}</main>
<Footer />
<ProgressProvider>
<div className="sticky top-0 z-10">
<DHeader />
</div>
<main className="min-h-[calc(100vh-110px)] ">{children}</main>
<Footer />
</ProgressProvider>
</LenisProvider>
</ThemeProvider>
</AntdRegistry>
Expand Down
19 changes: 10 additions & 9 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
"use client";
import BlogName from "./Name";
import Menus from "./Menu/menu";
import Nav from "./Nav";
import ThemeSwitch from "./ThemeToggle";
import LoginInOut from "./LoginOutBtn";
import { SessionProvider } from "next-auth/react";
import Star from "./Star";
import MobileNav from "./MobileNav";
import MainLayout from "./Layouts/MainLayout";
import { osIconMap } from "./themeconfig";
import { useTheme } from "next-themes";
import { motion } from "framer-motion";
import classNames from "classnames";
import { NextAuthProvider } from "./Providers/AuthProvider";
export default function Header({ ...props }) {
const { theme, setTheme } = useTheme();
return (
<MainLayout>
<SessionProvider>
<NextAuthProvider>
<header
className="z-10"
{...props}
Expand All @@ -26,8 +25,8 @@ export default function Header({ ...props }) {
<div className="flex items-center space-x-4">
<Nav />
<ThemeSwitch />
<LoginInOut />
<Star />
<LoginInOut />
</div>
</div>

Expand All @@ -37,9 +36,11 @@ export default function Header({ ...props }) {
<button
key={item}
onClick={() => setTheme(item)}
className={`p-2 rounded-md flex items-center justify-center ${
item === theme ? "bg-primary-300" : ""
} `}
className={classNames(
`p-2 rounded-md flex items-center justify-center`,
{ "bg-primary-300": item === theme },
{ "text-white": item === theme }
)}
>
{osIconMap[item].icon}
</button>
Expand All @@ -49,7 +50,7 @@ export default function Header({ ...props }) {
<MobileNav />
</div>
</header>
</SessionProvider>
</NextAuthProvider>
</MainLayout>
);
}
12 changes: 10 additions & 2 deletions components/Layouts/PostLayOut.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Divider } from "antd";
import { Post } from "contentlayer/generated";
import Link from "next/link";
import { ReactNode } from "react";

import LikeAndCollect from "../LikeAndCollect";
import { Suspense } from "react";
import { NextAuthProvider } from "../Providers/AuthProvider";
export type CoreContent<T> = Omit<T, "body" | "_raw" | "_id">;
interface Props {
post: Post;
Expand All @@ -17,7 +19,6 @@ export default function PostLayout({ post, children, next, prev }: Props) {
return (
<div className="article-detail ">
<title>{title}</title>

<div className="bg-primary-400 text-white space-y-1 rounded-lg text-center sm:py-6 sm:py-10">
<h1 className="font-semibold !text-white">{title}</h1>
<div>
Expand All @@ -26,6 +27,7 @@ export default function PostLayout({ post, children, next, prev }: Props) {
{(readingTime.time / 60000).toFixed(0)}分钟
</div>
</div>

<div className="py-4 flex gap-4 flex-wrap items-center">
{post.categories &&
post.categories.split(",").map((item: string) => (
Expand Down Expand Up @@ -56,6 +58,12 @@ export default function PostLayout({ post, children, next, prev }: Props) {
</Link>
))}
</div>

<Suspense fallback={"loading"}>
<NextAuthProvider>
<LikeAndCollect blogKey={post.key}></LikeAndCollect>
</NextAuthProvider>
</Suspense>
<article className="mt-4">{children}</article>
</div>
);
Expand Down
55 changes: 55 additions & 0 deletions components/LikeAndCollect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use client";

import { get, post } from "@/lib/fetch";
import { EyeOutlined, LikeOutlined } from "@ant-design/icons";
import { PostTypes } from "@/types/post";
import { useSession } from "next-auth/react";
import LoginModal from "../login/page";
import { useEffect, useState } from "react";

export default function LikeAndCollect(data: { blogKey: string }) {
const [detail, setDetail] = useState<PostTypes.PostDetail>();

const getData = async () => {
const res = await get<PostTypes.PostDetail>("blog/detail", {
key: data.blogKey,
});

setDetail(res);
};

useEffect(() => {
getData();
}, [data.blogKey]);
const session = useSession();

const like = async () => {
if (session.status === "authenticated") {
const res = await post<PostTypes.PostDetail>("blog/detail", {
blog_key: detail?.blog_key,
});
setDetail(res);
} else {
setVisible(true);
}
};

const [visible, setVisible] = useState(false);
return (
detail && (
<div className="py-4 flex items-center space-x-4 text-md text-[--text-color] opacity-70">
<div>
<EyeOutlined /> {detail.views_count}
</div>

<div onClick={() => like()} className="text-primary-100 cursor-pointer">
<LikeOutlined /> {detail.likes_count.length}
</div>
<LoginModal
open={visible}
onClose={() => setVisible(false)}
></LoginModal>
</div>
)
);
}
14 changes: 14 additions & 0 deletions components/LoginModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useState, useEffect } from "react";
import LoginModal from "../login/page";

export default function useLoginModal() {
const [visible, setVisible] = useState(true);
useEffect(() => {
console.log(visible, "visbile");
visible && (
<LoginModal open={visible} onClose={() => setVisible(false)}></LoginModal>
);
}, [visible]);

return [setVisible];
}
Loading

0 comments on commit 6563890

Please sign in to comment.