Skip to content

Commit

Permalink
[add] Project list of Home page based on Group API & model
Browse files Browse the repository at this point in the history
[fix] some UI detail bugs
[fix] webpack building bug (vercel/next.js#28774)
  • Loading branch information
TechQuery committed Oct 9, 2022
1 parent d43c972 commit 991f1c6
Show file tree
Hide file tree
Showing 11 changed files with 537 additions and 101 deletions.
11 changes: 5 additions & 6 deletions components/OrganizationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { observer } from 'mobx-react';
import { PureComponent } from 'react';
import { Card, CardProps, Badge, Button, Image } from 'react-bootstrap';
import { text2color, Icon } from 'idea-react';
import type { TableCellMedia } from 'lark-ts-sdk';

import { StaticRoot } from '../models/Base';
import { Organization } from '../models/Organization';
import { fileURLOf } from '../pages/api/lark/file/[id]';

export interface OrganizationCardProps
extends Omit<Organization, 'id'>,
Expand Down Expand Up @@ -70,10 +70,7 @@ export class OrganizationCard extends PureComponent<OrganizationCardProps> {
const { name, logos, type, tags, summary, wechatName, onSwitch, ...props } =
this.props;

const logo =
logos instanceof Array &&
logos[0] &&
`/api/lark/file/${(logos[0] as TableCellMedia).file_token}`;
const logo = fileURLOf(logos);

return (
<Card {...props}>
Expand All @@ -82,7 +79,9 @@ export class OrganizationCard extends PureComponent<OrganizationCardProps> {
style={{ height: '30vh', objectFit: 'contain' }}
loading="lazy"
src={`${StaticRoot}/${(name + '').replace(/\s+/g, '-')}.png`}
onError={({ currentTarget: image }) => (image.src = logo || '')}
onError={({ currentTarget: image }) =>
logo && !image.src.endsWith(logo) && (image.src = logo || '')
}
/>
<Card.Body>
<Card.Title>
Expand Down
53 changes: 53 additions & 0 deletions models/Group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { NewData, ListModel, Stream } from 'mobx-restful';
import { TableCellLink, TableCellValue, TableRecordList } from 'lark-ts-sdk';

import { client } from './Base';
import { normalizeText, createListStream } from './Lark';

export type Group = Record<
| 'id'
| 'name'
| 'type'
| 'fullName'
| 'tags'
| 'startDate'
| 'leader'
| 'members'
| 'summary'
| 'document'
| 'email'
| 'link'
| 'codeLink'
| 'logo',
TableCellValue
>;

export class GroupModel extends Stream<Group>(ListModel) {
client = client;
baseURI = 'group';

normalize = ({
id,
fields: { link, codeLink, email, ...fields },
}: TableRecordList<Group>['data']['items'][number]): Group => ({
...fields,
id: id!,
link: normalizeText(link as TableCellLink),
codeLink: normalizeText(codeLink as TableCellLink),
email: normalizeText(email as TableCellLink),
});

async *openStream(filter: NewData<Group>) {
for await (const { total, items } of createListStream<Group>(
this.client,
this.baseURI,
filter,
)) {
this.totalCount = total;

yield* items?.map(this.normalize) || [];
}
}
}

export default new GroupModel();
10 changes: 9 additions & 1 deletion models/Lark.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { buildURLData } from 'web-utility';
import { DataObject, NewData, RESTClient } from 'mobx-restful';
import { Lark, TableRecordList } from 'lark-ts-sdk';
import {
Lark,
TableCellLink,
TableCellRelation,
TableRecordList,
} from 'lark-ts-sdk';

const LARK_APP_ID = process.env.LARK_APP_ID!,
LARK_APP_SECRET = process.env.LARK_APP_SECRET!;
Expand All @@ -15,6 +20,9 @@ export const makeFilter = (data: DataObject) =>
.map(([key, value]) => `CurrentValue.[${key}].contains("${value}")`)
.join('&&');

export const normalizeText = (value: TableCellLink | TableCellRelation) =>
value && typeof value === 'object' && 'text' in value ? value.text : value;

export async function* createListStream<T extends DataObject>(
client: RESTClient,
path: string,
Expand Down
15 changes: 6 additions & 9 deletions models/Organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from 'lark-ts-sdk';

import { client } from './Base';
import { createListStream } from './Lark';
import { normalizeText, createListStream } from './Lark';
import { OrganizationStatistic } from '../pages/api/organization/statistic';
import { CooperationData } from '../pages/api/organization/cooperation';

Expand Down Expand Up @@ -44,18 +44,15 @@ export class OrganizationModel extends Stream<Organization>(ListModel) {
@observable
cooperation: CooperationData = {} as CooperationData;

normalizeText = (value: TableCellLink | TableCellRelation) =>
value && typeof value === 'object' && 'text' in value ? value.text : value;

normalize = ({
id,
fields: { link, codeLink, email, ...fields },
}: TableRecordList<Organization>['data']['items'][number]): Organization => ({
...fields,
id: id!,
link: this.normalizeText(link as TableCellLink),
codeLink: this.normalizeText(codeLink as TableCellLink),
email: this.normalizeText(email as TableCellLink),
link: normalizeText(link as TableCellLink),
codeLink: normalizeText(codeLink as TableCellLink),
email: normalizeText(email as TableCellLink),
});

async *openStream(filter: NewData<Organization>) {
Expand Down Expand Up @@ -89,9 +86,9 @@ export class OrganizationModel extends Stream<Organization>(ListModel) {
list.map(({ organization, link, ...item }) => ({
...item,
organization: (organization as TableCellRelation[]).map(
this.normalizeText,
normalizeText,
),
link: (link as TableCellLink[]).map(this.normalizeText),
link: (link as TableCellLink[]).map(normalizeText),
})),
]),
);
Expand Down
11 changes: 10 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const withLess = require('next-with-less'),
const { NormalModuleReplacementPlugin } = require('webpack'),
withLess = require('next-with-less'),
setPWA = require('next-pwa');

const { NODE_ENV } = process.env;
Expand All @@ -13,6 +14,14 @@ const withPWA = setPWA({
/** @type {import('next').NextConfig} */
module.exports = withPWA(
withLess({
webpack: config => {
config.plugins.push(
new NormalModuleReplacementPlugin(/^node:/, resource => {
resource.request = resource.request.replace(/^node:/, '');
}),
);
return config;
},
reactStrictMode: true,
}),
);
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"lodash": "^4.17.21",
"mobx": "^5.15.7",
"mobx-react": "^6.3.1",
"mobx-restful": "^0.6.0-rc.16",
"mobx-restful": "^0.6.0-rc.17",
"next": "^12.3.1",
"nookies": "^2.5.2",
"qs": "^6.11.0",
Expand All @@ -49,7 +49,7 @@
"@types/node": "^16.11.64",
"@types/qs": "^6.9.7",
"@types/react": "^17.0.50",
"eslint": "^8.24.0",
"eslint": "^8.25.0",
"eslint-config-next": "^12.3.1",
"husky": "^8.0.1",
"jest": "^29.1.2",
Expand All @@ -59,11 +59,12 @@
"lint-staged": "^13.0.3",
"next-pwa": "^5.6.0",
"next-with-less": "^2.0.5",
"playwright": "^1.26.1",
"playwright": "^1.27.0",
"prettier": "^2.7.1",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "~4.8.4"
"typescript": "~4.8.4",
"webpack": "^5.74.0"
},
"prettier": {
"singleQuote": true,
Expand Down
38 changes: 38 additions & 0 deletions pages/api/group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { buildURLData, parseURLData } from 'web-utility';
import { DataObject } from 'mobx-restful';
import { TableRecordList } from 'lark-ts-sdk';
import { NextApiResponse } from 'next';

import { safeAPI } from '../base';
import { lark, makeFilter } from '../../../models/Lark';
import { Group } from '../../../models/Group';

const LARK_BITABLE_ID = process.env.LARK_BITABLE_ID!,
LARK_BITABLE_GROUP_ID = process.env.LARK_BITABLE_GROUP_ID!;

export default safeAPI(
async (
{ method, url },
response: NextApiResponse<TableRecordList<Group>['data']>,
) => {
switch (method) {
case 'GET': {
const biTable = await lark.getBITable(LARK_BITABLE_ID);

const table = await biTable.getTable<Group>(LARK_BITABLE_GROUP_ID),
{ page_size, page_token, ...filter } = parseURLData(
url!,
) as DataObject;

const { body } = await lark.client.get<TableRecordList<Group>>(
`${table!.baseURI}/records?${buildURLData({
page_size,
page_token,
filter: makeFilter(filter),
})}`,
);
response.json(body!.data);
}
}
},
);
10 changes: 10 additions & 0 deletions pages/api/lark/file/[id].ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { fileTypeFromBuffer } from 'file-type';
import { TableCellMedia, TableCellValue } from 'lark-ts-sdk';

import { lark } from '../../../../models/Lark';
import { safeAPI } from '../../base';

export const DefaultImage = 'https://github.com/kaiyuanshe.png';

export const fileURLOf = (field: TableCellValue) =>
field instanceof Array
? field[0]
? `/api/lark/file/${(field[0] as TableCellMedia).file_token}`
: field + ''
: field + '';

export default safeAPI(async (req, res) => {
switch (req.method) {
case 'GET': {
Expand Down
76 changes: 65 additions & 11 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { InferGetServerSidePropsType } from 'next';
import { observer } from 'mobx-react';
import { Fragment, PureComponent } from 'react';
import { Container, Row, Col, Image } from 'react-bootstrap';
Expand All @@ -7,39 +8,92 @@ import PageHead from '../components/PageHead';
import ArticleCard from '../components/ArticleCard';
import { CityStatisticMap } from '../components/CityStatisticMap';

import { slogan } from './api/home';
import { isServer } from '../models/Base';
import groupStore, { Group } from '../models/Group';
import activityStore from '../models/Activity';
import { slogan } from './api/home';
import { DefaultImage, fileURLOf } from './api/lark/file/[id]';

export async function getServerSideProps() {
const projects = await groupStore.getAll({ type: '项目' });

return {
props: {
projects: projects.map(item => JSON.parse(JSON.stringify(item)) as Group),
},
};
}

@observer
export default class HomePage extends PureComponent {
export default class HomePage extends PureComponent<
InferGetServerSidePropsType<typeof getServerSideProps>
> {
renderProject = ({ id, name, logo = DefaultImage, link }: Group) => (
<Col as="li" key={id + ''} className="position-relative">
<Image style={{ height: '8rem' }} src={fileURLOf(logo)} />
<a
className="d-block text-decoration-none text-dark h5 stretched-link mt-3"
target="_blank"
href={link + ''}
rel="noreferrer"
>
{name}
</a>
</Col>
);

render() {
const { projects } = this.props;

return (
<>
<PageHead />

<section className="py-5 text-center bg-primary">
<Image src="https://kaiyuanshe.cn/image/Heart_of_Community.png" />
<Image
fluid
src="https://kaiyuanshe.cn/image/Heart_of_Community.png"
/>
</section>

<Container>
<section className="py-5 text-center">
<section className="text-center">
{slogan.map(({ title, items }) => (
<Fragment key={title}>
<h2 className="text-primary">{title}</h2>
<h2 className="my-5 text-primary">{title}</h2>

<ul className="list-unstyled text-secondary d-flex justify-content-center">
<Row
as="ul"
className="list-unstyled mx-0 g-5 justify-content-center text-secondary"
xs={2}
sm={2}
md={4}
>
{items.map(({ icon, text }) => (
<li key={text} className="m-5">
<Col as="li" key={text}>
<Icon name={icon} size={6} />
<h3>{text}</h3>
</li>
<div className="h3">{text}</div>
</Col>
))}
</ul>
</Row>
</Fragment>
))}
</section>

<section className="text-center">
<h2 className="my-5 text-primary">自研开源项目</h2>

<Row
as="ul"
className="list-unstyled mx-0 g-5 justify-content-center"
xs={2}
sm={2}
md={4}
>
{projects.map(this.renderProject)}
</Row>
</section>

{/* <section>
<h2 className="text-center text-primary">最新动态</h2>
<p className="text-center text-muted">
Expand All @@ -55,7 +109,7 @@ export default class HomePage extends PureComponent {
</section> */}

<section>
<h2 className="mb-4 text-center text-primary">活动地图</h2>
<h2 className="my-5 text-center text-primary">活动地图</h2>

{!isServer() && <CityStatisticMap store={activityStore} />}
</section>
Expand Down
Loading

1 comment on commit 991f1c6

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for kaiyuanshe ready!

✅ Preview
https://kaiyuanshe-mft1hdis1-techquery.vercel.app

Built with commit 991f1c6.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.