This commit is contained in:
4
LOG.md
4
LOG.md
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## 2026-05-29
|
## 2026-05-29
|
||||||
|
|
||||||
|
- Fixed post detail 404s caused by double-encoding dynamic route slugs that already arrive percent-encoded from URLs such as `/posts/soft-delete%2C-hard-delete`.
|
||||||
|
- Updated the public post fetch helper to decode a route slug once before encoding it for the backend API path, preserving normal Korean/special-character slug requests while avoiding `%252C`-style API lookups.
|
||||||
|
- Validation: `npm run lint` passed and `npm run build` passed. A local production server with `NEXT_PUBLIC_API_URL=https://blogserver.wypark.me` returned real post titles for `/posts/soft-delete%2C-hard-delete`, `/posts/destructuring-%26-component%ED%95%A8%EC%88%98`, and `/posts/rtr-(refresh-token-rotation)`.
|
||||||
|
- Recommended next task: deploy the slug normalization fix before re-checking affected live post URLs in Search Console or the browser.
|
||||||
- Added a category post-list page size control with 9/18/27 options, defaulting to 9 and persisting the user's choice in `localStorage` under `categoryPageSize`.
|
- Added a category post-list page size control with 9/18/27 options, defaulting to 9 and persisting the user's choice in `localStorage` under `categoryPageSize`.
|
||||||
- Wired the selected category page size into the React Query key and `getPostsByCategory` request size, resetting to page 1 when the size changes while preserving search behavior.
|
- Wired the selected category page size into the React Query key and `getPostsByCategory` request size, resetting to page 1 when the size changes while preserving search behavior.
|
||||||
- Adjusted the category page toolbar so search, page-size controls, and grid/list controls stack cleanly on narrow screens and align in one row on desktop.
|
- Adjusted the category page toolbar so search, page-size controls, and grid/list controls stack cleanly on narrow screens and align in one row on desktop.
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ const buildPostListUrl = (params: PublicPostListParams = {}) => {
|
|||||||
return `${API_URL}/api/posts?${searchParams.toString()}`;
|
return `${API_URL}/api/posts?${searchParams.toString()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const encodeSlugPathSegment = (slug: string) => {
|
||||||
|
try {
|
||||||
|
return encodeURIComponent(decodeURIComponent(slug));
|
||||||
|
} catch {
|
||||||
|
return encodeURIComponent(slug);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const fetchPublicPosts = async (
|
export const fetchPublicPosts = async (
|
||||||
params: PublicPostListParams = {},
|
params: PublicPostListParams = {},
|
||||||
): Promise<PostListResponse | null> => {
|
): Promise<PostListResponse | null> => {
|
||||||
@@ -50,7 +58,7 @@ export const fetchPublicPosts = async (
|
|||||||
|
|
||||||
export const fetchPublicPost = async (slug: string): Promise<Post | null> => {
|
export const fetchPublicPost = async (slug: string): Promise<Post | null> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_URL}/api/posts/${encodeURIComponent(slug)}`, {
|
const response = await fetch(`${API_URL}/api/posts/${encodeSlugPathSegment(slug)}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
next: { revalidate: 60 },
|
next: { revalidate: 60 },
|
||||||
@@ -65,4 +73,3 @@ export const fetchPublicPost = async (slug: string): Promise<Post | null> => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user