chore: standardize security and quality foundations
This commit is contained in:
@@ -1,95 +1,95 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import PageHeading from '../ui/PageHeading'
|
||||
import PageHeading from "../ui/PageHeading";
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { authFetch, clearToken, getApiBase, getToken } from '../lib/auth'
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { authFetch, clearToken, getApiBase, getToken } from "../lib/auth";
|
||||
|
||||
type SiteInfo = {
|
||||
changelog?: string
|
||||
}
|
||||
changelog?: string;
|
||||
};
|
||||
|
||||
type ChangelogGroup = {
|
||||
date: string
|
||||
entries: string[]
|
||||
}
|
||||
date: string;
|
||||
entries: string[];
|
||||
};
|
||||
|
||||
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/
|
||||
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
const parseChangelog = (raw: string): ChangelogGroup[] => {
|
||||
const groups: ChangelogGroup[] = []
|
||||
for (const rawLine of raw.split('\n')) {
|
||||
const line = rawLine.trim()
|
||||
if (!line) continue
|
||||
const [candidateDate, ...messageParts] = line.split('|')
|
||||
const groups: ChangelogGroup[] = [];
|
||||
for (const rawLine of raw.split("\n")) {
|
||||
const line = rawLine.trim();
|
||||
if (!line) continue;
|
||||
const [candidateDate, ...messageParts] = line.split("|");
|
||||
if (DATE_PATTERN.test(candidateDate) && messageParts.length > 0) {
|
||||
const message = messageParts.join('|').trim()
|
||||
if (!message) continue
|
||||
const currentGroup = groups[groups.length - 1]
|
||||
const message = messageParts.join("|").trim();
|
||||
if (!message) continue;
|
||||
const currentGroup = groups[groups.length - 1];
|
||||
if (currentGroup?.date === candidateDate) {
|
||||
currentGroup.entries.push(message)
|
||||
currentGroup.entries.push(message);
|
||||
} else {
|
||||
groups.push({ date: candidateDate, entries: [message] })
|
||||
groups.push({ date: candidateDate, entries: [message] });
|
||||
}
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
if (groups.length === 0) {
|
||||
groups.push({ date: 'Updates', entries: [line] })
|
||||
groups.push({ date: "Updates", entries: [line] });
|
||||
} else {
|
||||
groups[groups.length - 1].entries.push(line)
|
||||
groups[groups.length - 1].entries.push(line);
|
||||
}
|
||||
}
|
||||
return groups
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
|
||||
export default function ChangelogPage() {
|
||||
const router = useRouter()
|
||||
const [groups, setGroups] = useState<ChangelogGroup[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const router = useRouter();
|
||||
const [groups, setGroups] = useState<ChangelogGroup[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const token = getToken()
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
router.push('/login')
|
||||
return
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
let active = true
|
||||
let active = true;
|
||||
const load = async () => {
|
||||
try {
|
||||
const baseUrl = getApiBase()
|
||||
const response = await authFetch(`${baseUrl}/site/info`)
|
||||
const baseUrl = getApiBase();
|
||||
const response = await authFetch(`${baseUrl}/site/info`);
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
clearToken()
|
||||
router.push('/login')
|
||||
return
|
||||
clearToken();
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
throw new Error('Failed to load changelog')
|
||||
throw new Error("Failed to load changelog");
|
||||
}
|
||||
const data: SiteInfo = await response.json()
|
||||
if (!active) return
|
||||
setGroups(parseChangelog(data?.changelog ?? ''))
|
||||
const data: SiteInfo = await response.json();
|
||||
if (!active) return;
|
||||
setGroups(parseChangelog(data?.changelog ?? ""));
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
if (!active) return
|
||||
setGroups([])
|
||||
console.error(err);
|
||||
if (!active) return;
|
||||
setGroups([]);
|
||||
} finally {
|
||||
if (active) setLoading(false)
|
||||
if (active) setLoading(false);
|
||||
}
|
||||
}
|
||||
void load()
|
||||
};
|
||||
void load();
|
||||
return () => {
|
||||
active = false
|
||||
}
|
||||
}, [router])
|
||||
active = false;
|
||||
};
|
||||
}, [router]);
|
||||
|
||||
const content = useMemo(() => {
|
||||
if (loading) {
|
||||
return <div className="loading-text">Loading changelog...</div>
|
||||
return <div className="loading-text">Loading changelog...</div>;
|
||||
}
|
||||
if (groups.length === 0) {
|
||||
return <div className="meta">No updates posted yet.</div>
|
||||
return <div className="meta">No updates posted yet.</div>;
|
||||
}
|
||||
return (
|
||||
<div className="changelog-groups">
|
||||
@@ -104,13 +104,13 @@ export default function ChangelogPage() {
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}, [groups, loading])
|
||||
);
|
||||
}, [groups, loading]);
|
||||
|
||||
return (
|
||||
<main className="card changelog-page">
|
||||
<PageHeading title="Changelog" description="What’s new and improved in Magent." />
|
||||
{content}
|
||||
</main>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user