mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(feeds): force infinite scroll on multiboards and canonicalize page URLs
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { normalizeMultiboardFeedPath } from '../route-utils';
|
||||
|
||||
describe('normalizeMultiboardFeedPath', () => {
|
||||
it('normalizes /all/3 -> /all', () => {
|
||||
expect(normalizeMultiboardFeedPath('/all/3')).toBe('/all');
|
||||
});
|
||||
|
||||
it('normalizes /all/1w/3 -> /all/1w', () => {
|
||||
expect(normalizeMultiboardFeedPath('/all/1w/3')).toBe('/all/1w');
|
||||
});
|
||||
|
||||
it('normalizes /subs/2/settings -> /subs/settings', () => {
|
||||
expect(normalizeMultiboardFeedPath('/subs/2/settings')).toBe('/subs/settings');
|
||||
});
|
||||
|
||||
it('normalizes /mod/catalog/4 -> /mod/catalog', () => {
|
||||
expect(normalizeMultiboardFeedPath('/mod/catalog/4')).toBe('/mod/catalog');
|
||||
});
|
||||
|
||||
it('leaves non-multiboard paths unchanged', () => {
|
||||
expect(normalizeMultiboardFeedPath('/biz')).toBe('/biz');
|
||||
expect(normalizeMultiboardFeedPath('/biz/3')).toBe('/biz/3');
|
||||
expect(normalizeMultiboardFeedPath('/biz/1w/2')).toBe('/biz/1w/2');
|
||||
expect(normalizeMultiboardFeedPath('/biz/catalog/4')).toBe('/biz/catalog/4');
|
||||
expect(normalizeMultiboardFeedPath('/pending/0')).toBe('/pending/0');
|
||||
expect(normalizeMultiboardFeedPath('/')).toBe('/');
|
||||
});
|
||||
});
|
||||
@@ -150,6 +150,43 @@ export const BOARD_PAGE_REGEX = /^([1-9]|10)$/;
|
||||
|
||||
export const isBoardFeedPageNumber = (segment: string): boolean => BOARD_PAGE_REGEX.test(segment);
|
||||
|
||||
/** Internal: check if segment is a multiboard root (all, subs, mod) */
|
||||
function isMultiboardRoot(segment: string): boolean {
|
||||
return segment === 'all' || segment === 'subs' || segment === 'mod';
|
||||
}
|
||||
|
||||
/** Internal: check if pathname is a multiboard feed path (starts with /all, /subs, or /mod) */
|
||||
function isMultiboardFeedPath(pathname: string): boolean {
|
||||
const trimmed = pathname.replace(/\/$/, '');
|
||||
const segments = trimmed.split('/').filter(Boolean);
|
||||
return segments.length > 0 && isMultiboardRoot(segments[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize multiboard feed paths by removing trailing page-number segments (1–10),
|
||||
* while preserving /settings and valid time-filter segments.
|
||||
* Non-multiboard paths are returned unchanged.
|
||||
*/
|
||||
export const normalizeMultiboardFeedPath = (pathname: string): string => {
|
||||
let path = pathname.replace(/\/$/, '');
|
||||
if (!isMultiboardFeedPath(path)) {
|
||||
return pathname;
|
||||
}
|
||||
|
||||
const hasSettings = path.endsWith('/settings');
|
||||
if (hasSettings) {
|
||||
path = path.replace(/\/settings$/, '');
|
||||
}
|
||||
|
||||
const segments = path.split('/').filter(Boolean);
|
||||
if (segments.length > 1 && isBoardFeedPageNumber(segments[segments.length - 1])) {
|
||||
const newPath = '/' + segments.slice(0, -1).join('/');
|
||||
return hasSettings ? newPath + '/settings' : newPath;
|
||||
}
|
||||
|
||||
return hasSettings ? path + '/settings' : path;
|
||||
};
|
||||
|
||||
/** Strip trailing page number (1–10) from path for feed cache key */
|
||||
export const stripPageFromFeedPath = (path: string): string => {
|
||||
const segments = path.split('/').filter(Boolean);
|
||||
|
||||
Reference in New Issue
Block a user