Skip to content

Commit

Permalink
filter topics
Browse files Browse the repository at this point in the history
  • Loading branch information
manyuanrong committed Mar 15, 2020
1 parent 06d2274 commit b37277e
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 70 deletions.
5 changes: 4 additions & 1 deletion src/common/base-page.ts
Expand Up @@ -3,5 +3,8 @@ import { match } from "react-router";

export interface BasePage<PrefetchType = any, PropsType = any> {
page: FunctionComponent<PropsType>;
prefetch?(match: match<any>): Promise<Partial<PrefetchType> | undefined>;
prefetch?(
match: match<any>,
search?: string
): Promise<Partial<PrefetchType> | undefined>;
}
5 changes: 3 additions & 2 deletions src/common/data-provider/prefetch.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { useRouteMatch } from "react-router";
import { useRouteMatch, useLocation } from "react-router";
import { BasePage } from "../base-page";

let restore_state = (window as any)["__INIT_STATE__"];
Expand All @@ -10,12 +10,13 @@ export function setPrefetchState(state: any) {

export function usePrefetchData<T>(page: BasePage<T>): Partial<T> {
const match = useRouteMatch();
const location = useLocation();
const [data, setData] = useState<Partial<T> | undefined>(restore_state);

useEffect(() => {
(async () => {
if (!restore_state && page.prefetch) {
const state = await page.prefetch(match);
const state = await page.prefetch(match, location.search);
setData(state);
} else {
restore_state = undefined;
Expand Down
10 changes: 10 additions & 0 deletions src/common/format.ts
@@ -1,8 +1,18 @@
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import relativeTime from "dayjs/plugin/relativeTime";

dayjs.extend(relativeTime);
dayjs.locale("zh-cn");

const DATE_FORMAT = "YYYY-MM-DD HH:mm:ss";

export function formatDate(date?: string): string {
if (!date) return "";
return dayjs(date).format(DATE_FORMAT);
}

export function formatFromNow(date?: string): string {
if (!date) return "";
return dayjs(date).fromNow();
}
17 changes: 15 additions & 2 deletions src/common/route-utli.ts
Expand Up @@ -14,14 +14,27 @@ export function findRoute(url: string): MatchRouteInfo | undefined {
}
}

export async function prefetch(routeInfo?: MatchRouteInfo): Promise<any> {
export async function prefetch(
routeInfo?: MatchRouteInfo,
search?: string
): Promise<any> {
let state = {};
if (routeInfo) {
const { route, match } = routeInfo;
const prefetcher = route.page?.prefetch;
if (prefetcher) {
state = (await prefetcher(match)) || {};
state = (await prefetcher(match, search)) || {};
}
}
return state;
}

export function getAllSearchParams(search?: string): any {
if (!search) return {};
const params = new URLSearchParams(search);
const paramsObject: any = {};
for (const key of params.keys()) {
paramsObject[key] = params.get(key);
}
return paramsObject;
}
10 changes: 7 additions & 3 deletions src/entry/server.tsx
Expand Up @@ -9,18 +9,22 @@ import { findRoute, prefetch } from "../common/route-utli";
globalThis.React = React;

interface RenderProps {
url?: string;
params: { url?: string; search?: string };
api_base: string;
data: Object;
}

export default async function render(props: RenderProps) {
const { url = "/", api_base = "", data } = props;
const {
params: { url = "/", search },
api_base = "",
data
} = props;

GlobalData.apiBase = api_base;

let routeInfo = findRoute(url);
let state = { ...data, ...(await prefetch(routeInfo)) };
let state = { ...data, ...(await prefetch(routeInfo, search)) };

setPrefetchState(state);

Expand Down
4 changes: 2 additions & 2 deletions src/pages/Detail/header.tsx
Expand Up @@ -9,7 +9,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Link } from "react-router-dom";
import { useUserData } from "../../common/data-provider/user";
import { formatDate } from "../../common/format";
import { formatFromNow } from "../../common/format";
import Topic from "../../model/topic";

interface DetailHeaderProps {
Expand All @@ -36,7 +36,7 @@ export default function DetailHeader(props: DetailHeaderProps) {
{topic.is_good && <i className="tag">精华</i>}
<span className="time">
<FontAwesomeIcon icon={faClock} color="#bbb" />
发布于 {formatDate(topic.created_at)}
发布于 {formatFromNow(topic.created_at)}
</span>
<span className="icon">
<FontAwesomeIcon icon={faCommentDots} />
Expand Down
28 changes: 12 additions & 16 deletions src/pages/Index/index.tsx
@@ -1,15 +1,16 @@
import React from "react";
import { Link, match, useHistory } from "react-router-dom";
import { Link, useHistory } from "react-router-dom";
import { BasePage } from "../../common/base-page";
import { usePrefetchData } from "../../common/data-provider/prefetch";
import GlobalData from "../../common/global";
import { getAllSearchParams } from "../../common/route-utli";
import BasePanel from "../../components/base-panel";
import DefaultLayout from "../../components/layouts/DefaultLayout";
import Pagination from "../../components/pagination";
import FriendsLinkPanel from "../../components/panels/friends-link";
import LoginUserPanel from "../../components/panels/login-user";
import QQGroupPanel from "../../components/panels/qq-group";
import Topic from "../../model/topic";
import { getTopics } from "./helper";
import "./index.less";
import TopicItem from "./topic";

Expand All @@ -30,18 +31,13 @@ interface IndexProps {
}

const Index: BasePage<IndexProps> = {
async prefetch(
match: match<{
type?: string;
page?: string;
pageSize?: string;
}>
) {
const { type = "all", page = "0", pageSize = "10" } = match.params;
const {
data: { list: topics = [], total }
} = await fetch(`${GlobalData.apiBase}/api/topic/${type}`).then(res =>
res.json()
async prefetch(_, search) {
const params = getAllSearchParams(search);
const { type = "all", page = "0", pageSize = "10" } = params;
const { topics, total } = await getTopics(
type,
parseInt(page),
parseInt(pageSize)
);

return {
Expand Down Expand Up @@ -79,14 +75,14 @@ const Index: BasePage<IndexProps> = {
header={
<div className="header">
{types.map(item => (
<Link key={item.type} replace to={`/?type=${item.type}`}>
<a key={item.type} href={`/?type=${item.type}`}>
<span
role="button"
className={item.type === type ? "active" : ""}
>
{item.title}
</span>
</Link>
</a>
))}
</div>
}
Expand Down
7 changes: 4 additions & 3 deletions src/pages/Index/topic.tsx
Expand Up @@ -6,6 +6,7 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Link } from "react-router-dom";
import { formatFromNow } from "../../common/format";
import Topic from "../../model/topic";

interface TopicItemProps {
Expand Down Expand Up @@ -46,13 +47,13 @@ export default function Topic(props: TopicItemProps) {
</>
) : (
<>
<Link className="author" to={`/user/${topic.author_id}`}>
{/* {topic.user_nick_name} */}
<Link className="author" to={`/user/${topic.author_id.$oid}`}>
{topic.author?.nick_name}
</Link>
<FontAwesomeIcon icon={faClock} color="#bbb" />
<span className="time">
发布于
{topic.created_at}
{formatFromNow(topic.created_at)}
</span>
</>
)}
Expand Down
22 changes: 12 additions & 10 deletions src/pages/User/index.tsx
Expand Up @@ -2,15 +2,17 @@ import dayjs from "dayjs";
import React from "react";
import { match } from "react-router";
import { BasePage } from "../../common/base-page";
import { usePrefetchData } from "../../common/data-provider/prefetch";
import GlobalData from "../../common/global";
import BasePanel from "../../components/base-panel";
import DefaultLayout from "../../components/layouts/DefaultLayout";
import FriendsLinkPanel from "../../components/panels/friends-link";
import QQGroupPanel from "../../components/panels/qq-group";
import UserModel from "../../model/user";
import "./index.less";

const User: BasePage<{
user: any;
user: UserModel;
}> = {
async prefetch(match: match<{ id: string }>) {
const id = match.params.id;
Expand All @@ -19,8 +21,8 @@ const User: BasePage<{
).then(res => res.json());
return { user: data };
},
page(props) {
const { user = {} } = props;
page() {
const { user } = usePrefetchData(User);
return (
<DefaultLayout
sides={
Expand All @@ -33,26 +35,26 @@ const User: BasePage<{
<BasePanel header="用户信息" className="page-user" style="white">
<div className="register-time">
注册于:
{dayjs(user.created_at).format("YYYY-MM-DD HH:mm:ss")}
{dayjs(user?.created_at).format("YYYY-MM-DD HH:mm:ss")}
</div>
<img className="avatar" src={user.avatar} alt={user.name} />
<img className="avatar" src={user?.avatar} alt={user?.name} />
<div className="name">
<span className="nick-name">{user.nick_name}</span>
<span className="nick-name">{user?.nick_name}</span>
<a
href={`https://github.com/${user.github_name}`}
href={`https://github.com/${user?.github_name}`}
className="github"
>
{user.name}
{user?.name}
</a>
</div>
<ul className="counters">
<li>
<h6>积分</h6>
<span>{user.score}</span>
<span>{user?.score}</span>
</li>
<li>
<h6>主题</h6>
<span>{user.topic_count || 0}</span>
<span>{0}</span>
</li>
</ul>
</BasePanel>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/detail/header.tsx
Expand Up @@ -9,7 +9,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Link } from "react-router-dom";
import { useUserData } from "../../common/data-provider/user";
import { formatDate } from "../../common/format";
import { formatFromNow } from "../../common/format";
import Topic from "../../model/topic";

interface DetailHeaderProps {
Expand All @@ -36,7 +36,7 @@ export default function DetailHeader(props: DetailHeaderProps) {
{topic.is_good && <i className="tag">精华</i>}
<span className="time">
<FontAwesomeIcon icon={faClock} color="#bbb" />
发布于 {formatDate(topic.created_at)}
发布于 {formatFromNow(topic.created_at)}
</span>
<span className="icon">
<FontAwesomeIcon icon={faCommentDots} />
Expand Down
15 changes: 15 additions & 0 deletions src/pages/index/helper.ts
@@ -0,0 +1,15 @@
import GlobalData from "../../common/global";

export async function getTopics(
type: string,
page: number = 1,
pageSize: number = 10
) {
const {
data: { list: topics = [], total }
} = await fetch(`${GlobalData.apiBase}/api/topic/${type}`).then(res =>
res.json()
);

return { topics, total, page, pageSize };
}
28 changes: 12 additions & 16 deletions src/pages/index/index.tsx
@@ -1,15 +1,16 @@
import React from "react";
import { Link, match, useHistory } from "react-router-dom";
import { Link, useHistory } from "react-router-dom";
import { BasePage } from "../../common/base-page";
import { usePrefetchData } from "../../common/data-provider/prefetch";
import GlobalData from "../../common/global";
import { getAllSearchParams } from "../../common/route-utli";
import BasePanel from "../../components/base-panel";
import DefaultLayout from "../../components/layouts/DefaultLayout";
import Pagination from "../../components/pagination";
import FriendsLinkPanel from "../../components/panels/friends-link";
import LoginUserPanel from "../../components/panels/login-user";
import QQGroupPanel from "../../components/panels/qq-group";
import Topic from "../../model/topic";
import { getTopics } from "./helper";
import "./index.less";
import TopicItem from "./topic";

Expand All @@ -30,18 +31,13 @@ interface IndexProps {
}

const Index: BasePage<IndexProps> = {
async prefetch(
match: match<{
type?: string;
page?: string;
pageSize?: string;
}>
) {
const { type = "all", page = "0", pageSize = "10" } = match.params;
const {
data: { list: topics = [], total }
} = await fetch(`${GlobalData.apiBase}/api/topic/${type}`).then(res =>
res.json()
async prefetch(_, search) {
const params = getAllSearchParams(search);
const { type = "all", page = "0", pageSize = "10" } = params;
const { topics, total } = await getTopics(
type,
parseInt(page),
parseInt(pageSize)
);

return {
Expand Down Expand Up @@ -79,14 +75,14 @@ const Index: BasePage<IndexProps> = {
header={
<div className="header">
{types.map(item => (
<Link key={item.type} replace to={`/?type=${item.type}`}>
<a key={item.type} href={`/?type=${item.type}`}>
<span
role="button"
className={item.type === type ? "active" : ""}
>
{item.title}
</span>
</Link>
</a>
))}
</div>
}
Expand Down
7 changes: 4 additions & 3 deletions src/pages/index/topic.tsx
Expand Up @@ -6,6 +6,7 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Link } from "react-router-dom";
import { formatFromNow } from "../../common/format";
import Topic from "../../model/topic";

interface TopicItemProps {
Expand Down Expand Up @@ -46,13 +47,13 @@ export default function Topic(props: TopicItemProps) {
</>
) : (
<>
<Link className="author" to={`/user/${topic.author_id}`}>
{/* {topic.user_nick_name} */}
<Link className="author" to={`/user/${topic.author_id.$oid}`}>
{topic.author?.nick_name}
</Link>
<FontAwesomeIcon icon={faClock} color="#bbb" />
<span className="time">
发布于
{topic.created_at}
{formatFromNow(topic.created_at)}
</span>
</>
)}
Expand Down

0 comments on commit b37277e

Please sign in to comment.