Skip to content

Commit 644b109

Browse files
committed
render project page
1 parent 73b6e81 commit 644b109

8 files changed

Lines changed: 62 additions & 12 deletions

File tree

web-server/src/app/index.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import express from "express";
2-
import path from "path";
2+
import { renderProjectPage } from "src/handler/project";
33
import { generateContributionsSitemap } from "src/handler/sitemap/contributions";
44
import { generateContributorsSitemap } from "src/handler/sitemap/contributors";
55
import { generateProjectsSitemap } from "src/handler/sitemap/projects";
6+
import { validateLangOrDefault } from "src/utils/languages";
7+
import { indexPath, staticPath } from "src/utils/paths";
68

79
const app = express();
810
const port = process.env.PORT || 6060;
911

10-
const staticPath = path.join(__dirname, "../../../web/bundle");
11-
const indexPath = path.join(staticPath, "index.html");
12-
1312
app.get("/w/contributions-sitemap.xml", async (req, res) => {
1413
const xml = await generateContributionsSitemap();
1514
res.setHeader("Content-Type", "application/xml; charset=utf-8");
@@ -29,13 +28,10 @@ app.get("/w/projects-sitemap.xml", async (req, res) => {
2928
});
3029

3130
app.get(/^\/(?:([a-z]{2})\/)?projects\/(.*)$/, (req, res) => {
32-
const lang = req.params[0] || "en";
31+
const lang = validateLangOrDefault(req.params[0]);
3332
const projectId = req.params[1];
3433

35-
res.json({
36-
lang,
37-
projectId,
38-
});
34+
renderProjectPage(res, lang, projectId);
3935
});
4036

4137
app.get(/^\/(?:([a-z]{2})\/)?contribute\/(.*)$/, (req, res) => {

web-server/src/handler/project.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Language } from "@dzcode.io/models/dist/language";
2+
import { Response } from "express";
3+
import { plainLocalize } from "@dzcode.io/web/dist/components/locale/utils";
4+
import { dictionary, AllDictionaryKeys } from "@dzcode.io/web/dist/components/locale/dictionary";
5+
import { fetchV2Factory } from "@dzcode.io/utils/dist/fetch/factory";
6+
import { Endpoints } from "@dzcode.io/api/dist/app/endpoints";
7+
import { fullstackConfig } from "src/utils/config";
8+
import { getProjectURL } from "@dzcode.io/web/dist/utils/project";
9+
import { templateContent } from "./templates";
10+
import { notFoundPath } from "src/utils/paths";
11+
12+
export const renderProjectPage = async (res: Response, lang: Language, projectId: string) => {
13+
const localize = (key: AllDictionaryKeys) =>
14+
plainLocalize(dictionary, lang.code, key, "NO-TRANSLATION");
15+
const fetchV2 = fetchV2Factory<Endpoints>(fullstackConfig, lang.code);
16+
17+
try {
18+
const { project } = await fetchV2("api:projects/:id/name", { params: { id: projectId } });
19+
const pageTitle = `${localize("project-title-pre")} ${project.name} ${localize("project-title-post")}`;
20+
21+
const newData = templateContent
22+
.replace(/{{template-title}}/g, pageTitle)
23+
.replace(/{{template-description}}/g, localize("projects-description"))
24+
.replace(/{{template-lang}}/g, lang.code)
25+
.replace(/{{template-canonical}}/g, getProjectURL({ id: projectId }, lang));
26+
27+
res.setHeader("Content-Type", "text/html; charset=utf-8");
28+
res.status(200).send(newData);
29+
} catch (error) {
30+
// @TODO-ZM: log error to loki
31+
console.error(error);
32+
res.status(404).sendFile(notFoundPath);
33+
}
34+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { readFileSync } from "fs";
2+
import { templatePath } from "src/utils/paths";
3+
4+
export const templateContent = Object.freeze(readFileSync(templatePath, "utf-8"));

web-server/src/utils/languages.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { LANGUAGES, DEFAULT_LANGUAGE } from "@dzcode.io/models/dist/language";
2+
3+
export const validateLangOrDefault = (lang: string) => {
4+
return LANGUAGES.find((l) => l.code === lang) ?? DEFAULT_LANGUAGE;
5+
};

web-server/src/utils/paths.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { join } from "path";
2+
3+
export const staticPath = join(__dirname, "../../../web/bundle");
4+
export const indexPath = join(staticPath, "index.html");
5+
export const templatePath = join(staticPath, "template.html");
6+
export const notFoundPath = join(staticPath, "404.html");

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"scripts": {
6363
"build": "lerna run build:alone --scope=@dzcode.io/web --include-dependencies --stream",
6464
"build:alone": "tspc",
65+
"build:alone:watch": "tspc --watch --preserveWatchOutput",
6566
"build:watch": "lerna run build:alone:watch --scope=@dzcode.io/web --include-dependencies --parallel",
6667
"bundle": "npm run build && npm run bundle:alone",
6768
"bundle:alone": "cross-env NODE_ENV=production rsbuild build",

web/src/utils/project.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
import { DEFAULT_LANGUAGE, Language } from "@dzcode.io/models/dist/language";
12
import { ProjectEntity } from "@dzcode.io/models/dist/project";
23

3-
export function getProjectURL({ id }: Pick<ProjectEntity, "id">): string {
4-
return `/projects/${id}`;
4+
export function getProjectURL({ id }: Pick<ProjectEntity, "id">, lang?: Language): string {
5+
if (!lang) return `/projects/${id}`;
6+
7+
if (lang === DEFAULT_LANGUAGE) return `/projects/${id}`;
8+
9+
return `/${lang.code}/projects/${id}`;
510
}

web/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"extends": "@dzcode.io/tooling/tsconfig.json",
33
"compilerOptions": {
4-
"module": "esnext",
54
"outDir": "dist",
65
"baseUrl": "."
76
},

0 commit comments

Comments
 (0)